19e39c5baSBill Taylor /*
29e39c5baSBill Taylor  * CDDL HEADER START
39e39c5baSBill Taylor  *
49e39c5baSBill Taylor  * The contents of this file are subject to the terms of the
59e39c5baSBill Taylor  * Common Development and Distribution License (the "License").
69e39c5baSBill Taylor  * You may not use this file except in compliance with the License.
79e39c5baSBill Taylor  *
89e39c5baSBill Taylor  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99e39c5baSBill Taylor  * or http://www.opensolaris.org/os/licensing.
109e39c5baSBill Taylor  * See the License for the specific language governing permissions
119e39c5baSBill Taylor  * and limitations under the License.
129e39c5baSBill Taylor  *
139e39c5baSBill Taylor  * When distributing Covered Code, include this CDDL HEADER in each
149e39c5baSBill Taylor  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159e39c5baSBill Taylor  * If applicable, add the following below this CDDL HEADER, with the
169e39c5baSBill Taylor  * fields enclosed by brackets "[]" replaced with your own identifying
179e39c5baSBill Taylor  * information: Portions Copyright [yyyy] [name of copyright owner]
189e39c5baSBill Taylor  *
199e39c5baSBill Taylor  * CDDL HEADER END
209e39c5baSBill Taylor  */
219e39c5baSBill Taylor 
229e39c5baSBill Taylor /*
23*17a2b317SBill Taylor  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
249e39c5baSBill Taylor  */
259e39c5baSBill Taylor 
269e39c5baSBill Taylor /*
279e39c5baSBill Taylor  * hermon_umap.c
289e39c5baSBill Taylor  *    Hermon Userland Mapping Routines
299e39c5baSBill Taylor  *
309e39c5baSBill Taylor  *    Implements all the routines necessary for enabling direct userland
319e39c5baSBill Taylor  *    access to the Hermon hardware.  This includes all routines necessary for
329e39c5baSBill Taylor  *    maintaining the "userland resources database" and all the support routines
339e39c5baSBill Taylor  *    for the devmap calls.
349e39c5baSBill Taylor  */
359e39c5baSBill Taylor 
369e39c5baSBill Taylor #include <sys/types.h>
379e39c5baSBill Taylor #include <sys/conf.h>
389e39c5baSBill Taylor #include <sys/ddi.h>
399e39c5baSBill Taylor #include <sys/sunddi.h>
409e39c5baSBill Taylor #include <sys/modctl.h>
419e39c5baSBill Taylor #include <sys/file.h>
429e39c5baSBill Taylor #include <sys/avl.h>
439e39c5baSBill Taylor #include <sys/sysmacros.h>
449e39c5baSBill Taylor 
459e39c5baSBill Taylor #include <sys/ib/adapters/hermon/hermon.h>
469e39c5baSBill Taylor 
479e39c5baSBill Taylor /* Hermon HCA state pointer (extern) */
489e39c5baSBill Taylor extern void *hermon_statep;
499e39c5baSBill Taylor 
509e39c5baSBill Taylor /* Hermon HCA Userland Resource Database (extern) */
519e39c5baSBill Taylor extern hermon_umap_db_t hermon_userland_rsrc_db;
529e39c5baSBill Taylor 
539e39c5baSBill Taylor static int hermon_umap_uarpg(hermon_state_t *state, devmap_cookie_t dhp,
549e39c5baSBill Taylor     hermon_rsrc_t *rsrcp, uint64_t offset, size_t *maplen, int *err);
559e39c5baSBill Taylor static int hermon_umap_cqmem(hermon_state_t *state, devmap_cookie_t dhp,
569e39c5baSBill Taylor     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
579e39c5baSBill Taylor static int hermon_umap_qpmem(hermon_state_t *state, devmap_cookie_t dhp,
589e39c5baSBill Taylor     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
599e39c5baSBill Taylor static int hermon_umap_srqmem(hermon_state_t *state, devmap_cookie_t dhp,
609e39c5baSBill Taylor     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
619e39c5baSBill Taylor static int hermon_umap_dbrecmem(hermon_state_t *state, devmap_cookie_t dhp,
629e39c5baSBill Taylor     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
639e39c5baSBill Taylor static int hermon_devmap_umem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
649e39c5baSBill Taylor     offset_t off, size_t len, void **pvtp);
659e39c5baSBill Taylor static int hermon_devmap_umem_dup(devmap_cookie_t dhp, void *pvtp,
669e39c5baSBill Taylor     devmap_cookie_t new_dhp, void **new_pvtp);
679e39c5baSBill Taylor static void hermon_devmap_umem_unmap(devmap_cookie_t dhp, void *pvtp,
689e39c5baSBill Taylor     offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
699e39c5baSBill Taylor     devmap_cookie_t new_dhp2, void **pvtp2);
709e39c5baSBill Taylor static int hermon_devmap_dbrecmem_map(devmap_cookie_t dhp, dev_t dev,
719e39c5baSBill Taylor     uint_t flags, offset_t off, size_t len, void **pvtp);
729e39c5baSBill Taylor static int hermon_devmap_dbrecmem_dup(devmap_cookie_t dhp, void *pvtp,
739e39c5baSBill Taylor     devmap_cookie_t new_dhp, void **new_pvtp);
749e39c5baSBill Taylor static void hermon_devmap_dbrecmem_unmap(devmap_cookie_t dhp, void *pvtp,
759e39c5baSBill Taylor     offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
769e39c5baSBill Taylor     devmap_cookie_t new_dhp2, void **pvtp2);
779e39c5baSBill Taylor static int hermon_devmap_devmem_map(devmap_cookie_t dhp, dev_t dev,
789e39c5baSBill Taylor     uint_t flags, offset_t off, size_t len, void **pvtp);
799e39c5baSBill Taylor static int hermon_devmap_devmem_dup(devmap_cookie_t dhp, void *pvtp,
809e39c5baSBill Taylor     devmap_cookie_t new_dhp, void **new_pvtp);
819e39c5baSBill Taylor static void hermon_devmap_devmem_unmap(devmap_cookie_t dhp, void *pvtp,
829e39c5baSBill Taylor     offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
839e39c5baSBill Taylor     devmap_cookie_t new_dhp2, void **pvtp2);
849e39c5baSBill Taylor static ibt_status_t hermon_umap_mr_data_in(hermon_mrhdl_t mr,
859e39c5baSBill Taylor     ibt_mr_data_in_t *data, size_t data_sz);
869e39c5baSBill Taylor static ibt_status_t hermon_umap_cq_data_out(hermon_cqhdl_t cq,
879e39c5baSBill Taylor     mlnx_umap_cq_data_out_t *data, size_t data_sz);
889e39c5baSBill Taylor static ibt_status_t hermon_umap_qp_data_out(hermon_qphdl_t qp,
899e39c5baSBill Taylor     mlnx_umap_qp_data_out_t *data, size_t data_sz);
909e39c5baSBill Taylor static ibt_status_t hermon_umap_srq_data_out(hermon_srqhdl_t srq,
919e39c5baSBill Taylor     mlnx_umap_srq_data_out_t *data, size_t data_sz);
929e39c5baSBill Taylor static ibt_status_t hermon_umap_pd_data_out(hermon_pdhdl_t pd,
939e39c5baSBill Taylor     mlnx_umap_pd_data_out_t *data, size_t data_sz);
949e39c5baSBill Taylor static int hermon_umap_db_compare(const void *query, const void *entry);
959e39c5baSBill Taylor 
969e39c5baSBill Taylor 
979e39c5baSBill Taylor /*
989e39c5baSBill Taylor  * These callbacks are passed to devmap_umem_setup() and devmap_devmem_setup(),
999e39c5baSBill Taylor  * respectively.  They are used to handle (among other things) partial
1009e39c5baSBill Taylor  * unmappings and to provide a method for invalidating mappings inherited
1019e39c5baSBill Taylor  * as a result of a fork(2) system call.
1029e39c5baSBill Taylor  */
1039e39c5baSBill Taylor static struct devmap_callback_ctl hermon_devmap_umem_cbops = {
1049e39c5baSBill Taylor 	DEVMAP_OPS_REV,
1059e39c5baSBill Taylor 	hermon_devmap_umem_map,
1069e39c5baSBill Taylor 	NULL,
1079e39c5baSBill Taylor 	hermon_devmap_umem_dup,
1089e39c5baSBill Taylor 	hermon_devmap_umem_unmap
1099e39c5baSBill Taylor };
1109e39c5baSBill Taylor static struct devmap_callback_ctl hermon_devmap_devmem_cbops = {
1119e39c5baSBill Taylor 	DEVMAP_OPS_REV,
1129e39c5baSBill Taylor 	hermon_devmap_devmem_map,
1139e39c5baSBill Taylor 	NULL,
1149e39c5baSBill Taylor 	hermon_devmap_devmem_dup,
1159e39c5baSBill Taylor 	hermon_devmap_devmem_unmap
1169e39c5baSBill Taylor };
1179e39c5baSBill Taylor static struct devmap_callback_ctl hermon_devmap_dbrecmem_cbops = {
1189e39c5baSBill Taylor 	DEVMAP_OPS_REV,
1199e39c5baSBill Taylor 	hermon_devmap_dbrecmem_map,
1209e39c5baSBill Taylor 	NULL,
1219e39c5baSBill Taylor 	hermon_devmap_dbrecmem_dup,
1229e39c5baSBill Taylor 	hermon_devmap_dbrecmem_unmap
1239e39c5baSBill Taylor };
1249e39c5baSBill Taylor 
1259e39c5baSBill Taylor /*
1269e39c5baSBill Taylor  * hermon_devmap()
1279e39c5baSBill Taylor  *    Context: Can be called from user context.
1289e39c5baSBill Taylor  */
1299e39c5baSBill Taylor /* ARGSUSED */
1309e39c5baSBill Taylor int
hermon_devmap(dev_t dev,devmap_cookie_t dhp,offset_t off,size_t len,size_t * maplen,uint_t model)1319e39c5baSBill Taylor hermon_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
1329e39c5baSBill Taylor     size_t *maplen, uint_t model)
1339e39c5baSBill Taylor {
1349e39c5baSBill Taylor 	hermon_state_t	*state;
1359e39c5baSBill Taylor 	hermon_rsrc_t 	*rsrcp;
1369e39c5baSBill Taylor 	minor_t		instance;
1379e39c5baSBill Taylor 	uint64_t	key, value;
1389e39c5baSBill Taylor 	uint64_t	bf_offset = 0;
1399e39c5baSBill Taylor 	uint_t		type;
1409e39c5baSBill Taylor 	int		err, status;
1419e39c5baSBill Taylor 
1429e39c5baSBill Taylor 	/* Get Hermon softstate structure from instance */
1439e39c5baSBill Taylor 	instance = HERMON_DEV_INSTANCE(dev);
1449e39c5baSBill Taylor 	state = ddi_get_soft_state(hermon_statep, instance);
1459e39c5baSBill Taylor 	if (state == NULL) {
1469e39c5baSBill Taylor 		return (ENXIO);
1479e39c5baSBill Taylor 	}
1489e39c5baSBill Taylor 
1499e39c5baSBill Taylor 	/*
1509e39c5baSBill Taylor 	 * Access to Hermon devmap interface is not allowed in
1519e39c5baSBill Taylor 	 * "maintenance mode".
1529e39c5baSBill Taylor 	 */
1539e39c5baSBill Taylor 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
1549e39c5baSBill Taylor 		return (EFAULT);
1559e39c5baSBill Taylor 	}
1569e39c5baSBill Taylor 
1579e39c5baSBill Taylor 	/*
1589e39c5baSBill Taylor 	 * The bottom bits of "offset" are undefined (number depends on
1599e39c5baSBill Taylor 	 * system PAGESIZE).  Shifting these off leaves us with a "key".
1609e39c5baSBill Taylor 	 * The "key" is actually a combination of both a real key value
1619e39c5baSBill Taylor 	 * (for the purpose of database lookup) and a "type" value.  We
1629e39c5baSBill Taylor 	 * extract this information before doing the database lookup.
1639e39c5baSBill Taylor 	 */
1649e39c5baSBill Taylor 	key  = off >> PAGESHIFT;
1659e39c5baSBill Taylor 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
1669e39c5baSBill Taylor 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
1679e39c5baSBill Taylor 	if (type == MLNX_UMAP_BLUEFLAMEPG_RSRC) {
1689e39c5baSBill Taylor 		if (state->hs_devlim.blu_flm == 0) {
1699e39c5baSBill Taylor 			return (EFAULT);
1709e39c5baSBill Taylor 		}
1719e39c5baSBill Taylor 		bf_offset = state->hs_bf_offset;
1729e39c5baSBill Taylor 		type = MLNX_UMAP_UARPG_RSRC;
1739e39c5baSBill Taylor 	}
1749e39c5baSBill Taylor 	status = hermon_umap_db_find(instance, key, type, &value, 0, NULL);
1759e39c5baSBill Taylor 	if (status == DDI_SUCCESS) {
1769e39c5baSBill Taylor 		rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
1779e39c5baSBill Taylor 
1789e39c5baSBill Taylor 		switch (type) {
1799e39c5baSBill Taylor 		case MLNX_UMAP_UARPG_RSRC:
1809e39c5baSBill Taylor 			/*
1819e39c5baSBill Taylor 			 * Double check that process who open()'d Hermon is
1829e39c5baSBill Taylor 			 * same process attempting to mmap() UAR page.
1839e39c5baSBill Taylor 			 */
1849e39c5baSBill Taylor 			if (key != ddi_get_pid()) {
1859e39c5baSBill Taylor 				return (EINVAL);
1869e39c5baSBill Taylor 			}
1879e39c5baSBill Taylor 
1889e39c5baSBill Taylor 			/* Map the UAR page out for userland access */
1899e39c5baSBill Taylor 			status = hermon_umap_uarpg(state, dhp, rsrcp, bf_offset,
1909e39c5baSBill Taylor 			    maplen, &err);
1919e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
1929e39c5baSBill Taylor 				return (err);
1939e39c5baSBill Taylor 			}
1949e39c5baSBill Taylor 			break;
1959e39c5baSBill Taylor 
1969e39c5baSBill Taylor 		case MLNX_UMAP_CQMEM_RSRC:
1979e39c5baSBill Taylor 			/* Map the CQ memory out for userland access */
1989e39c5baSBill Taylor 			status = hermon_umap_cqmem(state, dhp, rsrcp, off,
1999e39c5baSBill Taylor 			    maplen, &err);
2009e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
2019e39c5baSBill Taylor 				return (err);
2029e39c5baSBill Taylor 			}
2039e39c5baSBill Taylor 			break;
2049e39c5baSBill Taylor 
2059e39c5baSBill Taylor 		case MLNX_UMAP_QPMEM_RSRC:
2069e39c5baSBill Taylor 			/* Map the QP memory out for userland access */
2079e39c5baSBill Taylor 			status = hermon_umap_qpmem(state, dhp, rsrcp, off,
2089e39c5baSBill Taylor 			    maplen, &err);
2099e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
2109e39c5baSBill Taylor 				return (err);
2119e39c5baSBill Taylor 			}
2129e39c5baSBill Taylor 			break;
2139e39c5baSBill Taylor 
2149e39c5baSBill Taylor 		case MLNX_UMAP_SRQMEM_RSRC:
2159e39c5baSBill Taylor 			/* Map the SRQ memory out for userland access */
2169e39c5baSBill Taylor 			status = hermon_umap_srqmem(state, dhp, rsrcp, off,
2179e39c5baSBill Taylor 			    maplen, &err);
2189e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
2199e39c5baSBill Taylor 				return (err);
2209e39c5baSBill Taylor 			}
2219e39c5baSBill Taylor 			break;
2229e39c5baSBill Taylor 
2239e39c5baSBill Taylor 		case MLNX_UMAP_DBRMEM_RSRC:
2249e39c5baSBill Taylor 			/*
2259e39c5baSBill Taylor 			 * Map the doorbell record memory out for
2269e39c5baSBill Taylor 			 * userland access
2279e39c5baSBill Taylor 			 */
2289e39c5baSBill Taylor 			status = hermon_umap_dbrecmem(state, dhp, rsrcp, off,
2299e39c5baSBill Taylor 			    maplen, &err);
2309e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
2319e39c5baSBill Taylor 				return (err);
2329e39c5baSBill Taylor 			}
2339e39c5baSBill Taylor 			break;
2349e39c5baSBill Taylor 
2359e39c5baSBill Taylor 		default:
2369e39c5baSBill Taylor 			HERMON_WARNING(state, "unexpected rsrc type in devmap");
2379e39c5baSBill Taylor 			return (EINVAL);
2389e39c5baSBill Taylor 		}
2399e39c5baSBill Taylor 	} else {
2409e39c5baSBill Taylor 		return (EINVAL);
2419e39c5baSBill Taylor 	}
2429e39c5baSBill Taylor 
2439e39c5baSBill Taylor 	return (0);
2449e39c5baSBill Taylor }
2459e39c5baSBill Taylor 
2469e39c5baSBill Taylor 
2479e39c5baSBill Taylor /*
2489e39c5baSBill Taylor  * hermon_umap_uarpg()
2499e39c5baSBill Taylor  *    Context: Can be called from user context.
2509e39c5baSBill Taylor  */
2519e39c5baSBill Taylor static int
hermon_umap_uarpg(hermon_state_t * state,devmap_cookie_t dhp,hermon_rsrc_t * rsrcp,uint64_t offset,size_t * maplen,int * err)2529e39c5baSBill Taylor hermon_umap_uarpg(hermon_state_t *state, devmap_cookie_t dhp,
2539e39c5baSBill Taylor     hermon_rsrc_t *rsrcp, uint64_t offset, size_t *maplen, int *err)
2549e39c5baSBill Taylor {
2559e39c5baSBill Taylor 	int			status;
2569e39c5baSBill Taylor 	uint_t			maxprot;
2579e39c5baSBill Taylor 	ddi_device_acc_attr_t	*accattrp = &state->hs_reg_accattr;
2589e39c5baSBill Taylor 	ddi_device_acc_attr_t	accattr;
2599e39c5baSBill Taylor 
2609e39c5baSBill Taylor 	if (offset != 0) {	/* Hermon Blueflame */
2619e39c5baSBill Taylor 		/* Try to use write coalescing data ordering */
2629e39c5baSBill Taylor 		accattr = *accattrp;
2639e39c5baSBill Taylor 		accattr.devacc_attr_dataorder = DDI_STORECACHING_OK_ACC;
2649e39c5baSBill Taylor 		accattrp = &accattr;
2659e39c5baSBill Taylor 	}
2669e39c5baSBill Taylor 
2679e39c5baSBill Taylor 	/* Map out the UAR page (doorbell page) */
2689e39c5baSBill Taylor 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
2699e39c5baSBill Taylor 	status = devmap_devmem_setup(dhp, state->hs_dip,
2709e39c5baSBill Taylor 	    &hermon_devmap_devmem_cbops, HERMON_UAR_BAR, (rsrcp->hr_indx <<
2719e39c5baSBill Taylor 	    PAGESHIFT) + offset, PAGESIZE, maxprot, DEVMAP_ALLOW_REMAP,
2729e39c5baSBill Taylor 	    accattrp);
2739e39c5baSBill Taylor 	if (status < 0) {
2749e39c5baSBill Taylor 		*err = status;
2759e39c5baSBill Taylor 		return (DDI_FAILURE);
2769e39c5baSBill Taylor 	}
2779e39c5baSBill Taylor 
2789e39c5baSBill Taylor 	*maplen = PAGESIZE;
2799e39c5baSBill Taylor 	return (DDI_SUCCESS);
2809e39c5baSBill Taylor }
2819e39c5baSBill Taylor 
2829e39c5baSBill Taylor 
2839e39c5baSBill Taylor /*
2849e39c5baSBill Taylor  * hermon_umap_cqmem()
2859e39c5baSBill Taylor  *    Context: Can be called from user context.
2869e39c5baSBill Taylor  */
2879e39c5baSBill Taylor /* ARGSUSED */
2889e39c5baSBill Taylor static int
hermon_umap_cqmem(hermon_state_t * state,devmap_cookie_t dhp,hermon_rsrc_t * rsrcp,offset_t off,size_t * maplen,int * err)2899e39c5baSBill Taylor hermon_umap_cqmem(hermon_state_t *state, devmap_cookie_t dhp,
2909e39c5baSBill Taylor     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
2919e39c5baSBill Taylor {
2929e39c5baSBill Taylor 	hermon_cqhdl_t	cq;
2939e39c5baSBill Taylor 	size_t		size;
2949e39c5baSBill Taylor 	uint_t		maxprot;
2959e39c5baSBill Taylor 	int		status;
2969e39c5baSBill Taylor 
2979e39c5baSBill Taylor 	/* Extract the Hermon CQ handle pointer from the hermon_rsrc_t */
2989e39c5baSBill Taylor 	cq = (hermon_cqhdl_t)rsrcp->hr_addr;
2999e39c5baSBill Taylor 
3009e39c5baSBill Taylor 	/* Round-up the CQ size to system page size */
3019e39c5baSBill Taylor 	size = ptob(btopr(cq->cq_resize_hdl ?
3029e39c5baSBill Taylor 	    cq->cq_resize_hdl->cq_cqinfo.qa_size : cq->cq_cqinfo.qa_size));
3039e39c5baSBill Taylor 
3049e39c5baSBill Taylor 	/* Map out the CQ memory - use resize_hdl if non-NULL */
3059e39c5baSBill Taylor 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
3069e39c5baSBill Taylor 	status = devmap_umem_setup(dhp, state->hs_dip,
3079e39c5baSBill Taylor 	    &hermon_devmap_umem_cbops, cq->cq_resize_hdl ?
3089e39c5baSBill Taylor 	    cq->cq_resize_hdl->cq_cqinfo.qa_umemcookie :
3099e39c5baSBill Taylor 	    cq->cq_cqinfo.qa_umemcookie, 0, size,
3109e39c5baSBill Taylor 	    maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
3119e39c5baSBill Taylor 	if (status < 0) {
3129e39c5baSBill Taylor 		*err = status;
3139e39c5baSBill Taylor 		return (DDI_FAILURE);
3149e39c5baSBill Taylor 	}
3159e39c5baSBill Taylor 	*maplen = size;
3169e39c5baSBill Taylor 
3179e39c5baSBill Taylor 	return (DDI_SUCCESS);
3189e39c5baSBill Taylor }
3199e39c5baSBill Taylor 
3209e39c5baSBill Taylor 
3219e39c5baSBill Taylor /*
3229e39c5baSBill Taylor  * hermon_umap_qpmem()
3239e39c5baSBill Taylor  *    Context: Can be called from user context.
3249e39c5baSBill Taylor  */
3259e39c5baSBill Taylor /* ARGSUSED */
3269e39c5baSBill Taylor static int
hermon_umap_qpmem(hermon_state_t * state,devmap_cookie_t dhp,hermon_rsrc_t * rsrcp,offset_t off,size_t * maplen,int * err)3279e39c5baSBill Taylor hermon_umap_qpmem(hermon_state_t *state, devmap_cookie_t dhp,
3289e39c5baSBill Taylor     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
3299e39c5baSBill Taylor {
3309e39c5baSBill Taylor 	hermon_qphdl_t	qp;
3319e39c5baSBill Taylor 	offset_t	offset;
3329e39c5baSBill Taylor 	size_t		size;
3339e39c5baSBill Taylor 	uint_t		maxprot;
3349e39c5baSBill Taylor 	int		status;
3359e39c5baSBill Taylor 
3369e39c5baSBill Taylor 	/* Extract the Hermon QP handle pointer from the hermon_rsrc_t */
3379e39c5baSBill Taylor 	qp = (hermon_qphdl_t)rsrcp->hr_addr;
3389e39c5baSBill Taylor 
3399e39c5baSBill Taylor 	/*
3409e39c5baSBill Taylor 	 * Calculate the offset of the first work queue (send or recv) into
3419e39c5baSBill Taylor 	 * the memory (ddi_umem_alloc()) allocated previously for the QP.
3429e39c5baSBill Taylor 	 */
3439e39c5baSBill Taylor 	offset = (offset_t)((uintptr_t)qp->qp_wqinfo.qa_buf_aligned -
3449e39c5baSBill Taylor 	    (uintptr_t)qp->qp_wqinfo.qa_buf_real);
3459e39c5baSBill Taylor 
3469e39c5baSBill Taylor 	/* Round-up the QP work queue sizes to system page size */
3479e39c5baSBill Taylor 	size = ptob(btopr(qp->qp_wqinfo.qa_size));
3489e39c5baSBill Taylor 
3499e39c5baSBill Taylor 	/* Map out the QP memory */
3509e39c5baSBill Taylor 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
3519e39c5baSBill Taylor 	status = devmap_umem_setup(dhp, state->hs_dip,
3529e39c5baSBill Taylor 	    &hermon_devmap_umem_cbops, qp->qp_wqinfo.qa_umemcookie, offset,
3539e39c5baSBill Taylor 	    size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
3549e39c5baSBill Taylor 	if (status < 0) {
3559e39c5baSBill Taylor 		*err = status;
3569e39c5baSBill Taylor 		return (DDI_FAILURE);
3579e39c5baSBill Taylor 	}
3589e39c5baSBill Taylor 	*maplen = size;
3599e39c5baSBill Taylor 
3609e39c5baSBill Taylor 	return (DDI_SUCCESS);
3619e39c5baSBill Taylor }
3629e39c5baSBill Taylor 
3639e39c5baSBill Taylor 
3649e39c5baSBill Taylor /*
3659e39c5baSBill Taylor  * hermon_umap_srqmem()
3669e39c5baSBill Taylor  *    Context: Can be called from user context.
3679e39c5baSBill Taylor  */
3689e39c5baSBill Taylor /* ARGSUSED */
3699e39c5baSBill Taylor static int
hermon_umap_srqmem(hermon_state_t * state,devmap_cookie_t dhp,hermon_rsrc_t * rsrcp,offset_t off,size_t * maplen,int * err)3709e39c5baSBill Taylor hermon_umap_srqmem(hermon_state_t *state, devmap_cookie_t dhp,
3719e39c5baSBill Taylor     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
3729e39c5baSBill Taylor {
3739e39c5baSBill Taylor 	hermon_srqhdl_t	srq;
3749e39c5baSBill Taylor 	offset_t	offset;
3759e39c5baSBill Taylor 	size_t		size;
3769e39c5baSBill Taylor 	uint_t		maxprot;
3779e39c5baSBill Taylor 	int		status;
3789e39c5baSBill Taylor 
3799e39c5baSBill Taylor 	/* Extract the Hermon SRQ handle pointer from the hermon_rsrc_t */
3809e39c5baSBill Taylor 	srq = (hermon_srqhdl_t)rsrcp->hr_addr;
3819e39c5baSBill Taylor 
3829e39c5baSBill Taylor 	/*
3839e39c5baSBill Taylor 	 * Calculate the offset of the first shared recv queue into the memory
3849e39c5baSBill Taylor 	 * (ddi_umem_alloc()) allocated previously for the SRQ.
3859e39c5baSBill Taylor 	 */
3869e39c5baSBill Taylor 	offset = (offset_t)((uintptr_t)srq->srq_wqinfo.qa_buf_aligned -
3879e39c5baSBill Taylor 	    (uintptr_t)srq->srq_wqinfo.qa_buf_real);
3889e39c5baSBill Taylor 
3899e39c5baSBill Taylor 	/* Round-up the SRQ work queue sizes to system page size */
3909e39c5baSBill Taylor 	size = ptob(btopr(srq->srq_wqinfo.qa_size));
3919e39c5baSBill Taylor 
3929e39c5baSBill Taylor 	/* Map out the SRQ memory */
3939e39c5baSBill Taylor 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
3949e39c5baSBill Taylor 	status = devmap_umem_setup(dhp, state->hs_dip,
3959e39c5baSBill Taylor 	    &hermon_devmap_umem_cbops, srq->srq_wqinfo.qa_umemcookie, offset,
3969e39c5baSBill Taylor 	    size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
3979e39c5baSBill Taylor 	if (status < 0) {
3989e39c5baSBill Taylor 		*err = status;
3999e39c5baSBill Taylor 		return (DDI_FAILURE);
4009e39c5baSBill Taylor 	}
4019e39c5baSBill Taylor 	*maplen = size;
4029e39c5baSBill Taylor 
4039e39c5baSBill Taylor 	return (DDI_SUCCESS);
4049e39c5baSBill Taylor }
4059e39c5baSBill Taylor 
4069e39c5baSBill Taylor 
4079e39c5baSBill Taylor /*
4089e39c5baSBill Taylor  * hermon_devmap_dbrecmem()
4099e39c5baSBill Taylor  *    Context: Can be called from user context.
4109e39c5baSBill Taylor  */
4119e39c5baSBill Taylor /* ARGSUSED */
4129e39c5baSBill Taylor static int
hermon_umap_dbrecmem(hermon_state_t * state,devmap_cookie_t dhp,hermon_rsrc_t * rsrcp,offset_t off,size_t * maplen,int * err)4139e39c5baSBill Taylor hermon_umap_dbrecmem(hermon_state_t *state, devmap_cookie_t dhp,
4149e39c5baSBill Taylor     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
4159e39c5baSBill Taylor {
4169e39c5baSBill Taylor 	hermon_udbr_page_t *pagep;
4179e39c5baSBill Taylor 	offset_t	offset;
4189e39c5baSBill Taylor 	size_t		size;
4199e39c5baSBill Taylor 	uint_t		maxprot;
4209e39c5baSBill Taylor 	int		status;
4219e39c5baSBill Taylor 
4229e39c5baSBill Taylor 	/* We stored the udbr_page pointer, and not a hermon_rsrc_t */
4239e39c5baSBill Taylor 	pagep = (hermon_udbr_page_t *)rsrcp;
4249e39c5baSBill Taylor 
4259e39c5baSBill Taylor 	/*
4269e39c5baSBill Taylor 	 * Calculate the offset of the doorbell records into the memory
4279e39c5baSBill Taylor 	 * (ddi_umem_alloc()) allocated previously for them.
4289e39c5baSBill Taylor 	 */
4299e39c5baSBill Taylor 	offset = 0;
4309e39c5baSBill Taylor 
4319e39c5baSBill Taylor 	/* Round-up the doorbell page to system page size */
4329e39c5baSBill Taylor 	size = PAGESIZE;
4339e39c5baSBill Taylor 
4349e39c5baSBill Taylor 	/* Map out the Doorbell Record memory */
4359e39c5baSBill Taylor 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
4369e39c5baSBill Taylor 	status = devmap_umem_setup(dhp, state->hs_dip,
4379e39c5baSBill Taylor 	    &hermon_devmap_dbrecmem_cbops, pagep->upg_umemcookie, offset,
4389e39c5baSBill Taylor 	    size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
4399e39c5baSBill Taylor 	if (status < 0) {
4409e39c5baSBill Taylor 		*err = status;
4419e39c5baSBill Taylor 		return (DDI_FAILURE);
4429e39c5baSBill Taylor 	}
4439e39c5baSBill Taylor 	*maplen = size;
4449e39c5baSBill Taylor 
4459e39c5baSBill Taylor 	return (DDI_SUCCESS);
4469e39c5baSBill Taylor }
4479e39c5baSBill Taylor 
4489e39c5baSBill Taylor 
4499e39c5baSBill Taylor /*
4509e39c5baSBill Taylor  * hermon_devmap_umem_map()
4519e39c5baSBill Taylor  *    Context: Can be called from kernel context.
4529e39c5baSBill Taylor  */
4539e39c5baSBill Taylor /* ARGSUSED */
4549e39c5baSBill Taylor static int
hermon_devmap_umem_map(devmap_cookie_t dhp,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)4559e39c5baSBill Taylor hermon_devmap_umem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
4569e39c5baSBill Taylor     offset_t off, size_t len, void **pvtp)
4579e39c5baSBill Taylor {
4589e39c5baSBill Taylor 	hermon_state_t		*state;
4599e39c5baSBill Taylor 	hermon_devmap_track_t	*dvm_track;
4609e39c5baSBill Taylor 	hermon_cqhdl_t		cq;
4619e39c5baSBill Taylor 	hermon_qphdl_t		qp;
4629e39c5baSBill Taylor 	hermon_srqhdl_t		srq;
4639e39c5baSBill Taylor 	minor_t			instance;
4649e39c5baSBill Taylor 	uint64_t		key;
4659e39c5baSBill Taylor 	uint_t			type;
4669e39c5baSBill Taylor 
4679e39c5baSBill Taylor 	/* Get Hermon softstate structure from instance */
4689e39c5baSBill Taylor 	instance = HERMON_DEV_INSTANCE(dev);
4699e39c5baSBill Taylor 	state = ddi_get_soft_state(hermon_statep, instance);
4709e39c5baSBill Taylor 	if (state == NULL) {
4719e39c5baSBill Taylor 		return (ENXIO);
4729e39c5baSBill Taylor 	}
4739e39c5baSBill Taylor 
4749e39c5baSBill Taylor 	/*
4759e39c5baSBill Taylor 	 * The bottom bits of "offset" are undefined (number depends on
4769e39c5baSBill Taylor 	 * system PAGESIZE).  Shifting these off leaves us with a "key".
4779e39c5baSBill Taylor 	 * The "key" is actually a combination of both a real key value
4789e39c5baSBill Taylor 	 * (for the purpose of database lookup) and a "type" value.  Although
4799e39c5baSBill Taylor 	 * we are not going to do any database lookup per se, we do want
4809e39c5baSBill Taylor 	 * to extract the "key" and the "type" (to enable faster lookup of
4819e39c5baSBill Taylor 	 * the appropriate CQ or QP handle).
4829e39c5baSBill Taylor 	 */
4839e39c5baSBill Taylor 	key  = off >> PAGESHIFT;
4849e39c5baSBill Taylor 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
4859e39c5baSBill Taylor 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
4869e39c5baSBill Taylor 
4879e39c5baSBill Taylor 	/*
4889e39c5baSBill Taylor 	 * Allocate an entry to track the mapping and unmapping (specifically,
4899e39c5baSBill Taylor 	 * partial unmapping) of this resource.
4909e39c5baSBill Taylor 	 */
4919e39c5baSBill Taylor 	dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
4929e39c5baSBill Taylor 	    sizeof (hermon_devmap_track_t), KM_SLEEP);
4939e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
4949e39c5baSBill Taylor 	dvm_track->hdt_offset = off;
4959e39c5baSBill Taylor 	dvm_track->hdt_state  = state;
4969e39c5baSBill Taylor 	dvm_track->hdt_refcnt = 1;
4979e39c5baSBill Taylor 	mutex_init(&dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
4989e39c5baSBill Taylor 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
4999e39c5baSBill Taylor 
5009e39c5baSBill Taylor 	/*
5019e39c5baSBill Taylor 	 * Depending of the type of resource that has been mapped out, we
5029e39c5baSBill Taylor 	 * need to update the QP or CQ handle to reflect that it has, in
5039e39c5baSBill Taylor 	 * fact, been mapped.  This allows the driver code which frees a QP
5049e39c5baSBill Taylor 	 * or a CQ to know whether it is appropriate to do a
5059e39c5baSBill Taylor 	 * devmap_devmem_remap() to invalidate the userland mapping for the
5069e39c5baSBill Taylor 	 * corresponding queue's memory.
5079e39c5baSBill Taylor 	 */
5089e39c5baSBill Taylor 	if (type == MLNX_UMAP_CQMEM_RSRC) {
5099e39c5baSBill Taylor 
5109e39c5baSBill Taylor 		/* Use "key" (CQ number) to do fast lookup of CQ handle */
5119e39c5baSBill Taylor 		cq = hermon_cqhdl_from_cqnum(state, key);
5129e39c5baSBill Taylor 
5139e39c5baSBill Taylor 		/*
5149e39c5baSBill Taylor 		 * Update the handle to the userland mapping.  Note:  If
5159e39c5baSBill Taylor 		 * the CQ already has a valid userland mapping, then stop
5169e39c5baSBill Taylor 		 * and return failure.
5179e39c5baSBill Taylor 		 */
5189e39c5baSBill Taylor 		mutex_enter(&cq->cq_lock);
5199e39c5baSBill Taylor 		if (cq->cq_umap_dhp == NULL) {
5209e39c5baSBill Taylor 			cq->cq_umap_dhp = dhp;
5219e39c5baSBill Taylor 			dvm_track->hdt_size = cq->cq_cqinfo.qa_size;
5229e39c5baSBill Taylor 			mutex_exit(&cq->cq_lock);
5239e39c5baSBill Taylor 		} else if (cq->cq_resize_hdl &&
5249e39c5baSBill Taylor 		    (cq->cq_resize_hdl->cq_umap_dhp == NULL)) {
5259e39c5baSBill Taylor 			cq->cq_resize_hdl->cq_umap_dhp = dhp;
5269e39c5baSBill Taylor 			dvm_track->hdt_size =
5279e39c5baSBill Taylor 			    cq->cq_resize_hdl->cq_cqinfo.qa_size;
5289e39c5baSBill Taylor 			mutex_exit(&cq->cq_lock);
5299e39c5baSBill Taylor 		} else {
5309e39c5baSBill Taylor 			mutex_exit(&cq->cq_lock);
5319e39c5baSBill Taylor 			goto umem_map_fail;
5329e39c5baSBill Taylor 		}
5339e39c5baSBill Taylor 
5349e39c5baSBill Taylor 	} else if (type == MLNX_UMAP_QPMEM_RSRC) {
5359e39c5baSBill Taylor 
5369e39c5baSBill Taylor 		/* Use "key" (QP number) to do fast lookup of QP handle */
5379e39c5baSBill Taylor 		qp = hermon_qphdl_from_qpnum(state, key);
5389e39c5baSBill Taylor 
5399e39c5baSBill Taylor 		/*
5409e39c5baSBill Taylor 		 * Update the handle to the userland mapping.  Note:  If
5419e39c5baSBill Taylor 		 * the CQ already has a valid userland mapping, then stop
5429e39c5baSBill Taylor 		 * and return failure.
5439e39c5baSBill Taylor 		 */
5449e39c5baSBill Taylor 		mutex_enter(&qp->qp_lock);
5459e39c5baSBill Taylor 		if (qp->qp_umap_dhp == NULL) {
5469e39c5baSBill Taylor 			qp->qp_umap_dhp = dhp;
5479e39c5baSBill Taylor 			dvm_track->hdt_size = qp->qp_wqinfo.qa_size;
5489e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
5499e39c5baSBill Taylor 		} else {
5509e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
5519e39c5baSBill Taylor 			goto umem_map_fail;
5529e39c5baSBill Taylor 		}
5539e39c5baSBill Taylor 
5549e39c5baSBill Taylor 	} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
5559e39c5baSBill Taylor 
5569e39c5baSBill Taylor 		/* Use "key" (SRQ number) to do fast lookup on SRQ handle */
5579e39c5baSBill Taylor 		srq = hermon_srqhdl_from_srqnum(state, key);
5589e39c5baSBill Taylor 
5599e39c5baSBill Taylor 		/*
5609e39c5baSBill Taylor 		 * Update the handle to the userland mapping.  Note:  If the
5619e39c5baSBill Taylor 		 * SRQ already has a valid userland mapping, then stop and
5629e39c5baSBill Taylor 		 * return failure.
5639e39c5baSBill Taylor 		 */
5649e39c5baSBill Taylor 		mutex_enter(&srq->srq_lock);
5659e39c5baSBill Taylor 		if (srq->srq_umap_dhp == NULL) {
5669e39c5baSBill Taylor 			srq->srq_umap_dhp = dhp;
5679e39c5baSBill Taylor 			dvm_track->hdt_size = srq->srq_wqinfo.qa_size;
5689e39c5baSBill Taylor 			mutex_exit(&srq->srq_lock);
5699e39c5baSBill Taylor 		} else {
5709e39c5baSBill Taylor 			mutex_exit(&srq->srq_lock);
5719e39c5baSBill Taylor 			goto umem_map_fail;
5729e39c5baSBill Taylor 		}
5739e39c5baSBill Taylor 	}
5749e39c5baSBill Taylor 
5759e39c5baSBill Taylor 	/*
5769e39c5baSBill Taylor 	 * Pass the private "Hermon devmap tracking structure" back.  This
5779e39c5baSBill Taylor 	 * pointer will be returned in subsequent "unmap" callbacks.
5789e39c5baSBill Taylor 	 */
5799e39c5baSBill Taylor 	*pvtp = dvm_track;
5809e39c5baSBill Taylor 
5819e39c5baSBill Taylor 	return (DDI_SUCCESS);
5829e39c5baSBill Taylor 
5839e39c5baSBill Taylor umem_map_fail:
5849e39c5baSBill Taylor 	mutex_destroy(&dvm_track->hdt_lock);
5859e39c5baSBill Taylor 	kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
5869e39c5baSBill Taylor 	return (DDI_FAILURE);
5879e39c5baSBill Taylor }
5889e39c5baSBill Taylor 
5899e39c5baSBill Taylor 
5909e39c5baSBill Taylor /*
5919e39c5baSBill Taylor  * hermon_devmap_umem_dup()
5929e39c5baSBill Taylor  *    Context: Can be called from kernel context.
5939e39c5baSBill Taylor  */
5949e39c5baSBill Taylor /* ARGSUSED */
5959e39c5baSBill Taylor static int
hermon_devmap_umem_dup(devmap_cookie_t dhp,void * pvtp,devmap_cookie_t new_dhp,void ** new_pvtp)5969e39c5baSBill Taylor hermon_devmap_umem_dup(devmap_cookie_t dhp, void *pvtp, devmap_cookie_t new_dhp,
5979e39c5baSBill Taylor     void **new_pvtp)
5989e39c5baSBill Taylor {
5999e39c5baSBill Taylor 	hermon_state_t		*state;
6009e39c5baSBill Taylor 	hermon_devmap_track_t	*dvm_track, *new_dvm_track;
6019e39c5baSBill Taylor 	uint_t			maxprot;
6029e39c5baSBill Taylor 	int			status;
6039e39c5baSBill Taylor 
6049e39c5baSBill Taylor 	/*
6059e39c5baSBill Taylor 	 * Extract the Hermon softstate pointer from "Hermon devmap tracking
6069e39c5baSBill Taylor 	 * structure" (in "pvtp").
6079e39c5baSBill Taylor 	 */
6089e39c5baSBill Taylor 	dvm_track = (hermon_devmap_track_t *)pvtp;
6099e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
6109e39c5baSBill Taylor 	state = dvm_track->hdt_state;
6119e39c5baSBill Taylor 
6129e39c5baSBill Taylor 	/*
6139e39c5baSBill Taylor 	 * Since this devmap_dup() entry point is generally called
6149e39c5baSBill Taylor 	 * when a process does fork(2), it is incumbent upon the driver
6159e39c5baSBill Taylor 	 * to insure that the child does not inherit a valid copy of
6169e39c5baSBill Taylor 	 * the parent's QP or CQ resource.  This is accomplished by using
6179e39c5baSBill Taylor 	 * devmap_devmem_remap() to invalidate the child's mapping to the
6189e39c5baSBill Taylor 	 * kernel memory.
6199e39c5baSBill Taylor 	 */
6209e39c5baSBill Taylor 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
6219e39c5baSBill Taylor 	status = devmap_devmem_remap(new_dhp, state->hs_dip, 0, 0,
6229e39c5baSBill Taylor 	    dvm_track->hdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
6239e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
6249e39c5baSBill Taylor 		HERMON_WARNING(state, "failed in hermon_devmap_umem_dup()");
6259e39c5baSBill Taylor 		return (status);
6269e39c5baSBill Taylor 	}
6279e39c5baSBill Taylor 
6289e39c5baSBill Taylor 	/*
6299e39c5baSBill Taylor 	 * Allocate a new entry to track the subsequent unmapping
6309e39c5baSBill Taylor 	 * (specifically, all partial unmappings) of the child's newly
6319e39c5baSBill Taylor 	 * invalidated resource.  Note: Setting the "hdt_size" field to
6329e39c5baSBill Taylor 	 * zero here is an indication to the devmap_unmap() entry point
6339e39c5baSBill Taylor 	 * that this mapping is invalid, and that its subsequent unmapping
6349e39c5baSBill Taylor 	 * should not affect any of the parent's CQ or QP resources.
6359e39c5baSBill Taylor 	 */
6369e39c5baSBill Taylor 	new_dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
6379e39c5baSBill Taylor 	    sizeof (hermon_devmap_track_t), KM_SLEEP);
6389e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*new_dvm_track))
6399e39c5baSBill Taylor 	new_dvm_track->hdt_offset = 0;
6409e39c5baSBill Taylor 	new_dvm_track->hdt_state  = state;
6419e39c5baSBill Taylor 	new_dvm_track->hdt_refcnt = 1;
6429e39c5baSBill Taylor 	new_dvm_track->hdt_size	  = 0;
6439e39c5baSBill Taylor 	mutex_init(&new_dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
6449e39c5baSBill Taylor 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
6459e39c5baSBill Taylor 	*new_pvtp = new_dvm_track;
6469e39c5baSBill Taylor 
6479e39c5baSBill Taylor 	return (DDI_SUCCESS);
6489e39c5baSBill Taylor }
6499e39c5baSBill Taylor 
6509e39c5baSBill Taylor 
6519e39c5baSBill Taylor /*
6529e39c5baSBill Taylor  * hermon_devmap_umem_unmap()
6539e39c5baSBill Taylor  *    Context: Can be called from kernel context.
6549e39c5baSBill Taylor  */
6559e39c5baSBill Taylor /* ARGSUSED */
6569e39c5baSBill Taylor static void
hermon_devmap_umem_unmap(devmap_cookie_t dhp,void * pvtp,offset_t off,size_t len,devmap_cookie_t new_dhp1,void ** pvtp1,devmap_cookie_t new_dhp2,void ** pvtp2)6579e39c5baSBill Taylor hermon_devmap_umem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
6589e39c5baSBill Taylor     size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
6599e39c5baSBill Taylor     devmap_cookie_t new_dhp2, void **pvtp2)
6609e39c5baSBill Taylor {
6619e39c5baSBill Taylor 	hermon_state_t 		*state;
6629e39c5baSBill Taylor 	hermon_rsrc_t 		*rsrcp;
6639e39c5baSBill Taylor 	hermon_devmap_track_t	*dvm_track;
6649e39c5baSBill Taylor 	hermon_cqhdl_t		cq;
6659e39c5baSBill Taylor 	hermon_qphdl_t		qp;
6669e39c5baSBill Taylor 	hermon_srqhdl_t		srq;
6679e39c5baSBill Taylor 	uint64_t		key, value;
6689e39c5baSBill Taylor 	uint_t			type;
6699e39c5baSBill Taylor 	uint_t			size;
6709e39c5baSBill Taylor 	int			status;
6719e39c5baSBill Taylor 
6729e39c5baSBill Taylor 	/*
6739e39c5baSBill Taylor 	 * Extract the Hermon softstate pointer from "Hermon devmap tracking
6749e39c5baSBill Taylor 	 * structure" (in "pvtp").
6759e39c5baSBill Taylor 	 */
6769e39c5baSBill Taylor 	dvm_track = (hermon_devmap_track_t *)pvtp;
6779e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
6789e39c5baSBill Taylor 	state	  = dvm_track->hdt_state;
6799e39c5baSBill Taylor 
6809e39c5baSBill Taylor 	/*
6819e39c5baSBill Taylor 	 * Extract the "offset" from the "Hermon devmap tracking structure".
6829e39c5baSBill Taylor 	 * Note: The input argument "off" is ignored here because the
6839e39c5baSBill Taylor 	 * Hermon mapping interfaces define a very specific meaning to
6849e39c5baSBill Taylor 	 * each "logical offset".  Also extract the "key" and "type" encoded
6859e39c5baSBill Taylor 	 * in the logical offset.
6869e39c5baSBill Taylor 	 */
6879e39c5baSBill Taylor 	key  = dvm_track->hdt_offset >> PAGESHIFT;
6889e39c5baSBill Taylor 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
6899e39c5baSBill Taylor 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
6909e39c5baSBill Taylor 
6919e39c5baSBill Taylor 	/*
6929e39c5baSBill Taylor 	 * Extract the "size" of the mapping.  If this size is determined
6939e39c5baSBill Taylor 	 * to be zero, then it is an indication of a previously invalidated
6949e39c5baSBill Taylor 	 * mapping, and no CQ or QP resources should be affected.
6959e39c5baSBill Taylor 	 */
6969e39c5baSBill Taylor 	size = dvm_track->hdt_size;
6979e39c5baSBill Taylor 
6989e39c5baSBill Taylor 	/*
6999e39c5baSBill Taylor 	 * If only the "middle portion of a given mapping is being unmapped,
7009e39c5baSBill Taylor 	 * then we are effectively creating one new piece of mapped memory.
7019e39c5baSBill Taylor 	 * (Original region is divided into three pieces of which the middle
7029e39c5baSBill Taylor 	 * piece is being removed.  This leaves two pieces.  Since we started
7039e39c5baSBill Taylor 	 * with one piece and now have two pieces, we need to increment the
7049e39c5baSBill Taylor 	 * counter in the "Hermon devmap tracking structure".
7059e39c5baSBill Taylor 	 *
7069e39c5baSBill Taylor 	 * If, however, the whole mapped region is being unmapped, then we
7079e39c5baSBill Taylor 	 * have started with one region which we are completely removing.
7089e39c5baSBill Taylor 	 * In this case, we need to decrement the counter in the "Hermon
7099e39c5baSBill Taylor 	 * devmap tracking structure".
7109e39c5baSBill Taylor 	 *
7119e39c5baSBill Taylor 	 * In each of the remaining cases, we will have started with one
7129e39c5baSBill Taylor 	 * mapped region and ended with one (different) region.  So no counter
7139e39c5baSBill Taylor 	 * modification is necessary.
7149e39c5baSBill Taylor 	 */
7159e39c5baSBill Taylor 	mutex_enter(&dvm_track->hdt_lock);
7169e39c5baSBill Taylor 	if ((new_dhp1 == NULL) && (new_dhp2 == NULL)) {
7179e39c5baSBill Taylor 		dvm_track->hdt_refcnt--;
7189e39c5baSBill Taylor 	} else if ((new_dhp1 != NULL) && (new_dhp2 != NULL)) {
7199e39c5baSBill Taylor 		dvm_track->hdt_refcnt++;
7209e39c5baSBill Taylor 	}
7219e39c5baSBill Taylor 	mutex_exit(&dvm_track->hdt_lock);
7229e39c5baSBill Taylor 
7239e39c5baSBill Taylor 	/*
7249e39c5baSBill Taylor 	 * For each of the cases where the region is being divided, then we
7259e39c5baSBill Taylor 	 * need to pass back the "Hermon devmap tracking structure".  This way
7269e39c5baSBill Taylor 	 * we get it back when each of the remaining pieces is subsequently
7279e39c5baSBill Taylor 	 * unmapped.
7289e39c5baSBill Taylor 	 */
7299e39c5baSBill Taylor 	if (new_dhp1 != NULL) {
7309e39c5baSBill Taylor 		*pvtp1 = pvtp;
7319e39c5baSBill Taylor 	}
7329e39c5baSBill Taylor 	if (new_dhp2 != NULL) {
7339e39c5baSBill Taylor 		*pvtp2 = pvtp;
7349e39c5baSBill Taylor 	}
7359e39c5baSBill Taylor 
7369e39c5baSBill Taylor 	/*
7379e39c5baSBill Taylor 	 * If the "Hermon devmap tracking structure" is no longer being
7389e39c5baSBill Taylor 	 * referenced, then free it up.  Otherwise, return.
7399e39c5baSBill Taylor 	 */
7409e39c5baSBill Taylor 	if (dvm_track->hdt_refcnt == 0) {
7419e39c5baSBill Taylor 		mutex_destroy(&dvm_track->hdt_lock);
7429e39c5baSBill Taylor 		kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
7439e39c5baSBill Taylor 
7449e39c5baSBill Taylor 		/*
7459e39c5baSBill Taylor 		 * If the mapping was invalid (see explanation above), then
7469e39c5baSBill Taylor 		 * no further processing is necessary.
7479e39c5baSBill Taylor 		 */
7489e39c5baSBill Taylor 		if (size == 0) {
7499e39c5baSBill Taylor 			return;
7509e39c5baSBill Taylor 		}
7519e39c5baSBill Taylor 	} else {
7529e39c5baSBill Taylor 		return;
7539e39c5baSBill Taylor 	}
7549e39c5baSBill Taylor 
7559e39c5baSBill Taylor 	/*
7569e39c5baSBill Taylor 	 * Now that we can guarantee that the user memory is fully unmapped,
7579e39c5baSBill Taylor 	 * we can use the "key" and "type" values to try to find the entry
7589e39c5baSBill Taylor 	 * in the "userland resources database".  If it's found, then it
7599e39c5baSBill Taylor 	 * indicates that the queue memory (CQ or QP) has not yet been freed.
7609e39c5baSBill Taylor 	 * In this case, we update the corresponding CQ or QP handle to
7619e39c5baSBill Taylor 	 * indicate that the "devmap_devmem_remap()" call will be unnecessary.
7629e39c5baSBill Taylor 	 * If it's _not_ found, then it indicates that the CQ or QP memory
7639e39c5baSBill Taylor 	 * was, in fact, freed before it was unmapped (thus requiring a
7649e39c5baSBill Taylor 	 * previous invalidation by remapping - which will already have
7659e39c5baSBill Taylor 	 * been done in the free routine).
7669e39c5baSBill Taylor 	 */
7679e39c5baSBill Taylor 	status = hermon_umap_db_find(state->hs_instance, key, type, &value,
7689e39c5baSBill Taylor 	    0, NULL);
7699e39c5baSBill Taylor 	if (status == DDI_SUCCESS) {
7709e39c5baSBill Taylor 		/*
7719e39c5baSBill Taylor 		 * Depending on the type of the mapped resource (CQ or QP),
7729e39c5baSBill Taylor 		 * update handle to indicate that no invalidation remapping
7739e39c5baSBill Taylor 		 * will be necessary.
7749e39c5baSBill Taylor 		 */
7759e39c5baSBill Taylor 		if (type == MLNX_UMAP_CQMEM_RSRC) {
7769e39c5baSBill Taylor 
7779e39c5baSBill Taylor 			/* Use "value" to convert to CQ handle */
7789e39c5baSBill Taylor 			rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
7799e39c5baSBill Taylor 			cq = (hermon_cqhdl_t)rsrcp->hr_addr;
7809e39c5baSBill Taylor 
7819e39c5baSBill Taylor 			/*
7829e39c5baSBill Taylor 			 * Invalidate the handle to the userland mapping.
7839e39c5baSBill Taylor 			 * Note: We must ensure that the mapping being
7849e39c5baSBill Taylor 			 * unmapped here is the current one for the CQ.  It
7859e39c5baSBill Taylor 			 * is possible that it might not be if this CQ has
7869e39c5baSBill Taylor 			 * been resized and the previous CQ memory has not
7879e39c5baSBill Taylor 			 * yet been unmapped.  But in that case, because of
7889e39c5baSBill Taylor 			 * the devmap_devmem_remap(), there is no longer any
7899e39c5baSBill Taylor 			 * association between the mapping and the real CQ
7909e39c5baSBill Taylor 			 * kernel memory.
7919e39c5baSBill Taylor 			 */
7929e39c5baSBill Taylor 			mutex_enter(&cq->cq_lock);
7939e39c5baSBill Taylor 			if (cq->cq_umap_dhp == dhp) {
7949e39c5baSBill Taylor 				cq->cq_umap_dhp = NULL;
7959e39c5baSBill Taylor 				if (cq->cq_resize_hdl) {
7969e39c5baSBill Taylor 					/* resize is DONE, switch queues */
7979e39c5baSBill Taylor 					hermon_cq_resize_helper(state, cq);
7989e39c5baSBill Taylor 				}
7999e39c5baSBill Taylor 			} else {
8009e39c5baSBill Taylor 				if (cq->cq_resize_hdl &&
8019e39c5baSBill Taylor 				    cq->cq_resize_hdl->cq_umap_dhp == dhp) {
8029e39c5baSBill Taylor 					/*
8039e39c5baSBill Taylor 					 * Unexpected case.  munmap of the
8049e39c5baSBill Taylor 					 * cq_resize buf, and not the
8059e39c5baSBill Taylor 					 * original buf.
8069e39c5baSBill Taylor 					 */
8079e39c5baSBill Taylor 					cq->cq_resize_hdl->cq_umap_dhp = NULL;
8089e39c5baSBill Taylor 				}
8099e39c5baSBill Taylor 			}
8109e39c5baSBill Taylor 			mutex_exit(&cq->cq_lock);
8119e39c5baSBill Taylor 
8129e39c5baSBill Taylor 		} else if (type == MLNX_UMAP_QPMEM_RSRC) {
8139e39c5baSBill Taylor 
8149e39c5baSBill Taylor 			/* Use "value" to convert to QP handle */
8159e39c5baSBill Taylor 			rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
8169e39c5baSBill Taylor 			qp = (hermon_qphdl_t)rsrcp->hr_addr;
8179e39c5baSBill Taylor 
8189e39c5baSBill Taylor 			/*
8199e39c5baSBill Taylor 			 * Invalidate the handle to the userland mapping.
8209e39c5baSBill Taylor 			 * Note: we ensure that the mapping being unmapped
8219e39c5baSBill Taylor 			 * here is the current one for the QP.  This is
8229e39c5baSBill Taylor 			 * more of a sanity check here since, unlike CQs
8239e39c5baSBill Taylor 			 * (above) we do not support resize of QPs.
8249e39c5baSBill Taylor 			 */
8259e39c5baSBill Taylor 			mutex_enter(&qp->qp_lock);
8269e39c5baSBill Taylor 			if (qp->qp_umap_dhp == dhp) {
8279e39c5baSBill Taylor 				qp->qp_umap_dhp = NULL;
8289e39c5baSBill Taylor 			}
8299e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
8309e39c5baSBill Taylor 
8319e39c5baSBill Taylor 		} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
8329e39c5baSBill Taylor 
8339e39c5baSBill Taylor 			/* Use "value" to convert to SRQ handle */
8349e39c5baSBill Taylor 			rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
8359e39c5baSBill Taylor 			srq = (hermon_srqhdl_t)rsrcp->hr_addr;
8369e39c5baSBill Taylor 
8379e39c5baSBill Taylor 			/*
8389e39c5baSBill Taylor 			 * Invalidate the handle to the userland mapping.
8399e39c5baSBill Taylor 			 * Note: we ensure that the mapping being unmapped
8409e39c5baSBill Taylor 			 * here is the current one for the QP.  This is
8419e39c5baSBill Taylor 			 * more of a sanity check here since, unlike CQs
8429e39c5baSBill Taylor 			 * (above) we do not support resize of QPs.
8439e39c5baSBill Taylor 			 */
8449e39c5baSBill Taylor 			mutex_enter(&srq->srq_lock);
8459e39c5baSBill Taylor 			if (srq->srq_umap_dhp == dhp) {
8469e39c5baSBill Taylor 				srq->srq_umap_dhp = NULL;
8479e39c5baSBill Taylor 			}
8489e39c5baSBill Taylor 			mutex_exit(&srq->srq_lock);
8499e39c5baSBill Taylor 		}
8509e39c5baSBill Taylor 	}
8519e39c5baSBill Taylor }
8529e39c5baSBill Taylor 
8539e39c5baSBill Taylor 
8549e39c5baSBill Taylor /*
8559e39c5baSBill Taylor  * hermon_devmap_devmem_map()
8569e39c5baSBill Taylor  *    Context: Can be called from kernel context.
8579e39c5baSBill Taylor  */
8589e39c5baSBill Taylor /* ARGSUSED */
8599e39c5baSBill Taylor static int
hermon_devmap_dbrecmem_map(devmap_cookie_t dhp,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)8609e39c5baSBill Taylor hermon_devmap_dbrecmem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
8619e39c5baSBill Taylor     offset_t off, size_t len, void **pvtp)
8629e39c5baSBill Taylor {
8639e39c5baSBill Taylor 	hermon_state_t		*state;
8649e39c5baSBill Taylor 	hermon_devmap_track_t	*dvm_track;
8659e39c5baSBill Taylor 	hermon_cqhdl_t		cq;
8669e39c5baSBill Taylor 	hermon_qphdl_t		qp;
8679e39c5baSBill Taylor 	hermon_srqhdl_t		srq;
8689e39c5baSBill Taylor 	minor_t			instance;
8699e39c5baSBill Taylor 	uint64_t		key;
8709e39c5baSBill Taylor 	uint_t			type;
8719e39c5baSBill Taylor 
8729e39c5baSBill Taylor 	/* Get Hermon softstate structure from instance */
8739e39c5baSBill Taylor 	instance = HERMON_DEV_INSTANCE(dev);
8749e39c5baSBill Taylor 	state = ddi_get_soft_state(hermon_statep, instance);
8759e39c5baSBill Taylor 	if (state == NULL) {
8769e39c5baSBill Taylor 		return (ENXIO);
8779e39c5baSBill Taylor 	}
8789e39c5baSBill Taylor 
8799e39c5baSBill Taylor 	/*
8809e39c5baSBill Taylor 	 * The bottom bits of "offset" are undefined (number depends on
8819e39c5baSBill Taylor 	 * system PAGESIZE).  Shifting these off leaves us with a "key".
8829e39c5baSBill Taylor 	 * The "key" is actually a combination of both a real key value
8839e39c5baSBill Taylor 	 * (for the purpose of database lookup) and a "type" value.  Although
8849e39c5baSBill Taylor 	 * we are not going to do any database lookup per se, we do want
8859e39c5baSBill Taylor 	 * to extract the "key" and the "type" (to enable faster lookup of
8869e39c5baSBill Taylor 	 * the appropriate CQ or QP handle).
8879e39c5baSBill Taylor 	 */
8889e39c5baSBill Taylor 	key  = off >> PAGESHIFT;
8899e39c5baSBill Taylor 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
8909e39c5baSBill Taylor 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
8919e39c5baSBill Taylor 
8929e39c5baSBill Taylor 	/*
8939e39c5baSBill Taylor 	 * Allocate an entry to track the mapping and unmapping (specifically,
8949e39c5baSBill Taylor 	 * partial unmapping) of this resource.
8959e39c5baSBill Taylor 	 */
8969e39c5baSBill Taylor 	dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
8979e39c5baSBill Taylor 	    sizeof (hermon_devmap_track_t), KM_SLEEP);
8989e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
8999e39c5baSBill Taylor 	dvm_track->hdt_offset = off;
9009e39c5baSBill Taylor 	dvm_track->hdt_state  = state;
9019e39c5baSBill Taylor 	dvm_track->hdt_refcnt = 1;
9029e39c5baSBill Taylor 	mutex_init(&dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
9039e39c5baSBill Taylor 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
9049e39c5baSBill Taylor 
9059e39c5baSBill Taylor 	/*
9069e39c5baSBill Taylor 	 * Depending of the type of resource that has been mapped out, we
9079e39c5baSBill Taylor 	 * need to update the QP or CQ handle to reflect that it has, in
9089e39c5baSBill Taylor 	 * fact, been mapped.  This allows the driver code which frees a QP
9099e39c5baSBill Taylor 	 * or a CQ to know whether it is appropriate to do a
9109e39c5baSBill Taylor 	 * devmap_devmem_remap() to invalidate the userland mapping for the
9119e39c5baSBill Taylor 	 * corresponding queue's memory.
9129e39c5baSBill Taylor 	 */
9139e39c5baSBill Taylor 	if (type == MLNX_UMAP_CQMEM_RSRC) {
9149e39c5baSBill Taylor 
9159e39c5baSBill Taylor 		/* Use "key" (CQ number) to do fast lookup of CQ handle */
9169e39c5baSBill Taylor 		cq = hermon_cqhdl_from_cqnum(state, key);
9179e39c5baSBill Taylor 
9189e39c5baSBill Taylor 		/*
9199e39c5baSBill Taylor 		 * Update the handle to the userland mapping.  Note:  If
9209e39c5baSBill Taylor 		 * the CQ already has a valid userland mapping, then stop
9219e39c5baSBill Taylor 		 * and return failure.
9229e39c5baSBill Taylor 		 */
9239e39c5baSBill Taylor 		mutex_enter(&cq->cq_lock);
9249e39c5baSBill Taylor 		if (cq->cq_umap_dhp == NULL) {
9259e39c5baSBill Taylor 			cq->cq_umap_dhp = dhp;
9269e39c5baSBill Taylor 			dvm_track->hdt_size = cq->cq_cqinfo.qa_size;
9279e39c5baSBill Taylor 			mutex_exit(&cq->cq_lock);
9289e39c5baSBill Taylor 		} else {
9299e39c5baSBill Taylor 			mutex_exit(&cq->cq_lock);
9309e39c5baSBill Taylor 			goto umem_map_fail;
9319e39c5baSBill Taylor 		}
9329e39c5baSBill Taylor 
9339e39c5baSBill Taylor 	} else if (type == MLNX_UMAP_QPMEM_RSRC) {
9349e39c5baSBill Taylor 
9359e39c5baSBill Taylor 		/* Use "key" (QP number) to do fast lookup of QP handle */
9369e39c5baSBill Taylor 		qp = hermon_qphdl_from_qpnum(state, key);
9379e39c5baSBill Taylor 
9389e39c5baSBill Taylor 		/*
9399e39c5baSBill Taylor 		 * Update the handle to the userland mapping.  Note:  If
9409e39c5baSBill Taylor 		 * the CQ already has a valid userland mapping, then stop
9419e39c5baSBill Taylor 		 * and return failure.
9429e39c5baSBill Taylor 		 */
9439e39c5baSBill Taylor 		mutex_enter(&qp->qp_lock);
9449e39c5baSBill Taylor 		if (qp->qp_umap_dhp == NULL) {
9459e39c5baSBill Taylor 			qp->qp_umap_dhp = dhp;
9469e39c5baSBill Taylor 			dvm_track->hdt_size = qp->qp_wqinfo.qa_size;
9479e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
9489e39c5baSBill Taylor 		} else {
9499e39c5baSBill Taylor 			mutex_exit(&qp->qp_lock);
9509e39c5baSBill Taylor 			goto umem_map_fail;
9519e39c5baSBill Taylor 		}
9529e39c5baSBill Taylor 
9539e39c5baSBill Taylor 	} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
9549e39c5baSBill Taylor 
9559e39c5baSBill Taylor 		/* Use "key" (SRQ number) to do fast lookup on SRQ handle */
9569e39c5baSBill Taylor 		srq = hermon_srqhdl_from_srqnum(state, key);
9579e39c5baSBill Taylor 
9589e39c5baSBill Taylor 		/*
9599e39c5baSBill Taylor 		 * Update the handle to the userland mapping.  Note:  If the
9609e39c5baSBill Taylor 		 * SRQ already has a valid userland mapping, then stop and
9619e39c5baSBill Taylor 		 * return failure.
9629e39c5baSBill Taylor 		 */
9639e39c5baSBill Taylor 		mutex_enter(&srq->srq_lock);
9649e39c5baSBill Taylor 		if (srq->srq_umap_dhp == NULL) {
9659e39c5baSBill Taylor 			srq->srq_umap_dhp = dhp;
9669e39c5baSBill Taylor 			dvm_track->hdt_size = srq->srq_wqinfo.qa_size;
9679e39c5baSBill Taylor 			mutex_exit(&srq->srq_lock);
9689e39c5baSBill Taylor 		} else {
9699e39c5baSBill Taylor 			mutex_exit(&srq->srq_lock);
9709e39c5baSBill Taylor 			goto umem_map_fail;
9719e39c5baSBill Taylor 		}
9729e39c5baSBill Taylor 	}
9739e39c5baSBill Taylor 
9749e39c5baSBill Taylor 	/*
9759e39c5baSBill Taylor 	 * Pass the private "Hermon devmap tracking structure" back.  This
9769e39c5baSBill Taylor 	 * pointer will be returned in subsequent "unmap" callbacks.
9779e39c5baSBill Taylor 	 */
9789e39c5baSBill Taylor 	*pvtp = dvm_track;
9799e39c5baSBill Taylor 
9809e39c5baSBill Taylor 	return (DDI_SUCCESS);
9819e39c5baSBill Taylor 
9829e39c5baSBill Taylor umem_map_fail:
9839e39c5baSBill Taylor 	mutex_destroy(&dvm_track->hdt_lock);
9849e39c5baSBill Taylor 	kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
9859e39c5baSBill Taylor 	return (DDI_FAILURE);
9869e39c5baSBill Taylor }
9879e39c5baSBill Taylor 
9889e39c5baSBill Taylor 
9899e39c5baSBill Taylor /*
9909e39c5baSBill Taylor  * hermon_devmap_dbrecmem_dup()
9919e39c5baSBill Taylor  *    Context: Can be called from kernel context.
9929e39c5baSBill Taylor  */
9939e39c5baSBill Taylor /* ARGSUSED */
9949e39c5baSBill Taylor static int
hermon_devmap_dbrecmem_dup(devmap_cookie_t dhp,void * pvtp,devmap_cookie_t new_dhp,void ** new_pvtp)9959e39c5baSBill Taylor hermon_devmap_dbrecmem_dup(devmap_cookie_t dhp, void *pvtp,
9969e39c5baSBill Taylor     devmap_cookie_t new_dhp, void **new_pvtp)
9979e39c5baSBill Taylor {
9989e39c5baSBill Taylor 	hermon_state_t		*state;
9999e39c5baSBill Taylor 	hermon_devmap_track_t	*dvm_track, *new_dvm_track;
10009e39c5baSBill Taylor 	uint_t			maxprot;
10019e39c5baSBill Taylor 	int			status;
10029e39c5baSBill Taylor 
10039e39c5baSBill Taylor 	/*
10049e39c5baSBill Taylor 	 * Extract the Hermon softstate pointer from "Hermon devmap tracking
10059e39c5baSBill Taylor 	 * structure" (in "pvtp").
10069e39c5baSBill Taylor 	 */
10079e39c5baSBill Taylor 	dvm_track = (hermon_devmap_track_t *)pvtp;
10089e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
10099e39c5baSBill Taylor 	state = dvm_track->hdt_state;
10109e39c5baSBill Taylor 
10119e39c5baSBill Taylor 	/*
10129e39c5baSBill Taylor 	 * Since this devmap_dup() entry point is generally called
10139e39c5baSBill Taylor 	 * when a process does fork(2), it is incumbent upon the driver
10149e39c5baSBill Taylor 	 * to insure that the child does not inherit a valid copy of
10159e39c5baSBill Taylor 	 * the parent's QP or CQ resource.  This is accomplished by using
10169e39c5baSBill Taylor 	 * devmap_devmem_remap() to invalidate the child's mapping to the
10179e39c5baSBill Taylor 	 * kernel memory.
10189e39c5baSBill Taylor 	 */
10199e39c5baSBill Taylor 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
10209e39c5baSBill Taylor 	status = devmap_devmem_remap(new_dhp, state->hs_dip, 0, 0,
1021