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