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(®_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