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