xref: /titanic_50/usr/src/uts/common/io/ib/adapters/hermon/hermon_umap.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * hermon_umap.c
28  *    Hermon Userland Mapping Routines
29  *
30  *    Implements all the routines necessary for enabling direct userland
31  *    access to the Hermon hardware.  This includes all routines necessary for
32  *    maintaining the "userland resources database" and all the support routines
33  *    for the devmap calls.
34  */
35 
36 #include <sys/types.h>
37 #include <sys/conf.h>
38 #include <sys/ddi.h>
39 #include <sys/sunddi.h>
40 #include <sys/modctl.h>
41 #include <sys/file.h>
42 #include <sys/avl.h>
43 #include <sys/sysmacros.h>
44 
45 #include <sys/ib/adapters/hermon/hermon.h>
46 
47 /* Hermon HCA state pointer (extern) */
48 extern void *hermon_statep;
49 
50 /* Hermon HCA Userland Resource Database (extern) */
51 extern hermon_umap_db_t hermon_userland_rsrc_db;
52 
53 static int hermon_umap_uarpg(hermon_state_t *state, devmap_cookie_t dhp,
54     hermon_rsrc_t *rsrcp, uint64_t offset, size_t *maplen, int *err);
55 static int hermon_umap_cqmem(hermon_state_t *state, devmap_cookie_t dhp,
56     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
57 static int hermon_umap_qpmem(hermon_state_t *state, devmap_cookie_t dhp,
58     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
59 static int hermon_umap_srqmem(hermon_state_t *state, devmap_cookie_t dhp,
60     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
61 static int hermon_umap_dbrecmem(hermon_state_t *state, devmap_cookie_t dhp,
62     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err);
63 static int hermon_devmap_umem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
64     offset_t off, size_t len, void **pvtp);
65 static int hermon_devmap_umem_dup(devmap_cookie_t dhp, void *pvtp,
66     devmap_cookie_t new_dhp, void **new_pvtp);
67 static void hermon_devmap_umem_unmap(devmap_cookie_t dhp, void *pvtp,
68     offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
69     devmap_cookie_t new_dhp2, void **pvtp2);
70 static int hermon_devmap_dbrecmem_map(devmap_cookie_t dhp, dev_t dev,
71     uint_t flags, offset_t off, size_t len, void **pvtp);
72 static int hermon_devmap_dbrecmem_dup(devmap_cookie_t dhp, void *pvtp,
73     devmap_cookie_t new_dhp, void **new_pvtp);
74 static void hermon_devmap_dbrecmem_unmap(devmap_cookie_t dhp, void *pvtp,
75     offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
76     devmap_cookie_t new_dhp2, void **pvtp2);
77 static int hermon_devmap_devmem_map(devmap_cookie_t dhp, dev_t dev,
78     uint_t flags, offset_t off, size_t len, void **pvtp);
79 static int hermon_devmap_devmem_dup(devmap_cookie_t dhp, void *pvtp,
80     devmap_cookie_t new_dhp, void **new_pvtp);
81 static void hermon_devmap_devmem_unmap(devmap_cookie_t dhp, void *pvtp,
82     offset_t off, size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
83     devmap_cookie_t new_dhp2, void **pvtp2);
84 static ibt_status_t hermon_umap_mr_data_in(hermon_mrhdl_t mr,
85     ibt_mr_data_in_t *data, size_t data_sz);
86 static ibt_status_t hermon_umap_cq_data_out(hermon_cqhdl_t cq,
87     mlnx_umap_cq_data_out_t *data, size_t data_sz);
88 static ibt_status_t hermon_umap_qp_data_out(hermon_qphdl_t qp,
89     mlnx_umap_qp_data_out_t *data, size_t data_sz);
90 static ibt_status_t hermon_umap_srq_data_out(hermon_srqhdl_t srq,
91     mlnx_umap_srq_data_out_t *data, size_t data_sz);
92 static ibt_status_t hermon_umap_pd_data_out(hermon_pdhdl_t pd,
93     mlnx_umap_pd_data_out_t *data, size_t data_sz);
94 static int hermon_umap_db_compare(const void *query, const void *entry);
95 
96 
97 /*
98  * These callbacks are passed to devmap_umem_setup() and devmap_devmem_setup(),
99  * respectively.  They are used to handle (among other things) partial
100  * unmappings and to provide a method for invalidating mappings inherited
101  * as a result of a fork(2) system call.
102  */
103 static struct devmap_callback_ctl hermon_devmap_umem_cbops = {
104 	DEVMAP_OPS_REV,
105 	hermon_devmap_umem_map,
106 	NULL,
107 	hermon_devmap_umem_dup,
108 	hermon_devmap_umem_unmap
109 };
110 static struct devmap_callback_ctl hermon_devmap_devmem_cbops = {
111 	DEVMAP_OPS_REV,
112 	hermon_devmap_devmem_map,
113 	NULL,
114 	hermon_devmap_devmem_dup,
115 	hermon_devmap_devmem_unmap
116 };
117 static struct devmap_callback_ctl hermon_devmap_dbrecmem_cbops = {
118 	DEVMAP_OPS_REV,
119 	hermon_devmap_dbrecmem_map,
120 	NULL,
121 	hermon_devmap_dbrecmem_dup,
122 	hermon_devmap_dbrecmem_unmap
123 };
124 
125 /*
126  * hermon_devmap()
127  *    Context: Can be called from user context.
128  */
129 /* ARGSUSED */
130 int
hermon_devmap(dev_t dev,devmap_cookie_t dhp,offset_t off,size_t len,size_t * maplen,uint_t model)131 hermon_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
132     size_t *maplen, uint_t model)
133 {
134 	hermon_state_t	*state;
135 	hermon_rsrc_t 	*rsrcp;
136 	minor_t		instance;
137 	uint64_t	key, value;
138 	uint64_t	bf_offset = 0;
139 	uint_t		type;
140 	int		err, status;
141 
142 	/* Get Hermon softstate structure from instance */
143 	instance = HERMON_DEV_INSTANCE(dev);
144 	state = ddi_get_soft_state(hermon_statep, instance);
145 	if (state == NULL) {
146 		return (ENXIO);
147 	}
148 
149 	/*
150 	 * Access to Hermon devmap interface is not allowed in
151 	 * "maintenance mode".
152 	 */
153 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
154 		return (EFAULT);
155 	}
156 
157 	/*
158 	 * The bottom bits of "offset" are undefined (number depends on
159 	 * system PAGESIZE).  Shifting these off leaves us with a "key".
160 	 * The "key" is actually a combination of both a real key value
161 	 * (for the purpose of database lookup) and a "type" value.  We
162 	 * extract this information before doing the database lookup.
163 	 */
164 	key  = off >> PAGESHIFT;
165 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
166 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
167 	if (type == MLNX_UMAP_BLUEFLAMEPG_RSRC) {
168 		if (state->hs_devlim.blu_flm == 0) {
169 			return (EFAULT);
170 		}
171 		bf_offset = state->hs_bf_offset;
172 		type = MLNX_UMAP_UARPG_RSRC;
173 	}
174 	status = hermon_umap_db_find(instance, key, type, &value, 0, NULL);
175 	if (status == DDI_SUCCESS) {
176 		rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
177 
178 		switch (type) {
179 		case MLNX_UMAP_UARPG_RSRC:
180 			/*
181 			 * Double check that process who open()'d Hermon is
182 			 * same process attempting to mmap() UAR page.
183 			 */
184 			if (key != ddi_get_pid()) {
185 				return (EINVAL);
186 			}
187 
188 			/* Map the UAR page out for userland access */
189 			status = hermon_umap_uarpg(state, dhp, rsrcp, bf_offset,
190 			    maplen, &err);
191 			if (status != DDI_SUCCESS) {
192 				return (err);
193 			}
194 			break;
195 
196 		case MLNX_UMAP_CQMEM_RSRC:
197 			/* Map the CQ memory out for userland access */
198 			status = hermon_umap_cqmem(state, dhp, rsrcp, off,
199 			    maplen, &err);
200 			if (status != DDI_SUCCESS) {
201 				return (err);
202 			}
203 			break;
204 
205 		case MLNX_UMAP_QPMEM_RSRC:
206 			/* Map the QP memory out for userland access */
207 			status = hermon_umap_qpmem(state, dhp, rsrcp, off,
208 			    maplen, &err);
209 			if (status != DDI_SUCCESS) {
210 				return (err);
211 			}
212 			break;
213 
214 		case MLNX_UMAP_SRQMEM_RSRC:
215 			/* Map the SRQ memory out for userland access */
216 			status = hermon_umap_srqmem(state, dhp, rsrcp, off,
217 			    maplen, &err);
218 			if (status != DDI_SUCCESS) {
219 				return (err);
220 			}
221 			break;
222 
223 		case MLNX_UMAP_DBRMEM_RSRC:
224 			/*
225 			 * Map the doorbell record memory out for
226 			 * userland access
227 			 */
228 			status = hermon_umap_dbrecmem(state, dhp, rsrcp, off,
229 			    maplen, &err);
230 			if (status != DDI_SUCCESS) {
231 				return (err);
232 			}
233 			break;
234 
235 		default:
236 			HERMON_WARNING(state, "unexpected rsrc type in devmap");
237 			return (EINVAL);
238 		}
239 	} else {
240 		return (EINVAL);
241 	}
242 
243 	return (0);
244 }
245 
246 
247 /*
248  * hermon_umap_uarpg()
249  *    Context: Can be called from user context.
250  */
251 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)252 hermon_umap_uarpg(hermon_state_t *state, devmap_cookie_t dhp,
253     hermon_rsrc_t *rsrcp, uint64_t offset, size_t *maplen, int *err)
254 {
255 	int			status;
256 	uint_t			maxprot;
257 	ddi_device_acc_attr_t	*accattrp = &state->hs_reg_accattr;
258 	ddi_device_acc_attr_t	accattr;
259 
260 	if (offset != 0) {	/* Hermon Blueflame */
261 		/* Try to use write coalescing data ordering */
262 		accattr = *accattrp;
263 		accattr.devacc_attr_dataorder = DDI_STORECACHING_OK_ACC;
264 		accattrp = &accattr;
265 	}
266 
267 	/* Map out the UAR page (doorbell page) */
268 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
269 	status = devmap_devmem_setup(dhp, state->hs_dip,
270 	    &hermon_devmap_devmem_cbops, HERMON_UAR_BAR, (rsrcp->hr_indx <<
271 	    PAGESHIFT) + offset, PAGESIZE, maxprot, DEVMAP_ALLOW_REMAP,
272 	    accattrp);
273 	if (status < 0) {
274 		*err = status;
275 		return (DDI_FAILURE);
276 	}
277 
278 	*maplen = PAGESIZE;
279 	return (DDI_SUCCESS);
280 }
281 
282 
283 /*
284  * hermon_umap_cqmem()
285  *    Context: Can be called from user context.
286  */
287 /* ARGSUSED */
288 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)289 hermon_umap_cqmem(hermon_state_t *state, devmap_cookie_t dhp,
290     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
291 {
292 	hermon_cqhdl_t	cq;
293 	size_t		size;
294 	uint_t		maxprot;
295 	int		status;
296 
297 	/* Extract the Hermon CQ handle pointer from the hermon_rsrc_t */
298 	cq = (hermon_cqhdl_t)rsrcp->hr_addr;
299 
300 	/* Round-up the CQ size to system page size */
301 	size = ptob(btopr(cq->cq_resize_hdl ?
302 	    cq->cq_resize_hdl->cq_cqinfo.qa_size : cq->cq_cqinfo.qa_size));
303 
304 	/* Map out the CQ memory - use resize_hdl if non-NULL */
305 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
306 	status = devmap_umem_setup(dhp, state->hs_dip,
307 	    &hermon_devmap_umem_cbops, cq->cq_resize_hdl ?
308 	    cq->cq_resize_hdl->cq_cqinfo.qa_umemcookie :
309 	    cq->cq_cqinfo.qa_umemcookie, 0, size,
310 	    maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
311 	if (status < 0) {
312 		*err = status;
313 		return (DDI_FAILURE);
314 	}
315 	*maplen = size;
316 
317 	return (DDI_SUCCESS);
318 }
319 
320 
321 /*
322  * hermon_umap_qpmem()
323  *    Context: Can be called from user context.
324  */
325 /* ARGSUSED */
326 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)327 hermon_umap_qpmem(hermon_state_t *state, devmap_cookie_t dhp,
328     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
329 {
330 	hermon_qphdl_t	qp;
331 	offset_t	offset;
332 	size_t		size;
333 	uint_t		maxprot;
334 	int		status;
335 
336 	/* Extract the Hermon QP handle pointer from the hermon_rsrc_t */
337 	qp = (hermon_qphdl_t)rsrcp->hr_addr;
338 
339 	/*
340 	 * Calculate the offset of the first work queue (send or recv) into
341 	 * the memory (ddi_umem_alloc()) allocated previously for the QP.
342 	 */
343 	offset = (offset_t)((uintptr_t)qp->qp_wqinfo.qa_buf_aligned -
344 	    (uintptr_t)qp->qp_wqinfo.qa_buf_real);
345 
346 	/* Round-up the QP work queue sizes to system page size */
347 	size = ptob(btopr(qp->qp_wqinfo.qa_size));
348 
349 	/* Map out the QP memory */
350 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
351 	status = devmap_umem_setup(dhp, state->hs_dip,
352 	    &hermon_devmap_umem_cbops, qp->qp_wqinfo.qa_umemcookie, offset,
353 	    size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
354 	if (status < 0) {
355 		*err = status;
356 		return (DDI_FAILURE);
357 	}
358 	*maplen = size;
359 
360 	return (DDI_SUCCESS);
361 }
362 
363 
364 /*
365  * hermon_umap_srqmem()
366  *    Context: Can be called from user context.
367  */
368 /* ARGSUSED */
369 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)370 hermon_umap_srqmem(hermon_state_t *state, devmap_cookie_t dhp,
371     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
372 {
373 	hermon_srqhdl_t	srq;
374 	offset_t	offset;
375 	size_t		size;
376 	uint_t		maxprot;
377 	int		status;
378 
379 	/* Extract the Hermon SRQ handle pointer from the hermon_rsrc_t */
380 	srq = (hermon_srqhdl_t)rsrcp->hr_addr;
381 
382 	/*
383 	 * Calculate the offset of the first shared recv queue into the memory
384 	 * (ddi_umem_alloc()) allocated previously for the SRQ.
385 	 */
386 	offset = (offset_t)((uintptr_t)srq->srq_wqinfo.qa_buf_aligned -
387 	    (uintptr_t)srq->srq_wqinfo.qa_buf_real);
388 
389 	/* Round-up the SRQ work queue sizes to system page size */
390 	size = ptob(btopr(srq->srq_wqinfo.qa_size));
391 
392 	/* Map out the SRQ memory */
393 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
394 	status = devmap_umem_setup(dhp, state->hs_dip,
395 	    &hermon_devmap_umem_cbops, srq->srq_wqinfo.qa_umemcookie, offset,
396 	    size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
397 	if (status < 0) {
398 		*err = status;
399 		return (DDI_FAILURE);
400 	}
401 	*maplen = size;
402 
403 	return (DDI_SUCCESS);
404 }
405 
406 
407 /*
408  * hermon_devmap_dbrecmem()
409  *    Context: Can be called from user context.
410  */
411 /* ARGSUSED */
412 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)413 hermon_umap_dbrecmem(hermon_state_t *state, devmap_cookie_t dhp,
414     hermon_rsrc_t *rsrcp, offset_t off, size_t *maplen, int *err)
415 {
416 	hermon_udbr_page_t *pagep;
417 	offset_t	offset;
418 	size_t		size;
419 	uint_t		maxprot;
420 	int		status;
421 
422 	/* We stored the udbr_page pointer, and not a hermon_rsrc_t */
423 	pagep = (hermon_udbr_page_t *)rsrcp;
424 
425 	/*
426 	 * Calculate the offset of the doorbell records into the memory
427 	 * (ddi_umem_alloc()) allocated previously for them.
428 	 */
429 	offset = 0;
430 
431 	/* Round-up the doorbell page to system page size */
432 	size = PAGESIZE;
433 
434 	/* Map out the Doorbell Record memory */
435 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
436 	status = devmap_umem_setup(dhp, state->hs_dip,
437 	    &hermon_devmap_dbrecmem_cbops, pagep->upg_umemcookie, offset,
438 	    size, maxprot, (DEVMAP_ALLOW_REMAP | DEVMAP_DEFAULTS), NULL);
439 	if (status < 0) {
440 		*err = status;
441 		return (DDI_FAILURE);
442 	}
443 	*maplen = size;
444 
445 	return (DDI_SUCCESS);
446 }
447 
448 
449 /*
450  * hermon_devmap_umem_map()
451  *    Context: Can be called from kernel context.
452  */
453 /* ARGSUSED */
454 static int
hermon_devmap_umem_map(devmap_cookie_t dhp,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)455 hermon_devmap_umem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
456     offset_t off, size_t len, void **pvtp)
457 {
458 	hermon_state_t		*state;
459 	hermon_devmap_track_t	*dvm_track;
460 	hermon_cqhdl_t		cq;
461 	hermon_qphdl_t		qp;
462 	hermon_srqhdl_t		srq;
463 	minor_t			instance;
464 	uint64_t		key;
465 	uint_t			type;
466 
467 	/* Get Hermon softstate structure from instance */
468 	instance = HERMON_DEV_INSTANCE(dev);
469 	state = ddi_get_soft_state(hermon_statep, instance);
470 	if (state == NULL) {
471 		return (ENXIO);
472 	}
473 
474 	/*
475 	 * The bottom bits of "offset" are undefined (number depends on
476 	 * system PAGESIZE).  Shifting these off leaves us with a "key".
477 	 * The "key" is actually a combination of both a real key value
478 	 * (for the purpose of database lookup) and a "type" value.  Although
479 	 * we are not going to do any database lookup per se, we do want
480 	 * to extract the "key" and the "type" (to enable faster lookup of
481 	 * the appropriate CQ or QP handle).
482 	 */
483 	key  = off >> PAGESHIFT;
484 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
485 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
486 
487 	/*
488 	 * Allocate an entry to track the mapping and unmapping (specifically,
489 	 * partial unmapping) of this resource.
490 	 */
491 	dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
492 	    sizeof (hermon_devmap_track_t), KM_SLEEP);
493 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
494 	dvm_track->hdt_offset = off;
495 	dvm_track->hdt_state  = state;
496 	dvm_track->hdt_refcnt = 1;
497 	mutex_init(&dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
498 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
499 
500 	/*
501 	 * Depending of the type of resource that has been mapped out, we
502 	 * need to update the QP or CQ handle to reflect that it has, in
503 	 * fact, been mapped.  This allows the driver code which frees a QP
504 	 * or a CQ to know whether it is appropriate to do a
505 	 * devmap_devmem_remap() to invalidate the userland mapping for the
506 	 * corresponding queue's memory.
507 	 */
508 	if (type == MLNX_UMAP_CQMEM_RSRC) {
509 
510 		/* Use "key" (CQ number) to do fast lookup of CQ handle */
511 		cq = hermon_cqhdl_from_cqnum(state, key);
512 
513 		/*
514 		 * Update the handle to the userland mapping.  Note:  If
515 		 * the CQ already has a valid userland mapping, then stop
516 		 * and return failure.
517 		 */
518 		mutex_enter(&cq->cq_lock);
519 		if (cq->cq_umap_dhp == NULL) {
520 			cq->cq_umap_dhp = dhp;
521 			dvm_track->hdt_size = cq->cq_cqinfo.qa_size;
522 			mutex_exit(&cq->cq_lock);
523 		} else if (cq->cq_resize_hdl &&
524 		    (cq->cq_resize_hdl->cq_umap_dhp == NULL)) {
525 			cq->cq_resize_hdl->cq_umap_dhp = dhp;
526 			dvm_track->hdt_size =
527 			    cq->cq_resize_hdl->cq_cqinfo.qa_size;
528 			mutex_exit(&cq->cq_lock);
529 		} else {
530 			mutex_exit(&cq->cq_lock);
531 			goto umem_map_fail;
532 		}
533 
534 	} else if (type == MLNX_UMAP_QPMEM_RSRC) {
535 
536 		/* Use "key" (QP number) to do fast lookup of QP handle */
537 		qp = hermon_qphdl_from_qpnum(state, key);
538 
539 		/*
540 		 * Update the handle to the userland mapping.  Note:  If
541 		 * the CQ already has a valid userland mapping, then stop
542 		 * and return failure.
543 		 */
544 		mutex_enter(&qp->qp_lock);
545 		if (qp->qp_umap_dhp == NULL) {
546 			qp->qp_umap_dhp = dhp;
547 			dvm_track->hdt_size = qp->qp_wqinfo.qa_size;
548 			mutex_exit(&qp->qp_lock);
549 		} else {
550 			mutex_exit(&qp->qp_lock);
551 			goto umem_map_fail;
552 		}
553 
554 	} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
555 
556 		/* Use "key" (SRQ number) to do fast lookup on SRQ handle */
557 		srq = hermon_srqhdl_from_srqnum(state, key);
558 
559 		/*
560 		 * Update the handle to the userland mapping.  Note:  If the
561 		 * SRQ already has a valid userland mapping, then stop and
562 		 * return failure.
563 		 */
564 		mutex_enter(&srq->srq_lock);
565 		if (srq->srq_umap_dhp == NULL) {
566 			srq->srq_umap_dhp = dhp;
567 			dvm_track->hdt_size = srq->srq_wqinfo.qa_size;
568 			mutex_exit(&srq->srq_lock);
569 		} else {
570 			mutex_exit(&srq->srq_lock);
571 			goto umem_map_fail;
572 		}
573 	}
574 
575 	/*
576 	 * Pass the private "Hermon devmap tracking structure" back.  This
577 	 * pointer will be returned in subsequent "unmap" callbacks.
578 	 */
579 	*pvtp = dvm_track;
580 
581 	return (DDI_SUCCESS);
582 
583 umem_map_fail:
584 	mutex_destroy(&dvm_track->hdt_lock);
585 	kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
586 	return (DDI_FAILURE);
587 }
588 
589 
590 /*
591  * hermon_devmap_umem_dup()
592  *    Context: Can be called from kernel context.
593  */
594 /* ARGSUSED */
595 static int
hermon_devmap_umem_dup(devmap_cookie_t dhp,void * pvtp,devmap_cookie_t new_dhp,void ** new_pvtp)596 hermon_devmap_umem_dup(devmap_cookie_t dhp, void *pvtp, devmap_cookie_t new_dhp,
597     void **new_pvtp)
598 {
599 	hermon_state_t		*state;
600 	hermon_devmap_track_t	*dvm_track, *new_dvm_track;
601 	uint_t			maxprot;
602 	int			status;
603 
604 	/*
605 	 * Extract the Hermon softstate pointer from "Hermon devmap tracking
606 	 * structure" (in "pvtp").
607 	 */
608 	dvm_track = (hermon_devmap_track_t *)pvtp;
609 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
610 	state = dvm_track->hdt_state;
611 
612 	/*
613 	 * Since this devmap_dup() entry point is generally called
614 	 * when a process does fork(2), it is incumbent upon the driver
615 	 * to insure that the child does not inherit a valid copy of
616 	 * the parent's QP or CQ resource.  This is accomplished by using
617 	 * devmap_devmem_remap() to invalidate the child's mapping to the
618 	 * kernel memory.
619 	 */
620 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
621 	status = devmap_devmem_remap(new_dhp, state->hs_dip, 0, 0,
622 	    dvm_track->hdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
623 	if (status != DDI_SUCCESS) {
624 		HERMON_WARNING(state, "failed in hermon_devmap_umem_dup()");
625 		return (status);
626 	}
627 
628 	/*
629 	 * Allocate a new entry to track the subsequent unmapping
630 	 * (specifically, all partial unmappings) of the child's newly
631 	 * invalidated resource.  Note: Setting the "hdt_size" field to
632 	 * zero here is an indication to the devmap_unmap() entry point
633 	 * that this mapping is invalid, and that its subsequent unmapping
634 	 * should not affect any of the parent's CQ or QP resources.
635 	 */
636 	new_dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
637 	    sizeof (hermon_devmap_track_t), KM_SLEEP);
638 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*new_dvm_track))
639 	new_dvm_track->hdt_offset = 0;
640 	new_dvm_track->hdt_state  = state;
641 	new_dvm_track->hdt_refcnt = 1;
642 	new_dvm_track->hdt_size	  = 0;
643 	mutex_init(&new_dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
644 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
645 	*new_pvtp = new_dvm_track;
646 
647 	return (DDI_SUCCESS);
648 }
649 
650 
651 /*
652  * hermon_devmap_umem_unmap()
653  *    Context: Can be called from kernel context.
654  */
655 /* ARGSUSED */
656 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)657 hermon_devmap_umem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
658     size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
659     devmap_cookie_t new_dhp2, void **pvtp2)
660 {
661 	hermon_state_t 		*state;
662 	hermon_rsrc_t 		*rsrcp;
663 	hermon_devmap_track_t	*dvm_track;
664 	hermon_cqhdl_t		cq;
665 	hermon_qphdl_t		qp;
666 	hermon_srqhdl_t		srq;
667 	uint64_t		key, value;
668 	uint_t			type;
669 	uint_t			size;
670 	int			status;
671 
672 	/*
673 	 * Extract the Hermon softstate pointer from "Hermon devmap tracking
674 	 * structure" (in "pvtp").
675 	 */
676 	dvm_track = (hermon_devmap_track_t *)pvtp;
677 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
678 	state	  = dvm_track->hdt_state;
679 
680 	/*
681 	 * Extract the "offset" from the "Hermon devmap tracking structure".
682 	 * Note: The input argument "off" is ignored here because the
683 	 * Hermon mapping interfaces define a very specific meaning to
684 	 * each "logical offset".  Also extract the "key" and "type" encoded
685 	 * in the logical offset.
686 	 */
687 	key  = dvm_track->hdt_offset >> PAGESHIFT;
688 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
689 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
690 
691 	/*
692 	 * Extract the "size" of the mapping.  If this size is determined
693 	 * to be zero, then it is an indication of a previously invalidated
694 	 * mapping, and no CQ or QP resources should be affected.
695 	 */
696 	size = dvm_track->hdt_size;
697 
698 	/*
699 	 * If only the "middle portion of a given mapping is being unmapped,
700 	 * then we are effectively creating one new piece of mapped memory.
701 	 * (Original region is divided into three pieces of which the middle
702 	 * piece is being removed.  This leaves two pieces.  Since we started
703 	 * with one piece and now have two pieces, we need to increment the
704 	 * counter in the "Hermon devmap tracking structure".
705 	 *
706 	 * If, however, the whole mapped region is being unmapped, then we
707 	 * have started with one region which we are completely removing.
708 	 * In this case, we need to decrement the counter in the "Hermon
709 	 * devmap tracking structure".
710 	 *
711 	 * In each of the remaining cases, we will have started with one
712 	 * mapped region and ended with one (different) region.  So no counter
713 	 * modification is necessary.
714 	 */
715 	mutex_enter(&dvm_track->hdt_lock);
716 	if ((new_dhp1 == NULL) && (new_dhp2 == NULL)) {
717 		dvm_track->hdt_refcnt--;
718 	} else if ((new_dhp1 != NULL) && (new_dhp2 != NULL)) {
719 		dvm_track->hdt_refcnt++;
720 	}
721 	mutex_exit(&dvm_track->hdt_lock);
722 
723 	/*
724 	 * For each of the cases where the region is being divided, then we
725 	 * need to pass back the "Hermon devmap tracking structure".  This way
726 	 * we get it back when each of the remaining pieces is subsequently
727 	 * unmapped.
728 	 */
729 	if (new_dhp1 != NULL) {
730 		*pvtp1 = pvtp;
731 	}
732 	if (new_dhp2 != NULL) {
733 		*pvtp2 = pvtp;
734 	}
735 
736 	/*
737 	 * If the "Hermon devmap tracking structure" is no longer being
738 	 * referenced, then free it up.  Otherwise, return.
739 	 */
740 	if (dvm_track->hdt_refcnt == 0) {
741 		mutex_destroy(&dvm_track->hdt_lock);
742 		kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
743 
744 		/*
745 		 * If the mapping was invalid (see explanation above), then
746 		 * no further processing is necessary.
747 		 */
748 		if (size == 0) {
749 			return;
750 		}
751 	} else {
752 		return;
753 	}
754 
755 	/*
756 	 * Now that we can guarantee that the user memory is fully unmapped,
757 	 * we can use the "key" and "type" values to try to find the entry
758 	 * in the "userland resources database".  If it's found, then it
759 	 * indicates that the queue memory (CQ or QP) has not yet been freed.
760 	 * In this case, we update the corresponding CQ or QP handle to
761 	 * indicate that the "devmap_devmem_remap()" call will be unnecessary.
762 	 * If it's _not_ found, then it indicates that the CQ or QP memory
763 	 * was, in fact, freed before it was unmapped (thus requiring a
764 	 * previous invalidation by remapping - which will already have
765 	 * been done in the free routine).
766 	 */
767 	status = hermon_umap_db_find(state->hs_instance, key, type, &value,
768 	    0, NULL);
769 	if (status == DDI_SUCCESS) {
770 		/*
771 		 * Depending on the type of the mapped resource (CQ or QP),
772 		 * update handle to indicate that no invalidation remapping
773 		 * will be necessary.
774 		 */
775 		if (type == MLNX_UMAP_CQMEM_RSRC) {
776 
777 			/* Use "value" to convert to CQ handle */
778 			rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
779 			cq = (hermon_cqhdl_t)rsrcp->hr_addr;
780 
781 			/*
782 			 * Invalidate the handle to the userland mapping.
783 			 * Note: We must ensure that the mapping being
784 			 * unmapped here is the current one for the CQ.  It
785 			 * is possible that it might not be if this CQ has
786 			 * been resized and the previous CQ memory has not
787 			 * yet been unmapped.  But in that case, because of
788 			 * the devmap_devmem_remap(), there is no longer any
789 			 * association between the mapping and the real CQ
790 			 * kernel memory.
791 			 */
792 			mutex_enter(&cq->cq_lock);
793 			if (cq->cq_umap_dhp == dhp) {
794 				cq->cq_umap_dhp = NULL;
795 				if (cq->cq_resize_hdl) {
796 					/* resize is DONE, switch queues */
797 					hermon_cq_resize_helper(state, cq);
798 				}
799 			} else {
800 				if (cq->cq_resize_hdl &&
801 				    cq->cq_resize_hdl->cq_umap_dhp == dhp) {
802 					/*
803 					 * Unexpected case.  munmap of the
804 					 * cq_resize buf, and not the
805 					 * original buf.
806 					 */
807 					cq->cq_resize_hdl->cq_umap_dhp = NULL;
808 				}
809 			}
810 			mutex_exit(&cq->cq_lock);
811 
812 		} else if (type == MLNX_UMAP_QPMEM_RSRC) {
813 
814 			/* Use "value" to convert to QP handle */
815 			rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
816 			qp = (hermon_qphdl_t)rsrcp->hr_addr;
817 
818 			/*
819 			 * Invalidate the handle to the userland mapping.
820 			 * Note: we ensure that the mapping being unmapped
821 			 * here is the current one for the QP.  This is
822 			 * more of a sanity check here since, unlike CQs
823 			 * (above) we do not support resize of QPs.
824 			 */
825 			mutex_enter(&qp->qp_lock);
826 			if (qp->qp_umap_dhp == dhp) {
827 				qp->qp_umap_dhp = NULL;
828 			}
829 			mutex_exit(&qp->qp_lock);
830 
831 		} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
832 
833 			/* Use "value" to convert to SRQ handle */
834 			rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
835 			srq = (hermon_srqhdl_t)rsrcp->hr_addr;
836 
837 			/*
838 			 * Invalidate the handle to the userland mapping.
839 			 * Note: we ensure that the mapping being unmapped
840 			 * here is the current one for the QP.  This is
841 			 * more of a sanity check here since, unlike CQs
842 			 * (above) we do not support resize of QPs.
843 			 */
844 			mutex_enter(&srq->srq_lock);
845 			if (srq->srq_umap_dhp == dhp) {
846 				srq->srq_umap_dhp = NULL;
847 			}
848 			mutex_exit(&srq->srq_lock);
849 		}
850 	}
851 }
852 
853 
854 /*
855  * hermon_devmap_devmem_map()
856  *    Context: Can be called from kernel context.
857  */
858 /* ARGSUSED */
859 static int
hermon_devmap_dbrecmem_map(devmap_cookie_t dhp,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)860 hermon_devmap_dbrecmem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
861     offset_t off, size_t len, void **pvtp)
862 {
863 	hermon_state_t		*state;
864 	hermon_devmap_track_t	*dvm_track;
865 	hermon_cqhdl_t		cq;
866 	hermon_qphdl_t		qp;
867 	hermon_srqhdl_t		srq;
868 	minor_t			instance;
869 	uint64_t		key;
870 	uint_t			type;
871 
872 	/* Get Hermon softstate structure from instance */
873 	instance = HERMON_DEV_INSTANCE(dev);
874 	state = ddi_get_soft_state(hermon_statep, instance);
875 	if (state == NULL) {
876 		return (ENXIO);
877 	}
878 
879 	/*
880 	 * The bottom bits of "offset" are undefined (number depends on
881 	 * system PAGESIZE).  Shifting these off leaves us with a "key".
882 	 * The "key" is actually a combination of both a real key value
883 	 * (for the purpose of database lookup) and a "type" value.  Although
884 	 * we are not going to do any database lookup per se, we do want
885 	 * to extract the "key" and the "type" (to enable faster lookup of
886 	 * the appropriate CQ or QP handle).
887 	 */
888 	key  = off >> PAGESHIFT;
889 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
890 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
891 
892 	/*
893 	 * Allocate an entry to track the mapping and unmapping (specifically,
894 	 * partial unmapping) of this resource.
895 	 */
896 	dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
897 	    sizeof (hermon_devmap_track_t), KM_SLEEP);
898 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
899 	dvm_track->hdt_offset = off;
900 	dvm_track->hdt_state  = state;
901 	dvm_track->hdt_refcnt = 1;
902 	mutex_init(&dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
903 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
904 
905 	/*
906 	 * Depending of the type of resource that has been mapped out, we
907 	 * need to update the QP or CQ handle to reflect that it has, in
908 	 * fact, been mapped.  This allows the driver code which frees a QP
909 	 * or a CQ to know whether it is appropriate to do a
910 	 * devmap_devmem_remap() to invalidate the userland mapping for the
911 	 * corresponding queue's memory.
912 	 */
913 	if (type == MLNX_UMAP_CQMEM_RSRC) {
914 
915 		/* Use "key" (CQ number) to do fast lookup of CQ handle */
916 		cq = hermon_cqhdl_from_cqnum(state, key);
917 
918 		/*
919 		 * Update the handle to the userland mapping.  Note:  If
920 		 * the CQ already has a valid userland mapping, then stop
921 		 * and return failure.
922 		 */
923 		mutex_enter(&cq->cq_lock);
924 		if (cq->cq_umap_dhp == NULL) {
925 			cq->cq_umap_dhp = dhp;
926 			dvm_track->hdt_size = cq->cq_cqinfo.qa_size;
927 			mutex_exit(&cq->cq_lock);
928 		} else {
929 			mutex_exit(&cq->cq_lock);
930 			goto umem_map_fail;
931 		}
932 
933 	} else if (type == MLNX_UMAP_QPMEM_RSRC) {
934 
935 		/* Use "key" (QP number) to do fast lookup of QP handle */
936 		qp = hermon_qphdl_from_qpnum(state, key);
937 
938 		/*
939 		 * Update the handle to the userland mapping.  Note:  If
940 		 * the CQ already has a valid userland mapping, then stop
941 		 * and return failure.
942 		 */
943 		mutex_enter(&qp->qp_lock);
944 		if (qp->qp_umap_dhp == NULL) {
945 			qp->qp_umap_dhp = dhp;
946 			dvm_track->hdt_size = qp->qp_wqinfo.qa_size;
947 			mutex_exit(&qp->qp_lock);
948 		} else {
949 			mutex_exit(&qp->qp_lock);
950 			goto umem_map_fail;
951 		}
952 
953 	} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
954 
955 		/* Use "key" (SRQ number) to do fast lookup on SRQ handle */
956 		srq = hermon_srqhdl_from_srqnum(state, key);
957 
958 		/*
959 		 * Update the handle to the userland mapping.  Note:  If the
960 		 * SRQ already has a valid userland mapping, then stop and
961 		 * return failure.
962 		 */
963 		mutex_enter(&srq->srq_lock);
964 		if (srq->srq_umap_dhp == NULL) {
965 			srq->srq_umap_dhp = dhp;
966 			dvm_track->hdt_size = srq->srq_wqinfo.qa_size;
967 			mutex_exit(&srq->srq_lock);
968 		} else {
969 			mutex_exit(&srq->srq_lock);
970 			goto umem_map_fail;
971 		}
972 	}
973 
974 	/*
975 	 * Pass the private "Hermon devmap tracking structure" back.  This
976 	 * pointer will be returned in subsequent "unmap" callbacks.
977 	 */
978 	*pvtp = dvm_track;
979 
980 	return (DDI_SUCCESS);
981 
982 umem_map_fail:
983 	mutex_destroy(&dvm_track->hdt_lock);
984 	kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
985 	return (DDI_FAILURE);
986 }
987 
988 
989 /*
990  * hermon_devmap_dbrecmem_dup()
991  *    Context: Can be called from kernel context.
992  */
993 /* ARGSUSED */
994 static int
hermon_devmap_dbrecmem_dup(devmap_cookie_t dhp,void * pvtp,devmap_cookie_t new_dhp,void ** new_pvtp)995 hermon_devmap_dbrecmem_dup(devmap_cookie_t dhp, void *pvtp,
996     devmap_cookie_t new_dhp, void **new_pvtp)
997 {
998 	hermon_state_t		*state;
999 	hermon_devmap_track_t	*dvm_track, *new_dvm_track;
1000 	uint_t			maxprot;
1001 	int			status;
1002 
1003 	/*
1004 	 * Extract the Hermon softstate pointer from "Hermon devmap tracking
1005 	 * structure" (in "pvtp").
1006 	 */
1007 	dvm_track = (hermon_devmap_track_t *)pvtp;
1008 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
1009 	state = dvm_track->hdt_state;
1010 
1011 	/*
1012 	 * Since this devmap_dup() entry point is generally called
1013 	 * when a process does fork(2), it is incumbent upon the driver
1014 	 * to insure that the child does not inherit a valid copy of
1015 	 * the parent's QP or CQ resource.  This is accomplished by using
1016 	 * devmap_devmem_remap() to invalidate the child's mapping to the
1017 	 * kernel memory.
1018 	 */
1019 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
1020 	status = devmap_devmem_remap(new_dhp, state->hs_dip, 0, 0,
1021 	    dvm_track->hdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
1022 	if (status != DDI_SUCCESS) {
1023 		HERMON_WARNING(state, "failed in hermon_devmap_dbrecmem_dup()");
1024 		return (status);
1025 	}
1026 
1027 	/*
1028 	 * Allocate a new entry to track the subsequent unmapping
1029 	 * (specifically, all partial unmappings) of the child's newly
1030 	 * invalidated resource.  Note: Setting the "hdt_size" field to
1031 	 * zero here is an indication to the devmap_unmap() entry point
1032 	 * that this mapping is invalid, and that its subsequent unmapping
1033 	 * should not affect any of the parent's CQ or QP resources.
1034 	 */
1035 	new_dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
1036 	    sizeof (hermon_devmap_track_t), KM_SLEEP);
1037 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*new_dvm_track))
1038 	new_dvm_track->hdt_offset = 0;
1039 	new_dvm_track->hdt_state  = state;
1040 	new_dvm_track->hdt_refcnt = 1;
1041 	new_dvm_track->hdt_size	  = 0;
1042 	mutex_init(&new_dvm_track->hdt_lock, NULL, MUTEX_DRIVER,
1043 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
1044 	*new_pvtp = new_dvm_track;
1045 
1046 	return (DDI_SUCCESS);
1047 }
1048 
1049 
1050 /*
1051  * hermon_devmap_dbrecmem_unmap()
1052  *    Context: Can be called from kernel context.
1053  */
1054 /* ARGSUSED */
1055 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)1056 hermon_devmap_dbrecmem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
1057     size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
1058     devmap_cookie_t new_dhp2, void **pvtp2)
1059 {
1060 	hermon_state_t 		*state;
1061 	hermon_rsrc_t 		*rsrcp;
1062 	hermon_devmap_track_t	*dvm_track;
1063 	hermon_cqhdl_t		cq;
1064 	hermon_qphdl_t		qp;
1065 	hermon_srqhdl_t		srq;
1066 	uint64_t		key, value;
1067 	uint_t			type;
1068 	uint_t			size;
1069 	int			status;
1070 
1071 	/*
1072 	 * Extract the Hermon softstate pointer from "Hermon devmap tracking
1073 	 * structure" (in "pvtp").
1074 	 */
1075 	dvm_track = (hermon_devmap_track_t *)pvtp;
1076 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
1077 	state	  = dvm_track->hdt_state;
1078 
1079 	/*
1080 	 * Extract the "offset" from the "Hermon devmap tracking structure".
1081 	 * Note: The input argument "off" is ignored here because the
1082 	 * Hermon mapping interfaces define a very specific meaning to
1083 	 * each "logical offset".  Also extract the "key" and "type" encoded
1084 	 * in the logical offset.
1085 	 */
1086 	key  = dvm_track->hdt_offset >> PAGESHIFT;
1087 	type = key & MLNX_UMAP_RSRC_TYPE_MASK;
1088 	key  = key >> MLNX_UMAP_RSRC_TYPE_SHIFT;
1089 
1090 	/*
1091 	 * Extract the "size" of the mapping.  If this size is determined
1092 	 * to be zero, then it is an indication of a previously invalidated
1093 	 * mapping, and no CQ or QP resources should be affected.
1094 	 */
1095 	size = dvm_track->hdt_size;
1096 
1097 	/*
1098 	 * If only the "middle portion of a given mapping is being unmapped,
1099 	 * then we are effectively creating one new piece of mapped memory.
1100 	 * (Original region is divided into three pieces of which the middle
1101 	 * piece is being removed.  This leaves two pieces.  Since we started
1102 	 * with one piece and now have two pieces, we need to increment the
1103 	 * counter in the "Hermon devmap tracking structure".
1104 	 *
1105 	 * If, however, the whole mapped region is being unmapped, then we
1106 	 * have started with one region which we are completely removing.
1107 	 * In this case, we need to decrement the counter in the "Hermon
1108 	 * devmap tracking structure".
1109 	 *
1110 	 * In each of the remaining cases, we will have started with one
1111 	 * mapped region and ended with one (different) region.  So no counter
1112 	 * modification is necessary.
1113 	 */
1114 	mutex_enter(&dvm_track->hdt_lock);
1115 	if ((new_dhp1 == NULL) && (new_dhp2 == NULL)) {
1116 		dvm_track->hdt_refcnt--;
1117 	} else if ((new_dhp1 != NULL) && (new_dhp2 != NULL)) {
1118 		dvm_track->hdt_refcnt++;
1119 	}
1120 	mutex_exit(&dvm_track->hdt_lock);
1121 
1122 	/*
1123 	 * For each of the cases where the region is being divided, then we
1124 	 * need to pass back the "Hermon devmap tracking structure".  This way
1125 	 * we get it back when each of the remaining pieces is subsequently
1126 	 * unmapped.
1127 	 */
1128 	if (new_dhp1 != NULL) {
1129 		*pvtp1 = pvtp;
1130 	}
1131 	if (new_dhp2 != NULL) {
1132 		*pvtp2 = pvtp;
1133 	}
1134 
1135 	/*
1136 	 * If the "Hermon devmap tracking structure" is no longer being
1137 	 * referenced, then free it up.  Otherwise, return.
1138 	 */
1139 	if (dvm_track->hdt_refcnt == 0) {
1140 		mutex_destroy(&dvm_track->hdt_lock);
1141 		kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
1142 
1143 		/*
1144 		 * If the mapping was invalid (see explanation above), then
1145 		 * no further processing is necessary.
1146 		 */
1147 		if (size == 0) {
1148 			return;
1149 		}
1150 	} else {
1151 		return;
1152 	}
1153 
1154 	/*
1155 	 * Now that we can guarantee that the user memory is fully unmapped,
1156 	 * we can use the "key" and "type" values to try to find the entry
1157 	 * in the "userland resources database".  If it's found, then it
1158 	 * indicates that the queue memory (CQ or QP) has not yet been freed.
1159 	 * In this case, we update the corresponding CQ or QP handle to
1160 	 * indicate that the "devmap_devmem_remap()" call will be unnecessary.
1161 	 * If it's _not_ found, then it indicates that the CQ or QP memory
1162 	 * was, in fact, freed before it was unmapped (thus requiring a
1163 	 * previous invalidation by remapping - which will already have
1164 	 * been done in the free routine).
1165 	 */
1166 	status = hermon_umap_db_find(state->hs_instance, key, type, &value,
1167 	    0, NULL);
1168 	if (status == DDI_SUCCESS) {
1169 		/*
1170 		 * Depending on the type of the mapped resource (CQ or QP),
1171 		 * update handle to indicate that no invalidation remapping
1172 		 * will be necessary.
1173 		 */
1174 		if (type == MLNX_UMAP_CQMEM_RSRC) {
1175 
1176 			/* Use "value" to convert to CQ handle */
1177 			rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
1178 			cq = (hermon_cqhdl_t)rsrcp->hr_addr;
1179 
1180 			/*
1181 			 * Invalidate the handle to the userland mapping.
1182 			 * Note: We must ensure that the mapping being
1183 			 * unmapped here is the current one for the CQ.  It
1184 			 * is possible that it might not be if this CQ has
1185 			 * been resized and the previous CQ memory has not
1186 			 * yet been unmapped.  But in that case, because of
1187 			 * the devmap_devmem_remap(), there is no longer any
1188 			 * association between the mapping and the real CQ
1189 			 * kernel memory.
1190 			 */
1191 			mutex_enter(&cq->cq_lock);
1192 			if (cq->cq_umap_dhp == dhp) {
1193 				cq->cq_umap_dhp = NULL;
1194 			}
1195 			mutex_exit(&cq->cq_lock);
1196 
1197 		} else if (type == MLNX_UMAP_QPMEM_RSRC) {
1198 
1199 			/* Use "value" to convert to QP handle */
1200 			rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
1201 			qp = (hermon_qphdl_t)rsrcp->hr_addr;
1202 
1203 			/*
1204 			 * Invalidate the handle to the userland mapping.
1205 			 * Note: we ensure that the mapping being unmapped
1206 			 * here is the current one for the QP.  This is
1207 			 * more of a sanity check here since, unlike CQs
1208 			 * (above) we do not support resize of QPs.
1209 			 */
1210 			mutex_enter(&qp->qp_lock);
1211 			if (qp->qp_umap_dhp == dhp) {
1212 				qp->qp_umap_dhp = NULL;
1213 			}
1214 			mutex_exit(&qp->qp_lock);
1215 
1216 		} else if (type == MLNX_UMAP_SRQMEM_RSRC) {
1217 
1218 			/* Use "value" to convert to SRQ handle */
1219 			rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
1220 			srq = (hermon_srqhdl_t)rsrcp->hr_addr;
1221 
1222 			/*
1223 			 * Invalidate the handle to the userland mapping.
1224 			 * Note: we ensure that the mapping being unmapped
1225 			 * here is the current one for the QP.  This is
1226 			 * more of a sanity check here since, unlike CQs
1227 			 * (above) we do not support resize of QPs.
1228 			 */
1229 			mutex_enter(&srq->srq_lock);
1230 			if (srq->srq_umap_dhp == dhp) {
1231 				srq->srq_umap_dhp = NULL;
1232 			}
1233 			mutex_exit(&srq->srq_lock);
1234 		}
1235 	}
1236 }
1237 
1238 
1239 /*
1240  * hermon_devmap_devmem_map()
1241  *    Context: Can be called from kernel context.
1242  */
1243 /* ARGSUSED */
1244 static int
hermon_devmap_devmem_map(devmap_cookie_t dhp,dev_t dev,uint_t flags,offset_t off,size_t len,void ** pvtp)1245 hermon_devmap_devmem_map(devmap_cookie_t dhp, dev_t dev, uint_t flags,
1246     offset_t off, size_t len, void **pvtp)
1247 {
1248 	hermon_state_t		*state;
1249 	hermon_devmap_track_t	*dvm_track;
1250 	minor_t			instance;
1251 
1252 	/* Get Hermon softstate structure from instance */
1253 	instance = HERMON_DEV_INSTANCE(dev);
1254 	state = ddi_get_soft_state(hermon_statep, instance);
1255 	if (state == NULL) {
1256 		return (ENXIO);
1257 	}
1258 
1259 	/*
1260 	 * Allocate an entry to track the mapping and unmapping of this
1261 	 * resource.  Note:  We don't need to initialize the "refcnt" or
1262 	 * "offset" fields here, nor do we need to initialize the mutex
1263 	 * used with the "refcnt".  Since UAR pages are single pages, they
1264 	 * are not subject to "partial" unmappings.  This makes these other
1265 	 * fields unnecessary.
1266 	 */
1267 	dvm_track = (hermon_devmap_track_t *)kmem_zalloc(
1268 	    sizeof (hermon_devmap_track_t), KM_SLEEP);
1269 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
1270 	dvm_track->hdt_state  = state;
1271 	dvm_track->hdt_size   = (uint_t)PAGESIZE;
1272 
1273 	/*
1274 	 * Pass the private "Hermon devmap tracking structure" back.  This
1275 	 * pointer will be returned in a subsequent "unmap" callback.
1276 	 */
1277 	*pvtp = dvm_track;
1278 
1279 	return (DDI_SUCCESS);
1280 }
1281 
1282 
1283 /*
1284  * hermon_devmap_devmem_dup()
1285  *    Context: Can be called from kernel context.
1286  */
1287 /* ARGSUSED */
1288 static int
hermon_devmap_devmem_dup(devmap_cookie_t dhp,void * pvtp,devmap_cookie_t new_dhp,void ** new_pvtp)1289 hermon_devmap_devmem_dup(devmap_cookie_t dhp, void *pvtp,
1290     devmap_cookie_t new_dhp, void **new_pvtp)
1291 {
1292 	hermon_state_t		*state;
1293 	hermon_devmap_track_t	*dvm_track;
1294 	uint_t			maxprot;
1295 	int			status;
1296 
1297 	/*
1298 	 * Extract the Hermon softstate pointer from "Hermon devmap tracking
1299 	 * structure" (in "pvtp").  Note: If the tracking structure is NULL
1300 	 * here, it means that the mapping corresponds to an invalid mapping.
1301 	 * In this case, it can be safely ignored ("new_pvtp" set to NULL).
1302 	 */
1303 	dvm_track = (hermon_devmap_track_t *)pvtp;
1304 	if (dvm_track == NULL) {
1305 		*new_pvtp = NULL;
1306 		return (DDI_SUCCESS);
1307 	}
1308 
1309 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
1310 	state = dvm_track->hdt_state;
1311 
1312 	/*
1313 	 * Since this devmap_dup() entry point is generally called
1314 	 * when a process does fork(2), it is incumbent upon the driver
1315 	 * to insure that the child does not inherit a valid copy of
1316 	 * the parent's resource.  This is accomplished by using
1317 	 * devmap_devmem_remap() to invalidate the child's mapping to the
1318 	 * kernel memory.
1319 	 */
1320 	maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
1321 	status = devmap_devmem_remap(new_dhp, state->hs_dip, 0, 0,
1322 	    dvm_track->hdt_size, maxprot, DEVMAP_MAPPING_INVALID, NULL);
1323 	if (status != DDI_SUCCESS) {
1324 		HERMON_WARNING(state, "failed in hermon_devmap_devmem_dup()");
1325 		return (status);
1326 	}
1327 
1328 	/*
1329 	 * Since the region is invalid, there is no need for us to
1330 	 * allocate and continue to track an additional "Hermon devmap
1331 	 * tracking structure".  Instead we return NULL here, which is an
1332 	 * indication to the devmap_unmap() entry point that this entry
1333 	 * can be safely ignored.
1334 	 */
1335 	*new_pvtp = NULL;
1336 
1337 	return (DDI_SUCCESS);
1338 }
1339 
1340 
1341 /*
1342  * hermon_devmap_devmem_unmap()
1343  *    Context: Can be called from kernel context.
1344  */
1345 /* ARGSUSED */
1346 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)1347 hermon_devmap_devmem_unmap(devmap_cookie_t dhp, void *pvtp, offset_t off,
1348     size_t len, devmap_cookie_t new_dhp1, void **pvtp1,
1349     devmap_cookie_t new_dhp2, void **pvtp2)
1350 {
1351 	hermon_devmap_track_t	*dvm_track;
1352 
1353 	/*
1354 	 * Free up the "Hermon devmap tracking structure" (in "pvtp").
1355 	 * There cannot be "partial" unmappings here because all UAR pages
1356 	 * are single pages.  Note: If the tracking structure is NULL here,
1357 	 * it means that the mapping corresponds to an invalid mapping.  In
1358 	 * this case, it can be safely ignored.
1359 	 */
1360 	dvm_track = (hermon_devmap_track_t *)pvtp;
1361 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dvm_track))
1362 	if (dvm_track == NULL) {
1363 		return;
1364 	}
1365 
1366 	kmem_free(dvm_track, sizeof (hermon_devmap_track_t));
1367 }
1368 
1369 
1370 /*
1371  * hermon_umap_ci_data_in()
1372  *    Context: Can be called from user or kernel context.
1373  */
1374 /* ARGSUSED */
1375 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)1376 hermon_umap_ci_data_in(hermon_state_t *state, ibt_ci_data_flags_t flags,
1377     ibt_object_type_t object, void *hdl, void *data_p, size_t data_sz)
1378 {
1379 	int	status;
1380 
1381 	/*
1382 	 * Depending on the type of object about which additional information
1383 	 * is being provided (currently only MR is supported), we call the
1384 	 * appropriate resource-specific function.
1385 	 */
1386 	switch (object) {
1387 	case IBT_HDL_MR:
1388 		status = hermon_umap_mr_data_in((hermon_mrhdl_t)hdl,
1389 		    (ibt_mr_data_in_t *)data_p, data_sz);
1390 		if (status != DDI_SUCCESS) {
1391 			return (status);
1392 		}
1393 		break;
1394 
1395 	/*
1396 	 * For other possible valid IBT types, we return IBT_NOT_SUPPORTED,
1397 	 * since the Hermon driver does not support these.
1398 	 */
1399 	case IBT_HDL_HCA:
1400 	case IBT_HDL_QP:
1401 	case IBT_HDL_CQ:
1402 	case IBT_HDL_PD:
1403 	case IBT_HDL_MW:
1404 	case IBT_HDL_AH:
1405 	case IBT_HDL_SCHED:
1406 	case IBT_HDL_EEC:
1407 	case IBT_HDL_RDD:
1408 	case IBT_HDL_SRQ:
1409 		return (IBT_NOT_SUPPORTED);
1410 
1411 	/*
1412 	 * Any other types are invalid.
1413 	 */
1414 	default:
1415 		return (IBT_INVALID_PARAM);
1416 	}
1417 
1418 	return (DDI_SUCCESS);
1419 }
1420 
1421 
1422 /*
1423  * hermon_umap_mr_data_in()
1424  *    Context: Can be called from user or kernel context.
1425  */
1426 static ibt_status_t
hermon_umap_mr_data_in(hermon_mrhdl_t mr,ibt_mr_data_in_t * data,size_t data_sz)1427 hermon_umap_mr_data_in(hermon_mrhdl_t mr, ibt_mr_data_in_t *data,
1428     size_t data_sz)
1429 {
1430 	if (data->mr_rev != IBT_MR_DATA_IN_IF_VERSION) {
1431 		return (IBT_NOT_SUPPORTED);
1432 	}
1433 
1434 	/* Check for valid MR handle pointer */
1435 	if (mr == NULL) {
1436 		return (IBT_MR_HDL_INVALID);
1437 	}
1438 
1439 	/* Check for valid MR input structure size */
1440 	if (data_sz < sizeof (ibt_mr_data_in_t)) {
1441 		return (IBT_INSUFF_RESOURCE);
1442 	}
1443 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
1444 
1445 	/*
1446 	 * Ensure that the MR corresponds to userland memory and that it is
1447 	 * a currently valid memory region as well.
1448 	 */
1449 	mutex_enter(&mr->mr_lock);
1450 	if ((mr->mr_is_umem == 0) || (mr->mr_umemcookie == NULL)) {
1451 		mutex_exit(&mr->mr_lock);
1452 		return (IBT_MR_HDL_INVALID);
1453 	}
1454 
1455 	/*
1456 	 * If it has passed all the above checks, then extract the callback
1457 	 * function and argument from the input structure.  Copy them into
1458 	 * the MR handle.  This function will be called only if the memory
1459 	 * corresponding to the MR handle gets a umem_lockmemory() callback.
1460 	 */
1461 	mr->mr_umem_cbfunc = data->mr_func;
1462 	mr->mr_umem_cbarg1 = data->mr_arg1;
1463 	mr->mr_umem_cbarg2 = data->mr_arg2;
1464 	mutex_exit(&mr->mr_lock);
1465 
1466 	return (DDI_SUCCESS);
1467 }
1468 
1469 
1470 /*
1471  * hermon_umap_ci_data_out()
1472  *    Context: Can be called from user or kernel context.
1473  */
1474 /* ARGSUSED */
1475 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)1476 hermon_umap_ci_data_out(hermon_state_t *state, ibt_ci_data_flags_t flags,
1477     ibt_object_type_t object, void *hdl, void *data_p, size_t data_sz)
1478 {
1479 	int	status;
1480 
1481 	/*
1482 	 * Depending on the type of object about which additional information
1483 	 * is being requested (CQ or QP), we call the appropriate resource-
1484 	 * specific mapping function.
1485 	 */
1486 	switch (object) {
1487 	case IBT_HDL_CQ:
1488 		status = hermon_umap_cq_data_out((hermon_cqhdl_t)hdl,
1489 		    (mlnx_umap_cq_data_out_t *)data_p, data_sz);
1490 		if (status != DDI_SUCCESS) {
1491 			return (status);
1492 		}
1493 		break;
1494 
1495 	case IBT_HDL_QP:
1496 		status = hermon_umap_qp_data_out((hermon_qphdl_t)hdl,
1497 		    (mlnx_umap_qp_data_out_t *)data_p, data_sz);
1498 		if (status != DDI_SUCCESS) {
1499 			return (status);
1500 		}
1501 		break;
1502 
1503 	case IBT_HDL_SRQ:
1504 		status = hermon_umap_srq_data_out((hermon_srqhdl_t)hdl,
1505 		    (mlnx_umap_srq_data_out_t *)data_p, data_sz);
1506 		if (status != DDI_SUCCESS) {
1507 			return (status);
1508 		}
1509 		break;
1510 
1511 	case IBT_HDL_PD:
1512 		status = hermon_umap_pd_data_out((hermon_pdhdl_t)hdl,
1513 		    (mlnx_umap_pd_data_out_t *)data_p, data_sz);
1514 		if (status != DDI_SUCCESS) {
1515 			return (status);
1516 		}
1517 		break;
1518 
1519 	/*
1520 	 * For other possible valid IBT types, we return IBT_NOT_SUPPORTED,
1521 	 * since the Hermon driver does not support these.
1522 	 */
1523 	case IBT_HDL_HCA:
1524 	case IBT_HDL_MR:
1525 	case IBT_HDL_MW:
1526 	case IBT_HDL_AH:
1527 	case IBT_HDL_SCHED:
1528 	case IBT_HDL_EEC:
1529 	case IBT_HDL_RDD:
1530 		return (IBT_NOT_SUPPORTED);
1531 
1532 	/*
1533 	 * Any other types are invalid.
1534 	 */
1535 	default:
1536 		return (IBT_INVALID_PARAM);
1537 	}
1538 
1539 	return (DDI_SUCCESS);
1540 }
1541 
1542 
1543 /*
1544  * hermon_umap_cq_data_out()
1545  *    Context: Can be called from user or kernel context.
1546  */
1547 static ibt_status_t
hermon_umap_cq_data_out(hermon_cqhdl_t cq,mlnx_umap_cq_data_out_t * data,size_t data_sz)1548 hermon_umap_cq_data_out(hermon_cqhdl_t cq, mlnx_umap_cq_data_out_t *data,
1549     size_t data_sz)
1550 {
1551 	/* Check for valid CQ handle pointer */
1552 	if (cq == NULL) {
1553 		return (IBT_CQ_HDL_INVALID);
1554 	}
1555 
1556 	/* Check for valid CQ mapping structure size */
1557 	if (data_sz < sizeof (mlnx_umap_cq_data_out_t)) {
1558 		return (IBT_INSUFF_RESOURCE);
1559 	}
1560 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
1561 
1562 	/* deal with cq_alloc() verses cq_resize() */
1563 	if (cq->cq_resize_hdl) {
1564 		data->mcq_maplen = cq->cq_resize_hdl->cq_cqinfo.qa_size;
1565 		data->mcq_numcqe = cq->cq_resize_hdl->cq_bufsz;
1566 	} else {
1567 		data->mcq_maplen = cq->cq_cqinfo.qa_size;
1568 		data->mcq_numcqe = cq->cq_bufsz;
1569 	}
1570 
1571 	/*
1572 	 * If it has passed all the above checks, then fill in all the useful
1573 	 * mapping information (including the mapping offset that will be
1574 	 * passed back to the devmap() interface during a subsequent mmap()
1575 	 * call.
1576 	 *
1577 	 * The "offset" for CQ mmap()'s looks like this:
1578 	 * +----------------------------------------+--------+--------------+
1579 	 * |		   CQ Number		    |  0x33  | Reserved (0) |
1580 	 * +----------------------------------------+--------+--------------+
1581 	 *	   (64 - 8 - PAGESHIFT) bits	    8 bits	PAGESHIFT bits
1582 	 *
1583 	 * This returns information about the mapping offset, the length of
1584 	 * the CQ memory, the CQ number (for use in later CQ doorbells), the
1585 	 * number of CQEs the CQ memory can hold, and the size of each CQE.
1586 	 */
1587 	data->mcq_rev			= MLNX_UMAP_IF_VERSION;
1588 	data->mcq_mapoffset		= ((((uint64_t)cq->cq_cqnum <<
1589 	    MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_CQMEM_RSRC) << PAGESHIFT);
1590 	data->mcq_cqnum			= cq->cq_cqnum;
1591 	data->mcq_cqesz			= sizeof (hermon_hw_cqe_t);
1592 
1593 	/* doorbell record fields */
1594 	data->mcq_polldbr_mapoffset	= cq->cq_dbr_mapoffset;
1595 	data->mcq_polldbr_maplen	= PAGESIZE;
1596 	data->mcq_polldbr_offset	= (uintptr_t)cq->cq_arm_ci_vdbr &
1597 	    PAGEOFFSET;
1598 	data->mcq_armdbr_mapoffset	= cq->cq_dbr_mapoffset;
1599 	data->mcq_armdbr_maplen		= PAGESIZE;
1600 	data->mcq_armdbr_offset		= data->mcq_polldbr_offset + 4;
1601 
1602 	return (DDI_SUCCESS);
1603 }
1604 
1605 
1606 /*
1607  * hermon_umap_qp_data_out()
1608  *    Context: Can be called from user or kernel context.
1609  */
1610 static ibt_status_t
hermon_umap_qp_data_out(hermon_qphdl_t qp,mlnx_umap_qp_data_out_t * data,size_t data_sz)1611 hermon_umap_qp_data_out(hermon_qphdl_t qp, mlnx_umap_qp_data_out_t *data,
1612     size_t data_sz)
1613 {
1614 	/* Check for valid QP handle pointer */
1615 	if (qp == NULL) {
1616 		return (IBT_QP_HDL_INVALID);
1617 	}
1618 
1619 	/* Check for valid QP mapping structure size */
1620 	if (data_sz < sizeof (mlnx_umap_qp_data_out_t)) {
1621 		return (IBT_INSUFF_RESOURCE);
1622 	}
1623 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
1624 
1625 	/*
1626 	 * If it has passed all the checks, then fill in all the useful
1627 	 * mapping information (including the mapping offset that will be
1628 	 * passed back to the devmap() interface during a subsequent mmap()
1629 	 * call.
1630 	 *
1631 	 * The "offset" for QP mmap()'s looks like this:
1632 	 * +----------------------------------------+--------+--------------+
1633 	 * |		   QP Number		    |  0x44  | Reserved (0) |
1634 	 * +----------------------------------------+--------+--------------+
1635 	 *	   (64 - 8 - PAGESHIFT) bits	    8 bits	PAGESHIFT bits
1636 	 *
1637 	 * This returns information about the mapping offset, the length of
1638 	 * the QP memory, and the QP number (for use in later send and recv
1639 	 * doorbells).  It also returns the following information for both
1640 	 * the receive work queue and the send work queue, respectively:  the
1641 	 * offset (from the base mapped address) of the start of the given
1642 	 * work queue, the 64-bit IB virtual address that corresponds to
1643 	 * the base mapped address (needed for posting WQEs though the
1644 	 * QP doorbells), the number of WQEs the given work queue can hold,
1645 	 * and the size of each WQE for the given work queue.
1646 	 */
1647 	data->mqp_rev		= MLNX_UMAP_IF_VERSION;
1648 	data->mqp_mapoffset	= ((((uint64_t)qp->qp_qpnum <<
1649 	    MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_QPMEM_RSRC) << PAGESHIFT);
1650 	data->mqp_maplen	= qp->qp_wqinfo.qa_size;
1651 	data->mqp_qpnum		= qp->qp_qpnum;
1652 
1653 	/*
1654 	 * If this QP is associated with a shared receive queue (SRQ),
1655 	 * then return invalid RecvQ parameters.  Otherwise, return
1656 	 * the proper parameter values.
1657 	 */
1658 	if (qp->qp_alloc_flags & IBT_QP_USES_SRQ) {
1659 		data->mqp_rq_off	= (uint32_t)qp->qp_wqinfo.qa_size;
1660 		data->mqp_rq_desc_addr	= (uint32_t)qp->qp_wqinfo.qa_size;
1661 		data->mqp_rq_numwqe	= 0;
1662 		data->mqp_rq_wqesz	= 0;
1663 		data->mqp_rdbr_mapoffset = 0;
1664 		data->mqp_rdbr_maplen	= 0;
1665 		data->mqp_rdbr_offset	= 0;
1666 	} else {
1667 		data->mqp_rq_off	= (uintptr_t)qp->qp_rq_buf -
1668 		    (uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
1669 		data->mqp_rq_desc_addr	= (uint32_t)((uintptr_t)qp->qp_rq_buf -
1670 		    qp->qp_desc_off);
1671 		data->mqp_rq_numwqe	= qp->qp_rq_bufsz;
1672 		data->mqp_rq_wqesz	= (1 << qp->qp_rq_log_wqesz);
1673 
1674 		/* doorbell record fields */
1675 		data->mqp_rdbr_mapoffset = qp->qp_rdbr_mapoffset;
1676 		data->mqp_rdbr_maplen	= PAGESIZE;
1677 		data->mqp_rdbr_offset	= (uintptr_t)qp->qp_rq_vdbr &
1678 		    PAGEOFFSET;
1679 	}
1680 	data->mqp_sq_off		= (uintptr_t)qp->qp_sq_buf -
1681 	    (uintptr_t)qp->qp_wqinfo.qa_buf_aligned;
1682 	data->mqp_sq_desc_addr	= (uint32_t)((uintptr_t)qp->qp_sq_buf -
1683 	    qp->qp_desc_off);
1684 	data->mqp_sq_numwqe	= qp->qp_sq_bufsz;
1685 	data->mqp_sq_wqesz	= (1 << qp->qp_sq_log_wqesz);
1686 	data->mqp_sq_headroomwqes = qp->qp_sq_hdrmwqes;
1687 
1688 	/* doorbell record fields */
1689 	data->mqp_sdbr_mapoffset = 0;
1690 	data->mqp_sdbr_maplen	= 0;
1691 	data->mqp_sdbr_offset	= 0;
1692 
1693 	return (DDI_SUCCESS);
1694 }
1695 
1696 
1697 /*
1698  * hermon_umap_srq_data_out()
1699  *    Context: Can be called from user or kernel context.
1700  */
1701 static ibt_status_t
hermon_umap_srq_data_out(hermon_srqhdl_t srq,mlnx_umap_srq_data_out_t * data,size_t data_sz)1702 hermon_umap_srq_data_out(hermon_srqhdl_t srq, mlnx_umap_srq_data_out_t *data,
1703     size_t data_sz)
1704 {
1705 	/* Check for valid SRQ handle pointer */
1706 	if (srq == NULL) {
1707 		return (IBT_SRQ_HDL_INVALID);
1708 	}
1709 
1710 	/* Check for valid SRQ mapping structure size */
1711 	if (data_sz < sizeof (mlnx_umap_srq_data_out_t)) {
1712 		return (IBT_INSUFF_RESOURCE);
1713 	}
1714 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
1715 
1716 	/*
1717 	 * If it has passed all the checks, then fill in all the useful
1718 	 * mapping information (including the mapping offset that will be
1719 	 * passed back to the devmap() interface during a subsequent mmap()
1720 	 * call.
1721 	 *
1722 	 * The "offset" for SRQ mmap()'s looks like this:
1723 	 * +----------------------------------------+--------+--------------+
1724 	 * |		   SRQ Number		    |  0x66  | Reserved (0) |
1725 	 * +----------------------------------------+--------+--------------+
1726 	 *	   (64 - 8 - PAGESHIFT) bits	    8 bits	PAGESHIFT bits
1727 	 *
1728 	 * This returns information about the mapping offset, the length of the
1729 	 * SRQ memory, and the SRQ number (for use in later send and recv
1730 	 * doorbells).  It also returns the following information for the
1731 	 * shared receive queue: the offset (from the base mapped address) of
1732 	 * the start of the given work queue, the 64-bit IB virtual address
1733 	 * that corresponds to the base mapped address (needed for posting WQEs
1734 	 * though the QP doorbells), the number of WQEs the given work queue
1735 	 * can hold, and the size of each WQE for the given work queue.
1736 	 */
1737 	data->msrq_rev		= MLNX_UMAP_IF_VERSION;
1738 	data->msrq_mapoffset	= ((((uint64_t)srq->srq_srqnum <<
1739 	    MLNX_UMAP_RSRC_TYPE_SHIFT) | MLNX_UMAP_SRQMEM_RSRC) << PAGESHIFT);
1740 	data->msrq_maplen	= srq->srq_wqinfo.qa_size;
1741 	data->msrq_srqnum	= srq->srq_srqnum;
1742 
1743 	data->msrq_desc_addr	= (uint32_t)((uintptr_t)srq->srq_wq_buf -
1744 	    srq->srq_desc_off);
1745 	data->msrq_numwqe	= srq->srq_wq_bufsz;
1746 	data->msrq_wqesz	= (1 << srq->srq_wq_log_wqesz);
1747 
1748 	/* doorbell record fields */
1749 	data->msrq_rdbr_mapoffset = srq->srq_rdbr_mapoffset;
1750 	data->msrq_rdbr_maplen	= PAGESIZE;
1751 	data->msrq_rdbr_offset	= (uintptr_t)srq->srq_wq_vdbr &
1752 	    PAGEOFFSET;
1753 
1754 	return (DDI_SUCCESS);
1755 }
1756 
1757 
1758 /*
1759  * hermon_umap_pd_data_out()
1760  *    Context: Can be called from user or kernel context.
1761  */
1762 static ibt_status_t
hermon_umap_pd_data_out(hermon_pdhdl_t pd,mlnx_umap_pd_data_out_t * data,size_t data_sz)1763 hermon_umap_pd_data_out(hermon_pdhdl_t pd, mlnx_umap_pd_data_out_t *data,
1764     size_t data_sz)
1765 {
1766 	/* Check for valid PD handle pointer */
1767 	if (pd == NULL) {
1768 		return (IBT_PD_HDL_INVALID);
1769 	}
1770 
1771 	/* Check for valid PD mapping structure size */
1772 	if (data_sz < sizeof (mlnx_umap_pd_data_out_t)) {
1773 		return (IBT_INSUFF_RESOURCE);
1774 	}
1775 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*data))
1776 
1777 	/*
1778 	 * If it has passed all the checks, then fill the PD table index
1779 	 * (the PD table allocated index for the PD pd_pdnum).
1780 	 */
1781 	data->mpd_rev		= MLNX_UMAP_IF_VERSION;
1782 	data->mpd_pdnum		= pd->pd_pdnum;
1783 
1784 	return (DDI_SUCCESS);
1785 }
1786 
1787 
1788 /*
1789  * hermon_umap_db_init()
1790  *    Context: Only called from attach() path context
1791  */
1792 void
hermon_umap_db_init(void)1793 hermon_umap_db_init(void)
1794 {
1795 	/*
1796 	 * Initialize the lock used by the Hermon "userland resources database"
1797 	 * This is used to ensure atomic access to add, remove, and find
1798 	 * entries in the database.
1799 	 */
1800 	mutex_init(&hermon_userland_rsrc_db.hdl_umapdb_lock, NULL,
1801 	    MUTEX_DRIVER, NULL);
1802 
1803 	/*
1804 	 * Initialize the AVL tree used for the "userland resources
1805 	 * database".  Using an AVL tree here provides the ability to
1806 	 * scale the database size to large numbers of resources.  The
1807 	 * entries in the tree are "hermon_umap_db_entry_t" (see
1808 	 * hermon_umap.h).  The tree is searched with the help of the
1809 	 * hermon_umap_db_compare() routine.
1810 	 */
1811 	avl_create(&hermon_userland_rsrc_db.hdl_umapdb_avl,
1812 	    hermon_umap_db_compare, sizeof (hermon_umap_db_entry_t),
1813 	    offsetof(hermon_umap_db_entry_t, hdbe_avlnode));
1814 }
1815 
1816 
1817 /*
1818  * hermon_umap_db_fini()
1819  *    Context: Only called from attach() and/or detach() path contexts
1820  */
1821 void
hermon_umap_db_fini(void)1822 hermon_umap_db_fini(void)
1823 {
1824 	/* Destroy the AVL tree for the "userland resources database" */
1825 	avl_destroy(&hermon_userland_rsrc_db.hdl_umapdb_avl);
1826 
1827 	/* Destroy the lock for the "userland resources database" */
1828 	mutex_destroy(&hermon_userland_rsrc_db.hdl_umapdb_lock);
1829 }
1830 
1831 
1832 /*
1833  * hermon_umap_db_alloc()
1834  *    Context: Can be called from user or kernel context.
1835  */
1836 hermon_umap_db_entry_t *
hermon_umap_db_alloc(uint_t instance,uint64_t key,uint_t type,uint64_t value)1837 hermon_umap_db_alloc(uint_t instance, uint64_t key, uint_t type, uint64_t value)
1838 {
1839 	hermon_umap_db_entry_t	*umapdb;
1840 
1841 	/* Allocate an entry to add to the "userland resources database" */
1842 	umapdb = kmem_zalloc(sizeof (hermon_umap_db_entry_t), KM_NOSLEEP);
1843 	if (umapdb == NULL) {
1844 		return (NULL);
1845 	}
1846 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*umapdb))
1847 
1848 	/* Fill in the fields in the database entry */
1849 	umapdb->hdbe_common.hdb_instance  = instance;
1850 	umapdb->hdbe_common.hdb_type	  = type;
1851 	umapdb->hdbe_common.hdb_key	  = key;
1852 	umapdb->hdbe_common.hdb_value	  = value;
1853 
1854 	return (umapdb);
1855 }
1856 
1857 
1858 /*
1859  * hermon_umap_db_free()
1860  *    Context: Can be called from user or kernel context.
1861  */
1862 void
hermon_umap_db_free(hermon_umap_db_entry_t * umapdb)1863 hermon_umap_db_free(hermon_umap_db_entry_t *umapdb)
1864 {
1865 	/* Free the database entry */
1866 	kmem_free(umapdb, sizeof (hermon_umap_db_entry_t));
1867 }
1868 
1869 
1870 /*
1871  * hermon_umap_db_add()
1872  *    Context: Can be called from user or kernel context.
1873  */
1874 void
hermon_umap_db_add(hermon_umap_db_entry_t * umapdb)1875 hermon_umap_db_add(hermon_umap_db_entry_t *umapdb)
1876 {
1877 	mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
1878 	hermon_umap_db_add_nolock(umapdb);
1879 	mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
1880 }
1881 
1882 
1883 /*
1884  * hermon_umap_db_add_nolock()
1885  *    Context: Can be called from user or kernel context.
1886  */
1887 void
hermon_umap_db_add_nolock(hermon_umap_db_entry_t * umapdb)1888 hermon_umap_db_add_nolock(hermon_umap_db_entry_t *umapdb)
1889 {
1890 	hermon_umap_db_query_t	query;
1891 	avl_index_t		where;
1892 
1893 	ASSERT(MUTEX_HELD(&hermon_userland_rsrc_db.hdl_umapdb_lock));
1894 
1895 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*umapdb))
1896 
1897 	/*
1898 	 * Copy the common portion of the "to-be-added" database entry
1899 	 * into the "hermon_umap_db_query_t" structure.  We use this structure
1900 	 * (with no flags set) to find the appropriate location in the
1901 	 * "userland resources database" for the new entry to be added.
1902 	 *
1903 	 * Note: we expect that this entry should not be found in the
1904 	 * database (unless something bad has happened).
1905 	 */
1906 	query.hqdb_common = umapdb->hdbe_common;
1907 	query.hqdb_flags  = 0;
1908 	(void) avl_find(&hermon_userland_rsrc_db.hdl_umapdb_avl, &query,
1909 	    &where);
1910 
1911 	/*
1912 	 * Now, using the "where" field from the avl_find() operation
1913 	 * above, we will insert the new database entry ("umapdb").
1914 	 */
1915 	avl_insert(&hermon_userland_rsrc_db.hdl_umapdb_avl, umapdb,
1916 	    where);
1917 }
1918 
1919 
1920 /*
1921  * hermon_umap_db_find()
1922  *    Context: Can be called from user or kernel context.
1923  */
1924 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)1925 hermon_umap_db_find(uint_t instance, uint64_t key, uint_t type,
1926     uint64_t *value, uint_t flag, hermon_umap_db_entry_t	**umapdb)
1927 {
1928 	int	status;
1929 
1930 	mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
1931 	status = hermon_umap_db_find_nolock(instance, key, type, value, flag,
1932 	    umapdb);
1933 	mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
1934 
1935 	return (status);
1936 }
1937 
1938 
1939 /*
1940  * hermon_umap_db_find_nolock()
1941  *    Context: Can be called from user or kernel context.
1942  */
1943 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)1944 hermon_umap_db_find_nolock(uint_t instance, uint64_t key, uint_t type,
1945     uint64_t *value, uint_t flags, hermon_umap_db_entry_t **umapdb)
1946 {
1947 	hermon_umap_db_query_t	query;
1948 	hermon_umap_db_entry_t	*entry;
1949 	avl_index_t		where;
1950 
1951 	ASSERT(MUTEX_HELD(&hermon_userland_rsrc_db.hdl_umapdb_lock));
1952 
1953 	/*
1954 	 * Fill in key, type, instance, and flags values of the
1955 	 * hermon_umap_db_query_t in preparation for the database
1956 	 * lookup.
1957 	 */
1958 	query.hqdb_flags		= flags;
1959 	query.hqdb_common.hdb_key	= key;
1960 	query.hqdb_common.hdb_type	= type;
1961 	query.hqdb_common.hdb_instance	= instance;
1962 
1963 	/*
1964 	 * Perform the database query.  If no entry is found, then
1965 	 * return failure, else continue.
1966 	 */
1967 	entry = (hermon_umap_db_entry_t *)avl_find(
1968 	    &hermon_userland_rsrc_db.hdl_umapdb_avl, &query, &where);
1969 	if (entry == NULL) {
1970 		return (DDI_FAILURE);
1971 	}
1972 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*entry))
1973 
1974 	/*
1975 	 * If the flags argument specifies that the entry should
1976 	 * be removed if found, then call avl_remove() to remove
1977 	 * the entry from the database.
1978 	 */
1979 	if (flags & HERMON_UMAP_DB_REMOVE) {
1980 
1981 		avl_remove(&hermon_userland_rsrc_db.hdl_umapdb_avl, entry);
1982 
1983 		/*
1984 		 * The database entry is returned with the expectation
1985 		 * that the caller will use hermon_umap_db_free() to
1986 		 * free the entry's memory.  ASSERT that this is non-NULL.
1987 		 * NULL pointer should never be passed for the
1988 		 * HERMON_UMAP_DB_REMOVE case.
1989 		 */
1990 		ASSERT(umapdb != NULL);
1991 	}
1992 
1993 	/*
1994 	 * If the caller would like visibility to the database entry
1995 	 * (indicated through the use of a non-NULL "umapdb" argument),
1996 	 * then fill it in.
1997 	 */
1998 	if (umapdb != NULL) {
1999 		*umapdb = entry;
2000 	}
2001 
2002 	/* Extract value field from database entry and return success */
2003 	*value = entry->hdbe_common.hdb_value;
2004 
2005 	return (DDI_SUCCESS);
2006 }
2007 
2008 
2009 /*
2010  * hermon_umap_umemlock_cb()
2011  *    Context: Can be called from callback context.
2012  */
2013 void
hermon_umap_umemlock_cb(ddi_umem_cookie_t * umem_cookie)2014 hermon_umap_umemlock_cb(ddi_umem_cookie_t *umem_cookie)
2015 {
2016 	hermon_umap_db_entry_t	*umapdb;
2017 	hermon_state_t		*state;
2018 	hermon_rsrc_t 		*rsrcp;
2019 	hermon_mrhdl_t		mr;
2020 	uint64_t		value;
2021 	uint_t			instance;
2022 	int			status;
2023 	void			(*mr_callback)(void *, void *);
2024 	void			*mr_cbarg1, *mr_cbarg2;
2025 
2026 	/*
2027 	 * If this was userland memory, then we need to remove its entry
2028 	 * from the "userland resources database".  Note:  We use the
2029 	 * HERMON_UMAP_DB_IGNORE_INSTANCE flag here because we don't know
2030 	 * which instance was used when the entry was added (but we want
2031 	 * to know after the entry is found using the other search criteria).
2032 	 */
2033 	status = hermon_umap_db_find(0, (uint64_t)(uintptr_t)umem_cookie,
2034 	    MLNX_UMAP_MRMEM_RSRC, &value, (HERMON_UMAP_DB_REMOVE |
2035 	    HERMON_UMAP_DB_IGNORE_INSTANCE), &umapdb);
2036 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*umapdb))
2037 	if (status == DDI_SUCCESS) {
2038 		instance = umapdb->hdbe_common.hdb_instance;
2039 		state = ddi_get_soft_state(hermon_statep, instance);
2040 		if (state == NULL) {
2041 			cmn_err(CE_WARN, "Unable to match Hermon instance\n");
2042 			return;
2043 		}
2044 
2045 		/* Free the database entry */
2046 		hermon_umap_db_free(umapdb);
2047 
2048 		/* Use "value" to convert to an MR handle */
2049 		rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
2050 		mr = (hermon_mrhdl_t)rsrcp->hr_addr;
2051 
2052 		/*
2053 		 * If a callback has been provided, call it first.  This
2054 		 * callback is expected to do any cleanup necessary to
2055 		 * guarantee that the subsequent MR deregister (below)
2056 		 * will succeed.  Specifically, this means freeing up memory
2057 		 * windows which might have been associated with the MR.
2058 		 */
2059 		mutex_enter(&mr->mr_lock);
2060 		mr_callback = mr->mr_umem_cbfunc;
2061 		mr_cbarg1   = mr->mr_umem_cbarg1;
2062 		mr_cbarg2   = mr->mr_umem_cbarg2;
2063 		mutex_exit(&mr->mr_lock);
2064 		if (mr_callback != NULL) {
2065 			mr_callback(mr_cbarg1, mr_cbarg2);
2066 		}
2067 
2068 		/*
2069 		 * Then call hermon_mr_deregister() to release the resources
2070 		 * associated with the MR handle.  Note: Because this routine
2071 		 * will also check for whether the ddi_umem_cookie_t is in the
2072 		 * database, it will take responsibility for disabling the
2073 		 * memory region and calling ddi_umem_unlock().
2074 		 */
2075 		status = hermon_mr_deregister(state, &mr, HERMON_MR_DEREG_ALL,
2076 		    HERMON_SLEEP);
2077 		if (status != DDI_SUCCESS) {
2078 			HERMON_WARNING(state, "Unexpected failure in "
2079 			    "deregister from callback\n");
2080 		}
2081 	}
2082 }
2083 
2084 
2085 /*
2086  * hermon_umap_db_compare()
2087  *    Context: Can be called from user or kernel context.
2088  */
2089 static int
hermon_umap_db_compare(const void * q,const void * e)2090 hermon_umap_db_compare(const void *q, const void *e)
2091 {
2092 	hermon_umap_db_common_t	*entry_common, *query_common;
2093 	uint_t			query_flags;
2094 
2095 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((hermon_umap_db_query_t *)q)))
2096 
2097 	entry_common = &((hermon_umap_db_entry_t *)e)->hdbe_common;
2098 	query_common = &((hermon_umap_db_query_t *)q)->hqdb_common;
2099 	query_flags  = ((hermon_umap_db_query_t *)q)->hqdb_flags;
2100 
2101 	/*
2102 	 * The first comparison is done on the "key" value in "query"
2103 	 * and "entry".  If they are not equal, then the appropriate
2104 	 * search direction is returned.  Else, we continue by
2105 	 * comparing "type".
2106 	 */
2107 	if (query_common->hdb_key < entry_common->hdb_key) {
2108 		return (-1);
2109 	} else if (query_common->hdb_key > entry_common->hdb_key) {
2110 		return (+1);
2111 	}
2112 
2113 	/*
2114 	 * If the search reaches this point, then "query" and "entry"
2115 	 * have equal key values.  So we continue be comparing their
2116 	 * "type" values.  Again, if they are not equal, then the
2117 	 * appropriate search direction is returned.  Else, we continue
2118 	 * by comparing "instance".
2119 	 */
2120 	if (query_common->hdb_type < entry_common->hdb_type) {
2121 		return (-1);
2122 	} else if (query_common->hdb_type > entry_common->hdb_type) {
2123 		return (+1);
2124 	}
2125 
2126 	/*
2127 	 * If the search reaches this point, then "query" and "entry"
2128 	 * have exactly the same key and type values.  Now we consult
2129 	 * the "flags" field in the query to determine whether the
2130 	 * "instance" is relevant to the search.  If the
2131 	 * HERMON_UMAP_DB_IGNORE_INSTANCE flags is set, then return
2132 	 * success (0) here.  Otherwise, continue the search by comparing
2133 	 * instance values and returning the appropriate search direction.
2134 	 */
2135 	if (query_flags & HERMON_UMAP_DB_IGNORE_INSTANCE) {
2136 		return (0);
2137 	}
2138 
2139 	/*
2140 	 * If the search has reached this point, then "query" and "entry"
2141 	 * can only be differentiated by their instance values.  If these
2142 	 * are not equal, then return the appropriate search direction.
2143 	 * Else, we return success (0).
2144 	 */
2145 	if (query_common->hdb_instance < entry_common->hdb_instance) {
2146 		return (-1);
2147 	} else if (query_common->hdb_instance > entry_common->hdb_instance) {
2148 		return (+1);
2149 	}
2150 
2151 	/* Everything matches... so return success */
2152 	return (0);
2153 }
2154 
2155 
2156 /*
2157  * hermon_umap_db_set_onclose_cb()
2158  *    Context: Can be called from user or kernel context.
2159  */
2160 int
hermon_umap_db_set_onclose_cb(dev_t dev,uint64_t flag,int (* callback)(void *),void * arg)2161 hermon_umap_db_set_onclose_cb(dev_t dev, uint64_t flag,
2162     int (*callback)(void *), void *arg)
2163 {
2164 	hermon_umap_db_priv_t	*priv;
2165 	hermon_umap_db_entry_t	*umapdb;
2166 	minor_t			instance;
2167 	uint64_t		value;
2168 	int			status;
2169 
2170 	instance = HERMON_DEV_INSTANCE(dev);
2171 	if (instance == (minor_t)-1) {
2172 		return (DDI_FAILURE);
2173 	}
2174 
2175 	if (flag != HERMON_ONCLOSE_FLASH_INPROGRESS) {
2176 		return (DDI_FAILURE);
2177 	}
2178 
2179 	/*
2180 	 * Grab the lock for the "userland resources database" and find
2181 	 * the entry corresponding to this minor number.  Once it's found,
2182 	 * allocate (if necessary) and add an entry (in the "hdb_priv"
2183 	 * field) to indicate that further processing may be needed during
2184 	 * Hermon's close() handling.
2185 	 */
2186 	mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2187 	status = hermon_umap_db_find_nolock(instance, dev,
2188 	    MLNX_UMAP_PID_RSRC, &value, 0, &umapdb);
2189 	if (status != DDI_SUCCESS) {
2190 		mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2191 		return (DDI_FAILURE);
2192 	}
2193 
2194 	priv = (hermon_umap_db_priv_t *)umapdb->hdbe_common.hdb_priv;
2195 	if (priv == NULL) {
2196 		priv = (hermon_umap_db_priv_t *)kmem_zalloc(
2197 		    sizeof (hermon_umap_db_priv_t), KM_NOSLEEP);
2198 		if (priv == NULL) {
2199 			mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2200 			return (DDI_FAILURE);
2201 		}
2202 	}
2203 
2204 	/*
2205 	 * Save away the callback and argument to be used during Hermon's
2206 	 * close() processing.
2207 	 */
2208 	priv->hdp_cb	= callback;
2209 	priv->hdp_arg	= arg;
2210 
2211 	umapdb->hdbe_common.hdb_priv = (void *)priv;
2212 	mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2213 
2214 	return (DDI_SUCCESS);
2215 }
2216 
2217 
2218 /*
2219  * hermon_umap_db_clear_onclose_cb()
2220  *    Context: Can be called from user or kernel context.
2221  */
2222 int
hermon_umap_db_clear_onclose_cb(dev_t dev,uint64_t flag)2223 hermon_umap_db_clear_onclose_cb(dev_t dev, uint64_t flag)
2224 {
2225 	hermon_umap_db_priv_t	*priv;
2226 	hermon_umap_db_entry_t	*umapdb;
2227 	minor_t			instance;
2228 	uint64_t		value;
2229 	int			status;
2230 
2231 	instance = HERMON_DEV_INSTANCE(dev);
2232 	if (instance == (minor_t)-1) {
2233 		return (DDI_FAILURE);
2234 	}
2235 
2236 	if (flag != HERMON_ONCLOSE_FLASH_INPROGRESS) {
2237 		return (DDI_FAILURE);
2238 	}
2239 
2240 	/*
2241 	 * Grab the lock for the "userland resources database" and find
2242 	 * the entry corresponding to this minor number.  Once it's found,
2243 	 * remove the entry (in the "hdb_priv" field) that indicated the
2244 	 * need for further processing during Hermon's close().  Free the
2245 	 * entry, if appropriate.
2246 	 */
2247 	mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2248 	status = hermon_umap_db_find_nolock(instance, dev,
2249 	    MLNX_UMAP_PID_RSRC, &value, 0, &umapdb);
2250 	if (status != DDI_SUCCESS) {
2251 		mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2252 		return (DDI_FAILURE);
2253 	}
2254 
2255 	priv = (hermon_umap_db_priv_t *)umapdb->hdbe_common.hdb_priv;
2256 	if (priv != NULL) {
2257 		kmem_free(priv, sizeof (hermon_umap_db_priv_t));
2258 		priv = NULL;
2259 	}
2260 
2261 	umapdb->hdbe_common.hdb_priv = (void *)priv;
2262 	mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
2263 	return (DDI_SUCCESS);
2264 }
2265 
2266 
2267 /*
2268  * hermon_umap_db_clear_onclose_cb()
2269  *    Context: Can be called from user or kernel context.
2270  */
2271 int
hermon_umap_db_handle_onclose_cb(hermon_umap_db_priv_t * priv)2272 hermon_umap_db_handle_onclose_cb(hermon_umap_db_priv_t *priv)
2273 {
2274 	int	(*callback)(void *);
2275 
2276 	ASSERT(MUTEX_HELD(&hermon_userland_rsrc_db.hdl_umapdb_lock));
2277 
2278 	/*
2279 	 * Call the callback.
2280 	 *    Note: Currently there is only one callback (in "hdp_cb"), but
2281 	 *    in the future there may be more, depending on what other types
2282 	 *    of interaction there are between userland processes and the
2283 	 *    driver.
2284 	 */
2285 	callback = priv->hdp_cb;
2286 	return (callback(priv->hdp_arg));
2287 }
2288