xref: /onnv-gate/usr/src/uts/common/io/ib/adapters/hermon/hermon_umap.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_umap.c
289517SBill.Taylor@Sun.COM  *    Hermon Userland Mapping Routines
299517SBill.Taylor@Sun.COM  *
309517SBill.Taylor@Sun.COM  *    Implements all the routines necessary for enabling direct userland
319517SBill.Taylor@Sun.COM  *    access to the Hermon hardware.  This includes all routines necessary for
329517SBill.Taylor@Sun.COM  *    maintaining the "userland resources database" and all the support routines
339517SBill.Taylor@Sun.COM  *    for the devmap calls.
349517SBill.Taylor@Sun.COM  */
359517SBill.Taylor@Sun.COM 
369517SBill.Taylor@Sun.COM #include <sys/types.h>
379517SBill.Taylor@Sun.COM #include <sys/conf.h>
389517SBill.Taylor@Sun.COM #include <sys/ddi.h>
399517SBill.Taylor@Sun.COM #include <sys/sunddi.h>
409517SBill.Taylor@Sun.COM #include <sys/modctl.h>
419517SBill.Taylor@Sun.COM #include <sys/file.h>
429517SBill.Taylor@Sun.COM #include <sys/avl.h>
439517SBill.Taylor@Sun.COM #include <sys/sysmacros.h>
449517SBill.Taylor@Sun.COM 
459517SBill.Taylor@Sun.COM #include <sys/ib/adapters/hermon/hermon.h>
469517SBill.Taylor@Sun.COM 
479517SBill.Taylor@Sun.COM /* Hermon HCA state pointer (extern) */
489517SBill.Taylor@Sun.COM extern void *hermon_statep;
499517SBill.Taylor@Sun.COM 
509517SBill.Taylor@Sun.COM /* Hermon HCA Userland Resource Database (extern) */
519517SBill.Taylor@Sun.COM extern hermon_umap_db_t hermon_userland_rsrc_db;
529517SBill.Taylor@Sun.COM 
539517SBill.Taylor@Sun.COM static int hermon_umap_uarpg(hermon_state_t *state, devmap_cookie_t dhp,
549517SBill.Taylor@Sun.COM     hermon_rsrc_t *rsrcp, uint64_t offset, size_t *maplen, int *err);
559517SBill.Taylor@Sun.COM static int hermon_umap_cqmem(hermon_state_t *state, devmap_cookie_t dhp,
569517SBill.Taylor@Sun.COM     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
579517SBill.Taylor@Sun.COM static int hermon_umap_qpmem(hermon_state_t *state, devmap_cookie_t dhp,
589517SBill.Taylor@Sun.COM     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
599517SBill.Taylor@Sun.COM static int hermon_umap_srqmem(hermon_state_t *state, devmap_cookie_t dhp,
609517SBill.Taylor@Sun.COM     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
619517SBill.Taylor@Sun.COM static int hermon_umap_dbrecmem(hermon_state_t *state, devmap_cookie_t dhp,
629517SBill.Taylor@Sun.COM     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
639517SBill.Taylor@Sun.COM static int hermon_devmap_umem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
649517SBill.Taylor@Sun.COM     offset_t off, size_t len, void **pvtp);
659517SBill.Taylor@Sun.COM static int hermon_devmap_umem_dup(devmap_cookie_t dhp, void *pvtp,
669517SBill.Taylor@Sun.COM     devmap_cookie_t new_dhp, void **new_pvtp);
679517SBill.Taylor@Sun.COM static void hermon_devmap_umem_unmap(devmap_cookie_t dhp, void *pvtp,
689517SBill.Taylor@Sun.COM     offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
699517SBill.Taylor@Sun.COM     devmap_cookie_t new_dhp2, void **pvtp2);
709517SBill.Taylor@Sun.COM static int hermon_devmap_dbrecmem_map(devmap_cookie_t dhp, dev_t dev,
719517SBill.Taylor@Sun.COM     uint_t flags, offset_t off, size_t len, void **pvtp);
729517SBill.Taylor@Sun.COM static int hermon_devmap_dbrecmem_dup(devmap_cookie_t dhp, void *pvtp,
739517SBill.Taylor@Sun.COM     devmap_cookie_t new_dhp, void **new_pvtp);
749517SBill.Taylor@Sun.COM static void hermon_devmap_dbrecmem_unmap(devmap_cookie_t dhp, void *pvtp,
759517SBill.Taylor@Sun.COM     offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
769517SBill.Taylor@Sun.COM     devmap_cookie_t new_dhp2, void **pvtp2);
779517SBill.Taylor@Sun.COM static int hermon_devmap_devmem_map(devmap_cookie_t dhp, dev_t dev,
789517SBill.Taylor@Sun.COM     uint_t flags, offset_t off, size_t len, void **pvtp);
799517SBill.Taylor@Sun.COM static int hermon_devmap_devmem_dup(devmap_cookie_t dhp, void *pvtp,
809517SBill.Taylor@Sun.COM     devmap_cookie_t new_dhp, void **new_pvtp);
819517SBill.Taylor@Sun.COM static void hermon_devmap_devmem_unmap(devmap_cookie_t dhp, void *pvtp,
829517SBill.Taylor@Sun.COM     offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
839517SBill.Taylor@Sun.COM     devmap_cookie_t new_dhp2, void **pvtp2);
849517SBill.Taylor@Sun.COM static ibt_status_t hermon_umap_mr_data_in(hermon_mrhdl_t mr,
859517SBill.Taylor@Sun.COM     ibt_mr_data_in_t *data, size_t data_sz);
869517SBill.Taylor@Sun.COM static ibt_status_t hermon_umap_cq_data_out(hermon_cqhdl_t cq,
879517SBill.Taylor@Sun.COM     mlnx_umap_cq_data_out_t *data, size_t data_sz);
889517SBill.Taylor@Sun.COM static ibt_status_t hermon_umap_qp_data_out(hermon_qphdl_t qp,
899517SBill.Taylor@Sun.COM     mlnx_umap_qp_data_out_t *data, size_t data_sz);
909517SBill.Taylor@Sun.COM static ibt_status_t hermon_umap_srq_data_out(hermon_srqhdl_t srq,
919517SBill.Taylor@Sun.COM     mlnx_umap_srq_data_out_t *data, size_t data_sz);
929517SBill.Taylor@Sun.COM static ibt_status_t hermon_umap_pd_data_out(hermon_pdhdl_t pd,
939517SBill.Taylor@Sun.COM     mlnx_umap_pd_data_out_t *data, size_t data_sz);
949517SBill.Taylor@Sun.COM static int hermon_umap_db_compare(const void *query, const void *entry);
959517SBill.Taylor@Sun.COM 
969517SBill.Taylor@Sun.COM 
979517SBill.Taylor@Sun.COM /*
989517SBill.Taylor@Sun.COM  * These callbacks are passed to devmap_umem_setup() and devmap_devmem_setup(),
999517SBill.Taylor@Sun.COM  * respectively.  They are used to handle (among other things) partial
1009517SBill.Taylor@Sun.COM  * unmappings and to provide a method for invalidating mappings inherited
1019517SBill.Taylor@Sun.COM  * as a result of a fork(2) system call.
1029517SBill.Taylor@Sun.COM  */
1039517SBill.Taylor@Sun.COM static struct devmap_callback_ctl hermon_devmap_umem_cbops = {
1049517SBill.Taylor@Sun.COM 	DEVMAP_OPS_REV,
1059517SBill.Taylor@Sun.COM 	hermon_devmap_umem_map,
1069517SBill.Taylor@Sun.COM 	NULL,
1079517SBill.Taylor@Sun.COM 	hermon_devmap_umem_dup,
1089517SBill.Taylor@Sun.COM 	hermon_devmap_umem_unmap
1099517SBill.Taylor@Sun.COM };
1109517SBill.Taylor@Sun.COM static struct devmap_callback_ctl hermon_devmap_devmem_cbops = {
1119517SBill.Taylor@Sun.COM 	DEVMAP_OPS_REV,
1129517SBill.Taylor@Sun.COM 	hermon_devmap_devmem_map,
1139517SBill.Taylor@Sun.COM 	NULL,
1149517SBill.Taylor@Sun.COM 	hermon_devmap_devmem_dup,
1159517SBill.Taylor@Sun.COM 	hermon_devmap_devmem_unmap
1169517SBill.Taylor@Sun.COM };
1179517SBill.Taylor@Sun.COM static struct devmap_callback_ctl hermon_devmap_dbrecmem_cbops = {
1189517SBill.Taylor@Sun.COM 	DEVMAP_OPS_REV,
1199517SBill.Taylor@Sun.COM 	hermon_devmap_dbrecmem_map,
1209517SBill.Taylor@Sun.COM 	NULL,
1219517SBill.Taylor@Sun.COM 	hermon_devmap_dbrecmem_dup,
1229517SBill.Taylor@Sun.COM 	hermon_devmap_dbrecmem_unmap
1239517SBill.Taylor@Sun.COM };
1249517SBill.Taylor@Sun.COM 
1259517SBill.Taylor@Sun.COM /*
1269517SBill.Taylor@Sun.COM  * hermon_devmap()
1279517SBill.Taylor@Sun.COM  *    Context: Can be called from user context.
1289517SBill.Taylor@Sun.COM  */
1299517SBill.Taylor@Sun.COM /* ARGSUSED */
1309517SBill.Taylor@Sun.COM int
hermon_devmap(dev_t dev,devmap_cookie_t dhp,offset_t off,size_t len,size_t * maplen,uint_t model)1319517SBill.Taylor@Sun.COM hermon_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
1329517SBill.Taylor@Sun.COM     size_t *maplen, uint_t model)
1339517SBill.Taylor@Sun.COM {
1349517SBill.Taylor@Sun.COM 	hermon_state_t	*state;
1359517SBill.Taylor@Sun.COM 	hermon_rsrc_t 	*rsrcp;
1369517SBill.Taylor@Sun.COM 	minor_t		instance;
1379517SBill.Taylor@Sun.COM 	uint64_t	key, value;
1389517SBill.Taylor@Sun.COM 	uint64_t	bf_offset = 0;
1399517SBill.Taylor@Sun.COM 	uint_t		type;
1409517SBill.Taylor@Sun.COM 	int		err, status;
1419517SBill.Taylor@Sun.COM 
1429517SBill.Taylor@Sun.COM 	/* Get Hermon softstate structure from instance */
1439517SBill.Taylor@Sun.COM 	instance = HERMON_DEV_INSTANCE(dev);
1449517SBill.Taylor@Sun.COM 	state = ddi_get_soft_state(hermon_statep, instance);
1459517SBill.Taylor@Sun.COM 	if (state == NULL) {
1469517SBill.Taylor@Sun.COM 		return (ENXIO);
1479517SBill.Taylor@Sun.COM 	}
1489517SBill.Taylor@Sun.COM 
1499517SBill.Taylor@Sun.COM 	/*
1509517SBill.Taylor@Sun.COM 	 * Access to Hermon devmap interface is not allowed in
1519517SBill.Taylor@Sun.COM 	 * "maintenance mode".
1529517SBill.Taylor@Sun.COM 	 */
1539517SBill.Taylor@Sun.COM 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
1549517SBill.Taylor@Sun.COM 		return (EFAULT);
1559517SBill.Taylor@Sun.COM 	}
1569517SBill.Taylor@Sun.COM 
1579517SBill.Taylor@Sun.COM 	/*
1589517SBill.Taylor@Sun.COM 	 * The bottom bits of "offset" are undefined (number depends on
1599517SBill.Taylor@Sun.COM 	 * system PAGESIZE).  Shifting these off leaves us with a "key".
1609517SBill.Taylor@Sun.COM 	 * The "key" is actually a combination of both a real key value
1619517SBill.Taylor@Sun.COM 	 * (for the purpose of database lookup) and a "type" value.  We
1629517SBill.Taylor@Sun.COM 	 * extract this information before doing the database lookup.
1639517SBill.Taylor@Sun.COM 	 */
1649517SBill.Taylor@Sun.COM 	key  = off >> PAGESHIFT;
1659517SBill.Taylor@Sun.COM 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
1669517SBill.Taylor@Sun.COM 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
1679517SBill.Taylor@Sun.COM 	if (type == MLNX_UMAP_BLUEFLAMEPG_RSRC) {
1689517SBill.Taylor@Sun.COM 		if (state->hs_devlim.blu_flm == 0) {
1699517SBill.Taylor@Sun.COM 			return (EFAULT);
1709517SBill.Taylor@Sun.COM 		}
1719517SBill.Taylor@Sun.COM 		bf_offset = state->hs_bf_offset;
1729517SBill.Taylor@Sun.COM 		type = MLNX_UMAP_UARPG_RSRC;
1739517SBill.Taylor@Sun.COM 	}
1749517SBill.Taylor@Sun.COM 	status = hermon_umap_db_find(instance, key, type, &value, 0, NULL);
1759517SBill.Taylor@Sun.COM 	if (status == DDI_SUCCESS) {
1769517SBill.Taylor@Sun.COM 		rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
1779517SBill.Taylor@Sun.COM 
1789517SBill.Taylor@Sun.COM 		switch (type) {
1799517SBill.Taylor@Sun.COM 		case MLNX_UMAP_UARPG_RSRC:
1809517SBill.Taylor@Sun.COM 			/*
1819517SBill.Taylor@Sun.COM 			 * Double check that process who open()'d Hermon is
1829517SBill.Taylor@Sun.COM 			 * same process attempting to mmap() UAR page.
1839517SBill.Taylor@Sun.COM 			 */
1849517SBill.Taylor@Sun.COM 			if (key != ddi_get_pid()) {
1859517SBill.Taylor@Sun.COM 				return (EINVAL);
1869517SBill.Taylor@Sun.COM 			}
1879517SBill.Taylor@Sun.COM 
1889517SBill.Taylor@Sun.COM 			/* Map the UAR page out for userland access */
1899517SBill.Taylor@Sun.COM 			status = hermon_umap_uarpg(state, dhp, rsrcp, bf_offset,
1909517SBill.Taylor@Sun.COM 			    maplen, &err);
1919517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
1929517SBill.Taylor@Sun.COM 				return (err);
1939517SBill.Taylor@Sun.COM 			}
1949517SBill.Taylor@Sun.COM 			break;
1959517SBill.Taylor@Sun.COM 
1969517SBill.Taylor@Sun.COM 		case MLNX_UMAP_CQMEM_RSRC:
1979517SBill.Taylor@Sun.COM 			/* Map the CQ memory out for userland access */
1989517SBill.Taylor@Sun.COM 			status = hermon_umap_cqmem(state, dhp, rsrcp, off,
1999517SBill.Taylor@Sun.COM 			    maplen, &err);
2009517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
2019517SBill.Taylor@Sun.COM 				return (err);
2029517SBill.Taylor@Sun.COM 			}
2039517SBill.Taylor@Sun.COM 			break;
2049517SBill.Taylor@Sun.COM 
2059517SBill.Taylor@Sun.COM 		case MLNX_UMAP_QPMEM_RSRC:
2069517SBill.Taylor@Sun.COM 			/* Map the QP memory out for userland access */
2079517SBill.Taylor@Sun.COM 			status = hermon_umap_qpmem(state, dhp, rsrcp, off,
2089517SBill.Taylor@Sun.COM 			    maplen, &err);
2099517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
2109517SBill.Taylor@Sun.COM 				return (err);
2119517SBill.Taylor@Sun.COM 			}
2129517SBill.Taylor@Sun.COM 			break;
2139517SBill.Taylor@Sun.COM 
2149517SBill.Taylor@Sun.COM 		case MLNX_UMAP_SRQMEM_RSRC:
2159517SBill.Taylor@Sun.COM 			/* Map the SRQ memory out for userland access */
2169517SBill.Taylor@Sun.COM 			status = hermon_umap_srqmem(state, dhp, rsrcp, off,
2179517SBill.Taylor@Sun.COM 			    maplen, &err);
2189517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
2199517SBill.Taylor@Sun.COM 				return (err);
2209517SBill.Taylor@Sun.COM 			}
2219517SBill.Taylor@Sun.COM 			break;
2229517SBill.Taylor@Sun.COM 
2239517SBill.Taylor@Sun.COM 		case MLNX_UMAP_DBRMEM_RSRC:
2249517SBill.Taylor@Sun.COM 			/*
2259517SBill.Taylor@Sun.COM 			 * Map the doorbell record memory out for
2269517SBill.Taylor@Sun.COM 			 * userland access
2279517SBill.Taylor@Sun.COM 			 */
2289517SBill.Taylor@Sun.COM 			status = hermon_umap_dbrecmem(state, dhp, rsrcp, off,
2299517SBill.Taylor@Sun.COM 			    maplen, &err);
2309517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
2319517SBill.Taylor@Sun.COM 				return (err);
2329517SBill.Taylor@Sun.COM 			}
2339517SBill.Taylor@Sun.COM 			break;
2349517SBill.Taylor@Sun.COM 
2359517SBill.Taylor@Sun.COM 		default:
2369517SBill.Taylor@Sun.COM 			HERMON_WARNING(state, "unexpected rsrc type in devmap");
2379517SBill.Taylor@Sun.COM 			return (EINVAL);
2389517SBill.Taylor@Sun.COM 		}
2399517SBill.Taylor@Sun.COM 	} else {
2409517SBill.Taylor@Sun.COM 		return (EINVAL);
2419517SBill.Taylor@Sun.COM 	}
2429517SBill.Taylor@Sun.COM 
2439517SBill.Taylor@Sun.COM 	return (0);
2449517SBill.Taylor@Sun.COM }
2459517SBill.Taylor@Sun.COM 
2469517SBill.Taylor@Sun.COM 
2479517SBill.Taylor@Sun.COM /*
2489517SBill.Taylor@Sun.COM  * hermon_umap_uarpg()
2499517SBill.Taylor@Sun.COM  *    Context: Can be called from user context.
2509517SBill.Taylor@Sun.COM  */
2519517SBill.Taylor@Sun.COM 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)2529517SBill.Taylor@Sun.COM hermon_umap_uarpg(hermon_state_t *state, devmap_cookie_t dhp,
2539517SBill.Taylor@Sun.COM     hermon_rsrc_t *rsrcp, uint64_t offset, size_t *maplen, int *err)
2549517SBill.Taylor@Sun.COM {
2559517SBill.Taylor@Sun.COM 	int			status;
2569517SBill.Taylor@Sun.COM 	uint_t			maxprot;
2579517SBill.Taylor@Sun.COM 	ddi_device_acc_attr_t	*accattrp = &state->hs_reg_accattr;
2589517SBill.Taylor@Sun.COM 	ddi_device_acc_attr_t	accattr;
2599517SBill.Taylor@Sun.COM 
2609517SBill.Taylor@Sun.COM 	if (offset != 0) {	/* Hermon Blueflame */
2619517SBill.Taylor@Sun.COM 		/* Try to use write coalescing data ordering */
2629517SBill.Taylor@Sun.COM 		accattr = *accattrp;
2639517SBill.Taylor@Sun.COM 		accattr.devacc_attr_dataorder = DDI_STORECACHING_OK_ACC;
2649517SBill.Taylor@Sun.COM 		accattrp = &accattr;
2659517SBill.Taylor@Sun.COM 	}
2669517SBill.Taylor@Sun.COM 
2679517SBill.Taylor@Sun.COM 	/* Map out the UAR page (doorbell page) */
2689517SBill.Taylor@Sun.COM 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
2699517SBill.Taylor@Sun.COM 	status = devmap_devmem_setup(dhp, state->hs_dip,
2709517SBill.Taylor@Sun.COM 	    &hermon_devmap_devmem_cbops, HERMON_UAR_BAR, (rsrcp->hr_indx <<
2719517SBill.Taylor@Sun.COM 	    PAGESHIFT) + offset, PAGESIZE, maxprot, DEVMAP_ALLOW_REMAP,
2729517SBill.Taylor@Sun.COM 	    accattrp);
2739517SBill.Taylor@Sun.COM 	if (status < 0) {
2749517SBill.Taylor@Sun.COM 		*err = status;
2759517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
2769517SBill.Taylor@Sun.COM 	}
2779517SBill.Taylor@Sun.COM 
2789517SBill.Taylor@Sun.COM 	*maplen = PAGESIZE;
2799517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
2809517SBill.Taylor@Sun.COM }
2819517SBill.Taylor@Sun.COM 
2829517SBill.Taylor@Sun.COM 
2839517SBill.Taylor@Sun.COM /*
2849517SBill.Taylor@Sun.COM  * hermon_umap_cqmem()
2859517SBill.Taylor@Sun.COM  *    Context: Can be called from user context.
2869517SBill.Taylor@Sun.COM  */
2879517SBill.Taylor@Sun.COM /* ARGSUSED */
2889517SBill.Taylor@Sun.COM 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)2899517SBill.Taylor@Sun.COM hermon_umap_cqmem(hermon_state_t *state, devmap_cookie_t dhp,
2909517SBill.Taylor@Sun.COM     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
2919517SBill.Taylor@Sun.COM {
2929517SBill.Taylor@Sun.COM 	hermon_cqhdl_t	cq;
2939517SBill.Taylor@Sun.COM 	size_t		size;
2949517SBill.Taylor@Sun.COM 	uint_t		maxprot;
2959517SBill.Taylor@Sun.COM 	int		status;
2969517SBill.Taylor@Sun.COM 
2979517SBill.Taylor@Sun.COM 	/* Extract the Hermon CQ handle pointer from the hermon_rsrc_t */
2989517SBill.Taylor@Sun.COM 	cq = (hermon_cqhdl_t)rsrcp->hr_addr;
2999517SBill.Taylor@Sun.COM 
3009517SBill.Taylor@Sun.COM 	/* Round-up the CQ size to system page size */
3019517SBill.Taylor@Sun.COM 	size = ptob(btopr(cq->cq_resize_hdl ?
3029517SBill.Taylor@Sun.COM 	    cq->cq_resize_hdl->cq_cqinfo.qa_size : cq->cq_cqinfo.qa_size));
3039517SBill.Taylor@Sun.COM 
3049517SBill.Taylor@Sun.COM 	/* Map out the CQ memory - use resize_hdl if non-NULL */
3059517SBill.Taylor@Sun.COM 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
3069517SBill.Taylor@Sun.COM 	status = devmap_umem_setup(dhp, state->hs_dip,
3079517SBill.Taylor@Sun.COM 	    &hermon_devmap_umem_cbops, cq->cq_resize_hdl ?
3089517SBill.Taylor@Sun.COM 	    cq->cq_resize_hdl->cq_cqinfo.qa_umemcookie :
3099517SBill.Taylor@Sun.COM 	    cq->cq_cqinfo.qa_umemcookie, 0, size,
3109517SBill.Taylor@Sun.COM 	    maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
3119517SBill.Taylor@Sun.COM 	if (status < 0) {
3129517SBill.Taylor@Sun.COM 		*err = status;
3139517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
3149517SBill.Taylor@Sun.COM 	}
3159517SBill.Taylor@Sun.COM 	*maplen = size;
3169517SBill.Taylor@Sun.COM 
3179517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
3189517SBill.Taylor@Sun.COM }
3199517SBill.Taylor@Sun.COM 
3209517SBill.Taylor@Sun.COM 
3219517SBill.Taylor@Sun.COM /*
3229517SBill.Taylor@Sun.COM  * hermon_umap_qpmem()
3239517SBill.Taylor@Sun.COM  *    Context: Can be called from user context.
3249517SBill.Taylor@Sun.COM  */
3259517SBill.Taylor@Sun.COM /* ARGSUSED */
3269517SBill.Taylor@Sun.COM 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)3279517SBill.Taylor@Sun.COM hermon_umap_qpmem(hermon_state_t *state, devmap_cookie_t dhp,
3289517SBill.Taylor@Sun.COM     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
3299517SBill.Taylor@Sun.COM {
3309517SBill.Taylor@Sun.COM 	hermon_qphdl_t	qp;
3319517SBill.Taylor@Sun.COM 	offset_t	offset;
3329517SBill.Taylor@Sun.COM 	size_t		size;
3339517SBill.Taylor@Sun.COM 	uint_t		maxprot;
3349517SBill.Taylor@Sun.COM 	int		status;
3359517SBill.Taylor@Sun.COM 
3369517SBill.Taylor@Sun.COM 	/* Extract the Hermon QP handle pointer from the hermon_rsrc_t */
3379517SBill.Taylor@Sun.COM 	qp = (hermon_qphdl_t)rsrcp->hr_addr;
3389517SBill.Taylor@Sun.COM 
3399517SBill.Taylor@Sun.COM 	/*
3409517SBill.Taylor@Sun.COM 	 * Calculate the offset of the first work queue (send or recv) into
3419517SBill.Taylor@Sun.COM 	 * the memory (ddi_umem_alloc()) allocated previously for the QP.
3429517SBill.Taylor@Sun.COM 	 */
3439517SBill.Taylor@Sun.COM 	offset = (offset_t)((uintptr_t)qp->qp_wqinfo.qa_buf_aligned -
3449517SBill.Taylor@Sun.COM 	    (uintptr_t)qp->qp_wqinfo.qa_buf_real);
3459517SBill.Taylor@Sun.COM 
3469517SBill.Taylor@Sun.COM 	/* Round-up the QP work queue sizes to system page size */
3479517SBill.Taylor@Sun.COM 	size = ptob(btopr(qp->qp_wqinfo.qa_size));
3489517SBill.Taylor@Sun.COM 
3499517SBill.Taylor@Sun.COM 	/* Map out the QP memory */
3509517SBill.Taylor@Sun.COM 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
3519517SBill.Taylor@Sun.COM 	status = devmap_umem_setup(dhp, state->hs_dip,
3529517SBill.Taylor@Sun.COM 	    &hermon_devmap_umem_cbops, qp->qp_wqinfo.qa_umemcookie, offset,
3539517SBill.Taylor@Sun.COM 	    size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
3549517SBill.Taylor@Sun.COM 	if (status < 0) {
3559517SBill.Taylor@Sun.COM 		*err = status;
3569517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
3579517SBill.Taylor@Sun.COM 	}
3589517SBill.Taylor@Sun.COM 	*maplen = size;
3599517SBill.Taylor@Sun.COM 
3609517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
3619517SBill.Taylor@Sun.COM }
3629517SBill.Taylor@Sun.COM 
3639517SBill.Taylor@Sun.COM 
3649517SBill.Taylor@Sun.COM /*
3659517SBill.Taylor@Sun.COM  * hermon_umap_srqmem()
3669517SBill.Taylor@Sun.COM  *    Context: Can be called from user context.
3679517SBill.Taylor@Sun.COM  */
3689517SBill.Taylor@Sun.COM /* ARGSUSED */
3699517SBill.Taylor@Sun.COM 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)3709517SBill.Taylor@Sun.COM hermon_umap_srqmem(hermon_state_t *state, devmap_cookie_t dhp,
3719517SBill.Taylor@Sun.COM     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
3729517SBill.Taylor@Sun.COM {
3739517SBill.Taylor@Sun.COM 	hermon_srqhdl_t	srq;
3749517SBill.Taylor@Sun.COM 	offset_t	offset;
3759517SBill.Taylor@Sun.COM 	size_t		size;
3769517SBill.Taylor@Sun.COM 	uint_t		maxprot;
3779517SBill.Taylor@Sun.COM 	int		status;
3789517SBill.Taylor@Sun.COM 
3799517SBill.Taylor@Sun.COM 	/* Extract the Hermon SRQ handle pointer from the hermon_rsrc_t */
3809517SBill.Taylor@Sun.COM 	srq = (hermon_srqhdl_t)rsrcp->hr_addr;
3819517SBill.Taylor@Sun.COM 
3829517SBill.Taylor@Sun.COM 	/*
3839517SBill.Taylor@Sun.COM 	 * Calculate the offset of the first shared recv queue into the memory
3849517SBill.Taylor@Sun.COM 	 * (ddi_umem_alloc()) allocated previously for the SRQ.
3859517SBill.Taylor@Sun.COM 	 */
3869517SBill.Taylor@Sun.COM 	offset = (offset_t)((uintptr_t)srq->srq_wqinfo.qa_buf_aligned -
3879517SBill.Taylor@Sun.COM 	    (uintptr_t)srq->srq_wqinfo.qa_buf_real);
3889517SBill.Taylor@Sun.COM 
3899517SBill.Taylor@Sun.COM 	/* Round-up the SRQ work queue sizes to system page size */
3909517SBill.Taylor@Sun.COM 	size = ptob(btopr(srq->srq_wqinfo.qa_size));
3919517SBill.Taylor@Sun.COM 
3929517SBill.Taylor@Sun.COM 	/* Map out the SRQ memory */
3939517SBill.Taylor@Sun.COM 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
3949517SBill.Taylor@Sun.COM 	status = devmap_umem_setup(dhp, state->hs_dip,
3959517SBill.Taylor@Sun.COM 	    &hermon_devmap_umem_cbops, srq->srq_wqinfo.qa_umemcookie, offset,
3969517SBill.Taylor@Sun.COM 	    size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
3979517SBill.Taylor@Sun.COM 	if (status < 0) {
3989517SBill.Taylor@Sun.COM 		*err = status;
3999517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
4009517SBill.Taylor@Sun.COM 	}
4019517SBill.Taylor@Sun.COM 	*maplen = size;
4029517SBill.Taylor@Sun.COM 
4039517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
4049517SBill.Taylor@Sun.COM }
4059517SBill.Taylor@Sun.COM 
4069517SBill.Taylor@Sun.COM 
4079517SBill.Taylor@Sun.COM /*
4089517SBill.Taylor@Sun.COM  * hermon_devmap_dbrecmem()
4099517SBill.Taylor@Sun.COM  *    Context: Can be called from user context.
4109517SBill.Taylor@Sun.COM  */
4119517SBill.Taylor@Sun.COM /* ARGSUSED */
4129517SBill.Taylor@Sun.COM 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)4139517SBill.Taylor@Sun.COM hermon_umap_dbrecmem(hermon_state_t *state, devmap_cookie_t dhp,
4149517SBill.Taylor@Sun.COM     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
4159517SBill.Taylor@Sun.COM {
4169517SBill.Taylor@Sun.COM 	hermon_udbr_page_t *pagep;
4179517SBill.Taylor@Sun.COM 	offset_t	offset;
4189517SBill.Taylor@Sun.COM 	size_t		size;
4199517SBill.Taylor@Sun.COM 	uint_t		maxprot;
4209517SBill.Taylor@Sun.COM 	int		status;
4219517SBill.Taylor@Sun.COM 
4229517SBill.Taylor@Sun.COM 	/* We stored the udbr_page pointer, and not a hermon_rsrc_t */
4239517SBill.Taylor@Sun.COM 	pagep = (hermon_udbr_page_t *)rsrcp;
4249517SBill.Taylor@Sun.COM 
4259517SBill.Taylor@Sun.COM 	/*
4269517SBill.Taylor@Sun.COM 	 * Calculate the offset of the doorbell records into the memory
4279517SBill.Taylor@Sun.COM 	 * (ddi_umem_alloc()) allocated previously for them.
4289517SBill.Taylor@Sun.COM 	 */
4299517SBill.Taylor@Sun.COM 	offset = 0;
4309517SBill.Taylor@Sun.COM 
4319517SBill.Taylor@Sun.COM 	/* Round-up the doorbell page to system page size */
4329517SBill.Taylor@Sun.COM 	size = PAGESIZE;
4339517SBill.Taylor@Sun.COM 
4349517SBill.Taylor@Sun.COM 	/* Map out the Doorbell Record memory */
4359517SBill.Taylor@Sun.COM 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
4369517SBill.Taylor@Sun.COM 	status = devmap_umem_setup(dhp, state->hs_dip,
4379517SBill.Taylor@Sun.COM 	    &hermon_devmap_dbrecmem_cbops, pagep->upg_umemcookie, offset,
4389517SBill.Taylor@Sun.COM 	    size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
4399517SBill.Taylor@Sun.COM 	if (status < 0) {
4409517SBill.Taylor@Sun.COM 		*err = status;
4419517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
4429517SBill.Taylor@Sun.COM 	}
4439517SBill.Taylor@Sun.COM 	*maplen = size;
4449517SBill.Taylor@Sun.COM 
4459517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
4469517SBill.Taylor@Sun.COM }
4479517SBill.Taylor@Sun.COM 
4489517SBill.Taylor@Sun.COM 
4499517SBill.Taylor@Sun.COM /*
4509517SBill.Taylor@Sun.COM  * hermon_devmap_umem_map()
4519517SBill.Taylor@Sun.COM  *    Context: Can be called from kernel context.
4529517SBill.Taylor@Sun.COM  */
4539517SBill.Taylor@Sun.COM /* ARGSUSED */
4549517SBill.Taylor@Sun.COM static int
hermon_devmap_umem_map(devmap_cookie_t dhp,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)4559517SBill.Taylor@Sun.COM hermon_devmap_umem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
4569517SBill.Taylor@Sun.COM     offset_t off, size_t len, void **pvtp)
4579517SBill.Taylor@Sun.COM {
4589517SBill.Taylor@Sun.COM 	hermon_state_t		*state;
4599517SBill.Taylor@Sun.COM 	hermon_devmap_track_t	*dvm_track;
4609517SBill.Taylor@Sun.COM 	hermon_cqhdl_t		cq;
4619517SBill.Taylor@Sun.COM 	hermon_qphdl_t		qp;
4629517SBill.Taylor@Sun.COM 	hermon_srqhdl_t		srq;
4639517SBill.Taylor@Sun.COM 	minor_t			instance;
4649517SBill.Taylor@Sun.COM 	uint64_t		key;
4659517SBill.Taylor@Sun.COM 	uint_t			type;
4669517SBill.Taylor@Sun.COM 
4679517SBill.Taylor@Sun.COM 	/* Get Hermon softstate structure from instance */
4689517SBill.Taylor@Sun.COM 	instance = HERMON_DEV_INSTANCE(dev);
4699517SBill.Taylor@Sun.COM 	state = ddi_get_soft_state(hermon_statep, instance);
4709517SBill.Taylor@Sun.COM 	if (state == NULL) {
4719517SBill.Taylor@Sun.COM 		return (ENXIO);
4729517SBill.Taylor@Sun.COM 	}
4739517SBill.Taylor@Sun.COM 
4749517SBill.Taylor@Sun.COM 	/*
4759517SBill.Taylor@Sun.COM 	 * The bottom bits of "offset" are undefined (number depends on
4769517SBill.Taylor@Sun.COM 	 * system PAGESIZE).  Shifting these off leaves us with a "key".
4779517SBill.Taylor@Sun.COM 	 * The "key" is actually a combination of both a real key value
4789517SBill.Taylor@Sun.COM 	 * (for the purpose of database lookup) and a "type" value.  Although
4799517SBill.Taylor@Sun.COM 	 * we are not going to do any database lookup per se, we do want
4809517SBill.Taylor@Sun.COM 	 * to extract the "key" and the "type" (to enable faster lookup of
4819517SBill.Taylor@Sun.COM 	 * the appropriate CQ or QP handle).
4829517SBill.Taylor@Sun.COM 	 */
4839517SBill.Taylor@Sun.COM 	key  = off >> PAGESHIFT;
4849517SBill.Taylor@Sun.COM 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
4859517SBill.Taylor@Sun.COM 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
4869517SBill.Taylor@Sun.COM 
4879517SBill.Taylor@Sun.COM 	/*
4889517SBill.Taylor@Sun.COM 	 * Allocate an entry to track the mapping and unmapping (specifically,
4899517SBill.Taylor@Sun.COM 	 * partial unmapping) of this resource.
4909517SBill.Taylor@Sun.COM 	 */
4919517SBill.Taylor@Sun.COM 	dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
4929517SBill.Taylor@Sun.COM 	    sizeof (hermon_devmap_track_t), KM_SLEEP);
4939517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
4949517SBill.Taylor@Sun.COM 	dvm_track->hdt_offset = off;
4959517SBill.Taylor@Sun.COM 	dvm_track->hdt_state  = state;
4969517SBill.Taylor@Sun.COM 	dvm_track->hdt_refcnt = 1;
4979517SBill.Taylor@Sun.COM 	mutex_init(&dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
4989517SBill.Taylor@Sun.COM 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
4999517SBill.Taylor@Sun.COM 
5009517SBill.Taylor@Sun.COM 	/*
5019517SBill.Taylor@Sun.COM 	 * Depending of the type of resource that has been mapped out, we
5029517SBill.Taylor@Sun.COM 	 * need to update the QP or CQ handle to reflect that it has, in
5039517SBill.Taylor@Sun.COM 	 * fact, been mapped.  This allows the driver code which frees a QP
5049517SBill.Taylor@Sun.COM 	 * or a CQ to know whether it is appropriate to do a
5059517SBill.Taylor@Sun.COM 	 * devmap_devmem_remap() to invalidate the userland mapping for the
5069517SBill.Taylor@Sun.COM 	 * corresponding queue's memory.
5079517SBill.Taylor@Sun.COM 	 */
5089517SBill.Taylor@Sun.COM 	if (type == MLNX_UMAP_CQMEM_RSRC) {
5099517SBill.Taylor@Sun.COM 
5109517SBill.Taylor@Sun.COM 		/* Use "key" (CQ number) to do fast lookup of CQ handle */
5119517SBill.Taylor@Sun.COM 		cq = hermon_cqhdl_from_cqnum(state, key);
5129517SBill.Taylor@Sun.COM 
5139517SBill.Taylor@Sun.COM 		/*
5149517SBill.Taylor@Sun.COM 		 * Update the handle to the userland mapping.  Note:  If
5159517SBill.Taylor@Sun.COM 		 * the CQ already has a valid userland mapping, then stop
5169517SBill.Taylor@Sun.COM 		 * and return failure.
5179517SBill.Taylor@Sun.COM 		 */
5189517SBill.Taylor@Sun.COM 		mutex_enter(&cq->cq_lock);
5199517SBill.Taylor@Sun.COM 		if (cq->cq_umap_dhp == NULL) {
5209517SBill.Taylor@Sun.COM 			cq->cq_umap_dhp = dhp;
5219517SBill.Taylor@Sun.COM 			dvm_track->hdt_size = cq->cq_cqinfo.qa_size;
5229517SBill.Taylor@Sun.COM 			mutex_exit(&cq->cq_lock);
5239517SBill.Taylor@Sun.COM 		} else if (cq->cq_resize_hdl &&
5249517SBill.Taylor@Sun.COM 		    (cq->cq_resize_hdl->cq_umap_dhp == NULL)) {
5259517SBill.Taylor@Sun.COM 			cq->cq_resize_hdl->cq_umap_dhp = dhp;
5269517SBill.Taylor@Sun.COM 			dvm_track->hdt_size =
5279517SBill.Taylor@Sun.COM 			    cq->cq_resize_hdl->cq_cqinfo.qa_size;
5289517SBill.Taylor@Sun.COM 			mutex_exit(&cq->cq_lock);
5299517SBill.Taylor@Sun.COM 		} else {
5309517SBill.Taylor@Sun.COM 			mutex_exit(&cq->cq_lock);
5319517SBill.Taylor@Sun.COM 			goto umem_map_fail;
5329517SBill.Taylor@Sun.COM 		}
5339517SBill.Taylor@Sun.COM 
5349517SBill.Taylor@Sun.COM 	} else if (type == MLNX_UMAP_QPMEM_RSRC) {
5359517SBill.Taylor@Sun.COM 
5369517SBill.Taylor@Sun.COM 		/* Use "key" (QP number) to do fast lookup of QP handle */
5379517SBill.Taylor@Sun.COM 		qp = hermon_qphdl_from_qpnum(state, key);
5389517SBill.Taylor@Sun.COM 
5399517SBill.Taylor@Sun.COM 		/*
5409517SBill.Taylor@Sun.COM 		 * Update the handle to the userland mapping.  Note:  If
5419517SBill.Taylor@Sun.COM 		 * the CQ already has a valid userland mapping, then stop
5429517SBill.Taylor@Sun.COM 		 * and return failure.
5439517SBill.Taylor@Sun.COM 		 */
5449517SBill.Taylor@Sun.COM 		mutex_enter(&qp->qp_lock);
5459517SBill.Taylor@Sun.COM 		if (qp->qp_umap_dhp == NULL) {
5469517SBill.Taylor@Sun.COM 			qp->qp_umap_dhp = dhp;
5479517SBill.Taylor@Sun.COM 			dvm_track->hdt_size = qp->qp_wqinfo.qa_size;
5489517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
5499517SBill.Taylor@Sun.COM 		} else {
5509517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
5519517SBill.Taylor@Sun.COM 			goto umem_map_fail;
5529517SBill.Taylor@Sun.COM 		}
5539517SBill.Taylor@Sun.COM 
5549517SBill.Taylor@Sun.COM 	} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
5559517SBill.Taylor@Sun.COM 
5569517SBill.Taylor@Sun.COM 		/* Use "key" (SRQ number) to do fast lookup on SRQ handle */
5579517SBill.Taylor@Sun.COM 		srq = hermon_srqhdl_from_srqnum(state, key);
5589517SBill.Taylor@Sun.COM 
5599517SBill.Taylor@Sun.COM 		/*
5609517SBill.Taylor@Sun.COM 		 * Update the handle to the userland mapping.  Note:  If the
5619517SBill.Taylor@Sun.COM 		 * SRQ already has a valid userland mapping, then stop and
5629517SBill.Taylor@Sun.COM 		 * return failure.
5639517SBill.Taylor@Sun.COM 		 */
5649517SBill.Taylor@Sun.COM 		mutex_enter(&srq->srq_lock);
5659517SBill.Taylor@Sun.COM 		if (srq->srq_umap_dhp == NULL) {
5669517SBill.Taylor@Sun.COM 			srq->srq_umap_dhp = dhp;
5679517SBill.Taylor@Sun.COM 			dvm_track->hdt_size = srq->srq_wqinfo.qa_size;
5689517SBill.Taylor@Sun.COM 			mutex_exit(&srq->srq_lock);
5699517SBill.Taylor@Sun.COM 		} else {
5709517SBill.Taylor@Sun.COM 			mutex_exit(&srq->srq_lock);
5719517SBill.Taylor@Sun.COM 			goto umem_map_fail;
5729517SBill.Taylor@Sun.COM 		}
5739517SBill.Taylor@Sun.COM 	}
5749517SBill.Taylor@Sun.COM 
5759517SBill.Taylor@Sun.COM 	/*
5769517SBill.Taylor@Sun.COM 	 * Pass the private "Hermon devmap tracking structure" back.  This
5779517SBill.Taylor@Sun.COM 	 * pointer will be returned in subsequent "unmap" callbacks.
5789517SBill.Taylor@Sun.COM 	 */
5799517SBill.Taylor@Sun.COM 	*pvtp = dvm_track;
5809517SBill.Taylor@Sun.COM 
5819517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
5829517SBill.Taylor@Sun.COM 
5839517SBill.Taylor@Sun.COM umem_map_fail:
5849517SBill.Taylor@Sun.COM 	mutex_destroy(&dvm_track->hdt_lock);
5859517SBill.Taylor@Sun.COM 	kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
5869517SBill.Taylor@Sun.COM 	return (DDI_FAILURE);
5879517SBill.Taylor@Sun.COM }
5889517SBill.Taylor@Sun.COM 
5899517SBill.Taylor@Sun.COM 
5909517SBill.Taylor@Sun.COM /*
5919517SBill.Taylor@Sun.COM  * hermon_devmap_umem_dup()
5929517SBill.Taylor@Sun.COM  *    Context: Can be called from kernel context.
5939517SBill.Taylor@Sun.COM  */
5949517SBill.Taylor@Sun.COM /* ARGSUSED */
5959517SBill.Taylor@Sun.COM static int
hermon_devmap_umem_dup(devmap_cookie_t dhp,void * pvtp,devmap_cookie_t new_dhp,void ** new_pvtp)5969517SBill.Taylor@Sun.COM hermon_devmap_umem_dup(devmap_cookie_t dhp, void *pvtp, devmap_cookie_t new_dhp,
5979517SBill.Taylor@Sun.COM     void **new_pvtp)
5989517SBill.Taylor@Sun.COM {
5999517SBill.Taylor@Sun.COM 	hermon_state_t		*state;
6009517SBill.Taylor@Sun.COM 	hermon_devmap_track_t	*dvm_track, *new_dvm_track;
6019517SBill.Taylor@Sun.COM 	uint_t			maxprot;
6029517SBill.Taylor@Sun.COM 	int			status;
6039517SBill.Taylor@Sun.COM 
6049517SBill.Taylor@Sun.COM 	/*
6059517SBill.Taylor@Sun.COM 	 * Extract the Hermon softstate pointer from "Hermon devmap tracking
6069517SBill.Taylor@Sun.COM 	 * structure" (in "pvtp").
6079517SBill.Taylor@Sun.COM 	 */
6089517SBill.Taylor@Sun.COM 	dvm_track = (hermon_devmap_track_t *)pvtp;
6099517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
6109517SBill.Taylor@Sun.COM 	state = dvm_track->hdt_state;
6119517SBill.Taylor@Sun.COM 
6129517SBill.Taylor@Sun.COM 	/*
6139517SBill.Taylor@Sun.COM 	 * Since this devmap_dup() entry point is generally called
6149517SBill.Taylor@Sun.COM 	 * when a process does fork(2), it is incumbent upon the driver
6159517SBill.Taylor@Sun.COM 	 * to insure that the child does not inherit a valid copy of
6169517SBill.Taylor@Sun.COM 	 * the parent's QP or CQ resource.  This is accomplished by using
6179517SBill.Taylor@Sun.COM 	 * devmap_devmem_remap() to invalidate the child's mapping to the
6189517SBill.Taylor@Sun.COM 	 * kernel memory.
6199517SBill.Taylor@Sun.COM 	 */
6209517SBill.Taylor@Sun.COM 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
6219517SBill.Taylor@Sun.COM 	status = devmap_devmem_remap(new_dhp, state->hs_dip, 0, 0,
6229517SBill.Taylor@Sun.COM 	    dvm_track->hdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
6239517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
6249517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "failed in hermon_devmap_umem_dup()");
6259517SBill.Taylor@Sun.COM 		return (status);
6269517SBill.Taylor@Sun.COM 	}
6279517SBill.Taylor@Sun.COM 
6289517SBill.Taylor@Sun.COM 	/*
6299517SBill.Taylor@Sun.COM 	 * Allocate a new entry to track the subsequent unmapping
6309517SBill.Taylor@Sun.COM 	 * (specifically, all partial unmappings) of the child's newly
6319517SBill.Taylor@Sun.COM 	 * invalidated resource.  Note: Setting the "hdt_size" field to
6329517SBill.Taylor@Sun.COM 	 * zero here is an indication to the devmap_unmap() entry point
6339517SBill.Taylor@Sun.COM 	 * that this mapping is invalid, and that its subsequent unmapping
6349517SBill.Taylor@Sun.COM 	 * should not affect any of the parent's CQ or QP resources.
6359517SBill.Taylor@Sun.COM 	 */
6369517SBill.Taylor@Sun.COM 	new_dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
6379517SBill.Taylor@Sun.COM 	    sizeof (hermon_devmap_track_t), KM_SLEEP);
6389517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*new_dvm_track))
6399517SBill.Taylor@Sun.COM 	new_dvm_track->hdt_offset = 0;
6409517SBill.Taylor@Sun.COM 	new_dvm_track->hdt_state  = state;
6419517SBill.Taylor@Sun.COM 	new_dvm_track->hdt_refcnt = 1;
6429517SBill.Taylor@Sun.COM 	new_dvm_track->hdt_size	  = 0;
6439517SBill.Taylor@Sun.COM 	mutex_init(&new_dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
6449517SBill.Taylor@Sun.COM 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
6459517SBill.Taylor@Sun.COM 	*new_pvtp = new_dvm_track;
6469517SBill.Taylor@Sun.COM 
6479517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
6489517SBill.Taylor@Sun.COM }
6499517SBill.Taylor@Sun.COM 
6509517SBill.Taylor@Sun.COM 
6519517SBill.Taylor@Sun.COM /*
6529517SBill.Taylor@Sun.COM  * hermon_devmap_umem_unmap()
6539517SBill.Taylor@Sun.COM  *    Context: Can be called from kernel context.
6549517SBill.Taylor@Sun.COM  */
6559517SBill.Taylor@Sun.COM /* ARGSUSED */
6569517SBill.Taylor@Sun.COM 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)6579517SBill.Taylor@Sun.COM hermon_devmap_umem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
6589517SBill.Taylor@Sun.COM     size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
6599517SBill.Taylor@Sun.COM     devmap_cookie_t new_dhp2, void **pvtp2)
6609517SBill.Taylor@Sun.COM {
6619517SBill.Taylor@Sun.COM 	hermon_state_t 		*state;
6629517SBill.Taylor@Sun.COM 	hermon_rsrc_t 		*rsrcp;
6639517SBill.Taylor@Sun.COM 	hermon_devmap_track_t	*dvm_track;
6649517SBill.Taylor@Sun.COM 	hermon_cqhdl_t		cq;
6659517SBill.Taylor@Sun.COM 	hermon_qphdl_t		qp;
6669517SBill.Taylor@Sun.COM 	hermon_srqhdl_t		srq;
6679517SBill.Taylor@Sun.COM 	uint64_t		key, value;
6689517SBill.Taylor@Sun.COM 	uint_t			type;
6699517SBill.Taylor@Sun.COM 	uint_t			size;
6709517SBill.Taylor@Sun.COM 	int			status;
6719517SBill.Taylor@Sun.COM 
6729517SBill.Taylor@Sun.COM 	/*
6739517SBill.Taylor@Sun.COM 	 * Extract the Hermon softstate pointer from "Hermon devmap tracking
6749517SBill.Taylor@Sun.COM 	 * structure" (in "pvtp").
6759517SBill.Taylor@Sun.COM 	 */
6769517SBill.Taylor@Sun.COM 	dvm_track = (hermon_devmap_track_t *)pvtp;
6779517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
6789517SBill.Taylor@Sun.COM 	state	  = dvm_track->hdt_state;
6799517SBill.Taylor@Sun.COM 
6809517SBill.Taylor@Sun.COM 	/*
6819517SBill.Taylor@Sun.COM 	 * Extract the "offset" from the "Hermon devmap tracking structure".
6829517SBill.Taylor@Sun.COM 	 * Note: The input argument "off" is ignored here because the
6839517SBill.Taylor@Sun.COM 	 * Hermon mapping interfaces define a very specific meaning to
6849517SBill.Taylor@Sun.COM 	 * each "logical offset".  Also extract the "key" and "type" encoded
6859517SBill.Taylor@Sun.COM 	 * in the logical offset.
6869517SBill.Taylor@Sun.COM 	 */
6879517SBill.Taylor@Sun.COM 	key  = dvm_track->hdt_offset >> PAGESHIFT;
6889517SBill.Taylor@Sun.COM 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
6899517SBill.Taylor@Sun.COM 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
6909517SBill.Taylor@Sun.COM 
6919517SBill.Taylor@Sun.COM 	/*
6929517SBill.Taylor@Sun.COM 	 * Extract the "size" of the mapping.  If this size is determined
6939517SBill.Taylor@Sun.COM 	 * to be zero, then it is an indication of a previously invalidated
6949517SBill.Taylor@Sun.COM 	 * mapping, and no CQ or QP resources should be affected.
6959517SBill.Taylor@Sun.COM 	 */
6969517SBill.Taylor@Sun.COM 	size = dvm_track->hdt_size;
6979517SBill.Taylor@Sun.COM 
6989517SBill.Taylor@Sun.COM 	/*
6999517SBill.Taylor@Sun.COM 	 * If only the "middle portion of a given mapping is being unmapped,
7009517SBill.Taylor@Sun.COM 	 * then we are effectively creating one new piece of mapped memory.
7019517SBill.Taylor@Sun.COM 	 * (Original region is divided into three pieces of which the middle
7029517SBill.Taylor@Sun.COM 	 * piece is being removed.  This leaves two pieces.  Since we started
7039517SBill.Taylor@Sun.COM 	 * with one piece and now have two pieces, we need to increment the
7049517SBill.Taylor@Sun.COM 	 * counter in the "Hermon devmap tracking structure".
7059517SBill.Taylor@Sun.COM 	 *
7069517SBill.Taylor@Sun.COM 	 * If, however, the whole mapped region is being unmapped, then we
7079517SBill.Taylor@Sun.COM 	 * have started with one region which we are completely removing.
7089517SBill.Taylor@Sun.COM 	 * In this case, we need to decrement the counter in the "Hermon
7099517SBill.Taylor@Sun.COM 	 * devmap tracking structure".
7109517SBill.Taylor@Sun.COM 	 *
7119517SBill.Taylor@Sun.COM 	 * In each of the remaining cases, we will have started with one
7129517SBill.Taylor@Sun.COM 	 * mapped region and ended with one (different) region.  So no counter
7139517SBill.Taylor@Sun.COM 	 * modification is necessary.
7149517SBill.Taylor@Sun.COM 	 */
7159517SBill.Taylor@Sun.COM 	mutex_enter(&dvm_track->hdt_lock);
7169517SBill.Taylor@Sun.COM 	if ((new_dhp1 == NULL) && (new_dhp2 == NULL)) {
7179517SBill.Taylor@Sun.COM 		dvm_track->hdt_refcnt--;
7189517SBill.Taylor@Sun.COM 	} else if ((new_dhp1 != NULL) && (new_dhp2 != NULL)) {
7199517SBill.Taylor@Sun.COM 		dvm_track->hdt_refcnt++;
7209517SBill.Taylor@Sun.COM 	}
7219517SBill.Taylor@Sun.COM 	mutex_exit(&dvm_track->hdt_lock);
7229517SBill.Taylor@Sun.COM 
7239517SBill.Taylor@Sun.COM 	/*
7249517SBill.Taylor@Sun.COM 	 * For each of the cases where the region is being divided, then we
7259517SBill.Taylor@Sun.COM 	 * need to pass back the "Hermon devmap tracking structure".  This way
7269517SBill.Taylor@Sun.COM 	 * we get it back when each of the remaining pieces is subsequently
7279517SBill.Taylor@Sun.COM 	 * unmapped.
7289517SBill.Taylor@Sun.COM 	 */
7299517SBill.Taylor@Sun.COM 	if (new_dhp1 != NULL) {
7309517SBill.Taylor@Sun.COM 		*pvtp1 = pvtp;
7319517SBill.Taylor@Sun.COM 	}
7329517SBill.Taylor@Sun.COM 	if (new_dhp2 != NULL) {
7339517SBill.Taylor@Sun.COM 		*pvtp2 = pvtp;
7349517SBill.Taylor@Sun.COM 	}
7359517SBill.Taylor@Sun.COM 
7369517SBill.Taylor@Sun.COM 	/*
7379517SBill.Taylor@Sun.COM 	 * If the "Hermon devmap tracking structure" is no longer being
7389517SBill.Taylor@Sun.COM 	 * referenced, then free it up.  Otherwise, return.
7399517SBill.Taylor@Sun.COM 	 */
7409517SBill.Taylor@Sun.COM 	if (dvm_track->hdt_refcnt == 0) {
7419517SBill.Taylor@Sun.COM 		mutex_destroy(&dvm_track->hdt_lock);
7429517SBill.Taylor@Sun.COM 		kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
7439517SBill.Taylor@Sun.COM 
7449517SBill.Taylor@Sun.COM 		/*
7459517SBill.Taylor@Sun.COM 		 * If the mapping was invalid (see explanation above), then
7469517SBill.Taylor@Sun.COM 		 * no further processing is necessary.
7479517SBill.Taylor@Sun.COM 		 */
7489517SBill.Taylor@Sun.COM 		if (size == 0) {
7499517SBill.Taylor@Sun.COM 			return;
7509517SBill.Taylor@Sun.COM 		}
7519517SBill.Taylor@Sun.COM 	} else {
7529517SBill.Taylor@Sun.COM 		return;
7539517SBill.Taylor@Sun.COM 	}
7549517SBill.Taylor@Sun.COM 
7559517SBill.Taylor@Sun.COM 	/*
7569517SBill.Taylor@Sun.COM 	 * Now that we can guarantee that the user memory is fully unmapped,
7579517SBill.Taylor@Sun.COM 	 * we can use the "key" and "type" values to try to find the entry
7589517SBill.Taylor@Sun.COM 	 * in the "userland resources database".  If it's found, then it
7599517SBill.Taylor@Sun.COM 	 * indicates that the queue memory (CQ or QP) has not yet been freed.
7609517SBill.Taylor@Sun.COM 	 * In this case, we update the corresponding CQ or QP handle to
7619517SBill.Taylor@Sun.COM 	 * indicate that the "devmap_devmem_remap()" call will be unnecessary.
7629517SBill.Taylor@Sun.COM 	 * If it's _not_ found, then it indicates that the CQ or QP memory
7639517SBill.Taylor@Sun.COM 	 * was, in fact, freed before it was unmapped (thus requiring a
7649517SBill.Taylor@Sun.COM 	 * previous invalidation by remapping - which will already have
7659517SBill.Taylor@Sun.COM 	 * been done in the free routine).
7669517SBill.Taylor@Sun.COM 	 */
7679517SBill.Taylor@Sun.COM 	status = hermon_umap_db_find(state->hs_instance, key, type, &value,
7689517SBill.Taylor@Sun.COM 	    0, NULL);
7699517SBill.Taylor@Sun.COM 	if (status == DDI_SUCCESS) {
7709517SBill.Taylor@Sun.COM 		/*
7719517SBill.Taylor@Sun.COM 		 * Depending on the type of the mapped resource (CQ or QP),
7729517SBill.Taylor@Sun.COM 		 * update handle to indicate that no invalidation remapping
7739517SBill.Taylor@Sun.COM 		 * will be necessary.
7749517SBill.Taylor@Sun.COM 		 */
7759517SBill.Taylor@Sun.COM 		if (type == MLNX_UMAP_CQMEM_RSRC) {
7769517SBill.Taylor@Sun.COM 
7779517SBill.Taylor@Sun.COM 			/* Use "value" to convert to CQ handle */
7789517SBill.Taylor@Sun.COM 			rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
7799517SBill.Taylor@Sun.COM 			cq = (hermon_cqhdl_t)rsrcp->hr_addr;
7809517SBill.Taylor@Sun.COM 
7819517SBill.Taylor@Sun.COM 			/*
7829517SBill.Taylor@Sun.COM 			 * Invalidate the handle to the userland mapping.
7839517SBill.Taylor@Sun.COM 			 * Note: We must ensure that the mapping being
7849517SBill.Taylor@Sun.COM 			 * unmapped here is the current one for the CQ.  It
7859517SBill.Taylor@Sun.COM 			 * is possible that it might not be if this CQ has
7869517SBill.Taylor@Sun.COM 			 * been resized and the previous CQ memory has not
7879517SBill.Taylor@Sun.COM 			 * yet been unmapped.  But in that case, because of
7889517SBill.Taylor@Sun.COM 			 * the devmap_devmem_remap(), there is no longer any
7899517SBill.Taylor@Sun.COM 			 * association between the mapping and the real CQ
7909517SBill.Taylor@Sun.COM 			 * kernel memory.
7919517SBill.Taylor@Sun.COM 			 */
7929517SBill.Taylor@Sun.COM 			mutex_enter(&cq->cq_lock);
7939517SBill.Taylor@Sun.COM 			if (cq->cq_umap_dhp == dhp) {
7949517SBill.Taylor@Sun.COM 				cq->cq_umap_dhp = NULL;
7959517SBill.Taylor@Sun.COM 				if (cq->cq_resize_hdl) {
7969517SBill.Taylor@Sun.COM 					/* resize is DONE, switch queues */
7979517SBill.Taylor@Sun.COM 					hermon_cq_resize_helper(state, cq);
7989517SBill.Taylor@Sun.COM 				}
7999517SBill.Taylor@Sun.COM 			} else {
8009517SBill.Taylor@Sun.COM 				if (cq->cq_resize_hdl &&
8019517SBill.Taylor@Sun.COM 				    cq->cq_resize_hdl->cq_umap_dhp == dhp) {
8029517SBill.Taylor@Sun.COM 					/*
8039517SBill.Taylor@Sun.COM 					 * Unexpected case.  munmap of the
8049517SBill.Taylor@Sun.COM 					 * cq_resize buf, and not the
8059517SBill.Taylor@Sun.COM 					 * original buf.
8069517SBill.Taylor@Sun.COM 					 */
8079517SBill.Taylor@Sun.COM 					cq->cq_resize_hdl->cq_umap_dhp = NULL;
8089517SBill.Taylor@Sun.COM 				}
8099517SBill.Taylor@Sun.COM 			}
8109517SBill.Taylor@Sun.COM 			mutex_exit(&cq->cq_lock);
8119517SBill.Taylor@Sun.COM 
8129517SBill.Taylor@Sun.COM 		} else if (type == MLNX_UMAP_QPMEM_RSRC) {
8139517SBill.Taylor@Sun.COM 
8149517SBill.Taylor@Sun.COM 			/* Use "value" to convert to QP handle */
8159517SBill.Taylor@Sun.COM 			rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
8169517SBill.Taylor@Sun.COM 			qp = (hermon_qphdl_t)rsrcp->hr_addr;
8179517SBill.Taylor@Sun.COM 
8189517SBill.Taylor@Sun.COM 			/*
8199517SBill.Taylor@Sun.COM 			 * Invalidate the handle to the userland mapping.
8209517SBill.Taylor@Sun.COM 			 * Note: we ensure that the mapping being unmapped
8219517SBill.Taylor@Sun.COM 			 * here is the current one for the QP.  This is
8229517SBill.Taylor@Sun.COM 			 * more of a sanity check here since, unlike CQs
8239517SBill.Taylor@Sun.COM 			 * (above) we do not support resize of QPs.
8249517SBill.Taylor@Sun.COM 			 */
8259517SBill.Taylor@Sun.COM 			mutex_enter(&qp->qp_lock);
8269517SBill.Taylor@Sun.COM 			if (qp->qp_umap_dhp == dhp) {
8279517SBill.Taylor@Sun.COM 				qp->qp_umap_dhp = NULL;
8289517SBill.Taylor@Sun.COM 			}
8299517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
8309517SBill.Taylor@Sun.COM 
8319517SBill.Taylor@Sun.COM 		} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
8329517SBill.Taylor@Sun.COM 
8339517SBill.Taylor@Sun.COM 			/* Use "value" to convert to SRQ handle */
8349517SBill.Taylor@Sun.COM 			rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
8359517SBill.Taylor@Sun.COM 			srq = (hermon_srqhdl_t)rsrcp->hr_addr;
8369517SBill.Taylor@Sun.COM 
8379517SBill.Taylor@Sun.COM 			/*
8389517SBill.Taylor@Sun.COM 			 * Invalidate the handle to the userland mapping.
8399517SBill.Taylor@Sun.COM 			 * Note: we ensure that the mapping being unmapped
8409517SBill.Taylor@Sun.COM 			 * here is the current one for the QP.  This is
8419517SBill.Taylor@Sun.COM 			 * more of a sanity check here since, unlike CQs
8429517SBill.Taylor@Sun.COM 			 * (above) we do not support resize of QPs.
8439517SBill.Taylor@Sun.COM 			 */
8449517SBill.Taylor@Sun.COM 			mutex_enter(&srq->srq_lock);
8459517SBill.Taylor@Sun.COM 			if (srq->srq_umap_dhp == dhp) {
8469517SBill.Taylor@Sun.COM 				srq->srq_umap_dhp = NULL;
8479517SBill.Taylor@Sun.COM 			}
8489517SBill.Taylor@Sun.COM 			mutex_exit(&srq->srq_lock);
8499517SBill.Taylor@Sun.COM 		}
8509517SBill.Taylor@Sun.COM 	}
8519517SBill.Taylor@Sun.COM }
8529517SBill.Taylor@Sun.COM 
8539517SBill.Taylor@Sun.COM 
8549517SBill.Taylor@Sun.COM /*
8559517SBill.Taylor@Sun.COM  * hermon_devmap_devmem_map()
8569517SBill.Taylor@Sun.COM  *    Context: Can be called from kernel context.
8579517SBill.Taylor@Sun.COM  */
8589517SBill.Taylor@Sun.COM /* ARGSUSED */
8599517SBill.Taylor@Sun.COM static int
hermon_devmap_dbrecmem_map(devmap_cookie_t dhp,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)8609517SBill.Taylor@Sun.COM hermon_devmap_dbrecmem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
8619517SBill.Taylor@Sun.COM     offset_t off, size_t len, void **pvtp)
8629517SBill.Taylor@Sun.COM {
8639517SBill.Taylor@Sun.COM 	hermon_state_t		*state;
8649517SBill.Taylor@Sun.COM 	hermon_devmap_track_t	*dvm_track;
8659517SBill.Taylor@Sun.COM 	hermon_cqhdl_t		cq;
8669517SBill.Taylor@Sun.COM 	hermon_qphdl_t		qp;
8679517SBill.Taylor@Sun.COM 	hermon_srqhdl_t		srq;
8689517SBill.Taylor@Sun.COM 	minor_t			instance;
8699517SBill.Taylor@Sun.COM 	uint64_t		key;
8709517SBill.Taylor@Sun.COM 	uint_t			type;
8719517SBill.Taylor@Sun.COM 
8729517SBill.Taylor@Sun.COM 	/* Get Hermon softstate structure from instance */
8739517SBill.Taylor@Sun.COM 	instance = HERMON_DEV_INSTANCE(dev);
8749517SBill.Taylor@Sun.COM 	state = ddi_get_soft_state(hermon_statep, instance);
8759517SBill.Taylor@Sun.COM 	if (state == NULL) {
8769517SBill.Taylor@Sun.COM 		return (ENXIO);
8779517SBill.Taylor@Sun.COM 	}
8789517SBill.Taylor@Sun.COM 
8799517SBill.Taylor@Sun.COM 	/*
8809517SBill.Taylor@Sun.COM 	 * The bottom bits of "offset" are undefined (number depends on
8819517SBill.Taylor@Sun.COM 	 * system PAGESIZE).  Shifting these off leaves us with a "key".
8829517SBill.Taylor@Sun.COM 	 * The "key" is actually a combination of both a real key value
8839517SBill.Taylor@Sun.COM 	 * (for the purpose of database lookup) and a "type" value.  Although
8849517SBill.Taylor@Sun.COM 	 * we are not going to do any database lookup per se, we do want
8859517SBill.Taylor@Sun.COM 	 * to extract the "key" and the "type" (to enable faster lookup of
8869517SBill.Taylor@Sun.COM 	 * the appropriate CQ or QP handle).
8879517SBill.Taylor@Sun.COM 	 */
8889517SBill.Taylor@Sun.COM 	key  = off >> PAGESHIFT;
8899517SBill.Taylor@Sun.COM 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
8909517SBill.Taylor@Sun.COM 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
8919517SBill.Taylor@Sun.COM 
8929517SBill.Taylor@Sun.COM 	/*
8939517SBill.Taylor@Sun.COM 	 * Allocate an entry to track the mapping and unmapping (specifically,
8949517SBill.Taylor@Sun.COM 	 * partial unmapping) of this resource.
8959517SBill.Taylor@Sun.COM 	 */
8969517SBill.Taylor@Sun.COM 	dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
8979517SBill.Taylor@Sun.COM 	    sizeof (hermon_devmap_track_t), KM_SLEEP);
8989517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
8999517SBill.Taylor@Sun.COM 	dvm_track->hdt_offset = off;
9009517SBill.Taylor@Sun.COM 	dvm_track->hdt_state  = state;
9019517SBill.Taylor@Sun.COM 	dvm_track->hdt_refcnt = 1;
9029517SBill.Taylor@Sun.COM 	mutex_init(&dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
9039517SBill.Taylor@Sun.COM 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
9049517SBill.Taylor@Sun.COM 
9059517SBill.Taylor@Sun.COM 	/*
9069517SBill.Taylor@Sun.COM 	 * Depending of the type of resource that has been mapped out, we
9079517SBill.Taylor@Sun.COM 	 * need to update the QP or CQ handle to reflect that it has, in
9089517SBill.Taylor@Sun.COM 	 * fact, been mapped.  This allows the driver code which frees a QP
9099517SBill.Taylor@Sun.COM 	 * or a CQ to know whether it is appropriate to do a
9109517SBill.Taylor@Sun.COM 	 * devmap_devmem_remap() to invalidate the userland mapping for the
9119517SBill.Taylor@Sun.COM 	 * corresponding queue's memory.
9129517SBill.Taylor@Sun.COM 	 */
9139517SBill.Taylor@Sun.COM 	if (type == MLNX_UMAP_CQMEM_RSRC) {
9149517SBill.Taylor@Sun.COM 
9159517SBill.Taylor@Sun.COM 		/* Use "key" (CQ number) to do fast lookup of CQ handle */
9169517SBill.Taylor@Sun.COM 		cq = hermon_cqhdl_from_cqnum(state, key);
9179517SBill.Taylor@Sun.COM 
9189517SBill.Taylor@Sun.COM 		/*
9199517SBill.Taylor@Sun.COM 		 * Update the handle to the userland mapping.  Note:  If
9209517SBill.Taylor@Sun.COM 		 * the CQ already has a valid userland mapping, then stop
9219517SBill.Taylor@Sun.COM 		 * and return failure.
9229517SBill.Taylor@Sun.COM 		 */
9239517SBill.Taylor@Sun.COM 		mutex_enter(&cq->cq_lock);
9249517SBill.Taylor@Sun.COM 		if (cq->cq_umap_dhp == NULL) {
9259517SBill.Taylor@Sun.COM 			cq->cq_umap_dhp = dhp;
9269517SBill.Taylor@Sun.COM 			dvm_track->hdt_size = cq->cq_cqinfo.qa_size;
9279517SBill.Taylor@Sun.COM 			mutex_exit(&cq->cq_lock);
9289517SBill.Taylor@Sun.COM 		} else {
9299517SBill.Taylor@Sun.COM 			mutex_exit(&cq->cq_lock);
9309517SBill.Taylor@Sun.COM 			goto umem_map_fail;
9319517SBill.Taylor@Sun.COM 		}
9329517SBill.Taylor@Sun.COM 
9339517SBill.Taylor@Sun.COM 	} else if (type == MLNX_UMAP_QPMEM_RSRC) {
9349517SBill.Taylor@Sun.COM 
9359517SBill.Taylor@Sun.COM 		/* Use "key" (QP number) to do fast lookup of QP handle */
9369517SBill.Taylor@Sun.COM 		qp = hermon_qphdl_from_qpnum(state, key);
9379517SBill.Taylor@Sun.COM 
9389517SBill.Taylor@Sun.COM 		/*
9399517SBill.Taylor@Sun.COM 		 * Update the handle to the userland mapping.  Note:  If
9409517SBill.Taylor@Sun.COM 		 * the CQ already has a valid userland mapping, then stop
9419517SBill.Taylor@Sun.COM 		 * and return failure.
9429517SBill.Taylor@Sun.COM 		 */
9439517SBill.Taylor@Sun.COM 		mutex_enter(&qp->qp_lock);
9449517SBill.Taylor@Sun.COM 		if (qp->qp_umap_dhp == NULL) {
9459517SBill.Taylor@Sun.COM 			qp->qp_umap_dhp = dhp;
9469517SBill.Taylor@Sun.COM 			dvm_track->hdt_size = qp->qp_wqinfo.qa_size;
9479517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
9489517SBill.Taylor@Sun.COM 		} else {
9499517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
9509517SBill.Taylor@Sun.COM 			goto umem_map_fail;
9519517SBill.Taylor@Sun.COM 		}
9529517SBill.Taylor@Sun.COM 
9539517SBill.Taylor@Sun.COM 	} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
9549517SBill.Taylor@Sun.COM 
9559517SBill.Taylor@Sun.COM 		/* Use "key" (SRQ number) to do fast lookup on SRQ handle */
9569517SBill.Taylor@Sun.COM 		srq = hermon_srqhdl_from_srqnum(state, key);
9579517SBill.Taylor@Sun.COM 
9589517SBill.Taylor@Sun.COM 		/*
9599517SBill.Taylor@Sun.COM 		 * Update the handle to the userland mapping.  Note:  If the
9609517SBill.Taylor@Sun.COM 		 * SRQ already has a valid userland mapping, then stop and
9619517SBill.Taylor@Sun.COM 		 * return failure.
9629517SBill.Taylor@Sun.COM 		 */
9639517SBill.Taylor@Sun.COM 		mutex_enter(&srq->srq_lock);
9649517SBill.Taylor@Sun.COM 		if (srq->srq_umap_dhp == NULL) {
9659517SBill.Taylor@Sun.COM 			srq->srq_umap_dhp = dhp;
9669517SBill.Taylor@Sun.COM 			dvm_track->hdt_size = srq->srq_wqinfo.qa_size;
9679517SBill.Taylor@Sun.COM 			mutex_exit(&srq->srq_lock);
9689517SBill.Taylor@Sun.COM 		} else {
9699517SBill.Taylor@Sun.COM 			mutex_exit(&srq->srq_lock);
9709517SBill.Taylor@Sun.COM 			goto umem_map_fail;
9719517SBill.Taylor@Sun.COM 		}
9729517SBill.Taylor@Sun.COM 	}
9739517SBill.Taylor@Sun.COM 
9749517SBill.Taylor@Sun.COM 	/*
9759517SBill.Taylor@Sun.COM 	 * Pass the private "Hermon devmap tracking structure" back.  This
9769517SBill.Taylor@Sun.COM 	 * pointer will be returned in subsequent "unmap" callbacks.
9779517SBill.Taylor@Sun.COM 	 */
9789517SBill.Taylor@Sun.COM 	*pvtp = dvm_track;
9799517SBill.Taylor@Sun.COM 
9809517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
9819517SBill.Taylor@Sun.COM 
9829517SBill.Taylor@Sun.COM umem_map_fail:
9839517SBill.Taylor@Sun.COM 	mutex_destroy(&dvm_track->hdt_lock);
9849517SBill.Taylor@Sun.COM 	kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
9859517SBill.Taylor@Sun.COM 	return (DDI_FAILURE);
9869517SBill.Taylor@Sun.COM }
9879517SBill.Taylor@Sun.COM 
9889517SBill.Taylor@Sun.COM 
9899517SBill.Taylor@Sun.COM /*
9909517SBill.Taylor@Sun.COM  * hermon_devmap_dbrecmem_dup()
9919517SBill.Taylor@Sun.COM  *    Context: Can be called from kernel context.
9929517SBill.Taylor@Sun.COM  */
9939517SBill.Taylor@Sun.COM /* ARGSUSED */
9949517SBill.Taylor@Sun.COM static int
hermon_devmap_dbrecmem_dup(devmap_cookie_t dhp,void * pvtp,devmap_cookie_t new_dhp,void ** new_pvtp)9959517SBill.Taylor@Sun.COM hermon_devmap_dbrecmem_dup(devmap_cookie_t dhp, void *pvtp,
9969517SBill.Taylor@Sun.COM     devmap_cookie_t new_dhp, void **new_pvtp)
9979517SBill.Taylor@Sun.COM {
9989517SBill.Taylor@Sun.COM 	hermon_state_t		*state;
9999517SBill.Taylor@Sun.COM 	hermon_devmap_track_t	*dvm_track, *new_dvm_track;
10009517SBill.Taylor@Sun.COM 	uint_t			maxprot;
10019517SBill.Taylor@Sun.COM 	int			status;
10029517SBill.Taylor@Sun.COM 
10039517SBill.Taylor@Sun.COM 	/*
10049517SBill.Taylor@Sun.COM 	 * Extract the Hermon softstate pointer from "Hermon devmap tracking
10059517SBill.Taylor@Sun.COM 	 * structure" (in "pvtp").
10069517SBill.Taylor@Sun.COM 	 */
10079517SBill.Taylor@Sun.COM 	dvm_track = (hermon_devmap_track_t *)pvtp;
10089517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
10099517SBill.Taylor@Sun.COM 	state = dvm_track->hdt_state;
10109517SBill.Taylor@Sun.COM 
10119517SBill.Taylor@Sun.COM 	/*
10129517SBill.Taylor@Sun.COM 	 * Since this devmap_dup() entry point is generally called
10139517SBill.Taylor@Sun.COM 	 * when a process does fork(2), it is incumbent upon the driver
10149517SBill.Taylor@Sun.COM 	 * to insure that the child does not inherit a valid copy of
10159517SBill.Taylor@Sun.COM 	 * the parent's QP or CQ resource.  This is accomplished by using
10169517SBill.Taylor@Sun.COM 	 * devmap_devmem_remap() to invalidate the child's mapping to the
10179517SBill.Taylor@Sun.COM 	 * kernel memory.
10189517SBill.Taylor@Sun.COM 	 */
10199517SBill.Taylor@Sun.COM 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
10209517SBill.Taylor@Sun.COM 	status = devmap_devmem_remap(new_dhp, state->hs_dip, 0, 0,
10219517SBill.Taylor@Sun.COM 	    dvm_track->hdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
10229517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
10239517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "failed in hermon_devmap_dbrecmem_dup()");
10249517SBill.Taylor@Sun.COM 		return (status);
10259517SBill.Taylor@Sun.COM 	}
10269517SBill.Taylor@Sun.COM 
10279517SBill.Taylor@Sun.COM 	/*
10289517SBill.Taylor@Sun.COM 	 * Allocate a new entry to track the subsequent unmapping
10299517SBill.Taylor@Sun.COM 	 * (specifically, all partial unmappings) of the child's newly
10309517SBill.Taylor@Sun.COM 	 * invalidated resource.  Note: Setting the "hdt_size" field to
10319517SBill.Taylor@Sun.COM 	 * zero here is an indication to the devmap_unmap() entry point
10329517SBill.Taylor@Sun.COM 	 * that this mapping is invalid, and that its subsequent unmapping
10339517SBill.Taylor@Sun.COM 	 * should not affect any of the parent's CQ or QP resources.
10349517SBill.Taylor@Sun.COM 	 */
10359517SBill.Taylor@Sun.COM 	new_dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
10369517SBill.Taylor@Sun.COM 	    sizeof (hermon_devmap_track_t), KM_SLEEP);
10379517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*new_dvm_track))
10389517SBill.Taylor@Sun.COM 	new_dvm_track->hdt_offset = 0;
10399517SBill.Taylor@Sun.COM 	new_dvm_track->hdt_state  = state;
10409517SBill.Taylor@Sun.COM 	new_dvm_track->hdt_refcnt = 1;
10419517SBill.Taylor@Sun.COM 	new_dvm_track->hdt_size	  = 0;
10429517SBill.Taylor@Sun.COM 	mutex_init(&new_dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
10439517SBill.Taylor@Sun.COM 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
10449517SBill.Taylor@Sun.COM 	*new_pvtp = new_dvm_track;
10459517SBill.Taylor@Sun.COM 
10469517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
10479517SBill.Taylor@Sun.COM }
10489517SBill.Taylor@Sun.COM 
10499517SBill.Taylor@Sun.COM 
10509517SBill.Taylor@Sun.COM /*
10519517SBill.Taylor@Sun.COM  * hermon_devmap_dbrecmem_unmap()
10529517SBill.Taylor@Sun.COM  *    Context: Can be called from kernel context.
10539517SBill.Taylor@Sun.COM  */
10549517SBill.Taylor@Sun.COM /* ARGSUSED */
10559517SBill.Taylor@Sun.COM static void
hermon_devmap_dbrecmem_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)10569517SBill.Taylor@Sun.COM hermon_devmap_dbrecmem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
10579517SBill.Taylor@Sun.COM     size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
10589517SBill.Taylor@Sun.COM     devmap_cookie_t new_dhp2, void **pvtp2)
10599517SBill.Taylor@Sun.COM {
10609517SBill.Taylor@Sun.COM 	hermon_state_t 		*state;
10619517SBill.Taylor@Sun.COM 	hermon_rsrc_t 		*rsrcp;
10629517SBill.Taylor@Sun.COM 	hermon_devmap_track_t	*dvm_track;
10639517SBill.Taylor@Sun.COM 	hermon_cqhdl_t		cq;
10649517SBill.Taylor@Sun.COM 	hermon_qphdl_t		qp;
10659517SBill.Taylor@Sun.COM 	hermon_srqhdl_t		srq;
10669517SBill.Taylor@Sun.COM 	uint64_t		key, value;
10679517SBill.Taylor@Sun.COM 	uint_t			type;
10689517SBill.Taylor@Sun.COM 	uint_t			size;
10699517SBill.Taylor@Sun.COM 	int			status;
10709517SBill.Taylor@Sun.COM 
10719517SBill.Taylor@Sun.COM 	/*
10729517SBill.Taylor@Sun.COM 	 * Extract the Hermon softstate pointer from "Hermon devmap tracking
10739517SBill.Taylor@Sun.COM 	 * structure" (in "pvtp").
10749517SBill.Taylor@Sun.COM 	 */
10759517SBill.Taylor@Sun.COM 	dvm_track = (hermon_devmap_track_t *)pvtp;
10769517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
10779517SBill.Taylor@Sun.COM 	state	  = dvm_track->hdt_state;
10789517SBill.Taylor@Sun.COM 
10799517SBill.Taylor@Sun.COM 	/*
10809517SBill.Taylor@Sun.COM 	 * Extract the "offset" from the "Hermon devmap tracking structure".
10819517SBill.Taylor@Sun.COM 	 * Note: The input argument "off" is ignored here because the
10829517SBill.Taylor@Sun.COM 	 * Hermon mapping interfaces define a very specific meaning to
10839517SBill.Taylor@Sun.COM 	 * each "logical offset".  Also extract the "key" and "type" encoded
10849517SBill.Taylor@Sun.COM 	 * in the logical offset.
10859517SBill.Taylor@Sun.COM 	 */
10869517SBill.Taylor@Sun.COM 	key  = dvm_track->hdt_offset >> PAGESHIFT;
10879517SBill.Taylor@Sun.COM 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
10889517SBill.Taylor@Sun.COM 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
10899517SBill.Taylor@Sun.COM 
10909517SBill.Taylor@Sun.COM 	/*
10919517SBill.Taylor@Sun.COM 	 * Extract the "size" of the mapping.  If this size is determined
10929517SBill.Taylor@Sun.COM 	 * to be zero, then it is an indication of a previously invalidated
10939517SBill.Taylor@Sun.COM 	 * mapping, and no CQ or QP resources should be affected.
10949517SBill.Taylor@Sun.COM 	 */
10959517SBill.Taylor@Sun.COM 	size = dvm_track->hdt_size;
10969517SBill.Taylor@Sun.COM 
10979517SBill.Taylor@Sun.COM 	/*
10989517SBill.Taylor@Sun.COM 	 * If only the "middle portion of a given mapping is being unmapped,
10999517SBill.Taylor@Sun.COM 	 * then we are effectively creating one new piece of mapped memory.
11009517SBill.Taylor@Sun.COM 	 * (Original region is divided into three pieces of which the middle
11019517SBill.Taylor@Sun.COM 	 * piece is being removed.  This leaves two pieces.  Since we started
11029517SBill.Taylor@Sun.COM 	 * with one piece and now have two pieces, we need to increment the
11039517SBill.Taylor@Sun.COM 	 * counter in the "Hermon devmap tracking structure".
11049517SBill.Taylor@Sun.COM 	 *
11059517SBill.Taylor@Sun.COM 	 * If, however, the whole mapped region is being unmapped, then we
11069517SBill.Taylor@Sun.COM 	 * have started with one region which we are completely removing.
11079517SBill.Taylor@Sun.COM 	 * In this case, we need to decrement the counter in the "Hermon
11089517SBill.Taylor@Sun.COM 	 * devmap tracking structure".
11099517SBill.Taylor@Sun.COM 	 *
11109517SBill.Taylor@Sun.COM 	 * In each of the remaining cases, we will have started with one
11119517SBill.Taylor@Sun.COM 	 * mapped region and ended with one (different) region.  So no counter
11129517SBill.Taylor@Sun.COM 	 * modification is necessary.
11139517SBill.Taylor@Sun.COM 	 */
11149517SBill.Taylor@Sun.COM 	mutex_enter(&dvm_track->hdt_lock);
11159517SBill.Taylor@Sun.COM 	if ((new_dhp1 == NULL) && (new_dhp2 == NULL)) {
11169517SBill.Taylor@Sun.COM 		dvm_track->hdt_refcnt--;
11179517SBill.Taylor@Sun.COM 	} else if ((new_dhp1 != NULL) && (new_dhp2 != NULL)) {
11189517SBill.Taylor@Sun.COM 		dvm_track->hdt_refcnt++;
11199517SBill.Taylor@Sun.COM 	}
11209517SBill.Taylor@Sun.COM 	mutex_exit(&dvm_track->hdt_lock);
11219517SBill.Taylor@Sun.COM 
11229517SBill.Taylor@Sun.COM 	/*
11239517SBill.Taylor@Sun.COM 	 * For each of the cases where the region is being divided, then we
11249517SBill.Taylor@Sun.COM 	 * need to pass back the "Hermon devmap tracking structure".  This way
11259517SBill.Taylor@Sun.COM 	 * we get it back when each of the remaining pieces is subsequently
11269517SBill.Taylor@Sun.COM 	 * unmapped.
11279517SBill.Taylor@Sun.COM 	 */
11289517SBill.Taylor@Sun.COM 	if (new_dhp1 != NULL) {
11299517SBill.Taylor@Sun.COM 		*pvtp1 = pvtp;
11309517SBill.Taylor@Sun.COM 	}
11319517SBill.Taylor@Sun.COM 	if (new_dhp2 != NULL) {
11329517SBill.Taylor@Sun.COM 		*pvtp2 = pvtp;
11339517SBill.Taylor@Sun.COM 	}
11349517SBill.Taylor@Sun.COM 
11359517SBill.Taylor@Sun.COM 	/*
11369517SBill.Taylor@Sun.COM 	 * If the "Hermon devmap tracking structure" is no longer being
11379517SBill.Taylor@Sun.COM 	 * referenced, then free it up.  Otherwise, return.
11389517SBill.Taylor@Sun.COM 	 */
11399517SBill.Taylor@Sun.COM 	if (dvm_track->hdt_refcnt == 0) {
11409517SBill.Taylor@Sun.COM 		mutex_destroy(&dvm_track->hdt_lock);
11419517SBill.Taylor@Sun.COM 		kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
11429517SBill.Taylor@Sun.COM 
11439517SBill.Taylor@Sun.COM 		/*
11449517SBill.Taylor@Sun.COM 		 * If the mapping was invalid (see explanation above), then
11459517SBill.Taylor@Sun.COM 		 * no further processing is necessary.
11469517SBill.Taylor@Sun.COM 		 */
11479517SBill.Taylor@Sun.COM 		if (size == 0) {
11489517SBill.Taylor@Sun.COM 			return;
11499517SBill.Taylor@Sun.COM 		}
11509517SBill.Taylor@Sun.COM 	} else {
11519517SBill.Taylor@Sun.COM 		return;
11529517SBill.Taylor@Sun.COM 	}
11539517SBill.Taylor@Sun.COM 
11549517SBill.Taylor@Sun.COM 	/*
11559517SBill.Taylor@Sun.COM 	 * Now that we can guarantee that the user memory is fully unmapped,
11569517SBill.Taylor@Sun.COM 	 * we can use the "key" and "type" values to try to find the entry
11579517SBill.Taylor@Sun.COM 	 * in the "userland resources database".  If it's found, then it
11589517SBill.Taylor@Sun.COM 	 * indicates that the queue memory (CQ or QP) has not yet been freed.
11599517SBill.Taylor@Sun.COM 	 * In this case, we update the corresponding CQ or QP handle to
11609517SBill.Taylor@Sun.COM 	 * indicate that the "devmap_devmem_remap()" call will be unnecessary.
11619517SBill.Taylor@Sun.COM 	 * If it's _not_ found, then it indicates that the CQ or QP memory
11629517SBill.Taylor@Sun.COM 	 * was, in fact, freed before it was unmapped (thus requiring a
11639517SBill.Taylor@Sun.COM 	 * previous invalidation by remapping - which will already have
11649517SBill.Taylor@Sun.COM 	 * been done in the free routine).
11659517SBill.Taylor@Sun.COM 	 */
11669517SBill.Taylor@Sun.COM 	status = hermon_umap_db_find(state->hs_instance, key, type, &value,
11679517SBill.Taylor@Sun.COM 	    0, NULL);
11689517SBill.Taylor@Sun.COM 	if (status == DDI_SUCCESS) {
11699517SBill.Taylor@Sun.COM 		/*
11709517SBill.Taylor@Sun.COM 		 * Depending on the type of the mapped resource (CQ or QP),
11719517SBill.Taylor@Sun.COM 		 * update handle to indicate that no invalidation remapping
11729517SBill.Taylor@Sun.COM 		 * will be necessary.
11739517SBill.Taylor@Sun.COM 		 */
11749517SBill.Taylor@Sun.COM 		if (type == MLNX_UMAP_CQMEM_RSRC) {
11759517SBill.Taylor@Sun.COM 
11769517SBill.Taylor@Sun.COM 			/* Use "value" to convert to CQ handle */
11779517SBill.Taylor@Sun.COM 			rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
11789517SBill.Taylor@Sun.COM 			cq = (hermon_cqhdl_t)rsrcp->hr_addr;
11799517SBill.Taylor@Sun.COM 
11809517SBill.Taylor@Sun.COM 			/*
11819517SBill.Taylor@Sun.COM 			 * Invalidate the handle to the userland mapping.
11829517SBill.Taylor@Sun.COM 			 * Note: We must ensure that the mapping being
11839517SBill.Taylor@Sun.COM 			 * unmapped here is the current one for the CQ.  It
11849517SBill.Taylor@Sun.COM 			 * is possible that it might not be if this CQ has
11859517SBill.Taylor@Sun.COM 			 * been resized and the previous CQ memory has not
11869517SBill.Taylor@Sun.COM 			 * yet been unmapped.  But in that case, because of
11879517SBill.Taylor@Sun.COM 			 * the devmap_devmem_remap(), there is no longer any
11889517SBill.Taylor@Sun.COM 			 * association between the mapping and the real CQ
11899517SBill.Taylor@Sun.COM 			 * kernel memory.
11909517SBill.Taylor@Sun.COM 			 */
11919517SBill.Taylor@Sun.COM 			mutex_enter(&cq->cq_lock);
11929517SBill.Taylor@Sun.COM 			if (cq->cq_umap_dhp == dhp) {
11939517SBill.Taylor@Sun.COM 				cq->cq_umap_dhp = NULL;
11949517SBill.Taylor@Sun.COM 			}
11959517SBill.Taylor@Sun.COM 			mutex_exit(&cq->cq_lock);
11969517SBill.Taylor@Sun.COM 
11979517SBill.Taylor@Sun.COM 		} else if (type == MLNX_UMAP_QPMEM_RSRC) {
11989517SBill.Taylor@Sun.COM 
11999517SBill.Taylor@Sun.COM 			/* Use "value" to convert to QP handle */
12009517SBill.Taylor@Sun.COM 			rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
12019517SBill.Taylor@Sun.COM 			qp = (hermon_qphdl_t)rsrcp->hr_addr;
12029517SBill.Taylor@Sun.COM 
12039517SBill.Taylor@Sun.COM 			/*
12049517SBill.Taylor@Sun.COM 			 * Invalidate the handle to the userland mapping.
12059517SBill.Taylor@Sun.COM 			 * Note: we ensure that the mapping being unmapped
12069517SBill.Taylor@Sun.COM 			 * here is the current one for the QP.  This is
12079517SBill.Taylor@Sun.COM 			 * more of a sanity check here since, unlike CQs
12089517SBill.Taylor@Sun.COM 			 * (above) we do not support resize of QPs.
12099517SBill.Taylor@Sun.COM 			 */
12109517SBill.Taylor@Sun.COM 			mutex_enter(&qp->qp_lock);
12119517SBill.Taylor@Sun.COM 			if (qp->qp_umap_dhp == dhp) {
12129517SBill.Taylor@Sun.COM 				qp->qp_umap_dhp = NULL;
12139517SBill.Taylor@Sun.COM 			}
12149517SBill.Taylor@Sun.COM 			mutex_exit(&qp->qp_lock);
12159517SBill.Taylor@Sun.COM 
12169517SBill.Taylor@Sun.COM 		} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
12179517SBill.Taylor@Sun.COM 
12189517SBill.Taylor@Sun.COM 			/* Use "value" to convert to SRQ handle */
12199517SBill.Taylor@Sun.COM 			rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
12209517SBill.Taylor@Sun.COM 			srq = (hermon_srqhdl_t)rsrcp->hr_addr;
12219517SBill.Taylor@Sun.COM 
12229517SBill.Taylor@Sun.COM 			/*
12239517SBill.Taylor@Sun.COM 			 * Invalidate the handle to the userland mapping.
12249517SBill.Taylor@Sun.COM 			 * Note: we ensure that the mapping being unmapped
12259517SBill.Taylor@Sun.COM 			 * here is the current one for the QP.  This is
12269517SBill.Taylor@Sun.COM 			 * more of a sanity check here since, unlike CQs
12279517SBill.Taylor@Sun.COM 			 * (above) we do not support resize of QPs.
12289517SBill.Taylor@Sun.COM 			 */
12299517SBill.Taylor@Sun.COM 			mutex_enter(&srq->srq_lock);
12309517SBill.Taylor@Sun.COM 			if (srq->srq_umap_dhp == dhp) {
12319517SBill.Taylor@Sun.COM 				srq->srq_umap_dhp = NULL;
12329517SBill.Taylor@Sun.COM 			}
12339517SBill.Taylor@Sun.COM 			mutex_exit(&srq->srq_lock);
12349517SBill.Taylor@Sun.COM 		}
12359517SBill.Taylor@Sun.COM 	}
12369517SBill.Taylor@Sun.COM }
12379517SBill.Taylor@Sun.COM 
12389517SBill.Taylor@Sun.COM 
12399517SBill.Taylor@Sun.COM /*
12409517SBill.Taylor@Sun.COM  * hermon_devmap_devmem_map()
12419517SBill.Taylor@Sun.COM  *    Context: Can be called from kernel context.
12429517SBill.Taylor@Sun.COM  */
12439517SBill.Taylor@Sun.COM /* ARGSUSED */
12449517SBill.Taylor@Sun.COM static int
hermon_devmap_devmem_map(devmap_cookie_t dhp,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)12459517SBill.Taylor@Sun.COM hermon_devmap_devmem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
12469517SBill.Taylor@Sun.COM     offset_t off, size_t len, void **pvtp)
12479517SBill.Taylor@Sun.COM {
12489517SBill.Taylor@Sun.COM 	hermon_state_t		*state;
12499517SBill.Taylor@Sun.COM 	hermon_devmap_track_t	*dvm_track;
12509517SBill.Taylor@Sun.COM 	minor_t			instance;
12519517SBill.Taylor@Sun.COM 
12529517SBill.Taylor@Sun.COM 	/* Get Hermon softstate structure from instance */
12539517SBill.Taylor@Sun.COM 	instance = HERMON_DEV_INSTANCE(dev);
12549517SBill.Taylor@Sun.COM 	state = ddi_get_soft_state(hermon_statep, instance);
12559517SBill.Taylor@Sun.COM 	if (state == NULL) {
12569517SBill.Taylor@Sun.COM 		return (ENXIO);
12579517SBill.Taylor@Sun.COM 	}
12589517SBill.Taylor@Sun.COM 
12599517SBill.Taylor@Sun.COM 	/*
12609517SBill.Taylor@Sun.COM 	 * Allocate an entry to track the mapping and unmapping of this
12619517SBill.Taylor@Sun.COM 	 * resource.  Note:  We don't need to initialize the "refcnt" or
12629517SBill.Taylor@Sun.COM 	 * "offset" fields here, nor do we need to initialize the mutex
12639517SBill.Taylor@Sun.COM 	 * used with the "refcnt".  Since UAR pages are single pages, they
12649517SBill.Taylor@Sun.COM 	 * are not subject to "partial" unmappings.  This makes these other
12659517SBill.Taylor@Sun.COM 	 * fields unnecessary.
12669517SBill.Taylor@Sun.COM 	 */
12679517SBill.Taylor@Sun.COM 	dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
12689517SBill.Taylor@Sun.COM 	    sizeof (hermon_devmap_track_t), KM_SLEEP);
12699517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
12709517SBill.Taylor@Sun.COM 	dvm_track->hdt_state  = state;
12719517SBill.Taylor@Sun.COM 	dvm_track->hdt_size   = (uint_t)PAGESIZE;
12729517SBill.Taylor@Sun.COM 
12739517SBill.Taylor@Sun.COM 	/*
12749517SBill.Taylor@Sun.COM 	 * Pass the private "Hermon devmap tracking structure" back.  This
12759517SBill.Taylor@Sun.COM 	 * pointer will be returned in a subsequent "unmap" callback.
12769517SBill.Taylor@Sun.COM 	 */
12779517SBill.Taylor@Sun.COM 	*pvtp = dvm_track;
12789517SBill.Taylor@Sun.COM 
12799517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
12809517SBill.Taylor@Sun.COM }
12819517SBill.Taylor@Sun.COM 
12829517SBill.Taylor@Sun.COM 
12839517SBill.Taylor@Sun.COM /*
12849517SBill.Taylor@Sun.COM  * hermon_devmap_devmem_dup()
12859517SBill.Taylor@Sun.COM  *    Context: Can be called from kernel context.
12869517SBill.Taylor@Sun.COM  */
12879517SBill.Taylor@Sun.COM /* ARGSUSED */
12889517SBill.Taylor@Sun.COM static int
hermon_devmap_devmem_dup(devmap_cookie_t dhp,void * pvtp,devmap_cookie_t new_dhp,void ** new_pvtp)12899517SBill.Taylor@Sun.COM hermon_devmap_devmem_dup(devmap_cookie_t dhp, void *pvtp,
12909517SBill.Taylor@Sun.COM     devmap_cookie_t new_dhp, void **new_pvtp)
12919517SBill.Taylor@Sun.COM {
12929517SBill.Taylor@Sun.COM 	hermon_state_t		*state;
12939517SBill.Taylor@Sun.COM 	hermon_devmap_track_t	*dvm_track;
12949517SBill.Taylor@Sun.COM 	uint_t			maxprot;
12959517SBill.Taylor@Sun.COM 	int			status;
12969517SBill.Taylor@Sun.COM 
12979517SBill.Taylor@Sun.COM 	/*
12989517SBill.Taylor@Sun.COM 	 * Extract the Hermon softstate pointer from "Hermon devmap tracking
12999517SBill.Taylor@Sun.COM 	 * structure" (in "pvtp").  Note: If the tracking structure is NULL
13009517SBill.Taylor@Sun.COM 	 * here, it means that the mapping corresponds to an invalid mapping.
13019517SBill.Taylor@Sun.COM 	 * In this case, it can be safely ignored ("new_pvtp" set to NULL).
13029517SBill.Taylor@Sun.COM 	 */
13039517SBill.Taylor@Sun.COM 	dvm_track = (hermon_devmap_track_t *)pvtp;
13049517SBill.Taylor@Sun.COM 	if (dvm_track == NULL) {
13059517SBill.Taylor@Sun.COM 		*new_pvtp = NULL;
13069517SBill.Taylor@Sun.COM 		return (DDI_SUCCESS);
13079517SBill.Taylor@Sun.COM 	}
13089517SBill.Taylor@Sun.COM 
13099517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
13109517SBill.Taylor@Sun.COM 	state = dvm_track->hdt_state;
13119517SBill.Taylor@Sun.COM 
13129517SBill.Taylor@Sun.COM 	/*
13139517SBill.Taylor@Sun.COM 	 * Since this devmap_dup() entry point is generally called
13149517SBill.Taylor@Sun.COM 	 * when a process does fork(2), it is incumbent upon the driver
13159517SBill.Taylor@Sun.COM 	 * to insure that the child does not inherit a valid copy of
13169517SBill.Taylor@Sun.COM 	 * the parent's resource.  This is accomplished by using
13179517SBill.Taylor@Sun.COM 	 * devmap_devmem_remap() to invalidate the child's mapping to the
13189517SBill.Taylor@Sun.COM 	 * kernel memory.
13199517SBill.Taylor@Sun.COM 	 */
13209517SBill.Taylor@Sun.COM 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
13219517SBill.Taylor@Sun.COM 	status = devmap_devmem_remap(new_dhp, state->hs_dip, 0, 0,
13229517SBill.Taylor@Sun.COM 	    dvm_track->hdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
13239517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
13249517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "failed in hermon_devmap_devmem_dup()");
13259517SBill.Taylor@Sun.COM 		return (status);
13269517SBill.Taylor@Sun.COM 	}
13279517SBill.Taylor@Sun.COM 
13289517SBill.Taylor@Sun.COM 	/*
13299517SBill.Taylor@Sun.COM 	 * Since the region is invalid, there is no need for us to
13309517SBill.Taylor@Sun.COM 	 * allocate and continue to track an additional "Hermon devmap
13319517SBill.Taylor@Sun.COM 	 * tracking structure".  Instead we return NULL here, which is an
13329517SBill.Taylor@Sun.COM 	 * indication to the devmap_unmap() entry point that this entry
13339517SBill.Taylor@Sun.COM 	 * can be safely ignored.
13349517SBill.Taylor@Sun.COM 	 */
13359517SBill.Taylor@Sun.COM 	*new_pvtp = NULL;
13369517SBill.Taylor@Sun.COM 
13379517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
13389517SBill.Taylor@Sun.COM }
13399517SBill.Taylor@Sun.COM 
13409517SBill.Taylor@Sun.COM 
13419517SBill.Taylor@Sun.COM /*
13429517SBill.Taylor@Sun.COM  * hermon_devmap_devmem_unmap()
13439517SBill.Taylor@Sun.COM  *    Context: Can be called from kernel context.
13449517SBill.Taylor@Sun.COM  */
13459517SBill.Taylor@Sun.COM /* ARGSUSED */
13469517SBill.Taylor@Sun.COM static void
hermon_devmap_devmem_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)13479517SBill.Taylor@Sun.COM hermon_devmap_devmem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
13489517SBill.Taylor@Sun.COM     size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
13499517SBill.Taylor@Sun.COM     devmap_cookie_t new_dhp2, void **pvtp2)
13509517SBill.Taylor@Sun.COM {
13519517SBill.Taylor@Sun.COM 	hermon_devmap_track_t	*dvm_track;
13529517SBill.Taylor@Sun.COM 
13539517SBill.Taylor@Sun.COM 	/*
13549517SBill.Taylor@Sun.COM 	 * Free up the "Hermon devmap tracking structure" (in "pvtp").
13559517SBill.Taylor@Sun.COM 	 * There cannot be "partial" unmappings here because all UAR pages
13569517SBill.Taylor@Sun.COM 	 * are single pages.  Note: If the tracking structure is NULL here,
13579517SBill.Taylor@Sun.COM 	 * it means that the mapping corresponds to an invalid mapping.  In
13589517SBill.Taylor@Sun.COM 	 * this case, it can be safely ignored.
13599517SBill.Taylor@Sun.COM 	 */
13609517SBill.Taylor@Sun.COM 	dvm_track = (hermon_devmap_track_t *)pvtp;
13619517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
13629517SBill.Taylor@Sun.COM 	if (dvm_track == NULL) {
13639517SBill.Taylor@Sun.COM 		return;
13649517SBill.Taylor@Sun.COM 	}
13659517SBill.Taylor@Sun.COM 
13669517SBill.Taylor@Sun.COM 	kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
13679517SBill.Taylor@Sun.COM }
13689517SBill.Taylor@Sun.COM 
13699517SBill.Taylor@Sun.COM 
13709517SBill.Taylor@Sun.COM /*
13719517SBill.Taylor@Sun.COM  * hermon_umap_ci_data_in()
13729517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
13739517SBill.Taylor@Sun.COM  */
13749517SBill.Taylor@Sun.COM /* ARGSUSED */
13759517SBill.Taylor@Sun.COM ibt_status_t
hermon_umap_ci_data_in(hermon_state_t * state,ibt_ci_data_flags_t flags,ibt_object_type_t object,void * hdl,void * data_p,size_t data_sz)13769517SBill.Taylor@Sun.COM hermon_umap_ci_data_in(hermon_state_t *state, ibt_ci_data_flags_t flags,
13779517SBill.Taylor@Sun.COM     ibt_object_type_t object, void *hdl, void *data_p, size_t data_sz)
13789517SBill.Taylor@Sun.COM {
13799517SBill.Taylor@Sun.COM 	int	status;
13809517SBill.Taylor@Sun.COM 
13819517SBill.Taylor@Sun.COM 	/*
13829517SBill.Taylor@Sun.COM 	 * Depending on the type of object about which additional information
13839517SBill.Taylor@Sun.COM 	 * is being provided (currently only MR is supported), we call the
13849517SBill.Taylor@Sun.COM 	 * appropriate resource-specific function.
13859517SBill.Taylor@Sun.COM 	 */
13869517SBill.Taylor@Sun.COM 	switch (object) {
13879517SBill.Taylor@Sun.COM 	case IBT_HDL_MR:
13889517SBill.Taylor@Sun.COM 		status = hermon_umap_mr_data_in((hermon_mrhdl_t)hdl,
13899517SBill.Taylor@Sun.COM 		    (ibt_mr_data_in_t *)data_p, data_sz);
13909517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
13919517SBill.Taylor@Sun.COM 			return (status);
13929517SBill.Taylor@Sun.COM 		}
13939517SBill.Taylor@Sun.COM 		break;
13949517SBill.Taylor@Sun.COM 
13959517SBill.Taylor@Sun.COM 	/*
13969517SBill.Taylor@Sun.COM 	 * For other possible valid IBT types, we return IBT_NOT_SUPPORTED,
13979517SBill.Taylor@Sun.COM 	 * since the Hermon driver does not support these.
13989517SBill.Taylor@Sun.COM 	 */
13999517SBill.Taylor@Sun.COM 	case IBT_HDL_HCA:
14009517SBill.Taylor@Sun.COM 	case IBT_HDL_QP:
14019517SBill.Taylor@Sun.COM 	case IBT_HDL_CQ:
14029517SBill.Taylor@Sun.COM 	case IBT_HDL_PD:
14039517SBill.Taylor@Sun.COM 	case IBT_HDL_MW:
14049517SBill.Taylor@Sun.COM 	case IBT_HDL_AH:
14059517SBill.Taylor@Sun.COM 	case IBT_HDL_SCHED:
14069517SBill.Taylor@Sun.COM 	case IBT_HDL_EEC:
14079517SBill.Taylor@Sun.COM 	case IBT_HDL_RDD:
14089517SBill.Taylor@Sun.COM 	case IBT_HDL_SRQ:
14099517SBill.Taylor@Sun.COM 		return (IBT_NOT_SUPPORTED);
14109517SBill.Taylor@Sun.COM 
14119517SBill.Taylor@Sun.COM 	/*
14129517SBill.Taylor@Sun.COM 	 * Any other types are invalid.
14139517SBill.Taylor@Sun.COM 	 */
14149517SBill.Taylor@Sun.COM 	default:
14159517SBill.Taylor@Sun.COM 		return (IBT_INVALID_PARAM);
14169517SBill.Taylor@Sun.COM 	}
14179517SBill.Taylor@Sun.COM 
14189517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
14199517SBill.Taylor@Sun.COM }
14209517SBill.Taylor@Sun.COM 
14219517SBill.Taylor@Sun.COM 
14229517SBill.Taylor@Sun.COM /*
14239517SBill.Taylor@Sun.COM  * hermon_umap_mr_data_in()
14249517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
14259517SBill.Taylor@Sun.COM  */
14269517SBill.Taylor@Sun.COM static ibt_status_t
hermon_umap_mr_data_in(hermon_mrhdl_t mr,ibt_mr_data_in_t * data,size_t data_sz)14279517SBill.Taylor@Sun.COM hermon_umap_mr_data_in(hermon_mrhdl_t mr, ibt_mr_data_in_t *data,
14289517SBill.Taylor@Sun.COM     size_t data_sz)
14299517SBill.Taylor@Sun.COM {
14309517SBill.Taylor@Sun.COM 	if (data->mr_rev != IBT_MR_DATA_IN_IF_VERSION) {
14319517SBill.Taylor@Sun.COM 		return (IBT_NOT_SUPPORTED);
14329517SBill.Taylor@Sun.COM 	}
14339517SBill.Taylor@Sun.COM 
14349517SBill.Taylor@Sun.COM 	/* Check for valid MR handle pointer */
14359517SBill.Taylor@Sun.COM 	if (mr == NULL) {
14369517SBill.Taylor@Sun.COM 		return (IBT_MR_HDL_INVALID);
14379517SBill.Taylor@Sun.COM 	}
14389517SBill.Taylor@Sun.COM 
14399517SBill.Taylor@Sun.COM 	/* Check for valid MR input structure size */
14409517SBill.Taylor@Sun.COM 	if (data_sz < sizeof (ibt_mr_data_in_t)) {
14419517SBill.Taylor@Sun.COM 		return (IBT_INSUFF_RESOURCE);
14429517SBill.Taylor@Sun.COM 	}
14439517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
14449517SBill.Taylor@Sun.COM 
14459517SBill.Taylor@Sun.COM 	/*
14469517SBill.Taylor@Sun.COM 	 * Ensure that the MR corresponds to userland memory and that it is
14479517SBill.Taylor@Sun.COM 	 * a currently valid memory region as well.
14489517SBill.Taylor@Sun.COM 	 */
14499517SBill.Taylor@Sun.COM 	mutex_enter(&mr->mr_lock);
14509517SBill.Taylor@Sun.COM 	if ((mr->mr_is_umem == 0) || (mr->mr_umemcookie == NULL)) {
14519517SBill.Taylor@Sun.COM 		mutex_exit(&mr->mr_lock);
14529517SBill.Taylor@Sun.COM 		return (IBT_MR_HDL_INVALID);
14539517SBill.Taylor@Sun.COM 	}
14549517SBill.Taylor@Sun.COM 
14559517SBill.Taylor@Sun.COM 	/*
14569517SBill.Taylor@Sun.COM 	 * If it has passed all the above checks, then extract the callback
14579517SBill.Taylor@Sun.COM 	 * function and argument from the input structure.  Copy them into
14589517SBill.Taylor@Sun.COM 	 * the MR handle.  This function will be called only if the memory
14599517SBill.Taylor@Sun.COM 	 * corresponding to the MR handle gets a umem_lockmemory() callback.
14609517SBill.Taylor@Sun.COM 	 */
14619517SBill.Taylor@Sun.COM 	mr->mr_umem_cbfunc = data->mr_func;
14629517SBill.Taylor@Sun.COM 	mr->mr_umem_cbarg1 = data->mr_arg1;
14639517SBill.Taylor@Sun.COM 	mr->mr_umem_cbarg2 = data->mr_arg2;
14649517SBill.Taylor@Sun.COM 	mutex_exit(&mr->mr_lock);
14659517SBill.Taylor@Sun.COM 
14669517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
14679517SBill.Taylor@Sun.COM }
14689517SBill.Taylor@Sun.COM 
14699517SBill.Taylor@Sun.COM 
14709517SBill.Taylor@Sun.COM /*
14719517SBill.Taylor@Sun.COM  * hermon_umap_ci_data_out()
14729517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
14739517SBill.Taylor@Sun.COM  */
14749517SBill.Taylor@Sun.COM /* ARGSUSED */
14759517SBill.Taylor@Sun.COM ibt_status_t
hermon_umap_ci_data_out(hermon_state_t * state,ibt_ci_data_flags_t flags,ibt_object_type_t object,void * hdl,void * data_p,size_t data_sz)14769517SBill.Taylor@Sun.COM hermon_umap_ci_data_out(hermon_state_t *state, ibt_ci_data_flags_t flags,
14779517SBill.Taylor@Sun.COM     ibt_object_type_t object, void *hdl, void *data_p, size_t data_sz)
14789517SBill.Taylor@Sun.COM {
14799517SBill.Taylor@Sun.COM 	int	status;
14809517SBill.Taylor@Sun.COM 
14819517SBill.Taylor@Sun.COM 	/*
14829517SBill.Taylor@Sun.COM 	 * Depending on the type of object about which additional information
14839517SBill.Taylor@Sun.COM 	 * is being requested (CQ or QP), we call the appropriate resource-
14849517SBill.Taylor@Sun.COM 	 * specific mapping function.
14859517SBill.Taylor@Sun.COM 	 */
14869517SBill.Taylor@Sun.COM 	switch (object) {
14879517SBill.Taylor@Sun.COM 	case IBT_HDL_CQ:
14889517SBill.Taylor@Sun.COM 		status = hermon_umap_cq_data_out((hermon_cqhdl_t)hdl,
14899517SBill.Taylor@Sun.COM 		    (mlnx_umap_cq_data_out_t *)data_p, data_sz);
14909517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
14919517SBill.Taylor@Sun.COM 			return (status);
14929517SBill.Taylor@Sun.COM 		}
14939517SBill.Taylor@Sun.COM 		break;
14949517SBill.Taylor@Sun.COM 
14959517SBill.Taylor@Sun.COM 	case IBT_HDL_QP:
14969517SBill.Taylor@Sun.COM 		status = hermon_umap_qp_data_out((hermon_qphdl_t)hdl,
14979517SBill.Taylor@Sun.COM 		    (mlnx_umap_qp_data_out_t *)data_p, data_sz);
14989517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
14999517SBill.Taylor@Sun.COM 			return (status);
15009517SBill.Taylor@Sun.COM 		}
15019517SBill.Taylor@Sun.COM 		break;
15029517SBill.Taylor@Sun.COM 
15039517SBill.Taylor@Sun.COM 	case IBT_HDL_SRQ:
15049517SBill.Taylor@Sun.COM 		status = hermon_umap_srq_data_out((hermon_srqhdl_t)hdl,
15059517SBill.Taylor@Sun.COM 		    (mlnx_umap_srq_data_out_t *)data_p, data_sz);
15069517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
15079517SBill.Taylor@Sun.COM 			return (status);
15089517SBill.Taylor@Sun.COM 		}
15099517SBill.Taylor@Sun.COM 		break;
15109517SBill.Taylor@Sun.COM 
15119517SBill.Taylor@Sun.COM 	case IBT_HDL_PD:
15129517SBill.Taylor@Sun.COM 		status = hermon_umap_pd_data_out((hermon_pdhdl_t)hdl,
15139517SBill.Taylor@Sun.COM 		    (mlnx_umap_pd_data_out_t *)data_p, data_sz);
15149517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
15159517SBill.Taylor@Sun.COM 			return (status);
15169517SBill.Taylor@Sun.COM 		}
15179517SBill.Taylor@Sun.COM 		break;
15189517SBill.Taylor@Sun.COM 
15199517SBill.Taylor@Sun.COM 	/*
15209517SBill.Taylor@Sun.COM 	 * For other possible valid IBT types, we return IBT_NOT_SUPPORTED,
15219517SBill.Taylor@Sun.COM 	 * since the Hermon driver does not support these.
15229517SBill.Taylor@Sun.COM 	 */
15239517SBill.Taylor@Sun.COM 	case IBT_HDL_HCA:
15249517SBill.Taylor@Sun.COM 	case IBT_HDL_MR:
15259517SBill.Taylor@Sun.COM 	case IBT_HDL_MW:
15269517SBill.Taylor@Sun.COM 	case IBT_HDL_AH:
15279517SBill.Taylor@Sun.COM 	case IBT_HDL_SCHED:
15289517SBill.Taylor@Sun.COM 	case IBT_HDL_EEC:
15299517SBill.Taylor@Sun.COM 	case IBT_HDL_RDD:
15309517SBill.Taylor@Sun.COM 		return (IBT_NOT_SUPPORTED);
15319517SBill.Taylor@Sun.COM 
15329517SBill.Taylor@Sun.COM 	/*
15339517SBill.Taylor@Sun.COM 	 * Any other types are invalid.
15349517SBill.Taylor@Sun.COM 	 */
15359517SBill.Taylor@Sun.COM 	default:
15369517SBill.Taylor@Sun.COM 		return (IBT_INVALID_PARAM);
15379517SBill.Taylor@Sun.COM 	}
15389517SBill.Taylor@Sun.COM 
15399517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
15409517SBill.Taylor@Sun.COM }
15419517SBill.Taylor@Sun.COM 
15429517SBill.Taylor@Sun.COM 
15439517SBill.Taylor@Sun.COM /*
15449517SBill.Taylor@Sun.COM  * hermon_umap_cq_data_out()
15459517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
15469517SBill.Taylor@Sun.COM  */
15479517SBill.Taylor@Sun.COM static ibt_status_t
hermon_umap_cq_data_out(hermon_cqhdl_t cq,mlnx_umap_cq_data_out_t * data,size_t data_sz)15489517SBill.Taylor@Sun.COM hermon_umap_cq_data_out(hermon_cqhdl_t cq, mlnx_umap_cq_data_out_t *data,
15499517SBill.Taylor@Sun.COM     size_t data_sz)
15509517SBill.Taylor@Sun.COM {
15519517SBill.Taylor@Sun.COM 	/* Check for valid CQ handle pointer */
15529517SBill.Taylor@Sun.COM 	if (cq == NULL) {
15539517SBill.Taylor@Sun.COM 		return (IBT_CQ_HDL_INVALID);
15549517SBill.Taylor@Sun.COM 	}
15559517SBill.Taylor@Sun.COM 
15569517SBill.Taylor@Sun.COM 	/* Check for valid CQ mapping structure size */
15579517SBill.Taylor@Sun.COM 	if (data_sz < sizeof (mlnx_umap_cq_data_out_t)) {
15589517SBill.Taylor@Sun.COM 		return (IBT_INSUFF_RESOURCE);
15599517SBill.Taylor@Sun.COM 	}
15609517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
15619517SBill.Taylor@Sun.COM 
15629517SBill.Taylor@Sun.COM 	/* deal with cq_alloc() verses cq_resize() */
15639517SBill.Taylor@Sun.COM 	if (cq->cq_resize_hdl) {
15649517SBill.Taylor@Sun.COM 		data->mcq_maplen = cq->cq_resize_hdl->cq_cqinfo.qa_size;
15659517SBill.Taylor@Sun.COM 		data->mcq_numcqe = cq->cq_resize_hdl->cq_bufsz;
15669517SBill.Taylor@Sun.COM 	} else {
15679517SBill.Taylor@Sun.COM 		data->mcq_maplen = cq->cq_cqinfo.qa_size;
15689517SBill.Taylor@Sun.COM 		data->mcq_numcqe = cq->cq_bufsz;
15699517SBill.Taylor@Sun.COM 	}
15709517SBill.Taylor@Sun.COM 
15719517SBill.Taylor@Sun.COM 	/*
15729517SBill.Taylor@Sun.COM 	 * If it has passed all the above checks, then fill in all the useful
15739517SBill.Taylor@Sun.COM 	 * mapping information (including the mapping offset that will be
15749517SBill.Taylor@Sun.COM 	 * passed back to the devmap() interface during a subsequent mmap()
15759517SBill.Taylor@Sun.COM 	 * call.
15769517SBill.Taylor@Sun.COM 	 *
15779517SBill.Taylor@Sun.COM 	 * The "offset" for CQ mmap()'s looks like this:
15789517SBill.Taylor@Sun.COM 	 * +----------------------------------------+--------+--------------+
15799517SBill.Taylor@Sun.COM 	 * |		   CQ Number		    |  0x33  | Reserved (0) |
15809517SBill.Taylor@Sun.COM 	 * +----------------------------------------+--------+--------------+
15819517SBill.Taylor@Sun.COM 	 *	   (64 - 8 - PAGESHIFT) bits	    8 bits	PAGESHIFT bits
15829517SBill.Taylor@Sun.COM 	 *
15839517SBill.Taylor@Sun.COM 	 * This returns information about the mapping offset, the length of
15849517SBill.Taylor@Sun.COM 	 * the CQ memory, the CQ number (for use in later CQ doorbells), the
15859517SBill.Taylor@Sun.COM 	 * number of CQEs the CQ memory can hold, and the size of each CQE.
15869517SBill.Taylor@Sun.COM 	 */
15879517SBill.Taylor@Sun.COM 	data->mcq_rev			= MLNX_UMAP_IF_VERSION;
15889517SBill.Taylor@Sun.COM 	data->mcq_mapoffset		= ((((uint64_t)cq->cq_cqnum <<
15899517SBill.Taylor@Sun.COM 	    MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_CQMEM_RSRC) << PAGESHIFT);
15909517SBill.Taylor@Sun.COM 	data->mcq_cqnum			= cq->cq_cqnum;
15919517SBill.Taylor@Sun.COM 	data->mcq_cqesz			= sizeof (hermon_hw_cqe_t);
15929517SBill.Taylor@Sun.COM 
15939517SBill.Taylor@Sun.COM 	/* doorbell record fields */
15949517SBill.Taylor@Sun.COM 	data->mcq_polldbr_mapoffset	= cq->cq_dbr_mapoffset;
15959517SBill.Taylor@Sun.COM 	data->mcq_polldbr_maplen	= PAGESIZE;
15969517SBill.Taylor@Sun.COM 	data->mcq_polldbr_offset	= (uintptr_t)cq->cq_arm_ci_vdbr &
15979517SBill.Taylor@Sun.COM 	    PAGEOFFSET;
15989517SBill.Taylor@Sun.COM 	data->mcq_armdbr_mapoffset	= cq->cq_dbr_mapoffset;
15999517SBill.Taylor@Sun.COM 	data->mcq_armdbr_maplen		= PAGESIZE;
16009517SBill.Taylor@Sun.COM 	data->mcq_armdbr_offset		= data->mcq_polldbr_offset + 4;
16019517SBill.Taylor@Sun.COM 
16029517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
16039517SBill.Taylor@Sun.COM }
16049517SBill.Taylor@Sun.COM 
16059517SBill.Taylor@Sun.COM 
16069517SBill.Taylor@Sun.COM /*
16079517SBill.Taylor@Sun.COM  * hermon_umap_qp_data_out()
16089517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
16099517SBill.Taylor@Sun.COM  */
16109517SBill.Taylor@Sun.COM static ibt_status_t
hermon_umap_qp_data_out(hermon_qphdl_t qp,mlnx_umap_qp_data_out_t * data,size_t data_sz)16119517SBill.Taylor@Sun.COM hermon_umap_qp_data_out(hermon_qphdl_t qp, mlnx_umap_qp_data_out_t *data,
16129517SBill.Taylor@Sun.COM     size_t data_sz)
16139517SBill.Taylor@Sun.COM {
16149517SBill.Taylor@Sun.COM 	/* Check for valid QP handle pointer */
16159517SBill.Taylor@Sun.COM 	if (qp == NULL) {
16169517SBill.Taylor@Sun.COM 		return (IBT_QP_HDL_INVALID);
16179517SBill.Taylor@Sun.COM 	}
16189517SBill.Taylor@Sun.COM 
16199517SBill.Taylor@Sun.COM 	/* Check for valid QP mapping structure size */
16209517SBill.Taylor@Sun.COM 	if (data_sz < sizeof (mlnx_umap_qp_data_out_t)) {
16219517SBill.Taylor@Sun.COM 		return (IBT_INSUFF_RESOURCE);
16229517SBill.Taylor@Sun.COM 	}
16239517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
16249517SBill.Taylor@Sun.COM 
16259517SBill.Taylor@Sun.COM 	/*
16269517SBill.Taylor@Sun.COM 	 * If it has passed all the checks, then fill in all the useful
16279517SBill.Taylor@Sun.COM 	 * mapping information (including the mapping offset that will be
16289517SBill.Taylor@Sun.COM 	 * passed back to the devmap() interface during a subsequent mmap()
16299517SBill.Taylor@Sun.COM 	 * call.
16309517SBill.Taylor@Sun.COM 	 *
16319517SBill.Taylor@Sun.COM 	 * The "offset" for QP mmap()'s looks like this:
16329517SBill.Taylor@Sun.COM 	 * +----------------------------------------+--------+--------------+
16339517SBill.Taylor@Sun.COM 	 * |		   QP Number		    |  0x44  | Reserved (0) |
16349517SBill.Taylor@Sun.COM 	 * +----------------------------------------+--------+--------------+
16359517SBill.Taylor@Sun.COM 	 *	   (64 - 8 - PAGESHIFT) bits	    8 bits	PAGESHIFT bits
16369517SBill.Taylor@Sun.COM 	 *
16379517SBill.Taylor@Sun.COM 	 * This returns information about the mapping offset, the length of
16389517SBill.Taylor@Sun.COM 	 * the QP memory, and the QP number (for use in later send and recv
16399517SBill.Taylor@Sun.COM 	 * doorbells).  It also returns the following information for both
16409517SBill.Taylor@Sun.COM 	 * the receive work queue and the send work queue, respectively:  the
16419517SBill.Taylor@Sun.COM 	 * offset (from the base mapped address) of the start of the given
16429517SBill.Taylor@Sun.COM 	 * work queue, the 64-bit IB virtual address that corresponds to
16439517SBill.Taylor@Sun.COM 	 * the base mapped address (needed for posting WQEs though the
16449517SBill.Taylor@Sun.COM 	 * QP doorbells), the number of WQEs the given work queue can hold,
16459517SBill.Taylor@Sun.COM 	 * and the size of each WQE for the given work queue.
16469517SBill.Taylor@Sun.COM 	 */
16479517SBill.Taylor@Sun.COM 	data->mqp_rev		= MLNX_UMAP_IF_VERSION;
16489517SBill.Taylor@Sun.COM 	data->mqp_mapoffset	= ((((uint64_t)qp->qp_qpnum <<
16499517SBill.Taylor@Sun.COM 	    MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_QPMEM_RSRC) << PAGESHIFT);
16509517SBill.Taylor@Sun.COM 	data->mqp_maplen	= qp->qp_wqinfo.qa_size;
16519517SBill.Taylor@Sun.COM 	data->mqp_qpnum		= qp->qp_qpnum;
16529517SBill.Taylor@Sun.COM 
16539517SBill.Taylor@Sun.COM 	/*
16549517SBill.Taylor@Sun.COM 	 * If this QP is associated with a shared receive queue (SRQ),
16559517SBill.Taylor@Sun.COM 	 * then return invalid RecvQ parameters.  Otherwise, return
16569517SBill.Taylor@Sun.COM 	 * the proper parameter values.
16579517SBill.Taylor@Sun.COM 	 */
1658*12965SWilliam.Taylor@Oracle.COM 	if (qp->qp_alloc_flags & IBT_QP_USES_SRQ) {
16599517SBill.Taylor@Sun.COM 		data->mqp_rq_off	= (uint32_t)qp->qp_wqinfo.qa_size;
16609517SBill.Taylor@Sun.COM 		data->mqp_rq_desc_addr	= (uint32_t)qp->qp_wqinfo.qa_size;
16619517SBill.Taylor@Sun.COM 		data->mqp_rq_numwqe	= 0;
16629517SBill.Taylor@Sun.COM 		data->mqp_rq_wqesz	= 0;
16639517SBill.Taylor@Sun.COM 		data->mqp_rdbr_mapoffset = 0;
16649517SBill.Taylor@Sun.COM 		data->mqp_rdbr_maplen	= 0;
16659517SBill.Taylor@Sun.COM 		data->mqp_rdbr_offset	= 0;
16669517SBill.Taylor@Sun.COM 	} else {
16679517SBill.Taylor@Sun.COM 		data->mqp_rq_off	= (uintptr_t)qp->qp_rq_buf -
16689517SBill.Taylor@Sun.COM 		    (uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
16699517SBill.Taylor@Sun.COM 		data->mqp_rq_desc_addr	= (uint32_t)((uintptr_t)qp->qp_rq_buf -
16709517SBill.Taylor@Sun.COM 		    qp->qp_desc_off);
16719517SBill.Taylor@Sun.COM 		data->mqp_rq_numwqe	= qp->qp_rq_bufsz;
16729517SBill.Taylor@Sun.COM 		data->mqp_rq_wqesz	= (1 << qp->qp_rq_log_wqesz);
16739517SBill.Taylor@Sun.COM 
16749517SBill.Taylor@Sun.COM 		/* doorbell record fields */
16759517SBill.Taylor@Sun.COM 		data->mqp_rdbr_mapoffset = qp->qp_rdbr_mapoffset;
16769517SBill.Taylor@Sun.COM 		data->mqp_rdbr_maplen	= PAGESIZE;
16779517SBill.Taylor@Sun.COM 		data->mqp_rdbr_offset	= (uintptr_t)qp->qp_rq_vdbr &
16789517SBill.Taylor@Sun.COM 		    PAGEOFFSET;
16799517SBill.Taylor@Sun.COM 	}
16809517SBill.Taylor@Sun.COM 	data->mqp_sq_off		= (uintptr_t)qp->qp_sq_buf -
16819517SBill.Taylor@Sun.COM 	    (uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
16829517SBill.Taylor@Sun.COM 	data->mqp_sq_desc_addr	= (uint32_t)((uintptr_t)qp->qp_sq_buf -
16839517SBill.Taylor@Sun.COM 	    qp->qp_desc_off);
16849517SBill.Taylor@Sun.COM 	data->mqp_sq_numwqe	= qp->qp_sq_bufsz;
16859517SBill.Taylor@Sun.COM 	data->mqp_sq_wqesz	= (1 << qp->qp_sq_log_wqesz);
16869517SBill.Taylor@Sun.COM 	data->mqp_sq_headroomwqes = qp->qp_sq_hdrmwqes;
16879517SBill.Taylor@Sun.COM 
16889517SBill.Taylor@Sun.COM 	/* doorbell record fields */
16899517SBill.Taylor@Sun.COM 	data->mqp_sdbr_mapoffset = 0;
16909517SBill.Taylor@Sun.COM 	data->mqp_sdbr_maplen	= 0;
16919517SBill.Taylor@Sun.COM 	data->mqp_sdbr_offset	= 0;
16929517SBill.Taylor@Sun.COM 
16939517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
16949517SBill.Taylor@Sun.COM }
16959517SBill.Taylor@Sun.COM 
16969517SBill.Taylor@Sun.COM 
16979517SBill.Taylor@Sun.COM /*
16989517SBill.Taylor@Sun.COM  * hermon_umap_srq_data_out()
16999517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
17009517SBill.Taylor@Sun.COM  */
17019517SBill.Taylor@Sun.COM static ibt_status_t
hermon_umap_srq_data_out(hermon_srqhdl_t srq,mlnx_umap_srq_data_out_t * data,size_t data_sz)17029517SBill.Taylor@Sun.COM hermon_umap_srq_data_out(hermon_srqhdl_t srq, mlnx_umap_srq_data_out_t *data,
17039517SBill.Taylor@Sun.COM     size_t data_sz)
17049517SBill.Taylor@Sun.COM {
17059517SBill.Taylor@Sun.COM 	/* Check for valid SRQ handle pointer */
17069517SBill.Taylor@Sun.COM 	if (srq == NULL) {
17079517SBill.Taylor@Sun.COM 		return (IBT_SRQ_HDL_INVALID);
17089517SBill.Taylor@Sun.COM 	}
17099517SBill.Taylor@Sun.COM 
17109517SBill.Taylor@Sun.COM 	/* Check for valid SRQ mapping structure size */
17119517SBill.Taylor@Sun.COM 	if (data_sz < sizeof (mlnx_umap_srq_data_out_t)) {
17129517SBill.Taylor@Sun.COM 		return (IBT_INSUFF_RESOURCE);
17139517SBill.Taylor@Sun.COM 	}
17149517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
17159517SBill.Taylor@Sun.COM 
17169517SBill.Taylor@Sun.COM 	/*
17179517SBill.Taylor@Sun.COM 	 * If it has passed all the checks, then fill in all the useful
17189517SBill.Taylor@Sun.COM 	 * mapping information (including the mapping offset that will be
17199517SBill.Taylor@Sun.COM 	 * passed back to the devmap() interface during a subsequent mmap()
17209517SBill.Taylor@Sun.COM 	 * call.
17219517SBill.Taylor@Sun.COM 	 *
17229517SBill.Taylor@Sun.COM 	 * The "offset" for SRQ mmap()'s looks like this:
17239517SBill.Taylor@Sun.COM 	 * +----------------------------------------+--------+--------------+
17249517SBill.Taylor@Sun.COM 	 * |		   SRQ Number		    |  0x66  | Reserved (0) |
17259517SBill.Taylor@Sun.COM 	 * +----------------------------------------+--------+--------------+
17269517SBill.Taylor@Sun.COM 	 *	   (64 - 8 - PAGESHIFT) bits	    8 bits	PAGESHIFT bits
17279517SBill.Taylor@Sun.COM 	 *
17289517SBill.Taylor@Sun.COM 	 * This returns information about the mapping offset, the length of the
17299517SBill.Taylor@Sun.COM 	 * SRQ memory, and the SRQ number (for use in later send and recv
17309517SBill.Taylor@Sun.COM 	 * doorbells).  It also returns the following information for the
17319517SBill.Taylor@Sun.COM 	 * shared receive queue: the offset (from the base mapped address) of
17329517SBill.Taylor@Sun.COM 	 * the start of the given work queue, the 64-bit IB virtual address
17339517SBill.Taylor@Sun.COM 	 * that corresponds to the base mapped address (needed for posting WQEs
17349517SBill.Taylor@Sun.COM 	 * though the QP doorbells), the number of WQEs the given work queue
17359517SBill.Taylor@Sun.COM 	 * can hold, and the size of each WQE for the given work queue.
17369517SBill.Taylor@Sun.COM 	 */
17379517SBill.Taylor@Sun.COM 	data->msrq_rev		= MLNX_UMAP_IF_VERSION;
17389517SBill.Taylor@Sun.COM 	data->msrq_mapoffset	= ((((uint64_t)srq->srq_srqnum <<
17399517SBill.Taylor@Sun.COM 	    MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_SRQMEM_RSRC) << PAGESHIFT);
17409517SBill.Taylor@Sun.COM 	data->msrq_maplen	= srq->srq_wqinfo.qa_size;
17419517SBill.Taylor@Sun.COM 	data->msrq_srqnum	= srq->srq_srqnum;
17429517SBill.Taylor@Sun.COM 
17439517SBill.Taylor@Sun.COM 	data->msrq_desc_addr	= (uint32_t)((uintptr_t)srq->srq_wq_buf -
17449517SBill.Taylor@Sun.COM 	    srq->srq_desc_off);
17459517SBill.Taylor@Sun.COM 	data->msrq_numwqe	= srq->srq_wq_bufsz;
17469517SBill.Taylor@Sun.COM 	data->msrq_wqesz	= (1 << srq->srq_wq_log_wqesz);
17479517SBill.Taylor@Sun.COM 
17489517SBill.Taylor@Sun.COM 	/* doorbell record fields */
17499517SBill.Taylor@Sun.COM 	data->msrq_rdbr_mapoffset = srq->srq_rdbr_mapoffset;
17509517SBill.Taylor@Sun.COM 	data->msrq_rdbr_maplen	= PAGESIZE;
17519517SBill.Taylor@Sun.COM 	data->msrq_rdbr_offset	= (uintptr_t)srq->srq_wq_vdbr &
17529517SBill.Taylor@Sun.COM 	    PAGEOFFSET;
17539517SBill.Taylor@Sun.COM 
17549517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
17559517SBill.Taylor@Sun.COM }
17569517SBill.Taylor@Sun.COM 
17579517SBill.Taylor@Sun.COM 
17589517SBill.Taylor@Sun.COM /*
17599517SBill.Taylor@Sun.COM  * hermon_umap_pd_data_out()
17609517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
17619517SBill.Taylor@Sun.COM  */
17629517SBill.Taylor@Sun.COM static ibt_status_t
hermon_umap_pd_data_out(hermon_pdhdl_t pd,mlnx_umap_pd_data_out_t * data,size_t data_sz)17639517SBill.Taylor@Sun.COM hermon_umap_pd_data_out(hermon_pdhdl_t pd, mlnx_umap_pd_data_out_t *data,
17649517SBill.Taylor@Sun.COM     size_t data_sz)
17659517SBill.Taylor@Sun.COM {
17669517SBill.Taylor@Sun.COM 	/* Check for valid PD handle pointer */
17679517SBill.Taylor@Sun.COM 	if (pd == NULL) {
17689517SBill.Taylor@Sun.COM 		return (IBT_PD_HDL_INVALID);
17699517SBill.Taylor@Sun.COM 	}
17709517SBill.Taylor@Sun.COM 
17719517SBill.Taylor@Sun.COM 	/* Check for valid PD mapping structure size */
17729517SBill.Taylor@Sun.COM 	if (data_sz < sizeof (mlnx_umap_pd_data_out_t)) {
17739517SBill.Taylor@Sun.COM 		return (IBT_INSUFF_RESOURCE);
17749517SBill.Taylor@Sun.COM 	}
17759517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
17769517SBill.Taylor@Sun.COM 
17779517SBill.Taylor@Sun.COM 	/*
17789517SBill.Taylor@Sun.COM 	 * If it has passed all the checks, then fill the PD table index
17799517SBill.Taylor@Sun.COM 	 * (the PD table allocated index for the PD pd_pdnum).
17809517SBill.Taylor@Sun.COM 	 */
17819517SBill.Taylor@Sun.COM 	data->mpd_rev		= MLNX_UMAP_IF_VERSION;
17829517SBill.Taylor@Sun.COM 	data->mpd_pdnum		= pd->pd_pdnum;
17839517SBill.Taylor@Sun.COM 
17849517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
17859517SBill.Taylor@Sun.COM }
17869517SBill.Taylor@Sun.COM 
17879517SBill.Taylor@Sun.COM 
17889517SBill.Taylor@Sun.COM /*
17899517SBill.Taylor@Sun.COM  * hermon_umap_db_init()
17909517SBill.Taylor@Sun.COM  *    Context: Only called from attach() path context
17919517SBill.Taylor@Sun.COM  */
17929517SBill.Taylor@Sun.COM void
hermon_umap_db_init(void)17939517SBill.Taylor@Sun.COM hermon_umap_db_init(void)
17949517SBill.Taylor@Sun.COM {
17959517SBill.Taylor@Sun.COM 	/*
17969517SBill.Taylor@Sun.COM 	 * Initialize the lock used by the Hermon "userland resources database"
17979517SBill.Taylor@Sun.COM 	 * This is used to ensure atomic access to add, remove, and find
17989517SBill.Taylor@Sun.COM 	 * entries in the database.
17999517SBill.Taylor@Sun.COM 	 */
18009517SBill.Taylor@Sun.COM 	mutex_init(&hermon_userland_rsrc_db.hdl_umapdb_lock, NULL,
18019517SBill.Taylor@Sun.COM 	    MUTEX_DRIVER, NULL);
18029517SBill.Taylor@Sun.COM 
18039517SBill.Taylor@Sun.COM 	/*
18049517SBill.Taylor@Sun.COM 	 * Initialize the AVL tree used for the "userland resources
18059517SBill.Taylor@Sun.COM 	 * database".  Using an AVL tree here provides the ability to
18069517SBill.Taylor@Sun.COM 	 * scale the database size to large numbers of resources.  The
18079517SBill.Taylor@Sun.COM 	 * entries in the tree are "hermon_umap_db_entry_t" (see
18089517SBill.Taylor@Sun.COM 	 * hermon_umap.h).  The tree is searched with the help of the
18099517SBill.Taylor@Sun.COM 	 * hermon_umap_db_compare() routine.
18109517SBill.Taylor@Sun.COM 	 */
18119517SBill.Taylor@Sun.COM 	avl_create(&hermon_userland_rsrc_db.hdl_umapdb_avl,
18129517SBill.Taylor@Sun.COM 	    hermon_umap_db_compare, sizeof (hermon_umap_db_entry_t),
18139517SBill.Taylor@Sun.COM 	    offsetof(hermon_umap_db_entry_t, hdbe_avlnode));
18149517SBill.Taylor@Sun.COM }
18159517SBill.Taylor@Sun.COM 
18169517SBill.Taylor@Sun.COM 
18179517SBill.Taylor@Sun.COM /*
18189517SBill.Taylor@Sun.COM  * hermon_umap_db_fini()
18199517SBill.Taylor@Sun.COM  *    Context: Only called from attach() and/or detach() path contexts
18209517SBill.Taylor@Sun.COM  */
18219517SBill.Taylor@Sun.COM void
hermon_umap_db_fini(void)18229517SBill.Taylor@Sun.COM hermon_umap_db_fini(void)
18239517SBill.Taylor@Sun.COM {
18249517SBill.Taylor@Sun.COM 	/* Destroy the AVL tree for the "userland resources database" */
18259517SBill.Taylor@Sun.COM 	avl_destroy(&hermon_userland_rsrc_db.hdl_umapdb_avl);
18269517SBill.Taylor@Sun.COM 
18279517SBill.Taylor@Sun.COM 	/* Destroy the lock for the "userland resources database" */
18289517SBill.Taylor@Sun.COM 	mutex_destroy(&hermon_userland_rsrc_db.hdl_umapdb_lock);
18299517SBill.Taylor@Sun.COM }
18309517SBill.Taylor@Sun.COM 
18319517SBill.Taylor@Sun.COM 
18329517SBill.Taylor@Sun.COM /*
18339517SBill.Taylor@Sun.COM  * hermon_umap_db_alloc()
18349517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
18359517SBill.Taylor@Sun.COM  */
18369517SBill.Taylor@Sun.COM hermon_umap_db_entry_t *
hermon_umap_db_alloc(uint_t instance,uint64_t key,uint_t type,uint64_t value)18379517SBill.Taylor@Sun.COM hermon_umap_db_alloc(uint_t instance, uint64_t key, uint_t type, uint64_t value)
18389517SBill.Taylor@Sun.COM {
18399517SBill.Taylor@Sun.COM 	hermon_umap_db_entry_t	*umapdb;
18409517SBill.Taylor@Sun.COM 
18419517SBill.Taylor@Sun.COM 	/* Allocate an entry to add to the "userland resources database" */
18429517SBill.Taylor@Sun.COM 	umapdb = kmem_zalloc(sizeof (hermon_umap_db_entry_t), KM_NOSLEEP);
18439517SBill.Taylor@Sun.COM 	if (umapdb == NULL) {
18449517SBill.Taylor@Sun.COM 		return (NULL);
18459517SBill.Taylor@Sun.COM 	}
18469517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*umapdb))
18479517SBill.Taylor@Sun.COM 
18489517SBill.Taylor@Sun.COM 	/* Fill in the fields in the database entry */
18499517SBill.Taylor@Sun.COM 	umapdb->hdbe_common.hdb_instance  = instance;
18509517SBill.Taylor@Sun.COM 	umapdb->hdbe_common.hdb_type	  = type;
18519517SBill.Taylor@Sun.COM 	umapdb->hdbe_common.hdb_key	  = key;
18529517SBill.Taylor@Sun.COM 	umapdb->hdbe_common.hdb_value	  = value;
18539517SBill.Taylor@Sun.COM 
18549517SBill.Taylor@Sun.COM 	return (umapdb);
18559517SBill.Taylor@Sun.COM }
18569517SBill.Taylor@Sun.COM 
18579517SBill.Taylor@Sun.COM 
18589517SBill.Taylor@Sun.COM /*
18599517SBill.Taylor@Sun.COM  * hermon_umap_db_free()
18609517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
18619517SBill.Taylor@Sun.COM  */
18629517SBill.Taylor@Sun.COM void
hermon_umap_db_free(hermon_umap_db_entry_t * umapdb)18639517SBill.Taylor@Sun.COM hermon_umap_db_free(hermon_umap_db_entry_t *umapdb)
18649517SBill.Taylor@Sun.COM {
18659517SBill.Taylor@Sun.COM 	/* Free the database entry */
18669517SBill.Taylor@Sun.COM 	kmem_free(umapdb, sizeof (hermon_umap_db_entry_t));
18679517SBill.Taylor@Sun.COM }
18689517SBill.Taylor@Sun.COM 
18699517SBill.Taylor@Sun.COM 
18709517SBill.Taylor@Sun.COM /*
18719517SBill.Taylor@Sun.COM  * hermon_umap_db_add()
18729517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
18739517SBill.Taylor@Sun.COM  */
18749517SBill.Taylor@Sun.COM void
hermon_umap_db_add(hermon_umap_db_entry_t * umapdb)18759517SBill.Taylor@Sun.COM hermon_umap_db_add(hermon_umap_db_entry_t *umapdb)
18769517SBill.Taylor@Sun.COM {
18779517SBill.Taylor@Sun.COM 	mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
18789517SBill.Taylor@Sun.COM 	hermon_umap_db_add_nolock(umapdb);
18799517SBill.Taylor@Sun.COM 	mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
18809517SBill.Taylor@Sun.COM }
18819517SBill.Taylor@Sun.COM 
18829517SBill.Taylor@Sun.COM 
18839517SBill.Taylor@Sun.COM /*
18849517SBill.Taylor@Sun.COM  * hermon_umap_db_add_nolock()
18859517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
18869517SBill.Taylor@Sun.COM  */
18879517SBill.Taylor@Sun.COM void
hermon_umap_db_add_nolock(hermon_umap_db_entry_t * umapdb)18889517SBill.Taylor@Sun.COM hermon_umap_db_add_nolock(hermon_umap_db_entry_t *umapdb)
18899517SBill.Taylor@Sun.COM {
18909517SBill.Taylor@Sun.COM 	hermon_umap_db_query_t	query;
18919517SBill.Taylor@Sun.COM 	avl_index_t		where;
18929517SBill.Taylor@Sun.COM 
18939517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&hermon_userland_rsrc_db.hdl_umapdb_lock));
18949517SBill.Taylor@Sun.COM 
18959517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*umapdb))
18969517SBill.Taylor@Sun.COM 
18979517SBill.Taylor@Sun.COM 	/*
18989517SBill.Taylor@Sun.COM 	 * Copy the common portion of the "to-be-added" database entry
18999517SBill.Taylor@Sun.COM 	 * into the "hermon_umap_db_query_t" structure.  We use this structure
19009517SBill.Taylor@Sun.COM 	 * (with no flags set) to find the appropriate location in the
19019517SBill.Taylor@Sun.COM 	 * "userland resources database" for the new entry to be added.
19029517SBill.Taylor@Sun.COM 	 *
19039517SBill.Taylor@Sun.COM 	 * Note: we expect that this entry should not be found in the
19049517SBill.Taylor@Sun.COM 	 * database (unless something bad has happened).
19059517SBill.Taylor@Sun.COM 	 */
19069517SBill.Taylor@Sun.COM 	query.hqdb_common = umapdb->hdbe_common;
19079517SBill.Taylor@Sun.COM 	query.hqdb_flags  = 0;
19089517SBill.Taylor@Sun.COM 	(void) avl_find(&hermon_userland_rsrc_db.hdl_umapdb_avl, &query,
19099517SBill.Taylor@Sun.COM 	    &where);
19109517SBill.Taylor@Sun.COM 
19119517SBill.Taylor@Sun.COM 	/*
19129517SBill.Taylor@Sun.COM 	 * Now, using the "where" field from the avl_find() operation
19139517SBill.Taylor@Sun.COM 	 * above, we will insert the new database entry ("umapdb").
19149517SBill.Taylor@Sun.COM 	 */
19159517SBill.Taylor@Sun.COM 	avl_insert(&hermon_userland_rsrc_db.hdl_umapdb_avl, umapdb,
19169517SBill.Taylor@Sun.COM 	    where);
19179517SBill.Taylor@Sun.COM }
19189517SBill.Taylor@Sun.COM 
19199517SBill.Taylor@Sun.COM 
19209517SBill.Taylor@Sun.COM /*
19219517SBill.Taylor@Sun.COM  * hermon_umap_db_find()
19229517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
19239517SBill.Taylor@Sun.COM  */
19249517SBill.Taylor@Sun.COM int
hermon_umap_db_find(uint_t instance,uint64_t key,uint_t type,uint64_t * value,uint_t flag,hermon_umap_db_entry_t ** umapdb)19259517SBill.Taylor@Sun.COM hermon_umap_db_find(uint_t instance, uint64_t key, uint_t type,
19269517SBill.Taylor@Sun.COM     uint64_t *value, uint_t flag, hermon_umap_db_entry_t	**umapdb)
19279517SBill.Taylor@Sun.COM {
19289517SBill.Taylor@Sun.COM 	int	status;
19299517SBill.Taylor@Sun.COM 
19309517SBill.Taylor@Sun.COM 	mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
19319517SBill.Taylor@Sun.COM 	status = hermon_umap_db_find_nolock(instance, key, type, value, flag,
19329517SBill.Taylor@Sun.COM 	    umapdb);
19339517SBill.Taylor@Sun.COM 	mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
19349517SBill.Taylor@Sun.COM 
19359517SBill.Taylor@Sun.COM 	return (status);
19369517SBill.Taylor@Sun.COM }
19379517SBill.Taylor@Sun.COM 
19389517SBill.Taylor@Sun.COM 
19399517SBill.Taylor@Sun.COM /*
19409517SBill.Taylor@Sun.COM  * hermon_umap_db_find_nolock()
19419517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
19429517SBill.Taylor@Sun.COM  */
19439517SBill.Taylor@Sun.COM int
hermon_umap_db_find_nolock(uint_t instance,uint64_t key,uint_t type,uint64_t * value,uint_t flags,hermon_umap_db_entry_t ** umapdb)19449517SBill.Taylor@Sun.COM hermon_umap_db_find_nolock(uint_t instance, uint64_t key, uint_t type,
19459517SBill.Taylor@Sun.COM     uint64_t *value, uint_t flags, hermon_umap_db_entry_t **umapdb)
19469517SBill.Taylor@Sun.COM {
19479517SBill.Taylor@Sun.COM 	hermon_umap_db_query_t	query;
19489517SBill.Taylor@Sun.COM 	hermon_umap_db_entry_t	*entry;
19499517SBill.Taylor@Sun.COM 	avl_index_t		where;
19509517SBill.Taylor@Sun.COM 
19519517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&hermon_userland_rsrc_db.hdl_umapdb_lock));
19529517SBill.Taylor@Sun.COM 
19539517SBill.Taylor@Sun.COM 	/*
19549517SBill.Taylor@Sun.COM 	 * Fill in key, type, instance, and flags values of the
19559517SBill.Taylor@Sun.COM 	 * hermon_umap_db_query_t in preparation for the database
19569517SBill.Taylor@Sun.COM 	 * lookup.
19579517SBill.Taylor@Sun.COM 	 */
19589517SBill.Taylor@Sun.COM 	query.hqdb_flags		= flags;
19599517SBill.Taylor@Sun.COM 	query.hqdb_common.hdb_key	= key;
19609517SBill.Taylor@Sun.COM 	query.hqdb_common.hdb_type	= type;
19619517SBill.Taylor@Sun.COM 	query.hqdb_common.hdb_instance	= instance;
19629517SBill.Taylor@Sun.COM 
19639517SBill.Taylor@Sun.COM 	/*
19649517SBill.Taylor@Sun.COM 	 * Perform the database query.  If no entry is found, then
19659517SBill.Taylor@Sun.COM 	 * return failure, else continue.
19669517SBill.Taylor@Sun.COM 	 */
19679517SBill.Taylor@Sun.COM 	entry = (hermon_umap_db_entry_t *)avl_find(
19689517SBill.Taylor@Sun.COM 	    &hermon_userland_rsrc_db.hdl_umapdb_avl, &query, &where);
19699517SBill.Taylor@Sun.COM 	if (entry == NULL) {
19709517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
19719517SBill.Taylor@Sun.COM 	}
19729517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*entry))
19739517SBill.Taylor@Sun.COM 
19749517SBill.Taylor@Sun.COM 	/*
19759517SBill.Taylor@Sun.COM 	 * If the flags argument specifies that the entry should
19769517SBill.Taylor@Sun.COM 	 * be removed if found, then call avl_remove() to remove
19779517SBill.Taylor@Sun.COM 	 * the entry from the database.
19789517SBill.Taylor@Sun.COM 	 */
19799517SBill.Taylor@Sun.COM 	if (flags & HERMON_UMAP_DB_REMOVE) {
19809517SBill.Taylor@Sun.COM 
19819517SBill.Taylor@Sun.COM 		avl_remove(&hermon_userland_rsrc_db.hdl_umapdb_avl, entry);
19829517SBill.Taylor@Sun.COM 
19839517SBill.Taylor@Sun.COM 		/*
19849517SBill.Taylor@Sun.COM 		 * The database entry is returned with the expectation
19859517SBill.Taylor@Sun.COM 		 * that the caller will use hermon_umap_db_free() to
19869517SBill.Taylor@Sun.COM 		 * free the entry's memory.  ASSERT that this is non-NULL.
19879517SBill.Taylor@Sun.COM 		 * NULL pointer should never be passed for the
19889517SBill.Taylor@Sun.COM 		 * HERMON_UMAP_DB_REMOVE case.
19899517SBill.Taylor@Sun.COM 		 */
19909517SBill.Taylor@Sun.COM 		ASSERT(umapdb != NULL);
19919517SBill.Taylor@Sun.COM 	}
19929517SBill.Taylor@Sun.COM 
19939517SBill.Taylor@Sun.COM 	/*
19949517SBill.Taylor@Sun.COM 	 * If the caller would like visibility to the database entry
19959517SBill.Taylor@Sun.COM 	 * (indicated through the use of a non-NULL "umapdb" argument),
19969517SBill.Taylor@Sun.COM 	 * then fill it in.
19979517SBill.Taylor@Sun.COM 	 */
19989517SBill.Taylor@Sun.COM 	if (umapdb != NULL) {
19999517SBill.Taylor@Sun.COM 		*umapdb = entry;
20009517SBill.Taylor@Sun.COM 	}
20019517SBill.Taylor@Sun.COM 
20029517SBill.Taylor@Sun.COM 	/* Extract value field from database entry and return success */
20039517SBill.Taylor@Sun.COM 	*value = entry->hdbe_common.hdb_value;
20049517SBill.Taylor@Sun.COM 
20059517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
20069517SBill.Taylor@Sun.COM }
20079517SBill.Taylor@Sun.COM 
20089517SBill.Taylor@Sun.COM 
20099517SBill.Taylor@Sun.COM /*
20109517SBill.Taylor@Sun.COM  * hermon_umap_umemlock_cb()
20119517SBill.Taylor@Sun.COM  *    Context: Can be called from callback context.
20129517SBill.Taylor@Sun.COM  */
20139517SBill.Taylor@Sun.COM void
hermon_umap_umemlock_cb(ddi_umem_cookie_t * umem_cookie)20149517SBill.Taylor@Sun.COM hermon_umap_umemlock_cb(ddi_umem_cookie_t *umem_cookie)
20159517SBill.Taylor@Sun.COM {
20169517SBill.Taylor@Sun.COM 	hermon_umap_db_entry_t	*umapdb;
20179517SBill.Taylor@Sun.COM 	hermon_state_t		*state;
20189517SBill.Taylor@Sun.COM 	hermon_rsrc_t 		*rsrcp;
20199517SBill.Taylor@Sun.COM 	hermon_mrhdl_t		mr;
20209517SBill.Taylor@Sun.COM 	uint64_t		value;
20219517SBill.Taylor@Sun.COM 	uint_t			instance;
20229517SBill.Taylor@Sun.COM 	int			status;
20239517SBill.Taylor@Sun.COM 	void			(*mr_callback)(void *, void *);
20249517SBill.Taylor@Sun.COM 	void			*mr_cbarg1, *mr_cbarg2;
20259517SBill.Taylor@Sun.COM 
20269517SBill.Taylor@Sun.COM 	/*
20279517SBill.Taylor@Sun.COM 	 * If this was userland memory, then we need to remove its entry
20289517SBill.Taylor@Sun.COM 	 * from the "userland resources database".  Note:  We use the
20299517SBill.Taylor@Sun.COM 	 * HERMON_UMAP_DB_IGNORE_INSTANCE flag here because we don't know
20309517SBill.Taylor@Sun.COM 	 * which instance was used when the entry was added (but we want
20319517SBill.Taylor@Sun.COM 	 * to know after the entry is found using the other search criteria).
20329517SBill.Taylor@Sun.COM 	 */
20339517SBill.Taylor@Sun.COM 	status = hermon_umap_db_find(0, (uint64_t)(uintptr_t)umem_cookie,
20349517SBill.Taylor@Sun.COM 	    MLNX_UMAP_MRMEM_RSRC, &value, (HERMON_UMAP_DB_REMOVE |
20359517SBill.Taylor@Sun.COM 	    HERMON_UMAP_DB_IGNORE_INSTANCE), &umapdb);
20369517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*umapdb))
20379517SBill.Taylor@Sun.COM 	if (status == DDI_SUCCESS) {
20389517SBill.Taylor@Sun.COM 		instance = umapdb->hdbe_common.hdb_instance;
20399517SBill.Taylor@Sun.COM 		state = ddi_get_soft_state(hermon_statep, instance);
20409517SBill.Taylor@Sun.COM 		if (state == NULL) {
20419517SBill.Taylor@Sun.COM 			cmn_err(CE_WARN, "Unable to match Hermon instance\n");
20429517SBill.Taylor@Sun.COM 			return;
20439517SBill.Taylor@Sun.COM 		}
20449517SBill.Taylor@Sun.COM 
20459517SBill.Taylor@Sun.COM 		/* Free the database entry */
20469517SBill.Taylor@Sun.COM 		hermon_umap_db_free(umapdb);
20479517SBill.Taylor@Sun.COM 
20489517SBill.Taylor@Sun.COM 		/* Use "value" to convert to an MR handle */
20499517SBill.Taylor@Sun.COM 		rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
20509517SBill.Taylor@Sun.COM 		mr = (hermon_mrhdl_t)rsrcp->hr_addr;
20519517SBill.Taylor@Sun.COM 
20529517SBill.Taylor@Sun.COM 		/*
20539517SBill.Taylor@Sun.COM 		 * If a callback has been provided, call it first.  This
20549517SBill.Taylor@Sun.COM 		 * callback is expected to do any cleanup necessary to
20559517SBill.Taylor@Sun.COM 		 * guarantee that the subsequent MR deregister (below)
20569517SBill.Taylor@Sun.COM 		 * will succeed.  Specifically, this means freeing up memory
20579517SBill.Taylor@Sun.COM 		 * windows which might have been associated with the MR.
20589517SBill.Taylor@Sun.COM 		 */
20599517SBill.Taylor@Sun.COM 		mutex_enter(&mr->mr_lock);
20609517SBill.Taylor@Sun.COM 		mr_callback = mr->mr_umem_cbfunc;
20619517SBill.Taylor@Sun.COM 		mr_cbarg1   = mr->mr_umem_cbarg1;
20629517SBill.Taylor@Sun.COM 		mr_cbarg2   = mr->mr_umem_cbarg2;
20639517SBill.Taylor@Sun.COM 		mutex_exit(&mr->mr_lock);
20649517SBill.Taylor@Sun.COM 		if (mr_callback != NULL) {
20659517SBill.Taylor@Sun.COM 			mr_callback(mr_cbarg1, mr_cbarg2);
20669517SBill.Taylor@Sun.COM 		}
20679517SBill.Taylor@Sun.COM 
20689517SBill.Taylor@Sun.COM 		/*
20699517SBill.Taylor@Sun.COM 		 * Then call hermon_mr_deregister() to release the resources
20709517SBill.Taylor@Sun.COM 		 * associated with the MR handle.  Note: Because this routine
20719517SBill.Taylor@Sun.COM 		 * will also check for whether the ddi_umem_cookie_t is in the
20729517SBill.Taylor@Sun.COM 		 * database, it will take responsibility for disabling the
20739517SBill.Taylor@Sun.COM 		 * memory region and calling ddi_umem_unlock().
20749517SBill.Taylor@Sun.COM 		 */
20759517SBill.Taylor@Sun.COM 		status = hermon_mr_deregister(state, &mr, HERMON_MR_DEREG_ALL,
20769517SBill.Taylor@Sun.COM 		    HERMON_SLEEP);
20779517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
20789517SBill.Taylor@Sun.COM 			HERMON_WARNING(state, "Unexpected failure in "
20799517SBill.Taylor@Sun.COM 			    "deregister from callback\n");
20809517SBill.Taylor@Sun.COM 		}
20819517SBill.Taylor@Sun.COM 	}
20829517SBill.Taylor@Sun.COM }
20839517SBill.Taylor@Sun.COM 
20849517SBill.Taylor@Sun.COM 
20859517SBill.Taylor@Sun.COM /*
20869517SBill.Taylor@Sun.COM  * hermon_umap_db_compare()
20879517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
20889517SBill.Taylor@Sun.COM  */
20899517SBill.Taylor@Sun.COM static int
hermon_umap_db_compare(const void * q,const void * e)20909517SBill.Taylor@Sun.COM hermon_umap_db_compare(const void *q, const void *e)
20919517SBill.Taylor@Sun.COM {
20929517SBill.Taylor@Sun.COM 	hermon_umap_db_common_t	*entry_common, *query_common;
20939517SBill.Taylor@Sun.COM 	uint_t			query_flags;
20949517SBill.Taylor@Sun.COM 
20959517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((hermon_umap_db_query_t *)q)))
20969517SBill.Taylor@Sun.COM 
20979517SBill.Taylor@Sun.COM 	entry_common = &((hermon_umap_db_entry_t *)e)->hdbe_common;
20989517SBill.Taylor@Sun.COM 	query_common = &((hermon_umap_db_query_t *)q)->hqdb_common;
20999517SBill.Taylor@Sun.COM 	query_flags  = ((hermon_umap_db_query_t *)q)->hqdb_flags;
21009517SBill.Taylor@Sun.COM 
21019517SBill.Taylor@Sun.COM 	/*
21029517SBill.Taylor@Sun.COM 	 * The first comparison is done on the "key" value in "query"
21039517SBill.Taylor@Sun.COM 	 * and "entry".  If they are not equal, then the appropriate
21049517SBill.Taylor@Sun.COM 	 * search direction is returned.  Else, we continue by
21059517SBill.Taylor@Sun.COM 	 * comparing "type".
21069517SBill.Taylor@Sun.COM 	 */
21079517SBill.Taylor@Sun.COM 	if (query_common->hdb_key < entry_common->hdb_key) {
21089517SBill.Taylor@Sun.COM 		return (-1);
21099517SBill.Taylor@Sun.COM 	} else if (query_common->hdb_key > entry_common->hdb_key) {
21109517SBill.Taylor@Sun.COM 		return (+1);
21119517SBill.Taylor@Sun.COM 	}
21129517SBill.Taylor@Sun.COM 
21139517SBill.Taylor@Sun.COM 	/*
21149517SBill.Taylor@Sun.COM 	 * If the search reaches this point, then "query" and "entry"
21159517SBill.Taylor@Sun.COM 	 * have equal key values.  So we continue be comparing their
21169517SBill.Taylor@Sun.COM 	 * "type" values.  Again, if they are not equal, then the
21179517SBill.Taylor@Sun.COM 	 * appropriate search direction is returned.  Else, we continue
21189517SBill.Taylor@Sun.COM 	 * by comparing "instance".
21199517SBill.Taylor@Sun.COM 	 */
21209517SBill.Taylor@Sun.COM 	if (query_common->hdb_type < entry_common->hdb_type) {
21219517SBill.Taylor@Sun.COM 		return (-1);
21229517SBill.Taylor@Sun.COM 	} else if (query_common->hdb_type > entry_common->hdb_type) {
21239517SBill.Taylor@Sun.COM 		return (+1);
21249517SBill.Taylor@Sun.COM 	}
21259517SBill.Taylor@Sun.COM 
21269517SBill.Taylor@Sun.COM 	/*
21279517SBill.Taylor@Sun.COM 	 * If the search reaches this point, then "query" and "entry"
21289517SBill.Taylor@Sun.COM 	 * have exactly the same key and type values.  Now we consult
21299517SBill.Taylor@Sun.COM 	 * the "flags" field in the query to determine whether the
21309517SBill.Taylor@Sun.COM 	 * "instance" is relevant to the search.  If the
21319517SBill.Taylor@Sun.COM 	 * HERMON_UMAP_DB_IGNORE_INSTANCE flags is set, then return
21329517SBill.Taylor@Sun.COM 	 * success (0) here.  Otherwise, continue the search by comparing
21339517SBill.Taylor@Sun.COM 	 * instance values and returning the appropriate search direction.
21349517SBill.Taylor@Sun.COM 	 */
21359517SBill.Taylor@Sun.COM 	if (query_flags & HERMON_UMAP_DB_IGNORE_INSTANCE) {
21369517SBill.Taylor@Sun.COM 		return (0);
21379517SBill.Taylor@Sun.COM 	}
21389517SBill.Taylor@Sun.COM 
21399517SBill.Taylor@Sun.COM 	/*
21409517SBill.Taylor@Sun.COM 	 * If the search has reached this point, then "query" and "entry"
21419517SBill.Taylor@Sun.COM 	 * can only be differentiated by their instance values.  If these
21429517SBill.Taylor@Sun.COM 	 * are not equal, then return the appropriate search direction.
21439517SBill.Taylor@Sun.COM 	 * Else, we return success (0).
21449517SBill.Taylor@Sun.COM 	 */
21459517SBill.Taylor@Sun.COM 	if (query_common->hdb_instance < entry_common->hdb_instance) {
21469517SBill.Taylor@Sun.COM 		return (-1);
21479517SBill.Taylor@Sun.COM 	} else if (query_common->hdb_instance > entry_common->hdb_instance) {
21489517SBill.Taylor@Sun.COM 		return (+1);
21499517SBill.Taylor@Sun.COM 	}
21509517SBill.Taylor@Sun.COM 
21519517SBill.Taylor@Sun.COM 	/* Everything matches... so return success */
21529517SBill.Taylor@Sun.COM 	return (0);
21539517SBill.Taylor@Sun.COM }
21549517SBill.Taylor@Sun.COM 
21559517SBill.Taylor@Sun.COM 
21569517SBill.Taylor@Sun.COM /*
21579517SBill.Taylor@Sun.COM  * hermon_umap_db_set_onclose_cb()
21589517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
21599517SBill.Taylor@Sun.COM  */
21609517SBill.Taylor@Sun.COM int
hermon_umap_db_set_onclose_cb(dev_t dev,uint64_t flag,int (* callback)(void *),void * arg)21619517SBill.Taylor@Sun.COM hermon_umap_db_set_onclose_cb(dev_t dev, uint64_t flag,
21629517SBill.Taylor@Sun.COM     int (*callback)(void *), void *arg)
21639517SBill.Taylor@Sun.COM {
21649517SBill.Taylor@Sun.COM 	hermon_umap_db_priv_t	*priv;
21659517SBill.Taylor@Sun.COM 	hermon_umap_db_entry_t	*umapdb;
21669517SBill.Taylor@Sun.COM 	minor_t			instance;
21679517SBill.Taylor@Sun.COM 	uint64_t		value;
21689517SBill.Taylor@Sun.COM 	int			status;
21699517SBill.Taylor@Sun.COM 
21709517SBill.Taylor@Sun.COM 	instance = HERMON_DEV_INSTANCE(dev);
21719517SBill.Taylor@Sun.COM 	if (instance == (minor_t)-1) {
21729517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
21739517SBill.Taylor@Sun.COM 	}
21749517SBill.Taylor@Sun.COM 
21759517SBill.Taylor@Sun.COM 	if (flag != HERMON_ONCLOSE_FLASH_INPROGRESS) {
21769517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
21779517SBill.Taylor@Sun.COM 	}
21789517SBill.Taylor@Sun.COM 
21799517SBill.Taylor@Sun.COM 	/*
21809517SBill.Taylor@Sun.COM 	 * Grab the lock for the "userland resources database" and find
21819517SBill.Taylor@Sun.COM 	 * the entry corresponding to this minor number.  Once it's found,
21829517SBill.Taylor@Sun.COM 	 * allocate (if necessary) and add an entry (in the "hdb_priv"
21839517SBill.Taylor@Sun.COM 	 * field) to indicate that further processing may be needed during
21849517SBill.Taylor@Sun.COM 	 * Hermon's close() handling.
21859517SBill.Taylor@Sun.COM 	 */
21869517SBill.Taylor@Sun.COM 	mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
21879517SBill.Taylor@Sun.COM 	status = hermon_umap_db_find_nolock(instance, dev,
21889517SBill.Taylor@Sun.COM 	    MLNX_UMAP_PID_RSRC, &value, 0, &umapdb);
21899517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
21909517SBill.Taylor@Sun.COM 		mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
21919517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
21929517SBill.Taylor@Sun.COM 	}
21939517SBill.Taylor@Sun.COM 
21949517SBill.Taylor@Sun.COM 	priv = (hermon_umap_db_priv_t *)umapdb->hdbe_common.hdb_priv;
21959517SBill.Taylor@Sun.COM 	if (priv == NULL) {
21969517SBill.Taylor@Sun.COM 		priv = (hermon_umap_db_priv_t *)kmem_zalloc(
21979517SBill.Taylor@Sun.COM 		    sizeof (hermon_umap_db_priv_t), KM_NOSLEEP);
21989517SBill.Taylor@Sun.COM 		if (priv == NULL) {
21999517SBill.Taylor@Sun.COM 			mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
22009517SBill.Taylor@Sun.COM 			return (DDI_FAILURE);
22019517SBill.Taylor@Sun.COM 		}
22029517SBill.Taylor@Sun.COM 	}
22039517SBill.Taylor@Sun.COM 
22049517SBill.Taylor@Sun.COM 	/*
22059517SBill.Taylor@Sun.COM 	 * Save away the callback and argument to be used during Hermon's
22069517SBill.Taylor@Sun.COM 	 * close() processing.
22079517SBill.Taylor@Sun.COM 	 */
22089517SBill.Taylor@Sun.COM 	priv->hdp_cb	= callback;
22099517SBill.Taylor@Sun.COM 	priv->hdp_arg	= arg;
22109517SBill.Taylor@Sun.COM 
22119517SBill.Taylor@Sun.COM 	umapdb->hdbe_common.hdb_priv = (void *)priv;
22129517SBill.Taylor@Sun.COM 	mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
22139517SBill.Taylor@Sun.COM 
22149517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
22159517SBill.Taylor@Sun.COM }
22169517SBill.Taylor@Sun.COM 
22179517SBill.Taylor@Sun.COM 
22189517SBill.Taylor@Sun.COM /*
22199517SBill.Taylor@Sun.COM  * hermon_umap_db_clear_onclose_cb()
22209517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
22219517SBill.Taylor@Sun.COM  */
22229517SBill.Taylor@Sun.COM int
hermon_umap_db_clear_onclose_cb(dev_t dev,uint64_t flag)22239517SBill.Taylor@Sun.COM hermon_umap_db_clear_onclose_cb(dev_t dev, uint64_t flag)
22249517SBill.Taylor@Sun.COM {
22259517SBill.Taylor@Sun.COM 	hermon_umap_db_priv_t	*priv;
22269517SBill.Taylor@Sun.COM 	hermon_umap_db_entry_t	*umapdb;
22279517SBill.Taylor@Sun.COM 	minor_t			instance;
22289517SBill.Taylor@Sun.COM 	uint64_t		value;
22299517SBill.Taylor@Sun.COM 	int			status;
22309517SBill.Taylor@Sun.COM 
22319517SBill.Taylor@Sun.COM 	instance = HERMON_DEV_INSTANCE(dev);
22329517SBill.Taylor@Sun.COM 	if (instance == (minor_t)-1) {
22339517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
22349517SBill.Taylor@Sun.COM 	}
22359517SBill.Taylor@Sun.COM 
22369517SBill.Taylor@Sun.COM 	if (flag != HERMON_ONCLOSE_FLASH_INPROGRESS) {
22379517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
22389517SBill.Taylor@Sun.COM 	}
22399517SBill.Taylor@Sun.COM 
22409517SBill.Taylor@Sun.COM 	/*
22419517SBill.Taylor@Sun.COM 	 * Grab the lock for the "userland resources database" and find
22429517SBill.Taylor@Sun.COM 	 * the entry corresponding to this minor number.  Once it's found,
22439517SBill.Taylor@Sun.COM 	 * remove the entry (in the "hdb_priv" field) that indicated the
22449517SBill.Taylor@Sun.COM 	 * need for further processing during Hermon's close().  Free the
22459517SBill.Taylor@Sun.COM 	 * entry, if appropriate.
22469517SBill.Taylor@Sun.COM 	 */
22479517SBill.Taylor@Sun.COM 	mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
22489517SBill.Taylor@Sun.COM 	status = hermon_umap_db_find_nolock(instance, dev,
22499517SBill.Taylor@Sun.COM 	    MLNX_UMAP_PID_RSRC, &value, 0, &umapdb);
22509517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
22519517SBill.Taylor@Sun.COM 		mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
22529517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
22539517SBill.Taylor@Sun.COM 	}
22549517SBill.Taylor@Sun.COM 
22559517SBill.Taylor@Sun.COM 	priv = (hermon_umap_db_priv_t *)umapdb->hdbe_common.hdb_priv;
22569517SBill.Taylor@Sun.COM 	if (priv != NULL) {
22579517SBill.Taylor@Sun.COM 		kmem_free(priv, sizeof (hermon_umap_db_priv_t));
22589517SBill.Taylor@Sun.COM 		priv = NULL;
22599517SBill.Taylor@Sun.COM 	}
22609517SBill.Taylor@Sun.COM 
22619517SBill.Taylor@Sun.COM 	umapdb->hdbe_common.hdb_priv = (void *)priv;
22629517SBill.Taylor@Sun.COM 	mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
22639517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
22649517SBill.Taylor@Sun.COM }
22659517SBill.Taylor@Sun.COM 
22669517SBill.Taylor@Sun.COM 
22679517SBill.Taylor@Sun.COM /*
22689517SBill.Taylor@Sun.COM  * hermon_umap_db_clear_onclose_cb()
22699517SBill.Taylor@Sun.COM  *    Context: Can be called from user or kernel context.
22709517SBill.Taylor@Sun.COM  */
22719517SBill.Taylor@Sun.COM int
hermon_umap_db_handle_onclose_cb(hermon_umap_db_priv_t * priv)22729517SBill.Taylor@Sun.COM hermon_umap_db_handle_onclose_cb(hermon_umap_db_priv_t *priv)
22739517SBill.Taylor@Sun.COM {
22749517SBill.Taylor@Sun.COM 	int	(*callback)(void *);
22759517SBill.Taylor@Sun.COM 
22769517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&hermon_userland_rsrc_db.hdl_umapdb_lock));
22779517SBill.Taylor@Sun.COM 
22789517SBill.Taylor@Sun.COM 	/*
22799517SBill.Taylor@Sun.COM 	 * Call the callback.
22809517SBill.Taylor@Sun.COM 	 *    Note: Currently there is only one callback (in "hdp_cb"), but
22819517SBill.Taylor@Sun.COM 	 *    in the future there may be more, depending on what other types
22829517SBill.Taylor@Sun.COM 	 *    of interaction there are between userland processes and the
22839517SBill.Taylor@Sun.COM 	 *    driver.
22849517SBill.Taylor@Sun.COM 	 */
22859517SBill.Taylor@Sun.COM 	callback = priv->hdp_cb;
22869517SBill.Taylor@Sun.COM 	return (callback(priv->hdp_arg));
22879517SBill.Taylor@Sun.COM }
2288