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) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * sol_uverbs.c
28  *
29  * Solaris OFED User Verbs kernel agent module
30  *
31  */
32 #include <sys/devops.h>
33 #include <sys/conf.h>
34 #include <sys/modctl.h>
35 #include <sys/types.h>
36 #include <sys/file.h>
37 #include <sys/errno.h>
38 #include <sys/open.h>
39 #include <sys/cred.h>
40 #include <sys/uio.h>
41 #include <sys/semaphore.h>
42 #include <sys/stat.h>
43 #include <sys/ddi.h>
44 #include <sys/sunddi.h>
45 #include <sys/ib/clients/of/ofa_solaris.h>
46 
47 #include <sys/ib/ibtl/ibvti.h>
48 #include <sys/ib/clients/of/sol_ofs/sol_ofs_common.h>
49 #include <sys/ib/clients/of/ofed_kernel.h>
50 #include <sys/ib/clients/of/sol_uverbs/sol_uverbs.h>
51 #include <sys/ib/clients/of/sol_uverbs/sol_uverbs_event.h>
52 #include <sys/ib/clients/of/sol_uverbs/sol_uverbs_comp.h>
53 #include <sys/ib/clients/of/sol_uverbs/sol_uverbs_qp.h>
54 
55 static void *statep;
56 static ibt_clnt_hdl_t	sol_uverbs_ib_clntp = NULL;
57 
58 char	*sol_uverbs_dbg_str = "sol_uverbs";
59 
60 static int sol_uverbs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
61 static int sol_uverbs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
62 static int sol_uverbs_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
63     void **resultp);
64 static int sol_uverbs_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
65     int flags, char *name, caddr_t valuep, int *lengthp);
66 static int sol_uverbs_open(dev_t *devp, int flag, int otyp, cred_t *cred);
67 static int sol_uverbs_close(dev_t dev, int flag, int otyp, cred_t *cred);
68 static int sol_uverbs_poll(dev_t, short, int, short *, struct pollhead **);
69 static int sol_uverbs_read(dev_t dev, struct uio *uiop, cred_t *credp);
70 static int sol_uverbs_mmap(dev_t dev, off_t sol_uverbs_mmap, int prot);
71 static int sol_uverbs_write(dev_t dev, struct uio *uiop, cred_t *credp);
72 
73 static struct cb_ops sol_uverbs_cb_ops = {
74 	.cb_open	= sol_uverbs_open,
75 	.cb_close	= sol_uverbs_close,
76 	.cb_strategy	= nodev,
77 	.cb_print	= nodev,
78 	.cb_dump	= nodev,
79 	.cb_read	= sol_uverbs_read,
80 	.cb_write	= sol_uverbs_write,
81 	.cb_ioctl	= nodev,
82 	.cb_devmap	= nodev,
83 	.cb_mmap	= sol_uverbs_mmap,
84 	.cb_segmap	= nodev,
85 	.cb_chpoll	= sol_uverbs_poll,
86 	.cb_prop_op	= sol_uverbs_prop_op,
87 	.cb_str		= NULL,
88 	.cb_flag	= D_NEW | D_MP,
89 	.cb_rev		= CB_REV,
90 	.cb_aread	= nodev,
91 	.cb_awrite	= nodev
92 };
93 
94 static struct dev_ops sol_uverbs_dev_ops = {
95 	.devo_rev	= DEVO_REV,
96 	.devo_refcnt	= 0,
97 	.devo_getinfo	= sol_uverbs_getinfo,
98 	.devo_identify	= nulldev,
99 	.devo_probe	= nulldev,
100 	.devo_attach	= sol_uverbs_attach,
101 	.devo_detach	= sol_uverbs_detach,
102 	.devo_reset	= nodev,
103 	.devo_cb_ops	= &sol_uverbs_cb_ops,
104 	.devo_bus_ops	= NULL,
105 	.devo_power	= nodev,
106 	.devo_quiesce	= ddi_quiesce_not_needed
107 };
108 
109 static struct modldrv modldrv = {
110 	.drv_modops	= &mod_driverops,
111 	.drv_linkinfo	= "Solaris User Verbs driver",
112 	.drv_dev_ops	= &sol_uverbs_dev_ops
113 };
114 
115 static struct modlinkage modlinkage = {
116 	.ml_rev			= MODREV_1,
117 	.ml_linkage = {
118 		[0]		= &modldrv,
119 		[1]		= NULL,
120 	}
121 };
122 
123 /*
124  * User Object Tables for management of user resources. The tables are driver
125  * wide, but each user context maintains a list of the objects it has created
126  * that is used in cleanup.
127  */
128 sol_ofs_uobj_table_t uverbs_uctxt_uo_tbl;
129 sol_ofs_uobj_table_t uverbs_upd_uo_tbl;
130 sol_ofs_uobj_table_t uverbs_uah_uo_tbl;
131 sol_ofs_uobj_table_t uverbs_umr_uo_tbl;
132 sol_ofs_uobj_table_t uverbs_ucq_uo_tbl;
133 sol_ofs_uobj_table_t uverbs_usrq_uo_tbl;
134 sol_ofs_uobj_table_t uverbs_uqp_uo_tbl;
135 sol_ofs_uobj_table_t uverbs_ufile_uo_tbl;
136 
137 static void sol_uverbs_user_objects_init(void);
138 static void sol_uverbs_user_objects_fini(void);
139 
140 /*
141  * Open Fabric User Verbs API, command table. See ib_user_verbs.h for
142  * definitions.
143  */
144 static int (*uverbs_cmd_table[])(uverbs_uctxt_uobj_t *uctxt, char *buf,
145 	int in_len, int out_len) = {
146 
147 	[IB_USER_VERBS_CMD_GET_CONTEXT]   	= sol_uverbs_get_context,
148 	[IB_USER_VERBS_CMD_QUERY_DEVICE]  	= sol_uverbs_query_device,
149 	[IB_USER_VERBS_CMD_QUERY_PORT]    	= sol_uverbs_query_port,
150 	[IB_USER_VERBS_CMD_ALLOC_PD]		= sol_uverbs_alloc_pd,
151 	[IB_USER_VERBS_CMD_DEALLOC_PD]		= sol_uverbs_dealloc_pd,
152 	[IB_USER_VERBS_CMD_REG_MR]		= sol_uverbs_reg_mr,
153 	[IB_USER_VERBS_CMD_DEREG_MR]		= sol_uverbs_dereg_mr,
154 	[IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL] =
155 					sol_uverbs_create_comp_channel,
156 	[IB_USER_VERBS_CMD_CREATE_CQ]		= sol_uverbs_create_cq,
157 	[IB_USER_VERBS_CMD_RESIZE_CQ]		= sol_uverbs_resize_cq,
158 	[IB_USER_VERBS_CMD_POLL_CQ]		= sol_uverbs_poll_cq,
159 	[IB_USER_VERBS_CMD_REQ_NOTIFY_CQ]	= sol_uverbs_req_notify_cq,
160 	[IB_USER_VERBS_CMD_DESTROY_CQ]    	= sol_uverbs_destroy_cq,
161 	[IB_USER_VERBS_CMD_CREATE_QP]		= sol_uverbs_create_qp,
162 	[IB_USER_VERBS_CMD_QUERY_QP]		= sol_uverbs_query_qp,
163 	[IB_USER_VERBS_CMD_MODIFY_QP]		= sol_uverbs_modify_qp,
164 	[IB_USER_VERBS_CMD_DESTROY_QP]    	= sol_uverbs_destroy_qp,
165 	[IB_USER_VERBS_CMD_POST_SEND]    	= sol_uverbs_dummy_command,
166 	[IB_USER_VERBS_CMD_POST_RECV]    	= sol_uverbs_dummy_command,
167 	[IB_USER_VERBS_CMD_POST_SRQ_RECV]    	= sol_uverbs_dummy_command,
168 	[IB_USER_VERBS_CMD_CREATE_AH]    	= sol_uverbs_create_ah,
169 	[IB_USER_VERBS_CMD_DESTROY_AH]    	= sol_uverbs_destroy_ah,
170 	[IB_USER_VERBS_CMD_ATTACH_MCAST]  	= sol_uverbs_attach_mcast,
171 	[IB_USER_VERBS_CMD_DETACH_MCAST]  	= sol_uverbs_detach_mcast,
172 	[IB_USER_VERBS_CMD_CREATE_SRQ]    	= sol_uverbs_create_srq,
173 	[IB_USER_VERBS_CMD_MODIFY_SRQ]		= sol_uverbs_modify_srq,
174 	[IB_USER_VERBS_CMD_QUERY_SRQ]		= sol_uverbs_query_srq,
175 	[IB_USER_VERBS_CMD_DESTROY_SRQ]   	= sol_uverbs_destroy_srq,
176 
177 		/* TODO - XRC */
178 
179 	[IB_USER_VERBS_CMD_CREATE_XRC_SRQ]   	= sol_uverbs_dummy_command,
180 	[IB_USER_VERBS_CMD_OPEN_XRC_DOMAIN]   	= sol_uverbs_dummy_command,
181 	[IB_USER_VERBS_CMD_CLOSE_XRC_DOMAIN]   	= sol_uverbs_dummy_command,
182 	[IB_USER_VERBS_CMD_CREATE_XRC_RCV_QP]  	= sol_uverbs_dummy_command,
183 	[IB_USER_VERBS_CMD_MODIFY_XRC_RCV_QP]  	= sol_uverbs_dummy_command,
184 	[IB_USER_VERBS_CMD_QUERY_XRC_RCV_QP]   	= sol_uverbs_dummy_command,
185 	[IB_USER_VERBS_CMD_REG_XRC_RCV_QP]   	= sol_uverbs_dummy_command,
186 	[IB_USER_VERBS_CMD_UNREG_XRC_RCV_QP]   	= sol_uverbs_dummy_command,
187 	[IB_USER_VERBS_CMD_QUERY_GID]		= sol_uverbs_query_gid,
188 	[IB_USER_VERBS_CMD_QUERY_PKEY]		= sol_uverbs_query_pkey,
189 };
190 
191 /*
192  * Function:
193  *	sol_uverbs_hca_open
194  * Input:
195  *	mod_ctxt	- Pointer to the user verbs module context.
196  * Output:
197  *	None
198  * Returns:
199  *	Zero on success, else error code.
200  * Description:
201  *	Register as a client with the IBT framework and open all of the
202  *	HCA's present.
203  */
204 static int
sol_uverbs_hca_open(uverbs_module_context_t * mod_ctxt)205 sol_uverbs_hca_open(uverbs_module_context_t *mod_ctxt)
206 {
207 	int			status;
208 	int			hca_ndx;
209 #ifdef DEBUG
210 	llist_head_t		*entry;
211 	sol_uverbs_hca_t	*temp;
212 #endif
213 
214 	mod_ctxt->hca_count	= 0;
215 	mod_ctxt->hca_guid_list	= NULL;
216 	mod_ctxt->hcas		= NULL;
217 	mod_ctxt->clnt_hdl	= NULL;
218 
219 	mod_ctxt->clnt_modinfo.mi_ibt_version   = IBTI_V_CURR;
220 	mod_ctxt->clnt_modinfo.mi_clnt_class    = IBT_USER;
221 	mod_ctxt->clnt_modinfo.mi_async_handler = uverbs_async_event_handler;
222 	mod_ctxt->clnt_modinfo.mi_reserved	= NULL;
223 	mod_ctxt->clnt_modinfo.mi_clnt_name	= "sol_uverbs";
224 
225 	status = ibt_attach(&mod_ctxt->clnt_modinfo, mod_ctxt->dip,
226 	    mod_ctxt, &mod_ctxt->clnt_hdl);
227 
228 	if (status != IBT_SUCCESS) {
229 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
230 		    "hca_open:ibt_attach fail %d", status);
231 		status = ENODEV;
232 		goto out_err;
233 	}
234 	if (sol_uverbs_ib_clntp == NULL)
235 		sol_uverbs_ib_clntp  = mod_ctxt->clnt_hdl;
236 
237 	mod_ctxt->hca_count = ibt_get_hca_list(&mod_ctxt->hca_guid_list);
238 
239 	if (mod_ctxt->hca_count == 0) {
240 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
241 		    "hca_open: Zero HCAs on this system!");
242 		status = ENODEV;
243 		goto out_err;
244 	}
245 
246 	if (mod_ctxt->hca_count > SOL_UVERBS_DRIVER_MAX_HCA_MINOR) {
247 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
248 		    "hca_open: HCA count %d exceeds max %d",
249 		    mod_ctxt->hca_count, SOL_UVERBS_DRIVER_MAX_HCA_MINOR);
250 		status =  ENODEV;
251 		goto out_err;
252 	}
253 
254 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
255 	    "hca_open: No. of HCAs present %d", mod_ctxt->hca_count);
256 
257 	mod_ctxt->hcas = kmem_zalloc(mod_ctxt->hca_count *
258 	    sizeof (sol_uverbs_hca_t), KM_SLEEP);
259 	ASSERT(mod_ctxt->hcas != NULL);
260 
261 	/*
262 	 * Note: we open these in the reverse order of the guid list, although
263 	 * this is technically not required it is done this way so that the
264 	 * mapping will be in same order as the interfaces. Also note, that we
265 	 * provide a guid property, and the guid should be used to map a verbs
266 	 * device to an interface (i.e. don't depend on the order).
267 	 */
268 	for (hca_ndx = 0; hca_ndx < mod_ctxt->hca_count; hca_ndx++) {
269 		status = ibt_open_hca(mod_ctxt->clnt_hdl,
270 		    mod_ctxt->hca_guid_list[mod_ctxt->hca_count - hca_ndx -1],
271 		    &mod_ctxt->hcas[hca_ndx].hdl);
272 		if (status != IBT_SUCCESS) {
273 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
274 			    "hca_open: ibt_open_hca() returned %d",
275 			    status);
276 			goto out_err;
277 		}
278 
279 		mod_ctxt->hcas[hca_ndx].clnt_hdl = mod_ctxt->clnt_hdl;
280 		llist_head_init(&mod_ctxt->hcas[hca_ndx].list,
281 		    &mod_ctxt->hcas[hca_ndx]);
282 		mutex_init(&mod_ctxt->hcas[hca_ndx].event_handler_lock, NULL,
283 		    MUTEX_DRIVER, NULL);
284 		llist_head_init(&mod_ctxt->hcas[hca_ndx].event_handler_list,
285 		    NULL);
286 		mutex_init(&mod_ctxt->hcas[hca_ndx].client_data_lock, NULL,
287 		    MUTEX_DRIVER, NULL);
288 		llist_head_init(&mod_ctxt->hcas[hca_ndx].client_data_list,
289 		    NULL);
290 
291 		mutex_enter(&sol_uverbs_hca_lock);
292 		llist_add_tail(&mod_ctxt->hcas[hca_ndx].list,
293 		    &sol_uverbs_hca_list);
294 		mutex_exit(&sol_uverbs_hca_lock);
295 
296 		mod_ctxt->hcas[hca_ndx].guid =
297 		    mod_ctxt->hca_guid_list[mod_ctxt->hca_count - hca_ndx -1];
298 
299 		/*
300 		 * Get a cached copy of the HCA's attributes for easy access.
301 		 */
302 		status = ibt_query_hca(mod_ctxt->hcas[hca_ndx].hdl,
303 		    &mod_ctxt->hcas[hca_ndx].attr);
304 		if (status != IBT_SUCCESS) {
305 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
306 			    "hca_open: ibt_query_hca() failed "
307 			    "(status=%d)", status);
308 			goto out_err;
309 		}
310 
311 		/* Note : GUID is in host order here */
312 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
313 		    "hca_open: HCA index %d, HCA GUID: 0x%016llX",
314 		    hca_ndx, (u_longlong_t)mod_ctxt->hcas[hca_ndx].guid);
315 	}
316 
317 #ifdef DEBUG
318 	mutex_enter(&sol_uverbs_hca_lock);
319 	list_for_each(entry, &sol_uverbs_hca_list) {
320 		temp = (sol_uverbs_hca_t *)entry->ptr;
321 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
322 		    "HCA list: entry: %p, handle: %p, "
323 		    "GUID: 0x%016llX", (void *)entry, (void *)temp->hdl,
324 		    (u_longlong_t)temp->guid);
325 	}
326 	mutex_exit(&sol_uverbs_hca_lock);
327 #endif
328 	return (0);
329 
330 out_err:
331 	/*
332 	 * Note, cleanup of hca list and associated resources is done via
333 	 * uverbs_hca_close called outside this routine in the case of bad
334 	 * status.
335 	 */
336 	return (status);
337 }
338 
339 /*
340  * Function:
341  *	sol_uverbs_hca_close
342  * Input:
343  *	mod_ctxt	- Pointer to the module context.
344  * Output:
345  *	None
346  * Returns:
347  *	None
348  * Description:
349  * 	Close all of the IBT HCAs opened by the driver and detach from
350  *	the IBT framework.
351  */
352 static void
sol_uverbs_hca_close(uverbs_module_context_t * mod_ctxt)353 sol_uverbs_hca_close(uverbs_module_context_t *mod_ctxt)
354 {
355 	int    hca_ndx;
356 
357 	if (mod_ctxt->hcas != NULL) {
358 		mutex_enter(&sol_uverbs_hca_lock);
359 		llist_head_init(&sol_uverbs_hca_list, NULL);
360 		mutex_exit(&sol_uverbs_hca_lock);
361 		for (hca_ndx = 0; hca_ndx < mod_ctxt->hca_count; hca_ndx++) {
362 			if (mod_ctxt->hcas[hca_ndx].hdl != NULL) {
363 				mutex_destroy(&mod_ctxt->hcas[hca_ndx].
364 				    event_handler_lock);
365 				mutex_destroy(&mod_ctxt->hcas[hca_ndx].
366 				    client_data_lock);
367 				(void) ibt_close_hca(mod_ctxt->
368 				    hcas[hca_ndx].hdl);
369 			}
370 		}
371 		kmem_free(mod_ctxt->hcas,
372 		    mod_ctxt->hca_count * sizeof (sol_uverbs_hca_t));
373 		mod_ctxt->hcas = NULL;
374 	}
375 
376 	if ((mod_ctxt->hca_guid_list != NULL) && (mod_ctxt->hca_count > 0)) {
377 		ibt_free_hca_list(mod_ctxt->hca_guid_list, mod_ctxt->hca_count);
378 		mod_ctxt->hca_count	= 0;
379 		mod_ctxt->hca_guid_list = NULL;
380 	}
381 
382 	if (mod_ctxt->clnt_hdl != NULL) {
383 		(void) ibt_detach(mod_ctxt->clnt_hdl);
384 		mod_ctxt->clnt_hdl = NULL;
385 	}
386 }
387 
388 /*
389  * Function:
390  *	_init
391  * Input:
392  *	None
393  * Output:
394  *	None
395  * Returns:
396  *	DDI_SUCCESS  on success, else error code.
397  * Description:
398  * 	Perform Solaris OFED user verbs kernel agent driver initialization.
399  */
400 int
_init(void)401 _init(void)
402 {
403 	int	error;
404 
405 	error = ddi_soft_state_init(&statep,
406 	    sizeof (uverbs_module_context_t), 0);
407 
408 	if (error != 0) {
409 		return (error);
410 	}
411 
412 	sol_uverbs_user_objects_init();
413 	if (sol_uverbs_common_hca_init()) {
414 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
415 		    "uverbs_hca_init() failed");
416 		ddi_soft_state_fini(&statep);
417 		return (ENODEV);
418 	}
419 
420 	error = mod_install(&modlinkage);
421 	if (error != 0) {
422 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
423 		    "uverbs: mod_install failed!!");
424 		sol_uverbs_common_hca_fini();
425 		sol_uverbs_user_objects_fini();
426 		ddi_soft_state_fini(&statep);
427 	}
428 	return (error);
429 }
430 
431 /*
432  * Function:
433  *	_info
434  * Input:
435  *	modinfop	- Pointer to an opqque modinfo structure.
436  * Output:
437  *	modinfop	- Updated structure.
438  * Returns:
439  *	The mod_info() return code.
440  * Description:
441  * 	Return information about the loadable module via the mod_info()
442  *	kernel function call.
443  */
444 int
_info(struct modinfo * modinfop)445 _info(struct modinfo *modinfop)
446 {
447 	return (mod_info(&modlinkage, modinfop));
448 }
449 
450 /*
451  * Function:
452  *	_fini
453  * Input:
454  *	None
455  * Output:
456  *	None
457  * Returns:
458  *	DDI_SUCCESS  on success, else error code returned by
459  *	mod_remove kernel function.
460  * Description:
461  * 	Perform Solaris OFED user verbs kernel agent driver cleanup.
462  */
463 int
_fini(void)464 _fini(void)
465 {
466 	int    rc;
467 
468 	rc = mod_remove(&modlinkage);
469 	if (!rc) {
470 		sol_uverbs_common_hca_fini();
471 		sol_uverbs_user_objects_fini();
472 	}
473 	return (rc);
474 }
475 
476 int
sol_uverbs_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)477 sol_uverbs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
478 {
479 	uverbs_module_context_t	*mod_ctxt;
480 	int			rc, instance, hca_ndx;
481 
482 	switch (cmd) {
483 		case DDI_ATTACH:
484 			break;
485 		case DDI_RESUME:
486 			return (DDI_SUCCESS);
487 		default:
488 			return (DDI_FAILURE);
489 	}
490 
491 	/*
492 	 * Allocate a soft data structure based on this dev info
493 	 */
494 	instance = ddi_get_instance(dip);
495 	if (instance != 0) {
496 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
497 		    "attach: bad instance number %d", instance);
498 		return (DDI_FAILURE);
499 	}
500 
501 	if (ddi_soft_state_zalloc(statep, instance) != DDI_SUCCESS) {
502 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
503 		    "attach: bad state zalloc");
504 		return (DDI_FAILURE);
505 	}
506 
507 	mod_ctxt = ddi_get_soft_state(statep, instance);
508 	if (mod_ctxt == NULL) {
509 		ddi_soft_state_free(statep, instance);
510 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
511 		    "attach: cannot get soft state");
512 		return (DDI_FAILURE);
513 	}
514 
515 	/*
516 	 * Save off our private context in the dev_info
517 	 */
518 	mod_ctxt->dip = dip;
519 	ddi_set_driver_private(dip, mod_ctxt);
520 
521 	/*
522 	 * Opening of the hca will perform the ibt_attach and build a list of
523 	 * devices.
524 	 */
525 	rc = sol_uverbs_hca_open(mod_ctxt);
526 	if (rc) {
527 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
528 		    "attach: sol_uverbs_hca_open() (rc=%d)", rc);
529 		goto error;
530 	}
531 
532 	/*
533 	 * Export our ABI revision as a property.
534 	 */
535 	rc = ddi_prop_update_int(makedevice(ddi_driver_major(dip), 0),
536 	    dip, "abi-version", IB_USER_VERBS_ABI_VERSION);
537 	if (rc != DDI_SUCCESS) {
538 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
539 		    "attach: could not add abi-version property");
540 	}
541 
542 	/*
543 	 * Create the filesystem device node for each HCA.
544 	 */
545 	for (hca_ndx = 0; hca_ndx < mod_ctxt->hca_count; hca_ndx++) {
546 		char name[20];
547 
548 		(void) snprintf(name, 20, "uverbs%d", hca_ndx);
549 		rc = ddi_create_minor_node(dip, name, S_IFCHR, hca_ndx,
550 		    DDI_PSEUDO, 0);
551 		if (rc != DDI_SUCCESS) {
552 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
553 			    "attach: could not add character node");
554 			goto error;
555 		}
556 
557 		rc = ddi_prop_update_int64(makedevice(ddi_driver_major(dip),
558 		    hca_ndx), dip, "guid", mod_ctxt->hcas[hca_ndx].guid);
559 		if (rc != DDI_SUCCESS) {
560 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
561 			    "attach: could not add GUID property");
562 		}
563 
564 		rc = ddi_prop_update_int(makedevice(ddi_driver_major(dip),
565 		    hca_ndx), dip, "vendor-id",
566 		    mod_ctxt->hcas[hca_ndx].attr.hca_vendor_id);
567 		if (rc != DDI_SUCCESS) {
568 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
569 			    "attach: could not add vendor-id property");
570 		}
571 
572 		rc = ddi_prop_update_int(makedevice(ddi_driver_major(dip),
573 		    hca_ndx), dip, "device-id", mod_ctxt->
574 		    hcas[hca_ndx].attr.hca_device_id);
575 		if (rc != DDI_SUCCESS) {
576 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
577 			    "attach: could not add device-id property");
578 		}
579 	}
580 
581 	rc = ddi_create_minor_node(dip, "ucma",  S_IFCHR,
582 	    SOL_UVERBS_DRIVER_MAX_HCA_MINOR, DDI_PSEUDO, 0);
583 
584 	if (rc != DDI_SUCCESS) {
585 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
586 		    "attach: could not add minor for ucma");
587 		goto error;
588 	}
589 
590 	rc = ddi_create_minor_node(dip, "event",  S_IFCHR,
591 	    SOL_UVERBS_DRIVER_EVENT_MINOR, DDI_PSEUDO, 0);
592 
593 	if (rc != DDI_SUCCESS) {
594 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
595 		    "attach: could not add minor for events");
596 		goto error;
597 	}
598 
599 	ddi_report_dev(dip);
600 
601 	return (DDI_SUCCESS);
602 
603 error:
604 	/*
605 	 * Cleanup any resources and dettach.
606 	 */
607 	sol_uverbs_hca_close(mod_ctxt);
608 	ddi_soft_state_free(statep, instance);
609 
610 	return (rc);
611 }
612 
613 /*
614  * Function:
615  *	sol_uverbs_detach
616  * Input:
617  *	dip	- A pointer to the devices dev_info_t structure.
618  *	cmd	- Type of detach (DDI_DETACH or DDI_SUSPEND).
619  * Output:
620  *	None
621  * Returns:
622  *	DDI_SUCCESS on success, else error code.
623  * Description:
624  * 	Detaches thea driver module and will cause the driver to close
625  *	the underlying IBT HCA and detach from the IBT driver.  Note
626  *	that this call will fail if user verb consumers or ucma have a
627  *	sol_uverbs device open.
628  */
629 static int
sol_uverbs_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)630 sol_uverbs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
631 {
632 	int			instance;
633 	uverbs_module_context_t	*mod_ctxt;
634 
635 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "detach()");
636 
637 	if (cmd != DDI_DETACH) {
638 		return (DDI_FAILURE);
639 	}
640 
641 	instance = ddi_get_instance(dip);
642 	if (instance != 0) {
643 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
644 		    "detach: bad instance number 0x%x", instance);
645 		return (DDI_FAILURE);
646 	}
647 
648 	rw_enter(&uverbs_uctxt_uo_tbl.uobj_tbl_lock, RW_WRITER);
649 	if (uverbs_uctxt_uo_tbl.uobj_tbl_uo_cnt > 0) {
650 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
651 		    "detach(): device in use");
652 		rw_exit(&uverbs_uctxt_uo_tbl.uobj_tbl_lock);
653 		return (DDI_FAILURE);
654 	}
655 	rw_exit(&uverbs_uctxt_uo_tbl.uobj_tbl_lock);
656 
657 	mod_ctxt = ddi_get_soft_state(statep, instance);
658 
659 	/*
660 	 * Sanity check, do not detach if other kernel agents
661 	 * are still using sol_uverbs IBT handles.
662 	 */
663 	mutex_enter(&sol_uverbs_hca_lock);
664 	if (!llist_empty(&sol_uverbs_client_list)) {
665 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
666 		    "detach: agents still registered");
667 		mutex_exit(&sol_uverbs_hca_lock);
668 		return (DDI_FAILURE);
669 	}
670 	mutex_exit(&sol_uverbs_hca_lock);
671 
672 	/*
673 	 * Hca close will perform the detach from IBTF.
674 	 */
675 	sol_uverbs_hca_close(mod_ctxt);
676 
677 	ddi_soft_state_free(statep, instance);
678 	ddi_remove_minor_node(dip, NULL);
679 	return (DDI_SUCCESS);
680 }
681 
682 /*
683  * Function:
684  *	sol_uverbs_getinfo
685  * Input:
686  *	dip     - Deprecated, do not use.
687  *	cmd     - Command argument (DDI_INFO_DEVT2DEVINFO or
688  *	          DDI_INFO_DEVT2INSTANCE).
689  *	arg     - Command specific argument.
690  *	resultp - Pointer to place results.
691  * Output:
692  *	resultp	- Location is updated with command results.
693  * Returns:
694  *	DDI_SUCCESS on success, else error code.
695  * Description:
696  *	Depending on the request (cmd) return either the dev_info_t pointer
697  *	associated with the dev_info_t specified, or the instance.  Note
698  *	that we have only a single instance.
699  */
700 /* ARGSUSED */
701 static int
sol_uverbs_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)702 sol_uverbs_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
703     void **resultp)
704 {
705 	uverbs_module_context_t	*mod_ctxt;
706 
707 	switch (cmd) {
708 		case DDI_INFO_DEVT2DEVINFO:
709 			mod_ctxt = ddi_get_soft_state(statep, 0);
710 			if (!mod_ctxt) {
711 				return (DDI_FAILURE);
712 			}
713 			*resultp = (void *)mod_ctxt->dip;
714 			return (DDI_SUCCESS);
715 
716 		case DDI_INFO_DEVT2INSTANCE:
717 			*resultp = 0;
718 			return (DDI_SUCCESS);
719 
720 		default:
721 			return (DDI_FAILURE);
722 	}
723 }
724 
725 /*
726  * Function:
727  *	sol_uverbs_prop_op
728  * Input:
729  *	dev	- The device number associated with this device.
730  *	dip	- A pointer to the device information structure for this device.
731  *	prop_op - Property operator (PROP_LEN, PROP_LEN_AND_VAL_BUF, or
732  *	          PROP_LEN_AND_VAL_ALLOC).
733  *	flags	- Only possible flag value is DDI_PROP_DONTPASS.
734  *	name    - Pointer to the property to be interrogated.
735  *	valuep	- Address of pointer if ALLOC, otherwise a pointer to the
736  *	          users buffer.
737  *	lengthp	- Pointer to update with property length.
738  * Output:
739  *	valuep	- Updated with the property value.
740  *	lenghtp	- Updated with the property length.
741  * Returns:
742  *	DDI_SUCCESS on success, else error code.
743  * Description:
744  *	Driver entry point to report the values of certain properties of the
745  *	driver or  device.
746  */
747 static int
sol_uverbs_prop_op(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int flags,char * name,caddr_t valuep,int * lengthp)748 sol_uverbs_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int flags,
749     char *name, caddr_t valuep, int *lengthp)
750 {
751 	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
752 
753 }
754 
755 static uverbs_uctxt_uobj_t *sol_uverbs_alloc_uctxt(dev_t *,
756     uverbs_module_context_t *, minor_t);
757 
758 /*
759  * Function:
760  *	sol_uverbs_open
761  * Input:
762  *	devp	- A pointer to the device number.
763  *	flag	- Flags specified by caller (FEXCL, FNDELAY, FREAD, FWRITE).
764  *	otyp	- Open type (OTYP_BLK, OTYP_CHR, OTYP_LYR).
765  *	cred	- Pointer to the callers credentials.
766  * Output:
767  *	devp	- On success devp has been cloned to point to a unique minor
768  *		  device.
769  * Returns:
770  *	DDI_SUCCESS on success, else error code.
771  * Description:
772  * 	Handles a user process open of a specific user verbs minor device by
773  *	allocating a user context user object and creating a unique device
774  *	to identify the user.  Note: The first SOL_UVERBS_DRIVER_MAX_MINOR
775  *	minor numbers are reserved for :
776  *		0 to SOL_UVERBS_DRIVER_MAX_HCA_MINOR - 1 : actual HCA devices
777  *		SOL_UVERBS_DRIVER_MAX_HCA_MINOR		 : UCMA node
778  *		SOL_UVERBS_DRIVER_EVENT_MINOR		 :
779  *			Event file for opening an event file for completion
780  *			or async notifications.
781  */
782 /* ARGSUSED */
783 static int
sol_uverbs_open(dev_t * devp,int flag,int otyp,cred_t * cred)784 sol_uverbs_open(dev_t *devp, int flag, int otyp, cred_t *cred)
785 {
786 	uverbs_module_context_t	*mod_ctxt;
787 	uverbs_uctxt_uobj_t	*uctxt;
788 	int			minor;
789 
790 	/* Char only */
791 	if (otyp != OTYP_CHR) {
792 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
793 		    "open: not CHR");
794 		return (EINVAL);
795 	}
796 
797 	mod_ctxt = ddi_get_soft_state(statep, 0);
798 	if (mod_ctxt == NULL) {
799 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
800 		    "open: get soft state failed");
801 		return (ENXIO);
802 	}
803 
804 	minor = getminor(*devp);
805 
806 	/*
807 	 * Special case of ucma module.
808 	 */
809 	if (minor == SOL_UVERBS_DRIVER_MAX_HCA_MINOR) {
810 		extern cred_t	*kcred;
811 
812 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
813 		    "open: ucma_open");
814 		if (cred != kcred) {
815 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
816 			    "open: ucma_open non-kernel context");
817 			return (ENOTSUP);
818 		}
819 
820 		return (DDI_SUCCESS);
821 	}
822 
823 	/*
824 	 * If this is not an open for sol_uverbs event file,
825 	 * A device minor number must be less than the user verb max
826 	 * minor device number and the HCA count.
827 	 */
828 	if (minor != SOL_UVERBS_DRIVER_EVENT_MINOR &&
829 	    (minor >= SOL_UVERBS_DRIVER_MAX_HCA_MINOR ||
830 	    minor >= mod_ctxt->hca_count)) {
831 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
832 		    "open: bad minor %d", minor);
833 		return (ENODEV);
834 	}
835 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "open() - minor %d", minor);
836 
837 	/*
838 	 * Allocate a user context and return a unique ID that can be used
839 	 * in identify the new user context object.  Create a clone device
840 	 * that uses this unique ID as the minor number.  Allocation of the
841 	 * user context object places one reference against it; which will
842 	 * be held until the device is closed.
843 	 *
844 	 * sol_uverbs_alloc_uctxt() returns a sucessful allocation of uctx
845 	 * with the uobj uo_lock held for WRITTER.
846 	 */
847 	uctxt = sol_uverbs_alloc_uctxt(devp, mod_ctxt, minor);
848 	if (!uctxt)  {
849 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
850 		    "open: user context alloc failed");
851 		return (ENODEV);
852 	}
853 
854 	/*
855 	 * Indicate the object is alive and release the user object write lock
856 	 * which was placed on the user context at allocation.
857 	 */
858 	uctxt->uobj.uo_live = 1;
859 	rw_exit(&uctxt->uobj.uo_lock);
860 
861 	return (DDI_SUCCESS);
862 }
863 
864 /*
865  * Function:
866  *	sol_uverbs_close
867  * Input:
868  *	dev	- Device number.
869  *	flag	- File status flag.
870  *	otyp	- Open type.
871  *	cred	- A pointer to the callers credientials.
872  * Output:
873  *	None
874  * Returns:
875  *	DDI_SUCCESS on success, else error code.
876  * Description:
877  * 	Handles a user process close of a specific user verbs minor device by
878  *	freeing any user objects this process may still have allocated and
879  * 	deleting the associated user context object.
880  */
881 /* ARGSUSED */
882 static int
sol_uverbs_close(dev_t dev,int flag,int otyp,cred_t * cred)883 sol_uverbs_close(dev_t dev, int flag, int otyp, cred_t *cred)
884 {
885 	minor_t			id = getminor(dev);
886 	genlist_entry_t		*entry, *new_entry;
887 	uverbs_uctxt_uobj_t	*uctxt;
888 	int			rc;
889 	genlist_t		tmp_genlist;
890 
891 	/*
892 	 * HCA specific device nodes created during attach are been
893 	 * closed. Return SUCCESS.
894 	 */
895 	if (id < SOL_UVERBS_DRIVER_MAX_MINOR) {
896 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
897 		    "uverbs_close: dev_t %x, minor %x < %x",
898 		    dev, id, SOL_UVERBS_DRIVER_MAX_MINOR);
899 		return (0);
900 	}
901 
902 	/*
903 	 * Must be a user or kernel open, i.e. not a minor node that
904 	 * that represents a user verbs device.  If it is the UCMA
905 	 * nothing needs to be done.
906 	 */
907 	if (id == SOL_UVERBS_DRIVER_MAX_HCA_MINOR) {
908 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
909 		    "uverbs_close: ucma close");
910 		return (DDI_SUCCESS);
911 	}
912 
913 	uctxt = uverbs_uobj_get_uctxt_write(id - SOL_UVERBS_DRIVER_MAX_MINOR);
914 	if (uctxt == NULL) {
915 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
916 		    "uverbs_close: Unknown user context");
917 		return (ENXIO);
918 	}
919 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "uverbs_close- "
920 	    "uctxt %p", uctxt);
921 
922 	/*
923 	 * Remove from the user context resource table, cleanup all
924 	 * user resources that may still be hanging around.
925 	 */
926 	if (!sol_ofs_uobj_remove(&uverbs_uctxt_uo_tbl, &uctxt->uobj)) {
927 		/*
928 		 * It was already removed, drop the lock held from
929 		 * get above and exit.
930 		 */
931 		sol_ofs_uobj_put(&uctxt->uobj);
932 		return (ENXIO);
933 	}
934 
935 	if (uctxt->uctxt_type == SOL_UVERBS_UCTXT_ASYNC ||
936 	    uctxt->uctxt_type == SOL_UVERBS_UCTXT_COMPL) {
937 		uverbs_uctxt_uobj_t	*verbs_uctxt;
938 
939 		SOL_OFS_DPRINTF_L4(sol_uverbs_dbg_str,
940 		    "uverbs_close: Async or Compl user context");
941 
942 		/*
943 		 * Verbs uctxt has already been freed, just return.
944 		 */
945 		if (!uctxt->uctxt_verbs_id) {
946 			sol_ofs_uobj_put(&uctxt->uobj);
947 			sol_ofs_uobj_deref(&uctxt->uobj, sol_ofs_uobj_free);
948 			return (0);
949 		}
950 
951 		/*
952 		 * Verbs uctxt has not been freed. Close the ufile. This
953 		 * also frees the ufile if reference count is 0.
954 		 */
955 		verbs_uctxt = uverbs_uobj_get_uctxt_write(
956 		    uctxt->uctxt_verbs_id - SOL_UVERBS_DRIVER_MAX_MINOR);
957 
958 		if (verbs_uctxt &&
959 		    uctxt->uctxt_type == SOL_UVERBS_UCTXT_ASYNC) {
960 			sol_uverbs_event_file_close(verbs_uctxt->async_evfile);
961 			verbs_uctxt->async_evfile = NULL;
962 		} else if (uctxt->comp_evfile) {
963 			uctxt->comp_evfile = NULL;
964 		}
965 		if (verbs_uctxt)
966 			sol_ofs_uobj_put(&verbs_uctxt->uobj);
967 
968 		sol_ofs_uobj_put(&uctxt->uobj);
969 		sol_ofs_uobj_deref(&uctxt->uobj, sol_ofs_uobj_free);
970 		return (0);
971 	} else if (uctxt->uctxt_type == SOL_UVERBS_UCTXT_EVENT) {
972 		sol_ofs_uobj_put(&uctxt->uobj);
973 		sol_ofs_uobj_deref(&uctxt->uobj, sol_ofs_uobj_free);
974 		return (0);
975 	}
976 
977 	ASSERT(uctxt->hca != NULL);
978 
979 	/*
980 	 * Release resources that may still be held by this user context.
981 	 * Remove the resources from the associated resource managment
982 	 * table and free it.
983 	 */
984 	mutex_enter(&uctxt->lock);
985 
986 	entry = remove_genlist_head(&uctxt->ah_list);
987 	while (entry) {
988 		uverbs_uah_uobj_t *uah = (uverbs_uah_uobj_t *)entry->data;
989 
990 		rw_enter(&(uah->uobj.uo_lock), RW_WRITER);
991 		(void) sol_ofs_uobj_remove(&uverbs_uah_uo_tbl, &uah->uobj);
992 		rw_exit(&(uah->uobj.uo_lock));
993 		(void) ibt_free_ah(uctxt->hca->hdl, uah->ah);
994 		sol_ofs_uobj_free(&uah->uobj);
995 
996 		kmem_free((void *)entry, sizeof (genlist_entry_t));
997 		entry = remove_genlist_head(&uctxt->ah_list);
998 	}
999 
1000 	init_genlist(&tmp_genlist);
1001 	entry = remove_genlist_head(&uctxt->qp_list);
1002 	while (entry) {
1003 		uverbs_uqp_uobj_t *uqp = (uverbs_uqp_uobj_t *)entry->data;
1004 
1005 		/* Free unreaped asynchronous events.  */
1006 		uverbs_release_uqp_uevents(uctxt->async_evfile, uqp);
1007 
1008 		/*
1009 		 * If ucma has disabled QP free for this QP, set the
1010 		 * uqp_free_state to FREE_PENDING. Free QP if not.
1011 		 */
1012 		rw_enter(&(uqp->uobj.uo_lock), RW_WRITER);
1013 		if (uqp->uqp_free_state != SOL_UVERBS2UCMA_ENABLE_QP_FREE) {
1014 			new_entry = add_genlist(&tmp_genlist, entry->data,
1015 			    entry->data_context);
1016 			uqp->list_entry = new_entry;
1017 			uqp->uqp_free_state = SOL_UVERBS2UCMA_FREE_PENDING;
1018 			rw_exit(&(uqp->uobj.uo_lock));
1019 		} else {
1020 			uqp->list_entry = NULL;
1021 			mutex_exit(&uctxt->lock);
1022 			sol_ofs_uobj_ref(&uqp->uobj);
1023 			rc = uverbs_uqp_free(uqp, uctxt);
1024 			mutex_enter(&uctxt->lock);
1025 			if (rc)
1026 				SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1027 				    "uqp_free(%p) failed", uqp);
1028 		}
1029 		kmem_free(entry, sizeof (genlist_entry_t));
1030 		entry = remove_genlist_head(&uctxt->qp_list);
1031 	}
1032 	(uctxt->qp_list).count = tmp_genlist.count;
1033 	(uctxt->qp_list).head = tmp_genlist.head;
1034 	(uctxt->qp_list).tail = tmp_genlist.tail;
1035 
1036 	init_genlist(&tmp_genlist);
1037 	entry = remove_genlist_head(&uctxt->cq_list);
1038 	while (entry) {
1039 		uverbs_ucq_uobj_t *ucq = (uverbs_ucq_uobj_t *)entry->data;
1040 
1041 		rw_enter(&(ucq->uobj.uo_lock), RW_WRITER);
1042 
1043 		/* Free events associated with the CQ.  */
1044 		uverbs_release_ucq_channel(uctxt, ucq->comp_chan, ucq);
1045 
1046 		if (ucq->active_qp_cnt) {
1047 			new_entry = add_genlist(&tmp_genlist, entry->data,
1048 			    entry->data_context);
1049 			ucq->list_entry = new_entry;
1050 			ucq->free_pending = 1;
1051 			rw_exit(&(ucq->uobj.uo_lock));
1052 		} else {
1053 			ucq->list_entry = NULL;
1054 			sol_ofs_uobj_ref(&ucq->uobj);
1055 			mutex_exit(&uctxt->lock);
1056 			rc = uverbs_ucq_free(ucq, uctxt);
1057 			mutex_enter(&uctxt->lock);
1058 			if (rc)
1059 				SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1060 				    "ucq_free(%p) failed", ucq);
1061 		}
1062 
1063 		kmem_free((void *)entry, sizeof (genlist_entry_t));
1064 		entry = remove_genlist_head(&uctxt->cq_list);
1065 	}
1066 	(uctxt->cq_list).count = tmp_genlist.count;
1067 	(uctxt->cq_list).head = tmp_genlist.head;
1068 	(uctxt->cq_list).tail = tmp_genlist.tail;
1069 
1070 	init_genlist(&tmp_genlist);
1071 	entry = remove_genlist_head(&uctxt->srq_list);
1072 	while (entry) {
1073 		uverbs_usrq_uobj_t *usrq = (uverbs_usrq_uobj_t *)entry->data;
1074 
1075 		rw_enter(&(usrq->uobj.uo_lock), RW_WRITER);
1076 
1077 		/* Free unreaped asynchronous events.  */
1078 		uverbs_release_usrq_uevents(uctxt->async_evfile, usrq);
1079 
1080 		if (usrq->active_qp_cnt) {
1081 			new_entry = add_genlist(&tmp_genlist, entry->data,
1082 			    entry->data_context);
1083 			usrq->list_entry = new_entry;
1084 			usrq->free_pending = 1;
1085 			rw_exit(&(usrq->uobj.uo_lock));
1086 		} else {
1087 			usrq->list_entry = NULL;
1088 			sol_ofs_uobj_ref(&usrq->uobj);
1089 			mutex_exit(&uctxt->lock);
1090 			rc = uverbs_usrq_free(usrq, uctxt);
1091 			mutex_enter(&uctxt->lock);
1092 			if (rc)
1093 				SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1094 				    "usrq_free(%p) failed", usrq);
1095 		}
1096 
1097 		kmem_free((void *)entry, sizeof (genlist_entry_t));
1098 		entry = remove_genlist_head(&uctxt->srq_list);
1099 	}
1100 	(uctxt->srq_list).count = tmp_genlist.count;
1101 	(uctxt->srq_list).head = tmp_genlist.head;
1102 	(uctxt->srq_list).tail = tmp_genlist.tail;
1103 
1104 	entry = remove_genlist_head(&uctxt->mr_list);
1105 	while (entry) {
1106 		uverbs_umr_uobj_t *umr = (uverbs_umr_uobj_t *)entry->data;
1107 
1108 		rw_enter(&(umr->uobj.uo_lock), RW_WRITER);
1109 		(void) sol_ofs_uobj_remove(&uverbs_umr_uo_tbl, &umr->uobj);
1110 		rw_exit(&(umr->uobj.uo_lock));
1111 
1112 		(void) ibt_deregister_mr(uctxt->hca->hdl, umr->mr);
1113 		sol_ofs_uobj_free(&umr->uobj);
1114 
1115 		kmem_free((void *)entry, sizeof (genlist_entry_t));
1116 		entry = remove_genlist_head(&uctxt->mr_list);
1117 	}
1118 
1119 	entry = remove_genlist_head(&uctxt->pd_list);
1120 	while (entry) {
1121 		uverbs_upd_uobj_t *upd = (uverbs_upd_uobj_t *)entry->data;
1122 
1123 		rw_enter(&(upd->uobj.uo_lock), RW_WRITER);
1124 		if (upd->active_qp_cnt) {
1125 			new_entry = add_genlist(&tmp_genlist, entry->data,
1126 			    entry->data_context);
1127 			upd->list_entry = new_entry;
1128 			upd->free_pending = 1;
1129 			rw_exit(&(upd->uobj.uo_lock));
1130 		} else {
1131 			upd->list_entry = NULL;
1132 			sol_ofs_uobj_ref(&upd->uobj);
1133 			mutex_exit(&uctxt->lock);
1134 			rc = uverbs_upd_free(upd, uctxt);
1135 			mutex_enter(&uctxt->lock);
1136 			if (rc)
1137 				SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1138 				    "upd_free(%p) failed", upd);
1139 		}
1140 
1141 		kmem_free((void *)entry, sizeof (genlist_entry_t));
1142 		entry = remove_genlist_head(&uctxt->pd_list);
1143 	}
1144 	(uctxt->pd_list).count = tmp_genlist.count;
1145 	(uctxt->pd_list).head = tmp_genlist.head;
1146 	(uctxt->pd_list).tail = tmp_genlist.tail;
1147 
1148 	mutex_exit(&uctxt->lock);
1149 
1150 	/*
1151 	 * Release the user file structure to the async file if it
1152 	 * has not be released yet. The uctxt for async file will
1153 	 * be closed when the async file is closed.
1154 	 */
1155 	if (uctxt->async_evfile) {
1156 		uverbs_uctxt_uobj_t	*async_uctxt;
1157 
1158 		async_uctxt = uverbs_uobj_get_uctxt_write(
1159 		    uctxt->uctxt_async_id -
1160 		    SOL_UVERBS_DRIVER_MAX_MINOR);
1161 		if (!async_uctxt) {
1162 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1163 			    "uverbs_close: Invalid async_id %x",
1164 			    uctxt->uctxt_async_id);
1165 			sol_ofs_uobj_put(&uctxt->uobj);
1166 			return (ENXIO);
1167 		}
1168 
1169 		async_uctxt->uctxt_verbs_id = 0;
1170 		sol_uverbs_event_file_close(uctxt->async_evfile);
1171 		uctxt->async_evfile = NULL;
1172 		sol_ofs_uobj_put(&async_uctxt->uobj);
1173 	}
1174 
1175 	/*
1176 	 * Release the write lock and the reference from the get above, and
1177 	 * release the reference placed on the user context as process open
1178 	 * to release context.
1179 	 */
1180 	sol_ofs_uobj_put(&uctxt->uobj);
1181 
1182 	/*
1183 	 * If some QPs have not been freed, donot free the uctxt.
1184 	 * Set uctxt_free_pending flag. This will be freed when
1185 	 * the QP will be freed.
1186 	 */
1187 	if ((uctxt->qp_list).count) {
1188 		SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str,
1189 		    "close: uctxt %p, has pending uqp", uctxt);
1190 		uctxt->uctxt_free_pending = 1;
1191 		return (0);
1192 	}
1193 
1194 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1195 	    "close: deallocated user context: %p, ref = %d",
1196 	    (void *)uctxt, uctxt->uobj.uo_refcnt);
1197 
1198 	sol_ofs_uobj_deref(&uctxt->uobj, sol_ofs_uobj_free);
1199 
1200 	return (0);
1201 }
1202 
1203 /*
1204  * Function:
1205  *	sol_uverbs_read
1206  * Input:
1207  *	dev	- Device number.
1208  *	uiop	- Pointer to the uio structgure where data is to be stored.
1209  *	credp	- A pointer to the credentials for the I/O transaction.
1210  * Output:
1211  *	None
1212  * Returns:
1213  *	DDI_SUCCESS on success, else error code.
1214  * Description:
1215  * 	User process read stub.
1216  */
1217 static int
sol_uverbs_read(dev_t dev,struct uio * uiop,cred_t * credp)1218 sol_uverbs_read(dev_t dev, struct uio *uiop, cred_t *credp)
1219 {
1220 	minor_t			id = getminor(dev);
1221 	uverbs_uctxt_uobj_t	*uctxt, *verbs_uctxt;
1222 	int			rc;
1223 
1224 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "uverbs_read(%x, %p, %p)",
1225 	    dev, uiop, credp);
1226 
1227 	ASSERT(id >= SOL_UVERBS_DRIVER_MAX_MINOR);
1228 	uctxt = uverbs_uobj_get_uctxt_read(id - SOL_UVERBS_DRIVER_MAX_MINOR);
1229 	if (uctxt == NULL) {
1230 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1231 		    "uverbs_read: Failed get user context");
1232 		return (ENXIO);
1233 	}
1234 
1235 	if (uctxt->uctxt_verbs_id < SOL_UVERBS_DRIVER_MAX_MINOR) {
1236 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1237 		    "uverbs_read: Invalid Verbs user context id, %x",
1238 		    uctxt->uctxt_verbs_id);
1239 		sol_ofs_uobj_put(&uctxt->uobj);
1240 		return (ENXIO);
1241 	}
1242 	verbs_uctxt = uverbs_uobj_get_uctxt_read(uctxt->uctxt_verbs_id
1243 	    - SOL_UVERBS_DRIVER_MAX_MINOR);
1244 	if (verbs_uctxt == NULL) {
1245 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1246 		    "uverbs_read: Failed get verbs user context");
1247 		sol_ofs_uobj_put(&uctxt->uobj);
1248 		return (ENXIO);
1249 	}
1250 	if (uctxt->uctxt_type == SOL_UVERBS_UCTXT_ASYNC) {
1251 		ASSERT(verbs_uctxt->async_evfile);
1252 		rc = sol_uverbs_event_file_read(verbs_uctxt->async_evfile,
1253 		    uiop, credp);
1254 	} else if (uctxt->uctxt_type == SOL_UVERBS_UCTXT_COMPL) {
1255 		rc = sol_uverbs_event_file_read(uctxt->comp_evfile,
1256 		    uiop, credp);
1257 	} else {
1258 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1259 		    "uverbs_read: invalid user context type %x",
1260 		    uctxt->uctxt_type);
1261 		rc = ENXIO;
1262 	}
1263 
1264 	sol_ofs_uobj_put(&verbs_uctxt->uobj);
1265 	sol_ofs_uobj_put(&uctxt->uobj);
1266 	return (rc);
1267 }
1268 
1269 /*
1270  * Function:
1271  *	sol_uverbs_mmap
1272  * Input:
1273  *	dev		- Device whose memory is to be mapped.
1274  *	sol_uverbs_mmap	- Offset within the device memory at which mapping
1275  *			  begins.
1276  *	prot		- Bitmask specifying protection.
1277  * Output:
1278  *	None
1279  * Returns:
1280  *	DDI_SUCCESS on success, else error code.
1281  * Description:
1282  * 	User process mmap stub.  Mmap operations are performed directly
1283  *	by the underlying IB HCA driver, bypassing the user verbs.
1284  */
1285 /* ARGSUSED */
1286 static int
sol_uverbs_mmap(dev_t dev,off_t mmap_offset,int prot)1287 sol_uverbs_mmap(dev_t dev, off_t mmap_offset, int prot)
1288 {
1289 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1290 	    "sol_uverbs_mmap(%d)-  not yet used", mmap_offset);
1291 	return (DDI_SUCCESS);
1292 }
1293 
1294 /*
1295  * Function:
1296  *	sol_uverbs_get_context
1297  * Input:
1298  *	uctxt   - Pointer to the callers user context.
1299  *	buf     - Pointer to kernel buffer containing command.
1300  *	in_len  - Length in bytes of input command buffer.
1301  *	out_len - Length in bytes of output response buffer.
1302  * Output:
1303  *	The command output buffer is updated with command results.
1304  * Returns:
1305  *	DDI_SUCCESS on success, else error code.
1306  * Description:
1307  * 	User verb entry point to return the unique user context to the process
1308  *	that opened the associated user verb driver instance.  Note that upon
1309  *	entry a reference will have already been placed on the user
1310  *	context user space object, so an additional reference is not
1311  *	required here.
1312  */
1313 int
sol_uverbs_get_context(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)1314 sol_uverbs_get_context(uverbs_uctxt_uobj_t *uctxt, char *buf, int in_len,
1315     int out_len)
1316 {
1317 	struct mthca_alloc_ucontext_resp	uresp;
1318 	struct ib_uverbs_get_context		cmd;
1319 	struct ib_uverbs_get_context_resp	resp;
1320 	struct ib_udata				udata;
1321 	int					rc;
1322 	minor_t					async_id;
1323 	uverbs_uctxt_uobj_t			*async_uctxt;
1324 
1325 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1326 	    "uverbs_get_context() - buf %p, sizeof (cmd) %d",
1327 	    buf, sizeof (cmd));
1328 
1329 	ASSERT(uctxt->hca);
1330 
1331 	(void) memcpy(&cmd, buf, sizeof (cmd));
1332 
1333 	udata.inbuf  = (void *)(buf + sizeof (cmd));
1334 #ifdef	_LP64
1335 	udata.outbuf = (void *)(cmd.response.r_laddr + sizeof (resp));
1336 #else
1337 	udata.outbuf = (void *)(cmd.response.r_addr + sizeof (resp));
1338 #endif
1339 	udata.inlen  = in_len - sizeof (cmd);
1340 	udata.outlen = out_len - sizeof (resp);
1341 
1342 	/*
1343 	 * libibverbs will have passed minor of the async file in
1344 	 * resp.fd. Use this to determine the uctxt created for
1345 	 * asyncs.
1346 	 */
1347 #ifdef	_LP64
1348 	rc = copyin((void*)cmd.response.r_laddr, (void*)&resp, sizeof (resp));
1349 #else
1350 	rc = copyin((void*)cmd.response.r_addr, (void*)&resp, sizeof (resp));
1351 #endif
1352 	if (rc != 0) {
1353 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1354 		    "get_context: copyin (rc=%d)", rc);
1355 		rc = EFAULT;
1356 		goto out;
1357 	}
1358 	async_id = resp.async_fd;
1359 	if (async_id < SOL_UVERBS_DRIVER_MAX_MINOR) {
1360 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1361 		    "get_context: Invalid async user context "
1362 		    "id %x", async_id);
1363 		return (ENXIO);
1364 	}
1365 
1366 	async_uctxt = uverbs_uobj_get_uctxt_read(async_id -
1367 	    SOL_UVERBS_DRIVER_MAX_MINOR);
1368 	if (async_uctxt == NULL) {
1369 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1370 		    "get_context: Failed get async user context");
1371 		return (ENXIO);
1372 	}
1373 	if (async_uctxt->uctxt_type != SOL_UVERBS_UCTXT_EVENT ||
1374 	    async_uctxt->uctxt_verbs_id != 0) {
1375 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1376 		    "get_context: Invalid user context - "
1377 		    "possibly reused");
1378 		return (ENXIO);
1379 	}
1380 	async_uctxt->uctxt_type = SOL_UVERBS_UCTXT_ASYNC;
1381 	async_uctxt->uctxt_verbs_id = uctxt->uobj.uo_id +
1382 	    SOL_UVERBS_DRIVER_MAX_MINOR;
1383 	uctxt->uctxt_async_id = async_id;
1384 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1385 	    "get_context: uctxt %p, async_uctxt %p, async_id %x",
1386 	    uctxt, async_uctxt, async_id);
1387 	sol_ofs_uobj_put(&async_uctxt->uobj);
1388 
1389 	uctxt->async_evfile = uverbs_alloc_event_file(uctxt, 1);
1390 	if (!uctxt->async_evfile) {
1391 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1392 		    "get_context: async event file allocation failed");
1393 		goto out;
1394 	}
1395 
1396 	(void) memset(&resp, 0, sizeof (resp));
1397 	resp.num_comp_vectors 	= 1;
1398 
1399 #ifdef	_LP64
1400 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
1401 #else
1402 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
1403 #endif
1404 	if (rc != 0) {
1405 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1406 		    "get_context: copyout (rc=%d)", rc);
1407 		rc = EFAULT;
1408 		goto out;
1409 	}
1410 
1411 	/*
1412 	 * This unfortunately is Mellanox specific, we need to consider moving
1413 	 * this directly into the command response as opaque data, instead of
1414 	 * using this method.
1415 	 */
1416 	(void) memset(&uresp, 0, sizeof (uresp));
1417 	uresp.uarc_size   = 0;
1418 	uresp.qp_tab_size = uctxt->hca->attr.hca_max_chans;
1419 
1420 	rc = copyout((void*)&uresp, (void*)udata.outbuf, sizeof (uresp));
1421 	if (rc != 0) {
1422 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1423 		    "get_context: copyout outbuf (rc=%d)", rc);
1424 		rc = EFAULT;
1425 		goto out;
1426 	}
1427 	rc = DDI_SUCCESS;
1428 
1429 out:
1430 	return (rc);
1431 }
1432 
1433 /*
1434  * Function:
1435  *	sol_uverbs_alloc_pd
1436  * Input:
1437  *	uctxt   - Pointer to the callers user context.
1438  *	buf     - Pointer to kernel buffer containing a alloc PD command.
1439  *	in_len  - Length in bytes of input command buffer.
1440  *	out_len - Length in bytes of output response buffer.
1441  * Output:
1442  *	The command output buffer is updated with command results.
1443  * Returns:
1444  *	DDI_SUCCESS on success, else error code.
1445  * Description:
1446  * 	User verb entry point to allocate a device protection domain.
1447  */
1448 /* ARGSUSED */
1449 int
sol_uverbs_alloc_pd(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)1450 sol_uverbs_alloc_pd(uverbs_uctxt_uobj_t *uctxt, char *buf, int in_len,
1451     int out_len)
1452 {
1453 	struct ib_uverbs_alloc_pd	cmd;
1454 	struct ib_uverbs_alloc_pd_resp	resp;
1455 	uverbs_upd_uobj_t		*upd;
1456 	int				rc;
1457 
1458 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "alloc_pd()");
1459 
1460 	(void) memcpy(&cmd, buf, sizeof (cmd));
1461 	(void) memset(&resp, 0, sizeof (resp));
1462 
1463 	upd = kmem_zalloc(sizeof (*upd), KM_NOSLEEP);
1464 	if (upd == NULL) {
1465 		rc = ENOMEM;
1466 		goto out;
1467 	}
1468 	sol_ofs_uobj_init(&upd->uobj, 0, SOL_UVERBS_UPD_UOBJ_TYPE);
1469 	rw_enter(&upd->uobj.uo_lock, RW_WRITER);
1470 
1471 	rc = ibt_alloc_pd(uctxt->hca->hdl, IBT_PD_NO_FLAGS, &upd->pd);
1472 	if (rc != IBT_SUCCESS) {
1473 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1474 		    "alloc_pd: ibt_alloc_pd() (rc=%d)", rc);
1475 		rc = sol_uverbs_ibt_to_kernel_status(rc);
1476 		upd->uobj.uo_uobj_sz = sizeof (uverbs_upd_uobj_t);
1477 		goto alloc_err;
1478 	}
1479 
1480 	if (sol_ofs_uobj_add(&uverbs_upd_uo_tbl, &upd->uobj) != 0) {
1481 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1482 		    "alloc_pd: User object add failed");
1483 		rc = ENOMEM;
1484 		goto err_add_uobj;
1485 	}
1486 	resp.pd_handle = upd->uobj.uo_id;
1487 
1488 	/*
1489 	 * Query underlying hardware driver for data that may be required
1490 	 * when using the PD in an OS Bypass creation of UD address vectors.
1491 	 */
1492 	rc = ibt_ci_data_out(uctxt->hca->hdl, IBT_CI_NO_FLAGS, IBT_HDL_PD,
1493 	    (void *)upd->pd, &resp.drv_out, sizeof (resp.drv_out));
1494 	if (rc != IBT_SUCCESS) {
1495 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1496 		    "alloc_pd: ibt_ci_data_out() (rc=%d)", rc);
1497 		rc = EFAULT;
1498 		goto err_response;
1499 	}
1500 
1501 #ifdef	_LP64
1502 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
1503 #else
1504 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
1505 #endif
1506 	if (rc != 0) {
1507 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1508 		    "alloc_pd: copyout fail (rc=%d)", rc);
1509 		rc = EFAULT;
1510 		goto err_response;
1511 	}
1512 
1513 	mutex_enter(&uctxt->lock);
1514 	upd->list_entry = add_genlist(&uctxt->pd_list, (uintptr_t)upd, uctxt);
1515 	mutex_exit(&uctxt->lock);
1516 
1517 	if (!upd->list_entry) {
1518 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1519 		    "alloc_pd: Error adding upd to pd_list\n");
1520 		rc = ENOMEM;
1521 		goto err_response;
1522 	}
1523 
1524 	upd->uobj.uo_live = 1;
1525 	rw_exit(&upd->uobj.uo_lock);
1526 	return (DDI_SUCCESS);
1527 
1528 err_response:
1529 	/*
1530 	 * Need to set uo_live, so sol_ofs_uobj_remove() will
1531 	 * remove the object from the object table.
1532 	 */
1533 	upd->uobj.uo_live = 1;
1534 	(void) sol_ofs_uobj_remove(&uverbs_upd_uo_tbl, &upd->uobj);
1535 
1536 err_add_uobj:
1537 	(void) ibt_free_pd(uctxt->hca->hdl, upd->pd);
1538 
1539 alloc_err:
1540 	rw_exit(&upd->uobj.uo_lock);
1541 	sol_ofs_uobj_deref(&upd->uobj, sol_ofs_uobj_free);
1542 out:
1543 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1544 	    "alloc_pd:error (rc=%d)", rc);
1545 	return (rc);
1546 }
1547 
1548 int
uverbs_upd_free(uverbs_upd_uobj_t * upd,uverbs_uctxt_uobj_t * uctxt)1549 uverbs_upd_free(uverbs_upd_uobj_t *upd, uverbs_uctxt_uobj_t *uctxt)
1550 {
1551 	int	rc;
1552 
1553 	rc = ibt_free_pd(uctxt->hca->hdl, upd->pd);
1554 	if (rc != IBT_SUCCESS) {
1555 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1556 		    "uverbs_upd_free: ibt_free_pd() failed %d", rc);
1557 		rc = sol_uverbs_ibt_to_kernel_status(rc);
1558 		sol_ofs_uobj_put(&upd->uobj);
1559 		return (rc);
1560 	}
1561 
1562 	/*
1563 	 * Remove from the list of this contexts PD resources, then remove from
1564 	 * the resource managment table and the reference placed on the user
1565 	 * object at PD allocation.
1566 	 */
1567 	upd->pd = NULL;
1568 	if (upd->list_entry) {
1569 		mutex_enter(&uctxt->lock);
1570 		delete_genlist(&uctxt->pd_list, upd->list_entry);
1571 		mutex_exit(&uctxt->lock);
1572 	}
1573 
1574 	/*
1575 	 * list_entry is NULL when called from sol_uverbs_close. Remove
1576 	 * from upd_uo_tbl and free upd, when called from close also.
1577 	 */
1578 	sol_ofs_uobj_put(&upd->uobj);
1579 	(void) sol_ofs_uobj_remove(&uverbs_upd_uo_tbl, &upd->uobj);
1580 	sol_ofs_uobj_deref(&upd->uobj, sol_ofs_uobj_free);
1581 	return (0);
1582 }
1583 
1584 /*
1585  * Function:
1586  *	sol_uverbs_dealloc_pd
1587  * Input:
1588  *	uctxt   - Pointer to the callers user context.
1589  *	buf     - Pointer to kernel buffer containing dealloc PD command.
1590  *	in_len  - Length in bytes of input command buffer.
1591  *	out_len - Length in bytes of output response buffer.
1592  * Output:
1593  *	The command output buffer is updated with command results.
1594  * Returns:
1595  *	DDI_SUCCESS on success, else error code.
1596  * Description:
1597  * 	User verb entry point to de-allocate a device protection domain.
1598  */
1599 /* ARGSUSED */
1600 int
sol_uverbs_dealloc_pd(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)1601 sol_uverbs_dealloc_pd(uverbs_uctxt_uobj_t *uctxt, char *buf, int in_len,
1602     int out_len)
1603 {
1604 	struct ib_uverbs_dealloc_pd	cmd;
1605 	uverbs_upd_uobj_t		*upd;
1606 	int				rc = 0;
1607 
1608 	(void) memcpy(&cmd, buf, sizeof (cmd));
1609 
1610 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1611 	    "dealloc_pd(%d)", cmd.pd_handle);
1612 
1613 	upd = uverbs_uobj_get_upd_write(cmd.pd_handle);
1614 	if (upd == NULL) {
1615 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1616 		    "dealloc_pd(%d) : invalid hdl", cmd.pd_handle);
1617 		rc = EINVAL;
1618 		goto err_out1;
1619 	}
1620 
1621 	if (upd->active_qp_cnt) {
1622 		sol_ofs_uobj_put(&upd->uobj);
1623 		rc = EBUSY;
1624 	} else {
1625 		rc = uverbs_upd_free(upd, uctxt);
1626 	}
1627 	cmd.pd_handle = 0;
1628 	return (rc);
1629 
1630 err_out1:
1631 	return (rc);
1632 }
1633 
1634 /*
1635  * Function:
1636  *	sol_uverbs_query_device
1637  * Input:
1638  *	uctxt   - Pointer to the callers user context.
1639  *	buf     - Pointer to kernel buffer containing query device command.
1640  *	in_len  - Length in bytes of input command buffer.
1641  *	out_len - Length in bytes of output response buffer.
1642  * Output:
1643  *	The command output buffer is updated with command results.
1644  * Returns:
1645  *	DDI_SUCCESS on success, else error code.
1646  * Description:
1647  * 	User verb entry point to query device attributes.
1648  */
1649 /* ARGSUSED */
1650 int
sol_uverbs_query_device(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)1651 sol_uverbs_query_device(uverbs_uctxt_uobj_t *uctxt, char *buf, int in_len,
1652 	int out_len)
1653 {
1654 	struct ib_uverbs_query_device		cmd;
1655 	struct ib_uverbs_query_device_resp	resp;
1656 	ibt_hca_attr_t				hca_attr;
1657 	int					rc;
1658 
1659 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "query_device()");
1660 
1661 	(void) memcpy(&cmd, buf, sizeof (cmd));
1662 	rc = ibt_query_hca(uctxt->hca->hdl, &hca_attr);
1663 	if (rc != IBT_SUCCESS) {
1664 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1665 		    "query_device: ibt_query_hca() (rc=%d)", rc);
1666 		rc = sol_uverbs_ibt_to_kernel_status(rc);
1667 		goto out;
1668 	}
1669 
1670 	(void) memset(&resp, 0, sizeof (resp));
1671 
1672 	resp.fw_ver = ((uint64_t)hca_attr.hca_fw_major_version << 32) |
1673 	    ((uint64_t)hca_attr.hca_fw_minor_version << 16) |
1674 	    ((uint64_t)hca_attr.hca_fw_micro_version);
1675 
1676 	/*
1677 	 * NOTE: node guid and system image guid must be returned in big
1678 	 * endian (network order).  On solaris these are in host
1679 	 * order, so we swap it back here.
1680 	 */
1681 	resp.node_guid			= htonll(hca_attr.hca_node_guid);
1682 	resp.sys_image_guid		= htonll(hca_attr.hca_si_guid);
1683 
1684 	resp.max_mr_size		= hca_attr.hca_max_memr_len;
1685 
1686 	resp.page_size_cap =
1687 	    sol_uverbs_ibt_to_of_page_sz(hca_attr.hca_page_sz);
1688 
1689 	resp.vendor_id			= hca_attr.hca_vendor_id;
1690 	resp.vendor_part_id		= hca_attr.hca_device_id;
1691 	resp.hw_ver			= hca_attr.hca_version_id;
1692 	resp.max_qp			= hca_attr.hca_max_chans;
1693 	resp.max_qp_wr			= hca_attr.hca_max_chan_sz;
1694 
1695 	resp.device_cap_flags		=
1696 	    sol_uverbs_ibt_to_of_device_cap_flags(hca_attr.hca_flags,
1697 	    hca_attr.hca_flags2);
1698 
1699 	resp.max_sge			= hca_attr.hca_max_sgl;
1700 	resp.max_sge_rd			= hca_attr.hca_max_sgl;
1701 	resp.max_cq			= hca_attr.hca_max_cq;
1702 	resp.max_cqe			= hca_attr.hca_max_cq_sz;
1703 	resp.max_mr			= hca_attr.hca_max_memr;
1704 	resp.max_pd			= hca_attr.hca_max_pd;
1705 	resp.max_qp_rd_atom		= hca_attr.hca_max_rdma_in_chan;
1706 	resp.max_ee_rd_atom		= 0;
1707 	resp.max_res_rd_atom		= hca_attr.hca_max_rsc;
1708 	resp.max_qp_init_rd_atom	= hca_attr.hca_max_rdma_out_chan;
1709 	resp.max_ee_init_rd_atom	= 0;
1710 	if (hca_attr.hca_flags & IBT_HCA_ATOMICS_GLOBAL) {
1711 		resp.atomic_cap = IB_ATOMIC_GLOB;
1712 	} else if (hca_attr.hca_flags & IBT_HCA_ATOMICS_HCA) {
1713 		resp.atomic_cap = IB_ATOMIC_HCA;
1714 	} else {
1715 		resp.atomic_cap = IB_ATOMIC_NONE;
1716 	}
1717 	resp.max_ee			= 0;
1718 	resp.max_rdd			= 0;
1719 	resp.max_mw			= hca_attr.hca_max_mem_win;
1720 	resp.max_raw_ipv6_qp		= hca_attr.hca_max_ipv6_chan;
1721 	resp.max_raw_ethy_qp		= hca_attr.hca_max_ether_chan;
1722 	resp.max_mcast_grp		= hca_attr.hca_max_mcg;
1723 	resp.max_mcast_qp_attach	= hca_attr.hca_max_chan_per_mcg;
1724 	resp.max_total_mcast_qp_attach	= hca_attr.hca_max_mcg_chans;
1725 	resp.max_ah			= hca_attr.hca_max_ud_dest;
1726 	resp.max_fmr			= hca_attr.hca_max_fmrs;
1727 	resp.max_map_per_fmr		= 0;
1728 	resp.max_srq			= hca_attr.hca_max_srqs;
1729 	resp.max_srq_wr			= hca_attr.hca_max_srqs_sz;
1730 	resp.max_srq_sge		= hca_attr.hca_max_srq_sgl;
1731 	resp.max_pkeys			= hca_attr.hca_max_port_pkey_tbl_sz;
1732 	resp.local_ca_ack_delay		= hca_attr.hca_local_ack_delay;
1733 	resp.phys_port_cnt		= hca_attr.hca_nports;
1734 
1735 #ifdef	_LP64
1736 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
1737 #else
1738 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
1739 #endif
1740 	if (rc != 0) {
1741 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1742 		    "query_device: Error writing resp data (rc=%d)", rc);
1743 		rc = EFAULT;
1744 		goto out;
1745 	}
1746 
1747 	rc = DDI_SUCCESS;
1748 
1749 out:
1750 	return (rc);
1751 }
1752 
1753 /*
1754  * Function:
1755  *	sol_uverbs_query_port
1756  * Input:
1757  *	uctxt   - Pointer to the callers user context.
1758  *	buf     - Pointer to kernel buffer containing query port command.
1759  *	in_len  - Length in bytes of input command buffer.
1760  *	out_len - Length in bytes of output response buffer.
1761  * Output:
1762  *	The command output buffer is updated with command results.
1763  * Returns:
1764  *	DDI_SUCCESS on success, else error code.
1765  * Description:
1766  * 	User verb entry point to query a device port attributes.
1767  */
1768 /* ARGSUSED */
1769 int
sol_uverbs_query_port(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)1770 sol_uverbs_query_port(uverbs_uctxt_uobj_t *uctxt, char *buf, int in_len,
1771     int out_len)
1772 {
1773 	struct ib_uverbs_query_port		cmd;
1774 	struct ib_uverbs_query_port_resp	resp;
1775 	ibt_hca_portinfo_t			*port_info;
1776 	uint_t					port_info_n;
1777 	uint_t					port_info_size;
1778 	int					rc;
1779 
1780 	(void) memcpy(&cmd, buf, sizeof (cmd));
1781 
1782 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "sol_uverbs_query_port: %d",
1783 	    cmd.port_num);
1784 
1785 	if (!cmd.port_num || cmd.port_num > uctxt->hca->attr.hca_nports) {
1786 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1787 		    "query_port: Invalid port specified");
1788 
1789 		rc = EINVAL;
1790 		goto out;
1791 	}
1792 
1793 	rc = ibt_query_hca_ports(uctxt->hca->hdl, cmd.port_num, &port_info,
1794 	    &port_info_n, &port_info_size);
1795 
1796 	if (rc != IBT_SUCCESS) {
1797 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1798 		    "query_port: ibt_query_hca_ports() (rc=%d)", rc);
1799 		rc = sol_uverbs_ibt_to_kernel_status(rc);
1800 		goto out;
1801 	}
1802 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "query_port: "
1803 	    "port_num %d, port_info %x, lid %x, sm_lid %x",
1804 	    cmd.port_num, port_info, port_info->p_opaque1,
1805 	    port_info->p_sm_lid);
1806 
1807 	(void) memset(&resp, 0, sizeof (resp));
1808 
1809 	resp.state			= port_info->p_linkstate;
1810 	resp.max_mtu			= port_info->p_mtu;
1811 	resp.active_mtu			= port_info->p_mtu;
1812 	resp.gid_tbl_len		= port_info->p_sgid_tbl_sz;
1813 	resp.port_cap_flags  		= port_info->p_capabilities;
1814 	resp.max_msg_sz			= port_info->p_msg_sz;
1815 	resp.bad_pkey_cntr   		= port_info->p_pkey_violations;
1816 	resp.qkey_viol_cntr  		= port_info->p_qkey_violations;
1817 	resp.pkey_tbl_len    		= port_info->p_pkey_tbl_sz;
1818 	resp.lid			= port_info->p_opaque1;
1819 	resp.sm_lid			= port_info->p_sm_lid;
1820 	resp.lmc			= port_info->p_lmc;
1821 	resp.max_vl_num			= port_info->p_max_vl;
1822 	resp.sm_sl			= port_info->p_sm_sl;
1823 	resp.subnet_timeout  		= port_info->p_subnet_timeout;
1824 	resp.init_type_reply 		= port_info->p_init_type_reply;
1825 	resp.active_width    		= port_info->p_width_active;
1826 	resp.active_speed    		= port_info->p_speed_active;
1827 	resp.phys_state			= port_info->p_phys_state;
1828 
1829 	ibt_free_portinfo(port_info, port_info_size);
1830 
1831 #ifdef	_LP64
1832 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
1833 #else
1834 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
1835 #endif
1836 	if (rc != 0) {
1837 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1838 		    "query_port : copyout fail %x", rc);
1839 		rc = EFAULT;
1840 		goto out;
1841 	}
1842 
1843 	rc = DDI_SUCCESS;
1844 
1845 out:
1846 	return (rc);
1847 }
1848 
1849 /*
1850  * Function:
1851  *	sol_uverbs_query_gid
1852  * Input:
1853  *	uctxt   - Pointer to the callers user context.
1854  *	buf     - Pointer to kernel buffer containing query gid command.
1855  *	in_len  - Length in bytes of input command buffer.
1856  *	out_len - Length in bytes of output response buffer.
1857  * Output:
1858  *	The command output buffer is updated with command results.
1859  * Returns:
1860  *	DDI_SUCCESS on success, else error code.
1861  * Description:
1862  * 	User verb entry point to query the device gid for the specified
1863  *	port and gid index.
1864  */
1865 /* ARGSUSED */
1866 int
sol_uverbs_query_gid(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)1867 sol_uverbs_query_gid(uverbs_uctxt_uobj_t *uctxt, char *buf, int in_len,
1868     int out_len)
1869 {
1870 	struct ib_uverbs_query_gid	cmd;
1871 	struct ib_uverbs_query_gid_resp	resp;
1872 	ibt_hca_portinfo_t		*port_info;
1873 	uint_t				port_info_n;
1874 	uint_t				port_info_size;
1875 	int				rc;
1876 	uint64_t			temp;
1877 
1878 	(void) memcpy(&cmd, buf, sizeof (cmd));
1879 
1880 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1881 	    "query_gid() : port_num %x, gid_index %x",
1882 	    cmd.port_num, cmd.gid_index);
1883 
1884 	if (!cmd.port_num || cmd.port_num > uctxt->hca->attr.hca_nports) {
1885 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1886 		    "query_gid: Invalid port specified");
1887 
1888 		rc = EINVAL;
1889 		goto out;
1890 	}
1891 
1892 	rc = ibt_query_hca_ports(uctxt->hca->hdl, cmd.port_num, &port_info,
1893 	    &port_info_n, &port_info_size);
1894 	if (rc != IBT_SUCCESS) {
1895 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1896 		    "query_gid: ibt_query_hca_ports() (rc=%d)", rc);
1897 		rc = sol_uverbs_ibt_to_kernel_status(rc);
1898 		goto out;
1899 	}
1900 
1901 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "number of "
1902 	    "gid entries %d", cmd.port_num, cmd.gid_index,
1903 	    port_info->p_sgid_tbl_sz);
1904 
1905 
1906 	if (cmd.gid_index >= port_info->p_sgid_tbl_sz) {
1907 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1908 		    "query_gid: cmd gid_index %x > port_info sz %x",
1909 		    cmd.gid_index, port_info->p_sgid_tbl_sz);
1910 		rc = EINVAL;
1911 		ibt_free_portinfo(port_info, port_info_size);
1912 		goto out;
1913 	}
1914 
1915 	/*
1916 	 * The gid must be returned as a network ordered byte array, on solaris
1917 	 * it is a structure in host order so we swap the components as needed.
1918 	 */
1919 	temp = htonll(port_info->p_sgid_tbl[cmd.gid_index].gid.ucast_gid.
1920 	    ugid_prefix);
1921 	(void) memcpy(&resp.gid[0], &temp, sizeof (temp));
1922 	temp = htonll(port_info->p_sgid_tbl[cmd.gid_index].gid.ucast_gid.
1923 	    ugid_guid);
1924 	(void) memcpy(&resp.gid[8], &temp, sizeof (temp));
1925 
1926 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "query_gid: gid = "
1927 	    "0x%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
1928 	    "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:",
1929 	    resp.gid[0], resp.gid[1], resp.gid[2], resp.gid[3],
1930 	    resp.gid[4], resp.gid[5], resp.gid[6], resp.gid[7],
1931 	    resp.gid[8], resp.gid[9], resp.gid[10], resp.gid[11],
1932 	    resp.gid[12], resp.gid[13], resp.gid[14], resp.gid[15]);
1933 
1934 	ibt_free_portinfo(port_info, port_info_size);
1935 
1936 #ifdef	_LP64
1937 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
1938 #else
1939 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
1940 #endif
1941 	if (rc != 0) {
1942 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1943 		    "query_gid: copyout %d", rc);
1944 		rc = EFAULT;
1945 		goto out;
1946 	}
1947 
1948 	rc = DDI_SUCCESS;
1949 out:
1950 	return (rc);
1951 }
1952 
1953 /*
1954  * Function:
1955  *	sol_uverbs_query_pkey
1956  * Input:
1957  *	uctxt   - Pointer to the callers user context.
1958  *	buf     - Pointer to kernel buffer containing a query pkey command.
1959  *	in_len  - Length in bytes of input command buffer.
1960  *	out_len - Length in bytes of output response buffer.
1961  * Output:
1962  *	The command output buffer is updated with command results.
1963  * Returns:
1964  *	DDI_SUCCESS on success, else error code.
1965  * Description:
1966  * 	User verb entry point to query a device for the pkey at the specified
1967  *	port and pkey index.
1968  */
1969 /* ARGSUSED */
1970 int
sol_uverbs_query_pkey(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)1971 sol_uverbs_query_pkey(uverbs_uctxt_uobj_t *uctxt, char *buf, int in_len,
1972     int out_len)
1973 {
1974 	struct ib_uverbs_query_pkey		cmd;
1975 	struct ib_uverbs_query_pkey_resp	resp;
1976 	ibt_hca_portinfo_t			*port_info;
1977 	uint_t					port_info_n;
1978 	uint_t					port_info_size;
1979 	int					rc;
1980 
1981 	(void) memcpy(&cmd, buf, sizeof (cmd));
1982 
1983 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1984 	    "query_pkey: entry, port = %d, pkey index = %d",
1985 	    cmd.port_num, cmd.pkey_index);
1986 
1987 	if (!cmd.port_num || cmd.port_num > uctxt->hca->attr.hca_nports) {
1988 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
1989 		    "query_pkey: Invalid port specified");
1990 
1991 		rc = EINVAL;
1992 		goto out;
1993 	}
1994 
1995 	rc = ibt_query_hca_ports(uctxt->hca->hdl, cmd.port_num, &port_info,
1996 	    &port_info_n, &port_info_size);
1997 	if (rc != IBT_SUCCESS) {
1998 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
1999 		    "query_pkey: ibt_query_hca_ports() %d", rc);
2000 		rc = sol_uverbs_ibt_to_kernel_status(rc);
2001 		goto out;
2002 	}
2003 
2004 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2005 	    "query_pkey: port %d, requested index %d, number of pkey entries "
2006 	    "%d", cmd.port_num, cmd.pkey_index, port_info->p_pkey_tbl_sz);
2007 
2008 
2009 	if (cmd.pkey_index >= port_info->p_pkey_tbl_sz) {
2010 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2011 		    "query_pkey: Invalid index %d, table size = %d",
2012 		    cmd.pkey_index, port_info->p_pkey_tbl_sz);
2013 
2014 		ibt_free_portinfo(port_info, port_info_size);
2015 		rc = EINVAL;
2016 		goto out;
2017 	}
2018 
2019 	(void) memset(&resp, 0, sizeof (resp));
2020 	resp.pkey = port_info->p_pkey_tbl[cmd.pkey_index];
2021 
2022 	ibt_free_portinfo(port_info, port_info_size);
2023 
2024 #ifdef	_LP64
2025 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
2026 #else
2027 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
2028 #endif
2029 	if (rc != 0) {
2030 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2031 		    "query_pkey: copyout %d", rc);
2032 		rc = EFAULT;
2033 		goto out;
2034 	}
2035 
2036 	rc = DDI_SUCCESS;
2037 out:
2038 	return (rc);
2039 }
2040 
2041 /*
2042  * Function:
2043  *	sol_uverbs_reg_mr
2044  * Input:
2045  *	uctxt   - Pointer to the callers user context.
2046  *	buf     - Pointer to kernel buffer containing command.
2047  *	in_len  - Length in bytes of input command buffer.
2048  *	out_len - Length in bytes of output response buffer.
2049  * Output:
2050  *	The command output buffer is updated with command results.
2051  * Returns:
2052  *	DDI_SUCCESS on success, else error code.
2053  * Description:
2054  * 	User verb entry point to register a memory region.
2055  */
2056 /* ARGSUSED */
2057 int
sol_uverbs_reg_mr(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)2058 sol_uverbs_reg_mr(uverbs_uctxt_uobj_t *uctxt, char *buf, int in_len,
2059     int out_len)
2060 {
2061 	struct ib_uverbs_reg_mr		cmd;
2062 	struct ib_uverbs_reg_mr_resp	resp;
2063 	uverbs_upd_uobj_t		*upd;
2064 	uverbs_umr_uobj_t		*umr;
2065 	ibt_mr_attr_t			new_mem_attr;
2066 	ibt_mr_desc_t			new_mr_desc;
2067 	int				rc;
2068 
2069 	(void) memcpy(&cmd, buf, sizeof (cmd));
2070 	(void) memset(&resp, 0, sizeof (resp));
2071 	(void) memset(&new_mem_attr, 0, sizeof (new_mem_attr));
2072 	(void) memset(&new_mr_desc, 0, sizeof (new_mr_desc));
2073 
2074 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "reg_mr()");
2075 
2076 	new_mem_attr.mr_vaddr	= cmd.start;
2077 	new_mem_attr.mr_len	= cmd.length;
2078 	new_mem_attr.mr_as	= curproc->p_as;
2079 	new_mem_attr.mr_flags	= IBT_MR_NOSLEEP;
2080 
2081 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "reg_mr : "
2082 	    "mr_vaddr 0x%0lX, mr_len %d, mr_as %d, mr_flags %d",
2083 	    new_mem_attr.mr_vaddr, new_mem_attr.mr_len,
2084 	    new_mem_attr.mr_as, new_mem_attr.mr_flags);
2085 
2086 	if ((cmd.access_flags & IB_ACCESS_LOCAL_WRITE) ==
2087 	    IB_ACCESS_LOCAL_WRITE) {
2088 		new_mem_attr.mr_flags |= IBT_MR_ENABLE_LOCAL_WRITE;
2089 	}
2090 	if ((cmd.access_flags & IB_ACCESS_REMOTE_WRITE) ==
2091 	    IB_ACCESS_REMOTE_WRITE) {
2092 		new_mem_attr.mr_flags |= IBT_MR_ENABLE_REMOTE_WRITE;
2093 	}
2094 	if ((cmd.access_flags & IB_ACCESS_REMOTE_READ) ==
2095 	    IB_ACCESS_REMOTE_READ) {
2096 		new_mem_attr.mr_flags |= IBT_MR_ENABLE_REMOTE_READ;
2097 	}
2098 	if ((cmd.access_flags & IB_ACCESS_REMOTE_ATOMIC) ==
2099 	    IB_ACCESS_REMOTE_ATOMIC) {
2100 		new_mem_attr.mr_flags |= IBT_MR_ENABLE_REMOTE_ATOMIC;
2101 	}
2102 	if ((cmd.access_flags & IB_ACCESS_MW_BIND) == IB_ACCESS_MW_BIND) {
2103 		new_mem_attr.mr_flags |= IBT_MR_ENABLE_WINDOW_BIND;
2104 	}
2105 	if ((cmd.access_flags & IB_ACCESS_SO) == IB_ACCESS_SO) {
2106 		new_mem_attr.mr_flags |= IBT_MR_DISABLE_RO;
2107 	}
2108 
2109 	umr = kmem_zalloc(sizeof (*umr), KM_NOSLEEP);
2110 	if (umr == NULL) {
2111 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2112 		    "reg_mr: User object mem allocation error");
2113 		rc = ENOMEM;
2114 		goto out;
2115 	}
2116 	sol_ofs_uobj_init(&umr->uobj, 0, SOL_UVERBS_UMR_UOBJ_TYPE);
2117 	rw_enter(&umr->uobj.uo_lock, RW_WRITER);
2118 
2119 	upd = uverbs_uobj_get_upd_read(cmd.pd_handle);
2120 	if (upd == NULL) {
2121 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2122 		    "reg_mr: PD invalid");
2123 		rc = EINVAL;
2124 		goto bad_pd;
2125 	}
2126 
2127 	rc = ibt_register_mr(uctxt->hca->hdl, upd->pd, &new_mem_attr, &umr->mr,
2128 	    &new_mr_desc);
2129 
2130 	if (rc != IBT_SUCCESS) {
2131 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2132 		    "reg_mr: ibt_register_mr() (rc=%d)", rc);
2133 		rc = sol_uverbs_ibt_to_kernel_status(rc);
2134 		umr->uobj.uo_uobj_sz = sizeof (uverbs_umr_uobj_t);
2135 		goto err_register;
2136 	}
2137 
2138 	if (sol_ofs_uobj_add(&uverbs_umr_uo_tbl, &umr->uobj) != 0) {
2139 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2140 		    "reg_mr: User object add failed");
2141 		rc = ENOMEM;
2142 		goto err_add_uobj;
2143 	}
2144 
2145 	resp.mr_handle  = umr->uobj.uo_id;
2146 	resp.lkey	= new_mr_desc.md_lkey;
2147 	resp.rkey	= new_mr_desc.md_rkey;
2148 
2149 #ifdef	_LP64
2150 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
2151 #else
2152 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
2153 #endif
2154 	if (rc != 0) {
2155 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2156 		    "reg_mr: Error writing resp data (rc=%d)", rc);
2157 		rc = EFAULT;
2158 		goto err_response;
2159 	}
2160 
2161 	mutex_enter(&uctxt->lock);
2162 	umr->list_entry  = add_genlist(&uctxt->mr_list, (uintptr_t)umr, uctxt);
2163 	mutex_exit(&uctxt->lock);
2164 
2165 	if (!umr->list_entry) {
2166 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2167 		    "reg_mr: Error adding umr to mr_list\n");
2168 		rc = ENOMEM;
2169 		goto err_response;
2170 	}
2171 
2172 	umr->uobj.uo_live = 1;
2173 	rw_exit(&umr->uobj.uo_lock);
2174 
2175 	sol_ofs_uobj_put(&upd->uobj);
2176 
2177 	return (DDI_SUCCESS);
2178 
2179 err_response:
2180 	/*
2181 	 * Need to set uo_live, so sol_ofs_uobj_remove() will
2182 	 * remove the object from the object table.
2183 	 */
2184 	umr->uobj.uo_live = 1;
2185 	(void) sol_ofs_uobj_remove(&uverbs_umr_uo_tbl, &umr->uobj);
2186 
2187 err_add_uobj:
2188 	(void) ibt_deregister_mr(uctxt->hca->hdl, umr->mr);
2189 
2190 err_register:
2191 	sol_ofs_uobj_put(&upd->uobj);
2192 
2193 bad_pd:
2194 	rw_exit(&umr->uobj.uo_lock);
2195 	sol_ofs_uobj_deref(&umr->uobj, sol_ofs_uobj_free);
2196 
2197 out:
2198 	return (rc);
2199 }
2200 
2201 /*
2202  * Function:
2203  *	sol_uverbs_dereg_mr
2204  * Input:
2205  *	uctxt   - Pointer to the callers user context.
2206  *	buf     - Pointer to kernel buffer containing command.
2207  *	in_len  - Length in bytes of input command buffer.
2208  *	out_len - Length in bytes of output response buffer.
2209  * Output:
2210  *	The command output buffer is updated with command results.
2211  * Returns:
2212  *	DDI_SUCCESS on success, else error code.
2213  * Description:
2214  * 	User verb entry point to de-register a memory region.
2215  */
2216 /* ARGSUSED */
2217 int
sol_uverbs_dereg_mr(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)2218 sol_uverbs_dereg_mr(uverbs_uctxt_uobj_t *uctxt, char *buf, int in_len,
2219     int out_len)
2220 {
2221 	struct ib_uverbs_dereg_mr	cmd;
2222 	uverbs_umr_uobj_t		*umr;
2223 	int				rc;
2224 
2225 	(void) memcpy(&cmd, buf, sizeof (cmd));
2226 
2227 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2228 	    "dereg_mr(mr_handle=%d)", cmd.mr_handle);
2229 
2230 	umr = uverbs_uobj_get_umr_write(cmd.mr_handle);
2231 	if (umr == NULL) {
2232 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2233 		    "dereg_mr: Invalid handle");
2234 		rc = EINVAL;
2235 		goto err_out;
2236 	}
2237 
2238 	rc = ibt_deregister_mr(uctxt->hca->hdl, umr->mr);
2239 
2240 	if (rc != IBT_SUCCESS) {
2241 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2242 		    "dereg_mr: ibt_deregister_mr() (rc=%d)", rc);
2243 		rc = sol_uverbs_ibt_to_kernel_status(rc);
2244 		goto err_deregister;
2245 	}
2246 
2247 	/*
2248 	 * Remove from the list of this contexts MR resources, then remove from
2249 	 * the resource management table and the reference placed on the user
2250 	 * object at MR creation.
2251 	 */
2252 	mutex_enter(&uctxt->lock);
2253 	delete_genlist(&uctxt->mr_list, umr->list_entry);
2254 	mutex_exit(&uctxt->lock);
2255 
2256 	(void) sol_ofs_uobj_remove(&uverbs_umr_uo_tbl, &umr->uobj);
2257 
2258 	/*
2259 	 * Drop the lock and ref held by get_umr_write.
2260 	 */
2261 	sol_ofs_uobj_put(&umr->uobj);
2262 
2263 	sol_ofs_uobj_deref(&umr->uobj, sol_ofs_uobj_free);
2264 
2265 	cmd.mr_handle = 0;
2266 	return (DDI_SUCCESS);
2267 
2268 err_deregister:
2269 	/*
2270 	 * Drop the lock and ref held by get_umr_write.
2271 	 */
2272 	sol_ofs_uobj_put(&umr->uobj);
2273 
2274 err_out:
2275 	return (rc);
2276 }
2277 
2278 /*
2279  * Function:
2280  *	sol_uverbs_create_ah
2281  * Input:
2282  *	uctxt   - Pointer to the callers user context.
2283  *	buf     - Pointer to kernel buffer containing command.
2284  *	in_len  - Length in bytes of input command buffer.
2285  *	out_len - Length in bytes of output response buffer.
2286  * Output:
2287  *	The command output buffer is updated with command results.
2288  * Returns:
2289  *	DDI_SUCCESS on success, else error code.
2290  * Description:
2291  * 	User verb entry point to for devices that require kernel AH creation.
2292  */
2293 /* ARGSUSED */
2294 int
sol_uverbs_create_ah(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)2295 sol_uverbs_create_ah(uverbs_uctxt_uobj_t *uctxt, char *buf, int in_len,
2296     int out_len)
2297 {
2298 	SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str,
2299 	    "create_ah: kernel user verb not implemented");
2300 	return (ENOTSUP);
2301 }
2302 
2303 /*
2304  * Function:
2305  *	sol_uverbs_destroy_ah
2306  * Input:
2307  *	uctxt   - Pointer to the callers user context.
2308  *	buf     - Pointer to kernel buffer containing command.
2309  *	in_len  - Length in bytes of input command buffer.
2310  *	out_len - Length in bytes of output response buffer.
2311  * Output:
2312  *	The command output buffer is updated with command results.
2313  * Returns:
2314  *	DDI_SUCCESS on success, else error code.
2315  * Description:
2316  * 	User verb entry point to for devices that require kernel AH deletion.
2317  */
2318 /* ARGSUSED */
2319 int
sol_uverbs_destroy_ah(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)2320 sol_uverbs_destroy_ah(uverbs_uctxt_uobj_t *uctxt, char *buf, int in_len,
2321     int out_len)
2322 {
2323 	SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str,
2324 	    "destroy_ah: kernel user verb not implemented");
2325 	return (ENOTSUP);
2326 }
2327 
2328 /*
2329  * Function:
2330  *	sol_uverbs_create_comp_chan
2331  * Input:
2332  *	uctxt   - Pointer to the callers user context.
2333  *	buf     - Pointer to kernel buffer containing command.
2334  *	in_len  - Length in bytes of input command buffer.
2335  *	out_len - Length in bytes of output response buffer.
2336  * Output:
2337  *	The command output buffer is updated with command results.
2338  * Returns:
2339  *	DDI_SUCCESS on success, else error code.
2340  * Description:
2341  * 	User verb entry point to create a completion event channel.
2342  */
2343 int
sol_uverbs_create_comp_channel(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)2344 sol_uverbs_create_comp_channel(uverbs_uctxt_uobj_t *uctxt, char *buf,
2345     int in_len, int out_len)
2346 {
2347 	struct ib_uverbs_create_comp_channel		cmd;
2348 	struct ib_uverbs_create_comp_channel_resp	resp;
2349 	int						rc;
2350 	minor_t						compl_id;
2351 	uverbs_uctxt_uobj_t				*compl_uctxt;
2352 
2353 	(void) memcpy(&cmd, buf, sizeof (cmd));
2354 	(void) memset(&resp, 0, sizeof (resp));
2355 
2356 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2357 	    "create_comp_chan: entry, in_len=%d, out_len=%d",
2358 	    in_len, out_len);
2359 
2360 	/*
2361 	 * libibverbs will have passed minor of the compl file in
2362 	 * resp.fd. Use this to determine the uctxt created for
2363 	 * completions.
2364 	 */
2365 #ifdef	_LP64
2366 	rc = copyin((void*)cmd.response.r_laddr, (void*)&resp, sizeof (resp));
2367 #else
2368 	rc = copyin((void*)cmd.response.r_addr, (void*)&resp, sizeof (resp));
2369 #endif
2370 	if (rc != 0) {
2371 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2372 		    "create_comp: copyin (rc=%d)", rc);
2373 		rc = EFAULT;
2374 		return (rc);
2375 	}
2376 	compl_id = resp.fd;
2377 	if (compl_id < SOL_UVERBS_DRIVER_MAX_MINOR) {
2378 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2379 		    "create_comp: Invalid compl user context id %x",
2380 		    compl_id);
2381 		return (ENXIO);
2382 	}
2383 
2384 	compl_uctxt = uverbs_uobj_get_uctxt_read(compl_id -
2385 	    SOL_UVERBS_DRIVER_MAX_MINOR);
2386 	if (compl_uctxt == NULL) {
2387 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2388 		    "create_comp: Failed get compl user context");
2389 		return (ENXIO);
2390 	}
2391 	if (compl_uctxt->uctxt_type != SOL_UVERBS_UCTXT_EVENT ||
2392 	    compl_uctxt->uctxt_verbs_id != 0) {
2393 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2394 		    "create_comp_chan: Invalid user context - "
2395 		    "possibly reused");
2396 		return (ENXIO);
2397 	}
2398 	compl_uctxt->uctxt_type = SOL_UVERBS_UCTXT_COMPL;
2399 	compl_uctxt->uctxt_verbs_id = uctxt->uobj.uo_id +
2400 	    SOL_UVERBS_DRIVER_MAX_MINOR;
2401 	uctxt->uctxt_comp_id = compl_id;
2402 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "create_comp_chan: "
2403 	    "uctxt %p, compl_uctxt %p, compl_id %x", uctxt,
2404 	    compl_uctxt, compl_id);
2405 
2406 	/*
2407 	 * Allocate an event file to be used for completion
2408 	 * event notification.
2409 	 */
2410 	compl_uctxt->comp_evfile = uverbs_alloc_event_file(uctxt, 0);
2411 	if (compl_uctxt->comp_evfile == NULL) {
2412 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2413 		    "create_comp_chan: Event file alloc error");
2414 		rc = EINVAL;
2415 		sol_ofs_uobj_put(&compl_uctxt->uobj);
2416 		return (rc);
2417 	}
2418 
2419 	/*
2420 	 * Place an extra reference on the compl event file.  These will
2421 	 * be used to handle the natural race of between the closing of
2422 	 * the compl event file and uverbs device file that can occur.
2423 	 */
2424 	sol_ofs_uobj_ref(&compl_uctxt->comp_evfile->uobj);
2425 
2426 	sol_ofs_uobj_put(&compl_uctxt->uobj);
2427 
2428 #ifdef	_LP64
2429 	rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
2430 #else
2431 	rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
2432 #endif
2433 	if (rc != 0) {
2434 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2435 		    "create_comp_chan: copyout %d", rc);
2436 		rc = EFAULT;
2437 		return (rc);
2438 	}
2439 
2440 	return (0);
2441 }
2442 
2443 /*
2444  * Function:
2445  *	sol_uverbs_dummy_command
2446  * Input:
2447  *	uctxt   - Pointer to the callers user context.
2448  *	buf     - Pointer to kernel buffer containing command.
2449  *	in_len  - Length in bytes of input command buffer.
2450  *	out_len - Length in bytes of output response buffer.
2451  * Output:
2452  *	The command output buffer is updated with command results.
2453  * Returns:
2454  *	DDI_SUCCESS on success, else error code.
2455  * Description:
2456  * 	User verb generic place holder stub.
2457  */
2458 /* ARGSUSED */
2459 int
sol_uverbs_dummy_command(uverbs_uctxt_uobj_t * uctxt,char * buf,int in_len,int out_len)2460 sol_uverbs_dummy_command(uverbs_uctxt_uobj_t *uctxt, char *buf, int in_len,
2461     int out_len)
2462 {
2463 	SOL_OFS_DPRINTF_L4(sol_uverbs_dbg_str,
2464 	    "sol_uverbs_dummy_command invoked");
2465 
2466 	return (0);
2467 }
2468 
2469 /*
2470  * Function:
2471  *	sol_uverbs_write
2472  * Input:
2473  *	dev	- Device number.
2474  *	uiop	- Pointer to the uio structure that describes the data (i.e.
2475  *                Solaris User Verbs command).
2476  *	credp	- A pointer to the user credentials for the I/O transaction.
2477  * Output:
2478  *	uiop	-
2479  * Returns:
2480  *	DDI_SUCCESS on success, else error code.
2481  * Description:
2482  * 	User verb write entry point.  A user deivce libraries use this
2483  *	entry point to execute a kernel agent user verbs call.  During
2484  *	the course of the call the user process will hold a read reference
2485  *	to the associated user context.
2486  */
2487 #define	SOL_UVERBS_MAX_CMD_PAYLOAD    512
2488 /* ARGSUSED */
2489 static int
sol_uverbs_write(dev_t dev,struct uio * uiop,cred_t * credp)2490 sol_uverbs_write(dev_t dev, struct uio *uiop, cred_t *credp)
2491 {
2492 	uverbs_uctxt_uobj_t		*uctxt;
2493 	size_t				len = uiop->uio_resid;
2494 	int				rc;
2495 	struct ib_uverbs_cmd_hdr	hdr;
2496 	char				payload[SOL_UVERBS_MAX_CMD_PAYLOAD];
2497 	minor_t				id = getminor(dev);
2498 
2499 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2500 	    "uverbs_write: entry (len=%d)", len);
2501 
2502 	ASSERT(id >= SOL_UVERBS_DRIVER_MAX_MINOR);
2503 
2504 	uctxt = uverbs_uobj_get_uctxt_read(id - SOL_UVERBS_DRIVER_MAX_MINOR);
2505 	if (uctxt == NULL) {
2506 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2507 		    "uverbs_write: Failed get user context");
2508 		return (ENXIO);
2509 	}
2510 
2511 	if (uctxt->uctxt_type != SOL_UVERBS_UCTXT_VERBS) {
2512 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2513 		    "uverbs_write: write() on invalid uctxt type %x",
2514 		    uctxt->uctxt_type);
2515 		rc = ENXIO;
2516 		goto out;
2517 	}
2518 
2519 	if (len < sizeof (hdr)) {
2520 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2521 		    "uverbs_write: Header too small");
2522 		rc =  EINVAL;
2523 		goto out;
2524 	}
2525 
2526 	hdr.command	= -1;
2527 	hdr.in_words	= 0;
2528 	hdr.out_words	= 0;
2529 
2530 	if (uiomove(&hdr, sizeof (hdr), UIO_WRITE, uiop) != 0) {
2531 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2532 		    "uverbs_write: Error reading header");
2533 		rc = EFAULT;
2534 		goto out;
2535 	}
2536 
2537 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2538 	    "uverbs_write:  hdr.command   = %d", hdr.command);
2539 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2540 	    "uverbs_write:  hdr.command   = %d", hdr.command);
2541 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2542 	    "uverbs_write:  hdr.in_words  = %d", hdr.in_words);
2543 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2544 	    "uverbs_write:  hdr.out_words = %d", hdr.out_words);
2545 
2546 	if (hdr.in_words * 4 != len) {
2547 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2548 		    "uverbs_write: Invalid header size");
2549 		rc = EINVAL;
2550 		goto out;
2551 	}
2552 
2553 	if (hdr.command >=
2554 	    sizeof (uverbs_cmd_table)/sizeof (uverbs_cmd_table[0]) ||
2555 	    !uverbs_cmd_table[hdr.command]) {
2556 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2557 		    "uverbs_write: Invalid command (%d)", hdr.command);
2558 		rc = EINVAL;
2559 		goto out;
2560 	}
2561 
2562 	ASSERT(len <= SOL_UVERBS_MAX_CMD_PAYLOAD);
2563 
2564 	if (uiomove(&payload, len, UIO_WRITE, uiop) != 0) {
2565 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2566 		    "uverbs_write: Error reading payload");
2567 		rc = EFAULT;
2568 		goto out;
2569 	}
2570 
2571 #ifdef DEBUG
2572 	unsigned int	*payload_int = (unsigned int *)payload;
2573 
2574 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2575 	    "payload:   %08x,    %08x,    %08x,    %08x",
2576 	    payload_int[0], payload_int[1],
2577 	    payload_int[2], payload_int[3]);
2578 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2579 	    "payload:   %08x,    %08x,    %08x,    %08x",
2580 	    payload_int[4], payload_int[5],
2581 	    payload_int[6], payload_int[7]);
2582 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2583 	    "payload:   %08x,    %08x,    %08x,    %08x",
2584 	    payload_int[8], payload_int[9],
2585 	    payload_int[10], payload_int[11]);
2586 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2587 	    "payload:   %08x,    %08x,    %08x",
2588 	    payload_int[12], payload_int[13], payload_int[14]);
2589 #endif
2590 
2591 	rc = uverbs_cmd_table[hdr.command](uctxt, &payload[0], hdr.in_words * 4,
2592 	    hdr.out_words * 4);
2593 
2594 out:
2595 	sol_ofs_uobj_put(&uctxt->uobj);
2596 
2597 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2598 	    "uverbs_write: rc = %d", rc);
2599 
2600 	return (rc);
2601 }
2602 
2603 static int
sol_uverbs_poll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)2604 sol_uverbs_poll(dev_t dev, short events, int anyyet,
2605     short *reventsp, struct pollhead **phpp)
2606 {
2607 	minor_t			id = getminor(dev);
2608 	uverbs_uctxt_uobj_t	*uctxt, *verbs_uctxt;
2609 	int			rc;
2610 
2611 #ifdef DEBUG
2612 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "uverbs_poll(%p, %x, %x, "
2613 	    "%p, %p)", dev, events, anyyet, reventsp, phpp);
2614 #endif
2615 
2616 	ASSERT(id >= SOL_UVERBS_DRIVER_MAX_MINOR);
2617 
2618 	uctxt = uverbs_uobj_get_uctxt_read(id - SOL_UVERBS_DRIVER_MAX_MINOR);
2619 	if (uctxt == NULL) {
2620 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2621 		    "uverbs_poll: Failed get user context");
2622 		return (ENXIO);
2623 	}
2624 
2625 	if (uctxt->uctxt_verbs_id < SOL_UVERBS_DRIVER_MAX_MINOR) {
2626 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2627 		    "uverbs_poll: Invalid Verbs user context id, %x",
2628 		    uctxt->uctxt_verbs_id);
2629 		sol_ofs_uobj_put(&uctxt->uobj);
2630 		return (ENXIO);
2631 	}
2632 	verbs_uctxt = uverbs_uobj_get_uctxt_read(uctxt->uctxt_verbs_id
2633 	    - SOL_UVERBS_DRIVER_MAX_MINOR);
2634 	if (verbs_uctxt == NULL) {
2635 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2636 		    "uverbs_poll: Failed get verbs user context");
2637 		sol_ofs_uobj_put(&uctxt->uobj);
2638 		return (ENXIO);
2639 	}
2640 	if (uctxt->uctxt_type == SOL_UVERBS_UCTXT_ASYNC) {
2641 		ASSERT(verbs_uctxt->async_evfile);
2642 		rc = sol_uverbs_event_file_poll(verbs_uctxt->async_evfile,
2643 		    events, anyyet, reventsp, phpp);
2644 	} else if (uctxt->uctxt_type == SOL_UVERBS_UCTXT_COMPL) {
2645 		ASSERT(uctxt->comp_evfile);
2646 		rc = sol_uverbs_event_file_poll(uctxt->comp_evfile,
2647 		    events, anyyet, reventsp, phpp);
2648 	} else {
2649 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2650 		    "uverbs_poll: poll user context type %d",
2651 		    uctxt->uctxt_type);
2652 		rc = ENXIO;
2653 	}
2654 
2655 	sol_ofs_uobj_put(&verbs_uctxt->uobj);
2656 	sol_ofs_uobj_put(&uctxt->uobj);
2657 	return (rc);
2658 }
2659 
2660 /*
2661  * Function:
2662  *	sol_uverbs_alloc_uctxt
2663  * Input:
2664  *	devp	 - A pointer to the device number associated with the open.
2665  *	mod_ctxt - A pointer to the drivers module context.
2666  *	minor    - The minor device number.
2667  * Output:
2668  *	None.
2669  * Returns:
2670  *	On success a new user context user resource object associated with
2671  *	the device passed via devp. NULL on error.
2672  * Description:
2673  * 	Allocate a new user context user resource object and initialize it.
2674  *	The users asynchronous event file is created as part of this. On
2675  *	successful allocation, the user context is returned with the
2676  *	associated write lock enabled.
2677  */
2678 static uverbs_uctxt_uobj_t *
sol_uverbs_alloc_uctxt(dev_t * devp,uverbs_module_context_t * mod_ctxt,minor_t minor)2679 sol_uverbs_alloc_uctxt(dev_t *devp, uverbs_module_context_t *mod_ctxt,
2680     minor_t minor)
2681 {
2682 	uverbs_uctxt_uobj_t *uctxt = NULL;
2683 
2684 	uctxt = kmem_zalloc(sizeof (uverbs_uctxt_uobj_t), KM_SLEEP);
2685 	ASSERT(uctxt != NULL);
2686 	sol_ofs_uobj_init(&uctxt->uobj, 0, SOL_UVERBS_UCTXT_UOBJ_TYPE);
2687 	rw_enter(&uctxt->uobj.uo_lock, RW_WRITER);
2688 	if (sol_ofs_uobj_add(&uverbs_uctxt_uo_tbl, &uctxt->uobj) != 0) {
2689 		/*
2690 		 * The initialization routine set's the initial reference,
2691 		 * we dereference the object here to clean it up.
2692 		 */
2693 		SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2694 		    "alloc_uctxt: Object add failed");
2695 		rw_exit(&uctxt->uobj.uo_lock);
2696 		sol_ofs_uobj_free(&uctxt->uobj);
2697 		return (NULL);
2698 	}
2699 
2700 	/*
2701 	 * Create the new clone for this user context using the
2702 	 * object id as the minor number.   Note we offset beyond all
2703 	 * real minor device numbers.
2704 	 */
2705 	*devp = makedevice(getmajor(*devp),
2706 	    uctxt->uobj.uo_id + SOL_UVERBS_DRIVER_MAX_MINOR);
2707 
2708 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "uverbs_open : "
2709 	    "uctxt %p, minor %x- alloced", uctxt,
2710 	    uctxt->uobj.uo_id + SOL_UVERBS_DRIVER_MAX_MINOR);
2711 
2712 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2713 	    "alloc_uctxt: user context allocated: %p, ref = %d",
2714 	    (void *)uctxt, uctxt->uobj.uo_refcnt);
2715 
2716 	mutex_init(&uctxt->lock, NULL, MUTEX_DRIVER, NULL);
2717 	uctxt->mod_ctxt	= mod_ctxt;
2718 	if (minor == SOL_UVERBS_DRIVER_EVENT_MINOR) {
2719 		uctxt->uctxt_type = SOL_UVERBS_UCTXT_EVENT;
2720 	} else {
2721 		uctxt->uctxt_type = SOL_UVERBS_UCTXT_VERBS;
2722 		uctxt->hca = &mod_ctxt->hcas[minor];
2723 	}
2724 
2725 	init_genlist(&uctxt->pd_list);
2726 	init_genlist(&uctxt->mr_list);
2727 	init_genlist(&uctxt->cq_list);
2728 	init_genlist(&uctxt->srq_list);
2729 	init_genlist(&uctxt->qp_list);
2730 	init_genlist(&uctxt->ah_list);
2731 
2732 	/* Return with uobj uo_lock held for WRITTER. */
2733 	return (uctxt);
2734 }
2735 
2736 /*
2737  * Function:
2738  *	sol_uverbs_qpnum2uqpid
2739  * Input:
2740  *	qp_num	- used to find the user object that mapped to this qp_num
2741  * Output:
2742  *	None
2743  * Returns:
2744  *	DDI_FAILURE if not found else
2745  *	the uo_id in the user object that matches the qp_num
2746  * Description:
2747  * 	Find the uo_id of the user object which mapped to the input qp_num
2748  */
2749 uint32_t
sol_uverbs_qpnum2uqpid(uint32_t qp_num)2750 sol_uverbs_qpnum2uqpid(uint32_t qp_num)
2751 {
2752 	sol_ofs_uobj_table_t	*uo_tbl;
2753 	sol_ofs_uobj_t		*uobj;
2754 	uverbs_uqp_uobj_t	*uqp;
2755 	int			i, j;
2756 	sol_ofs_uobj_blk_t	*blk;
2757 
2758 	uo_tbl = &uverbs_uqp_uo_tbl;
2759 	rw_enter(&uo_tbl->uobj_tbl_lock, RW_READER);
2760 
2761 	/*
2762 	 * Try to find an empty slot for the new user object.
2763 	 */
2764 	for (i = 0; i < uo_tbl->uobj_tbl_used_blks; i++) {
2765 		blk = uo_tbl->uobj_tbl_uo_root[i];
2766 		if (blk != NULL) {
2767 			for (j = 0; j < SOL_OFS_UO_BLKSZ; j++) {
2768 				if ((uobj = blk->ofs_uoblk_blks[j]) != NULL) {
2769 					uqp = (uverbs_uqp_uobj_t *)uobj;
2770 					if (uqp->qp_num == qp_num) {
2771 						rw_exit(&uo_tbl->uobj_tbl_lock);
2772 						SOL_OFS_DPRINTF_L5(
2773 						    sol_uverbs_dbg_str,
2774 						    "qpnum2uqpid(%x) ret %x",
2775 						    qp_num, uobj->uo_id);
2776 						return (uobj->uo_id);
2777 					}
2778 				}
2779 			}
2780 		}
2781 	}
2782 
2783 	rw_exit(&uo_tbl->uobj_tbl_lock);
2784 	SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qpnum2uqpid(%x) ret %x",
2785 	    qp_num, DDI_FAILURE);
2786 	return (DDI_FAILURE);
2787 }
2788 
2789 void
sol_uverbs_get_clnt_hdl(void ** ibclnt_hdl,void ** iwclnt_hdl)2790 sol_uverbs_get_clnt_hdl(void **ibclnt_hdl, void **iwclnt_hdl)
2791 {
2792 	*ibclnt_hdl = sol_uverbs_ib_clntp;
2793 	*iwclnt_hdl = NULL;
2794 }
2795 
2796 void *
sol_uverbs_qpnum2qphdl(uint32_t qpnum)2797 sol_uverbs_qpnum2qphdl(uint32_t qpnum)
2798 {
2799 	int32_t	uqpid;
2800 
2801 	uqpid = sol_uverbs_qpnum2uqpid(qpnum);
2802 	if (uqpid == DDI_FAILURE)
2803 		return (NULL);
2804 	return (sol_uverbs_uqpid_to_ibt_handle(uqpid));
2805 }
2806 
2807 int
sol_uverbs_disable_uqpn_modify(uint32_t qpnum)2808 sol_uverbs_disable_uqpn_modify(uint32_t qpnum)
2809 {
2810 	int32_t	uqpid;
2811 
2812 	uqpid = sol_uverbs_qpnum2uqpid(qpnum);
2813 	if (uqpid == DDI_FAILURE)
2814 		return (-1);
2815 
2816 	return (sol_uverbs_disable_user_qp_modify(uqpid));
2817 }
2818 
2819 extern int uverbs_uqpn_cq_ctrl(uint32_t, sol_uverbs_cq_ctrl_t);
2820 
2821 int
sol_uverbs_uqpn_cq_ctrl(uint32_t qpnum,sol_uverbs_cq_ctrl_t ctrl)2822 sol_uverbs_uqpn_cq_ctrl(uint32_t qpnum, sol_uverbs_cq_ctrl_t ctrl)
2823 {
2824 	int32_t	uqpid;
2825 
2826 	uqpid = sol_uverbs_qpnum2uqpid(qpnum);
2827 	if (uqpid == DDI_FAILURE)
2828 		return (-1);
2829 
2830 	return (uverbs_uqpn_cq_ctrl(uqpid, ctrl));
2831 }
2832 
2833 void
sol_uverbs_set_qp_free_state(sol_uverbs_qp_free_state_t qp_free_state,uint32_t qpnum,void * qphdl)2834 sol_uverbs_set_qp_free_state(sol_uverbs_qp_free_state_t qp_free_state,
2835     uint32_t qpnum, void *qphdl)
2836 {
2837 	int32_t			uqpid;
2838 	uverbs_uqp_uobj_t	*uqp;
2839 
2840 	SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2841 	    "sol_uverbs_set_qp_free_state(%x, %x, %p)",
2842 	    qp_free_state, qpnum, qphdl);
2843 	if (qp_free_state == SOL_UVERBS2UCMA_DISABLE_QP_FREE) {
2844 		uqpid = sol_uverbs_qpnum2uqpid(qpnum);
2845 		if (uqpid == DDI_FAILURE) {
2846 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2847 			    "set_qp_free_state(%d)-invalid qpnum",
2848 			    qpnum);
2849 			return;
2850 		}
2851 
2852 		uqp = uverbs_uobj_get_uqp_write(uqpid);
2853 		if (uqp == NULL) {
2854 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2855 			    "set_qp_free_state(%d)-uqp lookup failure", qpnum);
2856 			return;
2857 		}
2858 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2859 		    "set_qp_free_state : uqp %p, setting Disable QP Free", uqp);
2860 		uqp->uqp_free_state  = SOL_UVERBS2UCMA_DISABLE_QP_FREE;
2861 		sol_ofs_uobj_put(&uqp->uobj);
2862 		return;
2863 	}
2864 
2865 	ASSERT(qphdl);
2866 	uqp = (uverbs_uqp_uobj_t *)ibt_get_qp_private((ibt_qp_hdl_t)qphdl);
2867 	ASSERT(uqp);
2868 	if (uqp->uqp_free_state != SOL_UVERBS2UCMA_FREE_PENDING) {
2869 		/*
2870 		 * Enable free flag, so that close or userland free_qp
2871 		 * call can free this in the future.
2872 		 */
2873 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2874 		    "set_qp_free_state : uqp %p, setting Enable QP Free",
2875 		    uqp);
2876 		rw_enter(&(uqp->uobj.uo_lock), RW_WRITER);
2877 		uqp->uqp_free_state = SOL_UVERBS2UCMA_ENABLE_QP_FREE;
2878 		rw_exit(&(uqp->uobj.uo_lock));
2879 	} else {
2880 		/*
2881 		 * uqp_free_state is set to FREE_PENDING, QP has been freed
2882 		 * by userland. Call uverbs_uqp_free() to free this.
2883 		 */
2884 		SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
2885 		    "set_qp_free_state : uqp %p calling uverbs_uqp_free()",
2886 		    uqp);
2887 		rw_enter(&(uqp->uobj.uo_lock), RW_WRITER);
2888 		sol_ofs_uobj_ref(&uqp->uobj);
2889 		if (uverbs_uqp_free(uqp, uqp->uctxt))
2890 			SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
2891 			    "set_qp_free_state : uverbs_uqp_free(%p) failed",
2892 			    uqp);
2893 	}
2894 }
2895 
2896 /*
2897  * Function:
2898  *	sol_uverbs_user_objects_init
2899  * Input:
2900  *	None
2901  * Output:
2902  *	None
2903  * Returns:
2904  *	None
2905  * Description:
2906  * 	Initializes all of the user object resource managment tables.
2907  */
sol_uverbs_user_objects_init()2908 static void sol_uverbs_user_objects_init()
2909 {
2910 	sol_ofs_uobj_tbl_init(&uverbs_uctxt_uo_tbl,
2911 	    sizeof (uverbs_uctxt_uobj_t));
2912 	sol_ofs_uobj_tbl_init(&uverbs_upd_uo_tbl,
2913 	    sizeof (uverbs_upd_uobj_t));
2914 	sol_ofs_uobj_tbl_init(&uverbs_umr_uo_tbl,
2915 	    sizeof (uverbs_umr_uobj_t));
2916 	sol_ofs_uobj_tbl_init(&uverbs_ucq_uo_tbl,
2917 	    sizeof (uverbs_ucq_uobj_t));
2918 	sol_ofs_uobj_tbl_init(&uverbs_usrq_uo_tbl,
2919 	    sizeof (uverbs_usrq_uobj_t));
2920 	sol_ofs_uobj_tbl_init(&uverbs_uqp_uo_tbl,
2921 	    sizeof (uverbs_uqp_uobj_t));
2922 	sol_ofs_uobj_tbl_init(&uverbs_uah_uo_tbl,
2923 	    sizeof (uverbs_uah_uobj_t));
2924 	sol_ofs_uobj_tbl_init(&uverbs_ufile_uo_tbl,
2925 	    sizeof (uverbs_ufile_uobj_t));
2926 }
2927 
2928 /*
2929  * Function:
2930  *	sol_uverbs_user_objects_fini
2931  * Input:
2932  *	None
2933  * Output:
2934  *	None
2935  * Returns:
2936  *	None
2937  * Description:
2938  * 	Releases all of the user object resource managment tables.
2939  */
sol_uverbs_user_objects_fini()2940 static void sol_uverbs_user_objects_fini()
2941 {
2942 	sol_ofs_uobj_tbl_fini(&uverbs_ufile_uo_tbl);
2943 	sol_ofs_uobj_tbl_fini(&uverbs_uah_uo_tbl);
2944 	sol_ofs_uobj_tbl_fini(&uverbs_uqp_uo_tbl);
2945 	sol_ofs_uobj_tbl_fini(&uverbs_usrq_uo_tbl);
2946 	sol_ofs_uobj_tbl_fini(&uverbs_ucq_uo_tbl);
2947 	sol_ofs_uobj_tbl_fini(&uverbs_umr_uo_tbl);
2948 	sol_ofs_uobj_tbl_fini(&uverbs_upd_uo_tbl);
2949 	sol_ofs_uobj_tbl_fini(&uverbs_uctxt_uo_tbl);
2950 }
2951 
2952 /*
2953  * Function:
2954  *	sol_uverbs_ibt_to_kernel_status
2955  * Input:
2956  *	status	- An IBT status code.
2957  * Output:
2958  *	None
2959  * Returns:
2960  *	The "errno" based kernel error code the IBT status maps to.
2961  * Description:
2962  * 	Map an IBT status to the "errno" code that should be returned.
2963  */
2964 int
sol_uverbs_ibt_to_kernel_status(ibt_status_t status)2965 sol_uverbs_ibt_to_kernel_status(ibt_status_t status)
2966 {
2967 	int err;
2968 
2969 	switch (status) {
2970 		case IBT_NOT_SUPPORTED:
2971 			err = ENOTSUP;
2972 			break;
2973 
2974 		case IBT_ILLEGAL_OP:
2975 		case IBT_INVALID_PARAM:
2976 			err = EINVAL;
2977 			break;
2978 
2979 		case IBT_HCA_IN_USE:
2980 		case IBT_HCA_BUSY_DETACHING:
2981 		case IBT_HCA_BUSY_CLOSING:
2982 		case IBT_CHAN_IN_USE:
2983 		case IBT_CQ_BUSY:
2984 		case IBT_MR_IN_USE:
2985 		case IBT_PD_IN_USE:
2986 		case IBT_SRQ_IN_USE:
2987 			err = EBUSY;
2988 			break;
2989 		case	IBT_INSUFF_RESOURCE:
2990 		case	IBT_INSUFF_KERNEL_RESOURCE:
2991 		case	IBT_HCA_WR_EXCEEDED:
2992 		case	IBT_HCA_SGL_EXCEEDED:
2993 			err = ENOMEM;
2994 			break;
2995 
2996 		default:
2997 			err = EINVAL;
2998 	}
2999 	return (err);
3000 }
3001 
3002 /* ARGSUSED */
3003 uint32_t
sol_uverbs_ibt_to_of_device_cap_flags(ibt_hca_flags_t flags,ibt_hca_flags2_t flags2)3004 sol_uverbs_ibt_to_of_device_cap_flags(ibt_hca_flags_t flags,
3005     ibt_hca_flags2_t flags2) {
3006 
3007 	uint32_t of_flags = 0;
3008 
3009 	if (flags && IBT_HCA_RESIZE_CHAN)
3010 		of_flags |= IB_DEVICE_RESIZE_MAX_WR;
3011 
3012 	if (flags && IBT_HCA_PKEY_CNTR)
3013 		of_flags |= IB_DEVICE_BAD_PKEY_CNTR;
3014 
3015 	if (flags && IBT_HCA_QKEY_CNTR)
3016 		of_flags |= IB_DEVICE_BAD_QKEY_CNTR;
3017 
3018 	if (flags && IBT_HCA_RAW_MULTICAST)
3019 		of_flags |= IB_DEVICE_RAW_MULTI;
3020 
3021 	if (flags && IBT_HCA_AUTO_PATH_MIG)
3022 		of_flags |= IB_DEVICE_AUTO_PATH_MIG;
3023 
3024 	if (flags && IBT_HCA_SQD_SQD_PORT)
3025 		of_flags |= IB_DEVICE_CHANGE_PHY_PORT;
3026 
3027 	if (flags && IBT_HCA_AH_PORT_CHECK)
3028 		of_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE;
3029 
3030 	if (flags && IBT_HCA_CURRENT_QP_STATE)
3031 		of_flags |= IB_DEVICE_CURR_QP_STATE_MOD;
3032 
3033 	if (flags && IBT_HCA_SHUTDOWN_PORT)
3034 		of_flags |= IB_DEVICE_SHUTDOWN_PORT;
3035 
3036 	if (flags && IBT_HCA_INIT_TYPE)
3037 		of_flags |= IB_DEVICE_INIT_TYPE;
3038 
3039 	if (flags && IBT_HCA_PORT_UP)
3040 		of_flags |= IB_DEVICE_PORT_ACTIVE_EVENT;
3041 
3042 	if (flags && IBT_HCA_SI_GUID)
3043 		of_flags |= IB_DEVICE_SYS_IMAGE_GUID;
3044 
3045 	if (flags && IBT_HCA_RNR_NAK)
3046 		of_flags |= IB_DEVICE_RC_RNR_NAK_GEN;
3047 
3048 	if (flags && IBT_HCA_RESIZE_SRQ)
3049 		of_flags |= IB_DEVICE_SRQ_RESIZE;
3050 
3051 	if (flags && IBT_HCA_BASE_QUEUE_MGT)
3052 		of_flags |= IB_DEVICE_N_NOTIFY_CQ;
3053 
3054 	if (flags && IBT_HCA_ZERO_BASED_VA)
3055 		of_flags |= IB_DEVICE_ZERO_STAG;
3056 
3057 	if (flags && IBT_HCA_LOCAL_INVAL_FENCE)
3058 		of_flags |= IB_DEVICE_SEND_W_INV;
3059 
3060 	if (flags && IBT_HCA_MEM_WIN_TYPE_2B)
3061 		of_flags |= IB_DEVICE_MEM_WINDOW;
3062 
3063 	return (of_flags);
3064 }
3065 
3066 uint64_t
sol_uverbs_ibt_to_of_page_sz(ibt_page_sizes_t page_szs)3067 sol_uverbs_ibt_to_of_page_sz(ibt_page_sizes_t page_szs)
3068 {
3069 
3070 	uint64_t of_page_sz = 0;
3071 
3072 	if (page_szs && IBT_PAGE_4K)
3073 		of_page_sz |= 1LL << 12;
3074 
3075 	if (page_szs && IBT_PAGE_8K)
3076 		of_page_sz |= 1LL << 13;
3077 
3078 	if (page_szs && IBT_PAGE_16K)
3079 		of_page_sz |= 1LL << 14;
3080 
3081 	if (page_szs && IBT_PAGE_32K)
3082 		of_page_sz |= 1LL << 15;
3083 
3084 	if (page_szs && IBT_PAGE_64K)
3085 		of_page_sz |= 1LL << 16;
3086 
3087 	if (page_szs && IBT_PAGE_128K)
3088 		of_page_sz |= 1LL << 17;
3089 
3090 	if (page_szs && IBT_PAGE_256K)
3091 		of_page_sz |= 1LL << 18;
3092 
3093 	if (page_szs && IBT_PAGE_512K)
3094 		of_page_sz |= 1LL << 19;
3095 
3096 	if (page_szs && IBT_PAGE_1M)
3097 		of_page_sz |= 1LL << 20;
3098 
3099 	if (page_szs && IBT_PAGE_2M)
3100 		of_page_sz |= 1LL << 21;
3101 
3102 	if (page_szs && IBT_PAGE_4M)
3103 		of_page_sz |= 1LL << 22;
3104 
3105 	if (page_szs && IBT_PAGE_8M)
3106 		of_page_sz |= 1LL << 23;
3107 
3108 	if (page_szs && IBT_PAGE_16M)
3109 		of_page_sz |= 1LL << 24;
3110 
3111 	if (page_szs && IBT_PAGE_32M)
3112 		of_page_sz |= 1LL << 25;
3113 
3114 	if (page_szs && IBT_PAGE_64M)
3115 		of_page_sz |= 1LL << 26;
3116 
3117 	if (page_szs && IBT_PAGE_128M)
3118 		of_page_sz |= 1LL << 27;
3119 
3120 	if (page_szs && IBT_PAGE_256M)
3121 		of_page_sz |= 1LL << 28;
3122 
3123 	if (page_szs && IBT_PAGE_512M)
3124 		of_page_sz |= 1LL << 29;
3125 
3126 	if (page_szs && IBT_PAGE_1G)
3127 		of_page_sz |= 1LL << 30;
3128 
3129 	if (page_szs && IBT_PAGE_2G)
3130 		of_page_sz |= 1LL << 31;
3131 
3132 	if (page_szs && IBT_PAGE_4G)
3133 		of_page_sz |= 1LL << 32;
3134 
3135 	if (page_szs && IBT_PAGE_8G)
3136 		of_page_sz |= 1LL << 33;
3137 
3138 	if (page_szs && IBT_PAGE_16G)
3139 		of_page_sz |= 1LL << 34;
3140 
3141 	return (of_page_sz);
3142 }
3143