xref: /onnv-gate/usr/src/uts/common/io/ib/adapters/hermon/hermon_mr.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_mr.c
289517SBill.Taylor@Sun.COM  *    Hermon Memory Region/Window Routines
299517SBill.Taylor@Sun.COM  *
309517SBill.Taylor@Sun.COM  *    Implements all the routines necessary to provide the requisite memory
319517SBill.Taylor@Sun.COM  *    registration verbs.  These include operations like RegisterMemRegion(),
329517SBill.Taylor@Sun.COM  *    DeregisterMemRegion(), ReregisterMemRegion, RegisterSharedMemRegion,
339517SBill.Taylor@Sun.COM  *    etc., that affect Memory Regions.  It also includes the verbs that
349517SBill.Taylor@Sun.COM  *    affect Memory Windows, including AllocMemWindow(), FreeMemWindow(),
359517SBill.Taylor@Sun.COM  *    and QueryMemWindow().
369517SBill.Taylor@Sun.COM  */
379517SBill.Taylor@Sun.COM 
389517SBill.Taylor@Sun.COM #include <sys/types.h>
399517SBill.Taylor@Sun.COM #include <sys/conf.h>
409517SBill.Taylor@Sun.COM #include <sys/ddi.h>
419517SBill.Taylor@Sun.COM #include <sys/sunddi.h>
429517SBill.Taylor@Sun.COM #include <sys/modctl.h>
439517SBill.Taylor@Sun.COM #include <sys/esunddi.h>
449517SBill.Taylor@Sun.COM 
459517SBill.Taylor@Sun.COM #include <sys/ib/adapters/hermon/hermon.h>
469517SBill.Taylor@Sun.COM 
479517SBill.Taylor@Sun.COM extern uint32_t hermon_kernel_data_ro;
489517SBill.Taylor@Sun.COM extern uint32_t hermon_user_data_ro;
4911972SBill.Taylor@Sun.COM extern int hermon_rdma_debug;
509517SBill.Taylor@Sun.COM 
519517SBill.Taylor@Sun.COM /*
529517SBill.Taylor@Sun.COM  * Used by hermon_mr_keycalc() below to fill in the "unconstrained" portion
539517SBill.Taylor@Sun.COM  * of Hermon memory keys (LKeys and RKeys)
549517SBill.Taylor@Sun.COM  */
559517SBill.Taylor@Sun.COM static	uint_t hermon_memkey_cnt = 0x00;
5611972SBill.Taylor@Sun.COM #define	HERMON_MEMKEY_SHIFT	24
5711972SBill.Taylor@Sun.COM 
5811972SBill.Taylor@Sun.COM /* initial state of an MPT */
5911972SBill.Taylor@Sun.COM #define	HERMON_MPT_SW_OWNERSHIP	0xF	/* memory regions */
6011972SBill.Taylor@Sun.COM #define	HERMON_MPT_FREE		0x3	/* allocate lkey */
619517SBill.Taylor@Sun.COM 
629517SBill.Taylor@Sun.COM static int hermon_mr_common_reg(hermon_state_t *state, hermon_pdhdl_t pd,
639517SBill.Taylor@Sun.COM     hermon_bind_info_t *bind, hermon_mrhdl_t *mrhdl, hermon_mr_options_t *op,
649517SBill.Taylor@Sun.COM     hermon_mpt_rsrc_type_t mpt_type);
659517SBill.Taylor@Sun.COM static int hermon_mr_common_rereg(hermon_state_t *state, hermon_mrhdl_t mr,
669517SBill.Taylor@Sun.COM     hermon_pdhdl_t pd, hermon_bind_info_t *bind, hermon_mrhdl_t *mrhdl_new,
679517SBill.Taylor@Sun.COM     hermon_mr_options_t *op);
689517SBill.Taylor@Sun.COM static int hermon_mr_rereg_xlat_helper(hermon_state_t *state, hermon_mrhdl_t mr,
699517SBill.Taylor@Sun.COM     hermon_bind_info_t *bind, hermon_mr_options_t *op, uint64_t *mtt_addr,
709517SBill.Taylor@Sun.COM     uint_t sleep, uint_t *dereg_level);
719517SBill.Taylor@Sun.COM static uint64_t hermon_mr_nummtt_needed(hermon_state_t *state,
729517SBill.Taylor@Sun.COM     hermon_bind_info_t *bind, uint_t *mtt_pgsize);
739517SBill.Taylor@Sun.COM static int hermon_mr_mem_bind(hermon_state_t *state, hermon_bind_info_t *bind,
749517SBill.Taylor@Sun.COM     ddi_dma_handle_t dmahdl, uint_t sleep, uint_t is_buffer);
759517SBill.Taylor@Sun.COM static void hermon_mr_mem_unbind(hermon_state_t *state,
769517SBill.Taylor@Sun.COM     hermon_bind_info_t *bind);
779517SBill.Taylor@Sun.COM static int hermon_mr_fast_mtt_write(hermon_state_t *state, hermon_rsrc_t *mtt,
789517SBill.Taylor@Sun.COM     hermon_bind_info_t *bind, uint32_t mtt_pgsize_bits);
7911972SBill.Taylor@Sun.COM static int hermon_mr_fast_mtt_write_fmr(hermon_state_t *state,
8011972SBill.Taylor@Sun.COM     hermon_rsrc_t *mtt, ibt_pmr_attr_t *mem_pattr, uint32_t mtt_pgsize_bits);
819517SBill.Taylor@Sun.COM static uint_t hermon_mtt_refcnt_inc(hermon_rsrc_t *rsrc);
829517SBill.Taylor@Sun.COM static uint_t hermon_mtt_refcnt_dec(hermon_rsrc_t *rsrc);
839517SBill.Taylor@Sun.COM 
849517SBill.Taylor@Sun.COM 
859517SBill.Taylor@Sun.COM /*
869517SBill.Taylor@Sun.COM  * The Hermon umem_lockmemory() callback ops.  When userland memory is
879517SBill.Taylor@Sun.COM  * registered, these callback ops are specified.  The hermon_umap_umemlock_cb()
889517SBill.Taylor@Sun.COM  * callback will be called whenever the memory for the corresponding
899517SBill.Taylor@Sun.COM  * ddi_umem_cookie_t is being freed.
909517SBill.Taylor@Sun.COM  */
919517SBill.Taylor@Sun.COM static struct umem_callback_ops hermon_umem_cbops = {
929517SBill.Taylor@Sun.COM 	UMEM_CALLBACK_VERSION,
939517SBill.Taylor@Sun.COM 	hermon_umap_umemlock_cb,
949517SBill.Taylor@Sun.COM };
959517SBill.Taylor@Sun.COM 
969517SBill.Taylor@Sun.COM 
979517SBill.Taylor@Sun.COM 
989517SBill.Taylor@Sun.COM /*
999517SBill.Taylor@Sun.COM  * hermon_mr_register()
1009517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
1019517SBill.Taylor@Sun.COM  */
1029517SBill.Taylor@Sun.COM int
hermon_mr_register(hermon_state_t * state,hermon_pdhdl_t pd,ibt_mr_attr_t * mr_attr,hermon_mrhdl_t * mrhdl,hermon_mr_options_t * op,hermon_mpt_rsrc_type_t mpt_type)1039517SBill.Taylor@Sun.COM hermon_mr_register(hermon_state_t *state, hermon_pdhdl_t pd,
1049517SBill.Taylor@Sun.COM     ibt_mr_attr_t *mr_attr, hermon_mrhdl_t *mrhdl, hermon_mr_options_t *op,
1059517SBill.Taylor@Sun.COM     hermon_mpt_rsrc_type_t mpt_type)
1069517SBill.Taylor@Sun.COM {
1079517SBill.Taylor@Sun.COM 	hermon_bind_info_t	bind;
1089517SBill.Taylor@Sun.COM 	int			status;
1099517SBill.Taylor@Sun.COM 
1109517SBill.Taylor@Sun.COM 	/*
1119517SBill.Taylor@Sun.COM 	 * Fill in the "bind" struct.  This struct provides the majority
1129517SBill.Taylor@Sun.COM 	 * of the information that will be used to distinguish between an
1139517SBill.Taylor@Sun.COM 	 * "addr" binding (as is the case here) and a "buf" binding (see
1149517SBill.Taylor@Sun.COM 	 * below).  The "bind" struct is later passed to hermon_mr_mem_bind()
1159517SBill.Taylor@Sun.COM 	 * which does most of the "heavy lifting" for the Hermon memory
1169517SBill.Taylor@Sun.COM 	 * registration routines.
1179517SBill.Taylor@Sun.COM 	 */
1189517SBill.Taylor@Sun.COM 	bind.bi_type  = HERMON_BINDHDL_VADDR;
1199517SBill.Taylor@Sun.COM 	bind.bi_addr  = mr_attr->mr_vaddr;
1209517SBill.Taylor@Sun.COM 	bind.bi_len   = mr_attr->mr_len;
1219517SBill.Taylor@Sun.COM 	bind.bi_as    = mr_attr->mr_as;
1229517SBill.Taylor@Sun.COM 	bind.bi_flags = mr_attr->mr_flags;
1239517SBill.Taylor@Sun.COM 	status = hermon_mr_common_reg(state, pd, &bind, mrhdl, op,
1249517SBill.Taylor@Sun.COM 	    mpt_type);
1259517SBill.Taylor@Sun.COM 	return (status);
1269517SBill.Taylor@Sun.COM }
1279517SBill.Taylor@Sun.COM 
1289517SBill.Taylor@Sun.COM 
1299517SBill.Taylor@Sun.COM /*
1309517SBill.Taylor@Sun.COM  * hermon_mr_register_buf()
1319517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
1329517SBill.Taylor@Sun.COM  */
1339517SBill.Taylor@Sun.COM int
hermon_mr_register_buf(hermon_state_t * state,hermon_pdhdl_t pd,ibt_smr_attr_t * mr_attr,struct buf * buf,hermon_mrhdl_t * mrhdl,hermon_mr_options_t * op,hermon_mpt_rsrc_type_t mpt_type)1349517SBill.Taylor@Sun.COM hermon_mr_register_buf(hermon_state_t *state, hermon_pdhdl_t pd,
1359517SBill.Taylor@Sun.COM     ibt_smr_attr_t *mr_attr, struct buf *buf, hermon_mrhdl_t *mrhdl,
1369517SBill.Taylor@Sun.COM     hermon_mr_options_t *op, hermon_mpt_rsrc_type_t mpt_type)
1379517SBill.Taylor@Sun.COM {
1389517SBill.Taylor@Sun.COM 	hermon_bind_info_t	bind;
1399517SBill.Taylor@Sun.COM 	int			status;
1409517SBill.Taylor@Sun.COM 
1419517SBill.Taylor@Sun.COM 	/*
1429517SBill.Taylor@Sun.COM 	 * Fill in the "bind" struct.  This struct provides the majority
1439517SBill.Taylor@Sun.COM 	 * of the information that will be used to distinguish between an
1449517SBill.Taylor@Sun.COM 	 * "addr" binding (see above) and a "buf" binding (as is the case
1459517SBill.Taylor@Sun.COM 	 * here).  The "bind" struct is later passed to hermon_mr_mem_bind()
1469517SBill.Taylor@Sun.COM 	 * which does most of the "heavy lifting" for the Hermon memory
1479517SBill.Taylor@Sun.COM 	 * registration routines.  Note: We have chosen to provide
1489517SBill.Taylor@Sun.COM 	 * "b_un.b_addr" as the IB address (when the IBT_MR_PHYS_IOVA flag is
1499517SBill.Taylor@Sun.COM 	 * not set).  It is not critical what value we choose here as it need
1509517SBill.Taylor@Sun.COM 	 * only be unique for the given RKey (which will happen by default),
1519517SBill.Taylor@Sun.COM 	 * so the choice here is somewhat arbitrary.
1529517SBill.Taylor@Sun.COM 	 */
1539517SBill.Taylor@Sun.COM 	bind.bi_type  = HERMON_BINDHDL_BUF;
1549517SBill.Taylor@Sun.COM 	bind.bi_buf   = buf;
1559517SBill.Taylor@Sun.COM 	if (mr_attr->mr_flags & IBT_MR_PHYS_IOVA) {
1569517SBill.Taylor@Sun.COM 		bind.bi_addr  = mr_attr->mr_vaddr;
1579517SBill.Taylor@Sun.COM 	} else {
1589517SBill.Taylor@Sun.COM 		bind.bi_addr  = (uint64_t)(uintptr_t)buf->b_un.b_addr;
1599517SBill.Taylor@Sun.COM 	}
1609517SBill.Taylor@Sun.COM 	bind.bi_as    = NULL;
1619517SBill.Taylor@Sun.COM 	bind.bi_len   = (uint64_t)buf->b_bcount;
1629517SBill.Taylor@Sun.COM 	bind.bi_flags = mr_attr->mr_flags;
1639517SBill.Taylor@Sun.COM 	status = hermon_mr_common_reg(state, pd, &bind, mrhdl, op, mpt_type);
1649517SBill.Taylor@Sun.COM 	return (status);
1659517SBill.Taylor@Sun.COM }
1669517SBill.Taylor@Sun.COM 
1679517SBill.Taylor@Sun.COM 
1689517SBill.Taylor@Sun.COM /*
1699517SBill.Taylor@Sun.COM  * hermon_mr_register_shared()
1709517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
1719517SBill.Taylor@Sun.COM  */
1729517SBill.Taylor@Sun.COM int
hermon_mr_register_shared(hermon_state_t * state,hermon_mrhdl_t mrhdl,hermon_pdhdl_t pd,ibt_smr_attr_t * mr_attr,hermon_mrhdl_t * mrhdl_new)1739517SBill.Taylor@Sun.COM hermon_mr_register_shared(hermon_state_t *state, hermon_mrhdl_t mrhdl,
1749517SBill.Taylor@Sun.COM     hermon_pdhdl_t pd, ibt_smr_attr_t *mr_attr, hermon_mrhdl_t *mrhdl_new)
1759517SBill.Taylor@Sun.COM {
1769517SBill.Taylor@Sun.COM 	hermon_rsrc_t		*mpt, *mtt, *rsrc;
1779517SBill.Taylor@Sun.COM 	hermon_umap_db_entry_t	*umapdb;
1789517SBill.Taylor@Sun.COM 	hermon_hw_dmpt_t	mpt_entry;
1799517SBill.Taylor@Sun.COM 	hermon_mrhdl_t		mr;
1809517SBill.Taylor@Sun.COM 	hermon_bind_info_t	*bind;
1819517SBill.Taylor@Sun.COM 	ddi_umem_cookie_t	umem_cookie;
1829517SBill.Taylor@Sun.COM 	size_t			umem_len;
1839517SBill.Taylor@Sun.COM 	caddr_t			umem_addr;
1849517SBill.Taylor@Sun.COM 	uint64_t		mtt_addr, pgsize_msk;
1859517SBill.Taylor@Sun.COM 	uint_t			sleep, mr_is_umem;
1869517SBill.Taylor@Sun.COM 	int			status, umem_flags;
1879517SBill.Taylor@Sun.COM 
1889517SBill.Taylor@Sun.COM 	/*
1899517SBill.Taylor@Sun.COM 	 * Check the sleep flag.  Ensure that it is consistent with the
1909517SBill.Taylor@Sun.COM 	 * current thread context (i.e. if we are currently in the interrupt
1919517SBill.Taylor@Sun.COM 	 * context, then we shouldn't be attempting to sleep).
1929517SBill.Taylor@Sun.COM 	 */
1939517SBill.Taylor@Sun.COM 	sleep = (mr_attr->mr_flags & IBT_MR_NOSLEEP) ? HERMON_NOSLEEP :
1949517SBill.Taylor@Sun.COM 	    HERMON_SLEEP;
1959517SBill.Taylor@Sun.COM 	if ((sleep == HERMON_SLEEP) &&
1969517SBill.Taylor@Sun.COM 	    (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
1979517SBill.Taylor@Sun.COM 		status = IBT_INVALID_PARAM;
1989517SBill.Taylor@Sun.COM 		goto mrshared_fail;
1999517SBill.Taylor@Sun.COM 	}
2009517SBill.Taylor@Sun.COM 
2019517SBill.Taylor@Sun.COM 	/* Increment the reference count on the protection domain (PD) */
2029517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_inc(pd);
2039517SBill.Taylor@Sun.COM 
2049517SBill.Taylor@Sun.COM 	/*
2059517SBill.Taylor@Sun.COM 	 * Allocate an MPT entry.  This will be filled in with all the
2069517SBill.Taylor@Sun.COM 	 * necessary parameters to define the shared memory region.
2079517SBill.Taylor@Sun.COM 	 * Specifically, it will be made to reference the currently existing
2089517SBill.Taylor@Sun.COM 	 * MTT entries and ownership of the MPT will be passed to the hardware
2099517SBill.Taylor@Sun.COM 	 * in the last step below.  If we fail here, we must undo the
2109517SBill.Taylor@Sun.COM 	 * protection domain reference count.
2119517SBill.Taylor@Sun.COM 	 */
2129517SBill.Taylor@Sun.COM 	status = hermon_rsrc_alloc(state, HERMON_DMPT, 1, sleep, &mpt);
2139517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
2149517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
2159517SBill.Taylor@Sun.COM 		goto mrshared_fail1;
2169517SBill.Taylor@Sun.COM 	}
2179517SBill.Taylor@Sun.COM 
2189517SBill.Taylor@Sun.COM 	/*
2199517SBill.Taylor@Sun.COM 	 * Allocate the software structure for tracking the shared memory
2209517SBill.Taylor@Sun.COM 	 * region (i.e. the Hermon Memory Region handle).  If we fail here, we
2219517SBill.Taylor@Sun.COM 	 * must undo the protection domain reference count and the previous
2229517SBill.Taylor@Sun.COM 	 * resource allocation.
2239517SBill.Taylor@Sun.COM 	 */
2249517SBill.Taylor@Sun.COM 	status = hermon_rsrc_alloc(state, HERMON_MRHDL, 1, sleep, &rsrc);
2259517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
2269517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
2279517SBill.Taylor@Sun.COM 		goto mrshared_fail2;
2289517SBill.Taylor@Sun.COM 	}
2299517SBill.Taylor@Sun.COM 	mr = (hermon_mrhdl_t)rsrc->hr_addr;
2309517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mr))
2319517SBill.Taylor@Sun.COM 
2329517SBill.Taylor@Sun.COM 	/*
2339517SBill.Taylor@Sun.COM 	 * Setup and validate the memory region access flags.  This means
2349517SBill.Taylor@Sun.COM 	 * translating the IBTF's enable flags into the access flags that
2359517SBill.Taylor@Sun.COM 	 * will be used in later operations.
2369517SBill.Taylor@Sun.COM 	 */
2379517SBill.Taylor@Sun.COM 	mr->mr_accflag = 0;
2389517SBill.Taylor@Sun.COM 	if (mr_attr->mr_flags & IBT_MR_ENABLE_WINDOW_BIND)
2399517SBill.Taylor@Sun.COM 		mr->mr_accflag |= IBT_MR_WINDOW_BIND;
2409517SBill.Taylor@Sun.COM 	if (mr_attr->mr_flags & IBT_MR_ENABLE_LOCAL_WRITE)
2419517SBill.Taylor@Sun.COM 		mr->mr_accflag |= IBT_MR_LOCAL_WRITE;
2429517SBill.Taylor@Sun.COM 	if (mr_attr->mr_flags & IBT_MR_ENABLE_REMOTE_READ)
2439517SBill.Taylor@Sun.COM 		mr->mr_accflag |= IBT_MR_REMOTE_READ;
2449517SBill.Taylor@Sun.COM 	if (mr_attr->mr_flags & IBT_MR_ENABLE_REMOTE_WRITE)
2459517SBill.Taylor@Sun.COM 		mr->mr_accflag |= IBT_MR_REMOTE_WRITE;
2469517SBill.Taylor@Sun.COM 	if (mr_attr->mr_flags & IBT_MR_ENABLE_REMOTE_ATOMIC)
2479517SBill.Taylor@Sun.COM 		mr->mr_accflag |= IBT_MR_REMOTE_ATOMIC;
2489517SBill.Taylor@Sun.COM 
2499517SBill.Taylor@Sun.COM 	/*
2509517SBill.Taylor@Sun.COM 	 * Calculate keys (Lkey, Rkey) from MPT index.  Each key is formed
2519517SBill.Taylor@Sun.COM 	 * from a certain number of "constrained" bits (the least significant
2529517SBill.Taylor@Sun.COM 	 * bits) and some number of "unconstrained" bits.  The constrained
2539517SBill.Taylor@Sun.COM 	 * bits must be set to the index of the entry in the MPT table, but
2549517SBill.Taylor@Sun.COM 	 * the unconstrained bits can be set to any value we wish.  Note:
2559517SBill.Taylor@Sun.COM 	 * if no remote access is required, then the RKey value is not filled
2569517SBill.Taylor@Sun.COM 	 * in.  Otherwise both Rkey and LKey are given the same value.
2579517SBill.Taylor@Sun.COM 	 */
25811972SBill.Taylor@Sun.COM 	mr->mr_rkey = mr->mr_lkey = hermon_mr_keycalc(mpt->hr_indx);
2599517SBill.Taylor@Sun.COM 
2609517SBill.Taylor@Sun.COM 	/* Grab the MR lock for the current memory region */
2619517SBill.Taylor@Sun.COM 	mutex_enter(&mrhdl->mr_lock);
2629517SBill.Taylor@Sun.COM 
2639517SBill.Taylor@Sun.COM 	/*
2649517SBill.Taylor@Sun.COM 	 * Check here to see if the memory region has already been partially
2659517SBill.Taylor@Sun.COM 	 * deregistered as a result of a hermon_umap_umemlock_cb() callback.
2669517SBill.Taylor@Sun.COM 	 * If so, this is an error, return failure.
2679517SBill.Taylor@Sun.COM 	 */
2689517SBill.Taylor@Sun.COM 	if ((mrhdl->mr_is_umem) && (mrhdl->mr_umemcookie == NULL)) {
2699517SBill.Taylor@Sun.COM 		mutex_exit(&mrhdl->mr_lock);
2709517SBill.Taylor@Sun.COM 		status = IBT_MR_HDL_INVALID;
2719517SBill.Taylor@Sun.COM 		goto mrshared_fail3;
2729517SBill.Taylor@Sun.COM 	}
2739517SBill.Taylor@Sun.COM 
2749517SBill.Taylor@Sun.COM 	/*
2759517SBill.Taylor@Sun.COM 	 * Determine if the original memory was from userland and, if so, pin
2769517SBill.Taylor@Sun.COM 	 * the pages (again) with umem_lockmemory().  This will guarantee a
2779517SBill.Taylor@Sun.COM 	 * separate callback for each of this shared region's MR handles.
2789517SBill.Taylor@Sun.COM 	 * If this is userland memory, then allocate an entry in the
2799517SBill.Taylor@Sun.COM 	 * "userland resources database".  This will later be added to
2809517SBill.Taylor@Sun.COM 	 * the database (after all further memory registration operations are
2819517SBill.Taylor@Sun.COM 	 * successful).  If we fail here, we must undo all the above setup.
2829517SBill.Taylor@Sun.COM 	 */
2839517SBill.Taylor@Sun.COM 	mr_is_umem = mrhdl->mr_is_umem;
2849517SBill.Taylor@Sun.COM 	if (mr_is_umem) {
2859517SBill.Taylor@Sun.COM 		umem_len   = ptob(btopr(mrhdl->mr_bindinfo.bi_len));
2869517SBill.Taylor@Sun.COM 		umem_addr  = (caddr_t)((uintptr_t)mrhdl->mr_bindinfo.bi_addr &
2879517SBill.Taylor@Sun.COM 		    ~PAGEOFFSET);
2889517SBill.Taylor@Sun.COM 		umem_flags = (DDI_UMEMLOCK_WRITE | DDI_UMEMLOCK_READ |
2899517SBill.Taylor@Sun.COM 		    DDI_UMEMLOCK_LONGTERM);
2909517SBill.Taylor@Sun.COM 		status = umem_lockmemory(umem_addr, umem_len, umem_flags,
29110366SBill.Taylor@Sun.COM 		    &umem_cookie, &hermon_umem_cbops, NULL);
2929517SBill.Taylor@Sun.COM 		if (status != 0) {
2939517SBill.Taylor@Sun.COM 			mutex_exit(&mrhdl->mr_lock);
2949517SBill.Taylor@Sun.COM 			status = IBT_INSUFF_RESOURCE;
2959517SBill.Taylor@Sun.COM 			goto mrshared_fail3;
2969517SBill.Taylor@Sun.COM 		}
2979517SBill.Taylor@Sun.COM 
2989517SBill.Taylor@Sun.COM 		umapdb = hermon_umap_db_alloc(state->hs_instance,
2999517SBill.Taylor@Sun.COM 		    (uint64_t)(uintptr_t)umem_cookie, MLNX_UMAP_MRMEM_RSRC,
3009517SBill.Taylor@Sun.COM 		    (uint64_t)(uintptr_t)rsrc);
3019517SBill.Taylor@Sun.COM 		if (umapdb == NULL) {
3029517SBill.Taylor@Sun.COM 			mutex_exit(&mrhdl->mr_lock);
3039517SBill.Taylor@Sun.COM 			status = IBT_INSUFF_RESOURCE;
3049517SBill.Taylor@Sun.COM 			goto mrshared_fail4;
3059517SBill.Taylor@Sun.COM 		}
3069517SBill.Taylor@Sun.COM 	}
3079517SBill.Taylor@Sun.COM 
3089517SBill.Taylor@Sun.COM 	/*
3099517SBill.Taylor@Sun.COM 	 * Copy the MTT resource pointer (and additional parameters) from
3109517SBill.Taylor@Sun.COM 	 * the original Hermon Memory Region handle.  Note: this is normally
3119517SBill.Taylor@Sun.COM 	 * where the hermon_mr_mem_bind() routine would be called, but because
3129517SBill.Taylor@Sun.COM 	 * we already have bound and filled-in MTT entries it is simply a
3139517SBill.Taylor@Sun.COM 	 * matter here of managing the MTT reference count and grabbing the
3149517SBill.Taylor@Sun.COM 	 * address of the MTT table entries (for filling in the shared region's
3159517SBill.Taylor@Sun.COM 	 * MPT entry).
3169517SBill.Taylor@Sun.COM 	 */
3179517SBill.Taylor@Sun.COM 	mr->mr_mttrsrcp	  = mrhdl->mr_mttrsrcp;
3189517SBill.Taylor@Sun.COM 	mr->mr_logmttpgsz = mrhdl->mr_logmttpgsz;
3199517SBill.Taylor@Sun.COM 	mr->mr_bindinfo	  = mrhdl->mr_bindinfo;
3209517SBill.Taylor@Sun.COM 	mr->mr_mttrefcntp = mrhdl->mr_mttrefcntp;
3219517SBill.Taylor@Sun.COM 	mutex_exit(&mrhdl->mr_lock);
3229517SBill.Taylor@Sun.COM 	bind = &mr->mr_bindinfo;
3239517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind))
3249517SBill.Taylor@Sun.COM 	mtt = mr->mr_mttrsrcp;
3259517SBill.Taylor@Sun.COM 
3269517SBill.Taylor@Sun.COM 	/*
3279517SBill.Taylor@Sun.COM 	 * Increment the MTT reference count (to reflect the fact that
3289517SBill.Taylor@Sun.COM 	 * the MTT is now shared)
3299517SBill.Taylor@Sun.COM 	 */
3309517SBill.Taylor@Sun.COM 	(void) hermon_mtt_refcnt_inc(mr->mr_mttrefcntp);
3319517SBill.Taylor@Sun.COM 
3329517SBill.Taylor@Sun.COM 	/*
3339517SBill.Taylor@Sun.COM 	 * Update the new "bind" virtual address.  Do some extra work here
3349517SBill.Taylor@Sun.COM 	 * to ensure proper alignment.  That is, make sure that the page
3359517SBill.Taylor@Sun.COM 	 * offset for the beginning of the old range is the same as the
3369517SBill.Taylor@Sun.COM 	 * offset for this new mapping
3379517SBill.Taylor@Sun.COM 	 */
3389517SBill.Taylor@Sun.COM 	pgsize_msk = (((uint64_t)1 << mr->mr_logmttpgsz) - 1);
3399517SBill.Taylor@Sun.COM 	bind->bi_addr = ((mr_attr->mr_vaddr & ~pgsize_msk) |
3409517SBill.Taylor@Sun.COM 	    (mr->mr_bindinfo.bi_addr & pgsize_msk));
3419517SBill.Taylor@Sun.COM 
3429517SBill.Taylor@Sun.COM 	/*
3439517SBill.Taylor@Sun.COM 	 * Fill in the MPT entry.  This is the final step before passing
3449517SBill.Taylor@Sun.COM 	 * ownership of the MPT entry to the Hermon hardware.  We use all of
3459517SBill.Taylor@Sun.COM 	 * the information collected/calculated above to fill in the
3469517SBill.Taylor@Sun.COM 	 * requisite portions of the MPT.
3479517SBill.Taylor@Sun.COM 	 */
3489517SBill.Taylor@Sun.COM 	bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
3499517SBill.Taylor@Sun.COM 	mpt_entry.en_bind = (mr->mr_accflag & IBT_MR_WINDOW_BIND)   ? 1 : 0;
3509517SBill.Taylor@Sun.COM 	mpt_entry.atomic  = (mr->mr_accflag & IBT_MR_REMOTE_ATOMIC) ? 1 : 0;
3519517SBill.Taylor@Sun.COM 	mpt_entry.rw	  = (mr->mr_accflag & IBT_MR_REMOTE_WRITE)  ? 1 : 0;
3529517SBill.Taylor@Sun.COM 	mpt_entry.rr	  = (mr->mr_accflag & IBT_MR_REMOTE_READ)   ? 1 : 0;
3539517SBill.Taylor@Sun.COM 	mpt_entry.lw	  = (mr->mr_accflag & IBT_MR_LOCAL_WRITE)   ? 1 : 0;
3549517SBill.Taylor@Sun.COM 	mpt_entry.lr	  = 1;
3559517SBill.Taylor@Sun.COM 	mpt_entry.reg_win = HERMON_MPT_IS_REGION;
3569517SBill.Taylor@Sun.COM 	mpt_entry.entity_sz	= mr->mr_logmttpgsz;
3579517SBill.Taylor@Sun.COM 	mpt_entry.mem_key	= mr->mr_lkey;
3589517SBill.Taylor@Sun.COM 	mpt_entry.pd		= pd->pd_pdnum;
3599517SBill.Taylor@Sun.COM 	mpt_entry.start_addr	= bind->bi_addr;
3609517SBill.Taylor@Sun.COM 	mpt_entry.reg_win_len	= bind->bi_len;
3619517SBill.Taylor@Sun.COM 	mtt_addr = (mtt->hr_indx << HERMON_MTT_SIZE_SHIFT);
3629517SBill.Taylor@Sun.COM 	mpt_entry.mtt_addr_h = mtt_addr >> 32;
3639517SBill.Taylor@Sun.COM 	mpt_entry.mtt_addr_l = mtt_addr >> 3;
3649517SBill.Taylor@Sun.COM 
3659517SBill.Taylor@Sun.COM 	/*
3669517SBill.Taylor@Sun.COM 	 * Write the MPT entry to hardware.  Lastly, we pass ownership of
3679517SBill.Taylor@Sun.COM 	 * the entry to the hardware.  Note: in general, this operation
3689517SBill.Taylor@Sun.COM 	 * shouldn't fail.  But if it does, we have to undo everything we've
3699517SBill.Taylor@Sun.COM 	 * done above before returning error.
3709517SBill.Taylor@Sun.COM 	 */
3719517SBill.Taylor@Sun.COM 	status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
3729517SBill.Taylor@Sun.COM 	    sizeof (hermon_hw_dmpt_t), mpt->hr_indx, sleep);
3739517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
3749517SBill.Taylor@Sun.COM 		cmn_err(CE_CONT, "Hermon: SW2HW_MPT command failed: %08x\n",
3759517SBill.Taylor@Sun.COM 		    status);
3769517SBill.Taylor@Sun.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
3779517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
3789517SBill.Taylor@Sun.COM 		}
3799517SBill.Taylor@Sun.COM 		status = ibc_get_ci_failure(0);
3809517SBill.Taylor@Sun.COM 		goto mrshared_fail5;
3819517SBill.Taylor@Sun.COM 	}
3829517SBill.Taylor@Sun.COM 
3839517SBill.Taylor@Sun.COM 	/*
3849517SBill.Taylor@Sun.COM 	 * Fill in the rest of the Hermon Memory Region handle.  Having
3859517SBill.Taylor@Sun.COM 	 * successfully transferred ownership of the MPT, we can update the
3869517SBill.Taylor@Sun.COM 	 * following fields for use in further operations on the MR.
3879517SBill.Taylor@Sun.COM 	 */
3889517SBill.Taylor@Sun.COM 	mr->mr_mptrsrcp	  = mpt;
3899517SBill.Taylor@Sun.COM 	mr->mr_mttrsrcp	  = mtt;
3909517SBill.Taylor@Sun.COM 	mr->mr_mpt_type	  = HERMON_MPT_DMPT;
3919517SBill.Taylor@Sun.COM 	mr->mr_pdhdl	  = pd;
3929517SBill.Taylor@Sun.COM 	mr->mr_rsrcp	  = rsrc;
3939517SBill.Taylor@Sun.COM 	mr->mr_is_umem	  = mr_is_umem;
3949517SBill.Taylor@Sun.COM 	mr->mr_is_fmr	  = 0;
3959517SBill.Taylor@Sun.COM 	mr->mr_umemcookie = (mr_is_umem != 0) ? umem_cookie : NULL;
3969517SBill.Taylor@Sun.COM 	mr->mr_umem_cbfunc = NULL;
3979517SBill.Taylor@Sun.COM 	mr->mr_umem_cbarg1 = NULL;
3989517SBill.Taylor@Sun.COM 	mr->mr_umem_cbarg2 = NULL;
3999517SBill.Taylor@Sun.COM 	mr->mr_lkey	   = hermon_mr_key_swap(mr->mr_lkey);
4009517SBill.Taylor@Sun.COM 	mr->mr_rkey	   = hermon_mr_key_swap(mr->mr_rkey);
4019517SBill.Taylor@Sun.COM 
4029517SBill.Taylor@Sun.COM 	/*
4039517SBill.Taylor@Sun.COM 	 * If this is userland memory, then we need to insert the previously
4049517SBill.Taylor@Sun.COM 	 * allocated entry into the "userland resources database".  This will
4059517SBill.Taylor@Sun.COM 	 * allow for later coordination between the hermon_umap_umemlock_cb()
4069517SBill.Taylor@Sun.COM 	 * callback and hermon_mr_deregister().
4079517SBill.Taylor@Sun.COM 	 */
4089517SBill.Taylor@Sun.COM 	if (mr_is_umem) {
4099517SBill.Taylor@Sun.COM 		hermon_umap_db_add(umapdb);
4109517SBill.Taylor@Sun.COM 	}
4119517SBill.Taylor@Sun.COM 
4129517SBill.Taylor@Sun.COM 	*mrhdl_new = mr;
4139517SBill.Taylor@Sun.COM 
4149517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
4159517SBill.Taylor@Sun.COM 
4169517SBill.Taylor@Sun.COM /*
4179517SBill.Taylor@Sun.COM  * The following is cleanup for all possible failure cases in this routine
4189517SBill.Taylor@Sun.COM  */
4199517SBill.Taylor@Sun.COM mrshared_fail5:
4209517SBill.Taylor@Sun.COM 	(void) hermon_mtt_refcnt_dec(mr->mr_mttrefcntp);
4219517SBill.Taylor@Sun.COM 	if (mr_is_umem) {
4229517SBill.Taylor@Sun.COM 		hermon_umap_db_free(umapdb);
4239517SBill.Taylor@Sun.COM 	}
4249517SBill.Taylor@Sun.COM mrshared_fail4:
4259517SBill.Taylor@Sun.COM 	if (mr_is_umem) {
4269517SBill.Taylor@Sun.COM 		ddi_umem_unlock(umem_cookie);
4279517SBill.Taylor@Sun.COM 	}
4289517SBill.Taylor@Sun.COM mrshared_fail3:
4299517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &rsrc);
4309517SBill.Taylor@Sun.COM mrshared_fail2:
4319517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &mpt);
4329517SBill.Taylor@Sun.COM mrshared_fail1:
4339517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_dec(pd);
4349517SBill.Taylor@Sun.COM mrshared_fail:
4359517SBill.Taylor@Sun.COM 	return (status);
4369517SBill.Taylor@Sun.COM }
4379517SBill.Taylor@Sun.COM 
4389517SBill.Taylor@Sun.COM /*
4399517SBill.Taylor@Sun.COM  * hermon_mr_alloc_fmr()
4409517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
4419517SBill.Taylor@Sun.COM  */
4429517SBill.Taylor@Sun.COM int
hermon_mr_alloc_fmr(hermon_state_t * state,hermon_pdhdl_t pd,hermon_fmrhdl_t fmr_pool,hermon_mrhdl_t * mrhdl)4439517SBill.Taylor@Sun.COM hermon_mr_alloc_fmr(hermon_state_t *state, hermon_pdhdl_t pd,
4449517SBill.Taylor@Sun.COM     hermon_fmrhdl_t fmr_pool, hermon_mrhdl_t *mrhdl)
4459517SBill.Taylor@Sun.COM {
4469517SBill.Taylor@Sun.COM 	hermon_rsrc_t		*mpt, *mtt, *rsrc;
44711972SBill.Taylor@Sun.COM 	hermon_hw_dmpt_t	mpt_entry;
4489517SBill.Taylor@Sun.COM 	hermon_mrhdl_t		mr;
4499517SBill.Taylor@Sun.COM 	hermon_bind_info_t	bind;
4509517SBill.Taylor@Sun.COM 	uint64_t		mtt_addr;
4519517SBill.Taylor@Sun.COM 	uint64_t		nummtt;
4529517SBill.Taylor@Sun.COM 	uint_t			sleep, mtt_pgsize_bits;
4539517SBill.Taylor@Sun.COM 	int			status;
45411972SBill.Taylor@Sun.COM 	offset_t		i;
45511972SBill.Taylor@Sun.COM 	hermon_icm_table_t	*icm_table;
45611972SBill.Taylor@Sun.COM 	hermon_dma_info_t	*dma_info;
45711972SBill.Taylor@Sun.COM 	uint32_t		index1, index2, rindx;
4589517SBill.Taylor@Sun.COM 
4599517SBill.Taylor@Sun.COM 	/*
4609517SBill.Taylor@Sun.COM 	 * Check the sleep flag.  Ensure that it is consistent with the
4619517SBill.Taylor@Sun.COM 	 * current thread context (i.e. if we are currently in the interrupt
4629517SBill.Taylor@Sun.COM 	 * context, then we shouldn't be attempting to sleep).
4639517SBill.Taylor@Sun.COM 	 */
4649517SBill.Taylor@Sun.COM 	sleep = (fmr_pool->fmr_flags & IBT_MR_SLEEP) ? HERMON_SLEEP :
4659517SBill.Taylor@Sun.COM 	    HERMON_NOSLEEP;
4669517SBill.Taylor@Sun.COM 	if ((sleep == HERMON_SLEEP) &&
4679517SBill.Taylor@Sun.COM 	    (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
4689517SBill.Taylor@Sun.COM 		return (IBT_INVALID_PARAM);
4699517SBill.Taylor@Sun.COM 	}
4709517SBill.Taylor@Sun.COM 
4719517SBill.Taylor@Sun.COM 	/* Increment the reference count on the protection domain (PD) */
4729517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_inc(pd);
4739517SBill.Taylor@Sun.COM 
4749517SBill.Taylor@Sun.COM 	/*
4759517SBill.Taylor@Sun.COM 	 * Allocate an MPT entry.  This will be filled in with all the
4769517SBill.Taylor@Sun.COM 	 * necessary parameters to define the FMR.  Specifically, it will be
4779517SBill.Taylor@Sun.COM 	 * made to reference the currently existing MTT entries and ownership
4789517SBill.Taylor@Sun.COM 	 * of the MPT will be passed to the hardware in the last step below.
4799517SBill.Taylor@Sun.COM 	 * If we fail here, we must undo the protection domain reference count.
4809517SBill.Taylor@Sun.COM 	 */
4819517SBill.Taylor@Sun.COM 
4829517SBill.Taylor@Sun.COM 	status = hermon_rsrc_alloc(state, HERMON_DMPT, 1, sleep, &mpt);
4839517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
4849517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
4859517SBill.Taylor@Sun.COM 		goto fmralloc_fail1;
4869517SBill.Taylor@Sun.COM 	}
4879517SBill.Taylor@Sun.COM 
4889517SBill.Taylor@Sun.COM 	/*
4899517SBill.Taylor@Sun.COM 	 * Allocate the software structure for tracking the fmr memory
4909517SBill.Taylor@Sun.COM 	 * region (i.e. the Hermon Memory Region handle).  If we fail here, we
4919517SBill.Taylor@Sun.COM 	 * must undo the protection domain reference count and the previous
4929517SBill.Taylor@Sun.COM 	 * resource allocation.
4939517SBill.Taylor@Sun.COM 	 */
4949517SBill.Taylor@Sun.COM 	status = hermon_rsrc_alloc(state, HERMON_MRHDL, 1, sleep, &rsrc);
4959517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
4969517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
4979517SBill.Taylor@Sun.COM 		goto fmralloc_fail2;
4989517SBill.Taylor@Sun.COM 	}
4999517SBill.Taylor@Sun.COM 	mr = (hermon_mrhdl_t)rsrc->hr_addr;
5009517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mr))
5019517SBill.Taylor@Sun.COM 
5029517SBill.Taylor@Sun.COM 	/*
5039517SBill.Taylor@Sun.COM 	 * Setup and validate the memory region access flags.  This means
5049517SBill.Taylor@Sun.COM 	 * translating the IBTF's enable flags into the access flags that
5059517SBill.Taylor@Sun.COM 	 * will be used in later operations.
5069517SBill.Taylor@Sun.COM 	 */
5079517SBill.Taylor@Sun.COM 	mr->mr_accflag = 0;
5089517SBill.Taylor@Sun.COM 	if (fmr_pool->fmr_flags & IBT_MR_ENABLE_LOCAL_WRITE)
5099517SBill.Taylor@Sun.COM 		mr->mr_accflag |= IBT_MR_LOCAL_WRITE;
5109517SBill.Taylor@Sun.COM 	if (fmr_pool->fmr_flags & IBT_MR_ENABLE_REMOTE_READ)
5119517SBill.Taylor@Sun.COM 		mr->mr_accflag |= IBT_MR_REMOTE_READ;
5129517SBill.Taylor@Sun.COM 	if (fmr_pool->fmr_flags & IBT_MR_ENABLE_REMOTE_WRITE)
5139517SBill.Taylor@Sun.COM 		mr->mr_accflag |= IBT_MR_REMOTE_WRITE;
5149517SBill.Taylor@Sun.COM 	if (fmr_pool->fmr_flags & IBT_MR_ENABLE_REMOTE_ATOMIC)
5159517SBill.Taylor@Sun.COM 		mr->mr_accflag |= IBT_MR_REMOTE_ATOMIC;
5169517SBill.Taylor@Sun.COM 
5179517SBill.Taylor@Sun.COM 	/*
5189517SBill.Taylor@Sun.COM 	 * Calculate keys (Lkey, Rkey) from MPT index.  Each key is formed
5199517SBill.Taylor@Sun.COM 	 * from a certain number of "constrained" bits (the least significant
5209517SBill.Taylor@Sun.COM 	 * bits) and some number of "unconstrained" bits.  The constrained
5219517SBill.Taylor@Sun.COM 	 * bits must be set to the index of the entry in the MPT table, but
5229517SBill.Taylor@Sun.COM 	 * the unconstrained bits can be set to any value we wish.  Note:
5239517SBill.Taylor@Sun.COM 	 * if no remote access is required, then the RKey value is not filled
5249517SBill.Taylor@Sun.COM 	 * in.  Otherwise both Rkey and LKey are given the same value.
5259517SBill.Taylor@Sun.COM 	 */
52611972SBill.Taylor@Sun.COM 	mr->mr_fmr_key = 1;	/* ready for the next reload */
52711972SBill.Taylor@Sun.COM 	mr->mr_rkey = mr->mr_lkey = mpt->hr_indx;
5289517SBill.Taylor@Sun.COM 
5299517SBill.Taylor@Sun.COM 	/*
5309517SBill.Taylor@Sun.COM 	 * Determine number of pages spanned.  This routine uses the
5319517SBill.Taylor@Sun.COM 	 * information in the "bind" struct to determine the required
5329517SBill.Taylor@Sun.COM 	 * number of MTT entries needed (and returns the suggested page size -
5339517SBill.Taylor@Sun.COM 	 * as a "power-of-2" - for each MTT entry).
5349517SBill.Taylor@Sun.COM 	 */
5359517SBill.Taylor@Sun.COM 	/* Assume address will be page aligned later */
5369517SBill.Taylor@Sun.COM 	bind.bi_addr = 0;
5379517SBill.Taylor@Sun.COM 	/* Calculate size based on given max pages */
5389517SBill.Taylor@Sun.COM 	bind.bi_len = fmr_pool->fmr_max_pages << PAGESHIFT;
5399517SBill.Taylor@Sun.COM 	nummtt = hermon_mr_nummtt_needed(state, &bind, &mtt_pgsize_bits);
5409517SBill.Taylor@Sun.COM 
5419517SBill.Taylor@Sun.COM 	/*
5429517SBill.Taylor@Sun.COM 	 * Allocate the MTT entries.  Use the calculations performed above to
5439517SBill.Taylor@Sun.COM 	 * allocate the required number of MTT entries.  If we fail here, we
5449517SBill.Taylor@Sun.COM 	 * must not only undo all the previous resource allocation (and PD
5459517SBill.Taylor@Sun.COM 	 * reference count), but we must also unbind the memory.
5469517SBill.Taylor@Sun.COM 	 */
5479517SBill.Taylor@Sun.COM 	status = hermon_rsrc_alloc(state, HERMON_MTT, nummtt, sleep, &mtt);
5489517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
549*12965SWilliam.Taylor@Oracle.COM 		IBTF_DPRINTF_L2("FMR", "FATAL: too few MTTs");
5509517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
5519517SBill.Taylor@Sun.COM 		goto fmralloc_fail3;
5529517SBill.Taylor@Sun.COM 	}
5539517SBill.Taylor@Sun.COM 	mr->mr_logmttpgsz = mtt_pgsize_bits;
5549517SBill.Taylor@Sun.COM 
5559517SBill.Taylor@Sun.COM 	/*
5569517SBill.Taylor@Sun.COM 	 * Fill in the MPT entry.  This is the final step before passing
5579517SBill.Taylor@Sun.COM 	 * ownership of the MPT entry to the Hermon hardware.  We use all of
5589517SBill.Taylor@Sun.COM 	 * the information collected/calculated above to fill in the
5599517SBill.Taylor@Sun.COM 	 * requisite portions of the MPT.
5609517SBill.Taylor@Sun.COM 	 */
5619517SBill.Taylor@Sun.COM 	bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
5629517SBill.Taylor@Sun.COM 	mpt_entry.en_bind = 0;
5639517SBill.Taylor@Sun.COM 	mpt_entry.atomic  = (mr->mr_accflag & IBT_MR_REMOTE_ATOMIC) ? 1 : 0;
5649517SBill.Taylor@Sun.COM 	mpt_entry.rw	  = (mr->mr_accflag & IBT_MR_REMOTE_WRITE)  ? 1 : 0;
5659517SBill.Taylor@Sun.COM 	mpt_entry.rr	  = (mr->mr_accflag & IBT_MR_REMOTE_READ)   ? 1 : 0;
5669517SBill.Taylor@Sun.COM 	mpt_entry.lw	  = (mr->mr_accflag & IBT_MR_LOCAL_WRITE)   ? 1 : 0;
5679517SBill.Taylor@Sun.COM 	mpt_entry.lr	  = 1;
5689517SBill.Taylor@Sun.COM 	mpt_entry.reg_win = HERMON_MPT_IS_REGION;
5699517SBill.Taylor@Sun.COM 	mpt_entry.pd		= pd->pd_pdnum;
5709517SBill.Taylor@Sun.COM 
5719517SBill.Taylor@Sun.COM 	mpt_entry.entity_sz	= mr->mr_logmttpgsz;
5729517SBill.Taylor@Sun.COM 	mtt_addr = (mtt->hr_indx << HERMON_MTT_SIZE_SHIFT);
57311972SBill.Taylor@Sun.COM 	mpt_entry.fast_reg_en = 1;
57411972SBill.Taylor@Sun.COM 	mpt_entry.mtt_size = (uint_t)nummtt;
5759517SBill.Taylor@Sun.COM 	mpt_entry.mtt_addr_h = mtt_addr >> 32;
5769517SBill.Taylor@Sun.COM 	mpt_entry.mtt_addr_l = mtt_addr >> 3;
5779517SBill.Taylor@Sun.COM 	mpt_entry.mem_key = mr->mr_lkey;
5789517SBill.Taylor@Sun.COM 
5799517SBill.Taylor@Sun.COM 	/*
5809517SBill.Taylor@Sun.COM 	 * FMR sets these to 0 for now.  Later during actual fmr registration
5819517SBill.Taylor@Sun.COM 	 * these values are filled in.
5829517SBill.Taylor@Sun.COM 	 */
5839517SBill.Taylor@Sun.COM 	mpt_entry.start_addr	= 0;
5849517SBill.Taylor@Sun.COM 	mpt_entry.reg_win_len	= 0;
5859517SBill.Taylor@Sun.COM 
5869517SBill.Taylor@Sun.COM 	/*
5879517SBill.Taylor@Sun.COM 	 * Write the MPT entry to hardware.  Lastly, we pass ownership of
5889517SBill.Taylor@Sun.COM 	 * the entry to the hardware.  Note: in general, this operation
5899517SBill.Taylor@Sun.COM 	 * shouldn't fail.  But if it does, we have to undo everything we've
5909517SBill.Taylor@Sun.COM 	 * done above before returning error.
5919517SBill.Taylor@Sun.COM 	 */
5929517SBill.Taylor@Sun.COM 	status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
5939517SBill.Taylor@Sun.COM 	    sizeof (hermon_hw_dmpt_t), mpt->hr_indx, sleep);
5949517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
5959517SBill.Taylor@Sun.COM 		cmn_err(CE_CONT, "Hermon: SW2HW_MPT command failed: %08x\n",
5969517SBill.Taylor@Sun.COM 		    status);
5979517SBill.Taylor@Sun.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
5989517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
5999517SBill.Taylor@Sun.COM 		}
6009517SBill.Taylor@Sun.COM 		status = ibc_get_ci_failure(0);
6019517SBill.Taylor@Sun.COM 		goto fmralloc_fail4;
6029517SBill.Taylor@Sun.COM 	}
6039517SBill.Taylor@Sun.COM 
6049517SBill.Taylor@Sun.COM 	/*
6059517SBill.Taylor@Sun.COM 	 * Fill in the rest of the Hermon Memory Region handle.  Having
6069517SBill.Taylor@Sun.COM 	 * successfully transferred ownership of the MPT, we can update the
6079517SBill.Taylor@Sun.COM 	 * following fields for use in further operations on the MR.  Also, set
6089517SBill.Taylor@Sun.COM 	 * that this is an FMR region.
6099517SBill.Taylor@Sun.COM 	 */
6109517SBill.Taylor@Sun.COM 	mr->mr_mptrsrcp	  = mpt;
6119517SBill.Taylor@Sun.COM 	mr->mr_mttrsrcp	  = mtt;
61211972SBill.Taylor@Sun.COM 
6139517SBill.Taylor@Sun.COM 	mr->mr_mpt_type   = HERMON_MPT_DMPT;
6149517SBill.Taylor@Sun.COM 	mr->mr_pdhdl	  = pd;
6159517SBill.Taylor@Sun.COM 	mr->mr_rsrcp	  = rsrc;
6169517SBill.Taylor@Sun.COM 	mr->mr_is_fmr	  = 1;
6179517SBill.Taylor@Sun.COM 	mr->mr_lkey	   = hermon_mr_key_swap(mr->mr_lkey);
6189517SBill.Taylor@Sun.COM 	mr->mr_rkey	   = hermon_mr_key_swap(mr->mr_rkey);
61911972SBill.Taylor@Sun.COM 	mr->mr_mttaddr	   = mtt_addr;
6209517SBill.Taylor@Sun.COM 	(void) memcpy(&mr->mr_bindinfo, &bind, sizeof (hermon_bind_info_t));
6219517SBill.Taylor@Sun.COM 
62211972SBill.Taylor@Sun.COM 	/* initialize hr_addr for use during register/deregister/invalidate */
62311972SBill.Taylor@Sun.COM 	icm_table = &state->hs_icm[HERMON_DMPT];
62411972SBill.Taylor@Sun.COM 	rindx = mpt->hr_indx;
62511972SBill.Taylor@Sun.COM 	hermon_index(index1, index2, rindx, icm_table, i);
62611972SBill.Taylor@Sun.COM 	dma_info = icm_table->icm_dma[index1] + index2;
62711972SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpt))
62811972SBill.Taylor@Sun.COM 	mpt->hr_addr = (void *)((uintptr_t)(dma_info->vaddr + i * mpt->hr_len));
62911972SBill.Taylor@Sun.COM 
6309517SBill.Taylor@Sun.COM 	*mrhdl = mr;
6319517SBill.Taylor@Sun.COM 
6329517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
6339517SBill.Taylor@Sun.COM 
6349517SBill.Taylor@Sun.COM /*
6359517SBill.Taylor@Sun.COM  * The following is cleanup for all possible failure cases in this routine
6369517SBill.Taylor@Sun.COM  */
6379517SBill.Taylor@Sun.COM fmralloc_fail4:
6389517SBill.Taylor@Sun.COM 	kmem_free(mtt, sizeof (hermon_rsrc_t) * nummtt);
6399517SBill.Taylor@Sun.COM fmralloc_fail3:
6409517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &rsrc);
6419517SBill.Taylor@Sun.COM fmralloc_fail2:
6429517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &mpt);
6439517SBill.Taylor@Sun.COM fmralloc_fail1:
6449517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_dec(pd);
6459517SBill.Taylor@Sun.COM fmralloc_fail:
6469517SBill.Taylor@Sun.COM 	return (status);
6479517SBill.Taylor@Sun.COM }
6489517SBill.Taylor@Sun.COM 
64911972SBill.Taylor@Sun.COM 
6509517SBill.Taylor@Sun.COM /*
6519517SBill.Taylor@Sun.COM  * hermon_mr_register_physical_fmr()
6529517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
6539517SBill.Taylor@Sun.COM  */
6549517SBill.Taylor@Sun.COM /*ARGSUSED*/
6559517SBill.Taylor@Sun.COM int
hermon_mr_register_physical_fmr(hermon_state_t * state,ibt_pmr_attr_t * mem_pattr_p,hermon_mrhdl_t mr,ibt_pmr_desc_t * mem_desc_p)6569517SBill.Taylor@Sun.COM hermon_mr_register_physical_fmr(hermon_state_t *state,
6579517SBill.Taylor@Sun.COM     ibt_pmr_attr_t *mem_pattr_p, hermon_mrhdl_t mr, ibt_pmr_desc_t *mem_desc_p)
6589517SBill.Taylor@Sun.COM {
6599517SBill.Taylor@Sun.COM 	hermon_rsrc_t		*mpt;
6609517SBill.Taylor@Sun.COM 	uint64_t		*mpt_table;
6619517SBill.Taylor@Sun.COM 	int			status;
66211972SBill.Taylor@Sun.COM 	uint32_t		key;
6639517SBill.Taylor@Sun.COM 
6649517SBill.Taylor@Sun.COM 	mutex_enter(&mr->mr_lock);
6659517SBill.Taylor@Sun.COM 	mpt = mr->mr_mptrsrcp;
6669517SBill.Taylor@Sun.COM 	mpt_table = (uint64_t *)mpt->hr_addr;
6679517SBill.Taylor@Sun.COM 
6689517SBill.Taylor@Sun.COM 	/* Write MPT status to SW bit */
66911972SBill.Taylor@Sun.COM 	*(uint8_t *)mpt_table = 0xF0;
67011972SBill.Taylor@Sun.COM 
67111972SBill.Taylor@Sun.COM 	membar_producer();
6729517SBill.Taylor@Sun.COM 
6739517SBill.Taylor@Sun.COM 	/*
6749517SBill.Taylor@Sun.COM 	 * Write the mapped addresses into the MTT entries.  FMR needs to do
6759517SBill.Taylor@Sun.COM 	 * this a little differently, so we call the fmr specific fast mtt
6769517SBill.Taylor@Sun.COM 	 * write here.
6779517SBill.Taylor@Sun.COM 	 */
67811972SBill.Taylor@Sun.COM 	status = hermon_mr_fast_mtt_write_fmr(state, mr->mr_mttrsrcp,
67911972SBill.Taylor@Sun.COM 	    mem_pattr_p, mr->mr_logmttpgsz);
6809517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
6819517SBill.Taylor@Sun.COM 		mutex_exit(&mr->mr_lock);
6829517SBill.Taylor@Sun.COM 		status = ibc_get_ci_failure(0);
6839517SBill.Taylor@Sun.COM 		goto fmr_reg_fail1;
6849517SBill.Taylor@Sun.COM 	}
6859517SBill.Taylor@Sun.COM 
6869517SBill.Taylor@Sun.COM 	/*
6879517SBill.Taylor@Sun.COM 	 * Calculate keys (Lkey, Rkey) from MPT index.  Each key is formed
6889517SBill.Taylor@Sun.COM 	 * from a certain number of "constrained" bits (the least significant
6899517SBill.Taylor@Sun.COM 	 * bits) and some number of "unconstrained" bits.  The constrained
6909517SBill.Taylor@Sun.COM 	 * bits must be set to the index of the entry in the MPT table, but
6919517SBill.Taylor@Sun.COM 	 * the unconstrained bits can be set to any value we wish.  Note:
6929517SBill.Taylor@Sun.COM 	 * if no remote access is required, then the RKey value is not filled
6939517SBill.Taylor@Sun.COM 	 * in.  Otherwise both Rkey and LKey are given the same value.
6949517SBill.Taylor@Sun.COM 	 */
69511972SBill.Taylor@Sun.COM 	key = mpt->hr_indx | (mr->mr_fmr_key++ << HERMON_MEMKEY_SHIFT);
69611972SBill.Taylor@Sun.COM 	mr->mr_lkey = mr->mr_rkey = hermon_mr_key_swap(key);
6979517SBill.Taylor@Sun.COM 
6989517SBill.Taylor@Sun.COM 	/* write mem key value */
69911972SBill.Taylor@Sun.COM 	*(uint32_t *)&mpt_table[1] = htonl(key);
7009517SBill.Taylor@Sun.COM 
7019517SBill.Taylor@Sun.COM 	/* write length value */
70211972SBill.Taylor@Sun.COM 	mpt_table[3] = htonll(mem_pattr_p->pmr_len);
7039517SBill.Taylor@Sun.COM 
7049517SBill.Taylor@Sun.COM 	/* write start addr value */
70511972SBill.Taylor@Sun.COM 	mpt_table[2] = htonll(mem_pattr_p->pmr_iova);
7069517SBill.Taylor@Sun.COM 
7079517SBill.Taylor@Sun.COM 	/* write lkey value */
70811972SBill.Taylor@Sun.COM 	*(uint32_t *)&mpt_table[4] = htonl(key);
70911972SBill.Taylor@Sun.COM 
71011972SBill.Taylor@Sun.COM 	membar_producer();
7119517SBill.Taylor@Sun.COM 
7129517SBill.Taylor@Sun.COM 	/* Write MPT status to HW bit */
71311972SBill.Taylor@Sun.COM 	*(uint8_t *)mpt_table = 0x00;
7149517SBill.Taylor@Sun.COM 
7159517SBill.Taylor@Sun.COM 	/* Fill in return parameters */
7169517SBill.Taylor@Sun.COM 	mem_desc_p->pmd_lkey = mr->mr_lkey;
7179517SBill.Taylor@Sun.COM 	mem_desc_p->pmd_rkey = mr->mr_rkey;
7189517SBill.Taylor@Sun.COM 	mem_desc_p->pmd_iova = mem_pattr_p->pmr_iova;
7199517SBill.Taylor@Sun.COM 	mem_desc_p->pmd_phys_buf_list_sz = mem_pattr_p->pmr_len;
7209517SBill.Taylor@Sun.COM 
7219517SBill.Taylor@Sun.COM 	/* Fill in MR bindinfo struct for later sync or query operations */
7229517SBill.Taylor@Sun.COM 	mr->mr_bindinfo.bi_addr = mem_pattr_p->pmr_iova;
7239517SBill.Taylor@Sun.COM 	mr->mr_bindinfo.bi_flags = mem_pattr_p->pmr_flags & IBT_MR_NONCOHERENT;
7249517SBill.Taylor@Sun.COM 
7259517SBill.Taylor@Sun.COM 	mutex_exit(&mr->mr_lock);
7269517SBill.Taylor@Sun.COM 
7279517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
7289517SBill.Taylor@Sun.COM 
7299517SBill.Taylor@Sun.COM fmr_reg_fail1:
7309517SBill.Taylor@Sun.COM 	/*
7319517SBill.Taylor@Sun.COM 	 * Note, we fail here, and purposely leave the memory ownership in
7329517SBill.Taylor@Sun.COM 	 * software.  The memory tables may be corrupt, so we leave the region
7339517SBill.Taylor@Sun.COM 	 * unregistered.
7349517SBill.Taylor@Sun.COM 	 */
73511972SBill.Taylor@Sun.COM 	return (status);
7369517SBill.Taylor@Sun.COM }
7379517SBill.Taylor@Sun.COM 
7389517SBill.Taylor@Sun.COM 
7399517SBill.Taylor@Sun.COM /*
7409517SBill.Taylor@Sun.COM  * hermon_mr_deregister()
7419517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
7429517SBill.Taylor@Sun.COM  */
7439517SBill.Taylor@Sun.COM /* ARGSUSED */
7449517SBill.Taylor@Sun.COM int
hermon_mr_deregister(hermon_state_t * state,hermon_mrhdl_t * mrhdl,uint_t level,uint_t sleep)7459517SBill.Taylor@Sun.COM hermon_mr_deregister(hermon_state_t *state, hermon_mrhdl_t *mrhdl, uint_t level,
7469517SBill.Taylor@Sun.COM     uint_t sleep)
7479517SBill.Taylor@Sun.COM {
7489517SBill.Taylor@Sun.COM 	hermon_rsrc_t		*mpt, *mtt, *rsrc, *mtt_refcnt;
7499517SBill.Taylor@Sun.COM 	hermon_umap_db_entry_t	*umapdb;
7509517SBill.Taylor@Sun.COM 	hermon_pdhdl_t		pd;
7519517SBill.Taylor@Sun.COM 	hermon_mrhdl_t		mr;
7529517SBill.Taylor@Sun.COM 	hermon_bind_info_t	*bind;
7539517SBill.Taylor@Sun.COM 	uint64_t		value;
7549517SBill.Taylor@Sun.COM 	int			status;
7559517SBill.Taylor@Sun.COM 	uint_t			shared_mtt;
7569517SBill.Taylor@Sun.COM 
7579517SBill.Taylor@Sun.COM 	/*
7589517SBill.Taylor@Sun.COM 	 * Check the sleep flag.  Ensure that it is consistent with the
7599517SBill.Taylor@Sun.COM 	 * current thread context (i.e. if we are currently in the interrupt
7609517SBill.Taylor@Sun.COM 	 * context, then we shouldn't be attempting to sleep).
7619517SBill.Taylor@Sun.COM 	 */
7629517SBill.Taylor@Sun.COM 	if ((sleep == HERMON_SLEEP) &&
7639517SBill.Taylor@Sun.COM 	    (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
7649517SBill.Taylor@Sun.COM 		status = IBT_INVALID_PARAM;
7659517SBill.Taylor@Sun.COM 		return (status);
7669517SBill.Taylor@Sun.COM 	}
7679517SBill.Taylor@Sun.COM 
7689517SBill.Taylor@Sun.COM 	/*
7699517SBill.Taylor@Sun.COM 	 * Pull all the necessary information from the Hermon Memory Region
7709517SBill.Taylor@Sun.COM 	 * handle.  This is necessary here because the resource for the
7719517SBill.Taylor@Sun.COM 	 * MR handle is going to be freed up as part of the this
7729517SBill.Taylor@Sun.COM 	 * deregistration
7739517SBill.Taylor@Sun.COM 	 */
7749517SBill.Taylor@Sun.COM 	mr	= *mrhdl;
7759517SBill.Taylor@Sun.COM 	mutex_enter(&mr->mr_lock);
7769517SBill.Taylor@Sun.COM 	mpt	= mr->mr_mptrsrcp;
7779517SBill.Taylor@Sun.COM 	mtt	= mr->mr_mttrsrcp;
7789517SBill.Taylor@Sun.COM 	mtt_refcnt = mr->mr_mttrefcntp;
7799517SBill.Taylor@Sun.COM 	rsrc	= mr->mr_rsrcp;
7809517SBill.Taylor@Sun.COM 	pd	= mr->mr_pdhdl;
7819517SBill.Taylor@Sun.COM 	bind	= &mr->mr_bindinfo;
7829517SBill.Taylor@Sun.COM 
7839517SBill.Taylor@Sun.COM 	/*
7849517SBill.Taylor@Sun.COM 	 * Check here if the memory region is really an FMR.  If so, this is a
7859517SBill.Taylor@Sun.COM 	 * bad thing and we shouldn't be here.  Return failure.
7869517SBill.Taylor@Sun.COM 	 */
7879517SBill.Taylor@Sun.COM 	if (mr->mr_is_fmr) {
7889517SBill.Taylor@Sun.COM 		mutex_exit(&mr->mr_lock);
7899517SBill.Taylor@Sun.COM 		return (IBT_INVALID_PARAM);
7909517SBill.Taylor@Sun.COM 	}
7919517SBill.Taylor@Sun.COM 
7929517SBill.Taylor@Sun.COM 	/*
7939517SBill.Taylor@Sun.COM 	 * Check here to see if the memory region has already been partially
7949517SBill.Taylor@Sun.COM 	 * deregistered as a result of the hermon_umap_umemlock_cb() callback.
7959517SBill.Taylor@Sun.COM 	 * If so, then jump to the end and free the remaining resources.
7969517SBill.Taylor@Sun.COM 	 */
7979517SBill.Taylor@Sun.COM 	if ((mr->mr_is_umem) && (mr->mr_umemcookie == NULL)) {
7989517SBill.Taylor@Sun.COM 		goto mrdereg_finish_cleanup;
7999517SBill.Taylor@Sun.COM 	}
80011972SBill.Taylor@Sun.COM 	if (hermon_rdma_debug & 0x4)
80111972SBill.Taylor@Sun.COM 		IBTF_DPRINTF_L2("mr", "dereg: mr %p  key %x",
80211972SBill.Taylor@Sun.COM 		    mr, mr->mr_rkey);
8039517SBill.Taylor@Sun.COM 
8049517SBill.Taylor@Sun.COM 	/*
8059517SBill.Taylor@Sun.COM 	 * We must drop the "mr_lock" here to ensure that both SLEEP and
8069517SBill.Taylor@Sun.COM 	 * NOSLEEP calls into the firmware work as expected.  Also, if two
8079517SBill.Taylor@Sun.COM 	 * threads are attemping to access this MR (via de-register,
8089517SBill.Taylor@Sun.COM 	 * re-register, or otherwise), then we allow the firmware to enforce
8099517SBill.Taylor@Sun.COM 	 * the checking, that only one deregister is valid.
8109517SBill.Taylor@Sun.COM 	 */
8119517SBill.Taylor@Sun.COM 	mutex_exit(&mr->mr_lock);
8129517SBill.Taylor@Sun.COM 
8139517SBill.Taylor@Sun.COM 	/*
8149517SBill.Taylor@Sun.COM 	 * Reclaim MPT entry from hardware (if necessary).  Since the
8159517SBill.Taylor@Sun.COM 	 * hermon_mr_deregister() routine is used in the memory region
8169517SBill.Taylor@Sun.COM 	 * reregistration process as well, it is possible that we will
8179517SBill.Taylor@Sun.COM 	 * not always wish to reclaim ownership of the MPT.  Check the
8189517SBill.Taylor@Sun.COM 	 * "level" arg and, if necessary, attempt to reclaim it.  If
8199517SBill.Taylor@Sun.COM 	 * the ownership transfer fails for any reason, we check to see
8209517SBill.Taylor@Sun.COM 	 * what command status was returned from the hardware.  The only
8219517SBill.Taylor@Sun.COM 	 * "expected" error status is the one that indicates an attempt to
8229517SBill.Taylor@Sun.COM 	 * deregister a memory region that has memory windows bound to it
8239517SBill.Taylor@Sun.COM 	 */
8249517SBill.Taylor@Sun.COM 	if (level >= HERMON_MR_DEREG_ALL) {
8259517SBill.Taylor@Sun.COM 		if (mr->mr_mpt_type >= HERMON_MPT_DMPT) {
8269517SBill.Taylor@Sun.COM 			status = hermon_cmn_ownership_cmd_post(state, HW2SW_MPT,
8279517SBill.Taylor@Sun.COM 			    NULL, 0, mpt->hr_indx, sleep);
8289517SBill.Taylor@Sun.COM 			if (status != HERMON_CMD_SUCCESS) {
8299517SBill.Taylor@Sun.COM 				if (status == HERMON_CMD_REG_BOUND) {
8309517SBill.Taylor@Sun.COM 					return (IBT_MR_IN_USE);
8319517SBill.Taylor@Sun.COM 				} else {
8329517SBill.Taylor@Sun.COM 					cmn_err(CE_CONT, "Hermon: HW2SW_MPT "
8339517SBill.Taylor@Sun.COM 					    "command failed: %08x\n", status);
8349517SBill.Taylor@Sun.COM 					if (status ==
8359517SBill.Taylor@Sun.COM 					    HERMON_CMD_INVALID_STATUS) {
8369517SBill.Taylor@Sun.COM 						hermon_fm_ereport(state,
8379517SBill.Taylor@Sun.COM 						    HCA_SYS_ERR,
8389517SBill.Taylor@Sun.COM 						    DDI_SERVICE_LOST);
8399517SBill.Taylor@Sun.COM 					}
8409517SBill.Taylor@Sun.COM 					return (IBT_INVALID_PARAM);
8419517SBill.Taylor@Sun.COM 				}
8429517SBill.Taylor@Sun.COM 			}
8439517SBill.Taylor@Sun.COM 		}
8449517SBill.Taylor@Sun.COM 	}
8459517SBill.Taylor@Sun.COM 
8469517SBill.Taylor@Sun.COM 	/*
8479517SBill.Taylor@Sun.COM 	 * Re-grab the mr_lock here.  Since further access to the protected
8489517SBill.Taylor@Sun.COM 	 * 'mr' structure is needed, and we would have returned previously for
8499517SBill.Taylor@Sun.COM 	 * the multiple deregistration case, we can safely grab the lock here.
8509517SBill.Taylor@Sun.COM 	 */
8519517SBill.Taylor@Sun.COM 	mutex_enter(&mr->mr_lock);
8529517SBill.Taylor@Sun.COM 
8539517SBill.Taylor@Sun.COM 	/*
8549517SBill.Taylor@Sun.COM 	 * If the memory had come from userland, then we do a lookup in the
8559517SBill.Taylor@Sun.COM 	 * "userland resources database".  On success, we free the entry, call
8569517SBill.Taylor@Sun.COM 	 * ddi_umem_unlock(), and continue the cleanup.  On failure (which is
8579517SBill.Taylor@Sun.COM 	 * an indication that the umem_lockmemory() callback has called
8589517SBill.Taylor@Sun.COM 	 * hermon_mr_deregister()), we call ddi_umem_unlock() and invalidate
8599517SBill.Taylor@Sun.COM 	 * the "mr_umemcookie" field in the MR handle (this will be used
8609517SBill.Taylor@Sun.COM 	 * later to detect that only partial cleaup still remains to be done
8619517SBill.Taylor@Sun.COM 	 * on the MR handle).
8629517SBill.Taylor@Sun.COM 	 */
8639517SBill.Taylor@Sun.COM 	if (mr->mr_is_umem) {
8649517SBill.Taylor@Sun.COM 		status = hermon_umap_db_find(state->hs_instance,
8659517SBill.Taylor@Sun.COM 		    (uint64_t)(uintptr_t)mr->mr_umemcookie,
8669517SBill.Taylor@Sun.COM 		    MLNX_UMAP_MRMEM_RSRC, &value, HERMON_UMAP_DB_REMOVE,
8679517SBill.Taylor@Sun.COM 		    &umapdb);
8689517SBill.Taylor@Sun.COM 		if (status == DDI_SUCCESS) {
8699517SBill.Taylor@Sun.COM 			hermon_umap_db_free(umapdb);
8709517SBill.Taylor@Sun.COM 			ddi_umem_unlock(mr->mr_umemcookie);
8719517SBill.Taylor@Sun.COM 		} else {
8729517SBill.Taylor@Sun.COM 			ddi_umem_unlock(mr->mr_umemcookie);
8739517SBill.Taylor@Sun.COM 			mr->mr_umemcookie = NULL;
8749517SBill.Taylor@Sun.COM 		}
8759517SBill.Taylor@Sun.COM 	}
8769517SBill.Taylor@Sun.COM 
877*12965SWilliam.Taylor@Oracle.COM 	/* mtt_refcnt is NULL in the case of hermon_dma_mr_register() */
878*12965SWilliam.Taylor@Oracle.COM 	if (mtt_refcnt != NULL) {
879*12965SWilliam.Taylor@Oracle.COM 		/*
880*12965SWilliam.Taylor@Oracle.COM 		 * Decrement the MTT reference count.  Since the MTT resource
881*12965SWilliam.Taylor@Oracle.COM 		 * may be shared between multiple memory regions (as a result
882*12965SWilliam.Taylor@Oracle.COM 		 * of a "RegisterSharedMR" verb) it is important that we not
883*12965SWilliam.Taylor@Oracle.COM 		 * free up or unbind resources prematurely.  If it's not shared
884*12965SWilliam.Taylor@Oracle.COM 		 * (as indicated by the return status), then free the resource.
885*12965SWilliam.Taylor@Oracle.COM 		 */
886*12965SWilliam.Taylor@Oracle.COM 		shared_mtt = hermon_mtt_refcnt_dec(mtt_refcnt);
887*12965SWilliam.Taylor@Oracle.COM 		if (!shared_mtt) {
888*12965SWilliam.Taylor@Oracle.COM 			hermon_rsrc_free(state, &mtt_refcnt);
8899517SBill.Taylor@Sun.COM 		}
890*12965SWilliam.Taylor@Oracle.COM 
891*12965SWilliam.Taylor@Oracle.COM 		/*
892*12965SWilliam.Taylor@Oracle.COM 		 * Free up the MTT entries and unbind the memory.  Here,
893*12965SWilliam.Taylor@Oracle.COM 		 * as above, we attempt to free these resources only if
894*12965SWilliam.Taylor@Oracle.COM 		 * it is appropriate to do so.
895*12965SWilliam.Taylor@Oracle.COM 		 * Note, 'bind' is NULL in the alloc_lkey case.
896*12965SWilliam.Taylor@Oracle.COM 		 */
897*12965SWilliam.Taylor@Oracle.COM 		if (!shared_mtt) {
898*12965SWilliam.Taylor@Oracle.COM 			if (level >= HERMON_MR_DEREG_NO_HW2SW_MPT) {
899*12965SWilliam.Taylor@Oracle.COM 				hermon_mr_mem_unbind(state, bind);
900*12965SWilliam.Taylor@Oracle.COM 			}
901*12965SWilliam.Taylor@Oracle.COM 			hermon_rsrc_free(state, &mtt);
902*12965SWilliam.Taylor@Oracle.COM 		}
9039517SBill.Taylor@Sun.COM 	}
9049517SBill.Taylor@Sun.COM 
9059517SBill.Taylor@Sun.COM 	/*
9069517SBill.Taylor@Sun.COM 	 * If the MR handle has been invalidated, then drop the
9079517SBill.Taylor@Sun.COM 	 * lock and return success.  Note: This only happens because
9089517SBill.Taylor@Sun.COM 	 * the umem_lockmemory() callback has been triggered.  The
9099517SBill.Taylor@Sun.COM 	 * cleanup here is partial, and further cleanup (in a
9109517SBill.Taylor@Sun.COM 	 * subsequent hermon_mr_deregister() call) will be necessary.
9119517SBill.Taylor@Sun.COM 	 */
9129517SBill.Taylor@Sun.COM 	if ((mr->mr_is_umem) && (mr->mr_umemcookie == NULL)) {
9139517SBill.Taylor@Sun.COM 		mutex_exit(&mr->mr_lock);
9149517SBill.Taylor@Sun.COM 		return (DDI_SUCCESS);
9159517SBill.Taylor@Sun.COM 	}
9169517SBill.Taylor@Sun.COM 
9179517SBill.Taylor@Sun.COM mrdereg_finish_cleanup:
9189517SBill.Taylor@Sun.COM 	mutex_exit(&mr->mr_lock);
9199517SBill.Taylor@Sun.COM 
9209517SBill.Taylor@Sun.COM 	/* Free the Hermon Memory Region handle */
9219517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &rsrc);
9229517SBill.Taylor@Sun.COM 
9239517SBill.Taylor@Sun.COM 	/* Free up the MPT entry resource */
9249517SBill.Taylor@Sun.COM 	if (mpt != NULL)
9259517SBill.Taylor@Sun.COM 		hermon_rsrc_free(state, &mpt);
9269517SBill.Taylor@Sun.COM 
9279517SBill.Taylor@Sun.COM 	/* Decrement the reference count on the protection domain (PD) */
9289517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_dec(pd);
9299517SBill.Taylor@Sun.COM 
9309517SBill.Taylor@Sun.COM 	/* Set the mrhdl pointer to NULL and return success */
9319517SBill.Taylor@Sun.COM 	*mrhdl = NULL;
9329517SBill.Taylor@Sun.COM 
9339517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
9349517SBill.Taylor@Sun.COM }
9359517SBill.Taylor@Sun.COM 
9369517SBill.Taylor@Sun.COM /*
9379517SBill.Taylor@Sun.COM  * hermon_mr_dealloc_fmr()
9389517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
9399517SBill.Taylor@Sun.COM  */
9409517SBill.Taylor@Sun.COM /* ARGSUSED */
9419517SBill.Taylor@Sun.COM int
hermon_mr_dealloc_fmr(hermon_state_t * state,hermon_mrhdl_t * mrhdl)9429517SBill.Taylor@Sun.COM hermon_mr_dealloc_fmr(hermon_state_t *state, hermon_mrhdl_t *mrhdl)
9439517SBill.Taylor@Sun.COM {
9449517SBill.Taylor@Sun.COM 	hermon_rsrc_t		*mpt, *mtt, *rsrc;
9459517SBill.Taylor@Sun.COM 	hermon_pdhdl_t		pd;
9469517SBill.Taylor@Sun.COM 	hermon_mrhdl_t		mr;
9479517SBill.Taylor@Sun.COM 
9489517SBill.Taylor@Sun.COM 	/*
9499517SBill.Taylor@Sun.COM 	 * Pull all the necessary information from the Hermon Memory Region
9509517SBill.Taylor@Sun.COM 	 * handle.  This is necessary here because the resource for the
9519517SBill.Taylor@Sun.COM 	 * MR handle is going to be freed up as part of the this
9529517SBill.Taylor@Sun.COM 	 * deregistration
9539517SBill.Taylor@Sun.COM 	 */
9549517SBill.Taylor@Sun.COM 	mr	= *mrhdl;
9559517SBill.Taylor@Sun.COM 	mutex_enter(&mr->mr_lock);
9569517SBill.Taylor@Sun.COM 	mpt	= mr->mr_mptrsrcp;
9579517SBill.Taylor@Sun.COM 	mtt	= mr->mr_mttrsrcp;
9589517SBill.Taylor@Sun.COM 	rsrc	= mr->mr_rsrcp;
9599517SBill.Taylor@Sun.COM 	pd	= mr->mr_pdhdl;
9609517SBill.Taylor@Sun.COM 	mutex_exit(&mr->mr_lock);
9619517SBill.Taylor@Sun.COM 
9629517SBill.Taylor@Sun.COM 	/* Free the MTT entries */
9639517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &mtt);
9649517SBill.Taylor@Sun.COM 
9659517SBill.Taylor@Sun.COM 	/* Free the Hermon Memory Region handle */
9669517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &rsrc);
9679517SBill.Taylor@Sun.COM 
9689517SBill.Taylor@Sun.COM 	/* Free up the MPT entry resource */
9699517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &mpt);
9709517SBill.Taylor@Sun.COM 
9719517SBill.Taylor@Sun.COM 	/* Decrement the reference count on the protection domain (PD) */
9729517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_dec(pd);
9739517SBill.Taylor@Sun.COM 
9749517SBill.Taylor@Sun.COM 	/* Set the mrhdl pointer to NULL and return success */
9759517SBill.Taylor@Sun.COM 	*mrhdl = NULL;
9769517SBill.Taylor@Sun.COM 
9779517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
9789517SBill.Taylor@Sun.COM }
9799517SBill.Taylor@Sun.COM 
9809517SBill.Taylor@Sun.COM 
9819517SBill.Taylor@Sun.COM /*
9829517SBill.Taylor@Sun.COM  * hermon_mr_query()
9839517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
9849517SBill.Taylor@Sun.COM  */
9859517SBill.Taylor@Sun.COM /* ARGSUSED */
9869517SBill.Taylor@Sun.COM int
hermon_mr_query(hermon_state_t * state,hermon_mrhdl_t mr,ibt_mr_query_attr_t * attr)9879517SBill.Taylor@Sun.COM hermon_mr_query(hermon_state_t *state, hermon_mrhdl_t mr,
9889517SBill.Taylor@Sun.COM     ibt_mr_query_attr_t *attr)
9899517SBill.Taylor@Sun.COM {
99011972SBill.Taylor@Sun.COM 	int			status;
99111972SBill.Taylor@Sun.COM 	hermon_hw_dmpt_t	mpt_entry;
99211972SBill.Taylor@Sun.COM 	uint32_t		lkey;
99311972SBill.Taylor@Sun.COM 
9949517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*attr))
9959517SBill.Taylor@Sun.COM 
9969517SBill.Taylor@Sun.COM 	mutex_enter(&mr->mr_lock);
9979517SBill.Taylor@Sun.COM 
9989517SBill.Taylor@Sun.COM 	/*
9999517SBill.Taylor@Sun.COM 	 * Check here to see if the memory region has already been partially
10009517SBill.Taylor@Sun.COM 	 * deregistered as a result of a hermon_umap_umemlock_cb() callback.
10019517SBill.Taylor@Sun.COM 	 * If so, this is an error, return failure.
10029517SBill.Taylor@Sun.COM 	 */
10039517SBill.Taylor@Sun.COM 	if ((mr->mr_is_umem) && (mr->mr_umemcookie == NULL)) {
10049517SBill.Taylor@Sun.COM 		mutex_exit(&mr->mr_lock);
10059517SBill.Taylor@Sun.COM 		return (IBT_MR_HDL_INVALID);
10069517SBill.Taylor@Sun.COM 	}
10079517SBill.Taylor@Sun.COM 
100811972SBill.Taylor@Sun.COM 	status = hermon_cmn_query_cmd_post(state, QUERY_MPT, 0,
100911972SBill.Taylor@Sun.COM 	    mr->mr_lkey >> 8, &mpt_entry, sizeof (hermon_hw_dmpt_t),
101011972SBill.Taylor@Sun.COM 	    HERMON_NOSLEEP);
101111972SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
101211972SBill.Taylor@Sun.COM 		cmn_err(CE_CONT, "Hermon: QUERY_MPT failed: status %x", status);
101311972SBill.Taylor@Sun.COM 		mutex_exit(&mr->mr_lock);
101411972SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
101511972SBill.Taylor@Sun.COM 	}
101611972SBill.Taylor@Sun.COM 
101711972SBill.Taylor@Sun.COM 	/* Update the mr sw struct from the hw struct. */
101811972SBill.Taylor@Sun.COM 	lkey = mpt_entry.mem_key;
101911972SBill.Taylor@Sun.COM 	mr->mr_lkey = mr->mr_rkey = (lkey >> 8) | (lkey << 24);
102011972SBill.Taylor@Sun.COM 	mr->mr_bindinfo.bi_addr = mpt_entry.start_addr;
102111972SBill.Taylor@Sun.COM 	mr->mr_bindinfo.bi_len = mpt_entry.reg_win_len;
102211972SBill.Taylor@Sun.COM 	mr->mr_accflag = (mr->mr_accflag & IBT_MR_RO_DISABLED) |
102311972SBill.Taylor@Sun.COM 	    (mpt_entry.lw ? IBT_MR_LOCAL_WRITE : 0) |
102411972SBill.Taylor@Sun.COM 	    (mpt_entry.rr ? IBT_MR_REMOTE_READ : 0) |
102511972SBill.Taylor@Sun.COM 	    (mpt_entry.rw ? IBT_MR_REMOTE_WRITE : 0) |
102611972SBill.Taylor@Sun.COM 	    (mpt_entry.atomic ? IBT_MR_REMOTE_ATOMIC : 0) |
102711972SBill.Taylor@Sun.COM 	    (mpt_entry.en_bind ? IBT_MR_WINDOW_BIND : 0);
102811972SBill.Taylor@Sun.COM 	mr->mr_mttaddr = ((uint64_t)mpt_entry.mtt_addr_h << 32) |
102911972SBill.Taylor@Sun.COM 	    (mpt_entry.mtt_addr_l << 3);
103011972SBill.Taylor@Sun.COM 	mr->mr_logmttpgsz = mpt_entry.entity_sz;
103111972SBill.Taylor@Sun.COM 
10329517SBill.Taylor@Sun.COM 	/* Fill in the queried attributes */
103311972SBill.Taylor@Sun.COM 	attr->mr_lkey_state =
103411972SBill.Taylor@Sun.COM 	    (mpt_entry.status == HERMON_MPT_FREE) ? IBT_KEY_FREE :
103511972SBill.Taylor@Sun.COM 	    (mpt_entry.status == HERMON_MPT_SW_OWNERSHIP) ? IBT_KEY_INVALID :
103611972SBill.Taylor@Sun.COM 	    IBT_KEY_VALID;
103711972SBill.Taylor@Sun.COM 	attr->mr_phys_buf_list_sz = mpt_entry.mtt_size;
10389517SBill.Taylor@Sun.COM 	attr->mr_attr_flags = mr->mr_accflag;
103911972SBill.Taylor@Sun.COM 	attr->mr_pd = (ibt_pd_hdl_t)mr->mr_pdhdl;
10409517SBill.Taylor@Sun.COM 
10419517SBill.Taylor@Sun.COM 	/* Fill in the "local" attributes */
10429517SBill.Taylor@Sun.COM 	attr->mr_lkey = (ibt_lkey_t)mr->mr_lkey;
10439517SBill.Taylor@Sun.COM 	attr->mr_lbounds.pb_addr = (ib_vaddr_t)mr->mr_bindinfo.bi_addr;
10449517SBill.Taylor@Sun.COM 	attr->mr_lbounds.pb_len  = (size_t)mr->mr_bindinfo.bi_len;
10459517SBill.Taylor@Sun.COM 
10469517SBill.Taylor@Sun.COM 	/*
10479517SBill.Taylor@Sun.COM 	 * Fill in the "remote" attributes (if necessary).  Note: the
10489517SBill.Taylor@Sun.COM 	 * remote attributes are only valid if the memory region has one
10499517SBill.Taylor@Sun.COM 	 * or more of the remote access flags set.
10509517SBill.Taylor@Sun.COM 	 */
10519517SBill.Taylor@Sun.COM 	if ((mr->mr_accflag & IBT_MR_REMOTE_READ) ||
10529517SBill.Taylor@Sun.COM 	    (mr->mr_accflag & IBT_MR_REMOTE_WRITE) ||
10539517SBill.Taylor@Sun.COM 	    (mr->mr_accflag & IBT_MR_REMOTE_ATOMIC)) {
10549517SBill.Taylor@Sun.COM 		attr->mr_rkey = (ibt_rkey_t)mr->mr_rkey;
10559517SBill.Taylor@Sun.COM 		attr->mr_rbounds.pb_addr = (ib_vaddr_t)mr->mr_bindinfo.bi_addr;
10569517SBill.Taylor@Sun.COM 		attr->mr_rbounds.pb_len  = (size_t)mr->mr_bindinfo.bi_len;
10579517SBill.Taylor@Sun.COM 	}
10589517SBill.Taylor@Sun.COM 
10599517SBill.Taylor@Sun.COM 	/*
10609517SBill.Taylor@Sun.COM 	 * If region is mapped for streaming (i.e. noncoherent), then set sync
10619517SBill.Taylor@Sun.COM 	 * is required
10629517SBill.Taylor@Sun.COM 	 */
10639517SBill.Taylor@Sun.COM 	attr->mr_sync_required = (mr->mr_bindinfo.bi_flags &
10649517SBill.Taylor@Sun.COM 	    IBT_MR_NONCOHERENT) ? B_TRUE : B_FALSE;
10659517SBill.Taylor@Sun.COM 
10669517SBill.Taylor@Sun.COM 	mutex_exit(&mr->mr_lock);
10679517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
10689517SBill.Taylor@Sun.COM }
10699517SBill.Taylor@Sun.COM 
10709517SBill.Taylor@Sun.COM 
10719517SBill.Taylor@Sun.COM /*
10729517SBill.Taylor@Sun.COM  * hermon_mr_reregister()
10739517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
10749517SBill.Taylor@Sun.COM  */
10759517SBill.Taylor@Sun.COM int
hermon_mr_reregister(hermon_state_t * state,hermon_mrhdl_t mr,hermon_pdhdl_t pd,ibt_mr_attr_t * mr_attr,hermon_mrhdl_t * mrhdl_new,hermon_mr_options_t * op)10769517SBill.Taylor@Sun.COM hermon_mr_reregister(hermon_state_t *state, hermon_mrhdl_t mr,
10779517SBill.Taylor@Sun.COM     hermon_pdhdl_t pd, ibt_mr_attr_t *mr_attr, hermon_mrhdl_t *mrhdl_new,
10789517SBill.Taylor@Sun.COM     hermon_mr_options_t *op)
10799517SBill.Taylor@Sun.COM {
10809517SBill.Taylor@Sun.COM 	hermon_bind_info_t	bind;
10819517SBill.Taylor@Sun.COM 	int			status;
10829517SBill.Taylor@Sun.COM 
10839517SBill.Taylor@Sun.COM 	/*
10849517SBill.Taylor@Sun.COM 	 * Fill in the "bind" struct.  This struct provides the majority
10859517SBill.Taylor@Sun.COM 	 * of the information that will be used to distinguish between an
10869517SBill.Taylor@Sun.COM 	 * "addr" binding (as is the case here) and a "buf" binding (see
10879517SBill.Taylor@Sun.COM 	 * below).  The "bind" struct is later passed to hermon_mr_mem_bind()
10889517SBill.Taylor@Sun.COM 	 * which does most of the "heavy lifting" for the Hermon memory
10899517SBill.Taylor@Sun.COM 	 * registration (and reregistration) routines.
10909517SBill.Taylor@Sun.COM 	 */
10919517SBill.Taylor@Sun.COM 	bind.bi_type  = HERMON_BINDHDL_VADDR;
10929517SBill.Taylor@Sun.COM 	bind.bi_addr  = mr_attr->mr_vaddr;
10939517SBill.Taylor@Sun.COM 	bind.bi_len   = mr_attr->mr_len;
10949517SBill.Taylor@Sun.COM 	bind.bi_as    = mr_attr->mr_as;
10959517SBill.Taylor@Sun.COM 	bind.bi_flags = mr_attr->mr_flags;
10969517SBill.Taylor@Sun.COM 	status = hermon_mr_common_rereg(state, mr, pd, &bind, mrhdl_new, op);
10979517SBill.Taylor@Sun.COM 	return (status);
10989517SBill.Taylor@Sun.COM }
10999517SBill.Taylor@Sun.COM 
11009517SBill.Taylor@Sun.COM 
11019517SBill.Taylor@Sun.COM /*
11029517SBill.Taylor@Sun.COM  * hermon_mr_reregister_buf()
11039517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
11049517SBill.Taylor@Sun.COM  */
11059517SBill.Taylor@Sun.COM int
hermon_mr_reregister_buf(hermon_state_t * state,hermon_mrhdl_t mr,hermon_pdhdl_t pd,ibt_smr_attr_t * mr_attr,struct buf * buf,hermon_mrhdl_t * mrhdl_new,hermon_mr_options_t * op)11069517SBill.Taylor@Sun.COM hermon_mr_reregister_buf(hermon_state_t *state, hermon_mrhdl_t mr,
11079517SBill.Taylor@Sun.COM     hermon_pdhdl_t pd, ibt_smr_attr_t *mr_attr, struct buf *buf,
11089517SBill.Taylor@Sun.COM     hermon_mrhdl_t *mrhdl_new, hermon_mr_options_t *op)
11099517SBill.Taylor@Sun.COM {
11109517SBill.Taylor@Sun.COM 	hermon_bind_info_t	bind;
11119517SBill.Taylor@Sun.COM 	int			status;
11129517SBill.Taylor@Sun.COM 
11139517SBill.Taylor@Sun.COM 	/*
11149517SBill.Taylor@Sun.COM 	 * Fill in the "bind" struct.  This struct provides the majority
11159517SBill.Taylor@Sun.COM 	 * of the information that will be used to distinguish between an
11169517SBill.Taylor@Sun.COM 	 * "addr" binding (see above) and a "buf" binding (as is the case
11179517SBill.Taylor@Sun.COM 	 * here).  The "bind" struct is later passed to hermon_mr_mem_bind()
11189517SBill.Taylor@Sun.COM 	 * which does most of the "heavy lifting" for the Hermon memory
11199517SBill.Taylor@Sun.COM 	 * registration routines.  Note: We have chosen to provide
11209517SBill.Taylor@Sun.COM 	 * "b_un.b_addr" as the IB address (when the IBT_MR_PHYS_IOVA flag is
11219517SBill.Taylor@Sun.COM 	 * not set).  It is not critical what value we choose here as it need
11229517SBill.Taylor@Sun.COM 	 * only be unique for the given RKey (which will happen by default),
11239517SBill.Taylor@Sun.COM 	 * so the choice here is somewhat arbitrary.
11249517SBill.Taylor@Sun.COM 	 */
11259517SBill.Taylor@Sun.COM 	bind.bi_type  = HERMON_BINDHDL_BUF;
11269517SBill.Taylor@Sun.COM 	bind.bi_buf   = buf;
11279517SBill.Taylor@Sun.COM 	if (mr_attr->mr_flags & IBT_MR_PHYS_IOVA) {
11289517SBill.Taylor@Sun.COM 		bind.bi_addr  = mr_attr->mr_vaddr;
11299517SBill.Taylor@Sun.COM 	} else {
11309517SBill.Taylor@Sun.COM 		bind.bi_addr  = (uint64_t)(uintptr_t)buf->b_un.b_addr;
11319517SBill.Taylor@Sun.COM 	}
11329517SBill.Taylor@Sun.COM 	bind.bi_len   = (uint64_t)buf->b_bcount;
11339517SBill.Taylor@Sun.COM 	bind.bi_flags = mr_attr->mr_flags;
11349517SBill.Taylor@Sun.COM 	bind.bi_as    = NULL;
11359517SBill.Taylor@Sun.COM 	status = hermon_mr_common_rereg(state, mr, pd, &bind, mrhdl_new, op);
11369517SBill.Taylor@Sun.COM 	return (status);
11379517SBill.Taylor@Sun.COM }
11389517SBill.Taylor@Sun.COM 
11399517SBill.Taylor@Sun.COM 
11409517SBill.Taylor@Sun.COM /*
11419517SBill.Taylor@Sun.COM  * hermon_mr_sync()
11429517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
11439517SBill.Taylor@Sun.COM  */
11449517SBill.Taylor@Sun.COM /* ARGSUSED */
11459517SBill.Taylor@Sun.COM int
hermon_mr_sync(hermon_state_t * state,ibt_mr_sync_t * mr_segs,size_t num_segs)11469517SBill.Taylor@Sun.COM hermon_mr_sync(hermon_state_t *state, ibt_mr_sync_t *mr_segs, size_t num_segs)
11479517SBill.Taylor@Sun.COM {
11489517SBill.Taylor@Sun.COM 	hermon_mrhdl_t		mrhdl;
11499517SBill.Taylor@Sun.COM 	uint64_t		seg_vaddr, seg_len, seg_end;
11509517SBill.Taylor@Sun.COM 	uint64_t		mr_start, mr_end;
11519517SBill.Taylor@Sun.COM 	uint_t			type;
11529517SBill.Taylor@Sun.COM 	int			status, i;
11539517SBill.Taylor@Sun.COM 
11549517SBill.Taylor@Sun.COM 	/* Process each of the ibt_mr_sync_t's */
11559517SBill.Taylor@Sun.COM 	for (i = 0; i < num_segs; i++) {
11569517SBill.Taylor@Sun.COM 		mrhdl = (hermon_mrhdl_t)mr_segs[i].ms_handle;
11579517SBill.Taylor@Sun.COM 
11589517SBill.Taylor@Sun.COM 		/* Check for valid memory region handle */
11599517SBill.Taylor@Sun.COM 		if (mrhdl == NULL) {
11609517SBill.Taylor@Sun.COM 			status = IBT_MR_HDL_INVALID;
11619517SBill.Taylor@Sun.COM 			goto mrsync_fail;
11629517SBill.Taylor@Sun.COM 		}
11639517SBill.Taylor@Sun.COM 
11649517SBill.Taylor@Sun.COM 		mutex_enter(&mrhdl->mr_lock);
11659517SBill.Taylor@Sun.COM 
11669517SBill.Taylor@Sun.COM 		/*
11679517SBill.Taylor@Sun.COM 		 * Check here to see if the memory region has already been
11689517SBill.Taylor@Sun.COM 		 * partially deregistered as a result of a
11699517SBill.Taylor@Sun.COM 		 * hermon_umap_umemlock_cb() callback.  If so, this is an
11709517SBill.Taylor@Sun.COM 		 * error, return failure.
11719517SBill.Taylor@Sun.COM 		 */
11729517SBill.Taylor@Sun.COM 		if ((mrhdl->mr_is_umem) && (mrhdl->mr_umemcookie == NULL)) {
11739517SBill.Taylor@Sun.COM 			mutex_exit(&mrhdl->mr_lock);
11749517SBill.Taylor@Sun.COM 			status = IBT_MR_HDL_INVALID;
11759517SBill.Taylor@Sun.COM 			goto mrsync_fail;
11769517SBill.Taylor@Sun.COM 		}
11779517SBill.Taylor@Sun.COM 
11789517SBill.Taylor@Sun.COM 		/* Check for valid bounds on sync request */
11799517SBill.Taylor@Sun.COM 		seg_vaddr = mr_segs[i].ms_vaddr;
11809517SBill.Taylor@Sun.COM 		seg_len	  = mr_segs[i].ms_len;
11819517SBill.Taylor@Sun.COM 		seg_end	  = seg_vaddr + seg_len - 1;
11829517SBill.Taylor@Sun.COM 		mr_start  = mrhdl->mr_bindinfo.bi_addr;
11839517SBill.Taylor@Sun.COM 		mr_end	  = mr_start + mrhdl->mr_bindinfo.bi_len - 1;
11849517SBill.Taylor@Sun.COM 		if ((seg_vaddr < mr_start) || (seg_vaddr > mr_end)) {
11859517SBill.Taylor@Sun.COM 			mutex_exit(&mrhdl->mr_lock);
11869517SBill.Taylor@Sun.COM 			status = IBT_MR_VA_INVALID;
11879517SBill.Taylor@Sun.COM 			goto mrsync_fail;
11889517SBill.Taylor@Sun.COM 		}
11899517SBill.Taylor@Sun.COM 		if ((seg_end < mr_start) || (seg_end > mr_end)) {
11909517SBill.Taylor@Sun.COM 			mutex_exit(&mrhdl->mr_lock);
11919517SBill.Taylor@Sun.COM 			status = IBT_MR_LEN_INVALID;
11929517SBill.Taylor@Sun.COM 			goto mrsync_fail;
11939517SBill.Taylor@Sun.COM 		}
11949517SBill.Taylor@Sun.COM 
11959517SBill.Taylor@Sun.COM 		/* Determine what type (i.e. direction) for sync */
11969517SBill.Taylor@Sun.COM 		if (mr_segs[i].ms_flags & IBT_SYNC_READ) {
11979517SBill.Taylor@Sun.COM 			type = DDI_DMA_SYNC_FORDEV;
11989517SBill.Taylor@Sun.COM 		} else if (mr_segs[i].ms_flags & IBT_SYNC_WRITE) {
11999517SBill.Taylor@Sun.COM 			type = DDI_DMA_SYNC_FORCPU;
12009517SBill.Taylor@Sun.COM 		} else {
12019517SBill.Taylor@Sun.COM 			mutex_exit(&mrhdl->mr_lock);
12029517SBill.Taylor@Sun.COM 			status = IBT_INVALID_PARAM;
12039517SBill.Taylor@Sun.COM 			goto mrsync_fail;
12049517SBill.Taylor@Sun.COM 		}
12059517SBill.Taylor@Sun.COM 
12069517SBill.Taylor@Sun.COM 		(void) ddi_dma_sync(mrhdl->mr_bindinfo.bi_dmahdl,
12079517SBill.Taylor@Sun.COM 		    (off_t)(seg_vaddr - mr_start), (size_t)seg_len, type);
12089517SBill.Taylor@Sun.COM 
12099517SBill.Taylor@Sun.COM 		mutex_exit(&mrhdl->mr_lock);
12109517SBill.Taylor@Sun.COM 	}
12119517SBill.Taylor@Sun.COM 
12129517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
12139517SBill.Taylor@Sun.COM 
12149517SBill.Taylor@Sun.COM mrsync_fail:
12159517SBill.Taylor@Sun.COM 	return (status);
12169517SBill.Taylor@Sun.COM }
12179517SBill.Taylor@Sun.COM 
12189517SBill.Taylor@Sun.COM 
12199517SBill.Taylor@Sun.COM /*
12209517SBill.Taylor@Sun.COM  * hermon_mw_alloc()
12219517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
12229517SBill.Taylor@Sun.COM  */
12239517SBill.Taylor@Sun.COM int
hermon_mw_alloc(hermon_state_t * state,hermon_pdhdl_t pd,ibt_mw_flags_t flags,hermon_mwhdl_t * mwhdl)12249517SBill.Taylor@Sun.COM hermon_mw_alloc(hermon_state_t *state, hermon_pdhdl_t pd, ibt_mw_flags_t flags,
12259517SBill.Taylor@Sun.COM     hermon_mwhdl_t *mwhdl)
12269517SBill.Taylor@Sun.COM {
12279517SBill.Taylor@Sun.COM 	hermon_rsrc_t		*mpt, *rsrc;
12289517SBill.Taylor@Sun.COM 	hermon_hw_dmpt_t		mpt_entry;
12299517SBill.Taylor@Sun.COM 	hermon_mwhdl_t		mw;
12309517SBill.Taylor@Sun.COM 	uint_t			sleep;
12319517SBill.Taylor@Sun.COM 	int			status;
12329517SBill.Taylor@Sun.COM 
12339517SBill.Taylor@Sun.COM 	if (state != NULL)	/* XXX - bogus test that is always TRUE */
12349517SBill.Taylor@Sun.COM 		return (IBT_INSUFF_RESOURCE);
12359517SBill.Taylor@Sun.COM 
12369517SBill.Taylor@Sun.COM 	/*
12379517SBill.Taylor@Sun.COM 	 * Check the sleep flag.  Ensure that it is consistent with the
12389517SBill.Taylor@Sun.COM 	 * current thread context (i.e. if we are currently in the interrupt
12399517SBill.Taylor@Sun.COM 	 * context, then we shouldn't be attempting to sleep).
12409517SBill.Taylor@Sun.COM 	 */
12419517SBill.Taylor@Sun.COM 	sleep = (flags & IBT_MW_NOSLEEP) ? HERMON_NOSLEEP : HERMON_SLEEP;
12429517SBill.Taylor@Sun.COM 	if ((sleep == HERMON_SLEEP) &&
12439517SBill.Taylor@Sun.COM 	    (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
12449517SBill.Taylor@Sun.COM 		status = IBT_INVALID_PARAM;
12459517SBill.Taylor@Sun.COM 		goto mwalloc_fail;
12469517SBill.Taylor@Sun.COM 	}
12479517SBill.Taylor@Sun.COM 
12489517SBill.Taylor@Sun.COM 	/* Increment the reference count on the protection domain (PD) */
12499517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_inc(pd);
12509517SBill.Taylor@Sun.COM 
12519517SBill.Taylor@Sun.COM 	/*
12529517SBill.Taylor@Sun.COM 	 * Allocate an MPT entry (for use as a memory window).  Since the
12539517SBill.Taylor@Sun.COM 	 * Hermon hardware uses the MPT entry for memory regions and for
12549517SBill.Taylor@Sun.COM 	 * memory windows, we will fill in this MPT with all the necessary
12559517SBill.Taylor@Sun.COM 	 * parameters for the memory window.  And then (just as we do for
12569517SBill.Taylor@Sun.COM 	 * memory regions) ownership will be passed to the hardware in the
12579517SBill.Taylor@Sun.COM 	 * final step below.  If we fail here, we must undo the protection
12589517SBill.Taylor@Sun.COM 	 * domain reference count.
12599517SBill.Taylor@Sun.COM 	 */
12609517SBill.Taylor@Sun.COM 	status = hermon_rsrc_alloc(state, HERMON_DMPT, 1, sleep, &mpt);
12619517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
12629517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
12639517SBill.Taylor@Sun.COM 		goto mwalloc_fail1;
12649517SBill.Taylor@Sun.COM 	}
12659517SBill.Taylor@Sun.COM 
12669517SBill.Taylor@Sun.COM 	/*
12679517SBill.Taylor@Sun.COM 	 * Allocate the software structure for tracking the memory window (i.e.
12689517SBill.Taylor@Sun.COM 	 * the Hermon Memory Window handle).  Note: This is actually the same
12699517SBill.Taylor@Sun.COM 	 * software structure used for tracking memory regions, but since many
12709517SBill.Taylor@Sun.COM 	 * of the same properties are needed, only a single structure is
12719517SBill.Taylor@Sun.COM 	 * necessary.  If we fail here, we must undo the protection domain
12729517SBill.Taylor@Sun.COM 	 * reference count and the previous resource allocation.
12739517SBill.Taylor@Sun.COM 	 */
12749517SBill.Taylor@Sun.COM 	status = hermon_rsrc_alloc(state, HERMON_MRHDL, 1, sleep, &rsrc);
12759517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
12769517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
12779517SBill.Taylor@Sun.COM 		goto mwalloc_fail2;
12789517SBill.Taylor@Sun.COM 	}
12799517SBill.Taylor@Sun.COM 	mw = (hermon_mwhdl_t)rsrc->hr_addr;
12809517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mw))
12819517SBill.Taylor@Sun.COM 
12829517SBill.Taylor@Sun.COM 	/*
12839517SBill.Taylor@Sun.COM 	 * Calculate an "unbound" RKey from MPT index.  In much the same way
12849517SBill.Taylor@Sun.COM 	 * as we do for memory regions (above), this key is constructed from
12859517SBill.Taylor@Sun.COM 	 * a "constrained" (which depends on the MPT index) and an
12869517SBill.Taylor@Sun.COM 	 * "unconstrained" portion (which may be arbitrarily chosen).
12879517SBill.Taylor@Sun.COM 	 */
12889517SBill.Taylor@Sun.COM 	mw->mr_rkey = hermon_mr_keycalc(mpt->hr_indx);
12899517SBill.Taylor@Sun.COM 
12909517SBill.Taylor@Sun.COM 	/*
12919517SBill.Taylor@Sun.COM 	 * Fill in the MPT entry.  This is the final step before passing
12929517SBill.Taylor@Sun.COM 	 * ownership of the MPT entry to the Hermon hardware.  We use all of
12939517SBill.Taylor@Sun.COM 	 * the information collected/calculated above to fill in the
12949517SBill.Taylor@Sun.COM 	 * requisite portions of the MPT.  Note: fewer entries in the MPT
12959517SBill.Taylor@Sun.COM 	 * entry are necessary to allocate a memory window.
12969517SBill.Taylor@Sun.COM 	 */
12979517SBill.Taylor@Sun.COM 	bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
12989517SBill.Taylor@Sun.COM 	mpt_entry.reg_win	= HERMON_MPT_IS_WINDOW;
12999517SBill.Taylor@Sun.COM 	mpt_entry.mem_key	= mw->mr_rkey;
13009517SBill.Taylor@Sun.COM 	mpt_entry.pd		= pd->pd_pdnum;
13019517SBill.Taylor@Sun.COM 	mpt_entry.lr		= 1;
13029517SBill.Taylor@Sun.COM 
13039517SBill.Taylor@Sun.COM 	/*
13049517SBill.Taylor@Sun.COM 	 * Write the MPT entry to hardware.  Lastly, we pass ownership of
13059517SBill.Taylor@Sun.COM 	 * the entry to the hardware.  Note: in general, this operation
13069517SBill.Taylor@Sun.COM 	 * shouldn't fail.  But if it does, we have to undo everything we've
13079517SBill.Taylor@Sun.COM 	 * done above before returning error.
13089517SBill.Taylor@Sun.COM 	 */
13099517SBill.Taylor@Sun.COM 	status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
13109517SBill.Taylor@Sun.COM 	    sizeof (hermon_hw_dmpt_t), mpt->hr_indx, sleep);
13119517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
13129517SBill.Taylor@Sun.COM 		cmn_err(CE_CONT, "Hermon: SW2HW_MPT command failed: %08x\n",
13139517SBill.Taylor@Sun.COM 		    status);
13149517SBill.Taylor@Sun.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
13159517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
13169517SBill.Taylor@Sun.COM 		}
13179517SBill.Taylor@Sun.COM 		status = ibc_get_ci_failure(0);
13189517SBill.Taylor@Sun.COM 		goto mwalloc_fail3;
13199517SBill.Taylor@Sun.COM 	}
13209517SBill.Taylor@Sun.COM 
13219517SBill.Taylor@Sun.COM 	/*
13229517SBill.Taylor@Sun.COM 	 * Fill in the rest of the Hermon Memory Window handle.  Having
13239517SBill.Taylor@Sun.COM 	 * successfully transferred ownership of the MPT, we can update the
13249517SBill.Taylor@Sun.COM 	 * following fields for use in further operations on the MW.
13259517SBill.Taylor@Sun.COM 	 */
13269517SBill.Taylor@Sun.COM 	mw->mr_mptrsrcp	= mpt;
13279517SBill.Taylor@Sun.COM 	mw->mr_pdhdl	= pd;
13289517SBill.Taylor@Sun.COM 	mw->mr_rsrcp	= rsrc;
13299517SBill.Taylor@Sun.COM 	mw->mr_rkey	= hermon_mr_key_swap(mw->mr_rkey);
13309517SBill.Taylor@Sun.COM 	*mwhdl = mw;
13319517SBill.Taylor@Sun.COM 
13329517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
13339517SBill.Taylor@Sun.COM 
13349517SBill.Taylor@Sun.COM mwalloc_fail3:
13359517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &rsrc);
13369517SBill.Taylor@Sun.COM mwalloc_fail2:
13379517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &mpt);
13389517SBill.Taylor@Sun.COM mwalloc_fail1:
13399517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_dec(pd);
13409517SBill.Taylor@Sun.COM mwalloc_fail:
13419517SBill.Taylor@Sun.COM 	return (status);
13429517SBill.Taylor@Sun.COM }
13439517SBill.Taylor@Sun.COM 
13449517SBill.Taylor@Sun.COM 
13459517SBill.Taylor@Sun.COM /*
13469517SBill.Taylor@Sun.COM  * hermon_mw_free()
13479517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
13489517SBill.Taylor@Sun.COM  */
13499517SBill.Taylor@Sun.COM int
hermon_mw_free(hermon_state_t * state,hermon_mwhdl_t * mwhdl,uint_t sleep)13509517SBill.Taylor@Sun.COM hermon_mw_free(hermon_state_t *state, hermon_mwhdl_t *mwhdl, uint_t sleep)
13519517SBill.Taylor@Sun.COM {
13529517SBill.Taylor@Sun.COM 	hermon_rsrc_t		*mpt, *rsrc;
13539517SBill.Taylor@Sun.COM 	hermon_mwhdl_t		mw;
13549517SBill.Taylor@Sun.COM 	int			status;
13559517SBill.Taylor@Sun.COM 	hermon_pdhdl_t		pd;
13569517SBill.Taylor@Sun.COM 
13579517SBill.Taylor@Sun.COM 	/*
13589517SBill.Taylor@Sun.COM 	 * Check the sleep flag.  Ensure that it is consistent with the
13599517SBill.Taylor@Sun.COM 	 * current thread context (i.e. if we are currently in the interrupt
13609517SBill.Taylor@Sun.COM 	 * context, then we shouldn't be attempting to sleep).
13619517SBill.Taylor@Sun.COM 	 */
13629517SBill.Taylor@Sun.COM 	if ((sleep == HERMON_SLEEP) &&
13639517SBill.Taylor@Sun.COM 	    (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
13649517SBill.Taylor@Sun.COM 		status = IBT_INVALID_PARAM;
13659517SBill.Taylor@Sun.COM 		return (status);
13669517SBill.Taylor@Sun.COM 	}
13679517SBill.Taylor@Sun.COM 
13689517SBill.Taylor@Sun.COM 	/*
13699517SBill.Taylor@Sun.COM 	 * Pull all the necessary information from the Hermon Memory Window
13709517SBill.Taylor@Sun.COM 	 * handle.  This is necessary here because the resource for the
13719517SBill.Taylor@Sun.COM 	 * MW handle is going to be freed up as part of the this operation.
13729517SBill.Taylor@Sun.COM 	 */
13739517SBill.Taylor@Sun.COM 	mw	= *mwhdl;
13749517SBill.Taylor@Sun.COM 	mutex_enter(&mw->mr_lock);
13759517SBill.Taylor@Sun.COM 	mpt	= mw->mr_mptrsrcp;
13769517SBill.Taylor@Sun.COM 	rsrc	= mw->mr_rsrcp;
13779517SBill.Taylor@Sun.COM 	pd	= mw->mr_pdhdl;
13789517SBill.Taylor@Sun.COM 	mutex_exit(&mw->mr_lock);
13799517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mw))
13809517SBill.Taylor@Sun.COM 
13819517SBill.Taylor@Sun.COM 	/*
13829517SBill.Taylor@Sun.COM 	 * Reclaim the MPT entry from hardware.  Note: in general, it is
13839517SBill.Taylor@Sun.COM 	 * unexpected for this operation to return an error.
13849517SBill.Taylor@Sun.COM 	 */
13859517SBill.Taylor@Sun.COM 	status = hermon_cmn_ownership_cmd_post(state, HW2SW_MPT, NULL,
13869517SBill.Taylor@Sun.COM 	    0, mpt->hr_indx, sleep);
13879517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
13889517SBill.Taylor@Sun.COM 		cmn_err(CE_CONT, "Hermon: HW2SW_MPT command failed: %08x\n",
13899517SBill.Taylor@Sun.COM 		    status);
13909517SBill.Taylor@Sun.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
13919517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
13929517SBill.Taylor@Sun.COM 		}
13939517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
13949517SBill.Taylor@Sun.COM 	}
13959517SBill.Taylor@Sun.COM 
13969517SBill.Taylor@Sun.COM 	/* Free the Hermon Memory Window handle */
13979517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &rsrc);
13989517SBill.Taylor@Sun.COM 
13999517SBill.Taylor@Sun.COM 	/* Free up the MPT entry resource */
14009517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &mpt);
14019517SBill.Taylor@Sun.COM 
14029517SBill.Taylor@Sun.COM 	/* Decrement the reference count on the protection domain (PD) */
14039517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_dec(pd);
14049517SBill.Taylor@Sun.COM 
14059517SBill.Taylor@Sun.COM 	/* Set the mwhdl pointer to NULL and return success */
14069517SBill.Taylor@Sun.COM 	*mwhdl = NULL;
14079517SBill.Taylor@Sun.COM 
14089517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
14099517SBill.Taylor@Sun.COM }
14109517SBill.Taylor@Sun.COM 
14119517SBill.Taylor@Sun.COM 
14129517SBill.Taylor@Sun.COM /*
14139517SBill.Taylor@Sun.COM  * hermon_mr_keycalc()
14149517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
14159517SBill.Taylor@Sun.COM  *    NOTE:  Produces a key in the form of
14169517SBill.Taylor@Sun.COM  *		KKKKKKKK IIIIIIII IIIIIIII IIIIIIIII
14179517SBill.Taylor@Sun.COM  *    where K == the arbitrary bits and I == the index
14189517SBill.Taylor@Sun.COM  */
14199517SBill.Taylor@Sun.COM uint32_t
hermon_mr_keycalc(uint32_t indx)14209517SBill.Taylor@Sun.COM hermon_mr_keycalc(uint32_t indx)
14219517SBill.Taylor@Sun.COM {
14229517SBill.Taylor@Sun.COM 	uint32_t tmp_key, tmp_indx;
14239517SBill.Taylor@Sun.COM 
14249517SBill.Taylor@Sun.COM 	/*
14259517SBill.Taylor@Sun.COM 	 * Generate a simple key from counter.  Note:  We increment this
14269517SBill.Taylor@Sun.COM 	 * static variable _intentionally_ without any kind of mutex around
14279517SBill.Taylor@Sun.COM 	 * it.  First, single-threading all operations through a single lock
14289517SBill.Taylor@Sun.COM 	 * would be a bad idea (from a performance point-of-view).  Second,
14299517SBill.Taylor@Sun.COM 	 * the upper "unconstrained" bits don't really have to be unique
14309517SBill.Taylor@Sun.COM 	 * because the lower bits are guaranteed to be (although we do make a
14319517SBill.Taylor@Sun.COM 	 * best effort to ensure that they are).  Third, the window for the
14329517SBill.Taylor@Sun.COM 	 * race (where both threads read and update the counter at the same
14339517SBill.Taylor@Sun.COM 	 * time) is incredibly small.
14349517SBill.Taylor@Sun.COM 	 * And, lastly, we'd like to make this into a "random" key
14359517SBill.Taylor@Sun.COM 	 */
14369517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(hermon_memkey_cnt))
14379517SBill.Taylor@Sun.COM 	tmp_key = (hermon_memkey_cnt++) << HERMON_MEMKEY_SHIFT;
14389517SBill.Taylor@Sun.COM 	tmp_indx = indx & 0xffffff;
14399517SBill.Taylor@Sun.COM 	return (tmp_key | tmp_indx);
14409517SBill.Taylor@Sun.COM }
14419517SBill.Taylor@Sun.COM 
14429517SBill.Taylor@Sun.COM 
14439517SBill.Taylor@Sun.COM /*
14449517SBill.Taylor@Sun.COM  * hermon_mr_key_swap()
14459517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
14469517SBill.Taylor@Sun.COM  *    NOTE:  Produces a key in the form of
14479517SBill.Taylor@Sun.COM  *		IIIIIIII IIIIIIII IIIIIIIII KKKKKKKK
14489517SBill.Taylor@Sun.COM  *    where K == the arbitrary bits and I == the index
14499517SBill.Taylor@Sun.COM  */
14509517SBill.Taylor@Sun.COM uint32_t
hermon_mr_key_swap(uint32_t indx)14519517SBill.Taylor@Sun.COM hermon_mr_key_swap(uint32_t indx)
14529517SBill.Taylor@Sun.COM {
14539517SBill.Taylor@Sun.COM 	/*
14549517SBill.Taylor@Sun.COM 	 * The memory key format to pass down to the hardware is
14559517SBill.Taylor@Sun.COM 	 * (key[7:0],index[23:0]), which defines the index to the
14569517SBill.Taylor@Sun.COM 	 * hardware resource. When the driver passes this as a memory
14579517SBill.Taylor@Sun.COM 	 * key, (i.e. to retrieve a resource) the format is
14589517SBill.Taylor@Sun.COM 	 * (index[23:0],key[7:0]).
14599517SBill.Taylor@Sun.COM 	 */
14609517SBill.Taylor@Sun.COM 	return (((indx >> 24) & 0x000000ff) | ((indx << 8) & 0xffffff00));
14619517SBill.Taylor@Sun.COM }
14629517SBill.Taylor@Sun.COM 
14639517SBill.Taylor@Sun.COM /*
14649517SBill.Taylor@Sun.COM  * hermon_mr_common_reg()
14659517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
14669517SBill.Taylor@Sun.COM  */
14679517SBill.Taylor@Sun.COM static int
hermon_mr_common_reg(hermon_state_t * state,hermon_pdhdl_t pd,hermon_bind_info_t * bind,hermon_mrhdl_t * mrhdl,hermon_mr_options_t * op,hermon_mpt_rsrc_type_t mpt_type)14689517SBill.Taylor@Sun.COM hermon_mr_common_reg(hermon_state_t *state, hermon_pdhdl_t pd,
14699517SBill.Taylor@Sun.COM     hermon_bind_info_t *bind, hermon_mrhdl_t *mrhdl, hermon_mr_options_t *op,
14709517SBill.Taylor@Sun.COM     hermon_mpt_rsrc_type_t mpt_type)
14719517SBill.Taylor@Sun.COM {
14729517SBill.Taylor@Sun.COM 	hermon_rsrc_t		*mpt, *mtt, *rsrc, *mtt_refcnt;
14739517SBill.Taylor@Sun.COM 	hermon_umap_db_entry_t	*umapdb;
14749517SBill.Taylor@Sun.COM 	hermon_sw_refcnt_t	*swrc_tmp;
14759517SBill.Taylor@Sun.COM 	hermon_hw_dmpt_t	mpt_entry;
14769517SBill.Taylor@Sun.COM 	hermon_mrhdl_t		mr;
14779517SBill.Taylor@Sun.COM 	ibt_mr_flags_t		flags;
14789517SBill.Taylor@Sun.COM 	hermon_bind_info_t	*bh;
14799517SBill.Taylor@Sun.COM 	ddi_dma_handle_t	bind_dmahdl;
14809517SBill.Taylor@Sun.COM 	ddi_umem_cookie_t	umem_cookie;
14819517SBill.Taylor@Sun.COM 	size_t			umem_len;
14829517SBill.Taylor@Sun.COM 	caddr_t			umem_addr;
14839517SBill.Taylor@Sun.COM 	uint64_t		mtt_addr, max_sz;
14849517SBill.Taylor@Sun.COM 	uint_t			sleep, mtt_pgsize_bits, bind_type, mr_is_umem;
14859517SBill.Taylor@Sun.COM 	int			status, umem_flags, bind_override_addr;
14869517SBill.Taylor@Sun.COM 
14879517SBill.Taylor@Sun.COM 	/*
14889517SBill.Taylor@Sun.COM 	 * Check the "options" flag.  Currently this flag tells the driver
14899517SBill.Taylor@Sun.COM 	 * whether or not the region should be bound normally (i.e. with
14909517SBill.Taylor@Sun.COM 	 * entries written into the PCI IOMMU), whether it should be
14919517SBill.Taylor@Sun.COM 	 * registered to bypass the IOMMU, and whether or not the resulting
14929517SBill.Taylor@Sun.COM 	 * address should be "zero-based" (to aid the alignment restrictions
14939517SBill.Taylor@Sun.COM 	 * for QPs).
14949517SBill.Taylor@Sun.COM 	 */
14959517SBill.Taylor@Sun.COM 	if (op == NULL) {
14969517SBill.Taylor@Sun.COM 		bind_type   = HERMON_BINDMEM_NORMAL;
14979517SBill.Taylor@Sun.COM 		bind_dmahdl = NULL;
14989517SBill.Taylor@Sun.COM 		bind_override_addr = 0;
14999517SBill.Taylor@Sun.COM 	} else {
15009517SBill.Taylor@Sun.COM 		bind_type	   = op->mro_bind_type;
15019517SBill.Taylor@Sun.COM 		bind_dmahdl	   = op->mro_bind_dmahdl;
15029517SBill.Taylor@Sun.COM 		bind_override_addr = op->mro_bind_override_addr;
15039517SBill.Taylor@Sun.COM 	}
15049517SBill.Taylor@Sun.COM 
15059517SBill.Taylor@Sun.COM 	/* check what kind of mpt to use */
15069517SBill.Taylor@Sun.COM 
15079517SBill.Taylor@Sun.COM 	/* Extract the flags field from the hermon_bind_info_t */
15089517SBill.Taylor@Sun.COM 	flags = bind->bi_flags;
15099517SBill.Taylor@Sun.COM 
15109517SBill.Taylor@Sun.COM 	/*
15119517SBill.Taylor@Sun.COM 	 * Check for invalid length.  Check is the length is zero or if the
15129517SBill.Taylor@Sun.COM 	 * length is larger than the maximum configured value.  Return error
15139517SBill.Taylor@Sun.COM 	 * if it is.
15149517SBill.Taylor@Sun.COM 	 */
15159517SBill.Taylor@Sun.COM 	max_sz = ((uint64_t)1 << state->hs_cfg_profile->cp_log_max_mrw_sz);
15169517SBill.Taylor@Sun.COM 	if ((bind->bi_len == 0) || (bind->bi_len > max_sz)) {
15179517SBill.Taylor@Sun.COM 		status = IBT_MR_LEN_INVALID;
15189517SBill.Taylor@Sun.COM 		goto mrcommon_fail;
15199517SBill.Taylor@Sun.COM 	}
15209517SBill.Taylor@Sun.COM 
15219517SBill.Taylor@Sun.COM 	/*
15229517SBill.Taylor@Sun.COM 	 * Check the sleep flag.  Ensure that it is consistent with the
15239517SBill.Taylor@Sun.COM 	 * current thread context (i.e. if we are currently in the interrupt
15249517SBill.Taylor@Sun.COM 	 * context, then we shouldn't be attempting to sleep).
15259517SBill.Taylor@Sun.COM 	 */
15269517SBill.Taylor@Sun.COM 	sleep = (flags & IBT_MR_NOSLEEP) ? HERMON_NOSLEEP: HERMON_SLEEP;
15279517SBill.Taylor@Sun.COM 	if ((sleep == HERMON_SLEEP) &&
15289517SBill.Taylor@Sun.COM 	    (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
15299517SBill.Taylor@Sun.COM 		status = IBT_INVALID_PARAM;
15309517SBill.Taylor@Sun.COM 		goto mrcommon_fail;
15319517SBill.Taylor@Sun.COM 	}
15329517SBill.Taylor@Sun.COM 
15339517SBill.Taylor@Sun.COM 	/* Increment the reference count on the protection domain (PD) */
15349517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_inc(pd);
15359517SBill.Taylor@Sun.COM 
15369517SBill.Taylor@Sun.COM 	/*
15379517SBill.Taylor@Sun.COM 	 * Allocate an MPT entry.  This will be filled in with all the
15389517SBill.Taylor@Sun.COM 	 * necessary parameters to define the memory region.  And then
15399517SBill.Taylor@Sun.COM 	 * ownership will be passed to the hardware in the final step
15409517SBill.Taylor@Sun.COM 	 * below.  If we fail here, we must undo the protection domain
15419517SBill.Taylor@Sun.COM 	 * reference count.
15429517SBill.Taylor@Sun.COM 	 */
15439517SBill.Taylor@Sun.COM 	if (mpt_type == HERMON_MPT_DMPT) {
15449517SBill.Taylor@Sun.COM 		status = hermon_rsrc_alloc(state, HERMON_DMPT, 1, sleep, &mpt);
15459517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
15469517SBill.Taylor@Sun.COM 			status = IBT_INSUFF_RESOURCE;
15479517SBill.Taylor@Sun.COM 			goto mrcommon_fail1;
15489517SBill.Taylor@Sun.COM 		}
15499517SBill.Taylor@Sun.COM 	} else {
15509517SBill.Taylor@Sun.COM 		mpt = NULL;
15519517SBill.Taylor@Sun.COM 	}
15529517SBill.Taylor@Sun.COM 
15539517SBill.Taylor@Sun.COM 	/*
15549517SBill.Taylor@Sun.COM 	 * Allocate the software structure for tracking the memory region (i.e.
15559517SBill.Taylor@Sun.COM 	 * the Hermon Memory Region handle).  If we fail here, we must undo
15569517SBill.Taylor@Sun.COM 	 * the protection domain reference count and the previous resource
15579517SBill.Taylor@Sun.COM 	 * allocation.
15589517SBill.Taylor@Sun.COM 	 */
15599517SBill.Taylor@Sun.COM 	status = hermon_rsrc_alloc(state, HERMON_MRHDL, 1, sleep, &rsrc);
15609517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
15619517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
15629517SBill.Taylor@Sun.COM 		goto mrcommon_fail2;
15639517SBill.Taylor@Sun.COM 	}
15649517SBill.Taylor@Sun.COM 	mr = (hermon_mrhdl_t)rsrc->hr_addr;
15659517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mr))
15669517SBill.Taylor@Sun.COM 
15679517SBill.Taylor@Sun.COM 	/*
15689517SBill.Taylor@Sun.COM 	 * Setup and validate the memory region access flags.  This means
15699517SBill.Taylor@Sun.COM 	 * translating the IBTF's enable flags into the access flags that
15709517SBill.Taylor@Sun.COM 	 * will be used in later operations.
15719517SBill.Taylor@Sun.COM 	 */
15729517SBill.Taylor@Sun.COM 	mr->mr_accflag = 0;
15739517SBill.Taylor@Sun.COM 	if (flags & IBT_MR_ENABLE_WINDOW_BIND)
15749517SBill.Taylor@Sun.COM 		mr->mr_accflag |= IBT_MR_WINDOW_BIND;
15759517SBill.Taylor@Sun.COM 	if (flags & IBT_MR_ENABLE_LOCAL_WRITE)
15769517SBill.Taylor@Sun.COM 		mr->mr_accflag |= IBT_MR_LOCAL_WRITE;
15779517SBill.Taylor@Sun.COM 	if (flags & IBT_MR_ENABLE_REMOTE_READ)
15789517SBill.Taylor@Sun.COM 		mr->mr_accflag |= IBT_MR_REMOTE_READ;
15799517SBill.Taylor@Sun.COM 	if (flags & IBT_MR_ENABLE_REMOTE_WRITE)
15809517SBill.Taylor@Sun.COM 		mr->mr_accflag |= IBT_MR_REMOTE_WRITE;
15819517SBill.Taylor@Sun.COM 	if (flags & IBT_MR_ENABLE_REMOTE_ATOMIC)
15829517SBill.Taylor@Sun.COM 		mr->mr_accflag |= IBT_MR_REMOTE_ATOMIC;
15839517SBill.Taylor@Sun.COM 
15849517SBill.Taylor@Sun.COM 	/*
15859517SBill.Taylor@Sun.COM 	 * Calculate keys (Lkey, Rkey) from MPT index.  Each key is formed
15869517SBill.Taylor@Sun.COM 	 * from a certain number of "constrained" bits (the least significant
15879517SBill.Taylor@Sun.COM 	 * bits) and some number of "unconstrained" bits.  The constrained
15889517SBill.Taylor@Sun.COM 	 * bits must be set to the index of the entry in the MPT table, but
15899517SBill.Taylor@Sun.COM 	 * the unconstrained bits can be set to any value we wish.  Note:
15909517SBill.Taylor@Sun.COM 	 * if no remote access is required, then the RKey value is not filled
15919517SBill.Taylor@Sun.COM 	 * in.  Otherwise both Rkey and LKey are given the same value.
15929517SBill.Taylor@Sun.COM 	 */
15939517SBill.Taylor@Sun.COM 	if (mpt)
159411972SBill.Taylor@Sun.COM 		mr->mr_rkey = mr->mr_lkey = hermon_mr_keycalc(mpt->hr_indx);
15959517SBill.Taylor@Sun.COM 
15969517SBill.Taylor@Sun.COM 	/*
15979517SBill.Taylor@Sun.COM 	 * Determine if the memory is from userland and pin the pages
15989517SBill.Taylor@Sun.COM 	 * with umem_lockmemory() if necessary.
15999517SBill.Taylor@Sun.COM 	 * Then, if this is userland memory, allocate an entry in the
16009517SBill.Taylor@Sun.COM 	 * "userland resources database".  This will later be added to
16019517SBill.Taylor@Sun.COM 	 * the database (after all further memory registration operations are
16029517SBill.Taylor@Sun.COM 	 * successful).  If we fail here, we must undo the reference counts
16039517SBill.Taylor@Sun.COM 	 * and the previous resource allocations.
16049517SBill.Taylor@Sun.COM 	 */
16059517SBill.Taylor@Sun.COM 	mr_is_umem = (((bind->bi_as != NULL) && (bind->bi_as != &kas)) ? 1 : 0);
16069517SBill.Taylor@Sun.COM 	if (mr_is_umem) {
16079517SBill.Taylor@Sun.COM 		umem_len   = ptob(btopr(bind->bi_len +
16089517SBill.Taylor@Sun.COM 		    ((uintptr_t)bind->bi_addr & PAGEOFFSET)));
16099517SBill.Taylor@Sun.COM 		umem_addr  = (caddr_t)((uintptr_t)bind->bi_addr & ~PAGEOFFSET);
16109517SBill.Taylor@Sun.COM 		umem_flags = (DDI_UMEMLOCK_WRITE | DDI_UMEMLOCK_READ |
16119517SBill.Taylor@Sun.COM 		    DDI_UMEMLOCK_LONGTERM);
16129517SBill.Taylor@Sun.COM 		status = umem_lockmemory(umem_addr, umem_len, umem_flags,
161310366SBill.Taylor@Sun.COM 		    &umem_cookie, &hermon_umem_cbops, NULL);
16149517SBill.Taylor@Sun.COM 		if (status != 0) {
16159517SBill.Taylor@Sun.COM 			status = IBT_INSUFF_RESOURCE;
16169517SBill.Taylor@Sun.COM 			goto mrcommon_fail3;
16179517SBill.Taylor@Sun.COM 		}
16189517SBill.Taylor@Sun.COM 
16199517SBill.Taylor@Sun.COM 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind))
16209517SBill.Taylor@Sun.COM 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind->bi_buf))
16219517SBill.Taylor@Sun.COM 
16229517SBill.Taylor@Sun.COM 		bind->bi_buf = ddi_umem_iosetup(umem_cookie, 0, umem_len,
16239517SBill.Taylor@Sun.COM 		    B_WRITE, 0, 0, NULL, DDI_UMEM_SLEEP);
16249517SBill.Taylor@Sun.COM 		if (bind->bi_buf == NULL) {
16259517SBill.Taylor@Sun.COM 			status = IBT_INSUFF_RESOURCE;
16269517SBill.Taylor@Sun.COM 			goto mrcommon_fail3;
16279517SBill.Taylor@Sun.COM 		}
16289517SBill.Taylor@Sun.COM 		bind->bi_type = HERMON_BINDHDL_UBUF;
16299517SBill.Taylor@Sun.COM 		bind->bi_buf->b_flags |= B_READ;
16309517SBill.Taylor@Sun.COM 
16319517SBill.Taylor@Sun.COM 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*bind->bi_buf))
16329517SBill.Taylor@Sun.COM 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*bind))
16339517SBill.Taylor@Sun.COM 
16349517SBill.Taylor@Sun.COM 		umapdb = hermon_umap_db_alloc(state->hs_instance,
16359517SBill.Taylor@Sun.COM 		    (uint64_t)(uintptr_t)umem_cookie, MLNX_UMAP_MRMEM_RSRC,
16369517SBill.Taylor@Sun.COM 		    (uint64_t)(uintptr_t)rsrc);
16379517SBill.Taylor@Sun.COM 		if (umapdb == NULL) {
16389517SBill.Taylor@Sun.COM 			status = IBT_INSUFF_RESOURCE;
16399517SBill.Taylor@Sun.COM 			goto mrcommon_fail4;
16409517SBill.Taylor@Sun.COM 		}
16419517SBill.Taylor@Sun.COM 	}
16429517SBill.Taylor@Sun.COM 
16439517SBill.Taylor@Sun.COM 	/*
16449517SBill.Taylor@Sun.COM 	 * Setup the bindinfo for the mtt bind call
16459517SBill.Taylor@Sun.COM 	 */
16469517SBill.Taylor@Sun.COM 	bh = &mr->mr_bindinfo;
16479517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bh))
16489517SBill.Taylor@Sun.COM 	bcopy(bind, bh, sizeof (hermon_bind_info_t));
16499517SBill.Taylor@Sun.COM 	bh->bi_bypass = bind_type;
16509517SBill.Taylor@Sun.COM 	status = hermon_mr_mtt_bind(state, bh, bind_dmahdl, &mtt,
16519517SBill.Taylor@Sun.COM 	    &mtt_pgsize_bits, mpt != NULL);
16529517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
165311643SBill.Taylor@Sun.COM 		/*
165411643SBill.Taylor@Sun.COM 		 * When mtt_bind fails, freerbuf has already been done,
165511643SBill.Taylor@Sun.COM 		 * so make sure not to call it again.
165611643SBill.Taylor@Sun.COM 		 */
165711643SBill.Taylor@Sun.COM 		bind->bi_type = bh->bi_type;
16589517SBill.Taylor@Sun.COM 		goto mrcommon_fail5;
16599517SBill.Taylor@Sun.COM 	}
16609517SBill.Taylor@Sun.COM 	mr->mr_logmttpgsz = mtt_pgsize_bits;
16619517SBill.Taylor@Sun.COM 
16629517SBill.Taylor@Sun.COM 	/*
16639517SBill.Taylor@Sun.COM 	 * Allocate MTT reference count (to track shared memory regions).
16649517SBill.Taylor@Sun.COM 	 * This reference count resource may never be used on the given
16659517SBill.Taylor@Sun.COM 	 * memory region, but if it is ever later registered as "shared"
16669517SBill.Taylor@Sun.COM 	 * memory region then this resource will be necessary.  If we fail
16679517SBill.Taylor@Sun.COM 	 * here, we do pretty much the same as above to clean up.
16689517SBill.Taylor@Sun.COM 	 */
16699517SBill.Taylor@Sun.COM 	status = hermon_rsrc_alloc(state, HERMON_REFCNT, 1, sleep,
16709517SBill.Taylor@Sun.COM 	    &mtt_refcnt);
16719517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
16729517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
16739517SBill.Taylor@Sun.COM 		goto mrcommon_fail6;
16749517SBill.Taylor@Sun.COM 	}
16759517SBill.Taylor@Sun.COM 	mr->mr_mttrefcntp = mtt_refcnt;
16769517SBill.Taylor@Sun.COM 	swrc_tmp = (hermon_sw_refcnt_t *)mtt_refcnt->hr_addr;
16779517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*swrc_tmp))
16789517SBill.Taylor@Sun.COM 	HERMON_MTT_REFCNT_INIT(swrc_tmp);
16799517SBill.Taylor@Sun.COM 
16809517SBill.Taylor@Sun.COM 	mtt_addr = (mtt->hr_indx << HERMON_MTT_SIZE_SHIFT);
16819517SBill.Taylor@Sun.COM 
16829517SBill.Taylor@Sun.COM 	/*
16839517SBill.Taylor@Sun.COM 	 * Fill in the MPT entry.  This is the final step before passing
16849517SBill.Taylor@Sun.COM 	 * ownership of the MPT entry to the Hermon hardware.  We use all of
16859517SBill.Taylor@Sun.COM 	 * the information collected/calculated above to fill in the
16869517SBill.Taylor@Sun.COM 	 * requisite portions of the MPT.  Do this ONLY for DMPTs.
16879517SBill.Taylor@Sun.COM 	 */
16889517SBill.Taylor@Sun.COM 	if (mpt == NULL)
16899517SBill.Taylor@Sun.COM 		goto no_passown;
16909517SBill.Taylor@Sun.COM 
16919517SBill.Taylor@Sun.COM 	bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
16929517SBill.Taylor@Sun.COM 
16939517SBill.Taylor@Sun.COM 	mpt_entry.status  = HERMON_MPT_SW_OWNERSHIP;
16949517SBill.Taylor@Sun.COM 	mpt_entry.en_bind = (mr->mr_accflag & IBT_MR_WINDOW_BIND)   ? 1 : 0;
16959517SBill.Taylor@Sun.COM 	mpt_entry.atomic  = (mr->mr_accflag & IBT_MR_REMOTE_ATOMIC) ? 1 : 0;
16969517SBill.Taylor@Sun.COM 	mpt_entry.rw	  = (mr->mr_accflag & IBT_MR_REMOTE_WRITE)  ? 1 : 0;
16979517SBill.Taylor@Sun.COM 	mpt_entry.rr	  = (mr->mr_accflag & IBT_MR_REMOTE_READ)   ? 1 : 0;
16989517SBill.Taylor@Sun.COM 	mpt_entry.lw	  = (mr->mr_accflag & IBT_MR_LOCAL_WRITE)   ? 1 : 0;
16999517SBill.Taylor@Sun.COM 	mpt_entry.lr	  = 1;
17009517SBill.Taylor@Sun.COM 	mpt_entry.phys_addr = 0;
17019517SBill.Taylor@Sun.COM 	mpt_entry.reg_win = HERMON_MPT_IS_REGION;
17029517SBill.Taylor@Sun.COM 
17039517SBill.Taylor@Sun.COM 	mpt_entry.entity_sz	= mr->mr_logmttpgsz;
17049517SBill.Taylor@Sun.COM 	mpt_entry.mem_key	= mr->mr_lkey;
17059517SBill.Taylor@Sun.COM 	mpt_entry.pd		= pd->pd_pdnum;
17069517SBill.Taylor@Sun.COM 	mpt_entry.rem_acc_en = 0;
17079517SBill.Taylor@Sun.COM 	mpt_entry.fast_reg_en = 0;
17089517SBill.Taylor@Sun.COM 	mpt_entry.en_inval = 0;
17099517SBill.Taylor@Sun.COM 	mpt_entry.lkey = 0;
17109517SBill.Taylor@Sun.COM 	mpt_entry.win_cnt = 0;
17119517SBill.Taylor@Sun.COM 
17129517SBill.Taylor@Sun.COM 	if (bind_override_addr == 0) {
17139517SBill.Taylor@Sun.COM 		mpt_entry.start_addr = bh->bi_addr;
17149517SBill.Taylor@Sun.COM 	} else {
17159517SBill.Taylor@Sun.COM 		bh->bi_addr = bh->bi_addr & ((1 << mr->mr_logmttpgsz) - 1);
17169517SBill.Taylor@Sun.COM 		mpt_entry.start_addr = bh->bi_addr;
17179517SBill.Taylor@Sun.COM 	}
17189517SBill.Taylor@Sun.COM 	mpt_entry.reg_win_len	= bh->bi_len;
17199517SBill.Taylor@Sun.COM 
17209517SBill.Taylor@Sun.COM 	mpt_entry.mtt_addr_h = mtt_addr >> 32;  /* only 8 more bits */
17219517SBill.Taylor@Sun.COM 	mpt_entry.mtt_addr_l = mtt_addr >> 3;	/* only 29 bits */
17229517SBill.Taylor@Sun.COM 
17239517SBill.Taylor@Sun.COM 	/*
17249517SBill.Taylor@Sun.COM 	 * Write the MPT entry to hardware.  Lastly, we pass ownership of
17259517SBill.Taylor@Sun.COM 	 * the entry to the hardware if needed.  Note: in general, this
17269517SBill.Taylor@Sun.COM 	 * operation shouldn't fail.  But if it does, we have to undo
17279517SBill.Taylor@Sun.COM 	 * everything we've done above before returning error.
17289517SBill.Taylor@Sun.COM 	 *
17299517SBill.Taylor@Sun.COM 	 * For Hermon, this routine (which is common to the contexts) will only
17309517SBill.Taylor@Sun.COM 	 * set the ownership if needed - the process of passing the context
17319517SBill.Taylor@Sun.COM 	 * itself to HW will take care of setting up the MPT (based on type
17329517SBill.Taylor@Sun.COM 	 * and index).
17339517SBill.Taylor@Sun.COM 	 */
17349517SBill.Taylor@Sun.COM 
17359517SBill.Taylor@Sun.COM 	mpt_entry.bnd_qp = 0;	/* dMPT for a qp, check for window */
17369517SBill.Taylor@Sun.COM 	status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
17379517SBill.Taylor@Sun.COM 	    sizeof (hermon_hw_dmpt_t), mpt->hr_indx, sleep);
17389517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
17399517SBill.Taylor@Sun.COM 		cmn_err(CE_CONT, "Hermon: SW2HW_MPT command failed: %08x\n",
17409517SBill.Taylor@Sun.COM 		    status);
17419517SBill.Taylor@Sun.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
17429517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
17439517SBill.Taylor@Sun.COM 		}
17449517SBill.Taylor@Sun.COM 		status = ibc_get_ci_failure(0);
17459517SBill.Taylor@Sun.COM 		goto mrcommon_fail7;
17469517SBill.Taylor@Sun.COM 	}
174711972SBill.Taylor@Sun.COM 	if (hermon_rdma_debug & 0x4)
174811972SBill.Taylor@Sun.COM 		IBTF_DPRINTF_L2("mr", "  reg: mr %p  key %x",
174911972SBill.Taylor@Sun.COM 		    mr, hermon_mr_key_swap(mr->mr_rkey));
17509517SBill.Taylor@Sun.COM no_passown:
17519517SBill.Taylor@Sun.COM 
17529517SBill.Taylor@Sun.COM 	/*
17539517SBill.Taylor@Sun.COM 	 * Fill in the rest of the Hermon Memory Region handle.  Having
17549517SBill.Taylor@Sun.COM 	 * successfully transferred ownership of the MPT, we can update the
17559517SBill.Taylor@Sun.COM 	 * following fields for use in further operations on the MR.
17569517SBill.Taylor@Sun.COM 	 */
17579517SBill.Taylor@Sun.COM 	mr->mr_mttaddr	   = mtt_addr;
17589517SBill.Taylor@Sun.COM 
17599517SBill.Taylor@Sun.COM 	mr->mr_log2_pgsz   = (mr->mr_logmttpgsz - HERMON_PAGESHIFT);
17609517SBill.Taylor@Sun.COM 	mr->mr_mptrsrcp	   = mpt;
17619517SBill.Taylor@Sun.COM 	mr->mr_mttrsrcp	   = mtt;
17629517SBill.Taylor@Sun.COM 	mr->mr_pdhdl	   = pd;
17639517SBill.Taylor@Sun.COM 	mr->mr_rsrcp	   = rsrc;
17649517SBill.Taylor@Sun.COM 	mr->mr_is_umem	   = mr_is_umem;
17659517SBill.Taylor@Sun.COM 	mr->mr_is_fmr	   = 0;
17669517SBill.Taylor@Sun.COM 	mr->mr_umemcookie  = (mr_is_umem != 0) ? umem_cookie : NULL;
17679517SBill.Taylor@Sun.COM 	mr->mr_umem_cbfunc = NULL;
17689517SBill.Taylor@Sun.COM 	mr->mr_umem_cbarg1 = NULL;
17699517SBill.Taylor@Sun.COM 	mr->mr_umem_cbarg2 = NULL;
17709517SBill.Taylor@Sun.COM 	mr->mr_lkey	   = hermon_mr_key_swap(mr->mr_lkey);
17719517SBill.Taylor@Sun.COM 	mr->mr_rkey	   = hermon_mr_key_swap(mr->mr_rkey);
17729517SBill.Taylor@Sun.COM 	mr->mr_mpt_type	   = mpt_type;
17739517SBill.Taylor@Sun.COM 
17749517SBill.Taylor@Sun.COM 	/*
17759517SBill.Taylor@Sun.COM 	 * If this is userland memory, then we need to insert the previously
17769517SBill.Taylor@Sun.COM 	 * allocated entry into the "userland resources database".  This will
17779517SBill.Taylor@Sun.COM 	 * allow for later coordination between the hermon_umap_umemlock_cb()
17789517SBill.Taylor@Sun.COM 	 * callback and hermon_mr_deregister().
17799517SBill.Taylor@Sun.COM 	 */
17809517SBill.Taylor@Sun.COM 	if (mr_is_umem) {
17819517SBill.Taylor@Sun.COM 		hermon_umap_db_add(umapdb);
17829517SBill.Taylor@Sun.COM 	}
17839517SBill.Taylor@Sun.COM 
17849517SBill.Taylor@Sun.COM 	*mrhdl = mr;
17859517SBill.Taylor@Sun.COM 
17869517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
17879517SBill.Taylor@Sun.COM 
17889517SBill.Taylor@Sun.COM /*
17899517SBill.Taylor@Sun.COM  * The following is cleanup for all possible failure cases in this routine
17909517SBill.Taylor@Sun.COM  */
17919517SBill.Taylor@Sun.COM mrcommon_fail7:
17929517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &mtt_refcnt);
17939517SBill.Taylor@Sun.COM mrcommon_fail6:
17949517SBill.Taylor@Sun.COM 	hermon_mr_mem_unbind(state, bh);
179511247SPramod.Gunjikar@Sun.COM 	bind->bi_type = bh->bi_type;
17969517SBill.Taylor@Sun.COM mrcommon_fail5:
17979517SBill.Taylor@Sun.COM 	if (mr_is_umem) {
17989517SBill.Taylor@Sun.COM 		hermon_umap_db_free(umapdb);
17999517SBill.Taylor@Sun.COM 	}
18009517SBill.Taylor@Sun.COM mrcommon_fail4:
18019517SBill.Taylor@Sun.COM 	if (mr_is_umem) {
18029517SBill.Taylor@Sun.COM 		/*
18039517SBill.Taylor@Sun.COM 		 * Free up the memory ddi_umem_iosetup() allocates
18049517SBill.Taylor@Sun.COM 		 * internally.
18059517SBill.Taylor@Sun.COM 		 */
18069517SBill.Taylor@Sun.COM 		if (bind->bi_type == HERMON_BINDHDL_UBUF) {
18079517SBill.Taylor@Sun.COM 			freerbuf(bind->bi_buf);
18089517SBill.Taylor@Sun.COM 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind))
18099517SBill.Taylor@Sun.COM 			bind->bi_type = HERMON_BINDHDL_NONE;
18109517SBill.Taylor@Sun.COM 			_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*bind))
18119517SBill.Taylor@Sun.COM 		}
18129517SBill.Taylor@Sun.COM 		ddi_umem_unlock(umem_cookie);
18139517SBill.Taylor@Sun.COM 	}
18149517SBill.Taylor@Sun.COM mrcommon_fail3:
18159517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &rsrc);
18169517SBill.Taylor@Sun.COM mrcommon_fail2:
18179517SBill.Taylor@Sun.COM 	if (mpt != NULL)
18189517SBill.Taylor@Sun.COM 		hermon_rsrc_free(state, &mpt);
18199517SBill.Taylor@Sun.COM mrcommon_fail1:
18209517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_dec(pd);
18219517SBill.Taylor@Sun.COM mrcommon_fail:
18229517SBill.Taylor@Sun.COM 	return (status);
18239517SBill.Taylor@Sun.COM }
18249517SBill.Taylor@Sun.COM 
18259517SBill.Taylor@Sun.COM /*
1826*12965SWilliam.Taylor@Oracle.COM  * hermon_dma_mr_register()
1827*12965SWilliam.Taylor@Oracle.COM  *    Context: Can be called from base context.
1828*12965SWilliam.Taylor@Oracle.COM  */
1829*12965SWilliam.Taylor@Oracle.COM int
hermon_dma_mr_register(hermon_state_t * state,hermon_pdhdl_t pd,ibt_dmr_attr_t * mr_attr,hermon_mrhdl_t * mrhdl)1830*12965SWilliam.Taylor@Oracle.COM hermon_dma_mr_register(hermon_state_t *state, hermon_pdhdl_t pd,
1831*12965SWilliam.Taylor@Oracle.COM     ibt_dmr_attr_t *mr_attr, hermon_mrhdl_t *mrhdl)
1832*12965SWilliam.Taylor@Oracle.COM {
1833*12965SWilliam.Taylor@Oracle.COM 	hermon_rsrc_t		*mpt, *rsrc;
1834*12965SWilliam.Taylor@Oracle.COM 	hermon_hw_dmpt_t	mpt_entry;
1835*12965SWilliam.Taylor@Oracle.COM 	hermon_mrhdl_t		mr;
1836*12965SWilliam.Taylor@Oracle.COM 	ibt_mr_flags_t		flags;
1837*12965SWilliam.Taylor@Oracle.COM 	uint_t			sleep;
1838*12965SWilliam.Taylor@Oracle.COM 	int			status;
1839*12965SWilliam.Taylor@Oracle.COM 
1840*12965SWilliam.Taylor@Oracle.COM 	/* Extract the flags field */
1841*12965SWilliam.Taylor@Oracle.COM 	flags = mr_attr->dmr_flags;
1842*12965SWilliam.Taylor@Oracle.COM 
1843*12965SWilliam.Taylor@Oracle.COM 	/*
1844*12965SWilliam.Taylor@Oracle.COM 	 * Check the sleep flag.  Ensure that it is consistent with the
1845*12965SWilliam.Taylor@Oracle.COM 	 * current thread context (i.e. if we are currently in the interrupt
1846*12965SWilliam.Taylor@Oracle.COM 	 * context, then we shouldn't be attempting to sleep).
1847*12965SWilliam.Taylor@Oracle.COM 	 */
1848*12965SWilliam.Taylor@Oracle.COM 	sleep = (flags & IBT_MR_NOSLEEP) ? HERMON_NOSLEEP: HERMON_SLEEP;
1849*12965SWilliam.Taylor@Oracle.COM 	if ((sleep == HERMON_SLEEP) &&
1850*12965SWilliam.Taylor@Oracle.COM 	    (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
1851*12965SWilliam.Taylor@Oracle.COM 		status = IBT_INVALID_PARAM;
1852*12965SWilliam.Taylor@Oracle.COM 		goto mrcommon_fail;
1853*12965SWilliam.Taylor@Oracle.COM 	}
1854*12965SWilliam.Taylor@Oracle.COM 
1855*12965SWilliam.Taylor@Oracle.COM 	/* Increment the reference count on the protection domain (PD) */
1856*12965SWilliam.Taylor@Oracle.COM 	hermon_pd_refcnt_inc(pd);
1857*12965SWilliam.Taylor@Oracle.COM 
1858*12965SWilliam.Taylor@Oracle.COM 	/*
1859*12965SWilliam.Taylor@Oracle.COM 	 * Allocate an MPT entry.  This will be filled in with all the
1860*12965SWilliam.Taylor@Oracle.COM 	 * necessary parameters to define the memory region.  And then
1861*12965SWilliam.Taylor@Oracle.COM 	 * ownership will be passed to the hardware in the final step
1862*12965SWilliam.Taylor@Oracle.COM 	 * below.  If we fail here, we must undo the protection domain
1863*12965SWilliam.Taylor@Oracle.COM 	 * reference count.
1864*12965SWilliam.Taylor@Oracle.COM 	 */
1865*12965SWilliam.Taylor@Oracle.COM 	status = hermon_rsrc_alloc(state, HERMON_DMPT, 1, sleep, &mpt);
1866*12965SWilliam.Taylor@Oracle.COM 	if (status != DDI_SUCCESS) {
1867*12965SWilliam.Taylor@Oracle.COM 		status = IBT_INSUFF_RESOURCE;
1868*12965SWilliam.Taylor@Oracle.COM 		goto mrcommon_fail1;
1869*12965SWilliam.Taylor@Oracle.COM 	}
1870*12965SWilliam.Taylor@Oracle.COM 
1871*12965SWilliam.Taylor@Oracle.COM 	/*
1872*12965SWilliam.Taylor@Oracle.COM 	 * Allocate the software structure for tracking the memory region (i.e.
1873*12965SWilliam.Taylor@Oracle.COM 	 * the Hermon Memory Region handle).  If we fail here, we must undo
1874*12965SWilliam.Taylor@Oracle.COM 	 * the protection domain reference count and the previous resource
1875*12965SWilliam.Taylor@Oracle.COM 	 * allocation.
1876*12965SWilliam.Taylor@Oracle.COM 	 */
1877*12965SWilliam.Taylor@Oracle.COM 	status = hermon_rsrc_alloc(state, HERMON_MRHDL, 1, sleep, &rsrc);
1878*12965SWilliam.Taylor@Oracle.COM 	if (status != DDI_SUCCESS) {
1879*12965SWilliam.Taylor@Oracle.COM 		status = IBT_INSUFF_RESOURCE;
1880*12965SWilliam.Taylor@Oracle.COM 		goto mrcommon_fail2;
1881*12965SWilliam.Taylor@Oracle.COM 	}
1882*12965SWilliam.Taylor@Oracle.COM 	mr = (hermon_mrhdl_t)rsrc->hr_addr;
1883*12965SWilliam.Taylor@Oracle.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mr))
1884*12965SWilliam.Taylor@Oracle.COM 	bzero(mr, sizeof (*mr));
1885*12965SWilliam.Taylor@Oracle.COM 
1886*12965SWilliam.Taylor@Oracle.COM 	/*
1887*12965SWilliam.Taylor@Oracle.COM 	 * Setup and validate the memory region access flags.  This means
1888*12965SWilliam.Taylor@Oracle.COM 	 * translating the IBTF's enable flags into the access flags that
1889*12965SWilliam.Taylor@Oracle.COM 	 * will be used in later operations.
1890*12965SWilliam.Taylor@Oracle.COM 	 */
1891*12965SWilliam.Taylor@Oracle.COM 	mr->mr_accflag = 0;
1892*12965SWilliam.Taylor@Oracle.COM 	if (flags & IBT_MR_ENABLE_WINDOW_BIND)
1893*12965SWilliam.Taylor@Oracle.COM 		mr->mr_accflag |= IBT_MR_WINDOW_BIND;
1894*12965SWilliam.Taylor@Oracle.COM 	if (flags & IBT_MR_ENABLE_LOCAL_WRITE)
1895*12965SWilliam.Taylor@Oracle.COM 		mr->mr_accflag |= IBT_MR_LOCAL_WRITE;
1896*12965SWilliam.Taylor@Oracle.COM 	if (flags & IBT_MR_ENABLE_REMOTE_READ)
1897*12965SWilliam.Taylor@Oracle.COM 		mr->mr_accflag |= IBT_MR_REMOTE_READ;
1898*12965SWilliam.Taylor@Oracle.COM 	if (flags & IBT_MR_ENABLE_REMOTE_WRITE)
1899*12965SWilliam.Taylor@Oracle.COM 		mr->mr_accflag |= IBT_MR_REMOTE_WRITE;
1900*12965SWilliam.Taylor@Oracle.COM 	if (flags & IBT_MR_ENABLE_REMOTE_ATOMIC)
1901*12965SWilliam.Taylor@Oracle.COM 		mr->mr_accflag |= IBT_MR_REMOTE_ATOMIC;
1902*12965SWilliam.Taylor@Oracle.COM 
1903*12965SWilliam.Taylor@Oracle.COM 	/*
1904*12965SWilliam.Taylor@Oracle.COM 	 * Calculate keys (Lkey, Rkey) from MPT index.  Each key is formed
1905*12965SWilliam.Taylor@Oracle.COM 	 * from a certain number of "constrained" bits (the least significant
1906*12965SWilliam.Taylor@Oracle.COM 	 * bits) and some number of "unconstrained" bits.  The constrained
1907*12965SWilliam.Taylor@Oracle.COM 	 * bits must be set to the index of the entry in the MPT table, but
1908*12965SWilliam.Taylor@Oracle.COM 	 * the unconstrained bits can be set to any value we wish.  Note:
1909*12965SWilliam.Taylor@Oracle.COM 	 * if no remote access is required, then the RKey value is not filled
1910*12965SWilliam.Taylor@Oracle.COM 	 * in.  Otherwise both Rkey and LKey are given the same value.
1911*12965SWilliam.Taylor@Oracle.COM 	 */
1912*12965SWilliam.Taylor@Oracle.COM 	if (mpt)
1913*12965SWilliam.Taylor@Oracle.COM 		mr->mr_rkey = mr->mr_lkey = hermon_mr_keycalc(mpt->hr_indx);
1914*12965SWilliam.Taylor@Oracle.COM 
1915*12965SWilliam.Taylor@Oracle.COM 	/*
1916*12965SWilliam.Taylor@Oracle.COM 	 * Fill in the MPT entry.  This is the final step before passing
1917*12965SWilliam.Taylor@Oracle.COM 	 * ownership of the MPT entry to the Hermon hardware.  We use all of
1918*12965SWilliam.Taylor@Oracle.COM 	 * the information collected/calculated above to fill in the
1919*12965SWilliam.Taylor@Oracle.COM 	 * requisite portions of the MPT.  Do this ONLY for DMPTs.
1920*12965SWilliam.Taylor@Oracle.COM 	 */
1921*12965SWilliam.Taylor@Oracle.COM 	bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
1922*12965SWilliam.Taylor@Oracle.COM 
1923*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.status  = HERMON_MPT_SW_OWNERSHIP;
1924*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.en_bind = (mr->mr_accflag & IBT_MR_WINDOW_BIND)   ? 1 : 0;
1925*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.atomic  = (mr->mr_accflag & IBT_MR_REMOTE_ATOMIC) ? 1 : 0;
1926*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.rw	  = (mr->mr_accflag & IBT_MR_REMOTE_WRITE)  ? 1 : 0;
1927*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.rr	  = (mr->mr_accflag & IBT_MR_REMOTE_READ)   ? 1 : 0;
1928*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.lw	  = (mr->mr_accflag & IBT_MR_LOCAL_WRITE)   ? 1 : 0;
1929*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.lr	  = 1;
1930*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.phys_addr = 1;	/* critical bit for this */
1931*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.reg_win = HERMON_MPT_IS_REGION;
1932*12965SWilliam.Taylor@Oracle.COM 
1933*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.entity_sz	= mr->mr_logmttpgsz;
1934*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.mem_key	= mr->mr_lkey;
1935*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.pd		= pd->pd_pdnum;
1936*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.rem_acc_en = 0;
1937*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.fast_reg_en = 0;
1938*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.en_inval = 0;
1939*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.lkey = 0;
1940*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.win_cnt = 0;
1941*12965SWilliam.Taylor@Oracle.COM 
1942*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.start_addr = mr_attr->dmr_paddr;
1943*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.reg_win_len = mr_attr->dmr_len;
1944*12965SWilliam.Taylor@Oracle.COM 	if (mr_attr->dmr_len == 0)
1945*12965SWilliam.Taylor@Oracle.COM 		mpt_entry.len_b64 = 1;	/* needed for 2^^64 length */
1946*12965SWilliam.Taylor@Oracle.COM 
1947*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.mtt_addr_h = 0;
1948*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.mtt_addr_l = 0;
1949*12965SWilliam.Taylor@Oracle.COM 
1950*12965SWilliam.Taylor@Oracle.COM 	/*
1951*12965SWilliam.Taylor@Oracle.COM 	 * Write the MPT entry to hardware.  Lastly, we pass ownership of
1952*12965SWilliam.Taylor@Oracle.COM 	 * the entry to the hardware if needed.  Note: in general, this
1953*12965SWilliam.Taylor@Oracle.COM 	 * operation shouldn't fail.  But if it does, we have to undo
1954*12965SWilliam.Taylor@Oracle.COM 	 * everything we've done above before returning error.
1955*12965SWilliam.Taylor@Oracle.COM 	 *
1956*12965SWilliam.Taylor@Oracle.COM 	 * For Hermon, this routine (which is common to the contexts) will only
1957*12965SWilliam.Taylor@Oracle.COM 	 * set the ownership if needed - the process of passing the context
1958*12965SWilliam.Taylor@Oracle.COM 	 * itself to HW will take care of setting up the MPT (based on type
1959*12965SWilliam.Taylor@Oracle.COM 	 * and index).
1960*12965SWilliam.Taylor@Oracle.COM 	 */
1961*12965SWilliam.Taylor@Oracle.COM 
1962*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.bnd_qp = 0;	/* dMPT for a qp, check for window */
1963*12965SWilliam.Taylor@Oracle.COM 	status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
1964*12965SWilliam.Taylor@Oracle.COM 	    sizeof (hermon_hw_dmpt_t), mpt->hr_indx, sleep);
1965*12965SWilliam.Taylor@Oracle.COM 	if (status != HERMON_CMD_SUCCESS) {
1966*12965SWilliam.Taylor@Oracle.COM 		cmn_err(CE_CONT, "Hermon: SW2HW_MPT command failed: %08x\n",
1967*12965SWilliam.Taylor@Oracle.COM 		    status);
1968*12965SWilliam.Taylor@Oracle.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
1969*12965SWilliam.Taylor@Oracle.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
1970*12965SWilliam.Taylor@Oracle.COM 		}
1971*12965SWilliam.Taylor@Oracle.COM 		status = ibc_get_ci_failure(0);
1972*12965SWilliam.Taylor@Oracle.COM 		goto mrcommon_fail7;
1973*12965SWilliam.Taylor@Oracle.COM 	}
1974*12965SWilliam.Taylor@Oracle.COM 
1975*12965SWilliam.Taylor@Oracle.COM 	/*
1976*12965SWilliam.Taylor@Oracle.COM 	 * Fill in the rest of the Hermon Memory Region handle.  Having
1977*12965SWilliam.Taylor@Oracle.COM 	 * successfully transferred ownership of the MPT, we can update the
1978*12965SWilliam.Taylor@Oracle.COM 	 * following fields for use in further operations on the MR.
1979*12965SWilliam.Taylor@Oracle.COM 	 */
1980*12965SWilliam.Taylor@Oracle.COM 	mr->mr_mttaddr	   = 0;
1981*12965SWilliam.Taylor@Oracle.COM 
1982*12965SWilliam.Taylor@Oracle.COM 	mr->mr_log2_pgsz   = 0;
1983*12965SWilliam.Taylor@Oracle.COM 	mr->mr_mptrsrcp	   = mpt;
1984*12965SWilliam.Taylor@Oracle.COM 	mr->mr_mttrsrcp	   = NULL;
1985*12965SWilliam.Taylor@Oracle.COM 	mr->mr_pdhdl	   = pd;
1986*12965SWilliam.Taylor@Oracle.COM 	mr->mr_rsrcp	   = rsrc;
1987*12965SWilliam.Taylor@Oracle.COM 	mr->mr_is_umem	   = 0;
1988*12965SWilliam.Taylor@Oracle.COM 	mr->mr_is_fmr	   = 0;
1989*12965SWilliam.Taylor@Oracle.COM 	mr->mr_umemcookie  = NULL;
1990*12965SWilliam.Taylor@Oracle.COM 	mr->mr_umem_cbfunc = NULL;
1991*12965SWilliam.Taylor@Oracle.COM 	mr->mr_umem_cbarg1 = NULL;
1992*12965SWilliam.Taylor@Oracle.COM 	mr->mr_umem_cbarg2 = NULL;
1993*12965SWilliam.Taylor@Oracle.COM 	mr->mr_lkey	   = hermon_mr_key_swap(mr->mr_lkey);
1994*12965SWilliam.Taylor@Oracle.COM 	mr->mr_rkey	   = hermon_mr_key_swap(mr->mr_rkey);
1995*12965SWilliam.Taylor@Oracle.COM 	mr->mr_mpt_type	   = HERMON_MPT_DMPT;
1996*12965SWilliam.Taylor@Oracle.COM 
1997*12965SWilliam.Taylor@Oracle.COM 	*mrhdl = mr;
1998*12965SWilliam.Taylor@Oracle.COM 
1999*12965SWilliam.Taylor@Oracle.COM 	return (DDI_SUCCESS);
2000*12965SWilliam.Taylor@Oracle.COM 
2001*12965SWilliam.Taylor@Oracle.COM /*
2002*12965SWilliam.Taylor@Oracle.COM  * The following is cleanup for all possible failure cases in this routine
2003*12965SWilliam.Taylor@Oracle.COM  */
2004*12965SWilliam.Taylor@Oracle.COM mrcommon_fail7:
2005*12965SWilliam.Taylor@Oracle.COM 	hermon_rsrc_free(state, &rsrc);
2006*12965SWilliam.Taylor@Oracle.COM mrcommon_fail2:
2007*12965SWilliam.Taylor@Oracle.COM 	hermon_rsrc_free(state, &mpt);
2008*12965SWilliam.Taylor@Oracle.COM mrcommon_fail1:
2009*12965SWilliam.Taylor@Oracle.COM 	hermon_pd_refcnt_dec(pd);
2010*12965SWilliam.Taylor@Oracle.COM mrcommon_fail:
2011*12965SWilliam.Taylor@Oracle.COM 	return (status);
2012*12965SWilliam.Taylor@Oracle.COM }
2013*12965SWilliam.Taylor@Oracle.COM 
2014*12965SWilliam.Taylor@Oracle.COM /*
2015*12965SWilliam.Taylor@Oracle.COM  * hermon_mr_alloc_lkey()
2016*12965SWilliam.Taylor@Oracle.COM  *    Context: Can be called from base context.
2017*12965SWilliam.Taylor@Oracle.COM  */
2018*12965SWilliam.Taylor@Oracle.COM int
hermon_mr_alloc_lkey(hermon_state_t * state,hermon_pdhdl_t pd,ibt_lkey_flags_t flags,uint_t nummtt,hermon_mrhdl_t * mrhdl)2019*12965SWilliam.Taylor@Oracle.COM hermon_mr_alloc_lkey(hermon_state_t *state, hermon_pdhdl_t pd,
2020*12965SWilliam.Taylor@Oracle.COM     ibt_lkey_flags_t flags, uint_t nummtt, hermon_mrhdl_t *mrhdl)
2021*12965SWilliam.Taylor@Oracle.COM {
2022*12965SWilliam.Taylor@Oracle.COM 	hermon_rsrc_t		*mpt, *mtt, *rsrc, *mtt_refcnt;
2023*12965SWilliam.Taylor@Oracle.COM 	hermon_sw_refcnt_t	*swrc_tmp;
2024*12965SWilliam.Taylor@Oracle.COM 	hermon_hw_dmpt_t	mpt_entry;
2025*12965SWilliam.Taylor@Oracle.COM 	hermon_mrhdl_t		mr;
2026*12965SWilliam.Taylor@Oracle.COM 	uint64_t		mtt_addr;
2027*12965SWilliam.Taylor@Oracle.COM 	uint_t			sleep;
2028*12965SWilliam.Taylor@Oracle.COM 	int			status;
2029*12965SWilliam.Taylor@Oracle.COM 
2030*12965SWilliam.Taylor@Oracle.COM 	/* Increment the reference count on the protection domain (PD) */
2031*12965SWilliam.Taylor@Oracle.COM 	hermon_pd_refcnt_inc(pd);
2032*12965SWilliam.Taylor@Oracle.COM 
2033*12965SWilliam.Taylor@Oracle.COM 	sleep = (flags & IBT_KEY_NOSLEEP) ? HERMON_NOSLEEP: HERMON_SLEEP;
2034*12965SWilliam.Taylor@Oracle.COM 
2035*12965SWilliam.Taylor@Oracle.COM 	/*
2036*12965SWilliam.Taylor@Oracle.COM 	 * Allocate an MPT entry.  This will be filled in with "some" of the
2037*12965SWilliam.Taylor@Oracle.COM 	 * necessary parameters to define the memory region.  And then
2038*12965SWilliam.Taylor@Oracle.COM 	 * ownership will be passed to the hardware in the final step
2039*12965SWilliam.Taylor@Oracle.COM 	 * below.  If we fail here, we must undo the protection domain
2040*12965SWilliam.Taylor@Oracle.COM 	 * reference count.
2041*12965SWilliam.Taylor@Oracle.COM 	 *
2042*12965SWilliam.Taylor@Oracle.COM 	 * The MTTs will get filled in when the FRWR is processed.
2043*12965SWilliam.Taylor@Oracle.COM 	 */
2044*12965SWilliam.Taylor@Oracle.COM 	status = hermon_rsrc_alloc(state, HERMON_DMPT, 1, sleep, &mpt);
2045*12965SWilliam.Taylor@Oracle.COM 	if (status != DDI_SUCCESS) {
2046*12965SWilliam.Taylor@Oracle.COM 		status = IBT_INSUFF_RESOURCE;
2047*12965SWilliam.Taylor@Oracle.COM 		goto alloclkey_fail1;
2048*12965SWilliam.Taylor@Oracle.COM 	}
2049*12965SWilliam.Taylor@Oracle.COM 
2050*12965SWilliam.Taylor@Oracle.COM 	/*
2051*12965SWilliam.Taylor@Oracle.COM 	 * Allocate the software structure for tracking the memory region (i.e.
2052*12965SWilliam.Taylor@Oracle.COM 	 * the Hermon Memory Region handle).  If we fail here, we must undo
2053*12965SWilliam.Taylor@Oracle.COM 	 * the protection domain reference count and the previous resource
2054*12965SWilliam.Taylor@Oracle.COM 	 * allocation.
2055*12965SWilliam.Taylor@Oracle.COM 	 */
2056*12965SWilliam.Taylor@Oracle.COM 	status = hermon_rsrc_alloc(state, HERMON_MRHDL, 1, sleep, &rsrc);
2057*12965SWilliam.Taylor@Oracle.COM 	if (status != DDI_SUCCESS) {
2058*12965SWilliam.Taylor@Oracle.COM 		status = IBT_INSUFF_RESOURCE;
2059*12965SWilliam.Taylor@Oracle.COM 		goto alloclkey_fail2;
2060*12965SWilliam.Taylor@Oracle.COM 	}
2061*12965SWilliam.Taylor@Oracle.COM 	mr = (hermon_mrhdl_t)rsrc->hr_addr;
2062*12965SWilliam.Taylor@Oracle.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mr))
2063*12965SWilliam.Taylor@Oracle.COM 	bzero(mr, sizeof (*mr));
2064*12965SWilliam.Taylor@Oracle.COM 	mr->mr_bindinfo.bi_type = HERMON_BINDHDL_LKEY;
2065*12965SWilliam.Taylor@Oracle.COM 
2066*12965SWilliam.Taylor@Oracle.COM 	mr->mr_lkey = hermon_mr_keycalc(mpt->hr_indx);
2067*12965SWilliam.Taylor@Oracle.COM 
2068*12965SWilliam.Taylor@Oracle.COM 	status = hermon_rsrc_alloc(state, HERMON_MTT, nummtt, sleep, &mtt);
2069*12965SWilliam.Taylor@Oracle.COM 	if (status != DDI_SUCCESS) {
2070*12965SWilliam.Taylor@Oracle.COM 		status = IBT_INSUFF_RESOURCE;
2071*12965SWilliam.Taylor@Oracle.COM 		goto alloclkey_fail3;
2072*12965SWilliam.Taylor@Oracle.COM 	}
2073*12965SWilliam.Taylor@Oracle.COM 	mr->mr_logmttpgsz = PAGESHIFT;
2074*12965SWilliam.Taylor@Oracle.COM 
2075*12965SWilliam.Taylor@Oracle.COM 	/*
2076*12965SWilliam.Taylor@Oracle.COM 	 * Allocate MTT reference count (to track shared memory regions).
2077*12965SWilliam.Taylor@Oracle.COM 	 * This reference count resource may never be used on the given
2078*12965SWilliam.Taylor@Oracle.COM 	 * memory region, but if it is ever later registered as "shared"
2079*12965SWilliam.Taylor@Oracle.COM 	 * memory region then this resource will be necessary.  If we fail
2080*12965SWilliam.Taylor@Oracle.COM 	 * here, we do pretty much the same as above to clean up.
2081*12965SWilliam.Taylor@Oracle.COM 	 */
2082*12965SWilliam.Taylor@Oracle.COM 	status = hermon_rsrc_alloc(state, HERMON_REFCNT, 1, sleep,
2083*12965SWilliam.Taylor@Oracle.COM 	    &mtt_refcnt);
2084*12965SWilliam.Taylor@Oracle.COM 	if (status != DDI_SUCCESS) {
2085*12965SWilliam.Taylor@Oracle.COM 		status = IBT_INSUFF_RESOURCE;
2086*12965SWilliam.Taylor@Oracle.COM 		goto alloclkey_fail4;
2087*12965SWilliam.Taylor@Oracle.COM 	}
2088*12965SWilliam.Taylor@Oracle.COM 	mr->mr_mttrefcntp = mtt_refcnt;
2089*12965SWilliam.Taylor@Oracle.COM 	swrc_tmp = (hermon_sw_refcnt_t *)mtt_refcnt->hr_addr;
2090*12965SWilliam.Taylor@Oracle.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*swrc_tmp))
2091*12965SWilliam.Taylor@Oracle.COM 	HERMON_MTT_REFCNT_INIT(swrc_tmp);
2092*12965SWilliam.Taylor@Oracle.COM 
2093*12965SWilliam.Taylor@Oracle.COM 	mtt_addr = (mtt->hr_indx << HERMON_MTT_SIZE_SHIFT);
2094*12965SWilliam.Taylor@Oracle.COM 
2095*12965SWilliam.Taylor@Oracle.COM 	bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
2096*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.status = HERMON_MPT_FREE;
2097*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.lw = 1;
2098*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.lr = 1;
2099*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.reg_win = HERMON_MPT_IS_REGION;
2100*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.entity_sz = mr->mr_logmttpgsz;
2101*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.mem_key = mr->mr_lkey;
2102*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.pd = pd->pd_pdnum;
2103*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.fast_reg_en = 1;
2104*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.rem_acc_en = 1;
2105*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.en_inval = 1;
2106*12965SWilliam.Taylor@Oracle.COM 	if (flags & IBT_KEY_REMOTE) {
2107*12965SWilliam.Taylor@Oracle.COM 		mpt_entry.ren_inval = 1;
2108*12965SWilliam.Taylor@Oracle.COM 	}
2109*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.mtt_size = nummtt;
2110*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.mtt_addr_h = mtt_addr >> 32;	/* only 8 more bits */
2111*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.mtt_addr_l = mtt_addr >> 3;	/* only 29 bits */
2112*12965SWilliam.Taylor@Oracle.COM 
2113*12965SWilliam.Taylor@Oracle.COM 	/*
2114*12965SWilliam.Taylor@Oracle.COM 	 * Write the MPT entry to hardware.  Lastly, we pass ownership of
2115*12965SWilliam.Taylor@Oracle.COM 	 * the entry to the hardware if needed.  Note: in general, this
2116*12965SWilliam.Taylor@Oracle.COM 	 * operation shouldn't fail.  But if it does, we have to undo
2117*12965SWilliam.Taylor@Oracle.COM 	 * everything we've done above before returning error.
2118*12965SWilliam.Taylor@Oracle.COM 	 *
2119*12965SWilliam.Taylor@Oracle.COM 	 * For Hermon, this routine (which is common to the contexts) will only
2120*12965SWilliam.Taylor@Oracle.COM 	 * set the ownership if needed - the process of passing the context
2121*12965SWilliam.Taylor@Oracle.COM 	 * itself to HW will take care of setting up the MPT (based on type
2122*12965SWilliam.Taylor@Oracle.COM 	 * and index).
2123*12965SWilliam.Taylor@Oracle.COM 	 */
2124*12965SWilliam.Taylor@Oracle.COM 	status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
2125*12965SWilliam.Taylor@Oracle.COM 	    sizeof (hermon_hw_dmpt_t), mpt->hr_indx, sleep);
2126*12965SWilliam.Taylor@Oracle.COM 	if (status != HERMON_CMD_SUCCESS) {
2127*12965SWilliam.Taylor@Oracle.COM 		cmn_err(CE_CONT, "Hermon: alloc_lkey: SW2HW_MPT command "
2128*12965SWilliam.Taylor@Oracle.COM 		    "failed: %08x\n", status);
2129*12965SWilliam.Taylor@Oracle.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
2130*12965SWilliam.Taylor@Oracle.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
2131*12965SWilliam.Taylor@Oracle.COM 		}
2132*12965SWilliam.Taylor@Oracle.COM 		status = ibc_get_ci_failure(0);
2133*12965SWilliam.Taylor@Oracle.COM 		goto alloclkey_fail5;
2134*12965SWilliam.Taylor@Oracle.COM 	}
2135*12965SWilliam.Taylor@Oracle.COM 
2136*12965SWilliam.Taylor@Oracle.COM 	/*
2137*12965SWilliam.Taylor@Oracle.COM 	 * Fill in the rest of the Hermon Memory Region handle.  Having
2138*12965SWilliam.Taylor@Oracle.COM 	 * successfully transferred ownership of the MPT, we can update the
2139*12965SWilliam.Taylor@Oracle.COM 	 * following fields for use in further operations on the MR.
2140*12965SWilliam.Taylor@Oracle.COM 	 */
2141*12965SWilliam.Taylor@Oracle.COM 	mr->mr_accflag = IBT_MR_LOCAL_WRITE;
2142*12965SWilliam.Taylor@Oracle.COM 	mr->mr_mttaddr = mtt_addr;
2143*12965SWilliam.Taylor@Oracle.COM 	mr->mr_log2_pgsz = (mr->mr_logmttpgsz - HERMON_PAGESHIFT);
2144*12965SWilliam.Taylor@Oracle.COM 	mr->mr_mptrsrcp = mpt;
2145*12965SWilliam.Taylor@Oracle.COM 	mr->mr_mttrsrcp = mtt;
2146*12965SWilliam.Taylor@Oracle.COM 	mr->mr_pdhdl = pd;
2147*12965SWilliam.Taylor@Oracle.COM 	mr->mr_rsrcp = rsrc;
2148*12965SWilliam.Taylor@Oracle.COM 	mr->mr_lkey = hermon_mr_key_swap(mr->mr_lkey);
2149*12965SWilliam.Taylor@Oracle.COM 	mr->mr_rkey = mr->mr_lkey;
2150*12965SWilliam.Taylor@Oracle.COM 	mr->mr_mpt_type = HERMON_MPT_DMPT;
2151*12965SWilliam.Taylor@Oracle.COM 
2152*12965SWilliam.Taylor@Oracle.COM 	*mrhdl = mr;
2153*12965SWilliam.Taylor@Oracle.COM 	return (DDI_SUCCESS);
2154*12965SWilliam.Taylor@Oracle.COM 
2155*12965SWilliam.Taylor@Oracle.COM alloclkey_fail5:
2156*12965SWilliam.Taylor@Oracle.COM 	hermon_rsrc_free(state, &mtt_refcnt);
2157*12965SWilliam.Taylor@Oracle.COM alloclkey_fail4:
2158*12965SWilliam.Taylor@Oracle.COM 	hermon_rsrc_free(state, &mtt);
2159*12965SWilliam.Taylor@Oracle.COM alloclkey_fail3:
2160*12965SWilliam.Taylor@Oracle.COM 	hermon_rsrc_free(state, &rsrc);
2161*12965SWilliam.Taylor@Oracle.COM alloclkey_fail2:
2162*12965SWilliam.Taylor@Oracle.COM 	hermon_rsrc_free(state, &mpt);
2163*12965SWilliam.Taylor@Oracle.COM alloclkey_fail1:
2164*12965SWilliam.Taylor@Oracle.COM 	hermon_pd_refcnt_dec(pd);
2165*12965SWilliam.Taylor@Oracle.COM 	return (status);
2166*12965SWilliam.Taylor@Oracle.COM }
2167*12965SWilliam.Taylor@Oracle.COM 
2168*12965SWilliam.Taylor@Oracle.COM /*
2169*12965SWilliam.Taylor@Oracle.COM  * hermon_mr_fexch_mpt_init()
2170*12965SWilliam.Taylor@Oracle.COM  *    Context: Can be called from base context.
2171*12965SWilliam.Taylor@Oracle.COM  *
2172*12965SWilliam.Taylor@Oracle.COM  * This is the same as alloc_lkey, but not returning an mrhdl.
2173*12965SWilliam.Taylor@Oracle.COM  */
2174*12965SWilliam.Taylor@Oracle.COM int
hermon_mr_fexch_mpt_init(hermon_state_t * state,hermon_pdhdl_t pd,uint32_t mpt_indx,uint_t nummtt,uint64_t mtt_addr,uint_t sleep)2175*12965SWilliam.Taylor@Oracle.COM hermon_mr_fexch_mpt_init(hermon_state_t *state, hermon_pdhdl_t pd,
2176*12965SWilliam.Taylor@Oracle.COM     uint32_t mpt_indx, uint_t nummtt, uint64_t mtt_addr, uint_t sleep)
2177*12965SWilliam.Taylor@Oracle.COM {
2178*12965SWilliam.Taylor@Oracle.COM 	hermon_hw_dmpt_t	mpt_entry;
2179*12965SWilliam.Taylor@Oracle.COM 	int			status;
2180*12965SWilliam.Taylor@Oracle.COM 
2181*12965SWilliam.Taylor@Oracle.COM 	/*
2182*12965SWilliam.Taylor@Oracle.COM 	 * The MTTs will get filled in when the FRWR is processed.
2183*12965SWilliam.Taylor@Oracle.COM 	 */
2184*12965SWilliam.Taylor@Oracle.COM 
2185*12965SWilliam.Taylor@Oracle.COM 	bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
2186*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.status = HERMON_MPT_FREE;
2187*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.lw = 1;
2188*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.lr = 1;
2189*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.rw = 1;
2190*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.rr = 1;
2191*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.reg_win = HERMON_MPT_IS_REGION;
2192*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.entity_sz = PAGESHIFT;
2193*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.mem_key = mpt_indx;
2194*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.pd = pd->pd_pdnum;
2195*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.fast_reg_en = 1;
2196*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.rem_acc_en = 1;
2197*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.en_inval = 1;
2198*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.ren_inval = 1;
2199*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.mtt_size = nummtt;
2200*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.mtt_addr_h = mtt_addr >> 32;	/* only 8 more bits */
2201*12965SWilliam.Taylor@Oracle.COM 	mpt_entry.mtt_addr_l = mtt_addr >> 3;	/* only 29 bits */
2202*12965SWilliam.Taylor@Oracle.COM 
2203*12965SWilliam.Taylor@Oracle.COM 	/*
2204*12965SWilliam.Taylor@Oracle.COM 	 * Write the MPT entry to hardware.  Lastly, we pass ownership of
2205*12965SWilliam.Taylor@Oracle.COM 	 * the entry to the hardware if needed.  Note: in general, this
2206*12965SWilliam.Taylor@Oracle.COM 	 * operation shouldn't fail.  But if it does, we have to undo
2207*12965SWilliam.Taylor@Oracle.COM 	 * everything we've done above before returning error.
2208*12965SWilliam.Taylor@Oracle.COM 	 *
2209*12965SWilliam.Taylor@Oracle.COM 	 * For Hermon, this routine (which is common to the contexts) will only
2210*12965SWilliam.Taylor@Oracle.COM 	 * set the ownership if needed - the process of passing the context
2211*12965SWilliam.Taylor@Oracle.COM 	 * itself to HW will take care of setting up the MPT (based on type
2212*12965SWilliam.Taylor@Oracle.COM 	 * and index).
2213*12965SWilliam.Taylor@Oracle.COM 	 */
2214*12965SWilliam.Taylor@Oracle.COM 	status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
2215*12965SWilliam.Taylor@Oracle.COM 	    sizeof (hermon_hw_dmpt_t), mpt_indx, sleep);
2216*12965SWilliam.Taylor@Oracle.COM 	if (status != HERMON_CMD_SUCCESS) {
2217*12965SWilliam.Taylor@Oracle.COM 		cmn_err(CE_CONT, "Hermon: fexch_mpt_init: SW2HW_MPT command "
2218*12965SWilliam.Taylor@Oracle.COM 		    "failed: %08x\n", status);
2219*12965SWilliam.Taylor@Oracle.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
2220*12965SWilliam.Taylor@Oracle.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
2221*12965SWilliam.Taylor@Oracle.COM 		}
2222*12965SWilliam.Taylor@Oracle.COM 		status = ibc_get_ci_failure(0);
2223*12965SWilliam.Taylor@Oracle.COM 		return (status);
2224*12965SWilliam.Taylor@Oracle.COM 	}
2225*12965SWilliam.Taylor@Oracle.COM 	/* Increment the reference count on the protection domain (PD) */
2226*12965SWilliam.Taylor@Oracle.COM 	hermon_pd_refcnt_inc(pd);
2227*12965SWilliam.Taylor@Oracle.COM 
2228*12965SWilliam.Taylor@Oracle.COM 	return (DDI_SUCCESS);
2229*12965SWilliam.Taylor@Oracle.COM }
2230*12965SWilliam.Taylor@Oracle.COM 
2231*12965SWilliam.Taylor@Oracle.COM /*
2232*12965SWilliam.Taylor@Oracle.COM  * hermon_mr_fexch_mpt_fini()
2233*12965SWilliam.Taylor@Oracle.COM  *    Context: Can be called from base context.
2234*12965SWilliam.Taylor@Oracle.COM  *
2235*12965SWilliam.Taylor@Oracle.COM  * This is the same as deregister_mr, without an mrhdl.
2236*12965SWilliam.Taylor@Oracle.COM  */
2237*12965SWilliam.Taylor@Oracle.COM int
hermon_mr_fexch_mpt_fini(hermon_state_t * state,hermon_pdhdl_t pd,uint32_t mpt_indx,uint_t sleep)2238*12965SWilliam.Taylor@Oracle.COM hermon_mr_fexch_mpt_fini(hermon_state_t *state, hermon_pdhdl_t pd,
2239*12965SWilliam.Taylor@Oracle.COM     uint32_t mpt_indx, uint_t sleep)
2240*12965SWilliam.Taylor@Oracle.COM {
2241*12965SWilliam.Taylor@Oracle.COM 	int			status;
2242*12965SWilliam.Taylor@Oracle.COM 
2243*12965SWilliam.Taylor@Oracle.COM 	status = hermon_cmn_ownership_cmd_post(state, HW2SW_MPT,
2244*12965SWilliam.Taylor@Oracle.COM 	    NULL, 0, mpt_indx, sleep);
2245*12965SWilliam.Taylor@Oracle.COM 	if (status != DDI_SUCCESS) {
2246*12965SWilliam.Taylor@Oracle.COM 		cmn_err(CE_CONT, "Hermon: fexch_mpt_fini: HW2SW_MPT command "
2247*12965SWilliam.Taylor@Oracle.COM 		    "failed: %08x\n", status);
2248*12965SWilliam.Taylor@Oracle.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
2249*12965SWilliam.Taylor@Oracle.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
2250*12965SWilliam.Taylor@Oracle.COM 		}
2251*12965SWilliam.Taylor@Oracle.COM 		status = ibc_get_ci_failure(0);
2252*12965SWilliam.Taylor@Oracle.COM 		return (status);
2253*12965SWilliam.Taylor@Oracle.COM 	}
2254*12965SWilliam.Taylor@Oracle.COM 
2255*12965SWilliam.Taylor@Oracle.COM 	/* Decrement the reference count on the protection domain (PD) */
2256*12965SWilliam.Taylor@Oracle.COM 	hermon_pd_refcnt_dec(pd);
2257*12965SWilliam.Taylor@Oracle.COM 
2258*12965SWilliam.Taylor@Oracle.COM 	return (DDI_SUCCESS);
2259*12965SWilliam.Taylor@Oracle.COM }
2260*12965SWilliam.Taylor@Oracle.COM 
2261*12965SWilliam.Taylor@Oracle.COM /*
22629517SBill.Taylor@Sun.COM  * hermon_mr_mtt_bind()
22639517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
22649517SBill.Taylor@Sun.COM  */
22659517SBill.Taylor@Sun.COM int
hermon_mr_mtt_bind(hermon_state_t * state,hermon_bind_info_t * bind,ddi_dma_handle_t bind_dmahdl,hermon_rsrc_t ** mtt,uint_t * mtt_pgsize_bits,uint_t is_buffer)22669517SBill.Taylor@Sun.COM hermon_mr_mtt_bind(hermon_state_t *state, hermon_bind_info_t *bind,
22679517SBill.Taylor@Sun.COM     ddi_dma_handle_t bind_dmahdl, hermon_rsrc_t **mtt, uint_t *mtt_pgsize_bits,
22689517SBill.Taylor@Sun.COM     uint_t is_buffer)
22699517SBill.Taylor@Sun.COM {
22709517SBill.Taylor@Sun.COM 	uint64_t		nummtt;
22719517SBill.Taylor@Sun.COM 	uint_t			sleep;
22729517SBill.Taylor@Sun.COM 	int			status;
22739517SBill.Taylor@Sun.COM 
22749517SBill.Taylor@Sun.COM 	/*
22759517SBill.Taylor@Sun.COM 	 * Check the sleep flag.  Ensure that it is consistent with the
22769517SBill.Taylor@Sun.COM 	 * current thread context (i.e. if we are currently in the interrupt
22779517SBill.Taylor@Sun.COM 	 * context, then we shouldn't be attempting to sleep).
22789517SBill.Taylor@Sun.COM 	 */
22799517SBill.Taylor@Sun.COM 	sleep = (bind->bi_flags & IBT_MR_NOSLEEP) ?
22809517SBill.Taylor@Sun.COM 	    HERMON_NOSLEEP : HERMON_SLEEP;
22819517SBill.Taylor@Sun.COM 	if ((sleep == HERMON_SLEEP) &&
22829517SBill.Taylor@Sun.COM 	    (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
22839517SBill.Taylor@Sun.COM 		status = IBT_INVALID_PARAM;
22849517SBill.Taylor@Sun.COM 		goto mrmttbind_fail;
22859517SBill.Taylor@Sun.COM 	}
22869517SBill.Taylor@Sun.COM 
22879517SBill.Taylor@Sun.COM 	/*
22889517SBill.Taylor@Sun.COM 	 * Bind the memory and determine the mapped addresses.  This is
22899517SBill.Taylor@Sun.COM 	 * the first of two routines that do all the "heavy lifting" for
22909517SBill.Taylor@Sun.COM 	 * the Hermon memory registration routines.  The hermon_mr_mem_bind()
22919517SBill.Taylor@Sun.COM 	 * routine takes the "bind" struct with all its fields filled
22929517SBill.Taylor@Sun.COM 	 * in and returns a list of DMA cookies (for the PCI mapped addresses
22939517SBill.Taylor@Sun.COM 	 * corresponding to the specified address region) which are used by
22949517SBill.Taylor@Sun.COM 	 * the hermon_mr_fast_mtt_write() routine below.  If we fail here, we
22959517SBill.Taylor@Sun.COM 	 * must undo all the previous resource allocation (and PD reference
22969517SBill.Taylor@Sun.COM 	 * count).
22979517SBill.Taylor@Sun.COM 	 */
22989517SBill.Taylor@Sun.COM 	status = hermon_mr_mem_bind(state, bind, bind_dmahdl, sleep, is_buffer);
22999517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
23009517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
23019517SBill.Taylor@Sun.COM 		goto mrmttbind_fail;
23029517SBill.Taylor@Sun.COM 	}
23039517SBill.Taylor@Sun.COM 
23049517SBill.Taylor@Sun.COM 	/*
23059517SBill.Taylor@Sun.COM 	 * Determine number of pages spanned.  This routine uses the
23069517SBill.Taylor@Sun.COM 	 * information in the "bind" struct to determine the required
23079517SBill.Taylor@Sun.COM 	 * number of MTT entries needed (and returns the suggested page size -
23089517SBill.Taylor@Sun.COM 	 * as a "power-of-2" - for each MTT entry).
23099517SBill.Taylor@Sun.COM 	 */
23109517SBill.Taylor@Sun.COM 	nummtt = hermon_mr_nummtt_needed(state, bind, mtt_pgsize_bits);
23119517SBill.Taylor@Sun.COM 
23129517SBill.Taylor@Sun.COM 	/*
23139517SBill.Taylor@Sun.COM 	 * Allocate the MTT entries.  Use the calculations performed above to
23149517SBill.Taylor@Sun.COM 	 * allocate the required number of MTT entries. If we fail here, we
23159517SBill.Taylor@Sun.COM 	 * must not only undo all the previous resource allocation (and PD
23169517SBill.Taylor@Sun.COM 	 * reference count), but we must also unbind the memory.
23179517SBill.Taylor@Sun.COM 	 */
23189517SBill.Taylor@Sun.COM 	status = hermon_rsrc_alloc(state, HERMON_MTT, nummtt, sleep, mtt);
23199517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
23209517SBill.Taylor@Sun.COM 		status = IBT_INSUFF_RESOURCE;
23219517SBill.Taylor@Sun.COM 		goto mrmttbind_fail2;
23229517SBill.Taylor@Sun.COM 	}
23239517SBill.Taylor@Sun.COM 
23249517SBill.Taylor@Sun.COM 	/*
23259517SBill.Taylor@Sun.COM 	 * Write the mapped addresses into the MTT entries.  This is part two
23269517SBill.Taylor@Sun.COM 	 * of the "heavy lifting" routines that we talked about above.  Note:
23279517SBill.Taylor@Sun.COM 	 * we pass the suggested page size from the earlier operation here.
23289517SBill.Taylor@Sun.COM 	 * And if we fail here, we again do pretty much the same huge clean up.
23299517SBill.Taylor@Sun.COM 	 */
23309517SBill.Taylor@Sun.COM 	status = hermon_mr_fast_mtt_write(state, *mtt, bind, *mtt_pgsize_bits);
23319517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
23329517SBill.Taylor@Sun.COM 		/*
23339517SBill.Taylor@Sun.COM 		 * hermon_mr_fast_mtt_write() returns DDI_FAILURE
23349517SBill.Taylor@Sun.COM 		 * only if it detects a HW error during DMA.
23359517SBill.Taylor@Sun.COM 		 */
23369517SBill.Taylor@Sun.COM 		hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
23379517SBill.Taylor@Sun.COM 		status = ibc_get_ci_failure(0);
23389517SBill.Taylor@Sun.COM 		goto mrmttbind_fail3;
23399517SBill.Taylor@Sun.COM 	}
23409517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
23419517SBill.Taylor@Sun.COM 
23429517SBill.Taylor@Sun.COM /*
23439517SBill.Taylor@Sun.COM  * The following is cleanup for all possible failure cases in this routine
23449517SBill.Taylor@Sun.COM  */
23459517SBill.Taylor@Sun.COM mrmttbind_fail3:
23469517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, mtt);
23479517SBill.Taylor@Sun.COM mrmttbind_fail2:
23489517SBill.Taylor@Sun.COM 	hermon_mr_mem_unbind(state, bind);
23499517SBill.Taylor@Sun.COM mrmttbind_fail:
23509517SBill.Taylor@Sun.COM 	return (status);
23519517SBill.Taylor@Sun.COM }
23529517SBill.Taylor@Sun.COM 
23539517SBill.Taylor@Sun.COM 
23549517SBill.Taylor@Sun.COM /*
23559517SBill.Taylor@Sun.COM  * hermon_mr_mtt_unbind()
23569517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
23579517SBill.Taylor@Sun.COM  */
23589517SBill.Taylor@Sun.COM int
hermon_mr_mtt_unbind(hermon_state_t * state,hermon_bind_info_t * bind,hermon_rsrc_t * mtt)23599517SBill.Taylor@Sun.COM hermon_mr_mtt_unbind(hermon_state_t *state, hermon_bind_info_t *bind,
23609517SBill.Taylor@Sun.COM     hermon_rsrc_t *mtt)
23619517SBill.Taylor@Sun.COM {
23629517SBill.Taylor@Sun.COM 	/*
23639517SBill.Taylor@Sun.COM 	 * Free up the MTT entries and unbind the memory.  Here, as above, we
23649517SBill.Taylor@Sun.COM 	 * attempt to free these resources only if it is appropriate to do so.
23659517SBill.Taylor@Sun.COM 	 */
23669517SBill.Taylor@Sun.COM 	hermon_mr_mem_unbind(state, bind);
23679517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &mtt);
23689517SBill.Taylor@Sun.COM 
23699517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
23709517SBill.Taylor@Sun.COM }
23719517SBill.Taylor@Sun.COM 
23729517SBill.Taylor@Sun.COM 
23739517SBill.Taylor@Sun.COM /*
23749517SBill.Taylor@Sun.COM  * hermon_mr_common_rereg()
23759517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
23769517SBill.Taylor@Sun.COM  */
23779517SBill.Taylor@Sun.COM static int
hermon_mr_common_rereg(hermon_state_t * state,hermon_mrhdl_t mr,hermon_pdhdl_t pd,hermon_bind_info_t * bind,hermon_mrhdl_t * mrhdl_new,hermon_mr_options_t * op)23789517SBill.Taylor@Sun.COM hermon_mr_common_rereg(hermon_state_t *state, hermon_mrhdl_t mr,
23799517SBill.Taylor@Sun.COM     hermon_pdhdl_t pd, hermon_bind_info_t *bind, hermon_mrhdl_t *mrhdl_new,
23809517SBill.Taylor@Sun.COM     hermon_mr_options_t *op)
23819517SBill.Taylor@Sun.COM {
23829517SBill.Taylor@Sun.COM 	hermon_rsrc_t		*mpt;
23839517SBill.Taylor@Sun.COM 	ibt_mr_attr_flags_t	acc_flags_to_use;
23849517SBill.Taylor@Sun.COM 	ibt_mr_flags_t		flags;
23859517SBill.Taylor@Sun.COM 	hermon_pdhdl_t		pd_to_use;
23869517SBill.Taylor@Sun.COM 	hermon_hw_dmpt_t	mpt_entry;
23879517SBill.Taylor@Sun.COM 	uint64_t		mtt_addr_to_use, vaddr_to_use, len_to_use;
23889517SBill.Taylor@Sun.COM 	uint_t			sleep, dereg_level;
23899517SBill.Taylor@Sun.COM 	int			status;
23909517SBill.Taylor@Sun.COM 
23919517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind))
23929517SBill.Taylor@Sun.COM 
23939517SBill.Taylor@Sun.COM 	/*
23949517SBill.Taylor@Sun.COM 	 * Check here to see if the memory region corresponds to a userland
23959517SBill.Taylor@Sun.COM 	 * mapping.  Reregistration of userland memory regions is not
23969517SBill.Taylor@Sun.COM 	 * currently supported.  Return failure.
23979517SBill.Taylor@Sun.COM 	 */
23989517SBill.Taylor@Sun.COM 	if (mr->mr_is_umem) {
23999517SBill.Taylor@Sun.COM 		status = IBT_MR_HDL_INVALID;
24009517SBill.Taylor@Sun.COM 		goto mrrereg_fail;
24019517SBill.Taylor@Sun.COM 	}
24029517SBill.Taylor@Sun.COM 
24039517SBill.Taylor@Sun.COM 	mutex_enter(&mr->mr_lock);
24049517SBill.Taylor@Sun.COM 
24059517SBill.Taylor@Sun.COM 	/* Pull MPT resource pointer from the Hermon Memory Region handle */
24069517SBill.Taylor@Sun.COM 	mpt = mr->mr_mptrsrcp;
24079517SBill.Taylor@Sun.COM 
24089517SBill.Taylor@Sun.COM 	/* Extract the flags field from the hermon_bind_info_t */
24099517SBill.Taylor@Sun.COM 	flags = bind->bi_flags;
24109517SBill.Taylor@Sun.COM 
24119517SBill.Taylor@Sun.COM 	/*
24129517SBill.Taylor@Sun.COM 	 * Check the sleep flag.  Ensure that it is consistent with the
24139517SBill.Taylor@Sun.COM 	 * current thread context (i.e. if we are currently in the interrupt
24149517SBill.Taylor@Sun.COM 	 * context, then we shouldn't be attempting to sleep).
24159517SBill.Taylor@Sun.COM 	 */
24169517SBill.Taylor@Sun.COM 	sleep = (flags & IBT_MR_NOSLEEP) ? HERMON_NOSLEEP: HERMON_SLEEP;
24179517SBill.Taylor@Sun.COM 	if ((sleep == HERMON_SLEEP) &&
24189517SBill.Taylor@Sun.COM 	    (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
24199517SBill.Taylor@Sun.COM 		mutex_exit(&mr->mr_lock);
24209517SBill.Taylor@Sun.COM 		status = IBT_INVALID_PARAM;
24219517SBill.Taylor@Sun.COM 		goto mrrereg_fail;
24229517SBill.Taylor@Sun.COM 	}
24239517SBill.Taylor@Sun.COM 
24249517SBill.Taylor@Sun.COM 	/*
24259517SBill.Taylor@Sun.COM 	 * First step is to temporarily invalidate the MPT entry.  This
24269517SBill.Taylor@Sun.COM 	 * regains ownership from the hardware, and gives us the opportunity
24279517SBill.Taylor@Sun.COM 	 * to modify the entry.  Note: The HW2SW_MPT command returns the
24289517SBill.Taylor@Sun.COM 	 * current MPT entry contents.  These are saved away here because
24299517SBill.Taylor@Sun.COM 	 * they will be reused in a later step below.  If the region has
24309517SBill.Taylor@Sun.COM 	 * bound memory windows that we fail returning an "in use" error code.
24319517SBill.Taylor@Sun.COM 	 * Otherwise, this is an unexpected error and we deregister the
24329517SBill.Taylor@Sun.COM 	 * memory region and return error.
24339517SBill.Taylor@Sun.COM 	 *
24349517SBill.Taylor@Sun.COM 	 * We use HERMON_CMD_NOSLEEP_SPIN here always because we must protect
24359517SBill.Taylor@Sun.COM 	 * against holding the lock around this rereg call in all contexts.
24369517SBill.Taylor@Sun.COM 	 */
24379517SBill.Taylor@Sun.COM 	status = hermon_cmn_ownership_cmd_post(state, HW2SW_MPT, &mpt_entry,
24389517SBill.Taylor@Sun.COM 	    sizeof (hermon_hw_dmpt_t), mpt->hr_indx, HERMON_CMD_NOSLEEP_SPIN);
24399517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
24409517SBill.Taylor@Sun.COM 		mutex_exit(&mr->mr_lock);
24419517SBill.Taylor@Sun.COM 		if (status == HERMON_CMD_REG_BOUND) {
24429517SBill.Taylor@Sun.COM 			return (IBT_MR_IN_USE);
24439517SBill.Taylor@Sun.COM 		} else {
24449517SBill.Taylor@Sun.COM 			cmn_err(CE_CONT, "Hermon: HW2SW_MPT command failed: "
24459517SBill.Taylor@Sun.COM 			    "%08x\n", status);
24469517SBill.Taylor@Sun.COM 			if (status == HERMON_CMD_INVALID_STATUS) {
24479517SBill.Taylor@Sun.COM 				hermon_fm_ereport(state, HCA_SYS_ERR,
24489517SBill.Taylor@Sun.COM 				    HCA_ERR_SRV_LOST);
24499517SBill.Taylor@Sun.COM 			}
24509517SBill.Taylor@Sun.COM 			/*
24519517SBill.Taylor@Sun.COM 			 * Call deregister and ensure that all current
24529517SBill.Taylor@Sun.COM 			 * resources get freed up
24539517SBill.Taylor@Sun.COM 			 */
24549517SBill.Taylor@Sun.COM 			if (hermon_mr_deregister(state, &mr,
24559517SBill.Taylor@Sun.COM 			    HERMON_MR_DEREG_ALL, sleep) != DDI_SUCCESS) {
24569517SBill.Taylor@Sun.COM 				HERMON_WARNING(state, "failed to deregister "
24579517SBill.Taylor@Sun.COM 				    "memory region");
24589517SBill.Taylor@Sun.COM 			}
24599517SBill.Taylor@Sun.COM 			return (ibc_get_ci_failure(0));
24609517SBill.Taylor@Sun.COM 		}
24619517SBill.Taylor@Sun.COM 	}
24629517SBill.Taylor@Sun.COM 
24639517SBill.Taylor@Sun.COM 	/*
24649517SBill.Taylor@Sun.COM 	 * If we're changing the protection domain, then validate the new one
24659517SBill.Taylor@Sun.COM 	 */
24669517SBill.Taylor@Sun.COM 	if (flags & IBT_MR_CHANGE_PD) {
24679517SBill.Taylor@Sun.COM 
24689517SBill.Taylor@Sun.COM 		/* Check for valid PD handle pointer */
24699517SBill.Taylor@Sun.COM 		if (pd == NULL) {
24709517SBill.Taylor@Sun.COM 			mutex_exit(&mr->mr_lock);
24719517SBill.Taylor@Sun.COM 			/*
24729517SBill.Taylor@Sun.COM 			 * Call deregister and ensure that all current
24739517SBill.Taylor@Sun.COM 			 * resources get properly freed up. Unnecessary
24749517SBill.Taylor@Sun.COM 			 * here to attempt to regain software ownership
24759517SBill.Taylor@Sun.COM 			 * of the MPT entry as that has already been
24769517SBill.Taylor@Sun.COM 			 * done above.
24779517SBill.Taylor@Sun.COM 			 */
24789517SBill.Taylor@Sun.COM 			if (hermon_mr_deregister(state, &mr,
24799517SBill.Taylor@Sun.COM 			    HERMON_MR_DEREG_NO_HW2SW_MPT, sleep) !=
24809517SBill.Taylor@Sun.COM 			    DDI_SUCCESS) {
24819517SBill.Taylor@Sun.COM 				HERMON_WARNING(state, "failed to deregister "
24829517SBill.Taylor@Sun.COM 				    "memory region");
24839517SBill.Taylor@Sun.COM 			}
24849517SBill.Taylor@Sun.COM 			status = IBT_PD_HDL_INVALID;
24859517SBill.Taylor@Sun.COM 			goto mrrereg_fail;
24869517SBill.Taylor@Sun.COM 		}
24879517SBill.Taylor@Sun.COM 
24889517SBill.Taylor@Sun.COM 		/* Use the new PD handle in all operations below */
24899517SBill.Taylor@Sun.COM 		pd_to_use = pd;
24909517SBill.Taylor@Sun.COM 
24919517SBill.Taylor@Sun.COM 	} else {
24929517SBill.Taylor@Sun.COM 		/* Use the current PD handle in all operations below */
24939517SBill.Taylor@Sun.COM 		pd_to_use = mr->mr_pdhdl;
24949517SBill.Taylor@Sun.COM 	}
24959517SBill.Taylor@Sun.COM 
24969517SBill.Taylor@Sun.COM 	/*
24979517SBill.Taylor@Sun.COM 	 * If we're changing access permissions, then validate the new ones
24989517SBill.Taylor@Sun.COM 	 */
24999517SBill.Taylor@Sun.COM 	if (flags & IBT_MR_CHANGE_ACCESS) {
25009517SBill.Taylor@Sun.COM 		/*
25019517SBill.Taylor@Sun.COM 		 * Validate the access flags.  Both remote write and remote
25029517SBill.Taylor@Sun.COM 		 * atomic require the local write flag to be set
25039517SBill.Taylor@Sun.COM 		 */
25049517SBill.Taylor@Sun.COM 		if (((flags & IBT_MR_ENABLE_REMOTE_WRITE) ||
25059517SBill.Taylor@Sun.COM 		    (flags & IBT_MR_ENABLE_REMOTE_ATOMIC)) &&
25069517SBill.Taylor@Sun.COM 		    !(flags & IBT_MR_ENABLE_LOCAL_WRITE)) {
25079517SBill.Taylor@Sun.COM 			mutex_exit(&mr->mr_lock);
25089517SBill.Taylor@Sun.COM 			/*
25099517SBill.Taylor@Sun.COM 			 * Call deregister and ensure that all current
25109517SBill.Taylor@Sun.COM 			 * resources get properly freed up. Unnecessary
25119517SBill.Taylor@Sun.COM 			 * here to attempt to regain software ownership
25129517SBill.Taylor@Sun.COM 			 * of the MPT entry as that has already been
25139517SBill.Taylor@Sun.COM 			 * done above.
25149517SBill.Taylor@Sun.COM 			 */
25159517SBill.Taylor@Sun.COM 			if (hermon_mr_deregister(state, &mr,
25169517SBill.Taylor@Sun.COM 			    HERMON_MR_DEREG_NO_HW2SW_MPT, sleep) !=
25179517SBill.Taylor@Sun.COM 			    DDI_SUCCESS) {
25189517SBill.Taylor@Sun.COM 				HERMON_WARNING(state, "failed to deregister "
25199517SBill.Taylor@Sun.COM 				    "memory region");
25209517SBill.Taylor@Sun.COM 			}
25219517SBill.Taylor@Sun.COM 			status = IBT_MR_ACCESS_REQ_INVALID;
25229517SBill.Taylor@Sun.COM 			goto mrrereg_fail;
25239517SBill.Taylor@Sun.COM 		}
25249517SBill.Taylor@Sun.COM 
25259517SBill.Taylor@Sun.COM 		/*
25269517SBill.Taylor@Sun.COM 		 * Setup and validate the memory region access flags.  This
25279517SBill.Taylor@Sun.COM 		 * means translating the IBTF's enable flags into the access
25289517SBill.Taylor@Sun.COM 		 * flags that will be used in later operations.
25299517SBill.Taylor@Sun.COM 		 */
25309517SBill.Taylor@Sun.COM 		acc_flags_to_use = 0;
25319517SBill.Taylor@Sun.COM 		if (flags & IBT_MR_ENABLE_WINDOW_BIND)
25329517SBill.Taylor@Sun.COM 			acc_flags_to_use |= IBT_MR_WINDOW_BIND;
25339517SBill.Taylor@Sun.COM 		if (flags & IBT_MR_ENABLE_LOCAL_WRITE)
25349517SBill.Taylor@Sun.COM 			acc_flags_to_use |= IBT_MR_LOCAL_WRITE;
25359517SBill.Taylor@Sun.COM 		if (flags & IBT_MR_ENABLE_REMOTE_READ)
25369517SBill.Taylor@Sun.COM 			acc_flags_to_use |= IBT_MR_REMOTE_READ;
25379517SBill.Taylor@Sun.COM 		if (flags & IBT_MR_ENABLE_REMOTE_WRITE)
25389517SBill.Taylor@Sun.COM 			acc_flags_to_use |= IBT_MR_REMOTE_WRITE;
25399517SBill.Taylor@Sun.COM 		if (flags & IBT_MR_ENABLE_REMOTE_ATOMIC)
25409517SBill.Taylor@Sun.COM 			acc_flags_to_use |= IBT_MR_REMOTE_ATOMIC;
25419517SBill.Taylor@Sun.COM 
25429517SBill.Taylor@Sun.COM 	} else {
25439517SBill.Taylor@Sun.COM 		acc_flags_to_use = mr->mr_accflag;
25449517SBill.Taylor@Sun.COM 	}
25459517SBill.Taylor@Sun.COM 
25469517SBill.Taylor@Sun.COM 	/*
25479517SBill.Taylor@Sun.COM 	 * If we're modifying the translation, then figure out whether
25489517SBill.Taylor@Sun.COM 	 * we can reuse the current MTT resources.  This means calling
25499517SBill.Taylor@Sun.COM 	 * hermon_mr_rereg_xlat_helper() which does most of the heavy lifting
25509517SBill.Taylor@Sun.COM 	 * for the reregistration.  If the current memory region contains
25519517SBill.Taylor@Sun.COM 	 * sufficient MTT entries for the new regions, then it will be
25529517SBill.Taylor@Sun.COM 	 * reused and filled in.  Otherwise, new entries will be allocated,
25539517SBill.Taylor@Sun.COM 	 * the old ones will be freed, and the new entries will be filled
25549517SBill.Taylor@Sun.COM 	 * in.  Note:  If we're not modifying the translation, then we
25559517SBill.Taylor@Sun.COM 	 * should already have all the information we need to update the MPT.
25569517SBill.Taylor@Sun.COM 	 * Also note: If hermon_mr_rereg_xlat_helper() fails, it will return
25579517SBill.Taylor@Sun.COM 	 * a "dereg_level" which is the level of cleanup that needs to be
25589517SBill.Taylor@Sun.COM 	 * passed to hermon_mr_deregister() to finish the cleanup.
25599517SBill.Taylor@Sun.COM 	 */
25609517SBill.Taylor@Sun.COM 	if (flags & IBT_MR_CHANGE_TRANSLATION) {
25619517SBill.Taylor@Sun.COM 		status = hermon_mr_rereg_xlat_helper(state, mr, bind, op,
25629517SBill.Taylor@Sun.COM 		    &mtt_addr_to_use, sleep, &dereg_level);
25639517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
25649517SBill.Taylor@Sun.COM 			mutex_exit(&mr->mr_lock);
25659517SBill.Taylor@Sun.COM 			/*
25669517SBill.Taylor@Sun.COM 			 * Call deregister and ensure that all resources get
25679517SBill.Taylor@Sun.COM 			 * properly freed up.
25689517SBill.Taylor@Sun.COM 			 */
25699517SBill.Taylor@Sun.COM 			if (hermon_mr_deregister(state, &mr, dereg_level,
25709517SBill.Taylor@Sun.COM 			    sleep) != DDI_SUCCESS) {
25719517SBill.Taylor@Sun.COM 				HERMON_WARNING(state, "failed to deregister "
25729517SBill.Taylor@Sun.COM 				    "memory region");
25739517SBill.Taylor@Sun.COM 			}
25749517SBill.Taylor@Sun.COM 			goto mrrereg_fail;
25759517SBill.Taylor@Sun.COM 		}
25769517SBill.Taylor@Sun.COM 		vaddr_to_use = mr->mr_bindinfo.bi_addr;
25779517SBill.Taylor@Sun.COM 		len_to_use   = mr->mr_bindinfo.bi_len;
25789517SBill.Taylor@Sun.COM 	} else {
25799517SBill.Taylor@Sun.COM 		mtt_addr_to_use = mr->mr_mttaddr;
25809517SBill.Taylor@Sun.COM 		vaddr_to_use = mr->mr_bindinfo.bi_addr;
25819517SBill.Taylor@Sun.COM 		len_to_use   = mr->mr_bindinfo.bi_len;
25829517SBill.Taylor@Sun.COM 	}
25839517SBill.Taylor@Sun.COM 
25849517SBill.Taylor@Sun.COM 	/*
25859517SBill.Taylor@Sun.COM 	 * Calculate new keys (Lkey, Rkey) from MPT index.  Just like they were
25869517SBill.Taylor@Sun.COM 	 * when the region was first registered, each key is formed from
25879517SBill.Taylor@Sun.COM 	 * "constrained" bits and "unconstrained" bits.  Note:  If no remote
25889517SBill.Taylor@Sun.COM 	 * access is required, then the RKey value is not filled in.  Otherwise
25899517SBill.Taylor@Sun.COM 	 * both Rkey and LKey are given the same value.
25909517SBill.Taylor@Sun.COM 	 */
25919517SBill.Taylor@Sun.COM 	mr->mr_lkey = hermon_mr_keycalc(mpt->hr_indx);
25929517SBill.Taylor@Sun.COM 	if ((acc_flags_to_use & IBT_MR_REMOTE_READ) ||
25939517SBill.Taylor@Sun.COM 	    (acc_flags_to_use & IBT_MR_REMOTE_WRITE) ||
25949517SBill.Taylor@Sun.COM 	    (acc_flags_to_use & IBT_MR_REMOTE_ATOMIC)) {
25959517SBill.Taylor@Sun.COM 		mr->mr_rkey = mr->mr_lkey;
25969517SBill.Taylor@Sun.COM 	} else
25979517SBill.Taylor@Sun.COM 		mr->mr_rkey = 0;
25989517SBill.Taylor@Sun.COM 
25999517SBill.Taylor@Sun.COM 	/*
26009517SBill.Taylor@Sun.COM 	 * Fill in the MPT entry.  This is the final step before passing
26019517SBill.Taylor@Sun.COM 	 * ownership of the MPT entry to the Hermon hardware.  We use all of
26029517SBill.Taylor@Sun.COM 	 * the information collected/calculated above to fill in the
26039517SBill.Taylor@Sun.COM 	 * requisite portions of the MPT.
26049517SBill.Taylor@Sun.COM 	 */
26059517SBill.Taylor@Sun.COM 	bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
26069517SBill.Taylor@Sun.COM 
26079517SBill.Taylor@Sun.COM 	mpt_entry.status  = HERMON_MPT_SW_OWNERSHIP;
26089517SBill.Taylor@Sun.COM 	mpt_entry.en_bind = (acc_flags_to_use & IBT_MR_WINDOW_BIND)   ? 1 : 0;
26099517SBill.Taylor@Sun.COM 	mpt_entry.atomic  = (acc_flags_to_use & IBT_MR_REMOTE_ATOMIC) ? 1 : 0;
26109517SBill.Taylor@Sun.COM 	mpt_entry.rw	  = (acc_flags_to_use & IBT_MR_REMOTE_WRITE)  ? 1 : 0;
26119517SBill.Taylor@Sun.COM 	mpt_entry.rr	  = (acc_flags_to_use & IBT_MR_REMOTE_READ)   ? 1 : 0;
26129517SBill.Taylor@Sun.COM 	mpt_entry.lw	  = (acc_flags_to_use & IBT_MR_LOCAL_WRITE)   ? 1 : 0;
26139517SBill.Taylor@Sun.COM 	mpt_entry.lr	  = 1;
26149517SBill.Taylor@Sun.COM 	mpt_entry.phys_addr = 0;
26159517SBill.Taylor@Sun.COM 	mpt_entry.reg_win = HERMON_MPT_IS_REGION;
26169517SBill.Taylor@Sun.COM 
26179517SBill.Taylor@Sun.COM 	mpt_entry.entity_sz	= mr->mr_logmttpgsz;
26189517SBill.Taylor@Sun.COM 	mpt_entry.mem_key	= mr->mr_lkey;
26199517SBill.Taylor@Sun.COM 	mpt_entry.pd		= pd_to_use->pd_pdnum;
26209517SBill.Taylor@Sun.COM 
26219517SBill.Taylor@Sun.COM 	mpt_entry.start_addr	= vaddr_to_use;
26229517SBill.Taylor@Sun.COM 	mpt_entry.reg_win_len	= len_to_use;
26239517SBill.Taylor@Sun.COM 	mpt_entry.mtt_addr_h = mtt_addr_to_use >> 32;
26249517SBill.Taylor@Sun.COM 	mpt_entry.mtt_addr_l = mtt_addr_to_use >> 3;
26259517SBill.Taylor@Sun.COM 
26269517SBill.Taylor@Sun.COM 	/*
26279517SBill.Taylor@Sun.COM 	 * Write the updated MPT entry to hardware
26289517SBill.Taylor@Sun.COM 	 *
26299517SBill.Taylor@Sun.COM 	 * We use HERMON_CMD_NOSLEEP_SPIN here always because we must protect
26309517SBill.Taylor@Sun.COM 	 * against holding the lock around this rereg call in all contexts.
26319517SBill.Taylor@Sun.COM 	 */
26329517SBill.Taylor@Sun.COM 	status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
26339517SBill.Taylor@Sun.COM 	    sizeof (hermon_hw_dmpt_t), mpt->hr_indx, HERMON_CMD_NOSLEEP_SPIN);
26349517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
26359517SBill.Taylor@Sun.COM 		mutex_exit(&mr->mr_lock);
26369517SBill.Taylor@Sun.COM 		cmn_err(CE_CONT, "Hermon: SW2HW_MPT command failed: %08x\n",
26379517SBill.Taylor@Sun.COM 		    status);
26389517SBill.Taylor@Sun.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
26399517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
26409517SBill.Taylor@Sun.COM 		}
26419517SBill.Taylor@Sun.COM 		/*
26429517SBill.Taylor@Sun.COM 		 * Call deregister and ensure that all current resources get
26439517SBill.Taylor@Sun.COM 		 * properly freed up. Unnecessary here to attempt to regain
26449517SBill.Taylor@Sun.COM 		 * software ownership of the MPT entry as that has already
26459517SBill.Taylor@Sun.COM 		 * been done above.
26469517SBill.Taylor@Sun.COM 		 */
26479517SBill.Taylor@Sun.COM 		if (hermon_mr_deregister(state, &mr,
26489517SBill.Taylor@Sun.COM 		    HERMON_MR_DEREG_NO_HW2SW_MPT, sleep) != DDI_SUCCESS) {
26499517SBill.Taylor@Sun.COM 			HERMON_WARNING(state, "failed to deregister memory "
26509517SBill.Taylor@Sun.COM 			    "region");
26519517SBill.Taylor@Sun.COM 		}
26529517SBill.Taylor@Sun.COM 		return (ibc_get_ci_failure(0));
26539517SBill.Taylor@Sun.COM 	}
26549517SBill.Taylor@Sun.COM 
26559517SBill.Taylor@Sun.COM 	/*
26569517SBill.Taylor@Sun.COM 	 * If we're changing PD, then update their reference counts now.
26579517SBill.Taylor@Sun.COM 	 * This means decrementing the reference count on the old PD and
26589517SBill.Taylor@Sun.COM 	 * incrementing the reference count on the new PD.
26599517SBill.Taylor@Sun.COM 	 */
26609517SBill.Taylor@Sun.COM 	if (flags & IBT_MR_CHANGE_PD) {
26619517SBill.Taylor@Sun.COM 		hermon_pd_refcnt_dec(mr->mr_pdhdl);
26629517SBill.Taylor@Sun.COM 		hermon_pd_refcnt_inc(pd);
26639517SBill.Taylor@Sun.COM 	}
26649517SBill.Taylor@Sun.COM 
26659517SBill.Taylor@Sun.COM 	/*
26669517SBill.Taylor@Sun.COM 	 * Update the contents of the Hermon Memory Region handle to reflect
26679517SBill.Taylor@Sun.COM 	 * what has been changed.
26689517SBill.Taylor@Sun.COM 	 */
26699517SBill.Taylor@Sun.COM 	mr->mr_pdhdl	  = pd_to_use;
26709517SBill.Taylor@Sun.COM 	mr->mr_accflag	  = acc_flags_to_use;
26719517SBill.Taylor@Sun.COM 	mr->mr_is_umem	  = 0;
26729517SBill.Taylor@Sun.COM 	mr->mr_is_fmr	  = 0;
26739517SBill.Taylor@Sun.COM 	mr->mr_umemcookie = NULL;
26749517SBill.Taylor@Sun.COM 	mr->mr_lkey	  = hermon_mr_key_swap(mr->mr_lkey);
26759517SBill.Taylor@Sun.COM 	mr->mr_rkey	  = hermon_mr_key_swap(mr->mr_rkey);
26769517SBill.Taylor@Sun.COM 
26779517SBill.Taylor@Sun.COM 	/* New MR handle is same as the old */
26789517SBill.Taylor@Sun.COM 	*mrhdl_new = mr;
26799517SBill.Taylor@Sun.COM 	mutex_exit(&mr->mr_lock);
26809517SBill.Taylor@Sun.COM 
26819517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
26829517SBill.Taylor@Sun.COM 
26839517SBill.Taylor@Sun.COM mrrereg_fail:
26849517SBill.Taylor@Sun.COM 	return (status);
26859517SBill.Taylor@Sun.COM }
26869517SBill.Taylor@Sun.COM 
26879517SBill.Taylor@Sun.COM 
26889517SBill.Taylor@Sun.COM /*
26899517SBill.Taylor@Sun.COM  * hermon_mr_rereg_xlat_helper
26909517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
26919517SBill.Taylor@Sun.COM  *    Note: This routine expects the "mr_lock" to be held when it
26929517SBill.Taylor@Sun.COM  *    is called.  Upon returning failure, this routine passes information
26939517SBill.Taylor@Sun.COM  *    about what "dereg_level" should be passed to hermon_mr_deregister().
26949517SBill.Taylor@Sun.COM  */
26959517SBill.Taylor@Sun.COM static int
hermon_mr_rereg_xlat_helper(hermon_state_t * state,hermon_mrhdl_t mr,hermon_bind_info_t * bind,hermon_mr_options_t * op,uint64_t * mtt_addr,uint_t sleep,uint_t * dereg_level)26969517SBill.Taylor@Sun.COM hermon_mr_rereg_xlat_helper(hermon_state_t *state, hermon_mrhdl_t mr,
26979517SBill.Taylor@Sun.COM     hermon_bind_info_t *bind, hermon_mr_options_t *op, uint64_t *mtt_addr,
26989517SBill.Taylor@Sun.COM     uint_t sleep, uint_t *dereg_level)
26999517SBill.Taylor@Sun.COM {
27009517SBill.Taylor@Sun.COM 	hermon_rsrc_t		*mtt, *mtt_refcnt;
27019517SBill.Taylor@Sun.COM 	hermon_sw_refcnt_t	*swrc_old, *swrc_new;
27029517SBill.Taylor@Sun.COM 	ddi_dma_handle_t	dmahdl;
27039517SBill.Taylor@Sun.COM 	uint64_t		nummtt_needed, nummtt_in_currrsrc, max_sz;
27049517SBill.Taylor@Sun.COM 	uint_t			mtt_pgsize_bits, bind_type, reuse_dmahdl;
27059517SBill.Taylor@Sun.COM 	int			status;
27069517SBill.Taylor@Sun.COM 
27079517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&mr->mr_lock));
27089517SBill.Taylor@Sun.COM 
27099517SBill.Taylor@Sun.COM 	/*
27109517SBill.Taylor@Sun.COM 	 * Check the "options" flag.  Currently this flag tells the driver
27119517SBill.Taylor@Sun.COM 	 * whether or not the region should be bound normally (i.e. with
27129517SBill.Taylor@Sun.COM 	 * entries written into the PCI IOMMU) or whether it should be
27139517SBill.Taylor@Sun.COM 	 * registered to bypass the IOMMU.
27149517SBill.Taylor@Sun.COM 	 */
27159517SBill.Taylor@Sun.COM 	if (op == NULL) {
27169517SBill.Taylor@Sun.COM 		bind_type = HERMON_BINDMEM_NORMAL;
27179517SBill.Taylor@Sun.COM 	} else {
27189517SBill.Taylor@Sun.COM 		bind_type = op->mro_bind_type;
27199517SBill.Taylor@Sun.COM 	}
27209517SBill.Taylor@Sun.COM 
27219517SBill.Taylor@Sun.COM 	/*
27229517SBill.Taylor@Sun.COM 	 * Check for invalid length.  Check is the length is zero or if the
27239517SBill.Taylor@Sun.COM 	 * length is larger than the maximum configured value.  Return error
27249517SBill.Taylor@Sun.COM 	 * if it is.
27259517SBill.Taylor@Sun.COM 	 */
27269517SBill.Taylor@Sun.COM 	max_sz = ((uint64_t)1 << state->hs_cfg_profile->cp_log_max_mrw_sz);
27279517SBill.Taylor@Sun.COM 	if ((bind->bi_len == 0) || (bind->bi_len > max_sz)) {
27289517SBill.Taylor@Sun.COM 		/*
27299517SBill.Taylor@Sun.COM 		 * Deregister will be called upon returning failure from this
27309517SBill.Taylor@Sun.COM 		 * routine. This will ensure that all current resources get
27319517SBill.Taylor@Sun.COM 		 * properly freed up. Unnecessary to attempt to regain
27329517SBill.Taylor@Sun.COM 		 * software ownership of the MPT entry as that has already
27339517SBill.Taylor@Sun.COM 		 * been done above (in hermon_mr_reregister())
27349517SBill.Taylor@Sun.COM 		 */
27359517SBill.Taylor@Sun.COM 		*dereg_level = HERMON_MR_DEREG_NO_HW2SW_MPT;
27369517SBill.Taylor@Sun.COM 
27379517SBill.Taylor@Sun.COM 		status = IBT_MR_LEN_INVALID;
27389517SBill.Taylor@Sun.COM 		goto mrrereghelp_fail;
27399517SBill.Taylor@Sun.COM 	}
27409517SBill.Taylor@Sun.COM 
27419517SBill.Taylor@Sun.COM 	/*
27429517SBill.Taylor@Sun.COM 	 * Determine the number of pages necessary for new region and the
27439517SBill.Taylor@Sun.COM 	 * number of pages supported by the current MTT resources
27449517SBill.Taylor@Sun.COM 	 */
27459517SBill.Taylor@Sun.COM 	nummtt_needed = hermon_mr_nummtt_needed(state, bind, &mtt_pgsize_bits);
27469517SBill.Taylor@Sun.COM 	nummtt_in_currrsrc = mr->mr_mttrsrcp->hr_len >> HERMON_MTT_SIZE_SHIFT;
27479517SBill.Taylor@Sun.COM 
27489517SBill.Taylor@Sun.COM 	/*
27499517SBill.Taylor@Sun.COM 	 * Depending on whether we have enough pages or not, the next step is
27509517SBill.Taylor@Sun.COM 	 * to fill in a set of MTT entries that reflect the new mapping.  In
27519517SBill.Taylor@Sun.COM 	 * the first case below, we already have enough entries.  This means
27529517SBill.Taylor@Sun.COM 	 * we need to unbind the memory from the previous mapping, bind the
27539517SBill.Taylor@Sun.COM 	 * memory for the new mapping, write the new MTT entries, and update
27549517SBill.Taylor@Sun.COM 	 * the mr to reflect the changes.
27559517SBill.Taylor@Sun.COM 	 * In the second case below, we do not have enough entries in the
27569517SBill.Taylor@Sun.COM 	 * current mapping.  So, in this case, we need not only to unbind the
27579517SBill.Taylor@Sun.COM 	 * current mapping, but we need to free up the MTT resources associated
27589517SBill.Taylor@Sun.COM 	 * with that mapping.  After we've successfully done that, we continue
27599517SBill.Taylor@Sun.COM 	 * by binding the new memory, allocating new MTT entries, writing the
27609517SBill.Taylor@Sun.COM 	 * new MTT entries, and updating the mr to reflect the changes.
27619517SBill.Taylor@Sun.COM 	 */
27629517SBill.Taylor@Sun.COM 
27639517SBill.Taylor@Sun.COM 	/*
27649517SBill.Taylor@Sun.COM 	 * If this region is being shared (i.e. MTT refcount != 1), then we
27659517SBill.Taylor@Sun.COM 	 * can't reuse the current MTT resources regardless of their size.
27669517SBill.Taylor@Sun.COM 	 * Instead we'll need to alloc new ones (below) just as if there
27679517SBill.Taylor@Sun.COM 	 * hadn't been enough room in the current entries.
27689517SBill.Taylor@Sun.COM 	 */
27699517SBill.Taylor@Sun.COM 	swrc_old = (hermon_sw_refcnt_t *)mr->mr_mttrefcntp->hr_addr;
27709517SBill.Taylor@Sun.COM 	if (HERMON_MTT_IS_NOT_SHARED(swrc_old) &&
27719517SBill.Taylor@Sun.COM 	    (nummtt_needed <= nummtt_in_currrsrc)) {
27729517SBill.Taylor@Sun.COM 
27739517SBill.Taylor@Sun.COM 		/*
27749517SBill.Taylor@Sun.COM 		 * Unbind the old mapping for this memory region, but retain
27759517SBill.Taylor@Sun.COM 		 * the ddi_dma_handle_t (if possible) for reuse in the bind
27769517SBill.Taylor@Sun.COM 		 * operation below.  Note:  If original memory region was
27779517SBill.Taylor@Sun.COM 		 * bound for IOMMU bypass and the new region can not use
27789517SBill.Taylor@Sun.COM 		 * bypass, then a new DMA handle will be necessary.
27799517SBill.Taylor@Sun.COM 		 */
27809517SBill.Taylor@Sun.COM 		if (HERMON_MR_REUSE_DMAHDL(mr, bind->bi_flags)) {
27819517SBill.Taylor@Sun.COM 			mr->mr_bindinfo.bi_free_dmahdl = 0;
27829517SBill.Taylor@Sun.COM 			hermon_mr_mem_unbind(state, &mr->mr_bindinfo);
27839517SBill.Taylor@Sun.COM 			dmahdl = mr->mr_bindinfo.bi_dmahdl;
27849517SBill.Taylor@Sun.COM 			reuse_dmahdl = 1;
27859517SBill.Taylor@Sun.COM 		} else {
27869517SBill.Taylor@Sun.COM 			hermon_mr_mem_unbind(state, &mr->mr_bindinfo);
27879517SBill.Taylor@Sun.COM 			dmahdl = NULL;
27889517SBill.Taylor@Sun.COM 			reuse_dmahdl = 0;
27899517SBill.Taylor@Sun.COM 		}
27909517SBill.Taylor@Sun.COM 
27919517SBill.Taylor@Sun.COM 		/*
27929517SBill.Taylor@Sun.COM 		 * Bind the new memory and determine the mapped addresses.
27939517SBill.Taylor@Sun.COM 		 * As described, this routine and hermon_mr_fast_mtt_write()
27949517SBill.Taylor@Sun.COM 		 * do the majority of the work for the memory registration
27959517SBill.Taylor@Sun.COM 		 * operations.  Note:  When we successfully finish the binding,
27969517SBill.Taylor@Sun.COM 		 * we will set the "bi_free_dmahdl" flag to indicate that
27979517SBill.Taylor@Sun.COM 		 * even though we may have reused the ddi_dma_handle_t we do
27989517SBill.Taylor@Sun.COM 		 * wish it to be freed up at some later time.  Note also that
27999517SBill.Taylor@Sun.COM 		 * if we fail, we may need to cleanup the ddi_dma_handle_t.
28009517SBill.Taylor@Sun.COM 		 */
28019517SBill.Taylor@Sun.COM 		bind->bi_bypass	= bind_type;
28029517SBill.Taylor@Sun.COM 		status = hermon_mr_mem_bind(state, bind, dmahdl, sleep, 1);
28039517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
28049517SBill.Taylor@Sun.COM 			if (reuse_dmahdl) {
28059517SBill.Taylor@Sun.COM 				ddi_dma_free_handle(&dmahdl);
28069517SBill.Taylor@Sun.COM 			}
28079517SBill.Taylor@Sun.COM 
28089517SBill.Taylor@Sun.COM 			/*
28099517SBill.Taylor@Sun.COM 			 * Deregister will be called upon returning failure
28109517SBill.Taylor@Sun.COM 			 * from this routine. This will ensure that all
28119517SBill.Taylor@Sun.COM 			 * current resources get properly freed up.
28129517SBill.Taylor@Sun.COM 			 * Unnecessary to attempt to regain software ownership
28139517SBill.Taylor@Sun.COM 			 * of the MPT entry as that has already been done
28149517SBill.Taylor@Sun.COM 			 * above (in hermon_mr_reregister()).  Also unnecessary
28159517SBill.Taylor@Sun.COM 			 * to attempt to unbind the memory.
28169517SBill.Taylor@Sun.COM 			 */
28179517SBill.Taylor@Sun.COM 			*dereg_level = HERMON_MR_DEREG_NO_HW2SW_MPT_OR_UNBIND;
28189517SBill.Taylor@Sun.COM 
28199517SBill.Taylor@Sun.COM 			status = IBT_INSUFF_RESOURCE;
28209517SBill.Taylor@Sun.COM 			goto mrrereghelp_fail;
28219517SBill.Taylor@Sun.COM 		}
28229517SBill.Taylor@Sun.COM 		if (reuse_dmahdl) {
28239517SBill.Taylor@Sun.COM 			bind->bi_free_dmahdl = 1;
28249517SBill.Taylor@Sun.COM 		}
28259517SBill.Taylor@Sun.COM 
28269517SBill.Taylor@Sun.COM 		/*
28279517SBill.Taylor@Sun.COM 		 * Using the new mapping, but reusing the current MTT
28289517SBill.Taylor@Sun.COM 		 * resources, write the updated entries to MTT
28299517SBill.Taylor@Sun.COM 		 */
28309517SBill.Taylor@Sun.COM 		mtt    = mr->mr_mttrsrcp;
28319517SBill.Taylor@Sun.COM 		status = hermon_mr_fast_mtt_write(state, mtt, bind,
28329517SBill.Taylor@Sun.COM 		    mtt_pgsize_bits);
28339517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
28349517SBill.Taylor@Sun.COM 			/*
28359517SBill.Taylor@Sun.COM 			 * Deregister will be called upon returning failure
28369517SBill.Taylor@Sun.COM 			 * from this routine. This will ensure that all
28379517SBill.Taylor@Sun.COM 			 * current resources get properly freed up.
28389517SBill.Taylor@Sun.COM 			 * Unnecessary to attempt to regain software ownership
28399517SBill.Taylor@Sun.COM 			 * of the MPT entry as that has already been done
28409517SBill.Taylor@Sun.COM 			 * above (in hermon_mr_reregister()).  Also unnecessary
28419517SBill.Taylor@Sun.COM 			 * to attempt to unbind the memory.
28429517SBill.Taylor@Sun.COM 			 *
28439517SBill.Taylor@Sun.COM 			 * But we do need to unbind the newly bound memory
28449517SBill.Taylor@Sun.COM 			 * before returning.
28459517SBill.Taylor@Sun.COM 			 */
28469517SBill.Taylor@Sun.COM 			hermon_mr_mem_unbind(state, bind);
28479517SBill.Taylor@Sun.COM 			*dereg_level = HERMON_MR_DEREG_NO_HW2SW_MPT_OR_UNBIND;
28489517SBill.Taylor@Sun.COM 
28499517SBill.Taylor@Sun.COM 			/*
28509517SBill.Taylor@Sun.COM 			 * hermon_mr_fast_mtt_write() returns DDI_FAILURE
28519517SBill.Taylor@Sun.COM 			 * only if it detects a HW error during DMA.
28529517SBill.Taylor@Sun.COM 			 */
28539517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
28549517SBill.Taylor@Sun.COM 			status = ibc_get_ci_failure(0);
28559517SBill.Taylor@Sun.COM 			goto mrrereghelp_fail;
28569517SBill.Taylor@Sun.COM 		}
28579517SBill.Taylor@Sun.COM 
28589517SBill.Taylor@Sun.COM 		/* Put the updated information into the Mem Region handle */
28599517SBill.Taylor@Sun.COM 		mr->mr_bindinfo	  = *bind;
28609517SBill.Taylor@Sun.COM 		mr->mr_logmttpgsz = mtt_pgsize_bits;
28619517SBill.Taylor@Sun.COM 
28629517SBill.Taylor@Sun.COM 	} else {
28639517SBill.Taylor@Sun.COM 		/*
28649517SBill.Taylor@Sun.COM 		 * Check if the memory region MTT is shared by any other MRs.
28659517SBill.Taylor@Sun.COM 		 * Since the resource may be shared between multiple memory
28669517SBill.Taylor@Sun.COM 		 * regions (as a result of a "RegisterSharedMR()" verb) it is
28679517SBill.Taylor@Sun.COM 		 * important that we not unbind any resources prematurely.
28689517SBill.Taylor@Sun.COM 		 */
28699517SBill.Taylor@Sun.COM 		if (!HERMON_MTT_IS_SHARED(swrc_old)) {
28709517SBill.Taylor@Sun.COM 			/*
28719517SBill.Taylor@Sun.COM 			 * Unbind the old mapping for this memory region, but
28729517SBill.Taylor@Sun.COM 			 * retain the ddi_dma_handle_t for reuse in the bind
28739517SBill.Taylor@Sun.COM 			 * operation below. Note: This can only be done here
28749517SBill.Taylor@Sun.COM 			 * because the region being reregistered is not
28759517SBill.Taylor@Sun.COM 			 * currently shared.  Also if original memory region
28769517SBill.Taylor@Sun.COM 			 * was bound for IOMMU bypass and the new region can
28779517SBill.Taylor@Sun.COM 			 * not use bypass, then a new DMA handle will be
28789517SBill.Taylor@Sun.COM 			 * necessary.
28799517SBill.Taylor@Sun.COM 			 */
28809517SBill.Taylor@Sun.COM 			if (HERMON_MR_REUSE_DMAHDL(mr, bind->bi_flags)) {
28819517SBill.Taylor@Sun.COM 				mr->mr_bindinfo.bi_free_dmahdl = 0;
28829517SBill.Taylor@Sun.COM 				hermon_mr_mem_unbind(state, &mr->mr_bindinfo);
28839517SBill.Taylor@Sun.COM 				dmahdl = mr->mr_bindinfo.bi_dmahdl;
28849517SBill.Taylor@Sun.COM 				reuse_dmahdl = 1;
28859517SBill.Taylor@Sun.COM 			} else {
28869517SBill.Taylor@Sun.COM 				hermon_mr_mem_unbind(state, &mr->mr_bindinfo);
28879517SBill.Taylor@Sun.COM 				dmahdl = NULL;
28889517SBill.Taylor@Sun.COM 				reuse_dmahdl = 0;
28899517SBill.Taylor@Sun.COM 			}
28909517SBill.Taylor@Sun.COM 		} else {
28919517SBill.Taylor@Sun.COM 			dmahdl = NULL;
28929517SBill.Taylor@Sun.COM 			reuse_dmahdl = 0;
28939517SBill.Taylor@Sun.COM 		}
28949517SBill.Taylor@Sun.COM 
28959517SBill.Taylor@Sun.COM 		/*
28969517SBill.Taylor@Sun.COM 		 * Bind the new memory and determine the mapped addresses.
28979517SBill.Taylor@Sun.COM 		 * As described, this routine and hermon_mr_fast_mtt_write()
28989517SBill.Taylor@Sun.COM 		 * do the majority of the work for the memory registration
28999517SBill.Taylor@Sun.COM 		 * operations.  Note:  When we successfully finish the binding,
29009517SBill.Taylor@Sun.COM 		 * we will set the "bi_free_dmahdl" flag to indicate that
29019517SBill.Taylor@Sun.COM 		 * even though we may have reused the ddi_dma_handle_t we do
29029517SBill.Taylor@Sun.COM 		 * wish it to be freed up at some later time.  Note also that
29039517SBill.Taylor@Sun.COM 		 * if we fail, we may need to cleanup the ddi_dma_handle_t.
29049517SBill.Taylor@Sun.COM 		 */
29059517SBill.Taylor@Sun.COM 		bind->bi_bypass	= bind_type;
29069517SBill.Taylor@Sun.COM 		status = hermon_mr_mem_bind(state, bind, dmahdl, sleep, 1);
29079517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
29089517SBill.Taylor@Sun.COM 			if (reuse_dmahdl) {
29099517SBill.Taylor@Sun.COM 				ddi_dma_free_handle(&dmahdl);
29109517SBill.Taylor@Sun.COM 			}
29119517SBill.Taylor@Sun.COM 
29129517SBill.Taylor@Sun.COM 			/*
29139517SBill.Taylor@Sun.COM 			 * Deregister will be called upon returning failure
29149517SBill.Taylor@Sun.COM 			 * from this routine. This will ensure that all
29159517SBill.Taylor@Sun.COM 			 * current resources get properly freed up.
29169517SBill.Taylor@Sun.COM 			 * Unnecessary to attempt to regain software ownership
29179517SBill.Taylor@Sun.COM 			 * of the MPT entry as that has already been done
29189517SBill.Taylor@Sun.COM 			 * above (in hermon_mr_reregister()).  Also unnecessary
29199517SBill.Taylor@Sun.COM 			 * to attempt to unbind the memory.
29209517SBill.Taylor@Sun.COM 			 */
29219517SBill.Taylor@Sun.COM 			*dereg_level = HERMON_MR_DEREG_NO_HW2SW_MPT_OR_UNBIND;
29229517SBill.Taylor@Sun.COM 
29239517SBill.Taylor@Sun.COM 			status = IBT_INSUFF_RESOURCE;
29249517SBill.Taylor@Sun.COM 			goto mrrereghelp_fail;
29259517SBill.Taylor@Sun.COM 		}
29269517SBill.Taylor@Sun.COM 		if (reuse_dmahdl) {
29279517SBill.Taylor@Sun.COM 			bind->bi_free_dmahdl = 1;
29289517SBill.Taylor@Sun.COM 		}
29299517SBill.Taylor@Sun.COM 
29309517SBill.Taylor@Sun.COM 		/*
29319517SBill.Taylor@Sun.COM 		 * Allocate the new MTT entries resource
29329517SBill.Taylor@Sun.COM 		 */
29339517SBill.Taylor@Sun.COM 		status = hermon_rsrc_alloc(state, HERMON_MTT, nummtt_needed,
29349517SBill.Taylor@Sun.COM 		    sleep, &mtt);
29359517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
29369517SBill.Taylor@Sun.COM 			/*
29379517SBill.Taylor@Sun.COM 			 * Deregister will be called upon returning failure
29389517SBill.Taylor@Sun.COM 			 * from this routine. This will ensure that all
29399517SBill.Taylor@Sun.COM 			 * current resources get properly freed up.
29409517SBill.Taylor@Sun.COM 			 * Unnecessary to attempt to regain software ownership
29419517SBill.Taylor@Sun.COM 			 * of the MPT entry as that has already been done
29429517SBill.Taylor@Sun.COM 			 * above (in hermon_mr_reregister()).  Also unnecessary
29439517SBill.Taylor@Sun.COM 			 * to attempt to unbind the memory.
29449517SBill.Taylor@Sun.COM 			 *
29459517SBill.Taylor@Sun.COM 			 * But we do need to unbind the newly bound memory
29469517SBill.Taylor@Sun.COM 			 * before returning.
29479517SBill.Taylor@Sun.COM 			 */
29489517SBill.Taylor@Sun.COM 			hermon_mr_mem_unbind(state, bind);
29499517SBill.Taylor@Sun.COM 			*dereg_level = HERMON_MR_DEREG_NO_HW2SW_MPT_OR_UNBIND;
29509517SBill.Taylor@Sun.COM 
29519517SBill.Taylor@Sun.COM 			status = IBT_INSUFF_RESOURCE;
29529517SBill.Taylor@Sun.COM 			goto mrrereghelp_fail;
29539517SBill.Taylor@Sun.COM 		}
29549517SBill.Taylor@Sun.COM 
29559517SBill.Taylor@Sun.COM 		/*
29569517SBill.Taylor@Sun.COM 		 * Allocate MTT reference count (to track shared memory
29579517SBill.Taylor@Sun.COM 		 * regions).  As mentioned elsewhere above, this reference
29589517SBill.Taylor@Sun.COM 		 * count resource may never be used on the given memory region,
29599517SBill.Taylor@Sun.COM 		 * but if it is ever later registered as a "shared" memory
29609517SBill.Taylor@Sun.COM 		 * region then this resource will be necessary.  Note:  This
29619517SBill.Taylor@Sun.COM 		 * is only necessary here if the existing memory region is
29629517SBill.Taylor@Sun.COM 		 * already being shared (because otherwise we already have
29639517SBill.Taylor@Sun.COM 		 * a useable reference count resource).
29649517SBill.Taylor@Sun.COM 		 */
29659517SBill.Taylor@Sun.COM 		if (HERMON_MTT_IS_SHARED(swrc_old)) {
29669517SBill.Taylor@Sun.COM 			status = hermon_rsrc_alloc(state, HERMON_REFCNT, 1,
29679517SBill.Taylor@Sun.COM 			    sleep, &mtt_refcnt);
29689517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
29699517SBill.Taylor@Sun.COM 				/*
29709517SBill.Taylor@Sun.COM 				 * Deregister will be called upon returning
29719517SBill.Taylor@Sun.COM 				 * failure from this routine. This will ensure
29729517SBill.Taylor@Sun.COM 				 * that all current resources get properly
29739517SBill.Taylor@Sun.COM 				 * freed up.  Unnecessary to attempt to regain
29749517SBill.Taylor@Sun.COM 				 * software ownership of the MPT entry as that
29759517SBill.Taylor@Sun.COM 				 * has already been done above (in
29769517SBill.Taylor@Sun.COM 				 * hermon_mr_reregister()).  Also unnecessary
29779517SBill.Taylor@Sun.COM 				 * to attempt to unbind the memory.
29789517SBill.Taylor@Sun.COM 				 *
29799517SBill.Taylor@Sun.COM 				 * But we need to unbind the newly bound
29809517SBill.Taylor@Sun.COM 				 * memory and free up the newly allocated MTT
29819517SBill.Taylor@Sun.COM 				 * entries before returning.
29829517SBill.Taylor@Sun.COM 				 */
29839517SBill.Taylor@Sun.COM 				hermon_mr_mem_unbind(state, bind);
29849517SBill.Taylor@Sun.COM 				hermon_rsrc_free(state, &mtt);
29859517SBill.Taylor@Sun.COM 				*dereg_level =
29869517SBill.Taylor@Sun.COM 				    HERMON_MR_DEREG_NO_HW2SW_MPT_OR_UNBIND;
29879517SBill.Taylor@Sun.COM 
29889517SBill.Taylor@Sun.COM 				status = IBT_INSUFF_RESOURCE;
29899517SBill.Taylor@Sun.COM 				goto mrrereghelp_fail;
29909517SBill.Taylor@Sun.COM 			}
29919517SBill.Taylor@Sun.COM 			swrc_new = (hermon_sw_refcnt_t *)mtt_refcnt->hr_addr;
29929517SBill.Taylor@Sun.COM 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*swrc_new))
29939517SBill.Taylor@Sun.COM 			HERMON_MTT_REFCNT_INIT(swrc_new);
29949517SBill.Taylor@Sun.COM 		} else {
29959517SBill.Taylor@Sun.COM 			mtt_refcnt = mr->mr_mttrefcntp;
29969517SBill.Taylor@Sun.COM 		}
29979517SBill.Taylor@Sun.COM 
29989517SBill.Taylor@Sun.COM 		/*
29999517SBill.Taylor@Sun.COM 		 * Using the new mapping and the new MTT resources, write the
30009517SBill.Taylor@Sun.COM 		 * updated entries to MTT
30019517SBill.Taylor@Sun.COM 		 */
30029517SBill.Taylor@Sun.COM 		status = hermon_mr_fast_mtt_write(state, mtt, bind,
30039517SBill.Taylor@Sun.COM 		    mtt_pgsize_bits);
30049517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
30059517SBill.Taylor@Sun.COM 			/*
30069517SBill.Taylor@Sun.COM 			 * Deregister will be called upon returning failure
30079517SBill.Taylor@Sun.COM 			 * from this routine. This will ensure that all
30089517SBill.Taylor@Sun.COM 			 * current resources get properly freed up.
30099517SBill.Taylor@Sun.COM 			 * Unnecessary to attempt to regain software ownership
30109517SBill.Taylor@Sun.COM 			 * of the MPT entry as that has already been done
30119517SBill.Taylor@Sun.COM 			 * above (in hermon_mr_reregister()).  Also unnecessary
30129517SBill.Taylor@Sun.COM 			 * to attempt to unbind the memory.
30139517SBill.Taylor@Sun.COM 			 *
30149517SBill.Taylor@Sun.COM 			 * But we need to unbind the newly bound memory,
30159517SBill.Taylor@Sun.COM 			 * free up the newly allocated MTT entries, and
30169517SBill.Taylor@Sun.COM 			 * (possibly) free the new MTT reference count
30179517SBill.Taylor@Sun.COM 			 * resource before returning.
30189517SBill.Taylor@Sun.COM 			 */
30199517SBill.Taylor@Sun.COM 			if (HERMON_MTT_IS_SHARED(swrc_old)) {
30209517SBill.Taylor@Sun.COM 				hermon_rsrc_free(state, &mtt_refcnt);
30219517SBill.Taylor@Sun.COM 			}
30229517SBill.Taylor@Sun.COM 			hermon_mr_mem_unbind(state, bind);
30239517SBill.Taylor@Sun.COM 			hermon_rsrc_free(state, &mtt);
30249517SBill.Taylor@Sun.COM 			*dereg_level = HERMON_MR_DEREG_NO_HW2SW_MPT_OR_UNBIND;
30259517SBill.Taylor@Sun.COM 
30269517SBill.Taylor@Sun.COM 			status = IBT_INSUFF_RESOURCE;
30279517SBill.Taylor@Sun.COM 			goto mrrereghelp_fail;
30289517SBill.Taylor@Sun.COM 		}
30299517SBill.Taylor@Sun.COM 
30309517SBill.Taylor@Sun.COM 		/*
30319517SBill.Taylor@Sun.COM 		 * Check if the memory region MTT is shared by any other MRs.
30329517SBill.Taylor@Sun.COM 		 * Since the resource may be shared between multiple memory
30339517SBill.Taylor@Sun.COM 		 * regions (as a result of a "RegisterSharedMR()" verb) it is
30349517SBill.Taylor@Sun.COM 		 * important that we not free up any resources prematurely.
30359517SBill.Taylor@Sun.COM 		 */
30369517SBill.Taylor@Sun.COM 		if (HERMON_MTT_IS_SHARED(swrc_old)) {
30379517SBill.Taylor@Sun.COM 			/* Decrement MTT reference count for "old" region */
30389517SBill.Taylor@Sun.COM 			(void) hermon_mtt_refcnt_dec(mr->mr_mttrefcntp);
30399517SBill.Taylor@Sun.COM 		} else {
30409517SBill.Taylor@Sun.COM 			/* Free up the old MTT entries resource */
30419517SBill.Taylor@Sun.COM 			hermon_rsrc_free(state, &mr->mr_mttrsrcp);
30429517SBill.Taylor@Sun.COM 		}
30439517SBill.Taylor@Sun.COM 
30449517SBill.Taylor@Sun.COM 		/* Put the updated information into the mrhdl */
30459517SBill.Taylor@Sun.COM 		mr->mr_bindinfo	  = *bind;
30469517SBill.Taylor@Sun.COM 		mr->mr_logmttpgsz = mtt_pgsize_bits;
30479517SBill.Taylor@Sun.COM 		mr->mr_mttrsrcp   = mtt;
30489517SBill.Taylor@Sun.COM 		mr->mr_mttrefcntp = mtt_refcnt;
30499517SBill.Taylor@Sun.COM 	}
30509517SBill.Taylor@Sun.COM 
30519517SBill.Taylor@Sun.COM 	/*
30529517SBill.Taylor@Sun.COM 	 * Calculate and return the updated MTT address (in the DDR address
30539517SBill.Taylor@Sun.COM 	 * space).  This will be used by the caller (hermon_mr_reregister) in
30549517SBill.Taylor@Sun.COM 	 * the updated MPT entry
30559517SBill.Taylor@Sun.COM 	 */
30569517SBill.Taylor@Sun.COM 	*mtt_addr = mtt->hr_indx << HERMON_MTT_SIZE_SHIFT;
30579517SBill.Taylor@Sun.COM 
30589517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
30599517SBill.Taylor@Sun.COM 
30609517SBill.Taylor@Sun.COM mrrereghelp_fail:
30619517SBill.Taylor@Sun.COM 	return (status);
30629517SBill.Taylor@Sun.COM }
30639517SBill.Taylor@Sun.COM 
30649517SBill.Taylor@Sun.COM 
30659517SBill.Taylor@Sun.COM /*
30669517SBill.Taylor@Sun.COM  * hermon_mr_nummtt_needed()
30679517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
30689517SBill.Taylor@Sun.COM  */
30699517SBill.Taylor@Sun.COM /* ARGSUSED */
30709517SBill.Taylor@Sun.COM static uint64_t
hermon_mr_nummtt_needed(hermon_state_t * state,hermon_bind_info_t * bind,uint_t * mtt_pgsize_bits)30719517SBill.Taylor@Sun.COM hermon_mr_nummtt_needed(hermon_state_t *state, hermon_bind_info_t *bind,
30729517SBill.Taylor@Sun.COM     uint_t *mtt_pgsize_bits)
30739517SBill.Taylor@Sun.COM {
30749517SBill.Taylor@Sun.COM 	uint64_t	pg_offset_mask;
30759517SBill.Taylor@Sun.COM 	uint64_t	pg_offset, tmp_length;
30769517SBill.Taylor@Sun.COM 
30779517SBill.Taylor@Sun.COM 	/*
30789517SBill.Taylor@Sun.COM 	 * For now we specify the page size as 8Kb (the default page size for
30799517SBill.Taylor@Sun.COM 	 * the sun4u architecture), or 4Kb for x86.  Figure out optimal page
30809517SBill.Taylor@Sun.COM 	 * size by examining the dmacookies
30819517SBill.Taylor@Sun.COM 	 */
30829517SBill.Taylor@Sun.COM 	*mtt_pgsize_bits = PAGESHIFT;
30839517SBill.Taylor@Sun.COM 
30849517SBill.Taylor@Sun.COM 	pg_offset_mask = ((uint64_t)1 << *mtt_pgsize_bits) - 1;
30859517SBill.Taylor@Sun.COM 	pg_offset = bind->bi_addr & pg_offset_mask;
30869517SBill.Taylor@Sun.COM 	tmp_length = pg_offset + (bind->bi_len - 1);
30879517SBill.Taylor@Sun.COM 	return ((tmp_length >> *mtt_pgsize_bits) + 1);
30889517SBill.Taylor@Sun.COM }
30899517SBill.Taylor@Sun.COM 
30909517SBill.Taylor@Sun.COM 
30919517SBill.Taylor@Sun.COM /*
30929517SBill.Taylor@Sun.COM  * hermon_mr_mem_bind()
30939517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
30949517SBill.Taylor@Sun.COM  */
30959517SBill.Taylor@Sun.COM static int
hermon_mr_mem_bind(hermon_state_t * state,hermon_bind_info_t * bind,ddi_dma_handle_t dmahdl,uint_t sleep,uint_t is_buffer)30969517SBill.Taylor@Sun.COM hermon_mr_mem_bind(hermon_state_t *state, hermon_bind_info_t *bind,
30979517SBill.Taylor@Sun.COM     ddi_dma_handle_t dmahdl, uint_t sleep, uint_t is_buffer)
30989517SBill.Taylor@Sun.COM {
30999517SBill.Taylor@Sun.COM 	ddi_dma_attr_t	dma_attr;
31009517SBill.Taylor@Sun.COM 	int		(*callback)(caddr_t);
31019517SBill.Taylor@Sun.COM 	int		status;
31029517SBill.Taylor@Sun.COM 
31039517SBill.Taylor@Sun.COM 	/* bi_type must be set to a meaningful value to get a bind handle */
31049517SBill.Taylor@Sun.COM 	ASSERT(bind->bi_type == HERMON_BINDHDL_VADDR ||
31059517SBill.Taylor@Sun.COM 	    bind->bi_type == HERMON_BINDHDL_BUF ||
31069517SBill.Taylor@Sun.COM 	    bind->bi_type == HERMON_BINDHDL_UBUF);
31079517SBill.Taylor@Sun.COM 
31089517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind))
31099517SBill.Taylor@Sun.COM 
31109517SBill.Taylor@Sun.COM 	/* Set the callback flag appropriately */
31119517SBill.Taylor@Sun.COM 	callback = (sleep == HERMON_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
31129517SBill.Taylor@Sun.COM 
31139517SBill.Taylor@Sun.COM 	/*
31149517SBill.Taylor@Sun.COM 	 * Initialize many of the default DMA attributes.  Then, if we're
31159517SBill.Taylor@Sun.COM 	 * bypassing the IOMMU, set the DDI_DMA_FORCE_PHYSICAL flag.
31169517SBill.Taylor@Sun.COM 	 */
31179517SBill.Taylor@Sun.COM 	if (dmahdl == NULL) {
31189517SBill.Taylor@Sun.COM 		hermon_dma_attr_init(state, &dma_attr);
31199517SBill.Taylor@Sun.COM #ifdef	__sparc
31209517SBill.Taylor@Sun.COM 		if (bind->bi_bypass == HERMON_BINDMEM_BYPASS) {
31219517SBill.Taylor@Sun.COM 			dma_attr.dma_attr_flags = DDI_DMA_FORCE_PHYSICAL;
31229517SBill.Taylor@Sun.COM 		}
31239517SBill.Taylor@Sun.COM #endif
31249517SBill.Taylor@Sun.COM 
31259517SBill.Taylor@Sun.COM 		/* set RO if needed - tunable set and 'is_buffer' is non-0 */
31269517SBill.Taylor@Sun.COM 		if (is_buffer) {
31279517SBill.Taylor@Sun.COM 			if (! (bind->bi_flags & IBT_MR_DISABLE_RO)) {
31289517SBill.Taylor@Sun.COM 				if ((bind->bi_type != HERMON_BINDHDL_UBUF) &&
31299517SBill.Taylor@Sun.COM 				    (hermon_kernel_data_ro ==
31309517SBill.Taylor@Sun.COM 				    HERMON_RO_ENABLED)) {
31319517SBill.Taylor@Sun.COM 					dma_attr.dma_attr_flags |=
31329517SBill.Taylor@Sun.COM 					    DDI_DMA_RELAXED_ORDERING;
31339517SBill.Taylor@Sun.COM 				}
31349517SBill.Taylor@Sun.COM 				if (((bind->bi_type == HERMON_BINDHDL_UBUF) &&
31359517SBill.Taylor@Sun.COM 				    (hermon_user_data_ro ==
31369517SBill.Taylor@Sun.COM 				    HERMON_RO_ENABLED))) {
31379517SBill.Taylor@Sun.COM 					dma_attr.dma_attr_flags |=
31389517SBill.Taylor@Sun.COM 					    DDI_DMA_RELAXED_ORDERING;
31399517SBill.Taylor@Sun.COM 				}
31409517SBill.Taylor@Sun.COM 			}
31419517SBill.Taylor@Sun.COM 		}
31429517SBill.Taylor@Sun.COM 
31439517SBill.Taylor@Sun.COM 		/* Allocate a DMA handle for the binding */
31449517SBill.Taylor@Sun.COM 		status = ddi_dma_alloc_handle(state->hs_dip, &dma_attr,
31459517SBill.Taylor@Sun.COM 		    callback, NULL, &bind->bi_dmahdl);
31469517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
31479517SBill.Taylor@Sun.COM 			return (status);
31489517SBill.Taylor@Sun.COM 		}
31499517SBill.Taylor@Sun.COM 		bind->bi_free_dmahdl = 1;
31509517SBill.Taylor@Sun.COM 
31519517SBill.Taylor@Sun.COM 	} else  {
31529517SBill.Taylor@Sun.COM 		bind->bi_dmahdl = dmahdl;
31539517SBill.Taylor@Sun.COM 		bind->bi_free_dmahdl = 0;
31549517SBill.Taylor@Sun.COM 	}
31559517SBill.Taylor@Sun.COM 
31569517SBill.Taylor@Sun.COM 
31579517SBill.Taylor@Sun.COM 	/*
31589517SBill.Taylor@Sun.COM 	 * Bind the memory to get the PCI mapped addresses.  The decision
31599517SBill.Taylor@Sun.COM 	 * to call ddi_dma_addr_bind_handle() or ddi_dma_buf_bind_handle()
31609517SBill.Taylor@Sun.COM 	 * is determined by the "bi_type" flag.  Note: if the bind operation
31619517SBill.Taylor@Sun.COM 	 * fails then we have to free up the DMA handle and return error.
31629517SBill.Taylor@Sun.COM 	 */
31639517SBill.Taylor@Sun.COM 	if (bind->bi_type == HERMON_BINDHDL_VADDR) {
31649517SBill.Taylor@Sun.COM 		status = ddi_dma_addr_bind_handle(bind->bi_dmahdl, NULL,
31659517SBill.Taylor@Sun.COM 		    (caddr_t)(uintptr_t)bind->bi_addr, bind->bi_len,
31669517SBill.Taylor@Sun.COM 		    (DDI_DMA_RDWR | DDI_DMA_CONSISTENT), callback, NULL,
31679517SBill.Taylor@Sun.COM 		    &bind->bi_dmacookie, &bind->bi_cookiecnt);
31689517SBill.Taylor@Sun.COM 
31699517SBill.Taylor@Sun.COM 	} else {  /* HERMON_BINDHDL_BUF or HERMON_BINDHDL_UBUF */
31709517SBill.Taylor@Sun.COM 
31719517SBill.Taylor@Sun.COM 		status = ddi_dma_buf_bind_handle(bind->bi_dmahdl,
31729517SBill.Taylor@Sun.COM 		    bind->bi_buf, (DDI_DMA_RDWR | DDI_DMA_CONSISTENT), callback,
31739517SBill.Taylor@Sun.COM 		    NULL, &bind->bi_dmacookie, &bind->bi_cookiecnt);
31749517SBill.Taylor@Sun.COM 	}
31759517SBill.Taylor@Sun.COM 	if (status != DDI_DMA_MAPPED) {
31769517SBill.Taylor@Sun.COM 		if (bind->bi_free_dmahdl != 0) {
31779517SBill.Taylor@Sun.COM 			ddi_dma_free_handle(&bind->bi_dmahdl);
31789517SBill.Taylor@Sun.COM 		}
31799517SBill.Taylor@Sun.COM 		return (status);
31809517SBill.Taylor@Sun.COM 	}
31819517SBill.Taylor@Sun.COM 
31829517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
31839517SBill.Taylor@Sun.COM }
31849517SBill.Taylor@Sun.COM 
31859517SBill.Taylor@Sun.COM 
31869517SBill.Taylor@Sun.COM /*
31879517SBill.Taylor@Sun.COM  * hermon_mr_mem_unbind()
31889517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
31899517SBill.Taylor@Sun.COM  */
31909517SBill.Taylor@Sun.COM static void
hermon_mr_mem_unbind(hermon_state_t * state,hermon_bind_info_t * bind)31919517SBill.Taylor@Sun.COM hermon_mr_mem_unbind(hermon_state_t *state, hermon_bind_info_t *bind)
31929517SBill.Taylor@Sun.COM {
31939517SBill.Taylor@Sun.COM 	int	status;
31949517SBill.Taylor@Sun.COM 
3195*12965SWilliam.Taylor@Oracle.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind))
3196*12965SWilliam.Taylor@Oracle.COM 	/* there is nothing to unbind for alloc_lkey */
3197*12965SWilliam.Taylor@Oracle.COM 	if (bind->bi_type == HERMON_BINDHDL_LKEY)
3198*12965SWilliam.Taylor@Oracle.COM 		return;
3199*12965SWilliam.Taylor@Oracle.COM 
32009517SBill.Taylor@Sun.COM 	/*
32019517SBill.Taylor@Sun.COM 	 * In case of HERMON_BINDHDL_UBUF, the memory bi_buf points to
32029517SBill.Taylor@Sun.COM 	 * is actually allocated by ddi_umem_iosetup() internally, then
32039517SBill.Taylor@Sun.COM 	 * it's required to free it here. Reset bi_type to HERMON_BINDHDL_NONE
32049517SBill.Taylor@Sun.COM 	 * not to free it again later.
32059517SBill.Taylor@Sun.COM 	 */
32069517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind))
32079517SBill.Taylor@Sun.COM 	if (bind->bi_type == HERMON_BINDHDL_UBUF) {
32089517SBill.Taylor@Sun.COM 		freerbuf(bind->bi_buf);
32099517SBill.Taylor@Sun.COM 		bind->bi_type = HERMON_BINDHDL_NONE;
32109517SBill.Taylor@Sun.COM 	}
32119517SBill.Taylor@Sun.COM 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*bind))
32129517SBill.Taylor@Sun.COM 
32139517SBill.Taylor@Sun.COM 	/*
32149517SBill.Taylor@Sun.COM 	 * Unbind the DMA memory for the region
32159517SBill.Taylor@Sun.COM 	 *
32169517SBill.Taylor@Sun.COM 	 * Note: The only way ddi_dma_unbind_handle() currently
32179517SBill.Taylor@Sun.COM 	 * can return an error is if the handle passed in is invalid.
32189517SBill.Taylor@Sun.COM 	 * Since this should never happen, we choose to return void
32199517SBill.Taylor@Sun.COM 	 * from this function!  If this does return an error, however,
32209517SBill.Taylor@Sun.COM 	 * then we print a warning message to the console.
32219517SBill.Taylor@Sun.COM 	 */
32229517SBill.Taylor@Sun.COM 	status = ddi_dma_unbind_handle(bind->bi_dmahdl);
32239517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
32249517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "failed to unbind DMA mapping");
32259517SBill.Taylor@Sun.COM 		return;
32269517SBill.Taylor@Sun.COM 	}
32279517SBill.Taylor@Sun.COM 
32289517SBill.Taylor@Sun.COM 	/* Free up the DMA handle */
32299517SBill.Taylor@Sun.COM 	if (bind->bi_free_dmahdl != 0) {
32309517SBill.Taylor@Sun.COM 		ddi_dma_free_handle(&bind->bi_dmahdl);
32319517SBill.Taylor@Sun.COM 	}
32329517SBill.Taylor@Sun.COM }
32339517SBill.Taylor@Sun.COM 
32349517SBill.Taylor@Sun.COM 
32359517SBill.Taylor@Sun.COM /*
32369517SBill.Taylor@Sun.COM  * hermon_mr_fast_mtt_write()
32379517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
32389517SBill.Taylor@Sun.COM  */
32399517SBill.Taylor@Sun.COM static int
hermon_mr_fast_mtt_write(hermon_state_t * state,hermon_rsrc_t * mtt,hermon_bind_info_t * bind,uint32_t mtt_pgsize_bits)32409517SBill.Taylor@Sun.COM hermon_mr_fast_mtt_write(hermon_state_t *state, hermon_rsrc_t *mtt,
32419517SBill.Taylor@Sun.COM     hermon_bind_info_t *bind, uint32_t mtt_pgsize_bits)
32429517SBill.Taylor@Sun.COM {
32439517SBill.Taylor@Sun.COM 	hermon_icm_table_t	*icm_table;
32449517SBill.Taylor@Sun.COM 	hermon_dma_info_t	*dma_info;
32459517SBill.Taylor@Sun.COM 	uint32_t		index1, index2, rindx;
32469517SBill.Taylor@Sun.COM 	ddi_dma_cookie_t	dmacookie;
32479517SBill.Taylor@Sun.COM 	uint_t			cookie_cnt;
32489517SBill.Taylor@Sun.COM 	uint64_t		*mtt_table;
32499517SBill.Taylor@Sun.COM 	uint64_t		mtt_entry;
32509517SBill.Taylor@Sun.COM 	uint64_t		addr, endaddr;
32519517SBill.Taylor@Sun.COM 	uint64_t		pagesize;
32529517SBill.Taylor@Sun.COM 	offset_t		i, start;
32539517SBill.Taylor@Sun.COM 	uint_t			per_span;
32549517SBill.Taylor@Sun.COM 	int			sync_needed;
32559517SBill.Taylor@Sun.COM 
32569517SBill.Taylor@Sun.COM 	/*
32579517SBill.Taylor@Sun.COM 	 * XXX According to the PRM, we are to use the WRITE_MTT
32589517SBill.Taylor@Sun.COM 	 * command to write out MTTs. Tavor does not do this,
32599517SBill.Taylor@Sun.COM 	 * instead taking advantage of direct access to the MTTs,
32609517SBill.Taylor@Sun.COM 	 * and knowledge that Mellanox FMR relies on our ability
32619517SBill.Taylor@Sun.COM 	 * to write directly to the MTTs without any further
32629517SBill.Taylor@Sun.COM 	 * notification to the firmware. Likewise, we will choose
32639517SBill.Taylor@Sun.COM 	 * to not use the WRITE_MTT command, but to simply write
32649517SBill.Taylor@Sun.COM 	 * out the MTTs.
32659517SBill.Taylor@Sun.COM 	 */
32669517SBill.Taylor@Sun.COM 
32679517SBill.Taylor@Sun.COM 	/* Calculate page size from the suggested value passed in */
32689517SBill.Taylor@Sun.COM 	pagesize = ((uint64_t)1 << mtt_pgsize_bits);
32699517SBill.Taylor@Sun.COM 
32709517SBill.Taylor@Sun.COM 	/* Walk the "cookie list" and fill in the MTT table entries */
32719517SBill.Taylor@Sun.COM 	dmacookie  = bind->bi_dmacookie;
32729517SBill.Taylor@Sun.COM 	cookie_cnt = bind->bi_cookiecnt;
32739517SBill.Taylor@Sun.COM 
32749517SBill.Taylor@Sun.COM 	icm_table = &state->hs_icm[HERMON_MTT];
32759517SBill.Taylor@Sun.COM 	rindx = mtt->hr_indx;
32769517SBill.Taylor@Sun.COM 	hermon_index(index1, index2, rindx, icm_table, i);
32779517SBill.Taylor@Sun.COM 	start = i;
32789517SBill.Taylor@Sun.COM 
32799517SBill.Taylor@Sun.COM 	per_span   = icm_table->span;
32809517SBill.Taylor@Sun.COM 	dma_info   = icm_table->icm_dma[index1] + index2;
32819517SBill.Taylor@Sun.COM 	mtt_table  = (uint64_t *)(uintptr_t)dma_info->vaddr;
32829517SBill.Taylor@Sun.COM 
32839517SBill.Taylor@Sun.COM 	sync_needed = 0;
32849517SBill.Taylor@Sun.COM 	while (cookie_cnt-- > 0) {
32859517SBill.Taylor@Sun.COM 		addr    = dmacookie.dmac_laddress;
32869517SBill.Taylor@Sun.COM 		endaddr = addr + (dmacookie.dmac_size - 1);
32879517SBill.Taylor@Sun.COM 		addr    = addr & ~((uint64_t)pagesize - 1);
32889517SBill.Taylor@Sun.COM 
32899517SBill.Taylor@Sun.COM 		while (addr <= endaddr) {
32909517SBill.Taylor@Sun.COM 
32919517SBill.Taylor@Sun.COM 			/*
32929517SBill.Taylor@Sun.COM 			 * Fill in the mapped addresses (calculated above) and
32939517SBill.Taylor@Sun.COM 			 * set HERMON_MTT_ENTRY_PRESENT flag for each MTT entry.
32949517SBill.Taylor@Sun.COM 			 */
32959517SBill.Taylor@Sun.COM 			mtt_entry = addr | HERMON_MTT_ENTRY_PRESENT;
32969517SBill.Taylor@Sun.COM 			mtt_table[i] = htonll(mtt_entry);
32979517SBill.Taylor@Sun.COM 			i++;
32989517SBill.Taylor@Sun.COM 			rindx++;
32999517SBill.Taylor@Sun.COM 
33009517SBill.Taylor@Sun.COM 			if (i == per_span) {
33019517SBill.Taylor@Sun.COM 
33029517SBill.Taylor@Sun.COM 				(void) ddi_dma_sync(dma_info->dma_hdl,
33039517SBill.Taylor@Sun.COM 				    start * sizeof (hermon_hw_mtt_t),
33049517SBill.Taylor@Sun.COM 				    (i - start) * sizeof (hermon_hw_mtt_t),
33059517SBill.Taylor@Sun.COM 				    DDI_DMA_SYNC_FORDEV);
33069517SBill.Taylor@Sun.COM 
33079579SBill.Taylor@Sun.COM 				if ((addr + pagesize > endaddr) &&
33089579SBill.Taylor@Sun.COM 				    (cookie_cnt == 0))
33099579SBill.Taylor@Sun.COM 					return (DDI_SUCCESS);
33109579SBill.Taylor@Sun.COM 
33119517SBill.Taylor@Sun.COM 				hermon_index(index1, index2, rindx, icm_table,
33129517SBill.Taylor@Sun.COM 				    i);
33139517SBill.Taylor@Sun.COM 				start = i * sizeof (hermon_hw_mtt_t);
33149517SBill.Taylor@Sun.COM 				dma_info = icm_table->icm_dma[index1] + index2;
33159517SBill.Taylor@Sun.COM 				mtt_table =
33169517SBill.Taylor@Sun.COM 				    (uint64_t *)(uintptr_t)dma_info->vaddr;
33179517SBill.Taylor@Sun.COM 
33189517SBill.Taylor@Sun.COM 				sync_needed = 0;
33199517SBill.Taylor@Sun.COM 			} else {
33209517SBill.Taylor@Sun.COM 				sync_needed = 1;
33219517SBill.Taylor@Sun.COM 			}
33229517SBill.Taylor@Sun.COM 
33239517SBill.Taylor@Sun.COM 			addr += pagesize;
33249517SBill.Taylor@Sun.COM 			if (addr == 0) {
33259517SBill.Taylor@Sun.COM 				static int do_once = 1;
33269517SBill.Taylor@Sun.COM 				_NOTE(SCHEME_PROTECTS_DATA("safe sharing",
33279517SBill.Taylor@Sun.COM 				    do_once))
33289517SBill.Taylor@Sun.COM 				if (do_once) {
33299517SBill.Taylor@Sun.COM 					do_once = 0;
33309517SBill.Taylor@Sun.COM 					cmn_err(CE_NOTE, "probable error in "
33319517SBill.Taylor@Sun.COM 					    "dma_cookie address from caller\n");
33329517SBill.Taylor@Sun.COM 				}
33339517SBill.Taylor@Sun.COM 				break;
33349517SBill.Taylor@Sun.COM 			}
33359517SBill.Taylor@Sun.COM 		}
33369517SBill.Taylor@Sun.COM 
33379517SBill.Taylor@Sun.COM 		/*
33389517SBill.Taylor@Sun.COM 		 * When we've reached the end of the current DMA cookie,
33399517SBill.Taylor@Sun.COM 		 * jump to the next cookie (if there are more)
33409517SBill.Taylor@Sun.COM 		 */
33419517SBill.Taylor@Sun.COM 		if (cookie_cnt != 0) {
33429517SBill.Taylor@Sun.COM 			ddi_dma_nextcookie(bind->bi_dmahdl, &dmacookie);
33439517SBill.Taylor@Sun.COM 		}
33449517SBill.Taylor@Sun.COM 	}
33459517SBill.Taylor@Sun.COM 
33469517SBill.Taylor@Sun.COM 	/* done all the cookies, now sync the memory for the device */
33479517SBill.Taylor@Sun.COM 	if (sync_needed)
33489517SBill.Taylor@Sun.COM 		(void) ddi_dma_sync(dma_info->dma_hdl,
33499517SBill.Taylor@Sun.COM 		    start * sizeof (hermon_hw_mtt_t),
33509517SBill.Taylor@Sun.COM 		    (i - start) * sizeof (hermon_hw_mtt_t),
33519517SBill.Taylor@Sun.COM 		    DDI_DMA_SYNC_FORDEV);
33529517SBill.Taylor@Sun.COM 
33539517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
33549517SBill.Taylor@Sun.COM }
33559517SBill.Taylor@Sun.COM 
33569517SBill.Taylor@Sun.COM /*
33579517SBill.Taylor@Sun.COM  * hermon_mr_fast_mtt_write_fmr()
33589517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
33599517SBill.Taylor@Sun.COM  */
336011972SBill.Taylor@Sun.COM /* ARGSUSED */
33619517SBill.Taylor@Sun.COM static int
hermon_mr_fast_mtt_write_fmr(hermon_state_t * state,hermon_rsrc_t * mtt,ibt_pmr_attr_t * mem_pattr,uint32_t mtt_pgsize_bits)336211972SBill.Taylor@Sun.COM hermon_mr_fast_mtt_write_fmr(hermon_state_t *state, hermon_rsrc_t *mtt,
336311972SBill.Taylor@Sun.COM     ibt_pmr_attr_t *mem_pattr, uint32_t mtt_pgsize_bits)
33649517SBill.Taylor@Sun.COM {
336511972SBill.Taylor@Sun.COM 	hermon_icm_table_t	*icm_table;
336611972SBill.Taylor@Sun.COM 	hermon_dma_info_t	*dma_info;
336711972SBill.Taylor@Sun.COM 	uint32_t		index1, index2, rindx;
33689517SBill.Taylor@Sun.COM 	uint64_t		*mtt_table;
336911972SBill.Taylor@Sun.COM 	offset_t		i, j;
337011972SBill.Taylor@Sun.COM 	uint_t			per_span;
337111972SBill.Taylor@Sun.COM 
337211972SBill.Taylor@Sun.COM 	icm_table = &state->hs_icm[HERMON_MTT];
337311972SBill.Taylor@Sun.COM 	rindx = mtt->hr_indx;
337411972SBill.Taylor@Sun.COM 	hermon_index(index1, index2, rindx, icm_table, i);
337511972SBill.Taylor@Sun.COM 	per_span   = icm_table->span;
337611972SBill.Taylor@Sun.COM 	dma_info   = icm_table->icm_dma[index1] + index2;
337711972SBill.Taylor@Sun.COM 	mtt_table  = (uint64_t *)(uintptr_t)dma_info->vaddr;
33789517SBill.Taylor@Sun.COM 
33799517SBill.Taylor@Sun.COM 	/*
338011972SBill.Taylor@Sun.COM 	 * Fill in the MTT table entries
33819517SBill.Taylor@Sun.COM 	 */
338211972SBill.Taylor@Sun.COM 	for (j = 0; j < mem_pattr->pmr_num_buf; j++) {
338311972SBill.Taylor@Sun.COM 		mtt_table[i] = mem_pattr->pmr_addr_list[j].p_laddr;
338411972SBill.Taylor@Sun.COM 		i++;
338511972SBill.Taylor@Sun.COM 		rindx++;
338611972SBill.Taylor@Sun.COM 		if (i == per_span) {
338711972SBill.Taylor@Sun.COM 			hermon_index(index1, index2, rindx, icm_table, i);
338811972SBill.Taylor@Sun.COM 			dma_info = icm_table->icm_dma[index1] + index2;
338911972SBill.Taylor@Sun.COM 			mtt_table = (uint64_t *)(uintptr_t)dma_info->vaddr;
33909517SBill.Taylor@Sun.COM 		}
33919517SBill.Taylor@Sun.COM 	}
33929517SBill.Taylor@Sun.COM 
33939517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
33949517SBill.Taylor@Sun.COM }
33959517SBill.Taylor@Sun.COM 
33969517SBill.Taylor@Sun.COM 
33979517SBill.Taylor@Sun.COM /*
33989517SBill.Taylor@Sun.COM  * hermon_mtt_refcnt_inc()
33999517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
34009517SBill.Taylor@Sun.COM  */
34019517SBill.Taylor@Sun.COM static uint_t
hermon_mtt_refcnt_inc(hermon_rsrc_t * rsrc)34029517SBill.Taylor@Sun.COM hermon_mtt_refcnt_inc(hermon_rsrc_t *rsrc)
34039517SBill.Taylor@Sun.COM {
34049517SBill.Taylor@Sun.COM 	hermon_sw_refcnt_t *rc;
34059517SBill.Taylor@Sun.COM 
34069517SBill.Taylor@Sun.COM 	rc = (hermon_sw_refcnt_t *)rsrc->hr_addr;
34079517SBill.Taylor@Sun.COM 	return (atomic_inc_uint_nv(&rc->swrc_refcnt));
34089517SBill.Taylor@Sun.COM }
34099517SBill.Taylor@Sun.COM 
34109517SBill.Taylor@Sun.COM 
34119517SBill.Taylor@Sun.COM /*
34129517SBill.Taylor@Sun.COM  * hermon_mtt_refcnt_dec()
34139517SBill.Taylor@Sun.COM  *    Context: Can be called from interrupt or base context.
34149517SBill.Taylor@Sun.COM  */
34159517SBill.Taylor@Sun.COM static uint_t
hermon_mtt_refcnt_dec(hermon_rsrc_t * rsrc)34169517SBill.Taylor@Sun.COM hermon_mtt_refcnt_dec(hermon_rsrc_t *rsrc)
34179517SBill.Taylor@Sun.COM {
34189517SBill.Taylor@Sun.COM 	hermon_sw_refcnt_t *rc;
34199517SBill.Taylor@Sun.COM 
34209517SBill.Taylor@Sun.COM 	rc = (hermon_sw_refcnt_t *)rsrc->hr_addr;
34219517SBill.Taylor@Sun.COM 	return (atomic_dec_uint_nv(&rc->swrc_refcnt));
34229517SBill.Taylor@Sun.COM }
3423