xref: /titanic_44/usr/src/uts/common/io/ib/clients/of/sol_umad/sol_umad.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 
27 /*
28  * sol_umad.c
29  *
30  * ofuv user MAD kernel agent module
31  *
32  * Enables functionality of the OFED 1.3 Linux based MAD application code.
33  */
34 
35 #include <sys/open.h>
36 #include <sys/stat.h>
37 #include <sys/file.h>
38 #include <sys/conf.h>
39 #include <sys/modctl.h>
40 #include <sys/sysmacros.h>
41 #include <sys/ib/ibtl/ibti.h>
42 #include <sys/ib/mgt/ibmf/ibmf.h>
43 #include <sys/ib/mgt/ibmf/ibmf_rmpp.h>
44 
45 #include <sys/types.h>
46 #include <sys/ib/clients/of/ofed_kernel.h>
47 #include <sys/ib/clients/of/sol_ofs/sol_ofs_common.h>
48 #include <sys/ib/clients/of/rdma/ib_user_mad.h>
49 #include <sys/ib/clients/of/sol_umad/sol_umad.h>
50 #include <sys/policy.h>
51 #include <sys/priv_const.h>	/* sys/policy.h should include this, but... */
52 
53 
54 #define	MAX_NAME_LEN	32
55 
56 #if defined(DEBUG)
57 static char *sol_umad_dbg_str = "sol_umad";
58 #endif
59 
60 /* Local definitions */
61 static void *umad_statep;
62 
63 static struct cb_ops umad_cb_ops = {
64 	.cb_open			= umad_open,
65 	.cb_close			= umad_close,
66 	.cb_strategy			= nodev,
67 	.cb_print			= nodev,
68 	.cb_dump			= nodev,
69 	.cb_read			= umad_read,
70 	.cb_write			= umad_write,
71 	.cb_ioctl			= umad_ioctl,
72 	.cb_devmap			= nodev,
73 	.cb_mmap			= nodev,
74 	.cb_segmap			= nodev,
75 	.cb_chpoll			= umad_poll,
76 	.cb_prop_op			= umad_prop_op,
77 	.cb_str				= NULL,
78 	.cb_flag			= D_NEW | D_MP,
79 	.cb_rev				= CB_REV,
80 	.cb_aread			= nodev,
81 	.cb_awrite			= nodev
82 };
83 
84 static struct dev_ops umad_dev_ops = {
85 	.devo_rev			= DEVO_REV,
86 	.devo_refcnt			= 0,
87 	.devo_getinfo			= umad_getinfo,
88 	.devo_identify			= nulldev,
89 	.devo_probe			= nulldev,
90 	.devo_attach			= umad_attach,
91 	.devo_detach			= umad_detach,
92 	.devo_reset			= nodev,
93 	.devo_cb_ops			= &umad_cb_ops,
94 	.devo_bus_ops			= NULL,
95 	.devo_power			= nodev,
96 	.devo_quiesce			= ddi_quiesce_not_needed
97 };
98 
99 static struct modldrv umad_modldrv = {
100 	.drv_modops			= &mod_driverops,
101 	.drv_linkinfo			= "Solaris IB user MAD kernel driver",
102 	.drv_dev_ops			= &umad_dev_ops
103 };
104 
105 static struct modlinkage modlinkage = {
106 	.ml_rev				= MODREV_1,
107 	.ml_linkage = {
108 		[0]			= &umad_modldrv,
109 		[1]			= NULL,
110 	}
111 };
112 
113 static ibt_clnt_modinfo_t ibt_clnt_modinfo = {
114 	.mi_ibt_version			= IBTI_V_CURR,
115 	.mi_clnt_class			= IBT_USER,
116 	.mi_async_handler		= umad_async_handler,
117 	.mi_reserved			= NULL,
118 	.mi_clnt_name			= "sol_umad"
119 };
120 
121 #define	MAX_MAD_TO_IBMF_MAPPINGS	4 /* Max of 4 MADs to 1 IBMF */
122 const struct ibmf_class_to_mad_type {
123 	enum _ibmf_client_type_t	ibmf_class;
124 	uint8_t				mad_types[MAX_MAD_TO_IBMF_MAPPINGS];
125 } ibmf_class_to_mad_types[] = {
126 	{SUBN_MANAGER,
127 	    {MAD_MGMT_CLASS_SUBN_LID_ROUTED,
128 	    MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE,
129 	    0}},
130 	{0,
131 	{0}}
132 };
133 
134 const enum _ibmf_client_type_t umad_type_to_ibmf_class[256] = {
135 	0,				/* 0x00 Reserved */
136 	SUBN_MANAGER,			/* 0x01 CLASS_SUBN_LID_ROUTED */
137 	0,				/* 0x02 Reserved */
138 	SUBN_ADM_AGENT,			/* 0x03 CLASS_SUBN_ADM */
139 	PERF_MANAGER,			/* 0x04 CLASS_PERF_MGMT */
140 	BM_AGENT, 			/* 0x05 CLASS_BM */
141 	DEV_MGT_AGENT,			/* 0x06 CLASS_DEVICE_MGMT */
142 	COMM_MGT_MANAGER_AGENT,		/* 0x07 CLASS_CM */
143 	SNMP_MANAGER_AGENT,		/* 0x08 CLASS_SNMP */
144 
145 	VENDOR_09_MANAGER_AGENT,	/* 0x09 */
146 	VENDOR_0A_MANAGER_AGENT,	/* 0x0A */
147 	VENDOR_0B_MANAGER_AGENT,	/* 0x0B */
148 	VENDOR_0C_MANAGER_AGENT,	/* 0x0C */
149 	VENDOR_0D_MANAGER_AGENT,	/* 0x0D */
150 	VENDOR_0E_MANAGER_AGENT,	/* 0x0E */
151 	VENDOR_0F_MANAGER_AGENT,	/* 0x0F */
152 
153 	APPLICATION_10_MANAGER_AGENT,	/* 0x10 */
154 	APPLICATION_11_MANAGER_AGENT,	/* 0x11 */
155 	APPLICATION_12_MANAGER_AGENT,	/* 0x12 */
156 	APPLICATION_13_MANAGER_AGENT,	/* 0x13 */
157 	APPLICATION_14_MANAGER_AGENT,	/* 0x14 */
158 	APPLICATION_15_MANAGER_AGENT,	/* 0x15 */
159 	APPLICATION_16_MANAGER_AGENT,	/* 0x16 */
160 	APPLICATION_17_MANAGER_AGENT,	/* 0x17 */
161 	APPLICATION_18_MANAGER_AGENT,	/* 0x18 */
162 	APPLICATION_19_MANAGER_AGENT,	/* 0x19 */
163 	APPLICATION_1A_MANAGER_AGENT,	/* 0x1A */
164 	APPLICATION_1B_MANAGER_AGENT,	/* 0x1B */
165 	APPLICATION_1C_MANAGER_AGENT,	/* 0x1C */
166 	APPLICATION_1D_MANAGER_AGENT,	/* 0x1D */
167 	APPLICATION_1E_MANAGER_AGENT,	/* 0x1E */
168 	APPLICATION_1F_MANAGER_AGENT,	/* 0x1F */
169 	APPLICATION_20_MANAGER_AGENT,	/* 0x20 */
170 	APPLICATION_21_MANAGER_AGENT,	/* 0x21 */
171 	APPLICATION_22_MANAGER_AGENT,	/* 0x22 */
172 	APPLICATION_23_MANAGER_AGENT,	/* 0x23 */
173 	APPLICATION_24_MANAGER_AGENT,	/* 0x24 */
174 	APPLICATION_25_MANAGER_AGENT,	/* 0x25 */
175 	APPLICATION_26_MANAGER_AGENT,	/* 0x26 */
176 	APPLICATION_27_MANAGER_AGENT,	/* 0x27 */
177 	APPLICATION_28_MANAGER_AGENT,	/* 0x28 */
178 	APPLICATION_29_MANAGER_AGENT,	/* 0x29 */
179 	APPLICATION_2A_MANAGER_AGENT,	/* 0x2A */
180 	APPLICATION_2B_MANAGER_AGENT,	/* 0x2B */
181 	APPLICATION_2C_MANAGER_AGENT,	/* 0x2C */
182 	APPLICATION_2D_MANAGER_AGENT,	/* 0x2D */
183 	APPLICATION_2E_MANAGER_AGENT,	/* 0x2E */
184 	APPLICATION_2F_MANAGER_AGENT,	/* 0x2F */
185 
186 	VENDOR_30_MANAGER_AGENT,	/* 0x30 */
187 	VENDOR_31_MANAGER_AGENT,	/* 0x31 */
188 	VENDOR_32_MANAGER_AGENT,	/* 0x32 */
189 	VENDOR_33_MANAGER_AGENT,	/* 0x33 */
190 	VENDOR_34_MANAGER_AGENT,	/* 0x34 */
191 	VENDOR_35_MANAGER_AGENT,	/* 0x35 */
192 	VENDOR_36_MANAGER_AGENT,	/* 0x36 */
193 	VENDOR_37_MANAGER_AGENT,	/* 0x37 */
194 	VENDOR_38_MANAGER_AGENT,	/* 0x38 */
195 	VENDOR_39_MANAGER_AGENT,	/* 0x39 */
196 	VENDOR_3A_MANAGER_AGENT,	/* 0x3A */
197 	VENDOR_3B_MANAGER_AGENT,	/* 0x3B */
198 	VENDOR_3C_MANAGER_AGENT,	/* 0x3C */
199 	VENDOR_3D_MANAGER_AGENT,	/* 0x3D */
200 	VENDOR_3E_MANAGER_AGENT,	/* 0x3E */
201 	VENDOR_3F_MANAGER_AGENT,	/* 0x3F */
202 	VENDOR_40_MANAGER_AGENT,
203 	VENDOR_41_MANAGER_AGENT,
204 	VENDOR_42_MANAGER_AGENT,
205 	VENDOR_43_MANAGER_AGENT,
206 	VENDOR_44_MANAGER_AGENT,
207 	VENDOR_45_MANAGER_AGENT,
208 	VENDOR_46_MANAGER_AGENT,
209 	VENDOR_47_MANAGER_AGENT,
210 	VENDOR_48_MANAGER_AGENT,
211 	VENDOR_49_MANAGER_AGENT,
212 	VENDOR_4A_MANAGER_AGENT,
213 	VENDOR_4B_MANAGER_AGENT,
214 	VENDOR_4C_MANAGER_AGENT,
215 	VENDOR_4D_MANAGER_AGENT,
216 	VENDOR_4E_MANAGER_AGENT,
217 	VENDOR_4F_MANAGER_AGENT,
218 
219 	0,			/* 0x50 Reserved */
220 	0,			/* 0x51 Reserved */
221 	0,			/* 0x52 Reserved */
222 	0,			/* 0x53 Reserved */
223 	0,			/* 0x54 Reserved */
224 	0,			/* 0x55 Reserved */
225 	0,			/* 0x56 Reserved */
226 	0,			/* 0x57 Reserved */
227 	0,			/* 0x58 Reserved */
228 	0,			/* 0x59 Reserved */
229 	0,			/* 0x5A Reserved */
230 	0,			/* 0x5B Reserved */
231 	0,			/* 0x5C Reserved */
232 	0,			/* 0x5D Reserved */
233 	0,			/* 0x5E Reserved */
234 	0,			/* 0x5F Reserved */
235 	0,			/* 0x60 Reserved */
236 	0,			/* 0x61 Reserved */
237 	0,			/* 0x62 Reserved */
238 	0,			/* 0x63 Reserved */
239 	0,			/* 0x64 Reserved */
240 	0,			/* 0x65 Reserved */
241 	0,			/* 0x66 Reserved */
242 	0,			/* 0x67 Reserved */
243 	0,			/* 0x68 Reserved */
244 	0,			/* 0x69 Reserved */
245 	0,			/* 0x6A Reserved */
246 	0,			/* 0x6B Reserved */
247 	0,			/* 0x6C Reserved */
248 	0,			/* 0x6D Reserved */
249 	0,			/* 0x6E Reserved */
250 	0,			/* 0x6F Reserved */
251 	0,			/* 0x70 Reserved */
252 	0,			/* 0x71 Reserved */
253 	0,			/* 0x72 Reserved */
254 	0,			/* 0x73 Reserved */
255 	0,			/* 0x74 Reserved */
256 	0,			/* 0x75 Reserved */
257 	0,			/* 0x76 Reserved */
258 	0,			/* 0x77 Reserved */
259 	0,			/* 0x78 Reserved */
260 	0,			/* 0x79 Reserved */
261 	0,			/* 0x7A Reserved */
262 	0,			/* 0x7B Reserved */
263 	0,			/* 0x7C Reserved */
264 	0,			/* 0x7D Reserved */
265 	0,			/* 0x7E Reserved */
266 	0,			/* 0x7F Reserved */
267 	0,			/* 0x80 Reserved */
268 
269 	SUBN_MANAGER,		/* 0x81 CLASS_SUBN_DIRECT_ROUTE */
270 
271 	0,			/* 0x82 Reserved */
272 	0,			/* 0x82 Reserved */
273 	0,			/* 0x84 Reserved */
274 	0,			/* 0x85 Reserved */
275 	0,			/* 0x86 Reserved */
276 	0,			/* 0x87 Reserved */
277 	0,			/* 0x88 Reserved */
278 	0,			/* 0x89 Reserved */
279 	0,			/* 0x8A Reserved */
280 	0,			/* 0x8B Reserved */
281 	0,			/* 0x8C Reserved */
282 	0,			/* 0x8D Reserved */
283 	0,			/* 0x8E Reserved */
284 	0,			/* 0x8f Reserved */
285 	0,			/* 0x90 Reserved */
286 	0,			/* 0x91 Reserved */
287 	0,			/* 0x92 Reserved */
288 	0,			/* 0x93 Reserved */
289 	0,			/* 0x94 Reserved */
290 	0,			/* 0x95 Reserved */
291 	0,			/* 0x96 Reserved */
292 	0,			/* 0x97 Reserved */
293 	0,			/* 0x98 Reserved */
294 	0,			/* 0x99 Reserved */
295 	0,			/* 0x9A Reserved */
296 	0,			/* 0x9B Reserved */
297 	0,			/* 0x9C Reserved */
298 	0,			/* 0x9D Reserved */
299 	0,			/* 0x9E Reserved */
300 	0,			/* 0x9F Reserved */
301 	0,			/* 0xA0 Reserved */
302 	0,			/* 0xA1 Reserved */
303 	0,			/* 0xA2 Reserved */
304 	0,			/* 0xA3 Reserved */
305 	0,			/* 0xA4 Reserved */
306 	0,			/* 0xA5 Reserved */
307 	0,			/* 0xA6 Reserved */
308 	0,			/* 0xA7 Reserved */
309 	0,			/* 0xA8 Reserved */
310 	0,			/* 0xA9 Reserved */
311 	0,			/* 0xAA Reserved */
312 	0,			/* 0xAB Reserved */
313 	0,			/* 0xAC Reserved */
314 	0,			/* 0xAD Reserved */
315 	0,			/* 0xAE Reserved */
316 	0,			/* 0xAF Reserved */
317 	0,			/* 0xB0 Reserved */
318 	0,			/* 0xB1 Reserved */
319 	0,			/* 0xB2 Reserved */
320 	0,			/* 0xB3 Reserved */
321 	0,			/* 0xB4 Reserved */
322 	0,			/* 0xB5 Reserved */
323 	0,			/* 0xB6 Reserved */
324 	0,			/* 0xB7 Reserved */
325 	0,			/* 0xB8 Reserved */
326 	0,			/* 0xB9 Reserved */
327 	0,			/* 0xBA Reserved */
328 	0,			/* 0xBB Reserved */
329 	0,			/* 0xBC Reserved */
330 	0,			/* 0xBD Reserved */
331 	0,			/* 0xBE Reserved */
332 	0,			/* 0xBF Reserved */
333 	0,			/* 0xC0 Reserved */
334 	0,			/* 0xC1 Reserved */
335 	0,			/* 0xC2 Reserved */
336 	0,			/* 0xC3 Reserved */
337 	0,			/* 0xC4 Reserved */
338 	0,			/* 0xC5 Reserved */
339 	0,			/* 0xC6 Reserved */
340 	0,			/* 0xC7 Reserved */
341 	0,			/* 0xC8 Reserved */
342 	0,			/* 0xC9 Reserved */
343 	0,			/* 0xCA Reserved */
344 	0,			/* 0xCB Reserved */
345 	0,			/* 0xCC Reserved */
346 	0,			/* 0xCD Reserved */
347 	0,			/* 0xCE Reserved */
348 	0,			/* 0xCF Reserved */
349 	0,			/* 0xD0 Reserved */
350 	0,			/* 0xD1 Reserved */
351 	0,			/* 0xD2 Reserved */
352 	0,			/* 0xD3 Reserved */
353 	0,			/* 0xD4 Reserved */
354 	0,			/* 0xD5 Reserved */
355 	0,			/* 0xD6 Reserved */
356 	0,			/* 0xD7 Reserved */
357 	0,			/* 0xD8 Reserved */
358 	0,			/* 0xD9 Reserved */
359 	0,			/* 0xDA Reserved */
360 	0,			/* 0xDB Reserved */
361 	0,			/* 0xDC Reserved */
362 	0,			/* 0xDD Reserved */
363 	0,			/* 0xDE Reserved */
364 	0,			/* 0xDF Reserved */
365 	0,			/* 0xE0 Reserved */
366 	0,			/* 0xE1 Reserved */
367 	0,			/* 0xE2 Reserved */
368 	0,			/* 0xE3 Reserved */
369 	0,			/* 0xE4 Reserved */
370 	0,			/* 0xE5 Reserved */
371 	0,			/* 0xE6 Reserved */
372 	0,			/* 0xE7 Reserved */
373 	0,			/* 0xE8 Reserved */
374 	0,			/* 0xE9 Reserved */
375 	0,			/* 0xEA Reserved */
376 	0,			/* 0xEB Reserved */
377 	0,			/* 0xEC Reserved */
378 	0,			/* 0xED Reserved */
379 	0,			/* 0xEE Reserved */
380 	0,			/* 0xEF Reserved */
381 	0,			/* 0xF0 Reserved */
382 	0,			/* 0xF1 Reserved */
383 	0,			/* 0xF2 Reserved */
384 	0,			/* 0xF3 Reserved */
385 	0,			/* 0xF4 Reserved */
386 	0,			/* 0xF5 Reserved */
387 	0,			/* 0xF6 Reserved */
388 	0,			/* 0xF7 Reserved */
389 	0,			/* 0xF8 Reserved */
390 	0,			/* 0xF9 Reserved */
391 	0,			/* 0xFA Reserved */
392 	0,			/* 0xFB Reserved */
393 	0,			/* 0xFC Reserved */
394 	0,			/* 0xFD Reserved */
395 	0,			/* 0xFE Reserved */
396 	0,			/* 0xFF Reserved */
397 };
398 
399 /*
400  * Function:
401  *	umad_init_port_info
402  * Input:
403  *	info		- driver info
404  *	hca		- hca info
405  * Output:
406  *	port		- port info
407  * Returns:
408  *	None
409  * Called by:
410  *	umad_init_hca_info
411  * Description:
412  *      - Associates an hca to a port.
413  *	- Initializes user context list for the port passed in
414  *	- Initializes mutex to protect the user context list
415  */
416 static void
umad_init_port_info(const umad_hca_info_t * hca,umad_port_info_t * port)417 umad_init_port_info(const umad_hca_info_t *hca, umad_port_info_t *port)
418 {
419 	port->port_hca = hca;
420 	llist_head_init(&port->port_ibmf_regs, NULL);
421 	mutex_init(&port->port_lock, NULL, MUTEX_DRIVER, NULL);
422 }
423 
424 /*
425  * Function:
426  *	umad_release_hca_info
427  * Input:
428  *	hca		- hca info
429  * Output:
430  * Returns:
431  *	None
432  * Called by:
433  *	- umad_init_hca_info in case of error
434  *	- umad_init_driver_info in case of error
435  *	- umad_context_destroyed in normal case
436  * Description:
437  *      - For every port associated with this hca destory the mutex assicated
438  *        with the port and relese port info structure.
439  *	- Closes hca handle and resets the GUID
440  */
441 static void
umad_release_hca_info(umad_hca_info_t * hca)442 umad_release_hca_info(umad_hca_info_t *hca)
443 {
444 	unsigned int j;
445 	umad_port_info_t *port;
446 #if defined(DEBUG)
447 	ibt_status_t rc;
448 #endif
449 
450 	if (hca->hca_ports) {
451 		for (j = 0; j < hca->hca_nports; j++) {
452 			port = &(hca->hca_ports[j]);
453 			if (port->port_num)
454 				mutex_destroy(&port->port_lock);
455 		}
456 		kmem_free(hca->hca_ports, hca->hca_nports *
457 		    sizeof (umad_port_info_t));
458 		hca->hca_ports = NULL;
459 	}
460 	if (hca->hca_handle) {
461 #if defined(DEBUG)
462 		rc = ibt_close_hca(hca->hca_handle);
463 		if (rc != IBT_SUCCESS) {
464 			SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
465 			    "umad_release_hca: ibt_close_hca() returned %d\n",
466 			    rc);
467 		}
468 #else
469 		(void) ibt_close_hca(hca->hca_handle);
470 #endif
471 		hca->hca_handle = 0;
472 	}
473 
474 	hca->hca_guid = 0;
475 }
476 
477 /*
478  * Function:
479  *	umad_init_hca_info
480  * Input:
481  *	info 	pointer to umad info instructure
482  * Output:
483  * 	hca	handle associated with this hca
484  * Returns:
485  *	IBT_SUCCESS
486  *	IBT_HCA_IN_USE
487  *	IBT_HCA_INVALID
488  *	IBT_INVALID_PARAM
489  * 	IBT_HCA_INVALID
490  * Called by:
491  *	- umad_init_driver_info in case of error
492  * Description:
493  *	- It calls ibt_open_hca to get handle associated wit this hca
494  *	- Determines how many port this hca has by calling ibt_query_hca
495  *	- Allocates space for each port associated with this hca.
496  *	- For every port it calls umad_init_port_info with the hca port
497  *        structure.
498  *	- It assigns port # index starting at 1 (1-N, zero is reserved, means
499  *	  it does not exist).
500  */
501 static int
umad_init_hca_info(const umad_info_t * info,umad_hca_info_t * hca)502 umad_init_hca_info(const umad_info_t *info, umad_hca_info_t *hca)
503 {
504 	int rc;
505 	unsigned int j;
506 	umad_port_info_t *port;
507 
508 	rc = ibt_open_hca(info->info_clnt_hdl, hca->hca_guid, &hca->hca_handle);
509 	if (rc != IBT_SUCCESS)
510 		goto error;
511 
512 	rc = ibt_query_hca(hca->hca_handle, &hca->hca_attr);
513 	if (rc != IBT_SUCCESS)
514 		goto error;
515 
516 	hca->hca_nports = hca->hca_attr.hca_nports;
517 
518 	hca->hca_ports =
519 	    kmem_zalloc(sizeof (umad_port_info_t) * hca->hca_nports, KM_SLEEP);
520 
521 	/* Initialize ports structures. */
522 	for (j = 0; j < hca->hca_nports; j++) {
523 		port = &hca->hca_ports[j];
524 		umad_init_port_info(hca, port);
525 
526 		/*
527 		 * Note: A port number different than 0 means the port has been
528 		 * initialized.
529 		 */
530 		port->port_num = j + 1;
531 	}
532 
533 error:
534 	if (rc)
535 		umad_release_hca_info(hca);
536 
537 	return (rc);
538 }
539 
540 /*
541  * Function:
542  *	umad_init_driver_info
543  * Output:
544  *	info		- driver info
545  * Returns:
546  * 	IBT_SUCCESS
547  *	IBT_INVALID_PARAM
548  *	IBT_HCA_IN_USE
549  *	IBT_HCA_INVALID
550  *	IBT_INVALID_PARAM
551  * Called by:
552  *	umad_attach
553  * Description:
554  *	- Registers sol_umad instance with IBTF
555  *      - Calls ibt_get_hca_list to get hca count
556  *	- Allocates each hca and associate it with umad_info structure
557  *	- For every hca it assign GUID which was returned by ibt_get_hca_list
558  *        then calls umad_init_hca_info .
559  *	- Error case undone what was done, which calls umad_release_hca_info
560  */
561 static ibt_status_t
umad_init_driver_info(umad_info_t * info)562 umad_init_driver_info(umad_info_t *info)
563 {
564 	ibt_status_t		rc;
565 #if defined(DEBUG)
566 	ibt_status_t		rc2;
567 #endif
568 	unsigned int i;
569 	uint32_t		hca_count;
570 	ib_guid_t		*hca_guids = NULL;
571 	umad_hca_info_t		*hca;
572 
573 	info->info_hca_count 	= 0;
574 	info->info_clnt_hdl	= NULL;
575 	info->info_hcas		= NULL;
576 
577 	rc = ibt_attach(&ibt_clnt_modinfo, info->info_dip, info,
578 	    &info->info_clnt_hdl);
579 
580 	if (rc != IBT_SUCCESS)
581 		goto err1;
582 
583 	hca_count = info->info_hca_count = ibt_get_hca_list(&hca_guids);
584 
585 	if (hca_count == 0) {
586 		rc = IBT_HCA_INVALID;
587 		goto err2;
588 	}
589 
590 	info->info_hcas = kmem_zalloc(sizeof (umad_hca_info_t) * hca_count,
591 	    KM_SLEEP);
592 
593 	for (i = 0; i < hca_count; i++) {
594 		hca = &info->info_hcas[i];
595 
596 		/* Note: A non zero guid means the hca has been allocated. */
597 		hca->hca_guid = hca_guids[i];
598 
599 		rc = umad_init_hca_info(info, hca);
600 
601 		if (rc)
602 			goto err3;
603 	}
604 
605 	ibt_free_hca_list(hca_guids, hca_count);
606 
607 	return (0);
608 
609 err3:
610 	for (i = 0; i < info->info_hca_count; i++) {
611 		hca = &info->info_hcas[i];
612 
613 		if (hca->hca_guid)
614 			umad_release_hca_info(hca);
615 	}
616 	kmem_free(info->info_hcas,
617 	    info->info_hca_count * sizeof (umad_hca_info_t));
618 	info->info_hcas = NULL;
619 
620 	if (hca_guids)
621 		ibt_free_hca_list(hca_guids, hca_count);
622 err2:
623 
624 #if defined(DEBUG)
625 	rc2 = ibt_detach(info->info_clnt_hdl);
626 	if (rc2 != IBT_SUCCESS) {
627 		SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
628 		    "umad_init_driver_info: ibt_detach failed: %d\n", rc2);
629 	}
630 #else
631 	(void) ibt_detach(info->info_clnt_hdl);
632 #endif
633 	info->info_clnt_hdl = NULL;
634 
635 err1:
636 	return (rc);
637 }
638 
639 /*
640  * Function:
641  *	umad_context_destroy
642  * Input:
643  *	dip		- device info
644  *	info		- driver info
645  * Output:
646  *	None
647  * Returns:
648  *	None
649  * Called by:
650  *	umad_attach
651  *	umad_detach
652  * Description:
653  *	frees driver info resources
654  */
655 static void
umad_context_destroy(dev_info_t * dip,umad_info_t * info)656 umad_context_destroy(dev_info_t *dip, umad_info_t *info)
657 {
658 	unsigned int i;
659 	unsigned int j;
660 	size_t n;
661 
662 	for (i = 0; i < info->info_hca_count; i++) {
663 		umad_hca_info_t	*hca = &info->info_hcas[i];
664 
665 		if (! hca->hca_guid)
666 			continue;
667 
668 		for (j = 0; j < hca->hca_nports; j++) {
669 			umad_port_info_t *port = &hca->hca_ports[j];
670 			char name[MAX_NAME_LEN];
671 
672 			if (port->port_has_umad_minor_node) {
673 				n = snprintf(name, sizeof (name),
674 				    "umad%d", port->port_minor_name);
675 #if defined(DEBUG)
676 				if (n > sizeof (name)) {
677 					SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
678 					    "umad_context_destroy:"
679 					    " minor name \"%s\": is longer than"
680 					    " %d characters!\n",
681 					    name, MAX_NAME_LEN);
682 				}
683 #endif
684 
685 				ddi_remove_minor_node(dip, name);
686 			}
687 
688 			if (port->port_has_issm_minor_node) {
689 				n = snprintf(name, sizeof (name),
690 				    "issm%d", port->port_minor_name);
691 #if defined(DEBUG)
692 				if (n > sizeof (name)) {
693 					SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
694 					    "umad_context_destroy:"
695 					    " minor name \"%s\" is longer than"
696 					    " %d characters!\n",
697 					    name, MAX_NAME_LEN);
698 				}
699 #endif
700 				ddi_remove_minor_node(dip, name);
701 			}
702 		}
703 
704 		umad_release_hca_info(hca);
705 	}
706 
707 	if (info->info_hcas) {
708 		kmem_free(info->info_hcas,
709 		    info->info_hca_count * sizeof (umad_hca_info_t));
710 		info->info_hca_count = 0;
711 		info->info_hcas = NULL;
712 	}
713 
714 	if (info->info_clnt_hdl != NULL) {
715 		(void) ibt_detach(info->info_clnt_hdl);
716 		info->info_clnt_hdl = NULL;
717 	}
718 
719 	mutex_destroy(&info->info_mutex);
720 }
721 
722 /*
723  * Function:
724  *	_init
725  * Input:
726  *	None
727  * Output:
728  *	None
729  * Returns:
730  *	status
731  * Called by:
732  *	Framework
733  * Description:
734  *	driver initialization function
735  *	inits debug tracing, river info and calls mod_install
736  */
737 int
_init(void)738 _init(void)
739 {
740 	int rc;
741 
742 	rc = ddi_soft_state_init(&umad_statep, sizeof (umad_info_t), 0);
743 
744 	if (rc != 0)
745 		goto err;
746 
747 	rc = mod_install(&modlinkage);
748 
749 	if (rc != 0)
750 		ddi_soft_state_fini(&umad_statep);
751 
752 err:
753 	return (rc);
754 }
755 
756 /*
757  * Function:
758  *	_info
759  * Input:
760  *	None
761  * Output:
762  *	modinfop	Module information
763  * Returns:
764  *	status
765  * Called by:
766  *	Framework
767  * Description:
768  *	Provides module information
769  */
770 int
_info(struct modinfo * modinfop)771 _info(struct modinfo *modinfop)
772 {
773 	int rc;
774 
775 	rc = mod_info(&modlinkage, modinfop);
776 
777 	return (rc);
778 }
779 
780 /*
781  * Function:
782  *	_fini
783  * Input:
784  *	None
785  * Output:
786  *	None
787  * Returns:
788  *	status
789  * Called by:
790  *	Framework
791  * Description:
792  *	Cleans up upon module unloading
793  */
794 int
_fini(void)795 _fini(void)
796 {
797 	int rc;
798 
799 	if ((rc = mod_remove(&modlinkage)) == 0)
800 		ddi_soft_state_fini(&umad_statep);
801 
802 	return (rc);
803 }
804 
805 /*
806  * Function:
807  *	umad_attach
808  * Input:
809  *	dip		device info
810  *	cmd		DDI_ATTACH all others are invalid
811  * Output:
812  *	None
813  * Returns:
814  *	DDI_SUCCESS or DDI_FAILURE
815  * Called by:
816  *	Framwork
817  * Description:
818  *	Device attach routine
819  */
820 static int
umad_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)821 umad_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
822 {
823 	int			rc;
824 	unsigned int i;
825 	unsigned int j;
826 	umad_hca_info_t		hca;
827 	umad_info_t		*info;
828 	char			name[MAX_NAME_LEN];
829 	unsigned int minor_name;
830 
831 	switch (cmd) {
832 	case DDI_ATTACH:
833 		if (ddi_soft_state_zalloc(umad_statep, UMAD_INSTANCE)
834 		    != DDI_SUCCESS)
835 			goto err1;
836 
837 		info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
838 		if (info == NULL)
839 			goto err2;
840 
841 		info->info_dip = dip;
842 		mutex_init(&info->info_mutex, NULL, MUTEX_DRIVER, NULL);
843 
844 		/* initialize our data and per HCA info */
845 		rc = umad_init_driver_info(info);
846 
847 		if (rc != 0)
848 			goto err3;
849 
850 		rc = ddi_prop_update_int(DDI_DEV_T_NONE, dip,
851 		    "abi_version", IB_USER_MAD_ABI_VERSION);
852 
853 		if (rc != 0)
854 			goto err3;
855 
856 		/*
857 		 * create a minor node for each node/port pair
858 		 * device names are consistent with OFA
859 		 * conventions, e.g. umad0 for port 1 on the first HCA.
860 		 */
861 		minor_name = 0;
862 		for (i = 0; i < info->info_hca_count; i++) {
863 			hca = info->info_hcas[i];
864 			for (j = 0; j < hca.hca_nports; j++) {
865 				size_t n;
866 				dev_t minor_dev;
867 
868 				umad_port_info_t *port = &hca.hca_ports[j];
869 
870 				port->port_minor_name = minor_name;
871 
872 				n = snprintf(name, sizeof (name), "umad%d",
873 				    minor_name);
874 #if defined(DEBUG)
875 				if (n > sizeof (name)) {
876 					SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
877 					    "umad_attach: "
878 					    "name \"%s\" longer than %d!\n",
879 					    name, MAX_NAME_LEN);
880 				}
881 #endif
882 				rc = ddi_create_minor_node(dip, name, S_IFCHR,
883 				    GET_UMAD_MINOR(i, j), DDI_PSEUDO, 0);
884 				if (rc != DDI_SUCCESS)
885 					goto err3;
886 
887 				minor_dev = makedevice(ddi_driver_major(dip),
888 				    GET_UMAD_MINOR(i, j));
889 				rc = ddi_prop_update_int(minor_dev, dip,
890 				    "vendor-id", hca.hca_attr.hca_vendor_id);
891 				if (rc != DDI_SUCCESS)
892 					goto err3;
893 				rc = ddi_prop_update_int(minor_dev, dip,
894 				    "device-id", hca.hca_attr.hca_device_id);
895 				if (rc != DDI_SUCCESS)
896 					goto err3;
897 				rc = ddi_prop_update_int(minor_dev, dip,
898 				    "hca-instance", i);
899 				if (rc != DDI_SUCCESS)
900 					goto err3;
901 				rc = ddi_prop_update_int(minor_dev, dip,
902 				    "port", j + 1);
903 				if (rc != DDI_SUCCESS)
904 					goto err3;
905 
906 				port->port_has_umad_minor_node = 1;
907 
908 				n = snprintf(name, sizeof (name), "issm%d",
909 				    minor_name);
910 #if defined(DEBUG)
911 				if (n > sizeof (name)) {
912 					SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
913 					    "umad_attach: "
914 					    "name \"%s\" longer than %d!\n",
915 					    name, MAX_NAME_LEN);
916 				}
917 #endif
918 				rc = ddi_create_minor_node(dip, name, S_IFCHR,
919 				    GET_ISSM_MINOR(i, j), DDI_PSEUDO, 0);
920 
921 				if (rc != DDI_SUCCESS)
922 					goto err3;
923 
924 				minor_dev = makedevice(ddi_driver_major(dip),
925 				    GET_ISSM_MINOR(i, j));
926 				rc = ddi_prop_update_int(minor_dev, dip,
927 				    "vendor-id", hca.hca_attr.hca_vendor_id);
928 				if (rc != DDI_SUCCESS)
929 					goto err3;
930 				rc = ddi_prop_update_int(minor_dev, dip,
931 				    "device-id", hca.hca_attr.hca_device_id);
932 				if (rc != DDI_SUCCESS)
933 					goto err3;
934 				rc = ddi_prop_update_int(minor_dev, dip,
935 				    "hca-instance", i);
936 				if (rc != DDI_SUCCESS)
937 					goto err3;
938 				rc = ddi_prop_update_int(minor_dev, dip,
939 				    "port", j + 1);
940 				if (rc != DDI_SUCCESS)
941 					goto err3;
942 
943 				port->port_has_issm_minor_node = 1;
944 				minor_name++;
945 			}
946 		}
947 
948 		ddi_report_dev(dip);
949 		break;
950 
951 	default:
952 		goto err1;
953 	}
954 
955 	rc = DDI_SUCCESS;
956 
957 	return (rc);
958 
959 err3:
960 	umad_context_destroy(dip, info);
961 err2:
962 	ddi_soft_state_free(umad_statep, UMAD_INSTANCE);
963 err1:
964 	rc = DDI_FAILURE;
965 
966 	return (rc);
967 }
968 
969 /*
970  * Function:
971  *	umad_detach
972  * Input:
973  *	dip		Device pointer
974  *	cmd		DDI_DETACH all others are an error
975  * Output:
976  *	None
977  * Returns:
978  *	DDI_SUCCESS or DDI_FAILURE
979  * Called by:
980  *	Framework
981  * Description:
982  *	Used when a device is removed
983  */
984 static int
umad_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)985 umad_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
986 {
987 	int		rc = DDI_SUCCESS;
988 	umad_info_t	*info;
989 
990 
991 	switch (cmd) {
992 	case DDI_DETACH:
993 		info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
994 		umad_context_destroy(dip, info);
995 		ddi_soft_state_free(umad_statep, UMAD_INSTANCE);
996 		break;
997 
998 	default:
999 		rc = DDI_FAILURE;
1000 		break;
1001 	}
1002 
1003 	return (rc);
1004 }
1005 
1006 /*
1007  * Function:
1008  *	umad_getinfo
1009  * Input:
1010  *	dip	device pointer
1011  *	cmd	DDI_INFO_DEVT2DEVINFO or DDI_INFO_DEV2INSTANCE
1012  *	arg	Unused
1013  * Output:
1014  *	resultp	device pointer or device instance as per cmd
1015  * Returns:
1016  *	status
1017  * Called by:
1018  *	Framework
1019  * Description:
1020  *	Gets information about specific device
1021  */
1022 static int
umad_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)1023 umad_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
1024 {
1025 	int rc;
1026 
1027 #if defined(__lint)
1028 	extern void dummy2(void *);
1029 
1030 	dummy2(arg);
1031 #endif
1032 
1033 	switch (cmd) {
1034 	case DDI_INFO_DEVT2DEVINFO:
1035 		*resultp = (void *)dip;
1036 		break;
1037 
1038 	case DDI_INFO_DEVT2INSTANCE:
1039 		*resultp = (void *)UMAD_INSTANCE;
1040 		rc = DDI_SUCCESS;
1041 		break;
1042 
1043 	default:
1044 		rc = DDI_FAILURE;
1045 		break;
1046 	}
1047 
1048 	return (rc);
1049 }
1050 
1051 /*
1052  * Function:
1053  *	umad_prop_op
1054  * Input:
1055  *	dev		device
1056  *	dip		device pointer
1057  *	prop_op		which property operation
1058  *	flags		property flags
1059  *	name		proper name
1060  * Output:
1061  *	valuep		- property value
1062  *	lengthp		- propery length
1063  * Returns:
1064  *	status
1065  * Called by:
1066  *	Framework
1067  * Description:
1068  *	Passes straight through to default ddi_prop_op()
1069  */
1070 static int
umad_prop_op(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int flags,char * name,caddr_t valuep,int * lengthp)1071 umad_prop_op(
1072 	dev_t dev,
1073 	dev_info_t *dip,
1074 	ddi_prop_op_t prop_op,
1075 	int flags,
1076 	char *name,
1077 	caddr_t valuep,
1078 	int *lengthp)
1079 {
1080 	int rc;
1081 
1082 	rc = ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp);
1083 
1084 	return (rc);
1085 }
1086 
1087 
1088 /* Returns an array of mad classes associated with IBMF class */
1089 static const uint8_t *
umad_get_mad_classes_by_ibmf_class(enum _ibmf_client_type_t ibmf_class)1090 umad_get_mad_classes_by_ibmf_class(enum _ibmf_client_type_t ibmf_class)
1091 {
1092 	const struct ibmf_class_to_mad_type *entry;
1093 
1094 	for (entry = &ibmf_class_to_mad_types[0];
1095 	    entry->ibmf_class != 0;
1096 	    ++entry) {
1097 		if (ibmf_class == entry->ibmf_class)
1098 			return (entry->mad_types);
1099 	}
1100 	return (NULL);
1101 }
1102 
1103 /* Returns an agent from its ID. */
1104 static umad_agent_t *
umad_get_agent_by_id(umad_uctx_t * uctx,uint32_t agent_id)1105 umad_get_agent_by_id(umad_uctx_t *uctx, uint32_t agent_id)
1106 {
1107 	umad_agent_t *agent;
1108 	llist_head_t *entry;
1109 
1110 	ASSERT(MUTEX_HELD(&uctx->uctx_lock));
1111 
1112 	/* Look for the agent */
1113 	list_for_each(entry, &uctx->uctx_agent_list) {
1114 		agent = entry->ptr;
1115 
1116 		if (agent_id == agent->agent_req.id)
1117 			return (agent);
1118 	}
1119 
1120 	return (NULL);
1121 }
1122 
1123 /* Returns an agent from its MAD class. */
1124 static umad_agent_t *
umad_get_agent_by_class(umad_uctx_t * uctx,uint8_t agent_class)1125 umad_get_agent_by_class(umad_uctx_t *uctx, uint8_t agent_class)
1126 {
1127 	umad_agent_t *agent;
1128 	llist_head_t *entry;
1129 
1130 	ASSERT(MUTEX_HELD(&uctx->uctx_lock));
1131 
1132 	/* Look for the agent */
1133 	list_for_each(entry, &uctx->uctx_agent_list) {
1134 		agent = entry->ptr;
1135 		if (agent_class == agent->agent_req.mgmt_class)
1136 			return (agent);
1137 	}
1138 
1139 	return (NULL);
1140 }
1141 
1142 /*
1143  * Register the agent with a class.
1144  * mgmt_class is given from userspace.
1145  */
1146 static int
umad_register_agent(struct umad_agent_s * agent)1147 umad_register_agent(struct umad_agent_s *agent)
1148 {
1149 	uint8_t mgmt_class_num = agent->agent_req.mgmt_class;
1150 	umad_port_info_t *port = agent->agent_uctx->uctx_port;
1151 	const umad_hca_info_t *hca = port->port_hca;
1152 	int rc;
1153 	ibmf_register_info_t    reg_info	= {0, };
1154 	ibmf_impl_caps_t	impl_caps	= {0, };
1155 	uint_t	flags = 0;
1156 	enum _ibmf_client_type_t ibmf_class;
1157 	const uint8_t *umad_types;
1158 	struct ibmf_reg_info *ibmf_info;
1159 	llist_head_t *entry;
1160 	boolean_t found = B_FALSE;
1161 
1162 	ASSERT(MUTEX_HELD(&agent->agent_uctx->uctx_lock));
1163 
1164 	/*
1165 	 * Map MAD class to IBMF class
1166 	 */
1167 
1168 	ibmf_class = umad_type_to_ibmf_class[mgmt_class_num];
1169 
1170 	/*
1171 	 * It is is reserved, bail
1172 	 */
1173 	if (ibmf_class == 0) {
1174 		rc = EINVAL;
1175 		goto done;
1176 	}
1177 
1178 	/* Check to see if any other mad classes also map to this IBMF class */
1179 	umad_types = umad_get_mad_classes_by_ibmf_class(ibmf_class);
1180 	if (umad_types != NULL) {
1181 		struct umad_agent_s *other_agent;
1182 
1183 		for (; *umad_types != 0; ++umad_types) {
1184 			other_agent = umad_get_agent_by_class(agent->agent_uctx,
1185 			    *umad_types);
1186 			if (other_agent != NULL) {
1187 				struct ibmf_reg_info *ibmf_reg;
1188 
1189 				ibmf_reg = other_agent->agent_reg;
1190 				agent->agent_reg = ibmf_reg;
1191 				if (other_agent->agent_flags
1192 				    & UMAD_HANDLING_ASYNC) {
1193 					agent->agent_flags |=
1194 					    UMAD_HANDLING_ASYNC;
1195 				}
1196 
1197 				mutex_enter(&ibmf_reg->ibmf_reg_lock);
1198 				while (ibmf_reg->ibmf_flags
1199 				    & UMAD_IBMF_UNREGISTERING) {
1200 					cv_wait(&ibmf_reg->ibmf_cv,
1201 					    &ibmf_reg->ibmf_reg_lock);
1202 				}
1203 				ibmf_reg->ibmf_reg_refcnt++;
1204 				mutex_exit(&ibmf_reg->ibmf_reg_lock);
1205 				return (0);
1206 			}
1207 		}
1208 	}
1209 
1210 	/*
1211 	 * At this point we need to check if there is already an
1212 	 * ibmf_info already associated with this HCA, port and ibmf
1213 	 * class.  If so, simply increment the reference count
1214 	 * and set the agent's agent_reg field to point to the
1215 	 * ibmf_info structure that was found. (under locking)
1216 	 */
1217 	mutex_enter(&port->port_lock);
1218 	if (! llist_empty(&port->port_ibmf_regs)) {
1219 		list_for_each(entry, &port->port_ibmf_regs) {
1220 			ibmf_info = (struct ibmf_reg_info *)entry->ptr;
1221 			if (ibmf_info->ibmf_class == ibmf_class) {
1222 				found = B_TRUE;
1223 				break;
1224 			}
1225 		}
1226 	}
1227 	mutex_exit(&port->port_lock);
1228 
1229 	if (found) {
1230 		mutex_enter(&ibmf_info->ibmf_reg_lock);
1231 		ibmf_info->ibmf_reg_refcnt++;
1232 		agent->agent_reg = ibmf_info;
1233 		mutex_exit(&ibmf_info->ibmf_reg_lock);
1234 
1235 		return (0);
1236 	}
1237 
1238 	ibmf_info = kmem_zalloc(sizeof (struct ibmf_reg_info), KM_SLEEP);
1239 
1240 	mutex_init(&ibmf_info->ibmf_reg_lock, NULL, MUTEX_DRIVER, NULL);
1241 	cv_init(&ibmf_info->ibmf_cv, NULL, CV_DRIVER, NULL);
1242 
1243 	if (agent->agent_req.rmpp_version)
1244 		flags = IBMF_REG_FLAG_RMPP;
1245 
1246 	reg_info.ir_ci_guid = hca->hca_guid;
1247 	reg_info.ir_port_num = port->port_num;
1248 	reg_info.ir_client_class = ibmf_class;
1249 
1250 	mutex_enter(&ibmf_info->ibmf_reg_lock);
1251 	rc = ibmf_register(&reg_info, IBMF_VERSION, flags, NULL, NULL,
1252 	    &ibmf_info->ibmf_reg_handle, &impl_caps);
1253 
1254 	if (rc != IBMF_SUCCESS) {
1255 		mutex_exit(&ibmf_info->ibmf_reg_lock);
1256 		kmem_free(ibmf_info, sizeof (*ibmf_info));
1257 	} else {
1258 		/* The client wants to receive some unsolicited MADs. */
1259 		rc = ibmf_setup_async_cb(ibmf_info->ibmf_reg_handle,
1260 		    IBMF_QP_HANDLE_DEFAULT, umad_unsolicited_cb,
1261 		    (void *)ibmf_info, 0);
1262 
1263 		if (rc != IBMF_SUCCESS) {
1264 			(void) ibmf_unregister(&ibmf_info->ibmf_reg_handle, 0);
1265 			mutex_exit(&ibmf_info->ibmf_reg_lock);
1266 			kmem_free(ibmf_info, sizeof (*ibmf_info));
1267 		} else {
1268 			ibmf_info->ibmf_reg_refcnt++;
1269 			ibmf_info->ibmf_reg_uctx = agent->agent_uctx;
1270 			ibmf_info->ibmf_class = ibmf_class;
1271 			agent->agent_reg = ibmf_info;
1272 			agent->agent_flags |= UMAD_HANDLING_ASYNC;
1273 			mutex_exit(&ibmf_info->ibmf_reg_lock);
1274 
1275 			entry = kmem_zalloc(sizeof (llist_head_t), KM_SLEEP);
1276 			entry->ptr = ibmf_info;
1277 			mutex_enter(&port->port_lock);
1278 			llist_add(entry, &port->port_ibmf_regs);
1279 			mutex_exit(&port->port_lock);
1280 		}
1281 	}
1282 
1283 done:
1284 	return (rc);
1285 }
1286 
1287 /*
1288  * Function:
1289  *      umad_queue_mad_msg
1290  * Input:
1291  *	port            - handle to ibmf
1292  *      ibmf_msg        - The incoming SM MAD
1293  * Output:
1294  *	None
1295  * Returns:
1296  *     0 on success, otherwise error number
1297  * Called by:
1298  *      umad_solicitied_cb and umad_unsolicited_cb
1299  * Description:
1300  *      creates a umad_msg and adds it to the appropriate user's context
1301  */
1302 
1303 static int
umad_queue_mad_msg(struct umad_agent_s * agent,ibmf_msg_t * ibmf_msg)1304 umad_queue_mad_msg(struct umad_agent_s *agent, ibmf_msg_t *ibmf_msg)
1305 {
1306 	int rc;
1307 	ib_umad_msg_t *umad_msg;
1308 	umad_uctx_t *uctx = agent->agent_uctx;
1309 
1310 	if (agent->agent_uctx == NULL) {
1311 		rc = ENOENT;
1312 		goto err1;
1313 	}
1314 
1315 	umad_msg = kmem_zalloc(sizeof (*umad_msg), KM_NOSLEEP);
1316 	if (umad_msg == NULL) {
1317 		rc = ENOMEM;
1318 		goto err1;
1319 	}
1320 
1321 	umad_msg->umad_msg_hdr.id = agent->agent_req.id;
1322 	umad_msg->umad_msg_hdr.status = ibmf_msg->im_msg_status;
1323 	umad_msg->umad_msg_hdr.length = IB_MGMT_MAD_HDR +
1324 	    ibmf_msg->im_msgbufs_recv.im_bufs_cl_hdr_len +
1325 	    ibmf_msg->im_msgbufs_recv.im_bufs_cl_data_len;
1326 
1327 	umad_msg->umad_msg_hdr.qpn =
1328 	    htonl(ibmf_msg->im_local_addr.ia_remote_qno);
1329 	umad_msg->umad_msg_hdr.lid =
1330 	    htons(ibmf_msg->im_local_addr.ia_remote_lid);
1331 	umad_msg->umad_msg_hdr.sl =
1332 	    htonl(ibmf_msg->im_local_addr.ia_service_level);
1333 
1334 	umad_msg->umad_msg_ibmf_msg = ibmf_msg;
1335 
1336 	mutex_enter(&uctx->uctx_recv_lock);
1337 	if (! add_genlist(&uctx->uctx_recv_list, (uintptr_t)umad_msg, agent)) {
1338 		kmem_free(umad_msg, sizeof (*umad_msg));
1339 		mutex_exit(&uctx->uctx_recv_lock);
1340 		rc = ENOMEM;
1341 		goto err1;
1342 	}
1343 	mutex_exit(&uctx->uctx_recv_lock);
1344 
1345 	cv_broadcast(&uctx->uctx_recv_cv);
1346 	pollwakeup(&uctx->uctx_pollhead, POLLIN | POLLRDNORM);
1347 
1348 	rc = 0;
1349 
1350 err1:
1351 	return (rc);
1352 }
1353 
1354 /* Frees up user context state */
1355 static void
umad_release_uctx(umad_uctx_t * uctx)1356 umad_release_uctx(umad_uctx_t *uctx)
1357 {
1358 	ASSERT(genlist_empty(&uctx->uctx_recv_list));
1359 	ASSERT(llist_empty(&uctx->uctx_agent_list));
1360 
1361 	cv_destroy(&uctx->uctx_recv_cv);
1362 	mutex_destroy(&uctx->uctx_lock);
1363 	mutex_destroy(&uctx->uctx_recv_lock);
1364 }
1365 
1366 /*
1367  * Function:
1368  *	umad_open
1369  * Input:
1370  *	devp		device pointer
1371  *	flag		Unused
1372  *	otyp		Open type (just validated)
1373  *	cred		Unused
1374  * Output:
1375  *	None
1376  * Returns:
1377  *	status
1378  * Called by:
1379  *	Device open framework
1380  * Description:
1381  *	If this is the issm device, modify the port to indicate that this is
1382  *	a subnet manager.  If regular umad device, allocate and initialize
1383  *	a new user context and connect it to the hca info.  Return the new
1384  *	dev_t for the new minor.
1385  */
1386 static int
umad_open(dev_t * dev,int flag,int otyp,cred_t * cred)1387 umad_open(dev_t *dev, int flag, int otyp, cred_t *cred)
1388 {
1389 	umad_info_t		*info;
1390 	minor_t			minor;
1391 	minor_t			ctx_minor;
1392 	int			node_id, port_num;
1393 	int			rc = DDI_SUCCESS;
1394 	umad_hca_info_t		*hca;
1395 	umad_port_info_t	*port;
1396 	umad_uctx_t		*uctx;
1397 
1398 #if defined(__lint)
1399 	extern void dummy(int);
1400 
1401 	dummy(flag);
1402 #endif
1403 
1404 	rc = priv_policy(cred, PRIV_SYS_NET_CONFIG, B_FALSE, EACCES, NULL);
1405 	if (rc != 0)
1406 		return (rc);
1407 
1408 	info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
1409 	if (info == NULL) {
1410 		rc = ENXIO;
1411 		goto err1;
1412 	}
1413 	if (otyp != OTYP_CHR)
1414 		return (EINVAL);
1415 
1416 	/* lookup the node and port #s */
1417 	minor = getminor(*dev);
1418 
1419 	node_id	= GET_NODE(minor);
1420 	port_num = GET_PORT(minor);
1421 
1422 	hca = &info->info_hcas[node_id];
1423 	port = &hca->hca_ports[port_num];
1424 
1425 	if (ISSM_MINOR(minor)) {
1426 		ibt_status_t rc;
1427 
1428 		mutex_enter(&port->port_lock);
1429 
1430 		if (port->port_issm_open_cnt) {
1431 			mutex_exit(&port->port_lock);
1432 			rc = EBUSY;
1433 			goto err1;
1434 		}
1435 
1436 		port->port_issm_open_cnt++;
1437 
1438 		mutex_exit(&port->port_lock);
1439 
1440 		rc = ibt_modify_port(hca->hca_handle, port->port_num,
1441 		    IBT_PORT_SET_SM, 0);
1442 
1443 		if (rc) {
1444 			mutex_enter(&port->port_lock);
1445 			port->port_issm_open_cnt--;
1446 			mutex_exit(&port->port_lock);
1447 			goto err1;
1448 		}
1449 	} else {
1450 		unsigned int uctx_num;
1451 
1452 		uctx = kmem_zalloc(sizeof (umad_uctx_t), KM_SLEEP);
1453 
1454 		mutex_init(&uctx->uctx_lock, NULL, MUTEX_DRIVER, NULL);
1455 		cv_init(&uctx->uctx_recv_cv, NULL, CV_DRIVER, NULL);
1456 		init_genlist(&uctx->uctx_recv_list);
1457 		mutex_init(&uctx->uctx_recv_lock, NULL, MUTEX_DRIVER, NULL);
1458 		llist_head_init(&uctx->uctx_agent_list, NULL);
1459 		uctx->uctx_port = port;
1460 
1461 		mutex_enter(&info->info_mutex);
1462 		mutex_enter(&port->port_lock);
1463 
1464 		/* Find a free entry in uctx list */
1465 		for (uctx_num = 0; uctx_num < MAX_UCTX; uctx_num++) {
1466 			if (info->info_uctx[uctx_num] == NULL)
1467 				break;
1468 		}
1469 
1470 		if (uctx_num == MAX_UCTX) {
1471 			/* No room found */
1472 			mutex_exit(&port->port_lock);
1473 			mutex_exit(&info->info_mutex);
1474 
1475 			umad_release_uctx(uctx);
1476 
1477 			rc = EBUSY;
1478 			goto err1;
1479 		}
1480 
1481 		ctx_minor = GET_NEW_UCTX_MINOR(minor, uctx_num);
1482 		info->info_uctx[uctx_num] = uctx;
1483 		*dev = makedevice(getmajor(*dev), ctx_minor);
1484 
1485 		mutex_exit(&port->port_lock);
1486 		mutex_exit(&info->info_mutex);
1487 	}
1488 err1:
1489 	return (rc);
1490 }
1491 
1492 /*
1493  * Function:
1494  *	umad_close
1495  * Input:
1496  *	dev		device
1497  *	flag		Unused
1498  *	otyp		Unused
1499  *	cred		Unused
1500  * Output:
1501  *	None
1502  * Returns:
1503  *	status
1504  * Called by:
1505  *	Device close framework
1506  * Description:
1507  *	Unwinds open while waiting for any pending I/O to complete.
1508  */
1509 /* ARGSUSED1 */
1510 static int
umad_close(dev_t dev,int flag,int otyp,cred_t * cred)1511 umad_close(dev_t dev, int flag, int otyp, cred_t *cred)
1512 {
1513 	umad_info_t		*info;
1514 	minor_t			minor;
1515 	int			rc = DDI_SUCCESS;
1516 	umad_port_info_t	*port;
1517 	umad_uctx_t		*uctx;
1518 	llist_head_t		*lentry;
1519 	llist_head_t		*lentry_temp;
1520 	umad_agent_t		*agent;
1521 	int			port_num;
1522 	umad_hca_info_t		*hca;
1523 	int			node_id;
1524 
1525 	info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
1526 	if (info == NULL) {
1527 		rc = ENXIO;
1528 		goto  err1;
1529 	}
1530 	minor = getminor(dev);
1531 
1532 	node_id	= GET_NODE(minor);
1533 	port_num = GET_PORT(minor);
1534 
1535 	hca = &info->info_hcas[node_id];
1536 	port = &hca->hca_ports[port_num];
1537 
1538 	ASSERT(port != NULL);
1539 
1540 	if (ISSM_MINOR(minor)) {
1541 		(void) ibt_modify_port(hca->hca_handle, port->port_num,
1542 		    IBT_PORT_RESET_SM, 0);
1543 
1544 		mutex_enter(&port->port_lock);
1545 		port->port_issm_open_cnt--;
1546 		mutex_exit(&port->port_lock);
1547 
1548 		ASSERT(port->port_issm_open_cnt == 0);
1549 	} else {
1550 
1551 		mutex_enter(&info->info_mutex);
1552 		uctx = info->info_uctx[GET_UCTX(minor)];
1553 		ASSERT(uctx != NULL);
1554 
1555 		mutex_enter(&uctx->uctx_lock);
1556 
1557 		/* Unregister the agents. Cancel the pending operations. */
1558 		lentry = uctx->uctx_agent_list.nxt;
1559 		lentry_temp = lentry->nxt;
1560 		while (lentry != &uctx->uctx_agent_list) {
1561 			ASSERT(lentry);
1562 			agent = lentry->ptr;
1563 
1564 			(void) umad_unregister(&agent->agent_req, uctx);
1565 			lentry = lentry_temp;
1566 			lentry_temp = lentry->nxt;
1567 		}
1568 
1569 		mutex_exit(&uctx->uctx_lock);
1570 
1571 		umad_release_uctx(uctx);
1572 		kmem_free(uctx, sizeof (umad_uctx_t));
1573 
1574 		info->info_uctx[GET_UCTX(minor)] = NULL;
1575 		mutex_exit(&info->info_mutex);
1576 	}
1577 
1578 err1:
1579 	return (rc);
1580 }
1581 
1582 /*
1583  * return where optional header starts relative to the start
1584  * of the transmited mad
1585  */
1586 static int
umad_get_mad_clhdr_offset(uint8_t mgmt_class)1587 umad_get_mad_clhdr_offset(uint8_t mgmt_class)
1588 {
1589 	switch (mgmt_class) {
1590 	case MAD_MGMT_CLASS_SUBN_LID_ROUTED:
1591 	case MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE:
1592 	case MAD_MGMT_CLASS_PERF:
1593 	case MAD_MGMT_CLASS_BM:
1594 	case MAD_MGMT_CLASS_DEV_MGT:
1595 	case MAD_MGMT_CLASS_COMM_MGT:
1596 		return (IB_MGMT_MAD_HDR);
1597 	case MAD_MGMT_CLASS_SUBN_ADM:
1598 		return (IB_MGMT_RMPP_HDR);
1599 	case MAD_MGMT_CLASS_SNMP:
1600 		return (IB_MGMT_SNMP_HDR);
1601 	default:
1602 		if (((mgmt_class >= MAD_MGMT_CLASS_VENDOR_START) &&
1603 		    (mgmt_class <= MAD_MGMT_CLASS_VENDOR_END)) ||
1604 		    ((mgmt_class >= MAD_MGMT_CLASS_APPLICATION_START) &&
1605 		    (mgmt_class <= MAD_MGMT_CLASS_APPLICATION_END)))
1606 			return (IB_MGMT_MAD_HDR);
1607 		else if ((mgmt_class >= MAD_MGMT_CLASS_VENDOR2_START) &&
1608 		    (mgmt_class <= MAD_MGMT_CLASS_VENDOR2_END))
1609 			return (IB_MGMT_RMPP_HDR);
1610 		else {
1611 #if defined(DEBUG)
1612 			SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
1613 			    "umad_get_mad_clhdr_offset:"
1614 			    " got illegal management class %d", mgmt_class);
1615 #endif
1616 			return (0);  /* invalid mad */
1617 		}
1618 	}
1619 }
1620 
1621 /*
1622  * return the offset of the mad data in the transmited mad
1623  * following all headers
1624  */
1625 static int
umad_get_mad_data_offset(uint8_t mgmt_class)1626 umad_get_mad_data_offset(uint8_t mgmt_class)
1627 {
1628 	switch (mgmt_class) {
1629 	case MAD_MGMT_CLASS_SUBN_LID_ROUTED:
1630 	case MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE:
1631 	case MAD_MGMT_CLASS_PERF:
1632 	case MAD_MGMT_CLASS_BM:
1633 	case MAD_MGMT_CLASS_DEV_MGT:
1634 	case MAD_MGMT_CLASS_COMM_MGT:
1635 		return (IB_MGMT_MAD_HDR);
1636 	case MAD_MGMT_CLASS_SUBN_ADM:
1637 		return (IB_MGMT_SA_HDR);
1638 	case MAD_MGMT_CLASS_SNMP:
1639 		return (IB_MGMT_SNMP_DATA);
1640 	default:
1641 		if (((mgmt_class >= MAD_MGMT_CLASS_VENDOR_START) &&
1642 		    (mgmt_class <= MAD_MGMT_CLASS_VENDOR_END)) ||
1643 		    ((mgmt_class >= MAD_MGMT_CLASS_APPLICATION_START) &&
1644 		    (mgmt_class <= MAD_MGMT_CLASS_APPLICATION_END)))
1645 			return (IB_MGMT_MAD_HDR);
1646 		else if ((mgmt_class >= MAD_MGMT_CLASS_VENDOR2_START) &&
1647 		    (mgmt_class <= MAD_MGMT_CLASS_VENDOR2_END))
1648 			return (IB_MGMT_VENDOR_HDR);
1649 		else {
1650 #if defined(DEBUG)
1651 			SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
1652 			    "umad_get_mad_clhdr_offset:"
1653 			    " got illegal management class %d", mgmt_class);
1654 #endif
1655 			return (0);  /* invalid mad */
1656 		}
1657 	}
1658 
1659 }
1660 
1661 /*
1662  * Function:
1663  *	umad_read
1664  * Input:
1665  *	dev		device
1666  *	uiop		User I/O pointer
1667  *	credp		Unused
1668  * Output:
1669  *	None
1670  * Returns:
1671  *	status
1672  * Called by:
1673  *	Device read framework
1674  * Description:
1675  *	Cannot read from ISSM device.  Read from UMAD device
1676  *	does usual checks for blocking and when data is present,
1677  *	removes message from user context receive list, fills in user
1678  *	space with message and frees kernel copy of the message.
1679  */
1680 /* ARGSUSED2 */
1681 static int
umad_read(dev_t dev,struct uio * uiop,cred_t * credp)1682 umad_read(dev_t dev, struct uio *uiop, cred_t *credp)
1683 {
1684 	int			minor;
1685 	size_t			data_len;
1686 	int			rc = 0;
1687 	umad_port_info_t	*port;
1688 	umad_info_t		*info;
1689 	umad_uctx_t		*uctx;
1690 	genlist_entry_t		*entry;
1691 	ib_umad_msg_t		*umad_msg;
1692 	ibmf_msg_t		*ibmf_msg;
1693 	struct umad_agent_s	*agent;
1694 	ib_mad_hdr_t		*ib_mad_hdr;
1695 	ssize_t			start_resid;
1696 
1697 
1698 	info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
1699 	if (info == NULL) {
1700 		rc = ENXIO;
1701 		goto err1;
1702 	}
1703 
1704 	minor = getminor(dev);
1705 
1706 	if (ISSM_MINOR(minor)) {
1707 		rc = ENXIO;
1708 		goto err1;
1709 	}
1710 
1711 	mutex_enter(&info->info_mutex);
1712 	uctx = info->info_uctx[GET_UCTX(minor)];
1713 	mutex_exit(&info->info_mutex);
1714 	ASSERT(uctx != NULL);
1715 	port = uctx->uctx_port;
1716 	ASSERT(port != NULL);
1717 
1718 	start_resid = uiop->uio_resid;
1719 	while (rc == 0 && uiop->uio_resid > 0) {
1720 		mutex_enter(&uctx->uctx_recv_lock);
1721 
1722 		/* Check to see if we are in blocking mode or not */
1723 		if (! (uiop->uio_fmode & (FNDELAY | FNONBLOCK))) {
1724 			while (genlist_empty(&uctx->uctx_recv_list)) {
1725 				if (cv_wait_sig(&uctx->uctx_recv_cv,
1726 				    &uctx->uctx_recv_lock) == 0) {
1727 					mutex_exit(&uctx->uctx_recv_lock);
1728 					return (EINTR);
1729 				}
1730 			}
1731 		} else if (genlist_empty(&uctx->uctx_recv_list)) {
1732 			mutex_exit(&uctx->uctx_recv_lock);
1733 			/* Check for a short read */
1734 			if (uiop->uio_resid != start_resid)
1735 				return (0);
1736 			return (EAGAIN);
1737 		}
1738 
1739 		entry = remove_genlist_head(&uctx->uctx_recv_list);
1740 		mutex_exit(&uctx->uctx_recv_lock);
1741 
1742 		ASSERT(entry != NULL);
1743 		agent = entry->data_context;
1744 
1745 		umad_msg = (ib_umad_msg_t *)entry->data;
1746 		ibmf_msg =  (ibmf_msg_t *)umad_msg->umad_msg_ibmf_msg;
1747 
1748 		data_len = min(uiop->uio_resid, sizeof (struct ib_user_mad));
1749 		rc = uiomove(umad_msg, data_len, UIO_READ, uiop);
1750 		if (rc)
1751 			goto err2;
1752 
1753 		if (ibmf_msg->im_msg_status == IBMF_SUCCESS) {
1754 			ib_mad_hdr = (ib_mad_hdr_t *)
1755 			    ibmf_msg->im_msgbufs_recv.im_bufs_mad_hdr;
1756 			data_len =
1757 			    umad_get_mad_clhdr_offset(ib_mad_hdr->MgmtClass);
1758 			data_len = min(uiop->uio_resid, data_len);
1759 
1760 			rc = uiomove(ibmf_msg->im_msgbufs_recv.im_bufs_mad_hdr,
1761 			    data_len, UIO_READ, uiop);
1762 			if (rc)
1763 				goto err2;
1764 
1765 			data_len = min(uiop->uio_resid,
1766 			    ibmf_msg->im_msgbufs_recv.im_bufs_cl_hdr_len);
1767 			rc = uiomove(ibmf_msg->im_msgbufs_recv.im_bufs_cl_hdr,
1768 			    data_len, UIO_READ, uiop);
1769 			if (rc)
1770 				goto err2;
1771 
1772 			data_len = min(uiop->uio_resid,
1773 			    ibmf_msg->im_msgbufs_recv.im_bufs_cl_data_len);
1774 			rc = uiomove(ibmf_msg->im_msgbufs_recv.im_bufs_cl_data,
1775 			    data_len, UIO_READ, uiop);
1776 			if (rc)
1777 				goto err2;
1778 		}
1779 		rc = ibmf_free_msg(agent->agent_reg->ibmf_reg_handle,
1780 		    &ibmf_msg);
1781 
1782 		kmem_free(umad_msg, sizeof (*umad_msg));
1783 		if (rc != IBMF_SUCCESS) {
1784 #if defined(DEBUG)
1785 			SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
1786 			    "umad_read:"
1787 			    " ibmf_free_msg failed %d", rc);
1788 #endif
1789 			goto err1;
1790 		}
1791 	}
1792 err2:
1793 	if (rc) {
1794 		rc = ibmf_free_msg(agent->agent_reg->ibmf_reg_handle,
1795 		    &ibmf_msg);
1796 
1797 		kmem_free(umad_msg, sizeof (*umad_msg));
1798 
1799 		if (rc != IBMF_SUCCESS) {
1800 #if defined(DEBUG)
1801 			SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
1802 			    "umad_read:"
1803 			    " ibmf_free_msg failed %d", rc);
1804 #endif
1805 		}
1806 
1807 	}
1808 err1:
1809 	return (rc);
1810 }
1811 
1812 /*
1813  * Function:
1814  *     umad_solicited_cb
1815  * Input:
1816  *	ibmf_handle     -  handle to ibmf
1817  *      msgp            -  The incoming SM MAD
1818  *      args            -  umad_port_info_t object that the MAD cam in on
1819  * Output:
1820  *	None
1821  * Returns:
1822  *      none
1823  * Called by:
1824  * Description:
1825  *      Callback function (ibmf_msg_cb_t) that is invoked when the
1826  *      ibmf receives a SM MAD for the given Port.
1827  *      This function copies the MAD into the port recv queue.
1828  */
1829 static void
umad_solicited_cb(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)1830 umad_solicited_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
1831 {
1832 	struct umad_send *umad_ctx = (struct umad_send *)args;
1833 	umad_agent_t *agent = umad_ctx->send_agent;
1834 	int rc;
1835 
1836 #if defined(__lint)
1837 	ibmf_handle = 0;
1838 #endif
1839 	msgp->im_msgbufs_send.im_bufs_mad_hdr = NULL;
1840 	msgp->im_msgbufs_send.im_bufs_cl_hdr = NULL;
1841 	msgp->im_msgbufs_send.im_bufs_cl_hdr_len = 0;
1842 	msgp->im_msgbufs_send.im_bufs_cl_data = NULL;
1843 	msgp->im_msgbufs_send.im_bufs_cl_data_len = 0;
1844 	kmem_free(umad_ctx, umad_ctx->send_len);
1845 
1846 	mutex_enter(&agent->agent_lock);
1847 	agent->agent_outstanding_msgs--;
1848 	ASSERT(agent->agent_outstanding_msgs >= 0);
1849 	if (agent->agent_flags & UMAD_AGENT_UNREGISTERING) {
1850 		if (agent->agent_outstanding_msgs == 0)
1851 			cv_signal(&agent->agent_cv);
1852 	}
1853 	mutex_exit(&agent->agent_lock);
1854 	if (umad_queue_mad_msg(agent, msgp))
1855 		goto bad;
1856 
1857 	return;
1858 
1859 bad:
1860 	rc = ibmf_free_msg(agent->agent_reg->ibmf_reg_handle, &msgp);
1861 	ASSERT(rc == IBMF_SUCCESS);
1862 }
1863 
1864 /*
1865  * Function:
1866  *	umad_write
1867  * Input:
1868  *	dev		device
1869  *	uiop		User I/O pointer
1870  *	credp		Unused
1871  * Output:
1872  *	None
1873  * Returns:
1874  *	status
1875  * Called by:
1876  *	Device write framework
1877  * Description:
1878  *	Cannot write to ISSM device.  Allocate new umad_send structure
1879  *	and ibmf message and copy from user space into allocated message.
1880  *	Fill in required fields.  If this is a request make sure
1881  *	umad_solicited_cb() is passed.
1882  */
1883 /* ARGSUSED1 */
1884 static int
umad_write(dev_t dev,struct uio * uiop,cred_t * credp)1885 umad_write(dev_t dev, struct uio *uiop, cred_t *credp)
1886 {
1887 	int			rc, rc2;
1888 	int			mad_offset, flags = 0;
1889 	int			hdr_len;
1890 	size_t			len = uiop->uio_resid;
1891 	minor_t			minor;
1892 	ibmf_retrans_t		mad_retrans;
1893 	umad_info_t		*info;
1894 	umad_port_info_t		*port;
1895 	umad_uctx_t		*uctx;
1896 	umad_agent_t		*agent;
1897 	struct ib_user_mad	*user_mad;	/* incoming uMAD hdr */
1898 	ibmf_msg_t		*ibmf_msg;	/* outbound MAD mesg */
1899 	ib_mad_hdr_t		*ib_mad_hdr;	/* outbound MAD hdrs */
1900 	struct umad_send 	*umad_ctx;
1901 	boolean_t		need_callback;
1902 	ibt_status_t		status;
1903 	ib_pkey_t		pkey;
1904 
1905 	info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
1906 	if (info == NULL) {
1907 		rc = ENXIO;
1908 		goto err1;
1909 	}
1910 
1911 	/* lookup the node and port #s */
1912 	minor = getminor(dev);
1913 
1914 	if (ISSM_MINOR(minor)) {
1915 		rc = ENXIO;
1916 		goto err1;
1917 	}
1918 
1919 	mutex_enter(&info->info_mutex);
1920 	uctx = info->info_uctx[GET_UCTX(minor)];
1921 	mutex_exit(&info->info_mutex);
1922 	ASSERT(uctx != NULL);
1923 	port = uctx->uctx_port;
1924 	ASSERT(port != NULL);
1925 
1926 	umad_ctx = kmem_zalloc(sizeof (struct umad_send) + len, KM_SLEEP);
1927 	umad_ctx->send_len = sizeof (struct umad_send) + len;
1928 
1929 	/* copy the MAD data in from user space */
1930 	/* data = user_mad + mad_hdrs + class_hdrs + class data */
1931 	/* LINTED */
1932 	user_mad = (struct ib_user_mad *)umad_ctx->send_umad;
1933 	rc = uiomove(user_mad, len, UIO_WRITE, uiop);
1934 	if (rc != 0)
1935 		goto err3;
1936 
1937 
1938 	/* Look for the agent */
1939 	mutex_enter(&uctx->uctx_lock);
1940 	agent = umad_get_agent_by_id(uctx, user_mad->hdr.id);
1941 	mutex_exit(&uctx->uctx_lock);
1942 	if (! agent) {
1943 		rc = EINVAL;
1944 		goto err3;
1945 	}
1946 
1947 	mutex_enter(&agent->agent_lock);
1948 	if (agent->agent_flags & UMAD_AGENT_UNREGISTERING) {
1949 		mutex_exit(&agent->agent_lock);
1950 		rc = EINVAL;
1951 		goto err3;
1952 	}
1953 
1954 	/* Allocate the msg buf for IBMF */
1955 	rc = ibmf_alloc_msg(agent->agent_reg->ibmf_reg_handle,
1956 	    IBMF_ALLOC_NOSLEEP, &ibmf_msg);
1957 	if (rc != IBMF_SUCCESS) {
1958 		mutex_exit(&agent->agent_lock);
1959 		goto err3;
1960 	}
1961 
1962 	ib_mad_hdr = (ib_mad_hdr_t *)user_mad->data;
1963 
1964 	hdr_len = umad_get_mad_data_offset(ib_mad_hdr->MgmtClass);
1965 
1966 	/*
1967 	 * build the IBMF msg from the mad data passed in
1968 	 * construct the addr info
1969 	 */
1970 #if defined(__FUTURE_FEATURE__)
1971 	/* TODO Proper GRH handling (non-smp traffic only) */
1972 	if (mad.addr.grh_present) {
1973 		memcpy(&ibmf_msg->im_global_addr.ig_recver_gid, mad.addr.gid,
1974 		    16);
1975 		//  where can we get the GID??
1976 		im_global_addr.ig_sender_gid = get_gid(umad->addr.gid_index);
1977 		ibmf_msg->im_global_addr.ig_tclass = mad.addr.traffic_class;
1978 		ibmf_msg->im_global_addr.ig_hop_limit = mad.addr.hop_limit;
1979 		ibmf_msg->im_global_addr.ig_flow_label = mad.addr.flow_label;
1980 	}
1981 #endif
1982 
1983 	/*
1984 	 * Note: umad lid, qpn and qkey are in network order, so we need
1985 	 * to revert them to give them to ibmf. See userspace
1986 	 * umad_set_addr() and umad_set_addr_net().
1987 	 */
1988 	ibmf_msg->im_local_addr.ia_local_lid = port->port_lid;
1989 	ibmf_msg->im_local_addr.ia_remote_lid = ntohs(user_mad->hdr.lid);
1990 	ibmf_msg->im_local_addr.ia_remote_qno = ntohl(user_mad->hdr.qpn);
1991 	ibmf_msg->im_local_addr.ia_q_key = ntohl(user_mad->hdr.qkey);
1992 	ibmf_msg->im_local_addr.ia_service_level = user_mad->hdr.sl;
1993 
1994 	status = ibt_index2pkey(port->port_hca->hca_handle,
1995 	    port->port_num, user_mad->hdr.pkey_index, &pkey);
1996 	if (status != IBT_SUCCESS) {
1997 #if defined(DEBUG)
1998 		SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
1999 		    "umad_write: ibt_index2pkey failed %d",
2000 		    status);
2001 #endif
2002 	}
2003 	else
2004 		ibmf_msg->im_local_addr.ia_p_key = ntohs(pkey);
2005 
2006 	if ((ib_mad_hdr->R_Method & 0x80) == 0)
2007 		flags = IBMF_MSG_TRANS_FLAG_SEQ;
2008 
2009 	/*
2010 	 * This code is only correct for the cases of
2011 	 * no headers beyond the MAD header or the case of
2012 	 * MAD_MGMT_CLASS_SUBN_ADM (SA type) which has both
2013 	 * an RMPP header and an SA header.  Other header combinations
2014 	 * are simply not dealt with correctly, but no applications
2015 	 * utilize them either, so we should be ok.
2016 	 */
2017 
2018 	/* set use RMPP if UserAgent registered for it */
2019 	if (agent->agent_req.rmpp_version > 0) {
2020 		ibmf_rmpp_hdr_t *rmpp_hdr;
2021 
2022 		rmpp_hdr = (ibmf_rmpp_hdr_t *)(ib_mad_hdr + 1);
2023 
2024 		if (rmpp_hdr->rmpp_flags != 0)
2025 			flags |= IBMF_MSG_TRANS_FLAG_RMPP;
2026 	}
2027 
2028 	/* construct the msg bufs */
2029 	ibmf_msg->im_msgbufs_send.im_bufs_mad_hdr = ib_mad_hdr;
2030 
2031 	hdr_len = umad_get_mad_clhdr_offset(ib_mad_hdr->MgmtClass);
2032 	mad_offset = umad_get_mad_data_offset(ib_mad_hdr->MgmtClass);
2033 
2034 	/* Class headers and len, rmpp? */
2035 	ibmf_msg->im_msgbufs_send.im_bufs_cl_hdr =
2036 	    (unsigned char *)user_mad +
2037 	    offsetof(struct ib_user_mad, data) + hdr_len;
2038 	ibmf_msg->im_msgbufs_send.im_bufs_cl_hdr_len =
2039 	    mad_offset - hdr_len;
2040 
2041 	ibmf_msg->im_msgbufs_send.im_bufs_cl_data =
2042 	    (unsigned char *) user_mad + (sizeof (struct ib_user_mad) +
2043 	    mad_offset);
2044 	ibmf_msg->im_msgbufs_send.im_bufs_cl_data_len =
2045 	    len - sizeof (struct ib_user_mad) - mad_offset;
2046 
2047 	mad_retrans.retrans_retries = user_mad->hdr.retries;
2048 	mad_retrans.retrans_rtv = 0;
2049 	mad_retrans.retrans_rttv = 0;
2050 	mad_retrans.retrans_trans_to = 0;
2051 
2052 	umad_ctx->send_agent = agent;
2053 
2054 	need_callback = (flags & IBMF_MSG_TRANS_FLAG_SEQ) != 0;
2055 
2056 	if (need_callback)
2057 		agent->agent_outstanding_msgs++;
2058 
2059 	mutex_exit(&agent->agent_lock);
2060 
2061 	/* pass the MAD down to the IBMF layer */
2062 	rc = ibmf_msg_transport(agent->agent_reg->ibmf_reg_handle,
2063 	    IBMF_QP_HANDLE_DEFAULT,
2064 	    ibmf_msg, &mad_retrans,
2065 	    need_callback ? umad_solicited_cb : NULL,
2066 	    umad_ctx, flags);
2067 
2068 	if (! need_callback) {
2069 		rc2 = ibmf_free_msg(agent->agent_reg->ibmf_reg_handle,
2070 		    &ibmf_msg);
2071 		ASSERT(rc2 == IBMF_SUCCESS);
2072 
2073 		if (rc != IBMF_SUCCESS) {
2074 			rc = EIO;
2075 			goto err3;
2076 		}
2077 	} else if (rc != IBMF_SUCCESS) {
2078 		mutex_enter(&agent->agent_lock);
2079 		agent->agent_outstanding_msgs--;
2080 		ASSERT(agent->agent_outstanding_msgs >= 0);
2081 		if (agent->agent_flags & UMAD_AGENT_UNREGISTERING) {
2082 			if (agent->agent_outstanding_msgs == 0)
2083 				cv_signal(&agent->agent_cv);
2084 		}
2085 		mutex_exit(&agent->agent_lock);
2086 
2087 		rc2 = ibmf_free_msg(agent->agent_reg->ibmf_reg_handle,
2088 		    &ibmf_msg);
2089 		ASSERT(rc2 == IBMF_SUCCESS);
2090 
2091 		rc = EIO;
2092 		goto err3;
2093 	}
2094 
2095 	return (0);
2096 
2097 err3:
2098 	kmem_free(umad_ctx, umad_ctx->send_len);
2099 
2100 err1:
2101 	return (rc);
2102 }
2103 
2104 /*
2105  * Function:
2106  *	umad_async_handler
2107  * Input:
2108  *	private		Unused
2109  *	hca_hdl		Unused
2110  *	code		Unused
2111  *	event		Unused
2112  * Output:
2113  *	None
2114  * Returns:
2115  *	None
2116  * Called by:
2117  *	IBTL framework for asynchronous events.
2118  * Description:
2119  *	No special event handling currently.
2120  */
2121 /* ARGSUSED */
2122 static void
umad_async_handler(void * private,ibt_hca_hdl_t hca_hdl,ibt_async_code_t code,ibt_async_event_t * event)2123 umad_async_handler(
2124 	void *private,
2125 	ibt_hca_hdl_t hca_hdl,
2126 	ibt_async_code_t code,
2127 	ibt_async_event_t *event)
2128 {
2129 }
2130 
2131 /*
2132  * Need this ioctl to enable the newer interface (pkey_index and some
2133  * reserved key).  Since OFED changed the abi without changing the abi
2134  * version.  This resulted in wo abi interfaces (with and without the
2135  * pkey_index and some reserved bytes, but one abi version number.  The
2136  * application then tries to do an ioctl() to enable the "newwer" interface
2137  * and it that ioctl succeeds, the application code assumes the newer abi
2138  * interface otherwise it assumes the older abi intrface (Uggggggg).
2139  */
2140 static int
umad_pkey_enable()2141 umad_pkey_enable()
2142 {
2143 	/* When we move to later releases of OFED, this will go away */
2144 	return (DDI_SUCCESS);
2145 
2146 }
2147 
2148 /*
2149  * Function:
2150  *	umad_ioctl
2151  * Input:
2152  *	dev		device
2153  *	cmd		IB_USER_MAD_ENABLE_PKEY, IB_USER_MAD_REGISTER_AGENT or
2154  *			IB_USER_MAD_UNREGISTER_AGENT
2155  *	arg		which agent to register or unregister
2156  *	mode		passed on to ddi_copyin()
2157  *	credp		Unused
2158  *	rvalp		Unused
2159  * Output:
2160  *	None
2161  * Returns:
2162  *	Error status
2163  * Called by:
2164  *	Device ioctl framework
2165  * Description:
2166  *	IB_USER_MAD_ENABLE_PKEY just allows the ioctl to succed to
2167  *	indicate that we are at ABI version 5+, not really 5.
2168  *	IB_USER_MAD_REGISTER_AGENT requests that a specific MAD class
2169  *	for this device be handled by this process.
2170  *	IB_USER_MAD_UNREGISTER_AGENT undoes the request above.
2171  */
2172 /* ARGSUSED3 */
2173 static int
umad_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)2174 umad_ioctl(
2175 	dev_t dev,
2176 	int cmd,
2177 	intptr_t arg,
2178 	int mode,
2179 	cred_t *credp,
2180 	int *rvalp)
2181 {
2182 	int				rc = 0;
2183 	int				minor;
2184 	umad_info_t			*info;
2185 	umad_port_info_t		*port;
2186 	umad_uctx_t			*uctx;
2187 	struct ib_user_mad_reg_req	req = {0};
2188 
2189 	info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
2190 	if (info == NULL) {
2191 		rc = ENXIO;
2192 		goto err1;
2193 	}
2194 
2195 	/* lookup the node and port #s */
2196 	minor = getminor(dev);
2197 
2198 	if (ISSM_MINOR(minor)) {
2199 		rc = ENXIO;
2200 		goto err1;
2201 	}
2202 
2203 	mutex_enter(&info->info_mutex);
2204 	uctx = info->info_uctx[GET_UCTX(minor)];
2205 	mutex_exit(&info->info_mutex);
2206 	ASSERT(uctx != NULL);
2207 	port = uctx->uctx_port;
2208 	ASSERT(port != NULL);
2209 
2210 	if (cmd == IB_USER_MAD_ENABLE_PKEY)
2211 		return (umad_pkey_enable());
2212 
2213 	if (ddi_copyin((void *) arg, &req, sizeof (req), mode) != 0) {
2214 		rc = EFAULT;
2215 		goto err1;
2216 	}
2217 
2218 	switch (cmd) {
2219 	case IB_USER_MAD_REGISTER_AGENT:
2220 		mutex_enter(&uctx->uctx_lock);
2221 		rc = umad_register(&req, uctx);
2222 		mutex_exit(&uctx->uctx_lock);
2223 		if (rc)
2224 			goto err1;
2225 
2226 		/* return agent ID to user */
2227 		rc = ddi_copyout(&req, (void *) arg, sizeof (req), mode);
2228 
2229 		if (rc) {
2230 			mutex_enter(&uctx->uctx_lock);
2231 			(void) umad_unregister(&req, uctx);
2232 			mutex_exit(&uctx->uctx_lock);
2233 
2234 			rc = EFAULT;
2235 			goto err1;
2236 		}
2237 		break;
2238 
2239 	case IB_USER_MAD_UNREGISTER_AGENT:
2240 		mutex_enter(&uctx->uctx_lock);
2241 		rc = umad_unregister(&req, uctx);
2242 		mutex_exit(&uctx->uctx_lock);
2243 		break;
2244 
2245 	default:
2246 		rc = DDI_FAILURE;
2247 	}
2248 
2249 
2250 err1:
2251 	return (rc);
2252 }
2253 
2254 /*
2255  * Get a new unique agent ID. The agent list is already locked. The
2256  * complexity is not ideal, but the number of agents should be small
2257  * (ie 2 or 3) so it shouldn't matter.
2258  */
2259 static int
umad_get_new_agent_id(umad_uctx_t * uctx)2260 umad_get_new_agent_id(umad_uctx_t *uctx)
2261 {
2262 	boolean_t found;
2263 	unsigned int agent_id;
2264 	llist_head_t *entry;
2265 
2266 	agent_id = 0;
2267 
2268 	ASSERT(MUTEX_HELD(&uctx->uctx_lock));
2269 
2270 	for (;;) {
2271 		found = B_FALSE;
2272 		list_for_each(entry, &uctx->uctx_agent_list) {
2273 			umad_agent_t *agent = entry->ptr;
2274 
2275 			if (agent_id == agent->agent_req.id) {
2276 				found = B_TRUE;
2277 				break;
2278 			}
2279 		}
2280 
2281 		if (! found)
2282 			break;
2283 
2284 		agent_id++;
2285 	}
2286 
2287 	return (agent_id);
2288 }
2289 
2290 /*
2291  * Function:
2292  *	umad_register
2293  * Input:
2294  *	req 	User registration request
2295  *	uctx	User context
2296  * Output:
2297  *	None
2298  * Returns:
2299  *	status
2300  * Called by:
2301  *	umad_ioctl
2302  * Description:
2303  *      Handles the registration of user agents from userspace.
2304  *      Each call will result in the creation of a new agent object for
2305  *      the given HCA/port.  If UMAD_CA_MAX_AGENTS has been reached then an
2306  *      error is raised.
2307  */
2308 static int
umad_register(struct ib_user_mad_reg_req * req,umad_uctx_t * uctx)2309 umad_register(struct ib_user_mad_reg_req *req, umad_uctx_t *uctx)
2310 {
2311 	int			rc = IBMF_SUCCESS;
2312 	umad_agent_t		*agent = NULL;
2313 	umad_port_info_t	*port;
2314 
2315 	/* check for valid QP */
2316 	if ((req->qpn != 0) && (req->qpn != 1)) {
2317 		rc = EINVAL;
2318 		goto err1;
2319 	}
2320 
2321 
2322 	ASSERT(MUTEX_HELD(&uctx->uctx_lock));
2323 
2324 	port = uctx->uctx_port;
2325 	ASSERT(port != NULL);
2326 
2327 	agent = umad_get_agent_by_class(uctx, req->mgmt_class);
2328 	if (agent != NULL)
2329 		return (IBMF_PORT_IN_USE);
2330 
2331 	agent = kmem_zalloc(sizeof (umad_agent_t), KM_SLEEP);
2332 	mutex_init(&agent->agent_lock, NULL, MUTEX_DRIVER, NULL);
2333 	cv_init(&agent->agent_cv, NULL, CV_DRIVER, NULL);
2334 
2335 	agent->agent_req = *req;
2336 	agent->agent_uctx = uctx;
2337 
2338 	llist_head_init(&agent->agent_list, agent);
2339 
2340 	agent->agent_req.id = req->id = umad_get_new_agent_id(uctx);
2341 
2342 	rc = umad_register_agent(agent);
2343 	if (rc)
2344 		goto err1;
2345 
2346 	llist_add(&agent->agent_list, &uctx->uctx_agent_list);
2347 
2348 	return (0);
2349 
2350 err1:
2351 	if (rc) {
2352 		if (agent) {
2353 			cv_destroy(&agent->agent_cv);
2354 			mutex_destroy(&agent->agent_lock);
2355 			kmem_free(agent, sizeof (umad_agent_t));
2356 		}
2357 	}
2358 
2359 	return (rc);
2360 }
2361 
2362 /*
2363  * Function:
2364  *	umad_unregister
2365  * Input:
2366  *	req		- user unregister request
2367  *	info		- user context
2368  * Output:
2369  *	None
2370  * Returns:
2371  *	Status
2372  * Called by:
2373  *	umad_ioct
2374  * Description:
2375  *	Undoes registration.  Waits for pending operations before completing.
2376  */
2377 static int
umad_unregister(struct ib_user_mad_reg_req * req,umad_uctx_t * uctx)2378 umad_unregister(struct ib_user_mad_reg_req *req, umad_uctx_t *uctx)
2379 {
2380 	int			agent_id = req->id;
2381 	umad_agent_t		*agent;
2382 	int			rc;
2383 	genlist_entry_t		*entry;
2384 	struct ibmf_reg_info	*ibmf_info;
2385 	boolean_t		did_ibmf_unregister;
2386 	umad_port_info_t	*port;
2387 
2388 	ASSERT(MUTEX_HELD(&uctx->uctx_lock));
2389 
2390 	agent = umad_get_agent_by_id(uctx, agent_id);
2391 	if (agent == NULL) {
2392 		rc = EINVAL;
2393 		goto done;
2394 	}
2395 
2396 	mutex_enter(&agent->agent_lock);
2397 	while (agent->agent_outstanding_msgs != 0) {
2398 		agent->agent_flags |= UMAD_AGENT_UNREGISTERING;
2399 		cv_wait(&agent->agent_cv, &agent->agent_lock);
2400 	}
2401 	if (agent->agent_flags & UMAD_HANDLING_ASYNC)
2402 		agent->agent_reg->ibmf_reg_uctx = NULL;
2403 
2404 	mutex_exit(&agent->agent_lock);
2405 
2406 	/* Remove agent from the uctx list. */
2407 	llist_del(&agent->agent_list);
2408 
2409 	/* Get the IBMF registration information */
2410 	ibmf_info = agent->agent_reg;
2411 
2412 	mutex_enter(&ibmf_info->ibmf_reg_lock);
2413 
2414 	/* Remove the pending received MADs. */
2415 	mutex_enter(&uctx->uctx_recv_lock);
2416 	while ((entry = remove_genlist_head(&uctx->uctx_recv_list))) {
2417 		ib_umad_msg_t *msg;
2418 		ibmf_msg_t *ibmf_msg;
2419 
2420 		mutex_exit(&uctx->uctx_recv_lock);
2421 
2422 		msg = (ib_umad_msg_t *)entry->data;
2423 		ibmf_msg = msg->umad_msg_ibmf_msg;
2424 
2425 		rc = ibmf_free_msg(ibmf_info->ibmf_reg_handle, &ibmf_msg);
2426 		ASSERT(rc == IBMF_SUCCESS);
2427 
2428 		kmem_free(msg, sizeof (*msg));
2429 
2430 		mutex_enter(&uctx->uctx_recv_lock);
2431 	}
2432 	mutex_exit(&uctx->uctx_recv_lock);
2433 
2434 	/* If no more references, tear down the ibmf registration */
2435 	if (--ibmf_info->ibmf_reg_refcnt == 0) {
2436 		ibmf_info->ibmf_flags |= UMAD_IBMF_UNREGISTERING;
2437 		mutex_exit(&ibmf_info->ibmf_reg_lock);
2438 		/* Remove the callback */
2439 		rc = ibmf_tear_down_async_cb(ibmf_info->ibmf_reg_handle,
2440 		    IBMF_QP_HANDLE_DEFAULT, 0);
2441 #if defined(DEBUG)
2442 		if (rc) {
2443 			SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
2444 			    "umad_unregister: failed "
2445 			    "ibmf_tear_down_async_cb() error %d\n", rc);
2446 		}
2447 #endif
2448 
2449 		/* Remove the pending received MADs. */
2450 		mutex_enter(&uctx->uctx_recv_lock);
2451 		while ((entry = remove_genlist_head(&uctx->uctx_recv_list))) {
2452 			ib_umad_msg_t *msg;
2453 			ibmf_msg_t *ibmf_msg;
2454 
2455 			mutex_exit(&uctx->uctx_recv_lock);
2456 
2457 			msg = (ib_umad_msg_t *)entry->data;
2458 			ibmf_msg = msg->umad_msg_ibmf_msg;
2459 
2460 			rc = ibmf_free_msg(ibmf_info->ibmf_reg_handle,
2461 			    &ibmf_msg);
2462 			ASSERT(rc == IBMF_SUCCESS);
2463 
2464 			kmem_free(msg, sizeof (*msg));
2465 
2466 			mutex_enter(&uctx->uctx_recv_lock);
2467 		}
2468 		mutex_exit(&uctx->uctx_recv_lock);
2469 
2470 
2471 		/* unregister from IBMF */
2472 		rc = ibmf_unregister(&ibmf_info->ibmf_reg_handle, 0);
2473 #if defined(DEBUG)
2474 		if (rc) {
2475 			SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
2476 			    "umad_unregister: failed "
2477 			    "ibmf_unregister() error %d\n", rc);
2478 		}
2479 #endif
2480 		mutex_enter(&ibmf_info->ibmf_reg_lock);
2481 		ibmf_info->ibmf_flags &= ~UMAD_IBMF_UNREGISTERING;
2482 		cv_signal(&ibmf_info->ibmf_cv);
2483 		mutex_exit(&ibmf_info->ibmf_reg_lock);
2484 		did_ibmf_unregister = B_TRUE;
2485 	} else {
2486 		mutex_exit(&ibmf_info->ibmf_reg_lock);
2487 		did_ibmf_unregister = B_FALSE;
2488 	}
2489 
2490 	if (did_ibmf_unregister) {
2491 		llist_head_t *entry;
2492 		struct ibmf_reg_info *ibmf_entry = NULL;
2493 #if defined(DEBUG)
2494 		boolean_t found = B_FALSE;
2495 #endif
2496 
2497 		port = uctx->uctx_port;
2498 		mutex_enter(&port->port_lock);
2499 		list_for_each(entry, &port->port_ibmf_regs) {
2500 			ibmf_entry = entry->ptr;
2501 
2502 			if (ibmf_info == ibmf_entry) {
2503 #if defined(DEBUG)
2504 				found = B_TRUE;
2505 #endif
2506 				break;
2507 			}
2508 		}
2509 		ASSERT(found);
2510 		llist_del(entry);
2511 		kmem_free(entry, sizeof (*entry));
2512 
2513 		mutex_exit(&port->port_lock);
2514 		/* Release the registration memory */
2515 		kmem_free(ibmf_info, sizeof (*ibmf_info));
2516 	}
2517 	agent->agent_uctx = NULL;
2518 	cv_destroy(&agent->agent_cv);
2519 	mutex_destroy(&agent->agent_lock);
2520 	kmem_free(agent, sizeof (*agent));
2521 
2522 	rc = 0;
2523 
2524 done:
2525 	return (rc);
2526 }
2527 
2528 
2529 /*
2530  * Function:
2531  *      umad_poll
2532  * Input:
2533  *	dev             device
2534  *	events          which events
2535  *	anyyet          any events yet?
2536  * Output:
2537  *	reventsp        return of which events
2538  *	phpp            poll head pointer
2539  * Returns:
2540  *      return 0 for success, or the appropriate error number
2541  * Called by:
2542  *	Device poll framework
2543  * Description:
2544  *	Fails for ISSM device. POLLOUT is always true. POLLIN or POLLRDNORM
2545  *	is true if a message has been queued for the user context receive list.
2546  */
2547 static int
umad_poll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)2548 umad_poll(
2549 	dev_t dev,
2550 	short events,
2551 	int anyyet,
2552 	short *reventsp,
2553 	struct pollhead **phpp)
2554 {
2555 	int			rc = 0;
2556 	int			minor;
2557 	umad_uctx_t		*uctx;
2558 	umad_port_info_t	*port;
2559 	umad_info_t		*info;
2560 	short			revent = 0;
2561 
2562 	info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
2563 	if (info == NULL) {
2564 		rc = ENXIO;
2565 		goto err1;
2566 	}
2567 
2568 	/* lookup the node and port #s */
2569 	minor = getminor(dev);
2570 
2571 	if (ISSM_MINOR(minor)) {
2572 		rc = ENXIO;
2573 		goto err1;
2574 	}
2575 
2576 	mutex_enter(&info->info_mutex);
2577 	uctx = info->info_uctx[GET_UCTX(minor)];
2578 	mutex_exit(&info->info_mutex);
2579 	ASSERT(uctx != NULL);
2580 	port = uctx->uctx_port;
2581 	ASSERT(port != NULL);
2582 
2583 	/*
2584 	 * Always signal ready for POLLOUT / POLLWRNORM.
2585 	 * Signal for POLLIN / POLLRDNORM whenever there is something in
2586 	 * the receive list.
2587 	 */
2588 	if (events & POLLOUT) {
2589 		revent = POLLOUT;
2590 	} else if (events & (POLLIN | POLLRDNORM)) {
2591 		mutex_enter(&uctx->uctx_recv_lock);
2592 		if (! genlist_empty(&uctx->uctx_recv_list)) {
2593 			revent |=  POLLIN | POLLRDNORM;
2594 		}
2595 		mutex_exit(&uctx->uctx_recv_lock);
2596 	}
2597 
2598 	if (revent == 0) {
2599 		if (! anyyet)
2600 			*phpp = &uctx->uctx_pollhead;
2601 	}
2602 
2603 	*reventsp = revent;
2604 err1:
2605 
2606 	return (rc);
2607 }
2608 
2609 /*
2610  * Function:
2611  *     umad_unsolicited_cb
2612  * Input:
2613  *	ibmf_handle     - handle to ibmf
2614  *      msgp            -  The incoming SM MAD
2615  *      args            -  umad_port_info_t object that the MAD came in on
2616  * Output:
2617  *	None
2618  * Returns:
2619  *      none
2620  * Called by:
2621  *	IBMF from below
2622  * Description:
2623  *      Callback function (ibmf_msg_cb_t) that is invoked when the
2624  *      ibmf receives a response MAD and passes it up if requested.
2625  *      The message is tossed if no one wants it or queued if requested.
2626  */
2627 static void
umad_unsolicited_cb(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)2628 umad_unsolicited_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
2629 {
2630 	struct ibmf_reg_info *ibmf_info = (struct ibmf_reg_info *)args;
2631 	struct umad_agent_s *agent;
2632 	ib_mad_hdr_t *mad_hdr;
2633 	int rc;
2634 
2635 #if defined(__lint)
2636 	ibmf_handle = 0;
2637 #endif
2638 
2639 	ASSERT(msgp->im_msgbufs_send.im_bufs_mad_hdr == NULL);
2640 	ASSERT(msgp->im_msgbufs_send.im_bufs_cl_data == NULL);
2641 	ASSERT(msgp->im_msgbufs_send.im_bufs_cl_data_len == 0);
2642 
2643 	/* Apply the filters to this MAD. */
2644 	mad_hdr = msgp->im_msgbufs_recv.im_bufs_mad_hdr;
2645 
2646 	mutex_enter(&ibmf_info->ibmf_reg_lock);
2647 
2648 	/*
2649 	 * Make sure the user context that was receiving the unsolicited
2650 	 * messages is still present.
2651 	 */
2652 	if (ibmf_info->ibmf_reg_uctx == NULL)
2653 		goto reject;
2654 
2655 	mutex_enter(&ibmf_info->ibmf_reg_uctx->uctx_lock);
2656 	agent = umad_get_agent_by_class(ibmf_info->ibmf_reg_uctx,
2657 	    mad_hdr->MgmtClass);
2658 	mutex_exit(&ibmf_info->ibmf_reg_uctx->uctx_lock);
2659 	if (agent == NULL)
2660 		goto reject;
2661 
2662 	if (mad_hdr->ClassVersion != agent->agent_req.mgmt_class_version)
2663 		goto reject;
2664 
2665 	if (! is_supported_mad_method(mad_hdr->R_Method & MAD_METHOD_MASK,
2666 	    agent->agent_req.method_mask))
2667 		goto reject;
2668 
2669 	if (umad_queue_mad_msg(agent, msgp))
2670 		goto reject;
2671 
2672 	mutex_exit(&ibmf_info->ibmf_reg_lock);
2673 	return;
2674 
2675 reject:
2676 	rc = ibmf_free_msg(ibmf_info->ibmf_reg_handle, &msgp);
2677 	ASSERT(rc == IBMF_SUCCESS);
2678 
2679 	mutex_exit(&ibmf_info->ibmf_reg_lock);
2680 }
2681 
2682 #if defined(__lint)
2683 /*
2684  * This is needed because rdma/ib_verbs.h and sol_ofs/sol_ofs_common.h
2685  * both implement static functions.  Not all of those functions are
2686  * used by sol_umad, but lint doesn't like seeing static function that
2687  * are defined but not used.
2688  */
2689 void
lint_function(llist_head_t * a,llist_head_t * b)2690 lint_function(llist_head_t *a, llist_head_t *b)
2691 {
2692 	(void) llist_is_last(a, b);
2693 	llist_add_tail(a, b);
2694 	(void) ib_width_enum_to_int(IB_WIDTH_1X);
2695 }
2696 #endif
2697