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