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