xref: /illumos-gate/usr/src/lib/udapl/udapl_tavor/common/dapl_ia_util.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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) 2002-2003, Network Appliance, Inc. All rights reserved.
24  */
25 
26 /*
27  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 
32 /*
33  *
34  * MODULE: dapl_ia_util.c
35  *
36  * PURPOSE: Manage IA Info structure
37  *
38  * $Id: dapl_ia_util.c,v 1.29 2003/07/25 19:24:11 sjs2 Exp $
39  */
40 
41 #include "dapl.h"
42 #include "dapl_hca_util.h"
43 #include "dapl_ia_util.h"
44 #include "dapl_evd_util.h"
45 #include "dapl_adapter_util.h"
46 
47 /* Internal prototype */
48 void dapli_ia_release_hca(
49 	DAPL_HCA		*hca_ptr);
50 
51 
52 /*
53  * dapl_ia_alloc
54  *
55  * alloc and initialize an IA INFO struct
56  *
57  * Input:
58  * 	none
59  *
60  * Output:
61  * 	ia_ptr
62  *
63  * Returns:
64  * 	none
65  *
66  */
67 DAPL_IA *
68 dapl_ia_alloc(DAT_PROVIDER * provider, DAPL_HCA * hca_ptr)
69 {
70 	DAPL_IA * ia_ptr;
71 
72 	/* Allocate IA */
73 	ia_ptr = (DAPL_IA *) dapl_os_alloc(sizeof (DAPL_IA));
74 	if (ia_ptr == NULL) {
75 		return (NULL);
76 	}
77 
78 	/* zero the structure */
79 	(void) dapl_os_memzero(ia_ptr, sizeof (DAPL_IA));
80 
81 	/*
82 	 * initialize the header
83 	 */
84 	ia_ptr->header.provider		= provider;
85 	ia_ptr->header.magic		= DAPL_MAGIC_IA;
86 	ia_ptr->header.handle_type	= DAT_HANDLE_TYPE_IA;
87 	ia_ptr->header.owner_ia		= ia_ptr;
88 	ia_ptr->header.user_context.as_64 = 0;
89 	ia_ptr->header.user_context.as_ptr = NULL;
90 	dapl_llist_init_entry(&ia_ptr->header.ia_list_entry);
91 	dapl_os_lock_init(&ia_ptr->header.lock);
92 
93 	/*
94 	 * initialize the body
95 	 */
96 	ia_ptr->hca_ptr = hca_ptr;
97 	ia_ptr->async_error_evd = NULL;
98 	ia_ptr->cleanup_async_error_evd = DAT_FALSE;
99 	dapl_llist_init_entry(&ia_ptr->hca_ia_list_entry);
100 	dapl_llist_init_head(&ia_ptr->ep_list_head);
101 	dapl_llist_init_head(&ia_ptr->lmr_list_head);
102 	dapl_llist_init_head(&ia_ptr->rmr_list_head);
103 	dapl_llist_init_head(&ia_ptr->pz_list_head);
104 	dapl_llist_init_head(&ia_ptr->evd_list_head);
105 	dapl_llist_init_head(&ia_ptr->cno_list_head);
106 	dapl_llist_init_head(&ia_ptr->rsp_list_head);
107 	dapl_llist_init_head(&ia_ptr->psp_list_head);
108 
109 	/*
110 	 * initialize the flags
111 	 */
112 	ia_ptr->dapl_flags = 0;
113 
114 	dapl_hca_link_ia(hca_ptr, ia_ptr);
115 
116 	return (ia_ptr);
117 }
118 
119 
120 /*
121  * dapl_ia_abrupt_close
122  *
123  * Performs an abrupt close of the IA
124  *
125  * Input:
126  * 	ia_ptr
127  *
128  * Output:
129  * 	none
130  *
131  * Returns:
132  * 	status
133  *
134  */
135 
136 DAT_RETURN
137 dapl_ia_abrupt_close(
138 	IN DAPL_IA 	*ia_ptr)
139 {
140 	DAT_RETURN	dat_status;
141 	DAPL_EP		*ep_ptr, *next_ep_ptr;
142 	DAPL_LMR	*lmr_ptr, *next_lmr_ptr;
143 	DAPL_RMR	*rmr_ptr, *next_rmr_ptr;
144 	DAPL_PZ		*pz_ptr, *next_pz_ptr;
145 	DAPL_EVD	*evd_ptr, *next_evd_ptr;
146 	DAPL_CNO	*cno_ptr, *next_cno_ptr;
147 	DAPL_SP		*sp_ptr, *next_sp_ptr; /* for PSP and RSP queues */
148 	DAPL_HCA	*hca_ptr;
149 
150 	dat_status = DAT_SUCCESS;
151 
152 	/*
153 	 * clear all the data structures associated with the IA.
154 	 * this must be done in order (rmr,rsp) before (ep lmr psp) before
155 	 * (pz evd)
156 	 *
157 	 * Note that in all the following we can leave the loop either
158 	 * when we run out of entries, or when we get back to the head
159 	 * if we end up skipping an entry.
160 	 */
161 
162 	rmr_ptr = (dapl_llist_is_empty(&ia_ptr->rmr_list_head)
163 	    ? NULL : dapl_llist_peek_head(&ia_ptr->rmr_list_head));
164 	while (rmr_ptr != NULL) {
165 		next_rmr_ptr = dapl_llist_next_entry(&ia_ptr->rmr_list_head,
166 		    &rmr_ptr->header.ia_list_entry);
167 		dat_status = dapl_rmr_free(rmr_ptr);
168 		if (dat_status != DAT_SUCCESS) {
169 			dapl_dbg_log(DAPL_DBG_TYPE_WARN,
170 			    "ia_close(ABRUPT): rmr_free(%p) returns %x\n",
171 			    rmr_ptr,
172 			    dat_status);
173 		}
174 		rmr_ptr = next_rmr_ptr;
175 	}
176 
177 	sp_ptr = (dapl_llist_is_empty(&ia_ptr->rsp_list_head)
178 	    ? NULL : dapl_llist_peek_head(&ia_ptr->rsp_list_head));
179 	while (sp_ptr != NULL) {
180 		next_sp_ptr = dapl_llist_next_entry(&ia_ptr->rsp_list_head,
181 		    &sp_ptr->header.ia_list_entry);
182 		dat_status = dapl_rsp_free(sp_ptr);
183 		if (dat_status != DAT_SUCCESS) {
184 			dapl_dbg_log(DAPL_DBG_TYPE_WARN,
185 			    "ia_close(ABRUPT): rsp_free(%p) returns %x\n",
186 			    sp_ptr,
187 			    dat_status);
188 		}
189 		sp_ptr = next_sp_ptr;
190 	}
191 
192 	ep_ptr = (dapl_llist_is_empty(&ia_ptr->ep_list_head)
193 	    ? NULL : dapl_llist_peek_head(&ia_ptr->ep_list_head));
194 	while (ep_ptr != NULL) {
195 		next_ep_ptr = dapl_llist_next_entry(&ia_ptr->ep_list_head,
196 		    &ep_ptr->header.ia_list_entry);
197 		dat_status = dapl_ep_disconnect(ep_ptr, DAT_CLOSE_ABRUPT_FLAG);
198 		if (dat_status != DAT_SUCCESS) {
199 			dapl_dbg_log(DAPL_DBG_TYPE_WARN,
200 			    "ia_close(ABRUPT): ep_disconnect(%p) returns %x\n",
201 			    ep_ptr,
202 			    dat_status);
203 		}
204 		dat_status = dapl_ep_free(ep_ptr);
205 		if (dat_status != DAT_SUCCESS) {
206 			dapl_dbg_log(DAPL_DBG_TYPE_WARN,
207 			    "ia_close(ABRUPT): ep_free(%p) returns %x\n",
208 			    ep_ptr,
209 			    dat_status);
210 		}
211 		ep_ptr = next_ep_ptr;
212 	}
213 
214 	lmr_ptr = (dapl_llist_is_empty(&ia_ptr->lmr_list_head)
215 	    ? NULL : dapl_llist_peek_head(&ia_ptr->lmr_list_head));
216 	while (lmr_ptr != NULL) {
217 		next_lmr_ptr = dapl_llist_next_entry(&ia_ptr->lmr_list_head,
218 		    &lmr_ptr->header.ia_list_entry);
219 		dat_status = dapl_lmr_free(lmr_ptr);
220 		if (dat_status != DAT_SUCCESS) {
221 			dapl_dbg_log(DAPL_DBG_TYPE_WARN,
222 			    "ia_close(ABRUPT): lmr_free(%p) returns %x\n",
223 			    lmr_ptr,
224 			    dat_status);
225 		}
226 		lmr_ptr = next_lmr_ptr;
227 	}
228 
229 	sp_ptr = (dapl_llist_is_empty(&ia_ptr->psp_list_head)
230 	    ? NULL : dapl_llist_peek_head(&ia_ptr->psp_list_head));
231 	while (sp_ptr != NULL) {
232 		next_sp_ptr = dapl_llist_next_entry(&ia_ptr->psp_list_head,
233 		    &sp_ptr->header.ia_list_entry);
234 		dat_status = dapl_psp_free(sp_ptr);
235 		if (dat_status != DAT_SUCCESS) {
236 			dapl_dbg_log(DAPL_DBG_TYPE_WARN,
237 			    "ia_close(ABRUPT): psp_free(%p) returns %x\n",
238 			    sp_ptr,
239 			    dat_status);
240 		}
241 		sp_ptr = next_sp_ptr;
242 	}
243 
244 	pz_ptr = (dapl_llist_is_empty(&ia_ptr->pz_list_head)
245 	    ? NULL : dapl_llist_peek_head(&ia_ptr->pz_list_head));
246 	while (pz_ptr != NULL) {
247 		next_pz_ptr = dapl_llist_next_entry(&ia_ptr->pz_list_head,
248 		    &pz_ptr->header.ia_list_entry);
249 		dat_status = dapl_pz_free(pz_ptr);
250 		if (dat_status != DAT_SUCCESS) {
251 			dapl_dbg_log(DAPL_DBG_TYPE_WARN,
252 			    "ia_close(ABRUPT): pz_free(%p) returns %x\n",
253 			    pz_ptr,
254 			    dat_status);
255 		}
256 		pz_ptr = next_pz_ptr;
257 	}
258 
259 	/*
260 	 * EVDs are tricky; we want to release all except for the async
261 	 * EVD.  That EVD needs to stick around until after we close the
262 	 * HCA, to accept any async events that occur.  So we cycle through
263 	 * the list with dapl_llist_next_entry instead of dapl_llist_is_empty.
264 	 */
265 	evd_ptr = (dapl_llist_is_empty(&ia_ptr->evd_list_head)
266 	    ? NULL : dapl_llist_peek_head(&ia_ptr->evd_list_head));
267 	while (evd_ptr != NULL) {
268 		next_evd_ptr = dapl_llist_next_entry(&ia_ptr->evd_list_head,
269 		    &evd_ptr->header.ia_list_entry);
270 		if (evd_ptr == ia_ptr->async_error_evd) {
271 				/*
272 				 * Don't delete the EVD, but break any CNO
273 				 * connections.
274 				 */
275 				(void) dapl_evd_disable(evd_ptr);
276 				(void) dapl_evd_modify_cno(evd_ptr,
277 				    DAT_HANDLE_NULL);
278 		} else {
279 			/* it isn't the async EVD; delete it.  */
280 			dat_status = dapl_evd_free(evd_ptr);
281 			if (dat_status != DAT_SUCCESS) {
282 				dapl_dbg_log(DAPL_DBG_TYPE_WARN,
283 				    "ia_close(ABRUPT): evd_free(%p) "
284 				    "returns %x\n",
285 				    evd_ptr,
286 				    dat_status);
287 			}
288 		}
289 		evd_ptr = next_evd_ptr;
290 	}
291 
292 	cno_ptr = (dapl_llist_is_empty(&ia_ptr->cno_list_head)
293 	    ? NULL : dapl_llist_peek_head(&ia_ptr->cno_list_head));
294 	while (cno_ptr != NULL) {
295 		next_cno_ptr = dapl_llist_next_entry(&ia_ptr->cno_list_head,
296 		    &cno_ptr->header.ia_list_entry);
297 		dat_status = dapl_cno_free(cno_ptr);
298 		if (dat_status != DAT_SUCCESS) {
299 			dapl_dbg_log(DAPL_DBG_TYPE_WARN,
300 			    "ia_close(ABRUPT): cno_free(%p) returns %x\n",
301 			    cno_ptr,
302 			    dat_status);
303 		}
304 		cno_ptr = next_cno_ptr;
305 		}
306 
307 	hca_ptr = ia_ptr->hca_ptr;
308 
309 	/*
310 	 * Free the async EVD, shutting down callbacks from the HCA.
311 	 */
312 	if (ia_ptr->async_error_evd &&
313 	    (DAT_TRUE == ia_ptr->cleanup_async_error_evd)) {
314 		dat_status = dapls_ia_teardown_callbacks(ia_ptr);
315 
316 		hca_ptr->async_evd = NULL; /* It was our async EVD; nuke it.  */
317 
318 		dapl_os_atomic_dec(& ia_ptr->async_error_evd->evd_ref_count);
319 		dat_status = dapl_evd_free(ia_ptr->async_error_evd);
320 
321 		if (DAT_SUCCESS != dat_status) {
322 			dapl_dbg_log(DAPL_DBG_TYPE_WARN,
323 			    "ia_close(ABRUPT): evd_free(%p) returns %x\n",
324 			    ia_ptr->async_error_evd,
325 			    dat_status);
326 		}
327 
328 		ia_ptr->async_error_evd = NULL;
329 	}
330 
331 	/*
332 	 * Release our reference on the hca_handle. If we are the last
333 	 * one, close it
334 	 */
335 	dapli_ia_release_hca(hca_ptr);
336 
337 	dapls_ia_free(ia_ptr);
338 
339 	return (DAT_SUCCESS);		/* Abrupt close can't fail.  */
340 }
341 
342 
343 /*
344  * dapl_ia_graceful_close
345  *
346  * Performs an graceful close of the IA
347  *
348  * Input:
349  * 	ia_ptr
350  *
351  * Output:
352  * 	none
353  *
354  * Returns:
355  * 	status
356  *
357  */
358 
359 DAT_RETURN
360 dapl_ia_graceful_close(
361 	IN DAPL_IA	*ia_ptr)
362 {
363 	DAT_RETURN		dat_status;
364 	DAT_RETURN		cur_dat_status;
365 	DAPL_EVD		*evd_ptr;
366 	DAPL_LLIST_ENTRY 	*entry;
367 	DAPL_HCA		*hca_ptr;
368 
369 	dat_status = DAT_SUCCESS;
370 
371 	if (!dapl_llist_is_empty(&ia_ptr->rmr_list_head) ||
372 	    !dapl_llist_is_empty(&ia_ptr->rsp_list_head) ||
373 	    !dapl_llist_is_empty(&ia_ptr->ep_list_head) ||
374 	    !dapl_llist_is_empty(&ia_ptr->lmr_list_head) ||
375 	    !dapl_llist_is_empty(&ia_ptr->psp_list_head) ||
376 	    !dapl_llist_is_empty(&ia_ptr->pz_list_head)) {
377 		dat_status = DAT_ERROR(DAT_INVALID_STATE,
378 		    DAT_INVALID_STATE_IA_IN_USE);
379 		goto bail;
380 	}
381 
382 	/* if the async evd does not need to be cleaned up	*/
383 	/* (ie. it was not created by dapl_ia_open)		*/
384 	/*  then the evd list should be empty			*/
385 	if (DAT_FALSE == ia_ptr->cleanup_async_error_evd) {
386 		if (!dapl_llist_is_empty(&ia_ptr->evd_list_head)) {
387 			dat_status = DAT_ERROR(DAT_INVALID_STATE,
388 			    DAT_INVALID_STATE_IA_IN_USE);
389 			goto bail;
390 		}
391 	} else {
392 	/* else the async evd should be the only evd in */
393 	/* the list.					*/
394 		evd_ptr = (DAPL_EVD *)
395 		    dapl_llist_peek_head(&ia_ptr->evd_list_head);
396 
397 		if (!(evd_ptr->evd_flags & DAT_EVD_ASYNC_FLAG)) {
398 			dat_status = DAT_ERROR(DAT_INVALID_STATE,
399 			    DAT_INVALID_STATE_IA_IN_USE);
400 			goto bail;
401 		}
402 
403 		entry = ia_ptr->evd_list_head;
404 
405 		/* if the async evd is not the only element in the list */
406 		if (entry->blink != entry->flink) {
407 			dat_status = DAT_ERROR(DAT_INVALID_STATE,
408 			    DAT_INVALID_STATE_IA_IN_USE);
409 			goto bail;
410 		}
411 
412 		/*
413 		 * If the async evd has a non-unary ref count (i.e. it's in
414 		 * use by someone besides us.
415 		 */
416 		if (evd_ptr->evd_ref_count != 1) {
417 			dat_status = DAT_ERROR(DAT_INVALID_STATE,
418 			    DAT_INVALID_STATE_IA_IN_USE);
419 			goto bail;
420 		}
421 	}
422 
423 	/*
424 	 * We've validated the call; now we can start the teardown.
425 	 * Because we're in the IA close routine, we're safe from races with
426 	 * DAPL consumers on this IA (operate/destroy races are disallowed in
427 	 * DAPL).
428 	 */
429 	hca_ptr = ia_ptr->hca_ptr;
430 
431 	/* Tear down the async EVD if needed, first shutting down callbacks.  */
432 	if (ia_ptr->async_error_evd &&
433 	    (DAT_TRUE == ia_ptr->cleanup_async_error_evd)) {
434 		cur_dat_status = dapls_ia_teardown_callbacks(ia_ptr);
435 		if (DAT_SUCCESS != cur_dat_status) {
436 			dat_status = cur_dat_status;
437 		}
438 		hca_ptr->async_evd = NULL;
439 		dapl_os_atomic_dec(& ia_ptr->async_error_evd->evd_ref_count);
440 		cur_dat_status = dapl_evd_free(ia_ptr->async_error_evd);
441 		if (DAT_SUCCESS != cur_dat_status) {
442 			dat_status = cur_dat_status;
443 		}
444 
445 		ia_ptr->async_error_evd = NULL;
446 	}
447 
448 	dapli_ia_release_hca(hca_ptr);
449 
450 	dapls_ia_free(ia_ptr);
451 
452 bail:
453 	return (dat_status);
454 }
455 
456 /*
457  * Release a reference on the HCA handle. If it is 0, close the
458  * handle. Manipulate under lock to prevent races with threads trying to
459  * open the HCA.
460  */
461 void
462 dapli_ia_release_hca(
463     DAPL_HCA		*hca_ptr)
464 {
465 	dapl_os_lock(&hca_ptr->lock);
466 	dapl_os_atomic_dec(& hca_ptr->handle_ref_count);
467 	if (hca_ptr->handle_ref_count == 0) {
468 		DAT_RETURN dat_status;
469 
470 		/*
471 		 * Get rid of the cqd associated with the hca.
472 		 * Print out instead of status return as this routine
473 		 * shouldn't fail.
474 		 */
475 		dat_status = dapls_ib_cqd_destroy(hca_ptr);
476 		if (dat_status != DAT_SUCCESS) {
477 			dapl_dbg_log(DAPL_DBG_TYPE_ERR,
478 			    "ERR: Cannot free CQD: err %x\n", dat_status);
479 		}
480 
481 		(void) dapls_ib_close_hca(hca_ptr->ib_hca_handle);
482 		hca_ptr->ib_hca_handle = IB_INVALID_HANDLE;
483 	}
484 	dapl_os_unlock(&hca_ptr->lock);
485 }
486 
487 
488 /*
489  * dapls_ia_free
490  *
491  * free an IA INFO struct
492  *
493  * Input:
494  * 	ia_ptr
495  *
496  * Output:
497  * 	one
498  *
499  * Returns:
500  * 	none
501  *
502  */
503 void
504 dapls_ia_free(DAPL_IA *ia_ptr)
505 {
506 	dapl_os_assert(ia_ptr->header.magic == DAPL_MAGIC_IA);
507 
508 	dapl_os_assert(ia_ptr->async_error_evd == NULL);
509 	dapl_os_assert(dapl_llist_is_empty(&ia_ptr->lmr_list_head));
510 	dapl_os_assert(dapl_llist_is_empty(&ia_ptr->rmr_list_head));
511 	dapl_os_assert(dapl_llist_is_empty(&ia_ptr->ep_list_head));
512 	dapl_os_assert(dapl_llist_is_empty(&ia_ptr->evd_list_head));
513 	dapl_os_assert(dapl_llist_is_empty(&ia_ptr->cno_list_head));
514 	dapl_os_assert(dapl_llist_is_empty(&ia_ptr->psp_list_head));
515 	dapl_os_assert(dapl_llist_is_empty(&ia_ptr->rsp_list_head));
516 
517 	/*
518 	 * deinitialize the header
519 	 */
520 	dapl_hca_unlink_ia(ia_ptr->hca_ptr, ia_ptr);
521 	/* reset magic to prevent reuse */
522 	ia_ptr->header.magic = DAPL_MAGIC_INVALID;
523 	dapl_os_lock_destroy(&ia_ptr->header.lock);
524 
525 	dapl_os_free(ia_ptr, sizeof (DAPL_IA));
526 }
527 
528 /*
529  * dapl_ia_link_ep
530  *
531  * Add an ep to the IA structure
532  *
533  * Input:
534  *	ia_ptr
535  *	ep_ptr
536  *
537  * Output:
538  * 	none
539  *
540  * Returns:
541  * 	none
542  *
543  */
544 void
545 dapl_ia_link_ep(
546 	IN	DAPL_IA	   *ia_ptr,
547 	IN	DAPL_EP	   *ep_ptr)
548 {
549 	dapl_os_lock(&ia_ptr->header.lock);
550 	dapl_llist_add_head(&ia_ptr->ep_list_head,
551 	    &ep_ptr->header.ia_list_entry,
552 	    ep_ptr);
553 	dapl_os_unlock(&ia_ptr->header.lock);
554 }
555 
556 /*
557  * dapl_ia_unlink_ep
558  *
559  * Remove an ep from the ia info structure
560  *
561  * Input:
562  *	ia_ptr
563  *	ep_ptr
564  *
565  * Output:
566  * 	none
567  *
568  * Returns:
569  * 	none
570  *
571  */
572 void
573 dapl_ia_unlink_ep(
574 	IN	DAPL_IA	   *ia_ptr,
575 	IN	DAPL_EP	   *ep_ptr)
576 {
577 	dapl_os_lock(&ia_ptr->header.lock);
578 	(void) dapl_llist_remove_entry(&ia_ptr->ep_list_head,
579 	    &ep_ptr->header.ia_list_entry);
580 	dapl_os_unlock(&ia_ptr->header.lock);
581 }
582 
583 /*
584  * dapl_ia_link_lmr
585  *
586  * Add an lmr to the IA structure
587  *
588  * Input:
589  *	ia_ptr
590  *	lmr_ptr
591  *
592  * Output:
593  * 	none
594  *
595  * Returns:
596  * 	none
597  *
598  */
599 void
600 dapl_ia_link_lmr(
601 	IN	DAPL_IA	   *ia_ptr,
602 	IN	DAPL_LMR   *lmr_ptr)
603 {
604 	dapl_os_lock(&ia_ptr->header.lock);
605 	dapl_llist_add_head(&ia_ptr->lmr_list_head,
606 	    &lmr_ptr->header.ia_list_entry,
607 	    lmr_ptr);
608 	dapl_os_unlock(&ia_ptr->header.lock);
609 }
610 
611 /*
612  * dapl_ia_unlink_lmr
613  *
614  * Remove an lmr from the ia info structure
615  *
616  * Input:
617  *	ia_ptr
618  *	lmr_ptr
619  *
620  * Output:
621  * 	none
622  *
623  * Returns:
624  * 	none
625  *
626  */
627 void
628 dapl_ia_unlink_lmr(
629 	IN	DAPL_IA	   *ia_ptr,
630 	IN	DAPL_LMR   *lmr_ptr)
631 {
632 	dapl_os_lock(&ia_ptr->header.lock);
633 	(void) dapl_llist_remove_entry(&ia_ptr->lmr_list_head,
634 	    &lmr_ptr->header.ia_list_entry);
635 	dapl_os_unlock(&ia_ptr->header.lock);
636 }
637 
638 /*
639  * dapl_ia_link_rmr
640  *
641  * Add an rmr to the IA structure
642  *
643  * Input:
644  *	ia_ptr
645  *	rmr_ptr
646  *
647  * Output:
648  * 	none
649  *
650  * Returns:
651  * 	none
652  *
653  */
654 void
655 dapl_ia_link_rmr(
656 	IN	DAPL_IA	   *ia_ptr,
657 	IN	DAPL_RMR   *rmr_ptr)
658 {
659 	dapl_os_lock(&ia_ptr->header.lock);
660 	dapl_llist_add_head(&ia_ptr->rmr_list_head,
661 	    &rmr_ptr->header.ia_list_entry,
662 	    rmr_ptr);
663 	dapl_os_unlock(&ia_ptr->header.lock);
664 }
665 
666 /*
667  * dapl_ia_unlink_rmr
668  *
669  * Remove an rmr from the ia info structure
670  *
671  * Input:
672  *	ia_ptr
673  *	rmr_ptr
674  *
675  * Output:
676  * 	none
677  *
678  * Returns:
679  * 	none
680  *
681  */
682 void
683 dapl_ia_unlink_rmr(
684 	IN	DAPL_IA	   *ia_ptr,
685 	IN	DAPL_RMR   *rmr_ptr)
686 {
687 	dapl_os_lock(&ia_ptr->header.lock);
688 	(void) dapl_llist_remove_entry(&ia_ptr->rmr_list_head,
689 	    &rmr_ptr->header.ia_list_entry);
690 	dapl_os_unlock(&ia_ptr->header.lock);
691 }
692 
693 /*
694  * dapl_ia_link_pz
695  *
696  * Add an pz to the IA structure
697  *
698  * Input:
699  *	ia_ptr
700  *	pz_ptr
701  *
702  * Output:
703  * 	none
704  *
705  * Returns:
706  * 	none
707  *
708  */
709 void
710 dapl_ia_link_pz(
711 	IN	DAPL_IA	   *ia_ptr,
712 	IN	DAPL_PZ	   *pz_ptr)
713 {
714 	dapl_os_lock(&ia_ptr->header.lock);
715 	dapl_llist_add_head(&ia_ptr->pz_list_head,
716 	    &pz_ptr->header.ia_list_entry,
717 	    pz_ptr);
718 	dapl_os_unlock(&ia_ptr->header.lock);
719 }
720 
721 /*
722  * dapl_ia_unlink_pz
723  *
724  * Remove an pz from the ia info structure
725  *
726  * Input:
727  *	ia_ptr
728  *	pz_ptr
729  *
730  * Output:
731  * 	none
732  *
733  * Returns:
734  * 	none
735  *
736  */
737 void
738 dapl_ia_unlink_pz(
739 	IN	DAPL_IA	   *ia_ptr,
740 	IN	DAPL_PZ	   *pz_ptr)
741 {
742 	dapl_os_lock(&ia_ptr->header.lock);
743 	(void) dapl_llist_remove_entry(&ia_ptr->pz_list_head,
744 	    &pz_ptr->header.ia_list_entry);
745 	dapl_os_unlock(&ia_ptr->header.lock);
746 }
747 
748 /*
749  * dapl_ia_link_evd
750  *
751  * Add an evd to the IA structure
752  *
753  * Input:
754  *	ia_ptr
755  *	evd_ptr
756  *
757  * Output:
758  * 	none
759  *
760  * Returns:
761  * 	none
762  *
763  */
764 void
765 dapl_ia_link_evd(
766 	IN	DAPL_IA	   *ia_ptr,
767 	IN	DAPL_EVD   *evd_ptr)
768 {
769 	dapl_os_lock(&ia_ptr->header.lock);
770 	dapl_llist_add_head(&ia_ptr->evd_list_head,
771 	    &evd_ptr->header.ia_list_entry,
772 	    evd_ptr);
773 	dapl_os_unlock(&ia_ptr->header.lock);
774 }
775 
776 /*
777  * dapl_ia_unlink_evd
778  *
779  * Remove an evd from the ia info structure
780  *
781  * Input:
782  *	ia_ptr
783  *	evd_ptr
784  *
785  * Output:
786  * 	none
787  *
788  * Returns:
789  * 	none
790  *
791  */
792 void
793 dapl_ia_unlink_evd(
794 	IN	DAPL_IA	   *ia_ptr,
795 	IN	DAPL_EVD   *evd_ptr)
796 {
797 	dapl_os_lock(&ia_ptr->header.lock);
798 	(void) dapl_llist_remove_entry(&ia_ptr->evd_list_head,
799 	    &evd_ptr->header.ia_list_entry);
800 	dapl_os_unlock(&ia_ptr->header.lock);
801 }
802 
803 /*
804  * dapl_ia_link_cno
805  *
806  * Add an cno to the IA structure
807  *
808  * Input:
809  *	ia_ptr
810  *	cno_ptr
811  *
812  * Output:
813  * 	none
814  *
815  * Returns:
816  * 	none
817  *
818  */
819 void
820 dapl_ia_link_cno(
821 	IN	DAPL_IA	   *ia_ptr,
822 	IN	DAPL_CNO   *cno_ptr)
823 {
824 	dapl_os_lock(&ia_ptr->header.lock);
825 	dapl_llist_add_head(&ia_ptr->cno_list_head,
826 	    &cno_ptr->header.ia_list_entry,
827 	    cno_ptr);
828 	dapl_os_unlock(&ia_ptr->header.lock);
829 }
830 
831 /*
832  * dapl_ia_unlink_cno
833  *
834  * Remove an cno from the ia info structure
835  *
836  * Input:
837  *	ia_ptr
838  *	cno_ptr
839  *
840  * Output:
841  * 	none
842  *
843  * Returns:
844  * 	none
845  *
846  */
847 void
848 dapl_ia_unlink_cno(
849 	IN	DAPL_IA	   *ia_ptr,
850 	IN	DAPL_CNO   *cno_ptr)
851 {
852 	dapl_os_lock(&ia_ptr->header.lock);
853 	(void) dapl_llist_remove_entry(&ia_ptr->cno_list_head,
854 	    &cno_ptr->header.ia_list_entry);
855 	dapl_os_unlock(&ia_ptr->header.lock);
856 }
857 
858 /*
859  * dapl_ia_link_psp
860  *
861  * Add an psp to the IA structure
862  *
863  * Input:
864  *	ia_ptr
865  *	sp_ptr
866  *
867  * Output:
868  * 	none
869  *
870  * Returns:
871  * 	none
872  *
873  */
874 void
875 dapl_ia_link_psp(
876 	IN	DAPL_IA	   *ia_ptr,
877 	IN	DAPL_SP    *sp_ptr)
878 {
879 	dapl_os_lock(&ia_ptr->header.lock);
880 	dapl_llist_add_head(&ia_ptr->psp_list_head,
881 	    &sp_ptr->header.ia_list_entry,
882 	    sp_ptr);
883 	dapl_os_unlock(&ia_ptr->header.lock);
884 }
885 
886 /*
887  * daps_ia_unlink_sp
888  *
889  * Remove an sp from the appropriate ia rsp or psp queue
890  *
891  * Input:
892  *	ia_ptr
893  *	sp_ptr
894  *
895  * Output:
896  * 	none
897  *
898  * Returns:
899  * 	none
900  *
901  */
902 void
903 dapls_ia_unlink_sp(
904 	IN	DAPL_IA	   *ia_ptr,
905 	IN	DAPL_SP    *sp_ptr)
906 {
907 	DAPL_LLIST_HEAD	*list_head;
908 
909 	if (sp_ptr->header.handle_type == DAT_HANDLE_TYPE_PSP) {
910 		list_head = &ia_ptr->psp_list_head;
911 	} else {
912 		dapl_os_assert(sp_ptr->header.handle_type ==
913 		    DAT_HANDLE_TYPE_RSP);
914 		list_head = &ia_ptr->rsp_list_head;
915 	}
916 
917 	dapl_os_lock(&ia_ptr->header.lock);
918 	(void) dapl_llist_remove_entry(list_head,
919 	    &sp_ptr->header.ia_list_entry);
920 	dapl_os_unlock(&ia_ptr->header.lock);
921 }
922 
923 /*
924  * dapls_ia_sp_search
925  *
926  * Find an RSP or PSP on the IA list with a matching conn_qual value
927  *
928  * Input:
929  *	ia_ptr
930  *	sp_ptr
931  *
932  * Output:
933  * 	none
934  *
935  * Returns:
936  * 	none
937  *
938  */
939 DAPL_SP *
940 dapls_ia_sp_search(
941 	IN	DAPL_IA		   *ia_ptr,
942 	IN	DAT_CONN_QUAL	   conn_qual,
943 	IN	DAT_BOOLEAN	   is_psp)
944 {
945 	DAPL_SP		*sp_ptr;
946 	DAPL_LLIST_HEAD	*list_head;
947 
948 	if (is_psp) {
949 		list_head = &ia_ptr->psp_list_head;
950 	} else {
951 		list_head = &ia_ptr->rsp_list_head;
952 	}
953 
954 	dapl_os_lock(&ia_ptr->header.lock);
955 
956 	sp_ptr = (dapl_llist_is_empty(list_head) ? NULL :
957 	    dapl_llist_peek_head(list_head));
958 
959 	while (sp_ptr != NULL) {
960 		if (sp_ptr->conn_qual == conn_qual) {
961 			break;
962 		}
963 		sp_ptr = dapl_llist_next_entry(list_head,
964 		    &sp_ptr->header.ia_list_entry);
965 	}
966 
967 	dapl_os_unlock(&ia_ptr->header.lock);
968 
969 	return (sp_ptr);
970 }
971 
972 
973 /*
974  * dapl_ia_link_rsp
975  *
976  * Add an rsp to the IA structure
977  *
978  * Input:
979  *	ia_ptr
980  *	sp_ptr
981  *
982  * Output:
983  * 	none
984  *
985  * Returns:
986  * 	none
987  *
988  */
989 void
990 dapl_ia_link_rsp(
991 	IN	DAPL_IA	   *ia_ptr,
992 	IN	DAPL_SP    *sp_ptr)
993 {
994 	dapl_os_lock(&ia_ptr->header.lock);
995 	dapl_llist_add_head(&ia_ptr->rsp_list_head,
996 	    &sp_ptr->header.ia_list_entry,
997 	    sp_ptr);
998 	dapl_os_unlock(&ia_ptr->header.lock);
999 }
1000 
1001 /*
1002  * dapl_ia_link_srq
1003  *
1004  * Add an srq to the IA structure
1005  *
1006  * Input:
1007  *	ia_ptr
1008  *	srq_ptr
1009  *
1010  * Output:
1011  * 	none
1012  *
1013  * Returns:
1014  * 	none
1015  *
1016  */
1017 void
1018 dapl_ia_link_srq(
1019 	IN	DAPL_IA		*ia_ptr,
1020 	IN	DAPL_SRQ	*srq_ptr)
1021 {
1022 	dapl_os_lock(&ia_ptr->header.lock);
1023 	dapl_llist_add_head(&ia_ptr->srq_list_head,
1024 	    &srq_ptr->header.ia_list_entry,
1025 	    srq_ptr);
1026 	dapl_os_unlock(&ia_ptr->header.lock);
1027 }
1028 
1029 /*
1030  * dapl_ia_unlink_srq
1031  *
1032  * Remove an srq from the ia info structure
1033  *
1034  * Input:
1035  *	ia_ptr
1036  *	srq_ptr
1037  *
1038  * Output:
1039  * 	none
1040  *
1041  * Returns:
1042  * 	none
1043  *
1044  */
1045 void
1046 dapl_ia_unlink_srq(
1047 	IN	DAPL_IA	   *ia_ptr,
1048 	IN	DAPL_SRQ	   *srq_ptr)
1049 {
1050 	dapl_os_lock(&ia_ptr->header.lock);
1051 	(void) dapl_llist_remove_entry(&ia_ptr->srq_list_head,
1052 	    &srq_ptr->header.ia_list_entry);
1053 	dapl_os_unlock(&ia_ptr->header.lock);
1054 }
1055 
1056 DAT_RETURN
1057 dapls_ia_setup_callbacks(
1058     IN	DAPL_IA		*ia_ptr,
1059     IN	DAPL_EVD	*async_evd_ptr)
1060 {
1061 	DAT_RETURN dat_status = DAT_SUCCESS;
1062 
1063 	/* unaffiliated handler */
1064 	dat_status =
1065 	    dapls_ib_setup_async_callback(
1066 	    ia_ptr,
1067 	    DAPL_ASYNC_UNAFILIATED,
1068 	    NULL,
1069 	    (ib_async_handler_t)dapl_evd_un_async_error_callback,
1070 	    async_evd_ptr);
1071 
1072 	if (dat_status != DAT_SUCCESS) {
1073 		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
1074 		    "ib_set_un_async_error_eh failed %d\n",
1075 		    dat_status);
1076 		goto bail;
1077 	}
1078 
1079 	/* affiliated cq handler */
1080 	dat_status = dapls_ib_setup_async_callback(
1081 	    ia_ptr,
1082 	    DAPL_ASYNC_CQ_ERROR,
1083 	    NULL,
1084 	    (ib_async_handler_t)dapl_evd_cq_async_error_callback,
1085 	    async_evd_ptr);
1086 
1087 	if (dat_status != DAT_SUCCESS) {
1088 		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
1089 		    "ib_set_cq_async_error_eh failed %d\n",
1090 		    dat_status);
1091 		goto bail;
1092 	}
1093 
1094 	/* affiliated qp handler */
1095 	dat_status = dapls_ib_setup_async_callback(
1096 	    ia_ptr,
1097 	    DAPL_ASYNC_QP_ERROR,
1098 	    NULL,
1099 	    (ib_async_handler_t)dapl_evd_qp_async_error_callback,
1100 	    ia_ptr);
1101 	if (dat_status != DAT_SUCCESS) {
1102 		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
1103 		    "ib_set_qp_async_error_eh failed %d\n",
1104 		    dat_status);
1105 		goto bail;
1106 	}
1107 
1108 bail:
1109 	return (dat_status);
1110 }
1111 
1112 DAT_RETURN
1113 dapls_ia_teardown_callbacks(
1114     IN	DAPL_IA		*ia_ptr)
1115 {
1116 	DAT_RETURN dat_status = DAT_SUCCESS;
1117 
1118 	/* unaffiliated handler */
1119 	dat_status =
1120 	    dapls_ib_setup_async_callback(
1121 	    ia_ptr,
1122 	    DAPL_ASYNC_UNAFILIATED,
1123 	    NULL,
1124 	    (ib_async_handler_t)0,
1125 	    NULL);
1126 
1127 	if (dat_status != DAT_SUCCESS) {
1128 		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
1129 		    "ib_set_un_async_error_eh failed %d\n",
1130 		    dat_status);
1131 		goto bail;
1132 	}
1133 
1134 	/* affiliated cq handler */
1135 	dat_status = dapls_ib_setup_async_callback(
1136 	    ia_ptr,
1137 	    DAPL_ASYNC_CQ_ERROR,
1138 	    NULL,
1139 	    (ib_async_handler_t)0,
1140 	    NULL);
1141 
1142 	if (dat_status != DAT_SUCCESS) {
1143 		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
1144 		    "ib_set_cq_async_error_eh failed %d\n",
1145 		    dat_status);
1146 		goto bail;
1147 	}
1148 
1149 	/* affiliated qp handler */
1150 	dat_status = dapls_ib_setup_async_callback(
1151 	    ia_ptr,
1152 	    DAPL_ASYNC_QP_ERROR,
1153 	    NULL,
1154 	    (ib_async_handler_t)0,
1155 	    NULL);
1156 	if (dat_status != DAT_SUCCESS) {
1157 		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
1158 		    "ib_set_qp_async_error_eh failed %d\n",
1159 		    dat_status);
1160 		goto bail;
1161 	}
1162 
1163 bail:
1164 	return (dat_status);
1165 }
1166