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 * sol_cma is a part of sol_ofs misc module. This file
28 * provides interfaces for supporting the communication
29 * management API defined in "rdma_cm.h". In-Kernel
30 * consumers of the "rdma_cm.h" API should link sol_ofs
31 * misc module using :
32 * -N misc/sol_ofs
33 * Solaris uCMA (sol_ucma) driver is the current consumer for
34 * sol_cma.
35 */
36
37 /* Standard driver includes */
38 #include <sys/types.h>
39 #include <sys/modctl.h>
40 #include <sys/errno.h>
41 #include <sys/stat.h>
42 #include <sys/ddi.h>
43 #include <sys/sunddi.h>
44 #include <sys/modctl.h>
45
46 #include <sys/ib/clients/of/ofed_kernel.h>
47 #include <sys/ib/clients/of/rdma/ib_addr.h>
48
49 #include <sys/ib/clients/of/sol_ofs/sol_cma.h>
50 #include <sys/ib/clients/of/sol_ofs/sol_kverb_impl.h>
51
52 /* Modload support */
53 static struct modlmisc sol_ofs_modmisc = {
54 &mod_miscops,
55 "Solaris OFS Misc module"
56 };
57
58 struct modlinkage sol_ofs_modlinkage = {
59 MODREV_1,
60 (void *)&sol_ofs_modmisc,
61 NULL
62 };
63
64 static ib_client_t *sol_cma_ib_client;
65 sol_cma_glbl_listen_t sol_cma_glbl_listen;
66 avl_tree_t sol_cma_glbl_listen_tree;
67
68 static void sol_cma_add_dev(struct ib_device *);
69 static void sol_cma_rem_dev(struct ib_device *);
70
71 static llist_head_t sol_cma_dev_list = LLIST_HEAD_INIT(sol_cma_dev_list);
72 kmutex_t sol_cma_dev_mutex;
73 kmutex_t sol_cma_glob_mutex;
74
75 char *sol_rdmacm_dbg_str = "sol_rdmacm";
76 char *sol_ofs_dbg_str = "sol_ofs_mod";
77
78 /*
79 * Local functions defines.
80 */
81 int sol_cma_req_cmid_cmp(const void *p1, const void *p2);
82 int sol_cma_cmid_cmp(const void *p1, const void *p2);
83 int sol_cma_svc_cmp(const void *, const void *);
84
85 static struct rdma_cm_id *cma_alloc_chan(rdma_cm_event_handler,
86 void *, enum rdma_port_space);
87 static void cma_set_chan_state(sol_cma_chan_t *, cma_chan_state_t);
88 static int cma_cas_chan_state(sol_cma_chan_t *, cma_chan_state_t,
89 cma_chan_state_t);
90 static void cma_free_listen_list(struct rdma_cm_id *);
91 static void cma_destroy_id(struct rdma_cm_id *);
92 static void cma_handle_nomore_events(sol_cma_chan_t *);
93
94 extern void sol_ofs_dprintf_init();
95 extern void sol_ofs_dprintf_fini();
96
97 cma_chan_state_t cma_get_chan_state(sol_cma_chan_t *);
98 extern int ibcma_init_root_chan(sol_cma_chan_t *, sol_cma_glbl_listen_t *);
99 extern int ibcma_fini_root_chan(sol_cma_chan_t *);
100 extern void ibcma_copy_srv_hdl(sol_cma_chan_t *, sol_cma_glbl_listen_t *);
101 extern int ibcma_fini_ep_chan(sol_cma_chan_t *);
102 extern uint64_t ibcma_init_root_sid(sol_cma_chan_t *);
103 extern void rdma_ib_destroy_id(struct rdma_cm_id *);
104 extern int rdma_ib_bind_addr(struct rdma_cm_id *, struct sockaddr *);
105 extern int rdma_ib_resolve_addr(struct rdma_cm_id *, struct sockaddr *,
106 struct sockaddr *, int);
107 extern int rdma_ib_resolve_route(struct rdma_cm_id *, int);
108 extern int rdma_ib_init_qp_attr(struct rdma_cm_id *, struct ib_qp_attr *,
109 int *);
110 extern int rdma_ib_connect(struct rdma_cm_id *, struct rdma_conn_param *);
111 extern int rdma_ib_listen(struct rdma_cm_id *, int);
112 extern int rdma_ib_accept(struct rdma_cm_id *, struct rdma_conn_param *);
113 extern int rdma_ib_reject(struct rdma_cm_id *, const void *, uint8_t);
114 extern int rdma_ib_disconnect(struct rdma_cm_id *);
115 extern int rdma_ib_join_multicast(struct rdma_cm_id *, struct sockaddr *,
116 void *);
117 extern void rdma_ib_leave_multicast(struct rdma_cm_id *, struct sockaddr *);
118
119 int
_init(void)120 _init(void)
121 {
122 int err;
123
124 sol_ofs_dprintf_init();
125 SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "_init()");
126
127 mutex_init(&sol_cma_glob_mutex, NULL, MUTEX_DRIVER, NULL);
128 mutex_init(&sol_cma_dev_mutex, NULL, MUTEX_DRIVER, NULL);
129 avl_create(&sol_cma_glbl_listen_tree,
130 sol_cma_svc_cmp, sizeof (sol_cma_glbl_listen_t),
131 offsetof(sol_cma_glbl_listen_t, cma_listen_node));
132
133 sol_cma_ib_client = kmem_zalloc(sizeof (ib_client_t), KM_NOSLEEP);
134 if (!sol_cma_ib_client) {
135 SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
136 "_init() - mem alloc failed");
137 avl_destroy(&sol_cma_glbl_listen_tree);
138 mutex_destroy(&sol_cma_dev_mutex);
139 mutex_destroy(&sol_cma_glob_mutex);
140 sol_ofs_dprintf_fini();
141 return (ENOMEM);
142 }
143
144 sol_cma_ib_client->name = "sol_ofs";
145 sol_cma_ib_client->add = sol_cma_add_dev;
146 sol_cma_ib_client->remove = sol_cma_rem_dev;
147 sol_cma_ib_client->dip = NULL;
148
149 if ((err = ib_register_client(sol_cma_ib_client)) != 0) {
150 SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
151 "_init() ib_register_client() failed with err %d",
152 err);
153 kmem_free(sol_cma_ib_client, sizeof (ib_client_t));
154 avl_destroy(&sol_cma_glbl_listen_tree);
155 mutex_destroy(&sol_cma_dev_mutex);
156 mutex_destroy(&sol_cma_glob_mutex);
157 sol_ofs_dprintf_fini();
158 return (err);
159 }
160
161 if ((err = mod_install(&sol_ofs_modlinkage)) != 0) {
162 SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
163 "_init() - mod_install() failed");
164 ib_unregister_client(sol_cma_ib_client);
165 kmem_free(sol_cma_ib_client, sizeof (ib_client_t));
166 avl_destroy(&sol_cma_glbl_listen_tree);
167 mutex_destroy(&sol_cma_dev_mutex);
168 mutex_destroy(&sol_cma_glob_mutex);
169 sol_ofs_dprintf_fini();
170 return (err);
171 }
172
173 SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "_init() - ret");
174 return (err);
175 }
176
177 int
_fini(void)178 _fini(void)
179 {
180 int err;
181
182 SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "_fini()");
183
184 if (avl_numnodes(&sol_cma_glbl_listen_tree)) {
185 SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str, "_fini - "
186 "listen CMIDs still active");
187 return (EBUSY);
188 }
189 if ((err = mod_remove(&sol_ofs_modlinkage)) != 0) {
190 SOL_OFS_DPRINTF_L3(sol_ofs_dbg_str,
191 "_fini: mod_remove failed");
192 return (err);
193 }
194
195 ib_unregister_client(sol_cma_ib_client);
196 kmem_free(sol_cma_ib_client, sizeof (ib_client_t));
197 avl_destroy(&sol_cma_glbl_listen_tree);
198 mutex_destroy(&sol_cma_dev_mutex);
199 mutex_destroy(&sol_cma_glob_mutex);
200 SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "_fini() - ret");
201 sol_ofs_dprintf_fini();
202 return (err);
203 }
204
205 int
_info(struct modinfo * modinfop)206 _info(struct modinfo *modinfop)
207 {
208 return (mod_info(&sol_ofs_modlinkage, modinfop));
209 }
210
211 typedef struct cma_device {
212 kmutex_t cma_mutex;
213 /* Ptr in the global sol_cma_dev_list */
214 llist_head_t cma_list;
215 /* List of listeners for this device */
216 genlist_t cma_epchan_list;
217 struct ib_device *cma_device;
218 uint_t cma_ref_count;
219 enum {
220 SOL_CMA_DEV_ADDED,
221 SOL_CMA_DEV_REM_IN_PROGRESS
222 } cma_dev_state;
223 } cma_device_t;
224
225 static void
sol_cma_add_dev(struct ib_device * dev)226 sol_cma_add_dev(struct ib_device *dev)
227 {
228 cma_device_t *new_device;
229
230 new_device = kmem_zalloc(sizeof (cma_device_t), KM_NOSLEEP);
231 if (!new_device) {
232 SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str, "sol_cma_add_dev() "
233 "alloc failed!!");
234 return;
235 }
236 mutex_init(&new_device->cma_mutex, NULL, MUTEX_DRIVER, NULL);
237 llist_head_init(&new_device->cma_list, new_device);
238 init_genlist(&new_device->cma_epchan_list);
239 new_device->cma_device = dev;
240
241 ib_set_client_data(dev, sol_cma_ib_client, new_device);
242
243 mutex_enter(&sol_cma_dev_mutex);
244 llist_add_tail(&new_device->cma_list, &sol_cma_dev_list);
245 mutex_exit(&sol_cma_dev_mutex);
246 }
247
248 static void
sol_cma_rem_dev(struct ib_device * dev)249 sol_cma_rem_dev(struct ib_device *dev)
250 {
251 cma_device_t *rem_device;
252 genlist_entry_t *entry;
253
254 SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "sol_rem_dev(%p)", dev);
255
256 rem_device = (cma_device_t *)ib_get_client_data(dev, sol_cma_ib_client);
257 if (!rem_device) {
258 SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str, "sol_cma_rem_dev() "
259 "NULL cma_dev!!");
260 return;
261 }
262
263 mutex_enter(&rem_device->cma_mutex);
264 rem_device->cma_dev_state = SOL_CMA_DEV_REM_IN_PROGRESS;
265 if (rem_device->cma_ref_count) {
266 mutex_exit(&rem_device->cma_mutex);
267 SOL_OFS_DPRINTF_L3(sol_ofs_dbg_str, "sol_cma_rem_dev() "
268 "BUSY cma_dev!!");
269 return;
270 }
271 entry = remove_genlist_head(&rem_device->cma_epchan_list);
272 while (entry) {
273 sol_cma_chan_t *ep_chanp;
274
275 ep_chanp = (sol_cma_chan_t *)entry->data;
276 if (ibcma_fini_ep_chan(ep_chanp) == 0) {
277 genlist_entry_t *entry1;
278 sol_cma_chan_t *root_chanp;
279
280 ASSERT(ep_chanp->chan_listenp);
281 entry1 = ep_chanp->chan_listenp->listen_ep_root_entry;
282 root_chanp = (sol_cma_chan_t *)ep_chanp->listen_root;
283 root_chanp->chan_listenp->listen_eps--;
284 delete_genlist(&root_chanp->chan_listenp->listen_list,
285 entry1);
286
287 kmem_free(ep_chanp, sizeof (sol_cma_chan_t));
288 kmem_free(entry, sizeof (genlist_entry_t));
289 }
290
291 entry = remove_genlist_head(&rem_device->cma_epchan_list);
292 }
293 mutex_exit(&rem_device->cma_mutex);
294
295 mutex_enter(&sol_cma_dev_mutex);
296 llist_del(&rem_device->cma_list);
297 mutex_exit(&sol_cma_dev_mutex);
298
299 kmem_free(rem_device, sizeof (cma_device_t));
300 }
301
302 struct ib_device *
sol_cma_acquire_device(ib_guid_t hca_guid)303 sol_cma_acquire_device(ib_guid_t hca_guid)
304 {
305 llist_head_t *entry;
306 cma_device_t *cma_devp;
307
308 mutex_enter(&sol_cma_dev_mutex);
309 list_for_each(entry, &sol_cma_dev_list) {
310 cma_devp = (cma_device_t *)entry->ptr;
311
312 if (cma_devp->cma_device->node_guid != hca_guid)
313 continue;
314
315 mutex_enter(&cma_devp->cma_mutex);
316 if (cma_devp->cma_dev_state == SOL_CMA_DEV_REM_IN_PROGRESS) {
317 SOL_OFS_DPRINTF_L3(sol_ofs_dbg_str,
318 "sol_cma_acquire_dev() - Device getting removed!!");
319 mutex_exit(&cma_devp->cma_mutex);
320 mutex_exit(&sol_cma_dev_mutex);
321 return (NULL);
322 }
323 cma_devp->cma_ref_count++;
324 mutex_exit(&cma_devp->cma_mutex);
325 mutex_exit(&sol_cma_dev_mutex);
326 return (cma_devp->cma_device);
327
328 }
329 mutex_exit(&sol_cma_dev_mutex);
330 return (NULL);
331 }
332
333 static void
sol_cma_release_device(struct rdma_cm_id * id)334 sol_cma_release_device(struct rdma_cm_id *id)
335 {
336 ib_device_t *device = id->device;
337 llist_head_t *entry;
338 cma_device_t *cma_devp;
339
340 mutex_enter(&sol_cma_dev_mutex);
341 list_for_each(entry, &sol_cma_dev_list) {
342 cma_devp = (cma_device_t *)entry->ptr;
343
344 if (cma_devp->cma_device != device)
345 continue;
346
347 mutex_enter(&cma_devp->cma_mutex);
348 cma_devp->cma_ref_count--;
349 if (cma_devp->cma_dev_state == SOL_CMA_DEV_REM_IN_PROGRESS &&
350 cma_devp->cma_ref_count == 0) {
351 SOL_OFS_DPRINTF_L3(sol_ofs_dbg_str,
352 "sol_cma_release_dev() - Device free removed!!");
353 mutex_exit(&cma_devp->cma_mutex);
354 llist_del(&cma_devp->cma_list);
355 kmem_free(cma_devp, sizeof (cma_device_t));
356 mutex_exit(&sol_cma_dev_mutex);
357 return;
358 }
359 mutex_exit(&cma_devp->cma_mutex);
360 }
361 mutex_exit(&sol_cma_dev_mutex);
362 }
363
364 void
sol_cma_add_hca_list(sol_cma_chan_t * ep_chanp,ib_guid_t hca_guid)365 sol_cma_add_hca_list(sol_cma_chan_t *ep_chanp, ib_guid_t hca_guid)
366 {
367 llist_head_t *entry;
368 cma_device_t *cma_devp;
369
370 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "add_hca_list(%p, %llx)",
371 ep_chanp, hca_guid);
372 mutex_enter(&sol_cma_dev_mutex);
373 list_for_each(entry, &sol_cma_dev_list) {
374 cma_devp = (cma_device_t *)entry->ptr;
375
376 if ((cma_devp->cma_device)->node_guid != hca_guid)
377 continue;
378
379 mutex_enter(&cma_devp->cma_mutex);
380 ep_chanp->chan_listenp->listen_ep_dev_entry =
381 add_genlist(&cma_devp->cma_epchan_list,
382 (uintptr_t)ep_chanp, NULL);
383 ep_chanp->chan_listenp->listen_ep_device = cma_devp->cma_device;
384 mutex_exit(&cma_devp->cma_mutex);
385 mutex_exit(&sol_cma_dev_mutex);
386 return;
387 }
388 mutex_exit(&sol_cma_dev_mutex);
389 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "add_hca_list(%p, %llx): "
390 "No matching HCA in list!!", ep_chanp, hca_guid);
391 }
392
393 /*
394 * rdma_cm.h API functions.
395 */
396 struct rdma_cm_id *
rdma_create_id(rdma_cm_event_handler evt_hdlr,void * context,enum rdma_port_space ps)397 rdma_create_id(rdma_cm_event_handler evt_hdlr, void *context,
398 enum rdma_port_space ps)
399 {
400 struct rdma_cm_id *rdma_idp;
401
402 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_create_id(%p, %p, %x)",
403 evt_hdlr, context, ps);
404
405 if (ps != RDMA_PS_TCP && ps != RDMA_PS_UDP && ps != RDMA_PS_IPOIB) {
406 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
407 "rdma_create_id: unsupported protocol %x", ps);
408 return (NULL);
409 }
410
411 rdma_idp = cma_alloc_chan(evt_hdlr, context, ps);
412 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
413 "rdma_create_id : ret %p", rdma_idp);
414
415 return (rdma_idp);
416 }
417
418 void
rdma_map_id2clnthdl(struct rdma_cm_id * rdma_idp,void * ib_client_hdl,void * iw_client_hdl)419 rdma_map_id2clnthdl(struct rdma_cm_id *rdma_idp, void *ib_client_hdl,
420 void *iw_client_hdl)
421 {
422 sol_cma_chan_t *chanp = (sol_cma_chan_t *)rdma_idp;
423
424 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
425 "rdma_map_id2clnthdl(%p, %p, %p)",
426 rdma_idp, ib_client_hdl, iw_client_hdl);
427 ASSERT(ib_client_hdl != NULL || iw_client_hdl != NULL);
428 chanp->chan_ib_client_hdl = ib_client_hdl;
429 chanp->chan_iw_client_hdl = iw_client_hdl;
430 }
431
432 void
rdma_map_id2qphdl(struct rdma_cm_id * rdma_idp,void * qp_hdl)433 rdma_map_id2qphdl(struct rdma_cm_id *rdma_idp, void *qp_hdl)
434 {
435 sol_cma_chan_t *chanp = (sol_cma_chan_t *)rdma_idp;
436
437 ASSERT(rdma_idp);
438 ASSERT(qp_hdl);
439 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_mapid2qphdl(%p, %p)",
440 rdma_idp, qp_hdl);
441 chanp->chan_qp_hdl = qp_hdl;
442 }
443
444
445 void
rdma_destroy_id(struct rdma_cm_id * rdma_idp)446 rdma_destroy_id(struct rdma_cm_id *rdma_idp)
447 {
448 sol_cma_chan_t *chanp, *root_chanp;
449 cma_chan_state_t state;
450 int rc, is_root_cmid, do_wait, is_passive;
451
452 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id(%p)", rdma_idp);
453
454 if (!rdma_idp)
455 return;
456
457 is_root_cmid = do_wait = is_passive = 0;
458
459 chanp = (sol_cma_chan_t *)rdma_idp;
460 root_chanp = (sol_cma_chan_t *)chanp->listen_root;
461 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id(%p), %p",
462 rdma_idp, root_chanp);
463
464 mutex_enter(&chanp->chan_mutex);
465 chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_CMID_DESTROYED;
466
467 /*
468 * Wait in destroy of CMID when rdma_resolve_addr() / rdma_listen()
469 * rdma_resolve_route() API is in progress.
470 */
471 while (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_API_PROGRESS)
472 cv_wait(&chanp->chan_destroy_cv, &chanp->chan_mutex);
473
474 /* Wait if Event is been notified to consumer */
475 while (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_EVENT_PROGRESS)
476 cv_wait(&chanp->chan_destroy_cv, &chanp->chan_mutex);
477
478 if (rdma_idp->device)
479 sol_cma_release_device(rdma_idp);
480
481 if (chanp->chan_listenp && chanp->chan_listenp->listen_is_root)
482 is_root_cmid = 1;
483 if (root_chanp == NULL && is_root_cmid == 0)
484 is_passive = 1;
485
486 /*
487 * Skip Active side handling for passive CMIDs and listen CMID
488 * for which REQ CMIDs have not been created.
489 */
490 if (is_passive || (is_root_cmid && chanp->chan_req_state !=
491 REQ_CMID_QUEUED)) {
492 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id: "
493 "Skipping passive %p, %x, %x", chanp->chan_listenp,
494 is_root_cmid, chanp->chan_req_state);
495 goto skip_passive_handling;
496 }
497
498 /*
499 * destroy_id() called for listening CMID and there are REQ
500 * CMIDs not yet notified. Reject such CMIDs and decrement
501 * the count.
502 */
503 if (is_root_cmid && chanp->chan_req_cnt) {
504 sol_cma_chan_t *req_cmid_chan, *next_chan;
505
506 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id: "
507 "not notified handling");
508 for (req_cmid_chan = (sol_cma_chan_t *)avl_first(
509 &chanp->chan_req_avl_tree); req_cmid_chan &&
510 chanp->chan_req_cnt; req_cmid_chan = next_chan) {
511 next_chan = AVL_NEXT(
512 &chanp->chan_req_avl_tree, req_cmid_chan);
513 if (req_cmid_chan->chan_req_state ==
514 REQ_CMID_NOTIFIED) {
515 avl_remove(&chanp->chan_req_avl_tree,
516 req_cmid_chan);
517 chanp->chan_req_cnt--;
518 chanp->chan_req_total_cnt--;
519 mutex_exit(&chanp->chan_mutex);
520 mutex_enter(&req_cmid_chan->chan_mutex);
521 req_cmid_chan->chan_req_state =
522 REQ_CMID_SERVER_NONE;
523 if (rdma_idp->ps == RDMA_PS_TCP)
524 cma_set_chan_state(req_cmid_chan,
525 SOL_CMA_CHAN_DESTROY_PENDING);
526 mutex_exit(&req_cmid_chan->chan_mutex);
527 (void) rdma_disconnect(
528 (struct rdma_cm_id *)req_cmid_chan);
529 mutex_enter(&chanp->chan_mutex);
530 if (rdma_idp->ps == RDMA_PS_TCP) {
531 mutex_enter(
532 &req_cmid_chan->chan_mutex);
533 req_cmid_chan->listen_root =
534 rdma_idp;
535 mutex_exit(
536 &req_cmid_chan->chan_mutex);
537 } else {
538 mutex_destroy(
539 &req_cmid_chan->chan_mutex);
540 cv_destroy(
541 &req_cmid_chan->chan_destroy_cv);
542 kmem_free(req_cmid_chan,
543 sizeof (sol_cma_chan_t));
544 }
545 }
546 }
547 }
548
549 /*
550 * destroy_id() called for :
551 * listening CMID and all REQ CMIDs destroy_id() called
552 * REQ CMID and 1 more REQ CMID not yet destroyed.
553 * wait till the CMID is completly destroyed.
554 */
555 if (is_root_cmid && chanp->chan_req_total_cnt == 0) {
556 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id: "
557 "root idp waiting");
558 cma_set_chan_state(chanp, SOL_CMA_CHAN_DESTROY_WAIT);
559 cv_wait(&chanp->chan_destroy_cv, &chanp->chan_mutex);
560 }
561 mutex_exit(&chanp->chan_mutex);
562
563 if (root_chanp)
564 mutex_enter(&root_chanp->chan_mutex);
565 mutex_enter(&chanp->chan_mutex);
566 #ifdef DEBUG
567 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id: "
568 "root_idp %p, cnt %x, state %x", root_chanp,
569 root_chanp ? root_chanp->chan_req_total_cnt : 0,
570 root_chanp ? cma_get_chan_state(root_chanp) : 0);
571 #endif
572
573 if (root_chanp && root_chanp->chan_req_total_cnt == 1 &&
574 cma_get_chan_state(root_chanp) == SOL_CMA_CHAN_DESTROY_PENDING)
575 do_wait = 1;
576 if (root_chanp)
577 mutex_exit(&root_chanp->chan_mutex);
578
579 skip_passive_handling :
580 state = cma_get_chan_state(chanp);
581 if (is_root_cmid == 0 && state != SOL_CMA_CHAN_DISCONNECT &&
582 SOL_CMAID_CONNECTED(chanp)) {
583 /*
584 * A connected CM ID has not been disconnected.
585 * Call rdma_disconnect() to disconnect it.
586 */
587 mutex_exit(&chanp->chan_mutex);
588 rc = rdma_disconnect(rdma_idp);
589 if (rc) {
590 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
591 "rdma_destroy_id(%p)- disconnect failed!!",
592 rdma_idp);
593 return;
594 }
595 mutex_enter(&chanp->chan_mutex);
596 if (root_chanp && chanp->listen_root == NULL)
597 chanp->listen_root = (struct rdma_cm_id *)root_chanp;
598 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
599 "rdma_destroy_id(chanp %p, connect %x, ps %x)",
600 chanp, chanp->chan_connect_flag, rdma_idp->ps);
601 if (SOL_CMAID_CONNECTED(chanp)) {
602 if (do_wait) {
603 cma_set_chan_state(chanp,
604 SOL_CMA_CHAN_DESTROY_WAIT);
605 cv_wait(&chanp->chan_destroy_cv,
606 &chanp->chan_mutex);
607 mutex_exit(&chanp->chan_mutex);
608 cma_destroy_id(rdma_idp);
609 } else {
610 cma_set_chan_state(chanp,
611 SOL_CMA_CHAN_DESTROY_PENDING);
612 mutex_exit(&chanp->chan_mutex);
613 }
614 } else {
615 /*
616 * No more callbacks are expected for this CMID.
617 * Free this CMID.
618 */
619 mutex_exit(&chanp->chan_mutex);
620 cma_destroy_id(rdma_idp);
621 }
622 } else if (is_root_cmid == 0 && state ==
623 SOL_CMA_CHAN_DISCONNECT && SOL_CMAID_CONNECTED(chanp)) {
624 /*
625 * CM ID was connected and disconnect is process.
626 * Free of this CM ID is done for the DISCONNECT
627 * notification for this CMID.
628 */
629 cma_set_chan_state(chanp, SOL_CMA_CHAN_DESTROY_PENDING);
630 mutex_exit(&chanp->chan_mutex);
631 } else if (state != SOL_CMA_CHAN_DESTROY_PENDING) {
632 /* CM ID, not connected, just free it. */
633 mutex_exit(&chanp->chan_mutex);
634 cma_destroy_id(rdma_idp);
635 } else
636 mutex_exit(&chanp->chan_mutex);
637
638 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_destroy_id: ret");
639 }
640
641 /*
642 * State transitions for Address resolution :
643 * Active Side (Client) :
644 * 1. CREATE_ID-->BIND_ADDR-->RESOLVE_ADDR-->RESOLVE_ROUTE
645 *
646 * Passive Side (Server) :
647 * 2. CREATE_ID-->RESOLVE_ADDR-->RESOLVE_ROUTE
648 * IF_ADDR_ANY can be passed as local address in RESOLVE_ADDR
649 */
650 int
rdma_bind_addr(struct rdma_cm_id * idp,struct sockaddr * addr)651 rdma_bind_addr(struct rdma_cm_id *idp, struct sockaddr *addr)
652 {
653 sol_cma_chan_t *chanp;
654 struct rdma_addr *addrp;
655 int ret;
656
657 ASSERT(idp);
658 ASSERT(addr);
659 chanp = (sol_cma_chan_t *)idp;
660 addrp = &(idp->route.addr);
661 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_bind_addr(%p, %p)",
662 idp, addr);
663
664 mutex_enter(&chanp->chan_mutex);
665 ret = cma_cas_chan_state(chanp, SOL_CMA_CHAN_IDLE, SOL_CMA_CHAN_BOUND);
666 if (ret) {
667 mutex_exit(&chanp->chan_mutex);
668 return (ret);
669 }
670 /* Copy the local address to rdma_id structure */
671 bcopy((void *)addr, (void *)&(addrp->src_addr),
672 sizeof (struct sockaddr));
673 mutex_exit(&chanp->chan_mutex);
674
675 /*
676 * First call rdma_ib_bind_addr() to bind this address.
677 * Next call rdma_iw_bind_addr() to bind this address.
678 * For IF_ADDR_ANY, IB address is given priority over
679 * iWARP.
680 */
681 if (chanp->chan_ib_client_hdl == NULL) {
682 ofs_client_t *ofs_clnt;
683
684 ofs_clnt = (ofs_client_t *)sol_cma_ib_client->clnt_hdl;
685 chanp->chan_ib_client_hdl = ofs_clnt->ibt_hdl;
686 }
687 if (chanp->chan_ib_client_hdl && rdma_ib_bind_addr(idp, addr) == 0) {
688 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
689 "rdma_bind_addr: ret IB @");
690 return (0);
691 #ifdef IWARP_SUPPORT
692 } else if (chanp->chan_iw_client_hdl && rdma_iw_bind_addr(idp, addr)
693 == 0) {
694 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
695 "rdma_bind_addr: ret iWARP @");
696 return (0);
697 #endif /* IWARP_SUPPORT */
698 }
699
700 mutex_enter(&chanp->chan_mutex);
701 cma_set_chan_state(chanp, SOL_CMA_CHAN_IDLE);
702 mutex_exit(&chanp->chan_mutex);
703 SOL_OFS_DPRINTF_L4(sol_rdmacm_dbg_str, "rdma_bind_addr: ret failure!");
704 return (EINVAL);
705 }
706
707 int
rdma_resolve_addr(struct rdma_cm_id * idp,struct sockaddr * src_addr,struct sockaddr * dst_addr,int timeout_ms)708 rdma_resolve_addr(struct rdma_cm_id *idp, struct sockaddr *src_addr,
709 struct sockaddr *dst_addr, int timeout_ms)
710 {
711 sol_cma_chan_t *chanp;
712 struct rdma_addr *addrp;
713 cma_chan_state_t state;
714
715 ASSERT(idp);
716 chanp = (sol_cma_chan_t *)idp;
717 addrp = &(idp->route.addr);
718 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_resolve_addr(%p, %p, "
719 "%p, %x)", idp, src_addr, dst_addr, timeout_ms);
720
721 mutex_enter(&chanp->chan_mutex);
722 state = cma_get_chan_state(chanp);
723 if (state != SOL_CMA_CHAN_IDLE && state != SOL_CMA_CHAN_BOUND) {
724 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
725 "rdma_resolve_addr : invalid chan state %x", state);
726 mutex_exit(&chanp->chan_mutex);
727 return (EINVAL);
728 }
729 if (chanp->chan_cmid_destroy_state &
730 SOL_CMA_CALLER_CMID_DESTROYED) {
731 SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str,
732 "rdma_resolve_addr : CMID %p, destroy called", chanp);
733 mutex_exit(&chanp->chan_mutex);
734 return (EINVAL);
735 }
736 chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_API_PROGRESS;
737
738 if (chanp->chan_xport_type == SOL_CMA_XPORT_NONE) {
739 bcopy((void *)src_addr, (void *)&(addrp->src_addr),
740 sizeof (struct sockaddr));
741 }
742 bcopy((void *)dst_addr, (void *)&(addrp->dst_addr),
743 sizeof (struct sockaddr));
744 mutex_exit(&chanp->chan_mutex);
745
746 /*
747 * First resolve this as an @ corresponding to IB fabric
748 * if this fails, resolve this as an @ corresponding to iWARP
749 */
750 if (chanp->chan_ib_client_hdl == NULL) {
751 ofs_client_t *ofs_clnt;
752
753 ofs_clnt = (ofs_client_t *)sol_cma_ib_client->clnt_hdl;
754 chanp->chan_ib_client_hdl = ofs_clnt->ibt_hdl;
755 }
756 if (chanp->chan_ib_client_hdl && rdma_ib_resolve_addr(idp, src_addr,
757 dst_addr, timeout_ms) == 0) {
758 SOL_OFS_DPRINTF_L4(sol_rdmacm_dbg_str,
759 "rdma_resolve_addr: ret IB @");
760 #ifdef IWARP_SUPPORT
761 } else if (chanp->chan_iw_client_hdl && rdma_iw_resolve_addr(idp,
762 src_addr, dst_addr, timeout_ms) == 0) {
763 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
764 "rdma_resolve_addr: ret iWARP @");
765 #endif /* IWARP_SUPPORT */
766 } else {
767 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
768 "rdma_resolve_addr: Invalid @");
769 return (EINVAL);
770 }
771 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_resolve_addr: ret 0");
772 return (0);
773 }
774
775 static void cma_generate_event_sync(struct rdma_cm_id *,
776 enum rdma_cm_event_type, int, struct rdma_conn_param *,
777 struct rdma_ud_param *);
778
779 void
cma_resolve_addr_callback(sol_cma_chan_t * chanp,int rc)780 cma_resolve_addr_callback(sol_cma_chan_t *chanp, int rc)
781 {
782 enum rdma_cm_event_type event;
783
784 mutex_enter(&chanp->chan_mutex);
785 if (chanp->chan_cmid_destroy_state &
786 SOL_CMA_CALLER_CMID_DESTROYED) {
787 SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str,
788 "cma_resolve_addr : CMID %p, destroy called", chanp);
789 chanp->chan_cmid_destroy_state &=
790 ~SOL_CMA_CALLER_API_PROGRESS;
791 cv_broadcast(&chanp->chan_destroy_cv);
792 mutex_exit(&chanp->chan_mutex);
793 return;
794 }
795 if (rc == 0) {
796 cma_set_chan_state(chanp, SOL_CMA_CHAN_ADDR_RESLVD);
797 event = RDMA_CM_EVENT_ADDR_RESOLVED;
798 } else
799 event = RDMA_CM_EVENT_ADDR_ERROR;
800
801 /*
802 * Generate RDMA_CM_EVENT_ADDR_RESOLVED event
803 * This will result in RDMA_USER_CM_CMD_RESOLVE_ROUTE in
804 * userland.
805 */
806 chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_EVENT_PROGRESS;
807 mutex_exit(&chanp->chan_mutex);
808 cma_generate_event_sync((struct rdma_cm_id *)chanp, event, 0,
809 NULL, NULL);
810
811 mutex_enter(&chanp->chan_mutex);
812 chanp->chan_cmid_destroy_state &= ~SOL_CMA_CALLER_API_PROGRESS;
813 if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED)
814 cv_broadcast(&chanp->chan_destroy_cv);
815 mutex_exit(&chanp->chan_mutex);
816 }
817
818 int
rdma_resolve_route(struct rdma_cm_id * idp,int timeout_ms)819 rdma_resolve_route(struct rdma_cm_id *idp, int timeout_ms)
820 {
821 sol_cma_chan_t *chanp;
822
823 ASSERT(idp);
824 chanp = (sol_cma_chan_t *)idp;
825 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "resolve_route(%p, %x)", idp,
826 timeout_ms);
827
828 mutex_enter(&chanp->chan_mutex);
829 if (cma_cas_chan_state(chanp, SOL_CMA_CHAN_ADDR_RESLVD,
830 SOL_CMA_CHAN_ROUTE_RESLVD) != 0) {
831 mutex_exit(&chanp->chan_mutex);
832 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
833 "resolve_route: Invalid state");
834 return (EINVAL);
835 }
836 if (chanp->chan_cmid_destroy_state &
837 SOL_CMA_CALLER_CMID_DESTROYED) {
838 SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str,
839 "rdma_resolve_route : CMID %p, destroy called", chanp);
840 mutex_exit(&chanp->chan_mutex);
841 return (EINVAL);
842 }
843 chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_API_PROGRESS;
844 mutex_exit(&chanp->chan_mutex);
845
846 /*
847 * Generate RDMA_CM_EVENT_ROUTE_RESOLVED event
848 * This will result in RDMA_USER_CM_CMD_RESOLVE_ROUTE in
849 * userland
850 */
851 cma_generate_event(idp, RDMA_CM_EVENT_ROUTE_RESOLVED, 0,
852 NULL, NULL);
853
854 mutex_enter(&chanp->chan_mutex);
855 chanp->chan_cmid_destroy_state &= ~SOL_CMA_CALLER_API_PROGRESS;
856 if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED)
857 cv_broadcast(&chanp->chan_destroy_cv);
858 mutex_exit(&chanp->chan_mutex);
859
860 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "resolve_route: ret 0");
861 return (0);
862 }
863
864 /*
865 * Connect or Listen request should be send after Route is resolved
866 *
867 * Active Side (Client) :
868 * 1. (State ROUTE_RESOLVED)-->CONNECT-->ACCEPT/REJECT-->DISCONNECT
869 * -->DESTROY_ID-->close(9E)
870 * 2. Same as (1), DESTROY_ID without DISCONNECT
871 * 3. Same as (1), close(9e) without DESTROY_ID.
872 *
873 * Passive Side (Server) :
874 * 4. (State ROUTE_RESOLVED)-->LISTEN->DISCONNECT
875 * -->DESTROY_ID-->close(9E)
876 * 5. Same as (4), DESTROY_ID without DISCONNECT
877 * 6. Same as (4), close(9e) without DESTROY_ID.
878 */
879 int
rdma_connect(struct rdma_cm_id * idp,struct rdma_conn_param * conn_param)880 rdma_connect(struct rdma_cm_id *idp, struct rdma_conn_param *conn_param)
881 {
882 sol_cma_chan_t *chanp;
883 int ret = EINVAL;
884
885 ASSERT(idp);
886 chanp = (sol_cma_chan_t *)idp;
887 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_connect(%p, %p)", idp,
888 conn_param);
889
890 mutex_enter(&chanp->chan_mutex);
891 if (chanp->chan_xport_type == SOL_CMA_XPORT_NONE) {
892 mutex_exit(&chanp->chan_mutex);
893 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
894 "rdma_connect, Invalid Xport");
895 return (EINVAL);
896 }
897 if (cma_cas_chan_state(chanp, SOL_CMA_CHAN_ROUTE_RESLVD,
898 SOL_CMA_CHAN_CONNECT)) {
899 mutex_exit(&chanp->chan_mutex);
900 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
901 "rdma_connect, Invalid state");
902 return (EINVAL);
903 }
904
905 if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) {
906 ret = rdma_ib_connect(idp, conn_param);
907 #ifdef IWARP_SUPPORT
908 } else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP) {
909 ret = rdma_iw_connect(idp, conn_param);
910 #endif /* IWARP_SUPPORT */
911 }
912 mutex_exit(&chanp->chan_mutex);
913
914 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_connect: ret %x", ret);
915 return (ret);
916 }
917
918 static int cma_init_listen_root(sol_cma_chan_t *);
919 static void cma_fini_listen_root(sol_cma_chan_t *);
920
921 int
rdma_listen(struct rdma_cm_id * idp,int bklog)922 rdma_listen(struct rdma_cm_id *idp, int bklog)
923 {
924 sol_cma_chan_t *chanp;
925 int ret = 0;
926 genlist_entry_t *entry;
927 cma_chan_state_t state;
928
929 ASSERT(idp);
930 chanp = (sol_cma_chan_t *)idp;
931 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_listen(%p, %x)",
932 idp, bklog);
933
934 mutex_enter(&chanp->chan_mutex);
935 state = cma_get_chan_state(chanp);
936 if (state == SOL_CMA_CHAN_IDLE) {
937 mutex_exit(&chanp->chan_mutex);
938 return (EINVAL);
939 }
940 cma_set_chan_state(chanp, SOL_CMA_CHAN_LISTEN);
941
942 if (chanp->chan_cmid_destroy_state &
943 SOL_CMA_CALLER_CMID_DESTROYED) {
944 SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str,
945 "rdma_listen : CMID %p, destroy called", chanp);
946 mutex_exit(&chanp->chan_mutex);
947 return (EINVAL);
948 }
949 chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_API_PROGRESS;
950
951 ASSERT(chanp->chan_listenp == NULL);
952
953 chanp->chan_listenp = kmem_zalloc(sizeof (sol_cma_listen_info_t),
954 KM_SLEEP);
955 init_genlist(&(CHAN_LISTEN_LIST(chanp)));
956 (chanp->chan_listenp)->listen_is_root = 1;
957 ret = cma_init_listen_root(chanp);
958 if (ret) {
959 chanp->chan_listenp = NULL;
960 mutex_exit(&chanp->chan_mutex);
961 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "rdma_listen: "
962 "cma_init_listen_root: failed");
963 kmem_free(chanp->chan_listenp,
964 sizeof (sol_cma_listen_info_t));
965 return (EINVAL);
966 }
967
968 if (chanp->chan_xport_type == SOL_CMA_XPORT_NONE) {
969 ibcma_append_listen_list(idp);
970 #ifdef IWARP_SUPPORT
971 iwcma_append_listen_list(idp);
972 #endif
973 } else if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) {
974 ibcma_append_listen_list(idp);
975 #ifdef IWARP_SUPPORT
976 } else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP) {
977 iwcma_append_listen_list(idp);
978 #endif /* IWARP_SUPPORT */
979 }
980
981 if (genlist_empty(&(CHAN_LISTEN_LIST(chanp)))) {
982 cma_fini_listen_root(chanp);
983 kmem_free((void *)chanp->chan_listenp,
984 sizeof (sol_cma_listen_info_t));
985 chanp->chan_listenp = NULL;
986 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str, "rdma_listen: "
987 "No listeners");
988 mutex_exit(&chanp->chan_mutex);
989 return (0);
990 }
991
992 if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED) {
993 chanp->chan_cmid_destroy_state &=
994 ~SOL_CMA_CALLER_API_PROGRESS;
995 cv_broadcast(&chanp->chan_destroy_cv);
996 }
997
998 genlist_for_each(entry, &(CHAN_LISTEN_LIST(chanp))) {
999 struct rdma_cm_id *ep_idp;
1000 sol_cma_chan_t *ep_chanp;
1001
1002 ep_idp = (struct rdma_cm_id *)entry->data;
1003 ep_chanp = (sol_cma_chan_t *)ep_idp;
1004 if (ep_chanp->chan_xport_type == SOL_CMA_XPORT_IB)
1005 ret = rdma_ib_listen(ep_idp, bklog);
1006 #ifdef IWARP_SUPPORT
1007 if (ep_chanp->chan_xport_type == SOL_CMA_XPORT_IWARP)
1008 ret = rdma_iw_listen(ep_idp, bklog);
1009 #endif
1010 if (ret)
1011 break;
1012 }
1013
1014 chanp->chan_cmid_destroy_state &= ~SOL_CMA_CALLER_API_PROGRESS;
1015 if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED)
1016 cv_broadcast(&chanp->chan_destroy_cv);
1017 mutex_exit(&chanp->chan_mutex);
1018
1019 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_listen: ret %x", ret);
1020 return (ret);
1021 }
1022
1023 int
rdma_accept(struct rdma_cm_id * idp,struct rdma_conn_param * conn_param)1024 rdma_accept(struct rdma_cm_id *idp, struct rdma_conn_param *conn_param)
1025 {
1026 struct rdma_cm_id *root_idp;
1027 sol_cma_chan_t *root_chanp, *chanp;
1028 int ret = EINVAL;
1029
1030 ASSERT(idp);
1031 chanp = (sol_cma_chan_t *)idp;
1032 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_accept(%p, %p)",
1033 idp, conn_param);
1034
1035 mutex_enter(&chanp->chan_mutex);
1036 if (cma_cas_chan_state(chanp, SOL_CMA_CHAN_LISTEN,
1037 SOL_CMA_CHAN_ACCEPT) && cma_cas_chan_state(chanp,
1038 SOL_CMA_CHAN_CONNECT, SOL_CMA_CHAN_ACCEPT)) {
1039 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1040 "rdma_accept, Invalid state");
1041 mutex_exit(&chanp->chan_mutex);
1042 return (EINVAL);
1043 }
1044 mutex_exit(&chanp->chan_mutex);
1045
1046 root_idp = CHAN_LISTEN_ROOT(chanp);
1047 root_chanp = (sol_cma_chan_t *)root_idp;
1048 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "accept: root_idp %p",
1049 root_idp);
1050
1051 /* For TCP, delete from REQ AVL & insert to ACPT AVL */
1052 if (root_idp && root_idp->ps == RDMA_PS_TCP) {
1053 void *find_ret;
1054 avl_index_t where;
1055
1056 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "accept: root_idp %p"
1057 "REQ AVL remove %p", root_chanp, idp);
1058 mutex_enter(&root_chanp->chan_mutex);
1059 mutex_enter(&chanp->chan_mutex);
1060
1061 /*
1062 * This CMID has been deleted, maybe because of timeout.
1063 * Return EINVAL.
1064 */
1065 if (chanp->chan_req_state != REQ_CMID_NOTIFIED) {
1066 mutex_exit(&chanp->chan_mutex);
1067 mutex_exit(&root_chanp->chan_mutex);
1068 SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str,
1069 "accept: root_idp %p chanp %p, not in REQ "
1070 "AVL tree", root_chanp, chanp);
1071 return (EINVAL);
1072 }
1073 ASSERT(cma_get_req_idp(root_idp, chanp->chan_session_id));
1074 avl_remove(&root_chanp->chan_req_avl_tree, idp);
1075
1076
1077 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1078 "Add to ACPT AVL of %p IDP, idp %p, qp_hdl %p",
1079 root_idp, idp, chanp->chan_qp_hdl);
1080 find_ret = avl_find(&root_chanp->chan_acpt_avl_tree,
1081 (void *)chanp->chan_qp_hdl, &where);
1082 if (find_ret) {
1083 chanp->chan_req_state = REQ_CMID_SERVER_NONE;
1084 mutex_exit(&chanp->chan_mutex);
1085 mutex_exit(&root_chanp->chan_mutex);
1086 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1087 "DUPLICATE ENTRY in ACPT AVL : root %p, "
1088 "idp %p, qp_hdl %p",
1089 root_idp, idp, chanp->chan_qp_hdl);
1090 return (EINVAL);
1091 }
1092 avl_insert(&root_chanp->chan_acpt_avl_tree,
1093 (void *)idp, where);
1094 chanp->chan_req_state = REQ_CMID_ACCEPTED;
1095 mutex_exit(&chanp->chan_mutex);
1096 mutex_exit(&root_chanp->chan_mutex);
1097 }
1098
1099 if (root_idp && IS_UDP_CMID(root_idp)) {
1100 cma_chan_state_t chan_state;
1101
1102 /*
1103 * Accepting the connect request, no more events for this
1104 * connection.
1105 */
1106 cma_handle_nomore_events(chanp);
1107 mutex_enter(&chanp->chan_mutex);
1108 chan_state = cma_get_chan_state(chanp);
1109 mutex_exit(&chanp->chan_mutex);
1110 /* If rdma_destroy_id() was called, destroy CMID */
1111 if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING) {
1112 cma_destroy_id((struct rdma_cm_id *)chanp);
1113 return (EINVAL);
1114 }
1115 }
1116
1117 if (chanp->chan_xport_type == SOL_CMA_XPORT_IB)
1118 ret = rdma_ib_accept(idp, conn_param);
1119 #ifdef IWARP_SUPPORT
1120 if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP)
1121 ret = rdma_iw_accept(idp, conn_param);
1122 #endif /* IWARP_SUPPORT */
1123
1124 if (ret && root_idp && idp->ps == RDMA_PS_TCP) {
1125 void *find_ret;
1126 avl_index_t where;
1127
1128 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1129 "Delete from REQ AVL of %p IDP, idp %p",
1130 root_idp, idp);
1131 mutex_enter(&root_chanp->chan_mutex);
1132 mutex_enter(&chanp->chan_mutex);
1133 if (chanp->chan_req_state == REQ_CMID_ACCEPTED) {
1134 ASSERT(cma_get_acpt_idp(root_idp,
1135 chanp->chan_qp_hdl));
1136 avl_remove(&root_chanp->chan_acpt_avl_tree,
1137 idp);
1138 find_ret = avl_find(&root_chanp->chan_req_avl_tree,
1139 (void *)chanp->chan_qp_hdl, &where);
1140 if (find_ret) {
1141 chanp->chan_req_state = REQ_CMID_SERVER_NONE;
1142 mutex_exit(&chanp->chan_mutex);
1143 mutex_exit(&root_chanp->chan_mutex);
1144 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1145 "DUPLICATE ENTRY in REQ AVL : root %p, "
1146 "idp %p, session_id %p",
1147 root_idp, idp, chanp->chan_session_id);
1148 return (EINVAL);
1149 }
1150 avl_insert(&root_chanp->chan_req_avl_tree, idp, where);
1151 chanp->chan_req_state = REQ_CMID_NOTIFIED;
1152 }
1153 mutex_exit(&chanp->chan_mutex);
1154 mutex_exit(&root_chanp->chan_mutex);
1155 }
1156
1157 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_accept: ret %x", ret);
1158 return (ret);
1159 }
1160
1161 int
rdma_notify(struct rdma_cm_id * idp,enum ib_event_type evt)1162 rdma_notify(struct rdma_cm_id *idp, enum ib_event_type evt)
1163 {
1164 sol_cma_chan_t *chanp;
1165
1166 ASSERT(idp);
1167 chanp = (sol_cma_chan_t *)idp;
1168 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_notify(%p, %x)", idp, evt);
1169
1170 mutex_enter(&chanp->chan_mutex);
1171 if (cma_cas_chan_state(chanp, SOL_CMA_CHAN_ROUTE_RESLVD,
1172 SOL_CMA_CHAN_EVENT_NOTIFIED)) {
1173 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1174 "rdma_notify, Invalid state");
1175 mutex_exit(&chanp->chan_mutex);
1176 return (EINVAL);
1177 }
1178 mutex_exit(&chanp->chan_mutex);
1179
1180 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_notify: ret 0");
1181 return (0);
1182 }
1183
1184 int
rdma_reject(struct rdma_cm_id * idp,const void * priv_data,uint8_t priv_data_len)1185 rdma_reject(struct rdma_cm_id *idp, const void *priv_data,
1186 uint8_t priv_data_len)
1187 {
1188 struct rdma_cm_id *root_idp;
1189 sol_cma_chan_t *root_chanp, *chanp;
1190 int ret = EINVAL;
1191
1192 ASSERT(idp);
1193 chanp = (sol_cma_chan_t *)idp;
1194 root_idp = CHAN_LISTEN_ROOT(chanp);
1195 root_chanp = (sol_cma_chan_t *)root_idp;
1196 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_reject(%p, %p)", idp,
1197 priv_data, priv_data_len);
1198
1199 mutex_enter(&chanp->chan_mutex);
1200 if (cma_cas_chan_state(chanp, SOL_CMA_CHAN_LISTEN,
1201 SOL_CMA_CHAN_REJECT)) {
1202 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1203 "rdma_accept, Invalid state");
1204 mutex_exit(&chanp->chan_mutex);
1205 return (EINVAL);
1206 }
1207 mutex_exit(&chanp->chan_mutex);
1208
1209 if (root_idp) {
1210 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "reject: root_idp %p"
1211 "REQ AVL remove %p", root_chanp, idp);
1212
1213 /*
1214 * Remove from REQ AVL tree. If this CMID has been deleted,
1215 * it maybe because of timeout. Return EINVAL.
1216 */
1217 mutex_enter(&root_chanp->chan_mutex);
1218 mutex_enter(&chanp->chan_mutex);
1219 if (chanp->chan_req_state != REQ_CMID_NOTIFIED &&
1220 chanp->chan_req_state != REQ_CMID_QUEUED) {
1221 mutex_exit(&chanp->chan_mutex);
1222 mutex_exit(&root_chanp->chan_mutex);
1223 SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str,
1224 "reject: root_idp %p chanp %p, not in REQ "
1225 "AVL tree", root_chanp, chanp);
1226 return (EINVAL);
1227 }
1228 ASSERT(cma_get_req_idp(root_idp, chanp->chan_session_id));
1229 avl_remove(&root_chanp->chan_req_avl_tree, idp);
1230 chanp->chan_req_state = REQ_CMID_SERVER_NONE;
1231 mutex_exit(&chanp->chan_mutex);
1232 mutex_exit(&root_chanp->chan_mutex);
1233 }
1234
1235 if (chanp->chan_xport_type == SOL_CMA_XPORT_IB)
1236 ret = rdma_ib_reject(idp, priv_data, priv_data_len);
1237 #ifdef IWARP_SUPPORT
1238 if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP)
1239 ret = rdma_iw_reject(idp, priv_data, priv_data_len);
1240 #endif /* IWARP_SUPPORT */
1241
1242
1243 if (!ret && root_idp) {
1244 cma_chan_state_t chan_state;
1245
1246 /*
1247 * Rejecting connect request, no more events for this
1248 * connection.
1249 */
1250 cma_handle_nomore_events(chanp);
1251 mutex_enter(&chanp->chan_mutex);
1252 chan_state = cma_get_chan_state(chanp);
1253 mutex_exit(&chanp->chan_mutex);
1254 /* If rdma_destroy_id() was called, destroy CMID */
1255 if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING)
1256 cma_destroy_id((struct rdma_cm_id *)chanp);
1257 } else if (ret && root_idp) {
1258 avl_index_t where;
1259
1260 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1261 "reject fail: Add to Req AVL of %p IDP, idp %p,"
1262 "session_id %p", root_idp, idp,
1263 chanp->chan_session_id);
1264 mutex_enter(&root_chanp->chan_mutex);
1265 mutex_enter(&chanp->chan_mutex);
1266 if (chanp->chan_req_state == REQ_CMID_SERVER_NONE) {
1267 if (avl_find(&root_chanp->chan_req_avl_tree,
1268 (void *)chanp->chan_session_id, &where)) {
1269 mutex_exit(&chanp->chan_mutex);
1270 mutex_exit(&root_chanp->chan_mutex);
1271 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1272 "DUPLICATE ENTRY in REQ AVL : root %p, "
1273 "idp %p, session_id %p",
1274 root_idp, idp, chanp->chan_session_id);
1275 return (EINVAL);
1276 }
1277 avl_insert(&root_chanp->chan_req_avl_tree,
1278 (void *)idp, where);
1279 chanp->chan_req_state = REQ_CMID_NOTIFIED;
1280 }
1281 mutex_exit(&chanp->chan_mutex);
1282 mutex_exit(&root_chanp->chan_mutex);
1283 }
1284
1285 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_reject: ret %x", ret);
1286 return (ret);
1287 }
1288
1289 int
rdma_disconnect(struct rdma_cm_id * idp)1290 rdma_disconnect(struct rdma_cm_id *idp)
1291 {
1292 sol_cma_chan_t *chanp;
1293 int ret = EINVAL;
1294 cma_chan_state_t state;
1295
1296 chanp = (sol_cma_chan_t *)idp;
1297 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_disconnect(%p)", idp);
1298
1299 if (!idp)
1300 return (0);
1301
1302 mutex_enter(&chanp->chan_mutex);
1303 if (!(SOL_CMAID_CONNECTED(chanp))) {
1304 SOL_OFS_DPRINTF_L3(sol_rdmacm_dbg_str,
1305 "rdma_disconnect(%p) - Not connected!!", idp);
1306 mutex_exit(&chanp->chan_mutex);
1307 return (EINVAL);
1308 }
1309 state = cma_get_chan_state(chanp);
1310 cma_set_chan_state(chanp, SOL_CMA_CHAN_DISCONNECT);
1311 mutex_exit(&chanp->chan_mutex);
1312
1313 if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) {
1314 ret = rdma_ib_disconnect(idp);
1315 #ifdef IWARP_SUPPORT
1316 } else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP) {
1317 ret = rdma_iw_disconnect(idp);
1318 #endif /* IWARP_SUPPORT */
1319 }
1320
1321 if (ret) {
1322 mutex_enter(&chanp->chan_mutex);
1323 cma_set_chan_state(chanp, state);
1324 mutex_exit(&chanp->chan_mutex);
1325 return (ret);
1326 }
1327
1328 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_disconnect: ret %x", ret);
1329 return (ret);
1330 }
1331
1332 int
rdma_init_qp_attr(struct rdma_cm_id * idp,struct ib_qp_attr * qpattr,int * qp_attr_mask)1333 rdma_init_qp_attr(struct rdma_cm_id *idp, struct ib_qp_attr *qpattr,
1334 int *qp_attr_mask)
1335 {
1336 sol_cma_chan_t *chanp;
1337 int ret = EINVAL;
1338
1339 ASSERT(idp);
1340 chanp = (sol_cma_chan_t *)idp;
1341 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_init_qp_attr(%p, %p, %p)",
1342 idp, qpattr, qp_attr_mask);
1343
1344 if (chanp->chan_xport_type == SOL_CMA_XPORT_IB) {
1345 ret = rdma_ib_init_qp_attr(idp, qpattr, qp_attr_mask);
1346 #ifdef IWARP_SUPPORT
1347 } else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP)
1348 ret = rdma_iw_init_qp_attr(idp, qpattr, qp_attr_mask);
1349 #endif /* IWARP_SUPPORT */
1350 } else {
1351 ret = EINVAL;
1352 }
1353
1354 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1355 "rdma_init_qp_attr: ret %x", ret);
1356
1357 return (ret);
1358 }
1359
1360 int
1361 rdma_join_multicast(struct rdma_cm_id *idp, struct sockaddr *addr,
1362 void *context)
1363 {
1364 sol_cma_chan_t *chanp;
1365 int ret = ENODEV;
1366 cma_chan_state_t state;
1367
1368 ASSERT(idp);
1369 chanp = (sol_cma_chan_t *)idp;
1370 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1371 "rdma_join_multicast(%p, %p, %p)",
1372 idp, addr, context);
1373
1374 mutex_enter(&chanp->chan_mutex);
1375 state = cma_get_chan_state(chanp);
1376 if (state != SOL_CMA_CHAN_BOUND &&
1377 state != SOL_CMA_CHAN_ROUTE_RESLVD &&
1378 state != SOL_CMA_CHAN_ADDR_RESLVD) {
1379 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1380 "rdma_join_multicast, Invalid state");
1381 mutex_exit(&chanp->chan_mutex);
1382 return (EINVAL);
1383 }
1384
1385 if (chanp->chan_xport_type == SOL_CMA_XPORT_IB)
1386 ret = rdma_ib_join_multicast(idp, addr, context);
1387 #ifdef IWARP_SUPPORT
1388 /* No support for Multicast on iWARP */
1389 else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP)
1390 ret = ENOTSUP;
1391 #endif /* IWARP_SUPPORT */
1392 mutex_exit(&chanp->chan_mutex);
1393
1394 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1395 "rdma_join_multicast: ret %x", ret);
1396 return (ret);
1397 }
1398
1399 void
1400 rdma_leave_multicast(struct rdma_cm_id *idp, struct sockaddr *addr)
1401 {
1402 sol_cma_chan_t *chanp;
1403 cma_chan_state_t state;
1404
1405 ASSERT(idp);
1406 chanp = (sol_cma_chan_t *)idp;
1407 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_leave_multicast(%p, %p)",
1408 idp, addr);
1409
1410 mutex_enter(&chanp->chan_mutex);
1411 state = cma_get_chan_state(chanp);
1412 if (state != SOL_CMA_CHAN_BOUND &&
1413 state != SOL_CMA_CHAN_ROUTE_RESLVD &&
1414 state != SOL_CMA_CHAN_ADDR_RESLVD) {
1415 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1416 "rdma_leave_multicast, Invalid state");
1417 mutex_exit(&chanp->chan_mutex);
1418 return;
1419 }
1420
1421 if (chanp->chan_xport_type == SOL_CMA_XPORT_IB)
1422 rdma_ib_leave_multicast(idp, addr);
1423 #ifdef IWARP_SUPPORT
1424 /* No support for Multicast on iWARP */
1425 else if (chanp->chan_xport_type == SOL_CMA_XPORT_IWARP)
1426 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1427 "rdma_leave_multicast, iWARP");
1428 #endif /* IWARP_SUPPORT */
1429 mutex_exit(&chanp->chan_mutex);
1430
1431 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "rdma_join_multicast: ret");
1432 }
1433
1434 /*
1435 * Functions to compare to rdma_cm_id *, used by AVL tree
1436 * routines.
1437 */
1438 int
1439 sol_cma_req_cmid_cmp(const void *p1, const void *p2)
1440 {
1441 sol_cma_chan_t *chanp;
1442
1443 chanp = (sol_cma_chan_t *)p2;
1444 if (chanp->chan_session_id > p1)
1445 return (+1);
1446 else if (chanp->chan_session_id < p1)
1447 return (-1);
1448 else
1449 return (0);
1450 }
1451
1452 int
1453 sol_cma_cmid_cmp(const void *p1, const void *p2)
1454 {
1455 sol_cma_chan_t *chanp;
1456
1457 chanp = (sol_cma_chan_t *)p2;
1458 if (chanp->chan_qp_hdl > p1)
1459 return (+1);
1460 else if (chanp->chan_qp_hdl < p1)
1461 return (-1);
1462 else
1463 return (0);
1464 }
1465
1466 /*
1467 * Function to compare two sol_cma_glbl_listen_t *, used by
1468 * AVL tree routines.
1469 */
1470 int
1471 sol_cma_svc_cmp(const void *p1, const void *p2)
1472 {
1473 sol_cma_glbl_listen_t *listenp;
1474 uint64_t sid;
1475
1476 sid = *(uint64_t *)p1;
1477 listenp = (sol_cma_glbl_listen_t *)p2;
1478 if (listenp->cma_listen_chan_sid > sid)
1479 return (+1);
1480 else if (listenp->cma_listen_chan_sid < sid)
1481 return (-1);
1482 else
1483 return (0);
1484 }
1485
1486 static int
1487 cma_init_listen_root(sol_cma_chan_t *chanp)
1488 {
1489 sol_cma_glbl_listen_t *cma_listenp;
1490 sol_cma_listen_info_t *chan_listenp;
1491 int rc = 0;
1492 avl_index_t where = 0;
1493 uint64_t listen_sid;
1494
1495 ASSERT(chanp);
1496 ASSERT(chanp->chan_listenp);
1497 chan_listenp = chanp->chan_listenp;
1498
1499 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1500 "cma_init_listen_root(%p)", chanp);
1501
1502 /*
1503 * First search for matching global listen_info for this SID.
1504 * If found with the same client handle, reuse the service
1505 * handle, if matching SID is found with different client
1506 * handle, return EINVAL.
1507 */
1508 listen_sid = ibcma_init_root_sid(chanp);
1509 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1510 "cma_init_listen_root: search SID 0x%llx",
1511 listen_sid);
1512
1513 mutex_enter(&sol_cma_glob_mutex);
1514 cma_listenp = avl_find(&sol_cma_glbl_listen_tree,
1515 (void *) &listen_sid, &where);
1516 if (cma_listenp && cma_listenp->cma_listen_clnt_hdl ==
1517 chanp->chan_ib_client_hdl) {
1518 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1519 "cma_init_listen_root: matching listenp %p SID 0x%llx",
1520 cma_listenp, listen_sid);
1521 chan_listenp->listen_entry = add_genlist(
1522 &cma_listenp->cma_listen_chan_list,
1523 (uintptr_t)chanp, NULL);
1524 chan_listenp->chan_glbl_listen_info = cma_listenp;
1525 ibcma_copy_srv_hdl(chanp, cma_listenp);
1526 mutex_exit(&sol_cma_glob_mutex);
1527 return (0);
1528 } else if (cma_listenp) {
1529 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1530 "cma_init_listen_root: listenp %p, SID 0x%llx match, "
1531 "client hdl prev %p, new %p mismatch",
1532 cma_listenp, listen_sid,
1533 cma_listenp->cma_listen_clnt_hdl,
1534 chanp->chan_ib_client_hdl);
1535 mutex_exit(&sol_cma_glob_mutex);
1536 return (EINVAL);
1537 }
1538
1539 cma_listenp = kmem_zalloc(sizeof (sol_cma_glbl_listen_t), KM_SLEEP);
1540 init_genlist(&cma_listenp->cma_listen_chan_list);
1541 chan_listenp->listen_entry = add_genlist(
1542 &cma_listenp->cma_listen_chan_list, (uintptr_t)chanp, NULL);
1543 chan_listenp->chan_glbl_listen_info = cma_listenp;
1544 cma_listenp->cma_listen_clnt_hdl = chanp->chan_ib_client_hdl;
1545 cma_listenp->cma_listen_chan_sid = listen_sid;
1546
1547 rc = ibcma_init_root_chan(chanp, cma_listenp);
1548 if (rc) {
1549 mutex_exit(&sol_cma_glob_mutex);
1550 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1551 "cma_init_listen_root: ibcma_init_root_chan failed!!");
1552 delete_genlist(&cma_listenp->cma_listen_chan_list,
1553 chan_listenp->listen_entry);
1554 kmem_free(cma_listenp, sizeof (sol_cma_glbl_listen_t));
1555 return (rc);
1556 }
1557 avl_insert(&sol_cma_glbl_listen_tree, cma_listenp, where);
1558 mutex_exit(&sol_cma_glob_mutex);
1559 return (0);
1560 }
1561
1562 static void
1563 cma_fini_listen_root(sol_cma_chan_t *chanp)
1564 {
1565 sol_cma_glbl_listen_t *cma_listenp;
1566 sol_cma_listen_info_t *chan_listenp;
1567
1568 ASSERT(chanp);
1569 ASSERT(chanp->chan_listenp);
1570 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "cma_fini_listen_root(%p)",
1571 chanp);
1572 chan_listenp = chanp->chan_listenp;
1573 cma_listenp = chan_listenp->chan_glbl_listen_info;
1574 ASSERT(cma_listenp);
1575 mutex_enter(&sol_cma_glob_mutex);
1576 delete_genlist(&cma_listenp->cma_listen_chan_list,
1577 chan_listenp->listen_entry);
1578 if (genlist_empty(&cma_listenp->cma_listen_chan_list)) {
1579 if (ibcma_fini_root_chan(chanp) == 0) {
1580 avl_remove(&sol_cma_glbl_listen_tree,
1581 cma_listenp);
1582 kmem_free(cma_listenp,
1583 sizeof (sol_cma_glbl_listen_t));
1584 } else
1585 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1586 "cma_fini_listen_root: "
1587 "ibcma_fini_root_chan failed");
1588 }
1589
1590 mutex_exit(&sol_cma_glob_mutex);
1591 }
1592
1593 typedef struct cma_event_async_arg {
1594 struct rdma_cm_id *idp;
1595 enum rdma_cm_event_type event;
1596 int status;
1597 union {
1598 struct rdma_conn_param conn;
1599 struct rdma_ud_param param;
1600 } un;
1601 struct rdma_conn_param *conn_param;
1602 struct rdma_ud_param *ud_paramp;
1603 } cma_event_async_arg_t;
1604
1605 static void cma_generate_event_sync(struct rdma_cm_id *,
1606 enum rdma_cm_event_type, int, struct rdma_conn_param *,
1607 struct rdma_ud_param *);
1608
1609 void
1610 cma_generate_event_thr(void *arg)
1611 {
1612 cma_event_async_arg_t *event_arg = (cma_event_async_arg_t *)arg;
1613
1614 cma_generate_event_sync(event_arg->idp, event_arg->event,
1615 event_arg->status, event_arg->conn_param,
1616 event_arg->ud_paramp);
1617
1618 if (event_arg->conn_param && event_arg->conn_param->private_data_len)
1619 kmem_free((void *)event_arg->conn_param->private_data,
1620 event_arg->conn_param->private_data_len);
1621 if (event_arg->ud_paramp && event_arg->ud_paramp->private_data_len)
1622 kmem_free((void *)event_arg->ud_paramp->private_data,
1623 event_arg->ud_paramp->private_data_len);
1624 kmem_free(arg, sizeof (cma_event_async_arg_t));
1625 }
1626
1627 void
1628 cma_generate_event(struct rdma_cm_id *idp, enum rdma_cm_event_type event,
1629 int status, struct rdma_conn_param *conn_param,
1630 struct rdma_ud_param *ud_paramp)
1631 {
1632 cma_event_async_arg_t *event_arg;
1633 sol_cma_chan_t *chanp = (sol_cma_chan_t *)idp;
1634
1635 /*
1636 * Set SOL_CMA_CALLER_EVENT_PROGRESS to indicate event
1637 * notification is in progress, so that races between
1638 * rdma_destroy_id() and event notification is taken care.
1639 *
1640 * If rdma_destroy_id() has been called for this CMID, call
1641 * cma_generate_event_sync() which skips notification to the
1642 * consumer and handles the event.
1643 */
1644 mutex_enter(&chanp->chan_mutex);
1645 chanp->chan_cmid_destroy_state |= SOL_CMA_CALLER_EVENT_PROGRESS;
1646 if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED) {
1647 mutex_exit(&chanp->chan_mutex);
1648 cma_generate_event_sync(idp, event, status, conn_param,
1649 ud_paramp);
1650 return;
1651 }
1652 mutex_exit(&chanp->chan_mutex);
1653
1654 event_arg = kmem_zalloc(sizeof (cma_event_async_arg_t), KM_SLEEP);
1655 event_arg->idp = idp;
1656 event_arg->event = event;
1657 event_arg->status = status;
1658 event_arg->conn_param = NULL;
1659 event_arg->ud_paramp = NULL;
1660 if (conn_param && conn_param->private_data_len) {
1661 bcopy(conn_param, &(event_arg->un.conn),
1662 sizeof (struct rdma_conn_param));
1663 event_arg->conn_param = &(event_arg->un.conn);
1664 event_arg->conn_param->private_data = kmem_zalloc(
1665 conn_param->private_data_len, KM_SLEEP);
1666 bcopy(conn_param->private_data,
1667 (void *)event_arg->conn_param->private_data,
1668 conn_param->private_data_len);
1669 } else if (conn_param && conn_param->private_data_len == 0) {
1670 bcopy(conn_param, &(event_arg->un.conn),
1671 sizeof (struct rdma_conn_param));
1672 } else if (ud_paramp) {
1673 bcopy(ud_paramp, &(event_arg->un.param),
1674 sizeof (struct rdma_ud_param));
1675 event_arg->ud_paramp = &(event_arg->un.param);
1676 if (ud_paramp->private_data_len) {
1677 event_arg->ud_paramp->private_data = kmem_zalloc(
1678 ud_paramp->private_data_len, KM_SLEEP);
1679 bcopy(ud_paramp->private_data,
1680 (void *)event_arg->ud_paramp->private_data,
1681 ud_paramp->private_data_len);
1682 } else if (ud_paramp->private_data) {
1683 event_arg->ud_paramp->private_data =
1684 ud_paramp->private_data;
1685 }
1686 }
1687
1688 if (taskq_dispatch(system_taskq, cma_generate_event_thr,
1689 (void *)event_arg, TQ_SLEEP) == TASKQID_INVALID) {
1690 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1691 "generate_event_async: taskq_dispatch() failed!!");
1692 mutex_enter(&chanp->chan_mutex);
1693 chanp->chan_cmid_destroy_state &=
1694 ~SOL_CMA_CALLER_EVENT_PROGRESS;
1695 if (chanp->chan_cmid_destroy_state &
1696 SOL_CMA_CALLER_CMID_DESTROYED)
1697 cv_broadcast(&chanp->chan_destroy_cv);
1698 mutex_exit(&chanp->chan_mutex);
1699 }
1700 }
1701
1702 static void
1703 cma_generate_event_sync(struct rdma_cm_id *idp, enum rdma_cm_event_type event,
1704 int status, struct rdma_conn_param *conn_param,
1705 struct rdma_ud_param *ud_paramp)
1706 {
1707 struct rdma_cm_event cm_event;
1708 sol_cma_chan_t *chanp = (sol_cma_chan_t *)idp;
1709 struct rdma_cm_id *root_idp = NULL;
1710 sol_cma_chan_t *root_chanp;
1711 int ret;
1712 cma_chan_state_t chan_state;
1713
1714 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "generate_event_sync(%p, %x, "
1715 "%x, %p, %p", idp, event, status, conn_param, ud_paramp);
1716
1717 bzero(&cm_event, sizeof (cm_event));
1718 cm_event.event = event;
1719 cm_event.status = status;
1720 if (conn_param)
1721 bcopy((void *)conn_param, (void *)(&(cm_event.param.conn)),
1722 sizeof (struct rdma_conn_param));
1723 else if (ud_paramp)
1724 bcopy((void *)ud_paramp, (void *)(&(cm_event.param.ud)),
1725 sizeof (struct rdma_ud_param));
1726
1727 /*
1728 * If the consumer has destroyed the context for this CMID -
1729 * do not notify, skip to handling the sol_ofs specific
1730 * handling of the event.
1731 */
1732 mutex_enter(&chanp->chan_mutex);
1733 if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED) {
1734 mutex_exit(&chanp->chan_mutex);
1735 goto ofs_consume_event;
1736 }
1737 mutex_exit(&chanp->chan_mutex);
1738
1739 root_idp = CHAN_LISTEN_ROOT(chanp);
1740 root_chanp = (sol_cma_chan_t *)root_idp;
1741 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "gen_event: root_idp %p",
1742 root_idp);
1743
1744 if (event == RDMA_CM_EVENT_CONNECT_REQUEST) {
1745 /*
1746 * Update chan_req_state for the REQ CMID. Decrement
1747 * count of REQ CMIDs not notifed to consumer.
1748 */
1749 ASSERT(root_idp);
1750 mutex_enter(&root_chanp->chan_mutex);
1751 root_chanp->chan_req_cnt--;
1752 #ifdef DEBUG
1753 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str,
1754 "Dec req_cnt of %p IDP, idp %p, req_cnt %x",
1755 root_idp, idp, root_chanp->chan_req_cnt);
1756 #endif
1757 mutex_exit(&root_chanp->chan_mutex);
1758 }
1759
1760 /* Pass the event to the client */
1761 ret = (idp->event_handler) (idp, &cm_event);
1762
1763 if (ret) {
1764 /*
1765 * If the consumer returned failure :
1766 * CONNECT_REQUEST :
1767 * 1. rdma_disconnect() to disconnect connection.
1768 * 2. wakeup destroy, if destroy has been called
1769 * for this CMID
1770 * 3. Destroy CMID if rdma_destroy has not been
1771 * called.
1772 * DISCONNECTED :
1773 * 1. call cma_handle_nomore_events() to cleanup
1774 * Other Events :
1775 * 1. Client is expected to destroy the CMID.
1776 */
1777 if (event == RDMA_CM_EVENT_CONNECT_REQUEST) {
1778 SOL_OFS_DPRINTF_L4(sol_rdmacm_dbg_str,
1779 "cma_generate_event_async: consumer failed %d "
1780 "event", event);
1781 if (rdma_disconnect(idp)) {
1782 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1783 "generate_event_async: rdma_disconnect "
1784 "failed");
1785 }
1786 mutex_enter(&chanp->chan_mutex);
1787 ASSERT(SOL_IS_SERVER_CMID(chanp));
1788 chanp->chan_req_state = REQ_CMID_SERVER_NONE;
1789 chanp->chan_cmid_destroy_state &=
1790 ~SOL_CMA_CALLER_EVENT_PROGRESS;
1791 if (chanp->chan_cmid_destroy_state &
1792 SOL_CMA_CALLER_CMID_DESTROYED) {
1793 cv_broadcast(&chanp->chan_destroy_cv);
1794 mutex_exit(&chanp->chan_mutex);
1795 } else {
1796 mutex_exit(&chanp->chan_mutex);
1797 rdma_destroy_id(idp);
1798 }
1799 } else if (event == RDMA_CM_EVENT_DISCONNECTED) {
1800 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1801 "generate_event_async: consumer failed %d event",
1802 event);
1803 cma_handle_nomore_events(chanp);
1804 mutex_enter(&chanp->chan_mutex);
1805 chan_state = cma_get_chan_state(chanp);
1806 chanp->chan_cmid_destroy_state &=
1807 ~SOL_CMA_CALLER_EVENT_PROGRESS;
1808 if (chanp->chan_cmid_destroy_state &
1809 SOL_CMA_CALLER_CMID_DESTROYED) {
1810 cv_broadcast(&chanp->chan_destroy_cv);
1811 mutex_exit(&chanp->chan_mutex);
1812 } else if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING) {
1813 /* rdma_destroy_id() called: destroy CMID */
1814 mutex_exit(&chanp->chan_mutex);
1815 cma_destroy_id((struct rdma_cm_id *)chanp);
1816 } else
1817 mutex_exit(&chanp->chan_mutex);
1818 } else {
1819 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
1820 "generate_event_async: consumer failed %d event",
1821 event);
1822 }
1823
1824 return;
1825 }
1826 ofs_consume_event:
1827 if (event == RDMA_CM_EVENT_DISCONNECTED) {
1828 cma_chan_state_t chan_state;
1829
1830 cma_handle_nomore_events(chanp);
1831 mutex_enter(&chanp->chan_mutex);
1832 chan_state = cma_get_chan_state(chanp);
1833 chanp->chan_cmid_destroy_state &=
1834 ~SOL_CMA_CALLER_EVENT_PROGRESS;
1835 if (chanp->chan_cmid_destroy_state &
1836 SOL_CMA_CALLER_CMID_DESTROYED) {
1837 cv_broadcast(&chanp->chan_destroy_cv);
1838 mutex_exit(&chanp->chan_mutex);
1839 } else if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING) {
1840 /* If rdma_destroy_id() was called, destroy CMID */
1841 mutex_exit(&chanp->chan_mutex);
1842 cma_destroy_id((struct rdma_cm_id *)chanp);
1843 } else
1844 mutex_exit(&chanp->chan_mutex);
1845 return;
1846 } else if (IS_UDP_CMID(idp) && event == RDMA_CM_EVENT_UNREACHABLE) {
1847 /*
1848 * If rdma_destroy_id() was called, destroy CMID
1849 * If not chan_connect_flag/ chan_req_state has already been
1850 * set to indicate that it can be deleted.
1851 */
1852 mutex_enter(&chanp->chan_mutex);
1853 chan_state = cma_get_chan_state(chanp);
1854 chanp->chan_cmid_destroy_state &=
1855 ~SOL_CMA_CALLER_EVENT_PROGRESS;
1856 if (chanp->chan_cmid_destroy_state &
1857 SOL_CMA_CALLER_CMID_DESTROYED) {
1858 cv_broadcast(&chanp->chan_destroy_cv);
1859 mutex_exit(&chanp->chan_mutex);
1860 } else if (chan_state == SOL_CMA_CHAN_DESTROY_PENDING) {
1861 mutex_exit(&chanp->chan_mutex);
1862 cma_destroy_id(idp);
1863 } else
1864 mutex_exit(&chanp->chan_mutex);
1865 return;
1866 }
1867
1868 mutex_enter(&chanp->chan_mutex);
1869 chanp->chan_cmid_destroy_state &= ~SOL_CMA_CALLER_EVENT_PROGRESS;
1870 if (chanp->chan_cmid_destroy_state & SOL_CMA_CALLER_CMID_DESTROYED)
1871 cv_broadcast(&chanp->chan_destroy_cv);
1872 mutex_exit(&chanp->chan_mutex);
1873 }
1874
1875 /* Local Static functions */
1876 static struct rdma_cm_id *
1877 cma_alloc_chan(rdma_cm_event_handler evt_hdlr, void *context,
1878 enum rdma_port_space ps)
1879 {
1880 struct rdma_cm_id *rdma_idp;
1881 sol_cma_chan_t *chanp;
1882
1883 chanp = kmem_zalloc(sizeof (sol_cma_chan_t), KM_SLEEP);
1884 mutex_init(&chanp->chan_mutex, NULL, MUTEX_DRIVER, NULL);
1885 cv_init(&chanp->chan_destroy_cv, NULL, CV_DRIVER, NULL);
1886 rdma_idp = &(chanp->chan_rdma_cm);
1887 rdma_idp->context = context;
1888 rdma_idp->ps = ps;
1889 rdma_idp->event_handler = evt_hdlr;
1890 mutex_enter(&chanp->chan_mutex);
1891 cma_set_chan_state(chanp, SOL_CMA_CHAN_IDLE);
1892 avl_create(&chanp->chan_req_avl_tree, sol_cma_req_cmid_cmp,
1893 sizeof (sol_cma_chan_t),
1894 offsetof(sol_cma_chan_t, chan_req_avl_node));
1895 avl_create(&chanp->chan_acpt_avl_tree, sol_cma_cmid_cmp,
1896 sizeof (sol_cma_chan_t),
1897 offsetof(sol_cma_chan_t, chan_acpt_avl_node));
1898 mutex_exit(&chanp->chan_mutex);
1899
1900 return (rdma_idp);
1901 }
1902
1903 /* Change the state of sol_cma_chan_t */
1904 static void
1905 cma_set_chan_state(sol_cma_chan_t *chanp, cma_chan_state_t newstate)
1906 {
1907 ASSERT(MUTEX_HELD(&chanp->chan_mutex));
1908 chanp->chan_state = newstate;
1909 }
1910
1911 cma_chan_state_t
1912 cma_get_chan_state(sol_cma_chan_t *chanp)
1913 {
1914 ASSERT(MUTEX_HELD(&chanp->chan_mutex));
1915 return (chanp->chan_state);
1916 }
1917
1918 /* Check & Swap the state of sol_ucma_chan_t */
1919 static int
1920 cma_cas_chan_state(sol_cma_chan_t *chanp, cma_chan_state_t prevstate,
1921 cma_chan_state_t newstate)
1922 {
1923 int ret = 0;
1924
1925 ASSERT(MUTEX_HELD(&chanp->chan_mutex));
1926 if (chanp->chan_state != prevstate)
1927 ret = -1;
1928 else
1929 chanp->chan_state = newstate;
1930
1931 return (ret);
1932 }
1933
1934 static void
1935 cma_free_listen_list(struct rdma_cm_id *idp)
1936 {
1937 genlist_entry_t *entry;
1938 sol_cma_chan_t *chanp = (sol_cma_chan_t *)idp;
1939
1940 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "cma_free_listen_list(%p)", idp);
1941 mutex_enter(&chanp->chan_mutex);
1942 entry = remove_genlist_head(&(CHAN_LISTEN_LIST(chanp)));
1943 mutex_exit(&chanp->chan_mutex);
1944 while (entry) {
1945 sol_cma_chan_t *ep_chanp;
1946
1947 ep_chanp = (sol_cma_chan_t *)entry->data;
1948 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "fini_ep_chan: %p",
1949 ep_chanp);
1950 if (ibcma_fini_ep_chan(ep_chanp) == 0) {
1951 genlist_entry_t *entry1;
1952 struct ib_device *device;
1953 cma_device_t *cma_device;
1954
1955 ASSERT(ep_chanp->chan_listenp);
1956 mutex_enter(&ep_chanp->chan_mutex);
1957 entry1 = ep_chanp->chan_listenp->listen_ep_dev_entry;
1958 device = ep_chanp->chan_listenp->listen_ep_device;
1959 ASSERT(device);
1960 cma_device = device->data;
1961 delete_genlist(&cma_device->cma_epchan_list,
1962 entry1);
1963 sol_cma_release_device(
1964 (struct rdma_cm_id *)ep_chanp);
1965 mutex_exit(&ep_chanp->chan_mutex);
1966 if (ep_chanp->chan_listenp)
1967 kmem_free(ep_chanp->chan_listenp,
1968 sizeof (sol_cma_listen_info_t));
1969
1970 mutex_destroy(&ep_chanp->chan_mutex);
1971 cv_destroy(&ep_chanp->chan_destroy_cv);
1972 kmem_free(ep_chanp, sizeof (sol_cma_chan_t));
1973 kmem_free(entry, sizeof (genlist_entry_t));
1974 }
1975
1976 mutex_enter(&chanp->chan_mutex);
1977 entry = remove_genlist_head(&(CHAN_LISTEN_LIST(chanp)));
1978 mutex_exit(&chanp->chan_mutex);
1979 }
1980 }
1981
1982 /*
1983 * Destroy a listening CMID when :
1984 * a. All CONNECTION REQUEST recieved have been rejected
1985 * or closed.
1986 * b. No CONNECTION REQUEST recieved.
1987 * Do not destroy a listening CMID when :
1988 * a. CONNECTION REQUEST has been recieved and not been
1989 * accepted from the passive / server side.
1990 * b. CONNECTION REQUEST has been recieved and has been
1991 * accepted from the passive server side.
1992 * Mark the listening CMID as destroy pending.
1993 *
1994 * For CMIDs created for rdma_connect() or created for a
1995 * CONNECT request, destroy the CMID only when :
1996 * CONNECTION has been closed or rejected.
1997 *
1998 * Mark the CMID as destroy pending.
1999 *
2000 * When a connection is rejected or closed :
2001 * Check if flag indicates - destroy pending,
2002 * cma_destroy_id() is called, this also does
2003 *
2004 * If there is a listening CMID assosiated with it,
2005 * call cma_destroy_if(listen_cmid);
2006 */
2007 void
2008 cma_destroy_id(struct rdma_cm_id *idp)
2009 {
2010 sol_cma_chan_t *chanp = (sol_cma_chan_t *)idp;
2011 cma_chan_state_t state;
2012 ulong_t acpt_nodes, req_nodes;
2013
2014 mutex_enter(&chanp->chan_mutex);
2015 acpt_nodes = avl_numnodes(&chanp->chan_acpt_avl_tree);
2016 req_nodes = avl_numnodes(&chanp->chan_req_avl_tree);
2017 state = cma_get_chan_state(chanp);
2018 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "cma_destroy_id(%p)- "
2019 "est CMIDs %ld, req CMID %ld, listen_root %p, state %x, %x",
2020 idp, acpt_nodes, req_nodes, chanp->listen_root,
2021 state, chanp->chan_req_state);
2022
2023 /*
2024 * If there are either REQ recieved or Established CMIDs just return.
2025 * rdma_destroy() for these CMIDs can be called by client later.
2026 */
2027 if (acpt_nodes || req_nodes) {
2028 cma_set_chan_state(chanp, SOL_CMA_CHAN_DESTROY_PENDING);
2029 mutex_exit(&chanp->chan_mutex);
2030 return;
2031 }
2032 cma_set_chan_state(chanp, SOL_CMA_CHAN_DESTROYING);
2033 avl_destroy(&chanp->chan_req_avl_tree);
2034 avl_destroy(&chanp->chan_acpt_avl_tree);
2035
2036 mutex_exit(&chanp->chan_mutex);
2037 if (idp->route.path_rec) {
2038 kmem_free(idp->route.path_rec,
2039 sizeof (struct ib_sa_path_rec) * idp->route.num_paths);
2040 idp->route.path_rec = NULL;
2041 }
2042
2043 switch (chanp->chan_xport_type) {
2044 case SOL_CMA_XPORT_NONE :
2045 break;
2046 case SOL_CMA_XPORT_IB :
2047 rdma_ib_destroy_id(idp);
2048 break;
2049 #ifdef IWARP_SUPPORT
2050 case SOL_CMA_XPORT_IWARP :
2051 rdma_iw_destroy_id(idp);
2052 break;
2053 #endif /* IWARP_SUPPORT */
2054 default :
2055 SOL_OFS_DPRINTF_L2(sol_rdmacm_dbg_str,
2056 "cma_destroy_id: Unsupported xport type %x",
2057 chanp->chan_xport_type);
2058 break;
2059 }
2060
2061 /*
2062 * Flush out & Free all listeners wrt to this ID
2063 * No locking is required as this code is executed
2064 * all REQ CMIDs have been destroyed. listen_list
2065 * will therefore not be modified during this loop.
2066 */
2067 if (chanp->chan_listenp) {
2068 cma_free_listen_list(idp);
2069 cma_fini_listen_root(chanp);
2070 kmem_free((void *)chanp->chan_listenp,
2071 sizeof (sol_cma_listen_info_t));
2072 chanp->chan_listenp = NULL;
2073 }
2074
2075 if (chanp->listen_root) {
2076 struct rdma_cm_id *root_idp;
2077 sol_cma_chan_t *root_chanp;
2078
2079 root_idp = chanp->listen_root;
2080 root_chanp = (sol_cma_chan_t *)root_idp;
2081 mutex_enter(&root_chanp->chan_mutex);
2082 state = cma_get_chan_state(root_chanp);
2083 acpt_nodes = avl_numnodes(&root_chanp->chan_acpt_avl_tree);
2084 req_nodes = avl_numnodes(&root_chanp->chan_req_avl_tree);
2085 mutex_exit(&root_chanp->chan_mutex);
2086 SOL_OFS_DPRINTF_L5(sol_rdmacm_dbg_str, "cma_destroy_id(%p)-"
2087 " root idp %p, state %x, acpt_nodes %ld, req_nodes %ld",
2088 idp, root_idp, state, acpt_nodes, req_nodes);
2089
2090 if (state == SOL_CMA_CHAN_DESTROY_PENDING &&
2091 req_nodes == 0UL && acpt_nodes == 0UL) {
2092 mutex_enter(&root_chanp->chan_mutex);
2093 root_chanp->chan_req_state = REQ_CMID_SERVER_NONE;
2094 mutex_exit(&root_chanp->chan_mutex);
2095 cma_destroy_id(root_idp);
2096 } else if (state == SOL_CMA_CHAN_DESTROY_WAIT &&
2097 req_nodes == 0UL && acpt_nodes == 0UL) {
2098 mutex_enter(&root_chanp->chan_mutex);
2099 cma_set_chan_state(root_chanp,
2100 SOL_CMA_CHAN_DESTROY_PENDING);
2101 root_chanp->chan_req_state = REQ_CMID_SERVER_NONE;
2102 cv_broadcast(&root_chanp->chan_destroy_cv);
2103 mutex_exit(&root_chanp->chan_mutex);
2104 }
2105 }
2106
2107 mutex_destroy(&chanp->chan_mutex);
2108 cv_destroy(&chanp->chan_destroy_cv);
2109 kmem_free(chanp, sizeof (sol_cma_chan_t));
2110 }
2111
2112 /*
2113 * Server TCP disconnect for an established channel.
2114 * If destroy_id() has been called for the listening
2115 * CMID and there are no more CMIDs with pending
2116 * events corresponding to the listening CMID, free
2117 * the listening CMID.
2118 *
2119 */
2120 static void
2121 cma_handle_nomore_events(sol_cma_chan_t *chanp)
2122 {
2123 struct rdma_cm_id *idp, *root_idp;
2124 sol_cma_chan_t *root_chanp;
2125 cma_chan_state_t state;
2126 ulong_t req_nodes, acpt_nodes;
2127
2128 idp = (struct rdma_cm_id *)chanp;
2129 root_idp = CHAN_LISTEN_ROOT(chanp);
2130 root_chanp = (sol_cma_chan_t *)root_idp;
2131 if (!root_chanp)
2132 return;
2133
2134 mutex_enter(&root_chanp->chan_mutex);
2135 mutex_enter(&chanp->chan_mutex);
2136 CHAN_LISTEN_ROOT(chanp) = NULL;
2137 root_chanp->chan_req_total_cnt--;
2138
2139 /*
2140 * Removal of CMID from the AVL trees should already have been done
2141 * by now. Below code mainly as a safety net.
2142 */
2143 if (chanp->chan_req_state == REQ_CMID_ACCEPTED) {
2144 ASSERT(chanp->chan_qp_hdl);
2145 ASSERT(cma_get_acpt_idp(root_idp,
2146 chanp->chan_qp_hdl));
2147 avl_remove(&root_chanp->chan_acpt_avl_tree, idp);
2148 chanp->chan_req_state = REQ_CMID_SERVER_NONE;
2149 }
2150 if (REQ_CMID_IN_REQ_AVL_TREE(chanp)) {
2151 ASSERT(chanp->chan_session_id);
2152 ASSERT(cma_get_req_idp(root_idp,
2153 chanp->chan_session_id));
2154 avl_remove(&root_chanp->chan_req_avl_tree, idp);
2155 chanp->chan_req_state = REQ_CMID_SERVER_NONE;
2156 }
2157
2158 state = cma_get_chan_state(root_chanp);
2159 req_nodes = avl_numnodes(&root_chanp->chan_req_avl_tree);
2160 acpt_nodes = avl_numnodes(&root_chanp->chan_acpt_avl_tree);
2161 mutex_exit(&chanp->chan_mutex);
2162 mutex_exit(&root_chanp->chan_mutex);
2163 if (state == SOL_CMA_CHAN_DESTROY_PENDING && req_nodes == 0UL &&
2164 acpt_nodes == 0UL)
2165 cma_destroy_id(root_idp);
2166 }
2167
2168 extern int ib_modify_qp(struct ib_qp *, struct ib_qp_attr *, int);
2169 extern int rdma_init_qp_attr(struct rdma_cm_id *, struct ib_qp_attr *,
2170 int *);
2171
2172 static int
2173 cma_init_ud_qp(sol_cma_chan_t *chanp, struct ib_qp *qp)
2174 {
2175 struct ib_qp_attr qp_attr;
2176 int qp_attr_mask, ret;
2177
2178 qp_attr.qp_state = IB_QPS_INIT;
2179 ret = rdma_init_qp_attr(&chanp->chan_rdma_cm, &qp_attr, &qp_attr_mask);
2180 if (ret)
2181 return (ret);
2182
2183 ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask);
2184 if (ret)
2185 return (ret);
2186
2187 qp_attr.qp_state = IB_QPS_RTR;
2188 ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE);
2189 if (ret)
2190 return (ret);
2191
2192 qp_attr.qp_state = IB_QPS_RTS;
2193 qp_attr.sq_psn = 0;
2194 ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN);
2195
2196 return (ret);
2197 }
2198
2199 static int
2200 cma_init_conn_qp(sol_cma_chan_t *chanp, struct ib_qp *qp)
2201 {
2202 struct ib_qp_attr qp_attr;
2203 int qp_attr_mask, ret;
2204
2205 qp_attr.qp_state = IB_QPS_INIT;
2206 ret = rdma_init_qp_attr(&chanp->chan_rdma_cm, &qp_attr, &qp_attr_mask);
2207 if (ret)
2208 return (ret);
2209
2210 return (ib_modify_qp(qp, &qp_attr, qp_attr_mask));
2211 }
2212
2213 static inline int
2214 cma_is_ud_ps(enum rdma_port_space ps)
2215 {
2216 return (ps == RDMA_PS_UDP || ps == RDMA_PS_IPOIB);
2217 }
2218
2219 int
2220 rdma_create_qp(struct rdma_cm_id *idp, struct ib_pd *pd,
2221 struct ib_qp_init_attr *qp_init_attr)
2222 {
2223 sol_cma_chan_t *chanp;
2224 struct ib_qp *qp;
2225 int ret;
2226 ofs_client_t *dev_ofs_client;
2227
2228 ASSERT(idp);
2229 chanp = (sol_cma_chan_t *)idp;
2230 if (idp->device->node_guid != pd->device->node_guid)
2231 return (-EINVAL);
2232
2233 dev_ofs_client = (ofs_client_t *)pd->device->clnt_hdl;
2234 rdma_map_id2clnthdl(idp, dev_ofs_client->ibt_hdl, NULL);
2235
2236 qp = ib_create_qp(pd, qp_init_attr);
2237 if ((uintptr_t)qp >= (uintptr_t)-0xFFF) {
2238 return ((intptr_t)qp);
2239 }
2240 rdma_map_id2qphdl(idp, (void *)qp->ibt_qp);
2241
2242 if (cma_is_ud_ps(idp->ps)) {
2243 ret = cma_init_ud_qp(chanp, qp);
2244 } else {
2245 ret = cma_init_conn_qp(chanp, qp);
2246 }
2247
2248 if (ret) {
2249 goto err;
2250 }
2251
2252 idp->qp = qp;
2253 chanp->chan_qp_num = qp->qp_num;
2254 chanp->chan_is_srq = (qp->srq != NULL);
2255 return (0);
2256 err:
2257 (void) ib_destroy_qp(qp);
2258 return (ret);
2259 }
2260
2261 void
2262 rdma_destroy_qp(struct rdma_cm_id *idp)
2263 {
2264 ASSERT(idp);
2265 (void) ib_destroy_qp(idp->qp);
2266 idp->qp = NULL;
2267 }
2268