1448bf859SLida.Horn /*
2448bf859SLida.Horn  * CDDL HEADER START
3448bf859SLida.Horn  *
4448bf859SLida.Horn  * The contents of this file are subject to the terms of the
5448bf859SLida.Horn  * Common Development and Distribution License (the "License").
6448bf859SLida.Horn  * You may not use this file except in compliance with the License.
7448bf859SLida.Horn  *
8448bf859SLida.Horn  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9448bf859SLida.Horn  * or http://www.opensolaris.org/os/licensing.
10448bf859SLida.Horn  * See the License for the specific language governing permissions
11448bf859SLida.Horn  * and limitations under the License.
12448bf859SLida.Horn  *
13448bf859SLida.Horn  * When distributing Covered Code, include this CDDL HEADER in each
14448bf859SLida.Horn  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15448bf859SLida.Horn  * If applicable, add the following below this CDDL HEADER, with the
16448bf859SLida.Horn  * fields enclosed by brackets "[]" replaced with your own identifying
17448bf859SLida.Horn  * information: Portions Copyright [yyyy] [name of copyright owner]
18448bf859SLida.Horn  *
19448bf859SLida.Horn  * CDDL HEADER END
20448bf859SLida.Horn  */
21448bf859SLida.Horn 
22448bf859SLida.Horn /*
23448bf859SLida.Horn  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24*80d5689fSPatrick Mooney  * Copyright 2017 Joyent, Inc.
25448bf859SLida.Horn  */
26448bf859SLida.Horn 
27448bf859SLida.Horn 
28448bf859SLida.Horn /*
29448bf859SLida.Horn  * sol_umad.c
30448bf859SLida.Horn  *
31448bf859SLida.Horn  * ofuv user MAD kernel agent module
32448bf859SLida.Horn  *
33448bf859SLida.Horn  * Enables functionality of the OFED 1.3 Linux based MAD application code.
34448bf859SLida.Horn  */
35448bf859SLida.Horn 
36448bf859SLida.Horn #include <sys/open.h>
37448bf859SLida.Horn #include <sys/stat.h>
38448bf859SLida.Horn #include <sys/file.h>
39448bf859SLida.Horn #include <sys/conf.h>
40448bf859SLida.Horn #include <sys/modctl.h>
41448bf859SLida.Horn #include <sys/sysmacros.h>
42448bf859SLida.Horn #include <sys/ib/ibtl/ibti.h>
43448bf859SLida.Horn #include <sys/ib/mgt/ibmf/ibmf.h>
44448bf859SLida.Horn #include <sys/ib/mgt/ibmf/ibmf_rmpp.h>
45448bf859SLida.Horn 
46448bf859SLida.Horn #include <sys/types.h>
47448bf859SLida.Horn #include <sys/ib/clients/of/ofed_kernel.h>
48448bf859SLida.Horn #include <sys/ib/clients/of/sol_ofs/sol_ofs_common.h>
49448bf859SLida.Horn #include <sys/ib/clients/of/rdma/ib_user_mad.h>
50448bf859SLida.Horn #include <sys/ib/clients/of/sol_umad/sol_umad.h>
51448bf859SLida.Horn #include <sys/policy.h>
52448bf859SLida.Horn #include <sys/priv_const.h>	/* sys/policy.h should include this, but... */
53448bf859SLida.Horn 
54448bf859SLida.Horn 
55448bf859SLida.Horn #define	MAX_NAME_LEN	32
56448bf859SLida.Horn 
57448bf859SLida.Horn #if defined(DEBUG)
58448bf859SLida.Horn static char *sol_umad_dbg_str = "sol_umad";
59448bf859SLida.Horn #endif
60448bf859SLida.Horn 
61448bf859SLida.Horn /* Local definitions */
62448bf859SLida.Horn static void *umad_statep;
63448bf859SLida.Horn 
64448bf859SLida.Horn static struct cb_ops umad_cb_ops = {
65448bf859SLida.Horn 	.cb_open			= umad_open,
66448bf859SLida.Horn 	.cb_close			= umad_close,
67448bf859SLida.Horn 	.cb_strategy			= nodev,
68448bf859SLida.Horn 	.cb_print			= nodev,
69448bf859SLida.Horn 	.cb_dump			= nodev,
70448bf859SLida.Horn 	.cb_read			= umad_read,
71448bf859SLida.Horn 	.cb_write			= umad_write,
72448bf859SLida.Horn 	.cb_ioctl			= umad_ioctl,
73448bf859SLida.Horn 	.cb_devmap			= nodev,
74448bf859SLida.Horn 	.cb_mmap			= nodev,
75448bf859SLida.Horn 	.cb_segmap			= nodev,
76448bf859SLida.Horn 	.cb_chpoll			= umad_poll,
77448bf859SLida.Horn 	.cb_prop_op			= umad_prop_op,
78448bf859SLida.Horn 	.cb_str				= NULL,
79448bf859SLida.Horn 	.cb_flag			= D_NEW | D_MP,
80448bf859SLida.Horn 	.cb_rev				= CB_REV,
81448bf859SLida.Horn 	.cb_aread			= nodev,
82448bf859SLida.Horn 	.cb_awrite			= nodev
83448bf859SLida.Horn };
84448bf859SLida.Horn 
85448bf859SLida.Horn static struct dev_ops umad_dev_ops = {
86448bf859SLida.Horn 	.devo_rev			= DEVO_REV,
87448bf859SLida.Horn 	.devo_refcnt			= 0,
88448bf859SLida.Horn 	.devo_getinfo			= umad_getinfo,
89448bf859SLida.Horn 	.devo_identify			= nulldev,
90448bf859SLida.Horn 	.devo_probe			= nulldev,
91448bf859SLida.Horn 	.devo_attach			= umad_attach,
92448bf859SLida.Horn 	.devo_detach			= umad_detach,
93448bf859SLida.Horn 	.devo_reset			= nodev,
94448bf859SLida.Horn 	.devo_cb_ops			= &umad_cb_ops,
95448bf859SLida.Horn 	.devo_bus_ops			= NULL,
96448bf859SLida.Horn 	.devo_power			= nodev,
97448bf859SLida.Horn 	.devo_quiesce			= ddi_quiesce_not_needed
98448bf859SLida.Horn };
99448bf859SLida.Horn 
100448bf859SLida.Horn static struct modldrv umad_modldrv = {
101448bf859SLida.Horn 	.drv_modops			= &mod_driverops,
102448bf859SLida.Horn 	.drv_linkinfo			= "Solaris IB user MAD kernel driver",
103448bf859SLida.Horn 	.drv_dev_ops			= &umad_dev_ops
104448bf859SLida.Horn };
105448bf859SLida.Horn 
106448bf859SLida.Horn static struct modlinkage modlinkage = {
107448bf859SLida.Horn 	.ml_rev				= MODREV_1,
108448bf859SLida.Horn 	.ml_linkage = {
109448bf859SLida.Horn 		[0]			= &umad_modldrv,
110448bf859SLida.Horn 		[1]			= NULL,
111448bf859SLida.Horn 	}
112448bf859SLida.Horn };
113448bf859SLida.Horn 
114448bf859SLida.Horn static ibt_clnt_modinfo_t ibt_clnt_modinfo = {
115448bf859SLida.Horn 	.mi_ibt_version			= IBTI_V_CURR,
116448bf859SLida.Horn 	.mi_clnt_class			= IBT_USER,
117448bf859SLida.Horn 	.mi_async_handler		= umad_async_handler,
118448bf859SLida.Horn 	.mi_reserved			= NULL,
119448bf859SLida.Horn 	.mi_clnt_name			= "sol_umad"
120448bf859SLida.Horn };
121448bf859SLida.Horn 
122448bf859SLida.Horn #define	MAX_MAD_TO_IBMF_MAPPINGS	4 /* Max of 4 MADs to 1 IBMF */
123448bf859SLida.Horn const struct ibmf_class_to_mad_type {
124448bf859SLida.Horn 	enum _ibmf_client_type_t	ibmf_class;
125448bf859SLida.Horn 	uint8_t				mad_types[MAX_MAD_TO_IBMF_MAPPINGS];
126448bf859SLida.Horn } ibmf_class_to_mad_types[] = {
127448bf859SLida.Horn 	{SUBN_MANAGER,
128448bf859SLida.Horn 	    {MAD_MGMT_CLASS_SUBN_LID_ROUTED,
129448bf859SLida.Horn 	    MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE,
130448bf859SLida.Horn 	    0}},
131448bf859SLida.Horn 	{0,
132448bf859SLida.Horn 	{0}}
133448bf859SLida.Horn };
134448bf859SLida.Horn 
135448bf859SLida.Horn const enum _ibmf_client_type_t umad_type_to_ibmf_class[256] = {
136448bf859SLida.Horn 	0,				/* 0x00 Reserved */
137448bf859SLida.Horn 	SUBN_MANAGER,			/* 0x01 CLASS_SUBN_LID_ROUTED */
138448bf859SLida.Horn 	0,				/* 0x02 Reserved */
139448bf859SLida.Horn 	SUBN_ADM_AGENT,			/* 0x03 CLASS_SUBN_ADM */
140448bf859SLida.Horn 	PERF_MANAGER,			/* 0x04 CLASS_PERF_MGMT */
141448bf859SLida.Horn 	BM_AGENT, 			/* 0x05 CLASS_BM */
142448bf859SLida.Horn 	DEV_MGT_AGENT,			/* 0x06 CLASS_DEVICE_MGMT */
143448bf859SLida.Horn 	COMM_MGT_MANAGER_AGENT,		/* 0x07 CLASS_CM */
144448bf859SLida.Horn 	SNMP_MANAGER_AGENT,		/* 0x08 CLASS_SNMP */
145448bf859SLida.Horn 
146448bf859SLida.Horn 	VENDOR_09_MANAGER_AGENT,	/* 0x09 */
147448bf859SLida.Horn 	VENDOR_0A_MANAGER_AGENT,	/* 0x0A */
148448bf859SLida.Horn 	VENDOR_0B_MANAGER_AGENT,	/* 0x0B */
149448bf859SLida.Horn 	VENDOR_0C_MANAGER_AGENT,	/* 0x0C */
150448bf859SLida.Horn 	VENDOR_0D_MANAGER_AGENT,	/* 0x0D */
151448bf859SLida.Horn 	VENDOR_0E_MANAGER_AGENT,	/* 0x0E */
152448bf859SLida.Horn 	VENDOR_0F_MANAGER_AGENT,	/* 0x0F */
153448bf859SLida.Horn 
154448bf859SLida.Horn 	APPLICATION_10_MANAGER_AGENT,	/* 0x10 */
155448bf859SLida.Horn 	APPLICATION_11_MANAGER_AGENT,	/* 0x11 */
156448bf859SLida.Horn 	APPLICATION_12_MANAGER_AGENT,	/* 0x12 */
157448bf859SLida.Horn 	APPLICATION_13_MANAGER_AGENT,	/* 0x13 */
158448bf859SLida.Horn 	APPLICATION_14_MANAGER_AGENT,	/* 0x14 */
159448bf859SLida.Horn 	APPLICATION_15_MANAGER_AGENT,	/* 0x15 */
160448bf859SLida.Horn 	APPLICATION_16_MANAGER_AGENT,	/* 0x16 */
161448bf859SLida.Horn 	APPLICATION_17_MANAGER_AGENT,	/* 0x17 */
162448bf859SLida.Horn 	APPLICATION_18_MANAGER_AGENT,	/* 0x18 */
163448bf859SLida.Horn 	APPLICATION_19_MANAGER_AGENT,	/* 0x19 */
164448bf859SLida.Horn 	APPLICATION_1A_MANAGER_AGENT,	/* 0x1A */
165448bf859SLida.Horn 	APPLICATION_1B_MANAGER_AGENT,	/* 0x1B */
166448bf859SLida.Horn 	APPLICATION_1C_MANAGER_AGENT,	/* 0x1C */
167448bf859SLida.Horn 	APPLICATION_1D_MANAGER_AGENT,	/* 0x1D */
168448bf859SLida.Horn 	APPLICATION_1E_MANAGER_AGENT,	/* 0x1E */
169448bf859SLida.Horn 	APPLICATION_1F_MANAGER_AGENT,	/* 0x1F */
170448bf859SLida.Horn 	APPLICATION_20_MANAGER_AGENT,	/* 0x20 */
171448bf859SLida.Horn 	APPLICATION_21_MANAGER_AGENT,	/* 0x21 */
172448bf859SLida.Horn 	APPLICATION_22_MANAGER_AGENT,	/* 0x22 */
173448bf859SLida.Horn 	APPLICATION_23_MANAGER_AGENT,	/* 0x23 */
174448bf859SLida.Horn 	APPLICATION_24_MANAGER_AGENT,	/* 0x24 */
175448bf859SLida.Horn 	APPLICATION_25_MANAGER_AGENT,	/* 0x25 */
176448bf859SLida.Horn 	APPLICATION_26_MANAGER_AGENT,	/* 0x26 */
177448bf859SLida.Horn 	APPLICATION_27_MANAGER_AGENT,	/* 0x27 */
178448bf859SLida.Horn 	APPLICATION_28_MANAGER_AGENT,	/* 0x28 */
179448bf859SLida.Horn 	APPLICATION_29_MANAGER_AGENT,	/* 0x29 */
180448bf859SLida.Horn 	APPLICATION_2A_MANAGER_AGENT,	/* 0x2A */
181448bf859SLida.Horn 	APPLICATION_2B_MANAGER_AGENT,	/* 0x2B */
182448bf859SLida.Horn 	APPLICATION_2C_MANAGER_AGENT,	/* 0x2C */
183448bf859SLida.Horn 	APPLICATION_2D_MANAGER_AGENT,	/* 0x2D */
184448bf859SLida.Horn 	APPLICATION_2E_MANAGER_AGENT,	/* 0x2E */
185448bf859SLida.Horn 	APPLICATION_2F_MANAGER_AGENT,	/* 0x2F */
186448bf859SLida.Horn 
187448bf859SLida.Horn 	VENDOR_30_MANAGER_AGENT,	/* 0x30 */
188448bf859SLida.Horn 	VENDOR_31_MANAGER_AGENT,	/* 0x31 */
189448bf859SLida.Horn 	VENDOR_32_MANAGER_AGENT,	/* 0x32 */
190448bf859SLida.Horn 	VENDOR_33_MANAGER_AGENT,	/* 0x33 */
191448bf859SLida.Horn 	VENDOR_34_MANAGER_AGENT,	/* 0x34 */
192448bf859SLida.Horn 	VENDOR_35_MANAGER_AGENT,	/* 0x35 */
193448bf859SLida.Horn 	VENDOR_36_MANAGER_AGENT,	/* 0x36 */
194448bf859SLida.Horn 	VENDOR_37_MANAGER_AGENT,	/* 0x37 */
195448bf859SLida.Horn 	VENDOR_38_MANAGER_AGENT,	/* 0x38 */
196448bf859SLida.Horn 	VENDOR_39_MANAGER_AGENT,	/* 0x39 */
197448bf859SLida.Horn 	VENDOR_3A_MANAGER_AGENT,	/* 0x3A */
198448bf859SLida.Horn 	VENDOR_3B_MANAGER_AGENT,	/* 0x3B */
199448bf859SLida.Horn 	VENDOR_3C_MANAGER_AGENT,	/* 0x3C */
200448bf859SLida.Horn 	VENDOR_3D_MANAGER_AGENT,	/* 0x3D */
201448bf859SLida.Horn 	VENDOR_3E_MANAGER_AGENT,	/* 0x3E */
202448bf859SLida.Horn 	VENDOR_3F_MANAGER_AGENT,	/* 0x3F */
203448bf859SLida.Horn 	VENDOR_40_MANAGER_AGENT,
204448bf859SLida.Horn 	VENDOR_41_MANAGER_AGENT,
205448bf859SLida.Horn 	VENDOR_42_MANAGER_AGENT,
206448bf859SLida.Horn 	VENDOR_43_MANAGER_AGENT,
207448bf859SLida.Horn 	VENDOR_44_MANAGER_AGENT,
208448bf859SLida.Horn 	VENDOR_45_MANAGER_AGENT,
209448bf859SLida.Horn 	VENDOR_46_MANAGER_AGENT,
210448bf859SLida.Horn 	VENDOR_47_MANAGER_AGENT,
211448bf859SLida.Horn 	VENDOR_48_MANAGER_AGENT,
212448bf859SLida.Horn 	VENDOR_49_MANAGER_AGENT,
213448bf859SLida.Horn 	VENDOR_4A_MANAGER_AGENT,
214448bf859SLida.Horn 	VENDOR_4B_MANAGER_AGENT,
215448bf859SLida.Horn 	VENDOR_4C_MANAGER_AGENT,
216448bf859SLida.Horn 	VENDOR_4D_MANAGER_AGENT,
217448bf859SLida.Horn 	VENDOR_4E_MANAGER_AGENT,
218448bf859SLida.Horn 	VENDOR_4F_MANAGER_AGENT,
219448bf859SLida.Horn 
220448bf859SLida.Horn 	0,			/* 0x50 Reserved */
221448bf859SLida.Horn 	0,			/* 0x51 Reserved */
222448bf859SLida.Horn 	0,			/* 0x52 Reserved */
223448bf859SLida.Horn 	0,			/* 0x53 Reserved */
224448bf859SLida.Horn 	0,			/* 0x54 Reserved */
225448bf859SLida.Horn 	0,			/* 0x55 Reserved */
226448bf859SLida.Horn 	0,			/* 0x56 Reserved */
227448bf859SLida.Horn 	0,			/* 0x57 Reserved */
228448bf859SLida.Horn 	0,			/* 0x58 Reserved */
229448bf859SLida.Horn 	0,			/* 0x59 Reserved */
230448bf859SLida.Horn 	0,			/* 0x5A Reserved */
231448bf859SLida.Horn 	0,			/* 0x5B Reserved */
232448bf859SLida.Horn 	0,			/* 0x5C Reserved */
233448bf859SLida.Horn 	0,			/* 0x5D Reserved */
234448bf859SLida.Horn 	0,			/* 0x5E Reserved */
235448bf859SLida.Horn 	0,			/* 0x5F Reserved */
236448bf859SLida.Horn 	0,			/* 0x60 Reserved */
237448bf859SLida.Horn 	0,			/* 0x61 Reserved */
238448bf859SLida.Horn 	0,			/* 0x62 Reserved */
239448bf859SLida.Horn 	0,			/* 0x63 Reserved */
240448bf859SLida.Horn 	0,			/* 0x64 Reserved */
241448bf859SLida.Horn 	0,			/* 0x65 Reserved */
242448bf859SLida.Horn 	0,			/* 0x66 Reserved */
243448bf859SLida.Horn 	0,			/* 0x67 Reserved */
244448bf859SLida.Horn 	0,			/* 0x68 Reserved */
245448bf859SLida.Horn 	0,			/* 0x69 Reserved */
246448bf859SLida.Horn 	0,			/* 0x6A Reserved */
247448bf859SLida.Horn 	0,			/* 0x6B Reserved */
248448bf859SLida.Horn 	0,			/* 0x6C Reserved */
249448bf859SLida.Horn 	0,			/* 0x6D Reserved */
250448bf859SLida.Horn 	0,			/* 0x6E Reserved */
251448bf859SLida.Horn 	0,			/* 0x6F Reserved */
252448bf859SLida.Horn 	0,			/* 0x70 Reserved */
253448bf859SLida.Horn 	0,			/* 0x71 Reserved */
254448bf859SLida.Horn 	0,			/* 0x72 Reserved */
255448bf859SLida.Horn 	0,			/* 0x73 Reserved */
256448bf859SLida.Horn 	0,			/* 0x74 Reserved */
257448bf859SLida.Horn 	0,			/* 0x75 Reserved */
258448bf859SLida.Horn 	0,			/* 0x76 Reserved */
259448bf859SLida.Horn 	0,			/* 0x77 Reserved */
260448bf859SLida.Horn 	0,			/* 0x78 Reserved */
261448bf859SLida.Horn 	0,			/* 0x79 Reserved */
262448bf859SLida.Horn 	0,			/* 0x7A Reserved */
263448bf859SLida.Horn 	0,			/* 0x7B Reserved */
264448bf859SLida.Horn 	0,			/* 0x7C Reserved */
265448bf859SLida.Horn 	0,			/* 0x7D Reserved */
266448bf859SLida.Horn 	0,			/* 0x7E Reserved */
267448bf859SLida.Horn 	0,			/* 0x7F Reserved */
268448bf859SLida.Horn 	0,			/* 0x80 Reserved */
269448bf859SLida.Horn 
270448bf859SLida.Horn 	SUBN_MANAGER,		/* 0x81 CLASS_SUBN_DIRECT_ROUTE */
271448bf859SLida.Horn 
272448bf859SLida.Horn 	0,			/* 0x82 Reserved */
273448bf859SLida.Horn 	0,			/* 0x82 Reserved */
274448bf859SLida.Horn 	0,			/* 0x84 Reserved */
275448bf859SLida.Horn 	0,			/* 0x85 Reserved */
276448bf859SLida.Horn 	0,			/* 0x86 Reserved */
277448bf859SLida.Horn 	0,			/* 0x87 Reserved */
278448bf859SLida.Horn 	0,			/* 0x88 Reserved */
279448bf859SLida.Horn 	0,			/* 0x89 Reserved */
280448bf859SLida.Horn 	0,			/* 0x8A Reserved */
281448bf859SLida.Horn 	0,			/* 0x8B Reserved */
282448bf859SLida.Horn 	0,			/* 0x8C Reserved */
283448bf859SLida.Horn 	0,			/* 0x8D Reserved */
284448bf859SLida.Horn 	0,			/* 0x8E Reserved */
285448bf859SLida.Horn 	0,			/* 0x8f Reserved */
286448bf859SLida.Horn 	0,			/* 0x90 Reserved */
287448bf859SLida.Horn 	0,			/* 0x91 Reserved */
288448bf859SLida.Horn 	0,			/* 0x92 Reserved */
289448bf859SLida.Horn 	0,			/* 0x93 Reserved */
290448bf859SLida.Horn 	0,			/* 0x94 Reserved */
291448bf859SLida.Horn 	0,			/* 0x95 Reserved */
292448bf859SLida.Horn 	0,			/* 0x96 Reserved */
293448bf859SLida.Horn 	0,			/* 0x97 Reserved */
294448bf859SLida.Horn 	0,			/* 0x98 Reserved */
295448bf859SLida.Horn 	0,			/* 0x99 Reserved */
296448bf859SLida.Horn 	0,			/* 0x9A Reserved */
297448bf859SLida.Horn 	0,			/* 0x9B Reserved */
298448bf859SLida.Horn 	0,			/* 0x9C Reserved */
299448bf859SLida.Horn 	0,			/* 0x9D Reserved */
300448bf859SLida.Horn 	0,			/* 0x9E Reserved */
301448bf859SLida.Horn 	0,			/* 0x9F Reserved */
302448bf859SLida.Horn 	0,			/* 0xA0 Reserved */
303448bf859SLida.Horn 	0,			/* 0xA1 Reserved */
304448bf859SLida.Horn 	0,			/* 0xA2 Reserved */
305448bf859SLida.Horn 	0,			/* 0xA3 Reserved */
306448bf859SLida.Horn 	0,			/* 0xA4 Reserved */
307448bf859SLida.Horn 	0,			/* 0xA5 Reserved */
308448bf859SLida.Horn 	0,			/* 0xA6 Reserved */
309448bf859SLida.Horn 	0,			/* 0xA7 Reserved */
310448bf859SLida.Horn 	0,			/* 0xA8 Reserved */
311448bf859SLida.Horn 	0,			/* 0xA9 Reserved */
312448bf859SLida.Horn 	0,			/* 0xAA Reserved */
313448bf859SLida.Horn 	0,			/* 0xAB Reserved */
314448bf859SLida.Horn 	0,			/* 0xAC Reserved */
315448bf859SLida.Horn 	0,			/* 0xAD Reserved */
316448bf859SLida.Horn 	0,			/* 0xAE Reserved */
317448bf859SLida.Horn 	0,			/* 0xAF Reserved */
318448bf859SLida.Horn 	0,			/* 0xB0 Reserved */
319448bf859SLida.Horn 	0,			/* 0xB1 Reserved */
320448bf859SLida.Horn 	0,			/* 0xB2 Reserved */
321448bf859SLida.Horn 	0,			/* 0xB3 Reserved */
322448bf859SLida.Horn 	0,			/* 0xB4 Reserved */
323448bf859SLida.Horn 	0,			/* 0xB5 Reserved */
324448bf859SLida.Horn 	0,			/* 0xB6 Reserved */
325448bf859SLida.Horn 	0,			/* 0xB7 Reserved */
326448bf859SLida.Horn 	0,			/* 0xB8 Reserved */
327448bf859SLida.Horn 	0,			/* 0xB9 Reserved */
328448bf859SLida.Horn 	0,			/* 0xBA Reserved */
329448bf859SLida.Horn 	0,			/* 0xBB Reserved */
330448bf859SLida.Horn 	0,			/* 0xBC Reserved */
331448bf859SLida.Horn 	0,			/* 0xBD Reserved */
332448bf859SLida.Horn 	0,			/* 0xBE Reserved */
333448bf859SLida.Horn 	0,			/* 0xBF Reserved */
334448bf859SLida.Horn 	0,			/* 0xC0 Reserved */
335448bf859SLida.Horn 	0,			/* 0xC1 Reserved */
336448bf859SLida.Horn 	0,			/* 0xC2 Reserved */
337448bf859SLida.Horn 	0,			/* 0xC3 Reserved */
338448bf859SLida.Horn 	0,			/* 0xC4 Reserved */
339448bf859SLida.Horn 	0,			/* 0xC5 Reserved */
340448bf859SLida.Horn 	0,			/* 0xC6 Reserved */
341448bf859SLida.Horn 	0,			/* 0xC7 Reserved */
342448bf859SLida.Horn 	0,			/* 0xC8 Reserved */
343448bf859SLida.Horn 	0,			/* 0xC9 Reserved */
344448bf859SLida.Horn 	0,			/* 0xCA Reserved */
345448bf859SLida.Horn 	0,			/* 0xCB Reserved */
346448bf859SLida.Horn 	0,			/* 0xCC Reserved */
347448bf859SLida.Horn 	0,			/* 0xCD Reserved */
348448bf859SLida.Horn 	0,			/* 0xCE Reserved */
349448bf859SLida.Horn 	0,			/* 0xCF Reserved */
350448bf859SLida.Horn 	0,			/* 0xD0 Reserved */
351448bf859SLida.Horn 	0,			/* 0xD1 Reserved */
352448bf859SLida.Horn 	0,			/* 0xD2 Reserved */
353448bf859SLida.Horn 	0,			/* 0xD3 Reserved */
354448bf859SLida.Horn 	0,			/* 0xD4 Reserved */
355448bf859SLida.Horn 	0,			/* 0xD5 Reserved */
356448bf859SLida.Horn 	0,			/* 0xD6 Reserved */
357448bf859SLida.Horn 	0,			/* 0xD7 Reserved */
358448bf859SLida.Horn 	0,			/* 0xD8 Reserved */
359448bf859SLida.Horn 	0,			/* 0xD9 Reserved */
360448bf859SLida.Horn 	0,			/* 0xDA Reserved */
361448bf859SLida.Horn 	0,			/* 0xDB Reserved */
362448bf859SLida.Horn 	0,			/* 0xDC Reserved */
363448bf859SLida.Horn 	0,			/* 0xDD Reserved */
364448bf859SLida.Horn 	0,			/* 0xDE Reserved */
365448bf859SLida.Horn 	0,			/* 0xDF Reserved */
366448bf859SLida.Horn 	0,			/* 0xE0 Reserved */
367448bf859SLida.Horn 	0,			/* 0xE1 Reserved */
368448bf859SLida.Horn 	0,			/* 0xE2 Reserved */
369448bf859SLida.Horn 	0,			/* 0xE3 Reserved */
370448bf859SLida.Horn 	0,			/* 0xE4 Reserved */
371448bf859SLida.Horn 	0,			/* 0xE5 Reserved */
372448bf859SLida.Horn 	0,			/* 0xE6 Reserved */
373448bf859SLida.Horn 	0,			/* 0xE7 Reserved */
374448bf859SLida.Horn 	0,			/* 0xE8 Reserved */
375448bf859SLida.Horn 	0,			/* 0xE9 Reserved */
376448bf859SLida.Horn 	0,			/* 0xEA Reserved */
377448bf859SLida.Horn 	0,			/* 0xEB Reserved */
378448bf859SLida.Horn 	0,			/* 0xEC Reserved */
379448bf859SLida.Horn 	0,			/* 0xED Reserved */
380448bf859SLida.Horn 	0,			/* 0xEE Reserved */
381448bf859SLida.Horn 	0,			/* 0xEF Reserved */
382448bf859SLida.Horn 	0,			/* 0xF0 Reserved */
383448bf859SLida.Horn 	0,			/* 0xF1 Reserved */
384448bf859SLida.Horn 	0,			/* 0xF2 Reserved */
385448bf859SLida.Horn 	0,			/* 0xF3 Reserved */
386448bf859SLida.Horn 	0,			/* 0xF4 Reserved */
387448bf859SLida.Horn 	0,			/* 0xF5 Reserved */
388448bf859SLida.Horn 	0,			/* 0xF6 Reserved */
389448bf859SLida.Horn 	0,			/* 0xF7 Reserved */
390448bf859SLida.Horn 	0,			/* 0xF8 Reserved */
391448bf859SLida.Horn 	0,			/* 0xF9 Reserved */
392448bf859SLida.Horn 	0,			/* 0xFA Reserved */
393448bf859SLida.Horn 	0,			/* 0xFB Reserved */
394448bf859SLida.Horn 	0,			/* 0xFC Reserved */
395448bf859SLida.Horn 	0,			/* 0xFD Reserved */
396448bf859SLida.Horn 	0,			/* 0xFE Reserved */
397448bf859SLida.Horn 	0,			/* 0xFF Reserved */
398448bf859SLida.Horn };
399448bf859SLida.Horn 
400448bf859SLida.Horn /*
401448bf859SLida.Horn  * Function:
402448bf859SLida.Horn  *	umad_init_port_info
403448bf859SLida.Horn  * Input:
404448bf859SLida.Horn  *	info		- driver info
405448bf859SLida.Horn  *	hca		- hca info
406448bf859SLida.Horn  * Output:
407448bf859SLida.Horn  *	port		- port info
408448bf859SLida.Horn  * Returns:
409448bf859SLida.Horn  *	None
410448bf859SLida.Horn  * Called by:
411448bf859SLida.Horn  *	umad_init_hca_info
412448bf859SLida.Horn  * Description:
413448bf859SLida.Horn  *      - Associates an hca to a port.
414448bf859SLida.Horn  *	- Initializes user context list for the port passed in
415448bf859SLida.Horn  *	- Initializes mutex to protect the user context list
416448bf859SLida.Horn  */
417448bf859SLida.Horn static void
umad_init_port_info(const umad_hca_info_t * hca,umad_port_info_t * port)418448bf859SLida.Horn umad_init_port_info(const umad_hca_info_t *hca, umad_port_info_t *port)
419448bf859SLida.Horn {
420448bf859SLida.Horn 	port->port_hca = hca;
421448bf859SLida.Horn 	llist_head_init(&port->port_ibmf_regs, NULL);
422448bf859SLida.Horn 	mutex_init(&port->port_lock, NULL, MUTEX_DRIVER, NULL);
423448bf859SLida.Horn }
424448bf859SLida.Horn 
425448bf859SLida.Horn /*
426448bf859SLida.Horn  * Function:
427448bf859SLida.Horn  *	umad_release_hca_info
428448bf859SLida.Horn  * Input:
429448bf859SLida.Horn  *	hca		- hca info
430448bf859SLida.Horn  * Output:
431448bf859SLida.Horn  * Returns:
432448bf859SLida.Horn  *	None
433448bf859SLida.Horn  * Called by:
434448bf859SLida.Horn  *	- umad_init_hca_info in case of error
435448bf859SLida.Horn  *	- umad_init_driver_info in case of error
436448bf859SLida.Horn  *	- umad_context_destroyed in normal case
437448bf859SLida.Horn  * Description:
438448bf859SLida.Horn  *      - For every port associated with this hca destory the mutex assicated
439448bf859SLida.Horn  *        with the port and relese port info structure.
440448bf859SLida.Horn  *	- Closes hca handle and resets the GUID
441448bf859SLida.Horn  */
442448bf859SLida.Horn static void
umad_release_hca_info(umad_hca_info_t * hca)443448bf859SLida.Horn umad_release_hca_info(umad_hca_info_t *hca)
444448bf859SLida.Horn {
445448bf859SLida.Horn 	unsigned int j;
446448bf859SLida.Horn 	umad_port_info_t *port;
447448bf859SLida.Horn #if defined(DEBUG)
448448bf859SLida.Horn 	ibt_status_t rc;
449448bf859SLida.Horn #endif
450448bf859SLida.Horn 
451448bf859SLida.Horn 	if (hca->hca_ports) {
452448bf859SLida.Horn 		for (j = 0; j < hca->hca_nports; j++) {
453448bf859SLida.Horn 			port = &(hca->hca_ports[j]);
454448bf859SLida.Horn 			if (port->port_num)
455448bf859SLida.Horn 				mutex_destroy(&port->port_lock);
456448bf859SLida.Horn 		}
457448bf859SLida.Horn 		kmem_free(hca->hca_ports, hca->hca_nports *
458448bf859SLida.Horn 		    sizeof (umad_port_info_t));
459448bf859SLida.Horn 		hca->hca_ports = NULL;
460448bf859SLida.Horn 	}
461448bf859SLida.Horn 	if (hca->hca_handle) {
462448bf859SLida.Horn #if defined(DEBUG)
463448bf859SLida.Horn 		rc = ibt_close_hca(hca->hca_handle);
464448bf859SLida.Horn 		if (rc != IBT_SUCCESS) {
465448bf859SLida.Horn 			SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
466448bf859SLida.Horn 			    "umad_release_hca: ibt_close_hca() returned %d\n",
467448bf859SLida.Horn 			    rc);
468448bf859SLida.Horn 		}
469448bf859SLida.Horn #else
470448bf859SLida.Horn 		(void) ibt_close_hca(hca->hca_handle);
471448bf859SLida.Horn #endif
472448bf859SLida.Horn 		hca->hca_handle = 0;
473448bf859SLida.Horn 	}
474448bf859SLida.Horn 
475448bf859SLida.Horn 	hca->hca_guid = 0;
476448bf859SLida.Horn }
477448bf859SLida.Horn 
478448bf859SLida.Horn /*
479448bf859SLida.Horn  * Function:
480448bf859SLida.Horn  *	umad_init_hca_info
481448bf859SLida.Horn  * Input:
482448bf859SLida.Horn  *	info 	pointer to umad info instructure
483448bf859SLida.Horn  * Output:
484448bf859SLida.Horn  * 	hca	handle associated with this hca
485448bf859SLida.Horn  * Returns:
486448bf859SLida.Horn  *	IBT_SUCCESS
487448bf859SLida.Horn  *	IBT_HCA_IN_USE
488448bf859SLida.Horn  *	IBT_HCA_INVALID
489448bf859SLida.Horn  *	IBT_INVALID_PARAM
490448bf859SLida.Horn  * 	IBT_HCA_INVALID
491448bf859SLida.Horn  * Called by:
492448bf859SLida.Horn  *	- umad_init_driver_info in case of error
493448bf859SLida.Horn  * Description:
494448bf859SLida.Horn  *	- It calls ibt_open_hca to get handle associated wit this hca
495448bf859SLida.Horn  *	- Determines how many port this hca has by calling ibt_query_hca
496448bf859SLida.Horn  *	- Allocates space for each port associated with this hca.
497448bf859SLida.Horn  *	- For every port it calls umad_init_port_info with the hca port
498448bf859SLida.Horn  *        structure.
499448bf859SLida.Horn  *	- It assigns port # index starting at 1 (1-N, zero is reserved, means
500448bf859SLida.Horn  *	  it does not exist).
501448bf859SLida.Horn  */
502448bf859SLida.Horn static int
umad_init_hca_info(const umad_info_t * info,umad_hca_info_t * hca)503448bf859SLida.Horn umad_init_hca_info(const umad_info_t *info, umad_hca_info_t *hca)
504448bf859SLida.Horn {
505448bf859SLida.Horn 	int rc;
506448bf859SLida.Horn 	unsigned int j;
507448bf859SLida.Horn 	umad_port_info_t *port;
508448bf859SLida.Horn 
509448bf859SLida.Horn 	rc = ibt_open_hca(info->info_clnt_hdl, hca->hca_guid, &hca->hca_handle);
510448bf859SLida.Horn 	if (rc != IBT_SUCCESS)
511448bf859SLida.Horn 		goto error;
512448bf859SLida.Horn 
513448bf859SLida.Horn 	rc = ibt_query_hca(hca->hca_handle, &hca->hca_attr);
514448bf859SLida.Horn 	if (rc != IBT_SUCCESS)
515448bf859SLida.Horn 		goto error;
516448bf859SLida.Horn 
517448bf859SLida.Horn 	hca->hca_nports = hca->hca_attr.hca_nports;
518448bf859SLida.Horn 
519448bf859SLida.Horn 	hca->hca_ports =
520448bf859SLida.Horn 	    kmem_zalloc(sizeof (umad_port_info_t) * hca->hca_nports, KM_SLEEP);
521448bf859SLida.Horn 
522448bf859SLida.Horn 	/* Initialize ports structures. */
523448bf859SLida.Horn 	for (j = 0; j < hca->hca_nports; j++) {
524448bf859SLida.Horn 		port = &hca->hca_ports[j];
525448bf859SLida.Horn 		umad_init_port_info(hca, port);
526448bf859SLida.Horn 
527448bf859SLida.Horn 		/*
528448bf859SLida.Horn 		 * Note: A port number different than 0 means the port has been
529448bf859SLida.Horn 		 * initialized.
530448bf859SLida.Horn 		 */
531448bf859SLida.Horn 		port->port_num = j + 1;
532448bf859SLida.Horn 	}
533448bf859SLida.Horn 
534448bf859SLida.Horn error:
535448bf859SLida.Horn 	if (rc)
536448bf859SLida.Horn 		umad_release_hca_info(hca);
537448bf859SLida.Horn 
538448bf859SLida.Horn 	return (rc);
539448bf859SLida.Horn }
540448bf859SLida.Horn 
541448bf859SLida.Horn /*
542448bf859SLida.Horn  * Function:
543448bf859SLida.Horn  *	umad_init_driver_info
544448bf859SLida.Horn  * Output:
545448bf859SLida.Horn  *	info		- driver info
546448bf859SLida.Horn  * Returns:
547448bf859SLida.Horn  * 	IBT_SUCCESS
548448bf859SLida.Horn  *	IBT_INVALID_PARAM
549448bf859SLida.Horn  *	IBT_HCA_IN_USE
550448bf859SLida.Horn  *	IBT_HCA_INVALID
551448bf859SLida.Horn  *	IBT_INVALID_PARAM
552448bf859SLida.Horn  * Called by:
553448bf859SLida.Horn  *	umad_attach
554448bf859SLida.Horn  * Description:
555448bf859SLida.Horn  *	- Registers sol_umad instance with IBTF
556448bf859SLida.Horn  *      - Calls ibt_get_hca_list to get hca count
557448bf859SLida.Horn  *	- Allocates each hca and associate it with umad_info structure
558448bf859SLida.Horn  *	- For every hca it assign GUID which was returned by ibt_get_hca_list
559448bf859SLida.Horn  *        then calls umad_init_hca_info .
560448bf859SLida.Horn  *	- Error case undone what was done, which calls umad_release_hca_info
561448bf859SLida.Horn  */
562448bf859SLida.Horn static ibt_status_t
umad_init_driver_info(umad_info_t * info)563448bf859SLida.Horn umad_init_driver_info(umad_info_t *info)
564448bf859SLida.Horn {
565448bf859SLida.Horn 	ibt_status_t		rc;
566448bf859SLida.Horn #if defined(DEBUG)
567448bf859SLida.Horn 	ibt_status_t		rc2;
568448bf859SLida.Horn #endif
569448bf859SLida.Horn 	unsigned int i;
570448bf859SLida.Horn 	uint32_t		hca_count;
571448bf859SLida.Horn 	ib_guid_t		*hca_guids = NULL;
572448bf859SLida.Horn 	umad_hca_info_t		*hca;
573448bf859SLida.Horn 
574448bf859SLida.Horn 	info->info_hca_count 	= 0;
575448bf859SLida.Horn 	info->info_clnt_hdl	= NULL;
576448bf859SLida.Horn 	info->info_hcas		= NULL;
577448bf859SLida.Horn 
578448bf859SLida.Horn 	rc = ibt_attach(&ibt_clnt_modinfo, info->info_dip, info,
579448bf859SLida.Horn 	    &info->info_clnt_hdl);
580448bf859SLida.Horn 
581448bf859SLida.Horn 	if (rc != IBT_SUCCESS)
582448bf859SLida.Horn 		goto err1;
583448bf859SLida.Horn 
584448bf859SLida.Horn 	hca_count = info->info_hca_count = ibt_get_hca_list(&hca_guids);
585448bf859SLida.Horn 
586448bf859SLida.Horn 	if (hca_count == 0) {
587448bf859SLida.Horn 		rc = IBT_HCA_INVALID;
588448bf859SLida.Horn 		goto err2;
589448bf859SLida.Horn 	}
590448bf859SLida.Horn 
591448bf859SLida.Horn 	info->info_hcas = kmem_zalloc(sizeof (umad_hca_info_t) * hca_count,
592448bf859SLida.Horn 	    KM_SLEEP);
593448bf859SLida.Horn 
594448bf859SLida.Horn 	for (i = 0; i < hca_count; i++) {
595448bf859SLida.Horn 		hca = &info->info_hcas[i];
596448bf859SLida.Horn 
597448bf859SLida.Horn 		/* Note: A non zero guid means the hca has been allocated. */
598448bf859SLida.Horn 		hca->hca_guid = hca_guids[i];
599448bf859SLida.Horn 
600448bf859SLida.Horn 		rc = umad_init_hca_info(info, hca);
601448bf859SLida.Horn 
602448bf859SLida.Horn 		if (rc)
603448bf859SLida.Horn 			goto err3;
604448bf859SLida.Horn 	}
605448bf859SLida.Horn 
606448bf859SLida.Horn 	ibt_free_hca_list(hca_guids, hca_count);
607448bf859SLida.Horn 
608448bf859SLida.Horn 	return (0);
609448bf859SLida.Horn 
610448bf859SLida.Horn err3:
611448bf859SLida.Horn 	for (i = 0; i < info->info_hca_count; i++) {
612448bf859SLida.Horn 		hca = &info->info_hcas[i];
613448bf859SLida.Horn 
614448bf859SLida.Horn 		if (hca->hca_guid)
615448bf859SLida.Horn 			umad_release_hca_info(hca);
616448bf859SLida.Horn 	}
617448bf859SLida.Horn 	kmem_free(info->info_hcas,
618448bf859SLida.Horn 	    info->info_hca_count * sizeof (umad_hca_info_t));
619448bf859SLida.Horn 	info->info_hcas = NULL;
620448bf859SLida.Horn 
621448bf859SLida.Horn 	if (hca_guids)
622448bf859SLida.Horn 		ibt_free_hca_list(hca_guids, hca_count);
623448bf859SLida.Horn err2:
624448bf859SLida.Horn 
625448bf859SLida.Horn #if defined(DEBUG)
626448bf859SLida.Horn 	rc2 = ibt_detach(info->info_clnt_hdl);
627448bf859SLida.Horn 	if (rc2 != IBT_SUCCESS) {
628448bf859SLida.Horn 		SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
629448bf859SLida.Horn 		    "umad_init_driver_info: ibt_detach failed: %d\n", rc2);
630448bf859SLida.Horn 	}
631448bf859SLida.Horn #else
632448bf859SLida.Horn 	(void) ibt_detach(info->info_clnt_hdl);
633448bf859SLida.Horn #endif
634448bf859SLida.Horn 	info->info_clnt_hdl = NULL;
635448bf859SLida.Horn 
636448bf859SLida.Horn err1:
637448bf859SLida.Horn 	return (rc);
638448bf859SLida.Horn }
639448bf859SLida.Horn 
640448bf859SLida.Horn /*
641448bf859SLida.Horn  * Function:
642448bf859SLida.Horn  *	umad_context_destroy
643448bf859SLida.Horn  * Input:
644448bf859SLida.Horn  *	dip		- device info
645448bf859SLida.Horn  *	info		- driver info
646448bf859SLida.Horn  * Output:
647448bf859SLida.Horn  *	None
648448bf859SLida.Horn  * Returns:
649448bf859SLida.Horn  *	None
650448bf859SLida.Horn  * Called by:
651448bf859SLida.Horn  *	umad_attach
652448bf859SLida.Horn  *	umad_detach
653448bf859SLida.Horn  * Description:
654448bf859SLida.Horn  *	frees driver info resources
655448bf859SLida.Horn  */
656448bf859SLida.Horn static void
umad_context_destroy(dev_info_t * dip,umad_info_t * info)657448bf859SLida.Horn umad_context_destroy(dev_info_t *dip, umad_info_t *info)
658448bf859SLida.Horn {
659448bf859SLida.Horn 	unsigned int i;
660448bf859SLida.Horn 	unsigned int j;
661448bf859SLida.Horn 	size_t n;
662448bf859SLida.Horn 
663448bf859SLida.Horn 	for (i = 0; i < info->info_hca_count; i++) {
664448bf859SLida.Horn 		umad_hca_info_t	*hca = &info->info_hcas[i];
665448bf859SLida.Horn 
666448bf859SLida.Horn 		if (! hca->hca_guid)
667448bf859SLida.Horn 			continue;
668448bf859SLida.Horn 
669448bf859SLida.Horn 		for (j = 0; j < hca->hca_nports; j++) {
670448bf859SLida.Horn 			umad_port_info_t *port = &hca->hca_ports[j];
671448bf859SLida.Horn 			char name[MAX_NAME_LEN];
672448bf859SLida.Horn 
673448bf859SLida.Horn 			if (port->port_has_umad_minor_node) {
674448bf859SLida.Horn 				n = snprintf(name, sizeof (name),
675448bf859SLida.Horn 				    "umad%d", port->port_minor_name);
676448bf859SLida.Horn #if defined(DEBUG)
677448bf859SLida.Horn 				if (n > sizeof (name)) {
678448bf859SLida.Horn 					SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
679448bf859SLida.Horn 					    "umad_context_destroy:"
680448bf859SLida.Horn 					    " minor name \"%s\": is longer than"
681448bf859SLida.Horn 					    " %d characters!\n",
682448bf859SLida.Horn 					    name, MAX_NAME_LEN);
683448bf859SLida.Horn 				}
684448bf859SLida.Horn #endif
685448bf859SLida.Horn 
686448bf859SLida.Horn 				ddi_remove_minor_node(dip, name);
687448bf859SLida.Horn 			}
688448bf859SLida.Horn 
689448bf859SLida.Horn 			if (port->port_has_issm_minor_node) {
690448bf859SLida.Horn 				n = snprintf(name, sizeof (name),
691448bf859SLida.Horn 				    "issm%d", port->port_minor_name);
692448bf859SLida.Horn #if defined(DEBUG)
693448bf859SLida.Horn 				if (n > sizeof (name)) {
694448bf859SLida.Horn 					SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
695448bf859SLida.Horn 					    "umad_context_destroy:"
696448bf859SLida.Horn 					    " minor name \"%s\" is longer than"
697448bf859SLida.Horn 					    " %d characters!\n",
698448bf859SLida.Horn 					    name, MAX_NAME_LEN);
699448bf859SLida.Horn 				}
700448bf859SLida.Horn #endif
701448bf859SLida.Horn 				ddi_remove_minor_node(dip, name);
702448bf859SLida.Horn 			}
703448bf859SLida.Horn 		}
704448bf859SLida.Horn 
705448bf859SLida.Horn 		umad_release_hca_info(hca);
706448bf859SLida.Horn 	}
707448bf859SLida.Horn 
708448bf859SLida.Horn 	if (info->info_hcas) {
709448bf859SLida.Horn 		kmem_free(info->info_hcas,
710448bf859SLida.Horn 		    info->info_hca_count * sizeof (umad_hca_info_t));
711448bf859SLida.Horn 		info->info_hca_count = 0;
712448bf859SLida.Horn 		info->info_hcas = NULL;
713448bf859SLida.Horn 	}
714448bf859SLida.Horn 
715448bf859SLida.Horn 	if (info->info_clnt_hdl != NULL) {
716448bf859SLida.Horn 		(void) ibt_detach(info->info_clnt_hdl);
717448bf859SLida.Horn 		info->info_clnt_hdl = NULL;
718448bf859SLida.Horn 	}
719448bf859SLida.Horn 
720448bf859SLida.Horn 	mutex_destroy(&info->info_mutex);
721448bf859SLida.Horn }
722448bf859SLida.Horn 
723448bf859SLida.Horn /*
724448bf859SLida.Horn  * Function:
725448bf859SLida.Horn  *	_init
726448bf859SLida.Horn  * Input:
727448bf859SLida.Horn  *	None
728448bf859SLida.Horn  * Output:
729448bf859SLida.Horn  *	None
730448bf859SLida.Horn  * Returns:
731448bf859SLida.Horn  *	status
732448bf859SLida.Horn  * Called by:
733448bf859SLida.Horn  *	Framework
734448bf859SLida.Horn  * Description:
735448bf859SLida.Horn  *	driver initialization function
736448bf859SLida.Horn  *	inits debug tracing, river info and calls mod_install
737448bf859SLida.Horn  */
738448bf859SLida.Horn int
_init(void)739448bf859SLida.Horn _init(void)
740448bf859SLida.Horn {
741448bf859SLida.Horn 	int rc;
742448bf859SLida.Horn 
743448bf859SLida.Horn 	rc = ddi_soft_state_init(&umad_statep, sizeof (umad_info_t), 0);
744448bf859SLida.Horn 
745448bf859SLida.Horn 	if (rc != 0)
746448bf859SLida.Horn 		goto err;
747448bf859SLida.Horn 
748448bf859SLida.Horn 	rc = mod_install(&modlinkage);
749448bf859SLida.Horn 
750448bf859SLida.Horn 	if (rc != 0)
751448bf859SLida.Horn 		ddi_soft_state_fini(&umad_statep);
752448bf859SLida.Horn 
753448bf859SLida.Horn err:
754448bf859SLida.Horn 	return (rc);
755448bf859SLida.Horn }
756448bf859SLida.Horn 
757448bf859SLida.Horn /*
758448bf859SLida.Horn  * Function:
759448bf859SLida.Horn  *	_info
760448bf859SLida.Horn  * Input:
761448bf859SLida.Horn  *	None
762448bf859SLida.Horn  * Output:
763448bf859SLida.Horn  *	modinfop	Module information
764448bf859SLida.Horn  * Returns:
765448bf859SLida.Horn  *	status
766448bf859SLida.Horn  * Called by:
767448bf859SLida.Horn  *	Framework
768448bf859SLida.Horn  * Description:
769448bf859SLida.Horn  *	Provides module information
770448bf859SLida.Horn  */
771448bf859SLida.Horn int
_info(struct modinfo * modinfop)772448bf859SLida.Horn _info(struct modinfo *modinfop)
773448bf859SLida.Horn {
774448bf859SLida.Horn 	int rc;
775448bf859SLida.Horn 
776448bf859SLida.Horn 	rc = mod_info(&modlinkage, modinfop);
777448bf859SLida.Horn 
778448bf859SLida.Horn 	return (rc);
779448bf859SLida.Horn }
780448bf859SLida.Horn 
781448bf859SLida.Horn /*
782448bf859SLida.Horn  * Function:
783448bf859SLida.Horn  *	_fini
784448bf859SLida.Horn  * Input:
785448bf859SLida.Horn  *	None
786448bf859SLida.Horn  * Output:
787448bf859SLida.Horn  *	None
788448bf859SLida.Horn  * Returns:
789448bf859SLida.Horn  *	status
790448bf859SLida.Horn  * Called by:
791448bf859SLida.Horn  *	Framework
792448bf859SLida.Horn  * Description:
793448bf859SLida.Horn  *	Cleans up upon module unloading
794448bf859SLida.Horn  */
795448bf859SLida.Horn int
_fini(void)796448bf859SLida.Horn _fini(void)
797448bf859SLida.Horn {
798448bf859SLida.Horn 	int rc;
799448bf859SLida.Horn 
800448bf859SLida.Horn 	if ((rc = mod_remove(&modlinkage)) == 0)
801448bf859SLida.Horn 		ddi_soft_state_fini(&umad_statep);
802448bf859SLida.Horn 
803448bf859SLida.Horn 	return (rc);
804448bf859SLida.Horn }
805448bf859SLida.Horn 
806448bf859SLida.Horn /*
807448bf859SLida.Horn  * Function:
808448bf859SLida.Horn  *	umad_attach
809448bf859SLida.Horn  * Input:
810448bf859SLida.Horn  *	dip		device info
811448bf859SLida.Horn  *	cmd		DDI_ATTACH all others are invalid
812448bf859SLida.Horn  * Output:
813448bf859SLida.Horn  *	None
814448bf859SLida.Horn  * Returns:
815448bf859SLida.Horn  *	DDI_SUCCESS or DDI_FAILURE
816448bf859SLida.Horn  * Called by:
817448bf859SLida.Horn  *	Framwork
818448bf859SLida.Horn  * Description:
819448bf859SLida.Horn  *	Device attach routine
820448bf859SLida.Horn  */
821448bf859SLida.Horn static int
umad_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)822448bf859SLida.Horn umad_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
823448bf859SLida.Horn {
824448bf859SLida.Horn 	int			rc;
825448bf859SLida.Horn 	unsigned int i;
826448bf859SLida.Horn 	unsigned int j;
827448bf859SLida.Horn 	umad_hca_info_t		hca;
828448bf859SLida.Horn 	umad_info_t		*info;
829448bf859SLida.Horn 	char			name[MAX_NAME_LEN];
830448bf859SLida.Horn 	unsigned int minor_name;
831448bf859SLida.Horn 
832448bf859SLida.Horn 	switch (cmd) {
833448bf859SLida.Horn 	case DDI_ATTACH:
834448bf859SLida.Horn 		if (ddi_soft_state_zalloc(umad_statep, UMAD_INSTANCE)
835448bf859SLida.Horn 		    != DDI_SUCCESS)
836448bf859SLida.Horn 			goto err1;
837448bf859SLida.Horn 
838448bf859SLida.Horn 		info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
839448bf859SLida.Horn 		if (info == NULL)
840448bf859SLida.Horn 			goto err2;
841448bf859SLida.Horn 
842448bf859SLida.Horn 		info->info_dip = dip;
843448bf859SLida.Horn 		mutex_init(&info->info_mutex, NULL, MUTEX_DRIVER, NULL);
844448bf859SLida.Horn 
845448bf859SLida.Horn 		/* initialize our data and per HCA info */
846448bf859SLida.Horn 		rc = umad_init_driver_info(info);
847448bf859SLida.Horn 
848448bf859SLida.Horn 		if (rc != 0)
849448bf859SLida.Horn 			goto err3;
850448bf859SLida.Horn 
851448bf859SLida.Horn 		rc = ddi_prop_update_int(DDI_DEV_T_NONE, dip,
852448bf859SLida.Horn 		    "abi_version", IB_USER_MAD_ABI_VERSION);
853448bf859SLida.Horn 
854448bf859SLida.Horn 		if (rc != 0)
855448bf859SLida.Horn 			goto err3;
856448bf859SLida.Horn 
857448bf859SLida.Horn 		/*
858448bf859SLida.Horn 		 * create a minor node for each node/port pair
859448bf859SLida.Horn 		 * device names are consistent with OFA
860448bf859SLida.Horn 		 * conventions, e.g. umad0 for port 1 on the first HCA.
861448bf859SLida.Horn 		 */
862448bf859SLida.Horn 		minor_name = 0;
863448bf859SLida.Horn 		for (i = 0; i < info->info_hca_count; i++) {
864448bf859SLida.Horn 			hca = info->info_hcas[i];
865448bf859SLida.Horn 			for (j = 0; j < hca.hca_nports; j++) {
866448bf859SLida.Horn 				size_t n;
867448bf859SLida.Horn 				dev_t minor_dev;
868448bf859SLida.Horn 
869448bf859SLida.Horn 				umad_port_info_t *port = &hca.hca_ports[j];
870448bf859SLida.Horn 
871448bf859SLida.Horn 				port->port_minor_name = minor_name;
872448bf859SLida.Horn 
873448bf859SLida.Horn 				n = snprintf(name, sizeof (name), "umad%d",
874448bf859SLida.Horn 				    minor_name);
875448bf859SLida.Horn #if defined(DEBUG)
876448bf859SLida.Horn 				if (n > sizeof (name)) {
877448bf859SLida.Horn 					SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
878448bf859SLida.Horn 					    "umad_attach: "
879448bf859SLida.Horn 					    "name \"%s\" longer than %d!\n",
880448bf859SLida.Horn 					    name, MAX_NAME_LEN);
881448bf859SLida.Horn 				}
882448bf859SLida.Horn #endif
883448bf859SLida.Horn 				rc = ddi_create_minor_node(dip, name, S_IFCHR,
884448bf859SLida.Horn 				    GET_UMAD_MINOR(i, j), DDI_PSEUDO, 0);
885448bf859SLida.Horn 				if (rc != DDI_SUCCESS)
886448bf859SLida.Horn 					goto err3;
887448bf859SLida.Horn 
888448bf859SLida.Horn 				minor_dev = makedevice(ddi_driver_major(dip),
889448bf859SLida.Horn 				    GET_UMAD_MINOR(i, j));
890448bf859SLida.Horn 				rc = ddi_prop_update_int(minor_dev, dip,
891448bf859SLida.Horn 				    "vendor-id", hca.hca_attr.hca_vendor_id);
892448bf859SLida.Horn 				if (rc != DDI_SUCCESS)
893448bf859SLida.Horn 					goto err3;
894448bf859SLida.Horn 				rc = ddi_prop_update_int(minor_dev, dip,
895448bf859SLida.Horn 				    "device-id", hca.hca_attr.hca_device_id);
896448bf859SLida.Horn 				if (rc != DDI_SUCCESS)
897448bf859SLida.Horn 					goto err3;
898448bf859SLida.Horn 				rc = ddi_prop_update_int(minor_dev, dip,
899448bf859SLida.Horn 				    "hca-instance", i);
900448bf859SLida.Horn 				if (rc != DDI_SUCCESS)
901448bf859SLida.Horn 					goto err3;
902448bf859SLida.Horn 				rc = ddi_prop_update_int(minor_dev, dip,
903448bf859SLida.Horn 				    "port", j + 1);
904448bf859SLida.Horn 				if (rc != DDI_SUCCESS)
905448bf859SLida.Horn 					goto err3;
906448bf859SLida.Horn 
907448bf859SLida.Horn 				port->port_has_umad_minor_node = 1;
908448bf859SLida.Horn 
909448bf859SLida.Horn 				n = snprintf(name, sizeof (name), "issm%d",
910448bf859SLida.Horn 				    minor_name);
911448bf859SLida.Horn #if defined(DEBUG)
912448bf859SLida.Horn 				if (n > sizeof (name)) {
913448bf859SLida.Horn 					SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
914448bf859SLida.Horn 					    "umad_attach: "
915448bf859SLida.Horn 					    "name \"%s\" longer than %d!\n",
916448bf859SLida.Horn 					    name, MAX_NAME_LEN);
917448bf859SLida.Horn 				}
918448bf859SLida.Horn #endif
919448bf859SLida.Horn 				rc = ddi_create_minor_node(dip, name, S_IFCHR,
920448bf859SLida.Horn 				    GET_ISSM_MINOR(i, j), DDI_PSEUDO, 0);
921448bf859SLida.Horn 
922448bf859SLida.Horn 				if (rc != DDI_SUCCESS)
923448bf859SLida.Horn 					goto err3;
924448bf859SLida.Horn 
925448bf859SLida.Horn 				minor_dev = makedevice(ddi_driver_major(dip),
926448bf859SLida.Horn 				    GET_ISSM_MINOR(i, j));
927448bf859SLida.Horn 				rc = ddi_prop_update_int(minor_dev, dip,
928448bf859SLida.Horn 				    "vendor-id", hca.hca_attr.hca_vendor_id);
929448bf859SLida.Horn 				if (rc != DDI_SUCCESS)
930448bf859SLida.Horn 					goto err3;
931448bf859SLida.Horn 				rc = ddi_prop_update_int(minor_dev, dip,
932448bf859SLida.Horn 				    "device-id", hca.hca_attr.hca_device_id);
933448bf859SLida.Horn 				if (rc != DDI_SUCCESS)
934448bf859SLida.Horn 					goto err3;
935448bf859SLida.Horn 				rc = ddi_prop_update_int(minor_dev, dip,
936448bf859SLida.Horn 				    "hca-instance", i);
937448bf859SLida.Horn 				if (rc != DDI_SUCCESS)
938448bf859SLida.Horn 					goto err3;
939448bf859SLida.Horn 				rc = ddi_prop_update_int(minor_dev, dip,
940448bf859SLida.Horn 				    "port", j + 1);
941448bf859SLida.Horn 				if (rc != DDI_SUCCESS)
942448bf859SLida.Horn 					goto err3;
943448bf859SLida.Horn 
944448bf859SLida.Horn 				port->port_has_issm_minor_node = 1;
945448bf859SLida.Horn 				minor_name++;
946448bf859SLida.Horn 			}
947448bf859SLida.Horn 		}
948448bf859SLida.Horn 
949448bf859SLida.Horn 		ddi_report_dev(dip);
950448bf859SLida.Horn 		break;
951448bf859SLida.Horn 
952448bf859SLida.Horn 	default:
953448bf859SLida.Horn 		goto err1;
954448bf859SLida.Horn 	}
955448bf859SLida.Horn 
956448bf859SLida.Horn 	rc = DDI_SUCCESS;
957448bf859SLida.Horn 
958448bf859SLida.Horn 	return (rc);
959448bf859SLida.Horn 
960448bf859SLida.Horn err3:
961448bf859SLida.Horn 	umad_context_destroy(dip, info);
962448bf859SLida.Horn err2:
963448bf859SLida.Horn 	ddi_soft_state_free(umad_statep, UMAD_INSTANCE);
964448bf859SLida.Horn err1:
965448bf859SLida.Horn 	rc = DDI_FAILURE;
966448bf859SLida.Horn 
967448bf859SLida.Horn 	return (rc);
968448bf859SLida.Horn }
969448bf859SLida.Horn 
970448bf859SLida.Horn /*
971448bf859SLida.Horn  * Function:
972448bf859SLida.Horn  *	umad_detach
973448bf859SLida.Horn  * Input:
974448bf859SLida.Horn  *	dip		Device pointer
975448bf859SLida.Horn  *	cmd		DDI_DETACH all others are an error
976448bf859SLida.Horn  * Output:
977448bf859SLida.Horn  *	None
978448bf859SLida.Horn  * Returns:
979448bf859SLida.Horn  *	DDI_SUCCESS or DDI_FAILURE
980448bf859SLida.Horn  * Called by:
981448bf859SLida.Horn  *	Framework
982448bf859SLida.Horn  * Description:
983448bf859SLida.Horn  *	Used when a device is removed
984448bf859SLida.Horn  */
985448bf859SLida.Horn static int
umad_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)986448bf859SLida.Horn umad_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
987448bf859SLida.Horn {
988448bf859SLida.Horn 	int		rc = DDI_SUCCESS;
989448bf859SLida.Horn 	umad_info_t	*info;
990448bf859SLida.Horn 
991448bf859SLida.Horn 
992448bf859SLida.Horn 	switch (cmd) {
993448bf859SLida.Horn 	case DDI_DETACH:
994448bf859SLida.Horn 		info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
995448bf859SLida.Horn 		umad_context_destroy(dip, info);
996448bf859SLida.Horn 		ddi_soft_state_free(umad_statep, UMAD_INSTANCE);
997448bf859SLida.Horn 		break;
998448bf859SLida.Horn 
999448bf859SLida.Horn 	default:
1000448bf859SLida.Horn 		rc = DDI_FAILURE;
1001448bf859SLida.Horn 		break;
1002448bf859SLida.Horn 	}
1003448bf859SLida.Horn 
1004448bf859SLida.Horn 	return (rc);
1005448bf859SLida.Horn }
1006448bf859SLida.Horn 
1007448bf859SLida.Horn /*
1008448bf859SLida.Horn  * Function:
1009448bf859SLida.Horn  *	umad_getinfo
1010448bf859SLida.Horn  * Input:
1011448bf859SLida.Horn  *	dip	device pointer
1012448bf859SLida.Horn  *	cmd	DDI_INFO_DEVT2DEVINFO or DDI_INFO_DEV2INSTANCE
1013448bf859SLida.Horn  *	arg	Unused
1014448bf859SLida.Horn  * Output:
1015448bf859SLida.Horn  *	resultp	device pointer or device instance as per cmd
1016448bf859SLida.Horn  * Returns:
1017448bf859SLida.Horn  *	status
1018448bf859SLida.Horn  * Called by:
1019448bf859SLida.Horn  *	Framework
1020448bf859SLida.Horn  * Description:
1021448bf859SLida.Horn  *	Gets information about specific device
1022448bf859SLida.Horn  */
1023448bf859SLida.Horn static int
umad_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)1024448bf859SLida.Horn umad_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
1025448bf859SLida.Horn {
1026448bf859SLida.Horn 	int rc;
1027448bf859SLida.Horn 
1028448bf859SLida.Horn #if defined(__lint)
1029448bf859SLida.Horn 	extern void dummy2(void *);
1030448bf859SLida.Horn 
1031448bf859SLida.Horn 	dummy2(arg);
1032448bf859SLida.Horn #endif
1033448bf859SLida.Horn 
1034448bf859SLida.Horn 	switch (cmd) {
1035448bf859SLida.Horn 	case DDI_INFO_DEVT2DEVINFO:
1036448bf859SLida.Horn 		*resultp = (void *)dip;
1037448bf859SLida.Horn 		break;
1038448bf859SLida.Horn 
1039448bf859SLida.Horn 	case DDI_INFO_DEVT2INSTANCE:
1040448bf859SLida.Horn 		*resultp = (void *)UMAD_INSTANCE;
1041448bf859SLida.Horn 		rc = DDI_SUCCESS;
1042448bf859SLida.Horn 		break;
1043448bf859SLida.Horn 
1044448bf859SLida.Horn 	default:
1045448bf859SLida.Horn 		rc = DDI_FAILURE;
1046448bf859SLida.Horn 		break;
1047448bf859SLida.Horn 	}
1048448bf859SLida.Horn 
1049448bf859SLida.Horn 	return (rc);
1050448bf859SLida.Horn }
1051448bf859SLida.Horn 
1052448bf859SLida.Horn /*
1053448bf859SLida.Horn  * Function:
1054448bf859SLida.Horn  *	umad_prop_op
1055448bf859SLida.Horn  * Input:
1056448bf859SLida.Horn  *	dev		device
1057448bf859SLida.Horn  *	dip		device pointer
1058448bf859SLida.Horn  *	prop_op		which property operation
1059448bf859SLida.Horn  *	flags		property flags
1060448bf859SLida.Horn  *	name		proper name
1061448bf859SLida.Horn  * Output:
1062448bf859SLida.Horn  *	valuep		- property value
1063448bf859SLida.Horn  *	lengthp		- propery length
1064448bf859SLida.Horn  * Returns:
1065448bf859SLida.Horn  *	status
1066448bf859SLida.Horn  * Called by:
1067448bf859SLida.Horn  *	Framework
1068448bf859SLida.Horn  * Description:
1069448bf859SLida.Horn  *	Passes straight through to default ddi_prop_op()
1070448bf859SLida.Horn  */
1071448bf859SLida.Horn 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)1072448bf859SLida.Horn umad_prop_op(
1073448bf859SLida.Horn 	dev_t dev,
1074448bf859SLida.Horn 	dev_info_t *dip,
1075448bf859SLida.Horn 	ddi_prop_op_t prop_op,
1076448bf859SLida.Horn 	int flags,
1077448bf859SLida.Horn 	char *name,
1078448bf859SLida.Horn 	caddr_t valuep,
1079448bf859SLida.Horn 	int *lengthp)
1080448bf859SLida.Horn {
1081448bf859SLida.Horn 	int rc;
1082448bf859SLida.Horn 
1083448bf859SLida.Horn 	rc = ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp);
1084448bf859SLida.Horn 
1085448bf859SLida.Horn 	return (rc);
1086448bf859SLida.Horn }
1087448bf859SLida.Horn 
1088448bf859SLida.Horn 
1089448bf859SLida.Horn /* Returns an array of mad classes associated with IBMF class */
1090448bf859SLida.Horn static const uint8_t *
umad_get_mad_classes_by_ibmf_class(enum _ibmf_client_type_t ibmf_class)1091448bf859SLida.Horn umad_get_mad_classes_by_ibmf_class(enum _ibmf_client_type_t ibmf_class)
1092448bf859SLida.Horn {
1093448bf859SLida.Horn 	const struct ibmf_class_to_mad_type *entry;
1094448bf859SLida.Horn 
1095448bf859SLida.Horn 	for (entry = &ibmf_class_to_mad_types[0];
1096448bf859SLida.Horn 	    entry->ibmf_class != 0;
1097448bf859SLida.Horn 	    ++entry) {
1098448bf859SLida.Horn 		if (ibmf_class == entry->ibmf_class)
1099448bf859SLida.Horn 			return (entry->mad_types);
1100448bf859SLida.Horn 	}
1101448bf859SLida.Horn 	return (NULL);
1102448bf859SLida.Horn }
1103448bf859SLida.Horn 
1104448bf859SLida.Horn /* Returns an agent from its ID. */
1105448bf859SLida.Horn static umad_agent_t *
umad_get_agent_by_id(umad_uctx_t * uctx,uint32_t agent_id)1106448bf859SLida.Horn umad_get_agent_by_id(umad_uctx_t *uctx, uint32_t agent_id)
1107448bf859SLida.Horn {
1108448bf859SLida.Horn 	umad_agent_t *agent;
1109448bf859SLida.Horn 	llist_head_t *entry;
1110448bf859SLida.Horn 
1111448bf859SLida.Horn 	ASSERT(MUTEX_HELD(&uctx->uctx_lock));
1112448bf859SLida.Horn 
1113448bf859SLida.Horn 	/* Look for the agent */
1114448bf859SLida.Horn 	list_for_each(entry, &uctx->uctx_agent_list) {
1115448bf859SLida.Horn 		agent = entry->ptr;
1116448bf859SLida.Horn 
1117448bf859SLida.Horn 		if (agent_id == agent->agent_req.id)
1118448bf859SLida.Horn 			return (agent);
1119448bf859SLida.Horn 	}
1120448bf859SLida.Horn 
1121448bf859SLida.Horn 	return (NULL);
1122448bf859SLida.Horn }
1123448bf859SLida.Horn 
1124448bf859SLida.Horn /* Returns an agent from its MAD class. */
1125448bf859SLida.Horn static umad_agent_t *
umad_get_agent_by_class(umad_uctx_t * uctx,uint8_t agent_class)1126448bf859SLida.Horn umad_get_agent_by_class(umad_uctx_t *uctx, uint8_t agent_class)
1127448bf859SLida.Horn {
1128448bf859SLida.Horn 	umad_agent_t *agent;
1129448bf859SLida.Horn 	llist_head_t *entry;
1130448bf859SLida.Horn 
1131448bf859SLida.Horn 	ASSERT(MUTEX_HELD(&uctx->uctx_lock));
1132448bf859SLida.Horn 
1133448bf859SLida.Horn 	/* Look for the agent */
1134448bf859SLida.Horn 	list_for_each(entry, &uctx->uctx_agent_list) {
1135448bf859SLida.Horn 		agent = entry->ptr;
1136448bf859SLida.Horn 		if (agent_class == agent->agent_req.mgmt_class)
1137448bf859SLida.Horn 			return (agent);
1138448bf859SLida.Horn 	}
1139448bf859SLida.Horn 
1140448bf859SLida.Horn 	return (NULL);
1141448bf859SLida.Horn }
1142448bf859SLida.Horn 
1143448bf859SLida.Horn /*
1144448bf859SLida.Horn  * Register the agent with a class.
1145448bf859SLida.Horn  * mgmt_class is given from userspace.
1146448bf859SLida.Horn  */
1147448bf859SLida.Horn static int
umad_register_agent(struct umad_agent_s * agent)1148448bf859SLida.Horn umad_register_agent(struct umad_agent_s *agent)
1149448bf859SLida.Horn {
1150448bf859SLida.Horn 	uint8_t mgmt_class_num = agent->agent_req.mgmt_class;
1151448bf859SLida.Horn 	umad_port_info_t *port = agent->agent_uctx->uctx_port;
1152448bf859SLida.Horn 	const umad_hca_info_t *hca = port->port_hca;
1153448bf859SLida.Horn 	int rc;
1154448bf859SLida.Horn 	ibmf_register_info_t    reg_info	= {0, };
1155448bf859SLida.Horn 	ibmf_impl_caps_t	impl_caps	= {0, };
1156448bf859SLida.Horn 	uint_t	flags = 0;
1157448bf859SLida.Horn 	enum _ibmf_client_type_t ibmf_class;
1158448bf859SLida.Horn 	const uint8_t *umad_types;
1159448bf859SLida.Horn 	struct ibmf_reg_info *ibmf_info;
1160448bf859SLida.Horn 	llist_head_t *entry;
1161448bf859SLida.Horn 	boolean_t found = B_FALSE;
1162448bf859SLida.Horn 
1163448bf859SLida.Horn 	ASSERT(MUTEX_HELD(&agent->agent_uctx->uctx_lock));
1164448bf859SLida.Horn 
1165448bf859SLida.Horn 	/*
1166448bf859SLida.Horn 	 * Map MAD class to IBMF class
1167448bf859SLida.Horn 	 */
1168448bf859SLida.Horn 
1169448bf859SLida.Horn 	ibmf_class = umad_type_to_ibmf_class[mgmt_class_num];
1170448bf859SLida.Horn 
1171448bf859SLida.Horn 	/*
1172448bf859SLida.Horn 	 * It is is reserved, bail
1173448bf859SLida.Horn 	 */
1174448bf859SLida.Horn 	if (ibmf_class == 0) {
1175448bf859SLida.Horn 		rc = EINVAL;
1176448bf859SLida.Horn 		goto done;
1177448bf859SLida.Horn 	}
1178448bf859SLida.Horn 
1179448bf859SLida.Horn 	/* Check to see if any other mad classes also map to this IBMF class */
1180448bf859SLida.Horn 	umad_types = umad_get_mad_classes_by_ibmf_class(ibmf_class);
1181448bf859SLida.Horn 	if (umad_types != NULL) {
1182448bf859SLida.Horn 		struct umad_agent_s *other_agent;
1183448bf859SLida.Horn 
1184448bf859SLida.Horn 		for (; *umad_types != 0; ++umad_types) {
1185448bf859SLida.Horn 			other_agent = umad_get_agent_by_class(agent->agent_uctx,
1186448bf859SLida.Horn 			    *umad_types);
1187448bf859SLida.Horn 			if (other_agent != NULL) {
1188448bf859SLida.Horn 				struct ibmf_reg_info *ibmf_reg;
1189448bf859SLida.Horn 
1190448bf859SLida.Horn 				ibmf_reg = other_agent->agent_reg;
1191448bf859SLida.Horn 				agent->agent_reg = ibmf_reg;
1192448bf859SLida.Horn 				if (other_agent->agent_flags
1193448bf859SLida.Horn 				    & UMAD_HANDLING_ASYNC) {
1194448bf859SLida.Horn 					agent->agent_flags |=
1195448bf859SLida.Horn 					    UMAD_HANDLING_ASYNC;
1196448bf859SLida.Horn 				}
1197448bf859SLida.Horn 
1198448bf859SLida.Horn 				mutex_enter(&ibmf_reg->ibmf_reg_lock);
1199448bf859SLida.Horn 				while (ibmf_reg->ibmf_flags
1200448bf859SLida.Horn 				    & UMAD_IBMF_UNREGISTERING) {
1201448bf859SLida.Horn 					cv_wait(&ibmf_reg->ibmf_cv,
1202448bf859SLida.Horn 					    &ibmf_reg->ibmf_reg_lock);
1203448bf859SLida.Horn 				}
1204448bf859SLida.Horn 				ibmf_reg->ibmf_reg_refcnt++;
1205448bf859SLida.Horn 				mutex_exit(&ibmf_reg->ibmf_reg_lock);
1206448bf859SLida.Horn 				return (0);
1207448bf859SLida.Horn 			}
1208448bf859SLida.Horn 		}
1209448bf859SLida.Horn 	}
1210448bf859SLida.Horn 
1211448bf859SLida.Horn 	/*
1212448bf859SLida.Horn 	 * At this point we need to check if there is already an
1213448bf859SLida.Horn 	 * ibmf_info already associated with this HCA, port and ibmf
1214448bf859SLida.Horn 	 * class.  If so, simply increment the reference count
1215448bf859SLida.Horn 	 * and set the agent's agent_reg field to point to the
1216448bf859SLida.Horn 	 * ibmf_info structure that was found. (under locking)
1217448bf859SLida.Horn 	 */
1218448bf859SLida.Horn 	mutex_enter(&port->port_lock);
1219448bf859SLida.Horn 	if (! llist_empty(&port->port_ibmf_regs)) {
1220448bf859SLida.Horn 		list_for_each(entry, &port->port_ibmf_regs) {
1221448bf859SLida.Horn 			ibmf_info = (struct ibmf_reg_info *)entry->ptr;
1222448bf859SLida.Horn 			if (ibmf_info->ibmf_class == ibmf_class) {
1223448bf859SLida.Horn 				found = B_TRUE;
1224448bf859SLida.Horn 				break;
1225448bf859SLida.Horn 			}
1226448bf859SLida.Horn 		}
1227448bf859SLida.Horn 	}
1228448bf859SLida.Horn 	mutex_exit(&port->port_lock);
1229448bf859SLida.Horn 
1230448bf859SLida.Horn 	if (found) {
1231448bf859SLida.Horn 		mutex_enter(&ibmf_info->ibmf_reg_lock);
1232448bf859SLida.Horn 		ibmf_info->ibmf_reg_refcnt++;
1233448bf859SLida.Horn 		agent->agent_reg = ibmf_info;
1234448bf859SLida.Horn 		mutex_exit(&ibmf_info->ibmf_reg_lock);
1235448bf859SLida.Horn 
1236448bf859SLida.Horn 		return (0);
1237448bf859SLida.Horn 	}
1238448bf859SLida.Horn 
1239448bf859SLida.Horn 	ibmf_info = kmem_zalloc(sizeof (struct ibmf_reg_info), KM_SLEEP);
1240448bf859SLida.Horn 
1241448bf859SLida.Horn 	mutex_init(&ibmf_info->ibmf_reg_lock, NULL, MUTEX_DRIVER, NULL);
1242448bf859SLida.Horn 	cv_init(&ibmf_info->ibmf_cv, NULL, CV_DRIVER, NULL);
1243448bf859SLida.Horn 
1244448bf859SLida.Horn 	if (agent->agent_req.rmpp_version)
1245448bf859SLida.Horn 		flags = IBMF_REG_FLAG_RMPP;
1246448bf859SLida.Horn 
1247448bf859SLida.Horn 	reg_info.ir_ci_guid = hca->hca_guid;
1248448bf859SLida.Horn 	reg_info.ir_port_num = port->port_num;
1249448bf859SLida.Horn 	reg_info.ir_client_class = ibmf_class;
1250448bf859SLida.Horn 
1251448bf859SLida.Horn 	mutex_enter(&ibmf_info->ibmf_reg_lock);
1252448bf859SLida.Horn 	rc = ibmf_register(&reg_info, IBMF_VERSION, flags, NULL, NULL,
1253448bf859SLida.Horn 	    &ibmf_info->ibmf_reg_handle, &impl_caps);
1254448bf859SLida.Horn 
1255448bf859SLida.Horn 	if (rc != IBMF_SUCCESS) {
1256448bf859SLida.Horn 		mutex_exit(&ibmf_info->ibmf_reg_lock);
1257448bf859SLida.Horn 		kmem_free(ibmf_info, sizeof (*ibmf_info));
1258448bf859SLida.Horn 	} else {
1259448bf859SLida.Horn 		/* The client wants to receive some unsolicited MADs. */
1260448bf859SLida.Horn 		rc = ibmf_setup_async_cb(ibmf_info->ibmf_reg_handle,
1261448bf859SLida.Horn 		    IBMF_QP_HANDLE_DEFAULT, umad_unsolicited_cb,
1262448bf859SLida.Horn 		    (void *)ibmf_info, 0);
1263448bf859SLida.Horn 
1264448bf859SLida.Horn 		if (rc != IBMF_SUCCESS) {
1265448bf859SLida.Horn 			(void) ibmf_unregister(&ibmf_info->ibmf_reg_handle, 0);
1266448bf859SLida.Horn 			mutex_exit(&ibmf_info->ibmf_reg_lock);
1267448bf859SLida.Horn 			kmem_free(ibmf_info, sizeof (*ibmf_info));
1268448bf859SLida.Horn 		} else {
1269448bf859SLida.Horn 			ibmf_info->ibmf_reg_refcnt++;
1270448bf859SLida.Horn 			ibmf_info->ibmf_reg_uctx = agent->agent_uctx;
1271448bf859SLida.Horn 			ibmf_info->ibmf_class = ibmf_class;
1272448bf859SLida.Horn 			agent->agent_reg = ibmf_info;
1273448bf859SLida.Horn 			agent->agent_flags |= UMAD_HANDLING_ASYNC;
1274448bf859SLida.Horn 			mutex_exit(&ibmf_info->ibmf_reg_lock);
1275448bf859SLida.Horn 
1276448bf859SLida.Horn 			entry = kmem_zalloc(sizeof (llist_head_t), KM_SLEEP);
1277448bf859SLida.Horn 			entry->ptr = ibmf_info;
1278448bf859SLida.Horn 			mutex_enter(&port->port_lock);
1279448bf859SLida.Horn 			llist_add(entry, &port->port_ibmf_regs);
1280448bf859SLida.Horn 			mutex_exit(&port->port_lock);
1281448bf859SLida.Horn 		}
1282448bf859SLida.Horn 	}
1283448bf859SLida.Horn 
1284448bf859SLida.Horn done:
1285448bf859SLida.Horn 	return (rc);
1286448bf859SLida.Horn }
1287448bf859SLida.Horn 
1288448bf859SLida.Horn /*
1289448bf859SLida.Horn  * Function:
1290448bf859SLida.Horn  *      umad_queue_mad_msg
1291448bf859SLida.Horn  * Input:
1292448bf859SLida.Horn  *	port            - handle to ibmf
1293448bf859SLida.Horn  *      ibmf_msg        - The incoming SM MAD
1294448bf859SLida.Horn  * Output:
1295448bf859SLida.Horn  *	None
1296448bf859SLida.Horn  * Returns:
1297448bf859SLida.Horn  *     0 on success, otherwise error number
1298448bf859SLida.Horn  * Called by:
1299448bf859SLida.Horn  *      umad_solicitied_cb and umad_unsolicited_cb
1300448bf859SLida.Horn  * Description:
1301448bf859SLida.Horn  *      creates a umad_msg and adds it to the appropriate user's context
1302448bf859SLida.Horn  */
1303448bf859SLida.Horn 
1304448bf859SLida.Horn static int
umad_queue_mad_msg(struct umad_agent_s * agent,ibmf_msg_t * ibmf_msg)1305448bf859SLida.Horn umad_queue_mad_msg(struct umad_agent_s *agent, ibmf_msg_t *ibmf_msg)
1306448bf859SLida.Horn {
1307448bf859SLida.Horn 	int rc;
1308448bf859SLida.Horn 	ib_umad_msg_t *umad_msg;
1309448bf859SLida.Horn 	umad_uctx_t *uctx = agent->agent_uctx;
1310448bf859SLida.Horn 
1311448bf859SLida.Horn 	if (agent->agent_uctx == NULL) {
1312448bf859SLida.Horn 		rc = ENOENT;
1313448bf859SLida.Horn 		goto err1;
1314448bf859SLida.Horn 	}
1315448bf859SLida.Horn 
1316448bf859SLida.Horn 	umad_msg = kmem_zalloc(sizeof (*umad_msg), KM_NOSLEEP);
1317448bf859SLida.Horn 	if (umad_msg == NULL) {
1318448bf859SLida.Horn 		rc = ENOMEM;
1319448bf859SLida.Horn 		goto err1;
1320448bf859SLida.Horn 	}
1321448bf859SLida.Horn 
1322448bf859SLida.Horn 	umad_msg->umad_msg_hdr.id = agent->agent_req.id;
1323448bf859SLida.Horn 	umad_msg->umad_msg_hdr.status = ibmf_msg->im_msg_status;
1324448bf859SLida.Horn 	umad_msg->umad_msg_hdr.length = IB_MGMT_MAD_HDR +
1325448bf859SLida.Horn 	    ibmf_msg->im_msgbufs_recv.im_bufs_cl_hdr_len +
1326448bf859SLida.Horn 	    ibmf_msg->im_msgbufs_recv.im_bufs_cl_data_len;
1327448bf859SLida.Horn 
1328448bf859SLida.Horn 	umad_msg->umad_msg_hdr.qpn =
1329448bf859SLida.Horn 	    htonl(ibmf_msg->im_local_addr.ia_remote_qno);
1330448bf859SLida.Horn 	umad_msg->umad_msg_hdr.lid =
1331448bf859SLida.Horn 	    htons(ibmf_msg->im_local_addr.ia_remote_lid);
1332448bf859SLida.Horn 	umad_msg->umad_msg_hdr.sl =
1333448bf859SLida.Horn 	    htonl(ibmf_msg->im_local_addr.ia_service_level);
1334448bf859SLida.Horn 
1335448bf859SLida.Horn 	umad_msg->umad_msg_ibmf_msg = ibmf_msg;
1336448bf859SLida.Horn 
1337448bf859SLida.Horn 	mutex_enter(&uctx->uctx_recv_lock);
1338448bf859SLida.Horn 	if (! add_genlist(&uctx->uctx_recv_list, (uintptr_t)umad_msg, agent)) {
1339448bf859SLida.Horn 		kmem_free(umad_msg, sizeof (*umad_msg));
1340448bf859SLida.Horn 		mutex_exit(&uctx->uctx_recv_lock);
1341448bf859SLida.Horn 		rc = ENOMEM;
1342448bf859SLida.Horn 		goto err1;
1343448bf859SLida.Horn 	}
1344448bf859SLida.Horn 	mutex_exit(&uctx->uctx_recv_lock);
1345448bf859SLida.Horn 
1346448bf859SLida.Horn 	cv_broadcast(&uctx->uctx_recv_cv);
1347448bf859SLida.Horn 	pollwakeup(&uctx->uctx_pollhead, POLLIN | POLLRDNORM);
1348448bf859SLida.Horn 
1349448bf859SLida.Horn 	rc = 0;
1350448bf859SLida.Horn 
1351448bf859SLida.Horn err1:
1352448bf859SLida.Horn 	return (rc);
1353448bf859SLida.Horn }
1354448bf859SLida.Horn 
1355448bf859SLida.Horn /* Frees up user context state */
1356448bf859SLida.Horn static void
umad_release_uctx(umad_uctx_t * uctx)1357448bf859SLida.Horn umad_release_uctx(umad_uctx_t *uctx)
1358448bf859SLida.Horn {
1359448bf859SLida.Horn 	ASSERT(genlist_empty(&uctx->uctx_recv_list));
1360448bf859SLida.Horn 	ASSERT(llist_empty(&uctx->uctx_agent_list));
1361448bf859SLida.Horn 
1362448bf859SLida.Horn 	cv_destroy(&uctx->uctx_recv_cv);
1363448bf859SLida.Horn 	mutex_destroy(&uctx->uctx_lock);
1364448bf859SLida.Horn 	mutex_destroy(&uctx->uctx_recv_lock);
1365448bf859SLida.Horn }
1366448bf859SLida.Horn 
1367448bf859SLida.Horn /*
1368448bf859SLida.Horn  * Function:
1369448bf859SLida.Horn  *	umad_open
1370448bf859SLida.Horn  * Input:
1371448bf859SLida.Horn  *	devp		device pointer
1372448bf859SLida.Horn  *	flag		Unused
1373448bf859SLida.Horn  *	otyp		Open type (just validated)
1374448bf859SLida.Horn  *	cred		Unused
1375448bf859SLida.Horn  * Output:
1376448bf859SLida.Horn  *	None
1377448bf859SLida.Horn  * Returns:
1378448bf859SLida.Horn  *	status
1379448bf859SLida.Horn  * Called by:
1380448bf859SLida.Horn  *	Device open framework
1381448bf859SLida.Horn  * Description:
1382448bf859SLida.Horn  *	If this is the issm device, modify the port to indicate that this is
1383448bf859SLida.Horn  *	a subnet manager.  If regular umad device, allocate and initialize
1384448bf859SLida.Horn  *	a new user context and connect it to the hca info.  Return the new
1385448bf859SLida.Horn  *	dev_t for the new minor.
1386448bf859SLida.Horn  */
1387448bf859SLida.Horn static int
umad_open(dev_t * dev,int flag,int otyp,cred_t * cred)1388448bf859SLida.Horn umad_open(dev_t *dev, int flag, int otyp, cred_t *cred)
1389448bf859SLida.Horn {
1390448bf859SLida.Horn 	umad_info_t		*info;
1391448bf859SLida.Horn 	minor_t			minor;
1392448bf859SLida.Horn 	minor_t			ctx_minor;
1393448bf859SLida.Horn 	int			node_id, port_num;
1394448bf859SLida.Horn 	int			rc = DDI_SUCCESS;
1395448bf859SLida.Horn 	umad_hca_info_t		*hca;
1396448bf859SLida.Horn 	umad_port_info_t	*port;
1397448bf859SLida.Horn 	umad_uctx_t		*uctx;
1398448bf859SLida.Horn 
1399448bf859SLida.Horn #if defined(__lint)
1400448bf859SLida.Horn 	extern void dummy(int);
1401448bf859SLida.Horn 
1402448bf859SLida.Horn 	dummy(flag);
1403448bf859SLida.Horn #endif
1404448bf859SLida.Horn 
1405448bf859SLida.Horn 	rc = priv_policy(cred, PRIV_SYS_NET_CONFIG, B_FALSE, EACCES, NULL);
1406448bf859SLida.Horn 	if (rc != 0)
1407448bf859SLida.Horn 		return (rc);
1408448bf859SLida.Horn 
1409448bf859SLida.Horn 	info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
1410448bf859SLida.Horn 	if (info == NULL) {
1411448bf859SLida.Horn 		rc = ENXIO;
1412448bf859SLida.Horn 		goto err1;
1413448bf859SLida.Horn 	}
1414448bf859SLida.Horn 	if (otyp != OTYP_CHR)
1415448bf859SLida.Horn 		return (EINVAL);
1416448bf859SLida.Horn 
1417448bf859SLida.Horn 	/* lookup the node and port #s */
1418448bf859SLida.Horn 	minor = getminor(*dev);
1419448bf859SLida.Horn 
1420448bf859SLida.Horn 	node_id	= GET_NODE(minor);
1421448bf859SLida.Horn 	port_num = GET_PORT(minor);
1422448bf859SLida.Horn 
1423448bf859SLida.Horn 	hca = &info->info_hcas[node_id];
1424448bf859SLida.Horn 	port = &hca->hca_ports[port_num];
1425448bf859SLida.Horn 
1426448bf859SLida.Horn 	if (ISSM_MINOR(minor)) {
1427448bf859SLida.Horn 		ibt_status_t rc;
1428448bf859SLida.Horn 
1429448bf859SLida.Horn 		mutex_enter(&port->port_lock);
1430448bf859SLida.Horn 
1431448bf859SLida.Horn 		if (port->port_issm_open_cnt) {
1432448bf859SLida.Horn 			mutex_exit(&port->port_lock);
1433448bf859SLida.Horn 			rc = EBUSY;
1434448bf859SLida.Horn 			goto err1;
1435448bf859SLida.Horn 		}
1436448bf859SLida.Horn 
1437448bf859SLida.Horn 		port->port_issm_open_cnt++;
1438448bf859SLida.Horn 
1439448bf859SLida.Horn 		mutex_exit(&port->port_lock);
1440448bf859SLida.Horn 
1441448bf859SLida.Horn 		rc = ibt_modify_port(hca->hca_handle, port->port_num,
1442448bf859SLida.Horn 		    IBT_PORT_SET_SM, 0);
1443448bf859SLida.Horn 
1444448bf859SLida.Horn 		if (rc) {
1445448bf859SLida.Horn 			mutex_enter(&port->port_lock);
1446448bf859SLida.Horn 			port->port_issm_open_cnt--;
1447448bf859SLida.Horn 			mutex_exit(&port->port_lock);
1448448bf859SLida.Horn 			goto err1;
1449448bf859SLida.Horn 		}
1450448bf859SLida.Horn 	} else {
1451448bf859SLida.Horn 		unsigned int uctx_num;
1452448bf859SLida.Horn 
1453448bf859SLida.Horn 		uctx = kmem_zalloc(sizeof (umad_uctx_t), KM_SLEEP);
1454448bf859SLida.Horn 
1455448bf859SLida.Horn 		mutex_init(&uctx->uctx_lock, NULL, MUTEX_DRIVER, NULL);
1456448bf859SLida.Horn 		cv_init(&uctx->uctx_recv_cv, NULL, CV_DRIVER, NULL);
1457448bf859SLida.Horn 		init_genlist(&uctx->uctx_recv_list);
1458448bf859SLida.Horn 		mutex_init(&uctx->uctx_recv_lock, NULL, MUTEX_DRIVER, NULL);
1459448bf859SLida.Horn 		llist_head_init(&uctx->uctx_agent_list, NULL);
1460448bf859SLida.Horn 		uctx->uctx_port = port;
1461448bf859SLida.Horn 
1462448bf859SLida.Horn 		mutex_enter(&info->info_mutex);
1463448bf859SLida.Horn 		mutex_enter(&port->port_lock);
1464448bf859SLida.Horn 
1465448bf859SLida.Horn 		/* Find a free entry in uctx list */
1466448bf859SLida.Horn 		for (uctx_num = 0; uctx_num < MAX_UCTX; uctx_num++) {
1467448bf859SLida.Horn 			if (info->info_uctx[uctx_num] == NULL)
1468448bf859SLida.Horn 				break;
1469448bf859SLida.Horn 		}
1470448bf859SLida.Horn 
1471448bf859SLida.Horn 		if (uctx_num == MAX_UCTX) {
1472448bf859SLida.Horn 			/* No room found */
1473448bf859SLida.Horn 			mutex_exit(&port->port_lock);
1474448bf859SLida.Horn 			mutex_exit(&info->info_mutex);
1475448bf859SLida.Horn 
1476448bf859SLida.Horn 			umad_release_uctx(uctx);
1477448bf859SLida.Horn 
1478448bf859SLida.Horn 			rc = EBUSY;
1479448bf859SLida.Horn 			goto err1;
1480448bf859SLida.Horn 		}
1481448bf859SLida.Horn 
1482448bf859SLida.Horn 		ctx_minor = GET_NEW_UCTX_MINOR(minor, uctx_num);
1483448bf859SLida.Horn 		info->info_uctx[uctx_num] = uctx;
1484448bf859SLida.Horn 		*dev = makedevice(getmajor(*dev), ctx_minor);
1485448bf859SLida.Horn 
1486448bf859SLida.Horn 		mutex_exit(&port->port_lock);
1487448bf859SLida.Horn 		mutex_exit(&info->info_mutex);
1488448bf859SLida.Horn 	}
1489448bf859SLida.Horn err1:
1490448bf859SLida.Horn 	return (rc);
1491448bf859SLida.Horn }
1492448bf859SLida.Horn 
1493448bf859SLida.Horn /*
1494448bf859SLida.Horn  * Function:
1495448bf859SLida.Horn  *	umad_close
1496448bf859SLida.Horn  * Input:
1497448bf859SLida.Horn  *	dev		device
1498448bf859SLida.Horn  *	flag		Unused
1499448bf859SLida.Horn  *	otyp		Unused
1500448bf859SLida.Horn  *	cred		Unused
1501448bf859SLida.Horn  * Output:
1502448bf859SLida.Horn  *	None
1503448bf859SLida.Horn  * Returns:
1504448bf859SLida.Horn  *	status
1505448bf859SLida.Horn  * Called by:
1506448bf859SLida.Horn  *	Device close framework
1507448bf859SLida.Horn  * Description:
1508448bf859SLida.Horn  *	Unwinds open while waiting for any pending I/O to complete.
1509448bf859SLida.Horn  */
1510448bf859SLida.Horn /* ARGSUSED1 */
1511448bf859SLida.Horn static int
umad_close(dev_t dev,int flag,int otyp,cred_t * cred)1512448bf859SLida.Horn umad_close(dev_t dev, int flag, int otyp, cred_t *cred)
1513448bf859SLida.Horn {
1514448bf859SLida.Horn 	umad_info_t		*info;
1515448bf859SLida.Horn 	minor_t			minor;
1516448bf859SLida.Horn 	int			rc = DDI_SUCCESS;
1517448bf859SLida.Horn 	umad_port_info_t	*port;
1518448bf859SLida.Horn 	umad_uctx_t		*uctx;
1519448bf859SLida.Horn 	llist_head_t		*lentry;
1520448bf859SLida.Horn 	llist_head_t		*lentry_temp;
1521448bf859SLida.Horn 	umad_agent_t		*agent;
1522448bf859SLida.Horn 	int			port_num;
1523448bf859SLida.Horn 	umad_hca_info_t		*hca;
1524448bf859SLida.Horn 	int			node_id;
1525448bf859SLida.Horn 
1526448bf859SLida.Horn 	info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
1527448bf859SLida.Horn 	if (info == NULL) {
1528448bf859SLida.Horn 		rc = ENXIO;
1529448bf859SLida.Horn 		goto  err1;
1530448bf859SLida.Horn 	}
1531448bf859SLida.Horn 	minor = getminor(dev);
1532448bf859SLida.Horn 
1533448bf859SLida.Horn 	node_id	= GET_NODE(minor);
1534448bf859SLida.Horn 	port_num = GET_PORT(minor);
1535448bf859SLida.Horn 
1536448bf859SLida.Horn 	hca = &info->info_hcas[node_id];
1537448bf859SLida.Horn 	port = &hca->hca_ports[port_num];
1538448bf859SLida.Horn 
1539448bf859SLida.Horn 	ASSERT(port != NULL);
1540448bf859SLida.Horn 
1541448bf859SLida.Horn 	if (ISSM_MINOR(minor)) {
1542448bf859SLida.Horn 		(void) ibt_modify_port(hca->hca_handle, port->port_num,
1543448bf859SLida.Horn 		    IBT_PORT_RESET_SM, 0);
1544448bf859SLida.Horn 
1545448bf859SLida.Horn 		mutex_enter(&port->port_lock);
1546448bf859SLida.Horn 		port->port_issm_open_cnt--;
1547448bf859SLida.Horn 		mutex_exit(&port->port_lock);
1548448bf859SLida.Horn 
1549448bf859SLida.Horn 		ASSERT(port->port_issm_open_cnt == 0);
1550448bf859SLida.Horn 	} else {
1551448bf859SLida.Horn 
1552448bf859SLida.Horn 		mutex_enter(&info->info_mutex);
1553448bf859SLida.Horn 		uctx = info->info_uctx[GET_UCTX(minor)];
1554448bf859SLida.Horn 		ASSERT(uctx != NULL);
1555448bf859SLida.Horn 
1556448bf859SLida.Horn 		mutex_enter(&uctx->uctx_lock);
1557448bf859SLida.Horn 
1558448bf859SLida.Horn 		/* Unregister the agents. Cancel the pending operations. */
1559448bf859SLida.Horn 		lentry = uctx->uctx_agent_list.nxt;
1560448bf859SLida.Horn 		lentry_temp = lentry->nxt;
1561448bf859SLida.Horn 		while (lentry != &uctx->uctx_agent_list) {
1562448bf859SLida.Horn 			ASSERT(lentry);
1563448bf859SLida.Horn 			agent = lentry->ptr;
1564448bf859SLida.Horn 
1565448bf859SLida.Horn 			(void) umad_unregister(&agent->agent_req, uctx);
1566448bf859SLida.Horn 			lentry = lentry_temp;
1567448bf859SLida.Horn 			lentry_temp = lentry->nxt;
1568448bf859SLida.Horn 		}
1569448bf859SLida.Horn 
1570448bf859SLida.Horn 		mutex_exit(&uctx->uctx_lock);
1571448bf859SLida.Horn 
1572448bf859SLida.Horn 		umad_release_uctx(uctx);
1573448bf859SLida.Horn 		kmem_free(uctx, sizeof (umad_uctx_t));
1574448bf859SLida.Horn 
1575448bf859SLida.Horn 		info->info_uctx[GET_UCTX(minor)] = NULL;
1576448bf859SLida.Horn 		mutex_exit(&info->info_mutex);
1577448bf859SLida.Horn 	}
1578448bf859SLida.Horn 
1579448bf859SLida.Horn err1:
1580448bf859SLida.Horn 	return (rc);
1581448bf859SLida.Horn }
1582448bf859SLida.Horn 
1583448bf859SLida.Horn /*
1584448bf859SLida.Horn  * return where optional header starts relative to the start
1585448bf859SLida.Horn  * of the transmited mad
1586448bf859SLida.Horn  */
1587448bf859SLida.Horn static int
umad_get_mad_clhdr_offset(uint8_t mgmt_class)1588448bf859SLida.Horn umad_get_mad_clhdr_offset(uint8_t mgmt_class)
1589448bf859SLida.Horn {
1590448bf859SLida.Horn 	switch (mgmt_class) {
1591448bf859SLida.Horn 	case MAD_MGMT_CLASS_SUBN_LID_ROUTED:
1592448bf859SLida.Horn 	case MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE:
1593448bf859SLida.Horn 	case MAD_MGMT_CLASS_PERF:
1594448bf859SLida.Horn 	case MAD_MGMT_CLASS_BM:
1595448bf859SLida.Horn 	case MAD_MGMT_CLASS_DEV_MGT:
1596448bf859SLida.Horn 	case MAD_MGMT_CLASS_COMM_MGT:
1597448bf859SLida.Horn 		return (IB_MGMT_MAD_HDR);
1598448bf859SLida.Horn 	case MAD_MGMT_CLASS_SUBN_ADM:
1599448bf859SLida.Horn 		return (IB_MGMT_RMPP_HDR);
1600448bf859SLida.Horn 	case MAD_MGMT_CLASS_SNMP:
1601448bf859SLida.Horn 		return (IB_MGMT_SNMP_HDR);
1602448bf859SLida.Horn 	default:
1603448bf859SLida.Horn 		if (((mgmt_class >= MAD_MGMT_CLASS_VENDOR_START) &&
1604448bf859SLida.Horn 		    (mgmt_class <= MAD_MGMT_CLASS_VENDOR_END)) ||
1605448bf859SLida.Horn 		    ((mgmt_class >= MAD_MGMT_CLASS_APPLICATION_START) &&
1606448bf859SLida.Horn 		    (mgmt_class <= MAD_MGMT_CLASS_APPLICATION_END)))
1607448bf859SLida.Horn 			return (IB_MGMT_MAD_HDR);
1608448bf859SLida.Horn 		else if ((mgmt_class >= MAD_MGMT_CLASS_VENDOR2_START) &&
1609448bf859SLida.Horn 		    (mgmt_class <= MAD_MGMT_CLASS_VENDOR2_END))
1610448bf859SLida.Horn 			return (IB_MGMT_RMPP_HDR);
1611448bf859SLida.Horn 		else {
1612448bf859SLida.Horn #if defined(DEBUG)
1613448bf859SLida.Horn 			SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
1614448bf859SLida.Horn 			    "umad_get_mad_clhdr_offset:"
1615448bf859SLida.Horn 			    " got illegal management class %d", mgmt_class);
1616448bf859SLida.Horn #endif
1617448bf859SLida.Horn 			return (0);  /* invalid mad */
1618448bf859SLida.Horn 		}
1619448bf859SLida.Horn 	}
1620448bf859SLida.Horn }
1621448bf859SLida.Horn 
1622448bf859SLida.Horn /*
1623448bf859SLida.Horn  * return the offset of the mad data in the transmited mad
1624448bf859SLida.Horn  * following all headers
1625448bf859SLida.Horn  */
1626448bf859SLida.Horn static int
umad_get_mad_data_offset(uint8_t mgmt_class)1627448bf859SLida.Horn umad_get_mad_data_offset(uint8_t mgmt_class)
1628448bf859SLida.Horn {
1629448bf859SLida.Horn 	switch (mgmt_class) {
1630448bf859SLida.Horn 	case MAD_MGMT_CLASS_SUBN_LID_ROUTED:
1631448bf859SLida.Horn 	case MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE:
1632448bf859SLida.Horn 	case MAD_MGMT_CLASS_PERF:
1633448bf859SLida.Horn 	case MAD_MGMT_CLASS_BM:
1634448bf859SLida.Horn 	case MAD_MGMT_CLASS_DEV_MGT:
1635448bf859SLida.Horn 	case MAD_MGMT_CLASS_COMM_MGT:
1636448bf859SLida.Horn 		return (IB_MGMT_MAD_HDR);
1637448bf859SLida.Horn 	case MAD_MGMT_CLASS_SUBN_ADM:
1638448bf859SLida.Horn 		return (IB_MGMT_SA_HDR);
1639448bf859SLida.Horn 	case MAD_MGMT_CLASS_SNMP:
1640448bf859SLida.Horn 		return (IB_MGMT_SNMP_DATA);
1641448bf859SLida.Horn 	default:
1642448bf859SLida.Horn 		if (((mgmt_class >= MAD_MGMT_CLASS_VENDOR_START) &&
1643448bf859SLida.Horn 		    (mgmt_class <= MAD_MGMT_CLASS_VENDOR_END)) ||
1644448bf859SLida.Horn 		    ((mgmt_class >= MAD_MGMT_CLASS_APPLICATION_START) &&
1645448bf859SLida.Horn 		    (mgmt_class <= MAD_MGMT_CLASS_APPLICATION_END)))
1646448bf859SLida.Horn 			return (IB_MGMT_MAD_HDR);
1647448bf859SLida.Horn 		else if ((mgmt_class >= MAD_MGMT_CLASS_VENDOR2_START) &&
1648448bf859SLida.Horn 		    (mgmt_class <= MAD_MGMT_CLASS_VENDOR2_END))
1649448bf859SLida.Horn 			return (IB_MGMT_VENDOR_HDR);
1650448bf859SLida.Horn 		else {
1651448bf859SLida.Horn #if defined(DEBUG)
1652448bf859SLida.Horn 			SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
1653448bf859SLida.Horn 			    "umad_get_mad_clhdr_offset:"
1654448bf859SLida.Horn 			    " got illegal management class %d", mgmt_class);
1655448bf859SLida.Horn #endif
1656448bf859SLida.Horn 			return (0);  /* invalid mad */
1657448bf859SLida.Horn 		}
1658448bf859SLida.Horn 	}
1659448bf859SLida.Horn 
1660448bf859SLida.Horn }
1661448bf859SLida.Horn 
1662448bf859SLida.Horn /*
1663448bf859SLida.Horn  * Function:
1664448bf859SLida.Horn  *	umad_read
1665448bf859SLida.Horn  * Input:
1666448bf859SLida.Horn  *	dev		device
1667448bf859SLida.Horn  *	uiop		User I/O pointer
1668448bf859SLida.Horn  *	credp		Unused
1669448bf859SLida.Horn  * Output:
1670448bf859SLida.Horn  *	None
1671448bf859SLida.Horn  * Returns:
1672448bf859SLida.Horn  *	status
1673448bf859SLida.Horn  * Called by:
1674448bf859SLida.Horn  *	Device read framework
1675448bf859SLida.Horn  * Description:
1676448bf859SLida.Horn  *	Cannot read from ISSM device.  Read from UMAD device
1677448bf859SLida.Horn  *	does usual checks for blocking and when data is present,
1678448bf859SLida.Horn  *	removes message from user context receive list, fills in user
1679448bf859SLida.Horn  *	space with message and frees kernel copy of the message.
1680448bf859SLida.Horn  */
1681448bf859SLida.Horn /* ARGSUSED2 */
1682448bf859SLida.Horn static int
umad_read(dev_t dev,struct uio * uiop,cred_t * credp)1683448bf859SLida.Horn umad_read(dev_t dev, struct uio *uiop, cred_t *credp)
1684448bf859SLida.Horn {
1685448bf859SLida.Horn 	int			minor;
1686448bf859SLida.Horn 	size_t			data_len;
1687448bf859SLida.Horn 	int			rc = 0;
1688448bf859SLida.Horn 	umad_port_info_t	*port;
1689448bf859SLida.Horn 	umad_info_t		*info;
1690448bf859SLida.Horn 	umad_uctx_t		*uctx;
1691448bf859SLida.Horn 	genlist_entry_t		*entry;
1692448bf859SLida.Horn 	ib_umad_msg_t		*umad_msg;
1693448bf859SLida.Horn 	ibmf_msg_t		*ibmf_msg;
1694448bf859SLida.Horn 	struct umad_agent_s	*agent;
1695448bf859SLida.Horn 	ib_mad_hdr_t		*ib_mad_hdr;
1696448bf859SLida.Horn 	ssize_t			start_resid;
1697448bf859SLida.Horn 
1698448bf859SLida.Horn 
1699448bf859SLida.Horn 	info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
1700448bf859SLida.Horn 	if (info == NULL) {
1701448bf859SLida.Horn 		rc = ENXIO;
1702448bf859SLida.Horn 		goto err1;
1703448bf859SLida.Horn 	}
1704448bf859SLida.Horn 
1705448bf859SLida.Horn 	minor = getminor(dev);
1706448bf859SLida.Horn 
1707448bf859SLida.Horn 	if (ISSM_MINOR(minor)) {
1708448bf859SLida.Horn 		rc = ENXIO;
1709448bf859SLida.Horn 		goto err1;
1710448bf859SLida.Horn 	}
1711448bf859SLida.Horn 
1712448bf859SLida.Horn 	mutex_enter(&info->info_mutex);
1713448bf859SLida.Horn 	uctx = info->info_uctx[GET_UCTX(minor)];
1714448bf859SLida.Horn 	mutex_exit(&info->info_mutex);
1715448bf859SLida.Horn 	ASSERT(uctx != NULL);
1716448bf859SLida.Horn 	port = uctx->uctx_port;
1717448bf859SLida.Horn 	ASSERT(port != NULL);
1718448bf859SLida.Horn 
1719448bf859SLida.Horn 	start_resid = uiop->uio_resid;
1720448bf859SLida.Horn 	while (rc == 0 && uiop->uio_resid > 0) {
1721448bf859SLida.Horn 		mutex_enter(&uctx->uctx_recv_lock);
1722448bf859SLida.Horn 
1723448bf859SLida.Horn 		/* Check to see if we are in blocking mode or not */
1724448bf859SLida.Horn 		if (! (uiop->uio_fmode & (FNDELAY | FNONBLOCK))) {
1725448bf859SLida.Horn 			while (genlist_empty(&uctx->uctx_recv_list)) {
1726448bf859SLida.Horn 				if (cv_wait_sig(&uctx->uctx_recv_cv,
1727448bf859SLida.Horn 				    &uctx->uctx_recv_lock) == 0) {
1728448bf859SLida.Horn 					mutex_exit(&uctx->uctx_recv_lock);
1729448bf859SLida.Horn 					return (EINTR);
1730448bf859SLida.Horn 				}
1731448bf859SLida.Horn 			}
1732448bf859SLida.Horn 		} else if (genlist_empty(&uctx->uctx_recv_list)) {
1733448bf859SLida.Horn 			mutex_exit(&uctx->uctx_recv_lock);
1734448bf859SLida.Horn 			/* Check for a short read */
1735448bf859SLida.Horn 			if (uiop->uio_resid != start_resid)
1736448bf859SLida.Horn 				return (0);
1737448bf859SLida.Horn 			return (EAGAIN);
1738448bf859SLida.Horn 		}
1739448bf859SLida.Horn 
1740448bf859SLida.Horn 		entry = remove_genlist_head(&uctx->uctx_recv_list);
1741448bf859SLida.Horn 		mutex_exit(&uctx->uctx_recv_lock);
1742448bf859SLida.Horn 
1743448bf859SLida.Horn 		ASSERT(entry != NULL);
1744448bf859SLida.Horn 		agent = entry->data_context;
1745448bf859SLida.Horn 
1746448bf859SLida.Horn 		umad_msg = (ib_umad_msg_t *)entry->data;
1747448bf859SLida.Horn 		ibmf_msg =  (ibmf_msg_t *)umad_msg->umad_msg_ibmf_msg;
1748448bf859SLida.Horn 
1749448bf859SLida.Horn 		data_len = min(uiop->uio_resid, sizeof (struct ib_user_mad));
1750448bf859SLida.Horn 		rc = uiomove(umad_msg, data_len, UIO_READ, uiop);
1751448bf859SLida.Horn 		if (rc)
1752448bf859SLida.Horn 			goto err2;
1753448bf859SLida.Horn 
1754448bf859SLida.Horn 		if (ibmf_msg->im_msg_status == IBMF_SUCCESS) {
1755448bf859SLida.Horn 			ib_mad_hdr = (ib_mad_hdr_t *)
1756448bf859SLida.Horn 			    ibmf_msg->im_msgbufs_recv.im_bufs_mad_hdr;
1757448bf859SLida.Horn 			data_len =
1758448bf859SLida.Horn 			    umad_get_mad_clhdr_offset(ib_mad_hdr->MgmtClass);
1759448bf859SLida.Horn 			data_len = min(uiop->uio_resid, data_len);
1760448bf859SLida.Horn 
1761448bf859SLida.Horn 			rc = uiomove(ibmf_msg->im_msgbufs_recv.im_bufs_mad_hdr,
1762448bf859SLida.Horn 			    data_len, UIO_READ, uiop);
1763448bf859SLida.Horn 			if (rc)
1764448bf859SLida.Horn 				goto err2;
1765448bf859SLida.Horn 
1766448bf859SLida.Horn 			data_len = min(uiop->uio_resid,
1767448bf859SLida.Horn 			    ibmf_msg->im_msgbufs_recv.im_bufs_cl_hdr_len);
1768448bf859SLida.Horn 			rc = uiomove(ibmf_msg->im_msgbufs_recv.im_bufs_cl_hdr,
1769448bf859SLida.Horn 			    data_len, UIO_READ, uiop);
1770448bf859SLida.Horn 			if (rc)
1771448bf859SLida.Horn 				goto err2;
1772448bf859SLida.Horn 
1773448bf859SLida.Horn 			data_len = min(uiop->uio_resid,
1774448bf859SLida.Horn 			    ibmf_msg->im_msgbufs_recv.im_bufs_cl_data_len);
1775448bf859SLida.Horn 			rc = uiomove(ibmf_msg->im_msgbufs_recv.im_bufs_cl_data,
1776448bf859SLida.Horn 			    data_len, UIO_READ, uiop);
1777448bf859SLida.Horn 			if (rc)
1778448bf859SLida.Horn 				goto err2;
1779448bf859SLida.Horn 		}
1780448bf859SLida.Horn 		rc = ibmf_free_msg(agent->agent_reg->ibmf_reg_handle,
1781448bf859SLida.Horn 		    &ibmf_msg);
1782448bf859SLida.Horn 
1783448bf859SLida.Horn 		kmem_free(umad_msg, sizeof (*umad_msg));
1784448bf859SLida.Horn 		if (rc != IBMF_SUCCESS) {
1785448bf859SLida.Horn #if defined(DEBUG)
1786448bf859SLida.Horn 			SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
1787448bf859SLida.Horn 			    "umad_read:"
1788448bf859SLida.Horn 			    " ibmf_free_msg failed %d", rc);
1789448bf859SLida.Horn #endif
1790448bf859SLida.Horn 			goto err1;
1791448bf859SLida.Horn 		}
1792448bf859SLida.Horn 	}
1793448bf859SLida.Horn err2:
1794448bf859SLida.Horn 	if (rc) {
1795448bf859SLida.Horn 		rc = ibmf_free_msg(agent->agent_reg->ibmf_reg_handle,
1796448bf859SLida.Horn 		    &ibmf_msg);
1797448bf859SLida.Horn 
1798448bf859SLida.Horn 		kmem_free(umad_msg, sizeof (*umad_msg));
1799448bf859SLida.Horn 
1800448bf859SLida.Horn 		if (rc != IBMF_SUCCESS) {
1801448bf859SLida.Horn #if defined(DEBUG)
1802448bf859SLida.Horn 			SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
1803448bf859SLida.Horn 			    "umad_read:"
1804448bf859SLida.Horn 			    " ibmf_free_msg failed %d", rc);
1805448bf859SLida.Horn #endif
1806448bf859SLida.Horn 		}
1807448bf859SLida.Horn 
1808448bf859SLida.Horn 	}
1809448bf859SLida.Horn err1:
1810448bf859SLida.Horn 	return (rc);
1811448bf859SLida.Horn }
1812448bf859SLida.Horn 
1813448bf859SLida.Horn /*
1814448bf859SLida.Horn  * Function:
1815448bf859SLida.Horn  *     umad_solicited_cb
1816448bf859SLida.Horn  * Input:
1817448bf859SLida.Horn  *	ibmf_handle     -  handle to ibmf
1818448bf859SLida.Horn  *      msgp            -  The incoming SM MAD
1819448bf859SLida.Horn  *      args            -  umad_port_info_t object that the MAD cam in on
1820448bf859SLida.Horn  * Output:
1821448bf859SLida.Horn  *	None
1822448bf859SLida.Horn  * Returns:
1823448bf859SLida.Horn  *      none
1824448bf859SLida.Horn  * Called by:
1825448bf859SLida.Horn  * Description:
1826448bf859SLida.Horn  *      Callback function (ibmf_msg_cb_t) that is invoked when the
1827448bf859SLida.Horn  *      ibmf receives a SM MAD for the given Port.
1828448bf859SLida.Horn  *      This function copies the MAD into the port recv queue.
1829448bf859SLida.Horn  */
1830448bf859SLida.Horn static void
umad_solicited_cb(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)1831448bf859SLida.Horn umad_solicited_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
1832448bf859SLida.Horn {
1833448bf859SLida.Horn 	struct umad_send *umad_ctx = (struct umad_send *)args;
1834448bf859SLida.Horn 	umad_agent_t *agent = umad_ctx->send_agent;
1835448bf859SLida.Horn 	int rc;
1836448bf859SLida.Horn 
1837448bf859SLida.Horn #if defined(__lint)
1838448bf859SLida.Horn 	ibmf_handle = 0;
1839448bf859SLida.Horn #endif
1840448bf859SLida.Horn 	msgp->im_msgbufs_send.im_bufs_mad_hdr = NULL;
1841448bf859SLida.Horn 	msgp->im_msgbufs_send.im_bufs_cl_hdr = NULL;
1842448bf859SLida.Horn 	msgp->im_msgbufs_send.im_bufs_cl_hdr_len = 0;
1843448bf859SLida.Horn 	msgp->im_msgbufs_send.im_bufs_cl_data = NULL;
1844448bf859SLida.Horn 	msgp->im_msgbufs_send.im_bufs_cl_data_len = 0;
1845448bf859SLida.Horn 	kmem_free(umad_ctx, umad_ctx->send_len);
1846448bf859SLida.Horn 
1847448bf859SLida.Horn 	mutex_enter(&agent->agent_lock);
1848448bf859SLida.Horn 	agent->agent_outstanding_msgs--;
1849448bf859SLida.Horn 	ASSERT(agent->agent_outstanding_msgs >= 0);
1850448bf859SLida.Horn 	if (agent->agent_flags & UMAD_AGENT_UNREGISTERING) {
1851448bf859SLida.Horn 		if (agent->agent_outstanding_msgs == 0)
1852448bf859SLida.Horn 			cv_signal(&agent->agent_cv);
1853448bf859SLida.Horn 	}
1854448bf859SLida.Horn 	mutex_exit(&agent->agent_lock);
1855448bf859SLida.Horn 	if (umad_queue_mad_msg(agent, msgp))
1856448bf859SLida.Horn 		goto bad;
1857448bf859SLida.Horn 
1858448bf859SLida.Horn 	return;
1859448bf859SLida.Horn 
1860448bf859SLida.Horn bad:
1861448bf859SLida.Horn 	rc = ibmf_free_msg(agent->agent_reg->ibmf_reg_handle, &msgp);
1862448bf859SLida.Horn 	ASSERT(rc == IBMF_SUCCESS);
1863448bf859SLida.Horn }
1864448bf859SLida.Horn 
1865448bf859SLida.Horn /*
1866448bf859SLida.Horn  * Function:
1867448bf859SLida.Horn  *	umad_write
1868448bf859SLida.Horn  * Input:
1869448bf859SLida.Horn  *	dev		device
1870448bf859SLida.Horn  *	uiop		User I/O pointer
1871448bf859SLida.Horn  *	credp		Unused
1872448bf859SLida.Horn  * Output:
1873448bf859SLida.Horn  *	None
1874448bf859SLida.Horn  * Returns:
1875448bf859SLida.Horn  *	status
1876448bf859SLida.Horn  * Called by:
1877448bf859SLida.Horn  *	Device write framework
1878448bf859SLida.Horn  * Description:
1879448bf859SLida.Horn  *	Cannot write to ISSM device.  Allocate new umad_send structure
1880448bf859SLida.Horn  *	and ibmf message and copy from user space into allocated message.
1881448bf859SLida.Horn  *	Fill in required fields.  If this is a request make sure
1882448bf859SLida.Horn  *	umad_solicited_cb() is passed.
1883448bf859SLida.Horn  */
1884448bf859SLida.Horn /* ARGSUSED1 */
1885448bf859SLida.Horn static int
umad_write(dev_t dev,struct uio * uiop,cred_t * credp)1886448bf859SLida.Horn umad_write(dev_t dev, struct uio *uiop, cred_t *credp)
1887448bf859SLida.Horn {
1888448bf859SLida.Horn 	int			rc, rc2;
1889448bf859SLida.Horn 	int			mad_offset, flags = 0;
1890448bf859SLida.Horn 	int			hdr_len;
1891448bf859SLida.Horn 	size_t			len = uiop->uio_resid;
1892448bf859SLida.Horn 	minor_t			minor;
1893448bf859SLida.Horn 	ibmf_retrans_t		mad_retrans;
1894448bf859SLida.Horn 	umad_info_t		*info;
1895448bf859SLida.Horn 	umad_port_info_t		*port;
1896448bf859SLida.Horn 	umad_uctx_t		*uctx;
1897448bf859SLida.Horn 	umad_agent_t		*agent;
1898448bf859SLida.Horn 	struct ib_user_mad	*user_mad;	/* incoming uMAD hdr */
1899448bf859SLida.Horn 	ibmf_msg_t		*ibmf_msg;	/* outbound MAD mesg */
1900448bf859SLida.Horn 	ib_mad_hdr_t		*ib_mad_hdr;	/* outbound MAD hdrs */
1901448bf859SLida.Horn 	struct umad_send 	*umad_ctx;
1902448bf859SLida.Horn 	boolean_t		need_callback;
1903448bf859SLida.Horn 	ibt_status_t		status;
1904448bf859SLida.Horn 	ib_pkey_t		pkey;
1905448bf859SLida.Horn 
1906448bf859SLida.Horn 	info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
1907448bf859SLida.Horn 	if (info == NULL) {
1908448bf859SLida.Horn 		rc = ENXIO;
1909448bf859SLida.Horn 		goto err1;
1910448bf859SLida.Horn 	}
1911448bf859SLida.Horn 
1912448bf859SLida.Horn 	/* lookup the node and port #s */
1913448bf859SLida.Horn 	minor = getminor(dev);
1914448bf859SLida.Horn 
1915448bf859SLida.Horn 	if (ISSM_MINOR(minor)) {
1916448bf859SLida.Horn 		rc = ENXIO;
1917448bf859SLida.Horn 		goto err1;
1918448bf859SLida.Horn 	}
1919448bf859SLida.Horn 
1920448bf859SLida.Horn 	mutex_enter(&info->info_mutex);
1921448bf859SLida.Horn 	uctx = info->info_uctx[GET_UCTX(minor)];
1922448bf859SLida.Horn 	mutex_exit(&info->info_mutex);
1923448bf859SLida.Horn 	ASSERT(uctx != NULL);
1924448bf859SLida.Horn 	port = uctx->uctx_port;
1925448bf859SLida.Horn 	ASSERT(port != NULL);
1926448bf859SLida.Horn 
1927448bf859SLida.Horn 	umad_ctx = kmem_zalloc(sizeof (struct umad_send) + len, KM_SLEEP);
1928448bf859SLida.Horn 	umad_ctx->send_len = sizeof (struct umad_send) + len;
1929448bf859SLida.Horn 
1930448bf859SLida.Horn 	/* copy the MAD data in from user space */
1931448bf859SLida.Horn 	/* data = user_mad + mad_hdrs + class_hdrs + class data */
1932448bf859SLida.Horn 	/* LINTED */
1933448bf859SLida.Horn 	user_mad = (struct ib_user_mad *)umad_ctx->send_umad;
1934448bf859SLida.Horn 	rc = uiomove(user_mad, len, UIO_WRITE, uiop);
1935448bf859SLida.Horn 	if (rc != 0)
1936448bf859SLida.Horn 		goto err3;
1937448bf859SLida.Horn 
1938448bf859SLida.Horn 
1939448bf859SLida.Horn 	/* Look for the agent */
1940448bf859SLida.Horn 	mutex_enter(&uctx->uctx_lock);
1941448bf859SLida.Horn 	agent = umad_get_agent_by_id(uctx, user_mad->hdr.id);
1942448bf859SLida.Horn 	mutex_exit(&uctx->uctx_lock);
1943448bf859SLida.Horn 	if (! agent) {
1944448bf859SLida.Horn 		rc = EINVAL;
1945448bf859SLida.Horn 		goto err3;
1946448bf859SLida.Horn 	}
1947448bf859SLida.Horn 
1948448bf859SLida.Horn 	mutex_enter(&agent->agent_lock);
1949448bf859SLida.Horn 	if (agent->agent_flags & UMAD_AGENT_UNREGISTERING) {
1950448bf859SLida.Horn 		mutex_exit(&agent->agent_lock);
1951448bf859SLida.Horn 		rc = EINVAL;
1952448bf859SLida.Horn 		goto err3;
1953448bf859SLida.Horn 	}
1954448bf859SLida.Horn 
1955448bf859SLida.Horn 	/* Allocate the msg buf for IBMF */
1956448bf859SLida.Horn 	rc = ibmf_alloc_msg(agent->agent_reg->ibmf_reg_handle,
1957448bf859SLida.Horn 	    IBMF_ALLOC_NOSLEEP, &ibmf_msg);
1958448bf859SLida.Horn 	if (rc != IBMF_SUCCESS) {
1959448bf859SLida.Horn 		mutex_exit(&agent->agent_lock);
1960448bf859SLida.Horn 		goto err3;
1961448bf859SLida.Horn 	}
1962448bf859SLida.Horn 
1963448bf859SLida.Horn 	ib_mad_hdr = (ib_mad_hdr_t *)user_mad->data;
1964448bf859SLida.Horn 
1965448bf859SLida.Horn 	hdr_len = umad_get_mad_data_offset(ib_mad_hdr->MgmtClass);
1966448bf859SLida.Horn 
1967448bf859SLida.Horn 	/*
1968448bf859SLida.Horn 	 * build the IBMF msg from the mad data passed in
1969448bf859SLida.Horn 	 * construct the addr info
1970448bf859SLida.Horn 	 */
1971448bf859SLida.Horn #if defined(__FUTURE_FEATURE__)
1972448bf859SLida.Horn 	/* TODO Proper GRH handling (non-smp traffic only) */
1973448bf859SLida.Horn 	if (mad.addr.grh_present) {
1974448bf859SLida.Horn 		memcpy(&ibmf_msg->im_global_addr.ig_recver_gid, mad.addr.gid,
1975448bf859SLida.Horn 		    16);
1976448bf859SLida.Horn 		//  where can we get the GID??
1977448bf859SLida.Horn 		im_global_addr.ig_sender_gid = get_gid(umad->addr.gid_index);
1978448bf859SLida.Horn 		ibmf_msg->im_global_addr.ig_tclass = mad.addr.traffic_class;
1979448bf859SLida.Horn 		ibmf_msg->im_global_addr.ig_hop_limit = mad.addr.hop_limit;
1980448bf859SLida.Horn 		ibmf_msg->im_global_addr.ig_flow_label = mad.addr.flow_label;
1981448bf859SLida.Horn 	}
1982448bf859SLida.Horn #endif
1983448bf859SLida.Horn 
1984448bf859SLida.Horn 	/*
1985448bf859SLida.Horn 	 * Note: umad lid, qpn and qkey are in network order, so we need
1986448bf859SLida.Horn 	 * to revert them to give them to ibmf. See userspace
1987448bf859SLida.Horn 	 * umad_set_addr() and umad_set_addr_net().
1988448bf859SLida.Horn 	 */
1989448bf859SLida.Horn 	ibmf_msg->im_local_addr.ia_local_lid = port->port_lid;
1990448bf859SLida.Horn 	ibmf_msg->im_local_addr.ia_remote_lid = ntohs(user_mad->hdr.lid);
1991448bf859SLida.Horn 	ibmf_msg->im_local_addr.ia_remote_qno = ntohl(user_mad->hdr.qpn);
1992448bf859SLida.Horn 	ibmf_msg->im_local_addr.ia_q_key = ntohl(user_mad->hdr.qkey);
1993448bf859SLida.Horn 	ibmf_msg->im_local_addr.ia_service_level = user_mad->hdr.sl;
1994448bf859SLida.Horn 
1995448bf859SLida.Horn 	status = ibt_index2pkey(port->port_hca->hca_handle,
1996448bf859SLida.Horn 	    port->port_num, user_mad->hdr.pkey_index, &pkey);
1997448bf859SLida.Horn 	if (status != IBT_SUCCESS) {
1998448bf859SLida.Horn #if defined(DEBUG)
1999448bf859SLida.Horn 		SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
2000448bf859SLida.Horn 		    "umad_write: ibt_index2pkey failed %d",
2001448bf859SLida.Horn 		    status);
2002448bf859SLida.Horn #endif
2003448bf859SLida.Horn 	}
2004448bf859SLida.Horn 	else
2005448bf859SLida.Horn 		ibmf_msg->im_local_addr.ia_p_key = ntohs(pkey);
2006448bf859SLida.Horn 
2007448bf859SLida.Horn 	if ((ib_mad_hdr->R_Method & 0x80) == 0)
2008448bf859SLida.Horn 		flags = IBMF_MSG_TRANS_FLAG_SEQ;
2009448bf859SLida.Horn 
2010448bf859SLida.Horn 	/*
2011448bf859SLida.Horn 	 * This code is only correct for the cases of
2012448bf859SLida.Horn 	 * no headers beyond the MAD header or the case of
2013448bf859SLida.Horn 	 * MAD_MGMT_CLASS_SUBN_ADM (SA type) which has both
2014448bf859SLida.Horn 	 * an RMPP header and an SA header.  Other header combinations
2015448bf859SLida.Horn 	 * are simply not dealt with correctly, but no applications
2016448bf859SLida.Horn 	 * utilize them either, so we should be ok.
2017448bf859SLida.Horn 	 */
2018448bf859SLida.Horn 
2019448bf859SLida.Horn 	/* set use RMPP if UserAgent registered for it */
2020448bf859SLida.Horn 	if (agent->agent_req.rmpp_version > 0) {
2021448bf859SLida.Horn 		ibmf_rmpp_hdr_t *rmpp_hdr;
2022448bf859SLida.Horn 
2023448bf859SLida.Horn 		rmpp_hdr = (ibmf_rmpp_hdr_t *)(ib_mad_hdr + 1);
2024448bf859SLida.Horn 
2025448bf859SLida.Horn 		if (rmpp_hdr->rmpp_flags != 0)
2026448bf859SLida.Horn 			flags |= IBMF_MSG_TRANS_FLAG_RMPP;
2027448bf859SLida.Horn 	}
2028448bf859SLida.Horn 
2029448bf859SLida.Horn 	/* construct the msg bufs */
2030448bf859SLida.Horn 	ibmf_msg->im_msgbufs_send.im_bufs_mad_hdr = ib_mad_hdr;
2031448bf859SLida.Horn 
2032448bf859SLida.Horn 	hdr_len = umad_get_mad_clhdr_offset(ib_mad_hdr->MgmtClass);
2033448bf859SLida.Horn 	mad_offset = umad_get_mad_data_offset(ib_mad_hdr->MgmtClass);
2034448bf859SLida.Horn 
2035448bf859SLida.Horn 	/* Class headers and len, rmpp? */
2036448bf859SLida.Horn 	ibmf_msg->im_msgbufs_send.im_bufs_cl_hdr =
2037448bf859SLida.Horn 	    (unsigned char *)user_mad +
2038448bf859SLida.Horn 	    offsetof(struct ib_user_mad, data) + hdr_len;
2039448bf859SLida.Horn 	ibmf_msg->im_msgbufs_send.im_bufs_cl_hdr_len =
2040448bf859SLida.Horn 	    mad_offset - hdr_len;
2041448bf859SLida.Horn 
2042448bf859SLida.Horn 	ibmf_msg->im_msgbufs_send.im_bufs_cl_data =
2043448bf859SLida.Horn 	    (unsigned char *) user_mad + (sizeof (struct ib_user_mad) +
2044448bf859SLida.Horn 	    mad_offset);
2045448bf859SLida.Horn 	ibmf_msg->im_msgbufs_send.im_bufs_cl_data_len =
2046448bf859SLida.Horn 	    len - sizeof (struct ib_user_mad) - mad_offset;
2047448bf859SLida.Horn 
2048448bf859SLida.Horn 	mad_retrans.retrans_retries = user_mad->hdr.retries;
2049448bf859SLida.Horn 	mad_retrans.retrans_rtv = 0;
2050448bf859SLida.Horn 	mad_retrans.retrans_rttv = 0;
2051448bf859SLida.Horn 	mad_retrans.retrans_trans_to = 0;
2052448bf859SLida.Horn 
2053448bf859SLida.Horn 	umad_ctx->send_agent = agent;
2054448bf859SLida.Horn 
2055448bf859SLida.Horn 	need_callback = (flags & IBMF_MSG_TRANS_FLAG_SEQ) != 0;
2056448bf859SLida.Horn 
2057448bf859SLida.Horn 	if (need_callback)
2058448bf859SLida.Horn 		agent->agent_outstanding_msgs++;
2059448bf859SLida.Horn 
2060448bf859SLida.Horn 	mutex_exit(&agent->agent_lock);
2061448bf859SLida.Horn 
2062448bf859SLida.Horn 	/* pass the MAD down to the IBMF layer */
2063448bf859SLida.Horn 	rc = ibmf_msg_transport(agent->agent_reg->ibmf_reg_handle,
2064448bf859SLida.Horn 	    IBMF_QP_HANDLE_DEFAULT,
2065448bf859SLida.Horn 	    ibmf_msg, &mad_retrans,
2066448bf859SLida.Horn 	    need_callback ? umad_solicited_cb : NULL,
2067448bf859SLida.Horn 	    umad_ctx, flags);
2068448bf859SLida.Horn 
2069448bf859SLida.Horn 	if (! need_callback) {
2070448bf859SLida.Horn 		rc2 = ibmf_free_msg(agent->agent_reg->ibmf_reg_handle,
2071448bf859SLida.Horn 		    &ibmf_msg);
2072448bf859SLida.Horn 		ASSERT(rc2 == IBMF_SUCCESS);
2073448bf859SLida.Horn 
2074448bf859SLida.Horn 		if (rc != IBMF_SUCCESS) {
2075448bf859SLida.Horn 			rc = EIO;
2076448bf859SLida.Horn 			goto err3;
2077448bf859SLida.Horn 		}
2078448bf859SLida.Horn 	} else if (rc != IBMF_SUCCESS) {
2079448bf859SLida.Horn 		mutex_enter(&agent->agent_lock);
2080448bf859SLida.Horn 		agent->agent_outstanding_msgs--;
2081448bf859SLida.Horn 		ASSERT(agent->agent_outstanding_msgs >= 0);
2082448bf859SLida.Horn 		if (agent->agent_flags & UMAD_AGENT_UNREGISTERING) {
2083448bf859SLida.Horn 			if (agent->agent_outstanding_msgs == 0)
2084448bf859SLida.Horn 				cv_signal(&agent->agent_cv);
2085448bf859SLida.Horn 		}
2086448bf859SLida.Horn 		mutex_exit(&agent->agent_lock);
2087448bf859SLida.Horn 
2088448bf859SLida.Horn 		rc2 = ibmf_free_msg(agent->agent_reg->ibmf_reg_handle,
2089448bf859SLida.Horn 		    &ibmf_msg);
2090448bf859SLida.Horn 		ASSERT(rc2 == IBMF_SUCCESS);
2091448bf859SLida.Horn 
2092448bf859SLida.Horn 		rc = EIO;
2093448bf859SLida.Horn 		goto err3;
2094448bf859SLida.Horn 	}
2095448bf859SLida.Horn 
2096448bf859SLida.Horn 	return (0);
2097448bf859SLida.Horn 
2098448bf859SLida.Horn err3:
2099448bf859SLida.Horn 	kmem_free(umad_ctx, umad_ctx->send_len);
2100448bf859SLida.Horn 
2101448bf859SLida.Horn err1:
2102448bf859SLida.Horn 	return (rc);
2103448bf859SLida.Horn }
2104448bf859SLida.Horn 
2105448bf859SLida.Horn /*
2106448bf859SLida.Horn  * Function:
2107448bf859SLida.Horn  *	umad_async_handler
2108448bf859SLida.Horn  * Input:
2109448bf859SLida.Horn  *	private		Unused
2110448bf859SLida.Horn  *	hca_hdl		Unused
2111448bf859SLida.Horn  *	code		Unused
2112448bf859SLida.Horn  *	event		Unused
2113448bf859SLida.Horn  * Output:
2114448bf859SLida.Horn  *	None
2115448bf859SLida.Horn  * Returns:
2116448bf859SLida.Horn  *	None
2117448bf859SLida.Horn  * Called by:
2118448bf859SLida.Horn  *	IBTL framework for asynchronous events.
2119448bf859SLida.Horn  * Description:
2120448bf859SLida.Horn  *	No special event handling currently.
2121448bf859SLida.Horn  */
2122448bf859SLida.Horn /* ARGSUSED */
2123448bf859SLida.Horn static void
umad_async_handler(void * private,ibt_hca_hdl_t hca_hdl,ibt_async_code_t code,ibt_async_event_t * event)2124448bf859SLida.Horn umad_async_handler(
2125448bf859SLida.Horn 	void *private,
2126448bf859SLida.Horn 	ibt_hca_hdl_t hca_hdl,
2127448bf859SLida.Horn 	ibt_async_code_t code,
2128448bf859SLida.Horn 	ibt_async_event_t *event)
2129448bf859SLida.Horn {
2130448bf859SLida.Horn }
2131448bf859SLida.Horn 
2132448bf859SLida.Horn /*
2133448bf859SLida.Horn  * Need this ioctl to enable the newer interface (pkey_index and some
2134448bf859SLida.Horn  * reserved key).  Since OFED changed the abi without changing the abi
2135448bf859SLida.Horn  * version.  This resulted in wo abi interfaces (with and without the
2136448bf859SLida.Horn  * pkey_index and some reserved bytes, but one abi version number.  The
2137448bf859SLida.Horn  * application then tries to do an ioctl() to enable the "newwer" interface
2138448bf859SLida.Horn  * and it that ioctl succeeds, the application code assumes the newer abi
2139448bf859SLida.Horn  * interface otherwise it assumes the older abi intrface (Uggggggg).
2140448bf859SLida.Horn  */
2141448bf859SLida.Horn static int
umad_pkey_enable()2142448bf859SLida.Horn umad_pkey_enable()
2143448bf859SLida.Horn {
2144448bf859SLida.Horn 	/* When we move to later releases of OFED, this will go away */
2145448bf859SLida.Horn 	return (DDI_SUCCESS);
2146448bf859SLida.Horn 
2147448bf859SLida.Horn }
2148448bf859SLida.Horn 
2149448bf859SLida.Horn /*
2150448bf859SLida.Horn  * Function:
2151448bf859SLida.Horn  *	umad_ioctl
2152448bf859SLida.Horn  * Input:
2153448bf859SLida.Horn  *	dev		device
2154448bf859SLida.Horn  *	cmd		IB_USER_MAD_ENABLE_PKEY, IB_USER_MAD_REGISTER_AGENT or
2155448bf859SLida.Horn  *			IB_USER_MAD_UNREGISTER_AGENT
2156448bf859SLida.Horn  *	arg		which agent to register or unregister
2157448bf859SLida.Horn  *	mode		passed on to ddi_copyin()
2158448bf859SLida.Horn  *	credp		Unused
2159448bf859SLida.Horn  *	rvalp		Unused
2160448bf859SLida.Horn  * Output:
2161448bf859SLida.Horn  *	None
2162448bf859SLida.Horn  * Returns:
2163448bf859SLida.Horn  *	Error status
2164448bf859SLida.Horn  * Called by:
2165448bf859SLida.Horn  *	Device ioctl framework
2166448bf859SLida.Horn  * Description:
2167448bf859SLida.Horn  *	IB_USER_MAD_ENABLE_PKEY just allows the ioctl to succed to
2168448bf859SLida.Horn  *	indicate that we are at ABI version 5+, not really 5.
2169448bf859SLida.Horn  *	IB_USER_MAD_REGISTER_AGENT requests that a specific MAD class
2170448bf859SLida.Horn  *	for this device be handled by this process.
2171448bf859SLida.Horn  *	IB_USER_MAD_UNREGISTER_AGENT undoes the request above.
2172448bf859SLida.Horn  */
2173448bf859SLida.Horn /* ARGSUSED3 */
2174448bf859SLida.Horn static int
umad_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)2175448bf859SLida.Horn umad_ioctl(
2176448bf859SLida.Horn 	dev_t dev,
2177448bf859SLida.Horn 	int cmd,
2178448bf859SLida.Horn 	intptr_t arg,
2179448bf859SLida.Horn 	int mode,
2180448bf859SLida.Horn 	cred_t *credp,
2181448bf859SLida.Horn 	int *rvalp)
2182448bf859SLida.Horn {
2183448bf859SLida.Horn 	int				rc = 0;
2184448bf859SLida.Horn 	int				minor;
2185448bf859SLida.Horn 	umad_info_t			*info;
2186448bf859SLida.Horn 	umad_port_info_t		*port;
2187448bf859SLida.Horn 	umad_uctx_t			*uctx;
2188448bf859SLida.Horn 	struct ib_user_mad_reg_req	req = {0};
2189448bf859SLida.Horn 
2190448bf859SLida.Horn 	info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
2191448bf859SLida.Horn 	if (info == NULL) {
2192448bf859SLida.Horn 		rc = ENXIO;
2193448bf859SLida.Horn 		goto err1;
2194448bf859SLida.Horn 	}
2195448bf859SLida.Horn 
2196448bf859SLida.Horn 	/* lookup the node and port #s */
2197448bf859SLida.Horn 	minor = getminor(dev);
2198448bf859SLida.Horn 
2199448bf859SLida.Horn 	if (ISSM_MINOR(minor)) {
2200448bf859SLida.Horn 		rc = ENXIO;
2201448bf859SLida.Horn 		goto err1;
2202448bf859SLida.Horn 	}
2203448bf859SLida.Horn 
2204448bf859SLida.Horn 	mutex_enter(&info->info_mutex);
2205448bf859SLida.Horn 	uctx = info->info_uctx[GET_UCTX(minor)];
2206448bf859SLida.Horn 	mutex_exit(&info->info_mutex);
2207448bf859SLida.Horn 	ASSERT(uctx != NULL);
2208448bf859SLida.Horn 	port = uctx->uctx_port;
2209448bf859SLida.Horn 	ASSERT(port != NULL);
2210448bf859SLida.Horn 
2211448bf859SLida.Horn 	if (cmd == IB_USER_MAD_ENABLE_PKEY)
2212448bf859SLida.Horn 		return (umad_pkey_enable());
2213448bf859SLida.Horn 
2214448bf859SLida.Horn 	if (ddi_copyin((void *) arg, &req, sizeof (req), mode) != 0) {
2215448bf859SLida.Horn 		rc = EFAULT;
2216448bf859SLida.Horn 		goto err1;
2217448bf859SLida.Horn 	}
2218448bf859SLida.Horn 
2219448bf859SLida.Horn 	switch (cmd) {
2220448bf859SLida.Horn 	case IB_USER_MAD_REGISTER_AGENT:
2221448bf859SLida.Horn 		mutex_enter(&uctx->uctx_lock);
2222448bf859SLida.Horn 		rc = umad_register(&req, uctx);
2223448bf859SLida.Horn 		mutex_exit(&uctx->uctx_lock);
2224448bf859SLida.Horn 		if (rc)
2225448bf859SLida.Horn 			goto err1;
2226448bf859SLida.Horn 
2227448bf859SLida.Horn 		/* return agent ID to user */
2228448bf859SLida.Horn 		rc = ddi_copyout(&req, (void *) arg, sizeof (req), mode);
2229448bf859SLida.Horn 
2230448bf859SLida.Horn 		if (rc) {
2231448bf859SLida.Horn 			mutex_enter(&uctx->uctx_lock);
2232448bf859SLida.Horn 			(void) umad_unregister(&req, uctx);
2233448bf859SLida.Horn 			mutex_exit(&uctx->uctx_lock);
2234448bf859SLida.Horn 
2235448bf859SLida.Horn 			rc = EFAULT;
2236448bf859SLida.Horn 			goto err1;
2237448bf859SLida.Horn 		}
2238448bf859SLida.Horn 		break;
2239448bf859SLida.Horn 
2240448bf859SLida.Horn 	case IB_USER_MAD_UNREGISTER_AGENT:
2241448bf859SLida.Horn 		mutex_enter(&uctx->uctx_lock);
2242448bf859SLida.Horn 		rc = umad_unregister(&req, uctx);
2243448bf859SLida.Horn 		mutex_exit(&uctx->uctx_lock);
2244448bf859SLida.Horn 		break;
2245448bf859SLida.Horn 
2246448bf859SLida.Horn 	default:
2247448bf859SLida.Horn 		rc = DDI_FAILURE;
2248448bf859SLida.Horn 	}
2249448bf859SLida.Horn 
2250448bf859SLida.Horn 
2251448bf859SLida.Horn err1:
2252448bf859SLida.Horn 	return (rc);
2253448bf859SLida.Horn }
2254448bf859SLida.Horn 
2255448bf859SLida.Horn /*
2256448bf859SLida.Horn  * Get a new unique agent ID. The agent list is already locked. The
2257448bf859SLida.Horn  * complexity is not ideal, but the number of agents should be small
2258448bf859SLida.Horn  * (ie 2 or 3) so it shouldn't matter.
2259448bf859SLida.Horn  */
2260448bf859SLida.Horn static int
umad_get_new_agent_id(umad_uctx_t * uctx)2261448bf859SLida.Horn umad_get_new_agent_id(umad_uctx_t *uctx)
2262448bf859SLida.Horn {
2263448bf859SLida.Horn 	boolean_t found;
2264448bf859SLida.Horn 	unsigned int agent_id;
2265448bf859SLida.Horn 	llist_head_t *entry;
2266448bf859SLida.Horn 
2267448bf859SLida.Horn 	agent_id = 0;
2268448bf859SLida.Horn 
2269448bf859SLida.Horn 	ASSERT(MUTEX_HELD(&uctx->uctx_lock));
2270448bf859SLida.Horn 
2271448bf859SLida.Horn 	for (;;) {
2272448bf859SLida.Horn 		found = B_FALSE;
2273448bf859SLida.Horn 		list_for_each(entry, &uctx->uctx_agent_list) {
2274448bf859SLida.Horn 			umad_agent_t *agent = entry->ptr;
2275448bf859SLida.Horn 
2276448bf859SLida.Horn 			if (agent_id == agent->agent_req.id) {
2277448bf859SLida.Horn 				found = B_TRUE;
2278448bf859SLida.Horn 				break;
2279448bf859SLida.Horn 			}
2280448bf859SLida.Horn 		}
2281448bf859SLida.Horn 
2282448bf859SLida.Horn 		if (! found)
2283448bf859SLida.Horn 			break;
2284448bf859SLida.Horn 
2285448bf859SLida.Horn 		agent_id++;
2286448bf859SLida.Horn 	}
2287448bf859SLida.Horn 
2288448bf859SLida.Horn 	return (agent_id);
2289448bf859SLida.Horn }
2290448bf859SLida.Horn 
2291448bf859SLida.Horn /*
2292448bf859SLida.Horn  * Function:
2293448bf859SLida.Horn  *	umad_register
2294448bf859SLida.Horn  * Input:
2295448bf859SLida.Horn  *	req 	User registration request
2296448bf859SLida.Horn  *	uctx	User context
2297448bf859SLida.Horn  * Output:
2298448bf859SLida.Horn  *	None
2299448bf859SLida.Horn  * Returns:
2300448bf859SLida.Horn  *	status
2301448bf859SLida.Horn  * Called by:
2302448bf859SLida.Horn  *	umad_ioctl
2303448bf859SLida.Horn  * Description:
2304448bf859SLida.Horn  *      Handles the registration of user agents from userspace.
2305448bf859SLida.Horn  *      Each call will result in the creation of a new agent object for
2306448bf859SLida.Horn  *      the given HCA/port.  If UMAD_CA_MAX_AGENTS has been reached then an
2307448bf859SLida.Horn  *      error is raised.
2308448bf859SLida.Horn  */
2309448bf859SLida.Horn static int
umad_register(struct ib_user_mad_reg_req * req,umad_uctx_t * uctx)2310448bf859SLida.Horn umad_register(struct ib_user_mad_reg_req *req, umad_uctx_t *uctx)
2311448bf859SLida.Horn {
2312448bf859SLida.Horn 	int			rc = IBMF_SUCCESS;
2313448bf859SLida.Horn 	umad_agent_t		*agent = NULL;
2314448bf859SLida.Horn 	umad_port_info_t	*port;
2315448bf859SLida.Horn 
2316448bf859SLida.Horn 	/* check for valid QP */
2317448bf859SLida.Horn 	if ((req->qpn != 0) && (req->qpn != 1)) {
2318448bf859SLida.Horn 		rc = EINVAL;
2319448bf859SLida.Horn 		goto err1;
2320448bf859SLida.Horn 	}
2321448bf859SLida.Horn 
2322448bf859SLida.Horn 
2323448bf859SLida.Horn 	ASSERT(MUTEX_HELD(&uctx->uctx_lock));
2324448bf859SLida.Horn 
2325448bf859SLida.Horn 	port = uctx->uctx_port;
2326448bf859SLida.Horn 	ASSERT(port != NULL);
2327448bf859SLida.Horn 
2328448bf859SLida.Horn 	agent = umad_get_agent_by_class(uctx, req->mgmt_class);
2329448bf859SLida.Horn 	if (agent != NULL)
2330448bf859SLida.Horn 		return (IBMF_PORT_IN_USE);
2331448bf859SLida.Horn 
2332448bf859SLida.Horn 	agent = kmem_zalloc(sizeof (umad_agent_t), KM_SLEEP);
2333448bf859SLida.Horn 	mutex_init(&agent->agent_lock, NULL, MUTEX_DRIVER, NULL);
2334448bf859SLida.Horn 	cv_init(&agent->agent_cv, NULL, CV_DRIVER, NULL);
2335448bf859SLida.Horn 
2336448bf859SLida.Horn 	agent->agent_req = *req;
2337448bf859SLida.Horn 	agent->agent_uctx = uctx;
2338448bf859SLida.Horn 
2339448bf859SLida.Horn 	llist_head_init(&agent->agent_list, agent);
2340448bf859SLida.Horn 
2341448bf859SLida.Horn 	agent->agent_req.id = req->id = umad_get_new_agent_id(uctx);
2342448bf859SLida.Horn 
2343448bf859SLida.Horn 	rc = umad_register_agent(agent);
2344448bf859SLida.Horn 	if (rc)
2345448bf859SLida.Horn 		goto err1;
2346448bf859SLida.Horn 
2347448bf859SLida.Horn 	llist_add(&agent->agent_list, &uctx->uctx_agent_list);
2348448bf859SLida.Horn 
2349448bf859SLida.Horn 	return (0);
2350448bf859SLida.Horn 
2351448bf859SLida.Horn err1:
2352448bf859SLida.Horn 	if (rc) {
2353448bf859SLida.Horn 		if (agent) {
2354448bf859SLida.Horn 			cv_destroy(&agent->agent_cv);
2355448bf859SLida.Horn 			mutex_destroy(&agent->agent_lock);
2356448bf859SLida.Horn 			kmem_free(agent, sizeof (umad_agent_t));
2357448bf859SLida.Horn 		}
2358448bf859SLida.Horn 	}
2359448bf859SLida.Horn 
2360448bf859SLida.Horn 	return (rc);
2361448bf859SLida.Horn }
2362448bf859SLida.Horn 
2363448bf859SLida.Horn /*
2364448bf859SLida.Horn  * Function:
2365448bf859SLida.Horn  *	umad_unregister
2366448bf859SLida.Horn  * Input:
2367448bf859SLida.Horn  *	req		- user unregister request
2368448bf859SLida.Horn  *	info		- user context
2369448bf859SLida.Horn  * Output:
2370448bf859SLida.Horn  *	None
2371448bf859SLida.Horn  * Returns:
2372448bf859SLida.Horn  *	Status
2373448bf859SLida.Horn  * Called by:
2374448bf859SLida.Horn  *	umad_ioct
2375448bf859SLida.Horn  * Description:
2376448bf859SLida.Horn  *	Undoes registration.  Waits for pending operations before completing.
2377448bf859SLida.Horn  */
2378448bf859SLida.Horn static int
umad_unregister(struct ib_user_mad_reg_req * req,umad_uctx_t * uctx)2379448bf859SLida.Horn umad_unregister(struct ib_user_mad_reg_req *req, umad_uctx_t *uctx)
2380448bf859SLida.Horn {
2381448bf859SLida.Horn 	int			agent_id = req->id;
2382448bf859SLida.Horn 	umad_agent_t		*agent;
2383448bf859SLida.Horn 	int			rc;
2384448bf859SLida.Horn 	genlist_entry_t		*entry;
2385448bf859SLida.Horn 	struct ibmf_reg_info	*ibmf_info;
2386448bf859SLida.Horn 	boolean_t		did_ibmf_unregister;
2387448bf859SLida.Horn 	umad_port_info_t	*port;
2388448bf859SLida.Horn 
2389448bf859SLida.Horn 	ASSERT(MUTEX_HELD(&uctx->uctx_lock));
2390448bf859SLida.Horn 
2391448bf859SLida.Horn 	agent = umad_get_agent_by_id(uctx, agent_id);
2392448bf859SLida.Horn 	if (agent == NULL) {
2393448bf859SLida.Horn 		rc = EINVAL;
2394448bf859SLida.Horn 		goto done;
2395448bf859SLida.Horn 	}
2396448bf859SLida.Horn 
2397448bf859SLida.Horn 	mutex_enter(&agent->agent_lock);
2398448bf859SLida.Horn 	while (agent->agent_outstanding_msgs != 0) {
2399448bf859SLida.Horn 		agent->agent_flags |= UMAD_AGENT_UNREGISTERING;
2400448bf859SLida.Horn 		cv_wait(&agent->agent_cv, &agent->agent_lock);
2401448bf859SLida.Horn 	}
2402448bf859SLida.Horn 	if (agent->agent_flags & UMAD_HANDLING_ASYNC)
2403448bf859SLida.Horn 		agent->agent_reg->ibmf_reg_uctx = NULL;
2404448bf859SLida.Horn 
2405448bf859SLida.Horn 	mutex_exit(&agent->agent_lock);
2406448bf859SLida.Horn 
2407448bf859SLida.Horn 	/* Remove agent from the uctx list. */
2408448bf859SLida.Horn 	llist_del(&agent->agent_list);
2409448bf859SLida.Horn 
2410448bf859SLida.Horn 	/* Get the IBMF registration information */
2411448bf859SLida.Horn 	ibmf_info = agent->agent_reg;
2412448bf859SLida.Horn 
2413448bf859SLida.Horn 	mutex_enter(&ibmf_info->ibmf_reg_lock);
2414448bf859SLida.Horn 
2415448bf859SLida.Horn 	/* Remove the pending received MADs. */
2416448bf859SLida.Horn 	mutex_enter(&uctx->uctx_recv_lock);
2417448bf859SLida.Horn 	while ((entry = remove_genlist_head(&uctx->uctx_recv_list))) {
2418448bf859SLida.Horn 		ib_umad_msg_t *msg;
2419448bf859SLida.Horn 		ibmf_msg_t *ibmf_msg;
2420448bf859SLida.Horn 
2421448bf859SLida.Horn 		mutex_exit(&uctx->uctx_recv_lock);
2422448bf859SLida.Horn 
2423448bf859SLida.Horn 		msg = (ib_umad_msg_t *)entry->data;
2424448bf859SLida.Horn 		ibmf_msg = msg->umad_msg_ibmf_msg;
2425448bf859SLida.Horn 
2426448bf859SLida.Horn 		rc = ibmf_free_msg(ibmf_info->ibmf_reg_handle, &ibmf_msg);
2427448bf859SLida.Horn 		ASSERT(rc == IBMF_SUCCESS);
2428448bf859SLida.Horn 
2429448bf859SLida.Horn 		kmem_free(msg, sizeof (*msg));
2430448bf859SLida.Horn 
2431448bf859SLida.Horn 		mutex_enter(&uctx->uctx_recv_lock);
2432448bf859SLida.Horn 	}
2433448bf859SLida.Horn 	mutex_exit(&uctx->uctx_recv_lock);
2434448bf859SLida.Horn 
2435448bf859SLida.Horn 	/* If no more references, tear down the ibmf registration */
2436448bf859SLida.Horn 	if (--ibmf_info->ibmf_reg_refcnt == 0) {
2437448bf859SLida.Horn 		ibmf_info->ibmf_flags |= UMAD_IBMF_UNREGISTERING;
2438448bf859SLida.Horn 		mutex_exit(&ibmf_info->ibmf_reg_lock);
2439448bf859SLida.Horn 		/* Remove the callback */
2440448bf859SLida.Horn 		rc = ibmf_tear_down_async_cb(ibmf_info->ibmf_reg_handle,
2441448bf859SLida.Horn 		    IBMF_QP_HANDLE_DEFAULT, 0);
2442448bf859SLida.Horn #if defined(DEBUG)
2443448bf859SLida.Horn 		if (rc) {
2444448bf859SLida.Horn 			SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
2445448bf859SLida.Horn 			    "umad_unregister: failed "
2446448bf859SLida.Horn 			    "ibmf_tear_down_async_cb() error %d\n", rc);
2447448bf859SLida.Horn 		}
2448448bf859SLida.Horn #endif
2449448bf859SLida.Horn 
2450448bf859SLida.Horn 		/* Remove the pending received MADs. */
2451448bf859SLida.Horn 		mutex_enter(&uctx->uctx_recv_lock);
2452448bf859SLida.Horn 		while ((entry = remove_genlist_head(&uctx->uctx_recv_list))) {
2453448bf859SLida.Horn 			ib_umad_msg_t *msg;
2454448bf859SLida.Horn 			ibmf_msg_t *ibmf_msg;
2455448bf859SLida.Horn 
2456448bf859SLida.Horn 			mutex_exit(&uctx->uctx_recv_lock);
2457448bf859SLida.Horn 
2458448bf859SLida.Horn 			msg = (ib_umad_msg_t *)entry->data;
2459448bf859SLida.Horn 			ibmf_msg = msg->umad_msg_ibmf_msg;
2460448bf859SLida.Horn 
2461448bf859SLida.Horn 			rc = ibmf_free_msg(ibmf_info->ibmf_reg_handle,
2462448bf859SLida.Horn 			    &ibmf_msg);
2463448bf859SLida.Horn 			ASSERT(rc == IBMF_SUCCESS);
2464448bf859SLida.Horn 
2465448bf859SLida.Horn 			kmem_free(msg, sizeof (*msg));
2466448bf859SLida.Horn 
2467448bf859SLida.Horn 			mutex_enter(&uctx->uctx_recv_lock);
2468448bf859SLida.Horn 		}
2469448bf859SLida.Horn 		mutex_exit(&uctx->uctx_recv_lock);
2470448bf859SLida.Horn 
2471448bf859SLida.Horn 
2472448bf859SLida.Horn 		/* unregister from IBMF */
2473448bf859SLida.Horn 		rc = ibmf_unregister(&ibmf_info->ibmf_reg_handle, 0);
2474448bf859SLida.Horn #if defined(DEBUG)
2475448bf859SLida.Horn 		if (rc) {
2476448bf859SLida.Horn 			SOL_OFS_DPRINTF_L5(sol_umad_dbg_str,
2477448bf859SLida.Horn 			    "umad_unregister: failed "
2478448bf859SLida.Horn 			    "ibmf_unregister() error %d\n", rc);
2479448bf859SLida.Horn 		}
2480448bf859SLida.Horn #endif
2481448bf859SLida.Horn 		mutex_enter(&ibmf_info->ibmf_reg_lock);
2482448bf859SLida.Horn 		ibmf_info->ibmf_flags &= ~UMAD_IBMF_UNREGISTERING;
2483448bf859SLida.Horn 		cv_signal(&ibmf_info->ibmf_cv);
2484448bf859SLida.Horn 		mutex_exit(&ibmf_info->ibmf_reg_lock);
2485448bf859SLida.Horn 		did_ibmf_unregister = B_TRUE;
2486448bf859SLida.Horn 	} else {
2487448bf859SLida.Horn 		mutex_exit(&ibmf_info->ibmf_reg_lock);
2488448bf859SLida.Horn 		did_ibmf_unregister = B_FALSE;
2489448bf859SLida.Horn 	}
2490448bf859SLida.Horn 
2491448bf859SLida.Horn 	if (did_ibmf_unregister) {
2492448bf859SLida.Horn 		llist_head_t *entry;
2493448bf859SLida.Horn 		struct ibmf_reg_info *ibmf_entry = NULL;
2494448bf859SLida.Horn #if defined(DEBUG)
2495448bf859SLida.Horn 		boolean_t found = B_FALSE;
2496448bf859SLida.Horn #endif
2497448bf859SLida.Horn 
2498448bf859SLida.Horn 		port = uctx->uctx_port;
2499448bf859SLida.Horn 		mutex_enter(&port->port_lock);
2500448bf859SLida.Horn 		list_for_each(entry, &port->port_ibmf_regs) {
2501448bf859SLida.Horn 			ibmf_entry = entry->ptr;
2502448bf859SLida.Horn 
2503448bf859SLida.Horn 			if (ibmf_info == ibmf_entry) {
2504448bf859SLida.Horn #if defined(DEBUG)
2505448bf859SLida.Horn 				found = B_TRUE;
2506448bf859SLida.Horn #endif
2507448bf859SLida.Horn 				break;
2508448bf859SLida.Horn 			}
2509448bf859SLida.Horn 		}
2510448bf859SLida.Horn 		ASSERT(found);
2511448bf859SLida.Horn 		llist_del(entry);
2512448bf859SLida.Horn 		kmem_free(entry, sizeof (*entry));
2513448bf859SLida.Horn 
2514448bf859SLida.Horn 		mutex_exit(&port->port_lock);
2515448bf859SLida.Horn 		/* Release the registration memory */
2516448bf859SLida.Horn 		kmem_free(ibmf_info, sizeof (*ibmf_info));
2517448bf859SLida.Horn 	}
2518448bf859SLida.Horn 	agent->agent_uctx = NULL;
2519448bf859SLida.Horn 	cv_destroy(&agent->agent_cv);
2520448bf859SLida.Horn 	mutex_destroy(&agent->agent_lock);
2521448bf859SLida.Horn 	kmem_free(agent, sizeof (*agent));
2522448bf859SLida.Horn 
2523448bf859SLida.Horn 	rc = 0;
2524448bf859SLida.Horn 
2525448bf859SLida.Horn done:
2526448bf859SLida.Horn 	return (rc);
2527448bf859SLida.Horn }
2528448bf859SLida.Horn 
2529448bf859SLida.Horn 
2530448bf859SLida.Horn /*
2531448bf859SLida.Horn  * Function:
2532448bf859SLida.Horn  *      umad_poll
2533448bf859SLida.Horn  * Input:
2534448bf859SLida.Horn  *	dev             device
2535448bf859SLida.Horn  *	events          which events
2536448bf859SLida.Horn  *	anyyet          any events yet?
2537448bf859SLida.Horn  * Output:
2538448bf859SLida.Horn  *	reventsp        return of which events
2539448bf859SLida.Horn  *	phpp            poll head pointer
2540448bf859SLida.Horn  * Returns:
2541448bf859SLida.Horn  *      return 0 for success, or the appropriate error number
2542448bf859SLida.Horn  * Called by:
2543448bf859SLida.Horn  *	Device poll framework
2544448bf859SLida.Horn  * Description:
2545448bf859SLida.Horn  *	Fails for ISSM device. POLLOUT is always true. POLLIN or POLLRDNORM
2546448bf859SLida.Horn  *	is true if a message has been queued for the user context receive list.
2547448bf859SLida.Horn  */
2548448bf859SLida.Horn static int
umad_poll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)2549*80d5689fSPatrick Mooney umad_poll(dev_t dev, short events, int anyyet, short *reventsp,
2550*80d5689fSPatrick Mooney     struct pollhead **phpp)
2551448bf859SLida.Horn {
2552*80d5689fSPatrick Mooney 	int		minor;
2553*80d5689fSPatrick Mooney 	umad_uctx_t	*uctx;
2554*80d5689fSPatrick Mooney 	umad_info_t	*info;
2555*80d5689fSPatrick Mooney 	short		revent = 0;
2556448bf859SLida.Horn 
2557448bf859SLida.Horn 	info = ddi_get_soft_state(umad_statep, UMAD_INSTANCE);
2558448bf859SLida.Horn 	if (info == NULL) {
2559*80d5689fSPatrick Mooney 		return (ENXIO);
2560448bf859SLida.Horn 	}
2561448bf859SLida.Horn 
2562448bf859SLida.Horn 	/* lookup the node and port #s */
2563448bf859SLida.Horn 	minor = getminor(dev);
2564448bf859SLida.Horn 
2565448bf859SLida.Horn 	if (ISSM_MINOR(minor)) {
2566*80d5689fSPatrick Mooney 		return (ENXIO);
2567448bf859SLida.Horn 	}
2568448bf859SLida.Horn 
2569448bf859SLida.Horn 	mutex_enter(&info->info_mutex);
2570448bf859SLida.Horn 	uctx = info->info_uctx[GET_UCTX(minor)];
2571448bf859SLida.Horn 	mutex_exit(&info->info_mutex);
2572448bf859SLida.Horn 	ASSERT(uctx != NULL);
2573*80d5689fSPatrick Mooney 	ASSERT(uctx->uctx_port != NULL);
2574448bf859SLida.Horn 
2575448bf859SLida.Horn 	/*
2576448bf859SLida.Horn 	 * Always signal ready for POLLOUT / POLLWRNORM.
2577448bf859SLida.Horn 	 * Signal for POLLIN / POLLRDNORM whenever there is something in
2578448bf859SLida.Horn 	 * the receive list.
2579448bf859SLida.Horn 	 */
2580448bf859SLida.Horn 	if (events & POLLOUT) {
2581448bf859SLida.Horn 		revent = POLLOUT;
2582448bf859SLida.Horn 	} else if (events & (POLLIN | POLLRDNORM)) {
2583448bf859SLida.Horn 		mutex_enter(&uctx->uctx_recv_lock);
2584448bf859SLida.Horn 		if (! genlist_empty(&uctx->uctx_recv_list)) {
2585448bf859SLida.Horn 			revent |=  POLLIN | POLLRDNORM;
2586448bf859SLida.Horn 		}
2587448bf859SLida.Horn 		mutex_exit(&uctx->uctx_recv_lock);
2588448bf859SLida.Horn 	}
2589448bf859SLida.Horn 
2590*80d5689fSPatrick Mooney 	if ((revent == 0 && !anyyet) || (events & POLLET)) {
2591*80d5689fSPatrick Mooney 		*phpp = &uctx->uctx_pollhead;
2592448bf859SLida.Horn 	}
2593448bf859SLida.Horn 	*reventsp = revent;
2594*80d5689fSPatrick Mooney 	return (0);
2595448bf859SLida.Horn }
2596448bf859SLida.Horn 
2597448bf859SLida.Horn /*
2598448bf859SLida.Horn  * Function:
2599448bf859SLida.Horn  *     umad_unsolicited_cb
2600448bf859SLida.Horn  * Input:
2601448bf859SLida.Horn  *	ibmf_handle     - handle to ibmf
2602448bf859SLida.Horn  *      msgp            -  The incoming SM MAD
2603448bf859SLida.Horn  *      args            -  umad_port_info_t object that the MAD came in on
2604448bf859SLida.Horn  * Output:
2605448bf859SLida.Horn  *	None
2606448bf859SLida.Horn  * Returns:
2607448bf859SLida.Horn  *      none
2608448bf859SLida.Horn  * Called by:
2609448bf859SLida.Horn  *	IBMF from below
2610448bf859SLida.Horn  * Description:
2611448bf859SLida.Horn  *      Callback function (ibmf_msg_cb_t) that is invoked when the
2612448bf859SLida.Horn  *      ibmf receives a response MAD and passes it up if requested.
2613448bf859SLida.Horn  *      The message is tossed if no one wants it or queued if requested.
2614448bf859SLida.Horn  */
2615448bf859SLida.Horn static void
umad_unsolicited_cb(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)2616448bf859SLida.Horn umad_unsolicited_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
2617448bf859SLida.Horn {
2618448bf859SLida.Horn 	struct ibmf_reg_info *ibmf_info = (struct ibmf_reg_info *)args;
2619448bf859SLida.Horn 	struct umad_agent_s *agent;
2620448bf859SLida.Horn 	ib_mad_hdr_t *mad_hdr;
2621448bf859SLida.Horn 	int rc;
2622448bf859SLida.Horn 
2623448bf859SLida.Horn #if defined(__lint)
2624448bf859SLida.Horn 	ibmf_handle = 0;
2625448bf859SLida.Horn #endif
2626448bf859SLida.Horn 
2627448bf859SLida.Horn 	ASSERT(msgp->im_msgbufs_send.im_bufs_mad_hdr == NULL);
2628448bf859SLida.Horn 	ASSERT(msgp->im_msgbufs_send.im_bufs_cl_data == NULL);
2629448bf859SLida.Horn 	ASSERT(msgp->im_msgbufs_send.im_bufs_cl_data_len == 0);
2630448bf859SLida.Horn 
2631448bf859SLida.Horn 	/* Apply the filters to this MAD. */
2632448bf859SLida.Horn 	mad_hdr = msgp->im_msgbufs_recv.im_bufs_mad_hdr;
2633448bf859SLida.Horn 
2634448bf859SLida.Horn 	mutex_enter(&ibmf_info->ibmf_reg_lock);
2635448bf859SLida.Horn 
2636448bf859SLida.Horn 	/*
2637448bf859SLida.Horn 	 * Make sure the user context that was receiving the unsolicited
2638448bf859SLida.Horn 	 * messages is still present.
2639448bf859SLida.Horn 	 */
2640448bf859SLida.Horn 	if (ibmf_info->ibmf_reg_uctx == NULL)
2641448bf859SLida.Horn 		goto reject;
2642448bf859SLida.Horn 
2643448bf859SLida.Horn 	mutex_enter(&ibmf_info->ibmf_reg_uctx->uctx_lock);
2644448bf859SLida.Horn 	agent = umad_get_agent_by_class(ibmf_info->ibmf_reg_uctx,
2645448bf859SLida.Horn 	    mad_hdr->MgmtClass);
2646448bf859SLida.Horn 	mutex_exit(&ibmf_info->ibmf_reg_uctx->uctx_lock);
2647448bf859SLida.Horn 	if (agent == NULL)
2648448bf859SLida.Horn 		goto reject;
2649448bf859SLida.Horn 
2650448bf859SLida.Horn 	if (mad_hdr->ClassVersion != agent->agent_req.mgmt_class_version)
2651448bf859SLida.Horn 		goto reject;
2652448bf859SLida.Horn 
2653448bf859SLida.Horn 	if (! is_supported_mad_method(mad_hdr->R_Method & MAD_METHOD_MASK,
2654448bf859SLida.Horn 	    agent->agent_req.method_mask))
2655448bf859SLida.Horn 		goto reject;
2656448bf859SLida.Horn 
2657448bf859SLida.Horn 	if (umad_queue_mad_msg(agent, msgp))
2658448bf859SLida.Horn 		goto reject;
2659448bf859SLida.Horn 
2660448bf859SLida.Horn 	mutex_exit(&ibmf_info->ibmf_reg_lock);
2661448bf859SLida.Horn 	return;
2662448bf859SLida.Horn 
2663448bf859SLida.Horn reject:
2664448bf859SLida.Horn 	rc = ibmf_free_msg(ibmf_info->ibmf_reg_handle, &msgp);
2665448bf859SLida.Horn 	ASSERT(rc == IBMF_SUCCESS);
2666448bf859SLida.Horn 
2667448bf859SLida.Horn 	mutex_exit(&ibmf_info->ibmf_reg_lock);
2668448bf859SLida.Horn }
2669448bf859SLida.Horn 
2670448bf859SLida.Horn #if defined(__lint)
2671448bf859SLida.Horn /*
2672448bf859SLida.Horn  * This is needed because rdma/ib_verbs.h and sol_ofs/sol_ofs_common.h
2673448bf859SLida.Horn  * both implement static functions.  Not all of those functions are
2674448bf859SLida.Horn  * used by sol_umad, but lint doesn't like seeing static function that
2675448bf859SLida.Horn  * are defined but not used.
2676448bf859SLida.Horn  */
2677448bf859SLida.Horn void
lint_function(llist_head_t * a,llist_head_t * b)2678448bf859SLida.Horn lint_function(llist_head_t *a, llist_head_t *b)
2679448bf859SLida.Horn {
2680448bf859SLida.Horn 	(void) llist_is_last(a, b);
2681448bf859SLida.Horn 	llist_add_tail(a, b);
2682448bf859SLida.Horn 	(void) ib_width_enum_to_int(IB_WIDTH_1X);
2683448bf859SLida.Horn }
2684448bf859SLida.Horn #endif
2685