]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ofed/management/opensm/opensm/osm_sa_mad_ctrl.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ofed / management / opensm / opensm / osm_sa_mad_ctrl.c
1 /*
2  * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  *
34  */
35
36 /*
37  * Abstract:
38  *    Implementation of osm_sa_mad_ctrl_t.
39  * This object is part of the SA object.
40  */
41
42 #if HAVE_CONFIG_H
43 #  include <config.h>
44 #endif                          /* HAVE_CONFIG_H */
45
46 #include <string.h>
47 #include <complib/cl_debug.h>
48 #include <iba/ib_types.h>
49 #include <vendor/osm_vendor_api.h>
50 #include <opensm/osm_sa_mad_ctrl.h>
51 #include <opensm/osm_msgdef.h>
52 #include <opensm/osm_helper.h>
53 #include <opensm/osm_sa.h>
54
55 /****f* opensm: SA/__osm_sa_mad_ctrl_disp_done_callback
56  * NAME
57  * __osm_sa_mad_ctrl_disp_done_callback
58  *
59  * DESCRIPTION
60  * This function is the Dispatcher callback that indicates
61  * a received MAD has been processed by the recipient.
62  *
63  * SYNOPSIS
64  */
65 static void
66 __osm_sa_mad_ctrl_disp_done_callback(IN void *context, IN void *p_data)
67 {
68         osm_sa_mad_ctrl_t *const p_ctrl = (osm_sa_mad_ctrl_t *) context;
69         osm_madw_t *const p_madw = (osm_madw_t *) p_data;
70
71         OSM_LOG_ENTER(p_ctrl->p_log);
72
73         CL_ASSERT(p_madw);
74         /*
75            Return the MAD & wrapper to the pool.
76          */
77         osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
78         OSM_LOG_EXIT(p_ctrl->p_log);
79 }
80
81 /************/
82
83 /****f* opensm: SA/__osm_sa_mad_ctrl_process
84  * NAME
85  * __osm_sa_mad_ctrl_process
86  *
87  * DESCRIPTION
88  * This function handles known methods for received MADs.
89  *
90  * SYNOPSIS
91  */
92 static void
93 __osm_sa_mad_ctrl_process(IN osm_sa_mad_ctrl_t * const p_ctrl,
94                           IN osm_madw_t * p_madw)
95 {
96         ib_sa_mad_t *p_sa_mad;
97         cl_status_t status;
98         cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE;
99         uint64_t last_dispatched_msg_queue_time_msec;
100         uint32_t num_messages;
101
102         OSM_LOG_ENTER(p_ctrl->p_log);
103
104         /*
105            If the dispatcher is showing us that it is overloaded
106            there is no point in placing the request in. We should instead provide
107            immediate response - IB_RESOURCE_BUSY
108            But how do we know?
109            The dispatcher reports back the number of outstanding messages and the
110            time the last message stayed in the queue.
111            HACK: Actually, we cannot send a mad from within the receive callback;
112            thus - we will just drop it.
113          */
114         cl_disp_get_queue_status(p_ctrl->h_disp,
115                                  &num_messages,
116                                  &last_dispatched_msg_queue_time_msec);
117         if ((num_messages > 1) &&
118             (p_ctrl->p_subn->opt.max_msg_fifo_timeout) &&
119             (last_dispatched_msg_queue_time_msec >
120              p_ctrl->p_subn->opt.max_msg_fifo_timeout)) {
121                 OSM_LOG(p_ctrl->p_log, OSM_LOG_INFO,
122                         /*             "Responding BUSY status since the dispatcher is already" */
123                         "Dropping MAD since the dispatcher is already"
124                         " overloaded with %u messages and queue time of:"
125                         "%" PRIu64 "[msec]\n",
126                         num_messages, last_dispatched_msg_queue_time_msec);
127
128                 /* send a busy response */
129                 /* osm_sa_send_error(p_ctrl->p_resp, p_madw, IB_RESOURCE_BUSY); */
130
131                 /* return the request to the pool */
132                 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
133
134                 goto Exit;
135         }
136
137         p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
138
139         /*
140            Note that attr_id (like the rest of the MAD) is in
141            network byte order.
142          */
143         switch (p_sa_mad->attr_id) {
144         case IB_MAD_ATTR_CLASS_PORT_INFO:
145                 msg_id = OSM_MSG_MAD_CLASS_PORT_INFO;
146                 break;
147
148         case IB_MAD_ATTR_NODE_RECORD:
149                 msg_id = OSM_MSG_MAD_NODE_RECORD;
150                 break;
151
152         case IB_MAD_ATTR_PORTINFO_RECORD:
153                 msg_id = OSM_MSG_MAD_PORTINFO_RECORD;
154                 break;
155
156         case IB_MAD_ATTR_LINK_RECORD:
157                 msg_id = OSM_MSG_MAD_LINK_RECORD;
158                 break;
159
160         case IB_MAD_ATTR_SMINFO_RECORD:
161                 msg_id = OSM_MSG_MAD_SMINFO_RECORD;
162                 break;
163
164         case IB_MAD_ATTR_SERVICE_RECORD:
165                 msg_id = OSM_MSG_MAD_SERVICE_RECORD;
166                 break;
167
168         case IB_MAD_ATTR_PATH_RECORD:
169                 msg_id = OSM_MSG_MAD_PATH_RECORD;
170                 break;
171
172         case IB_MAD_ATTR_MCMEMBER_RECORD:
173                 msg_id = OSM_MSG_MAD_MCMEMBER_RECORD;
174                 break;
175
176         case IB_MAD_ATTR_INFORM_INFO:
177                 msg_id = OSM_MSG_MAD_INFORM_INFO;
178                 break;
179
180         case IB_MAD_ATTR_VLARB_RECORD:
181                 msg_id = OSM_MSG_MAD_VL_ARB_RECORD;
182                 break;
183
184         case IB_MAD_ATTR_SLVL_RECORD:
185                 msg_id = OSM_MSG_MAD_SLVL_TBL_RECORD;
186                 break;
187
188         case IB_MAD_ATTR_PKEY_TBL_RECORD:
189                 msg_id = OSM_MSG_MAD_PKEY_TBL_RECORD;
190                 break;
191
192         case IB_MAD_ATTR_LFT_RECORD:
193                 msg_id = OSM_MSG_MAD_LFT_RECORD;
194                 break;
195
196         case IB_MAD_ATTR_GUIDINFO_RECORD:
197                 msg_id = OSM_MSG_MAD_GUIDINFO_RECORD;
198                 break;
199
200         case IB_MAD_ATTR_INFORM_INFO_RECORD:
201                 msg_id = OSM_MSG_MAD_INFORM_INFO_RECORD;
202                 break;
203
204         case IB_MAD_ATTR_SWITCH_INFO_RECORD:
205                 msg_id = OSM_MSG_MAD_SWITCH_INFO_RECORD;
206                 break;
207
208         case IB_MAD_ATTR_MFT_RECORD:
209                 msg_id = OSM_MSG_MAD_MFT_RECORD;
210                 break;
211
212 #if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
213         case IB_MAD_ATTR_MULTIPATH_RECORD:
214                 msg_id = OSM_MSG_MAD_MULTIPATH_RECORD;
215                 break;
216 #endif
217
218         default:
219                 OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A01: "
220                         "Unsupported attribute = 0x%X\n",
221                         cl_ntoh16(p_sa_mad->attr_id));
222                 osm_dump_sa_mad(p_ctrl->p_log, p_sa_mad, OSM_LOG_ERROR);
223         }
224
225         if (msg_id != CL_DISP_MSGID_NONE) {
226                 /*
227                    Post this MAD to the dispatcher for asynchronous
228                    processing by the appropriate controller.
229                  */
230
231                 OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
232                         "Posting Dispatcher message %s\n",
233                         osm_get_disp_msg_str(msg_id));
234
235                 status = cl_disp_post(p_ctrl->h_disp,
236                                       msg_id,
237                                       p_madw,
238                                       __osm_sa_mad_ctrl_disp_done_callback,
239                                       p_ctrl);
240
241                 if (status != CL_SUCCESS) {
242                         OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A02: "
243                                 "Dispatcher post message failed (%s) for attribute = 0x%X\n",
244                                 CL_STATUS_MSG(status),
245                                 cl_ntoh16(p_sa_mad->attr_id));
246
247                         osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
248                         goto Exit;
249                 }
250         } else {
251                 /*
252                    There is an unknown MAD attribute type for which there is
253                    no recipient.  Simply retire the MAD here.
254                  */
255                 cl_atomic_inc(&p_ctrl->p_stats->sa_mads_rcvd_unknown);
256                 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
257         }
258
259 Exit:
260         OSM_LOG_EXIT(p_ctrl->p_log);
261 }
262
263 /*
264  * PARAMETERS
265  *
266  * RETURN VALUES
267  *
268  * NOTES
269  *
270  * SEE ALSO
271  *********/
272
273 /****f* opensm: SA/__osm_sa_mad_ctrl_rcv_callback
274  * NAME
275  * __osm_sa_mad_ctrl_rcv_callback
276  *
277  * DESCRIPTION
278  * This is the callback from the transport layer for received MADs.
279  *
280  * SYNOPSIS
281  */
282 static void
283 __osm_sa_mad_ctrl_rcv_callback(IN osm_madw_t * p_madw,
284                                IN void *bind_context,
285                                IN osm_madw_t * p_req_madw)
286 {
287         osm_sa_mad_ctrl_t *p_ctrl = (osm_sa_mad_ctrl_t *) bind_context;
288         ib_sa_mad_t *p_sa_mad;
289
290         OSM_LOG_ENTER(p_ctrl->p_log);
291
292         CL_ASSERT(p_madw);
293
294         /*
295            A MAD was received from the wire, possibly in response to a request.
296          */
297         cl_atomic_inc(&p_ctrl->p_stats->sa_mads_rcvd);
298
299         OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
300                 "%u SA MADs received\n", p_ctrl->p_stats->sa_mads_rcvd);
301
302         /*
303          * C15-0.1.3 requires not responding to any MAD if the SM is
304          * not in active state!
305          * We will not respond if the sm_state is not MASTER, or if the
306          * first_time_master_sweep flag (of the subnet) is TRUE - this
307          * flag indicates that the master still didn't finish its first
308          * sweep, so the subnet is not up and stable yet.
309          */
310         if (p_ctrl->p_subn->sm_state != IB_SMINFO_STATE_MASTER) {
311                 cl_atomic_inc(&p_ctrl->p_stats->sa_mads_ignored);
312                 OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE,
313                         "Received SA MAD while SM not MASTER. MAD ignored\n");
314                 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
315                 goto Exit;
316         }
317         if (p_ctrl->p_subn->first_time_master_sweep == TRUE) {
318                 cl_atomic_inc(&p_ctrl->p_stats->sa_mads_ignored);
319                 OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE,
320                         "Received SA MAD while SM in first sweep. MAD ignored\n");
321                 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
322                 goto Exit;
323         }
324
325         p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
326
327         if (osm_log_is_active(p_ctrl->p_log, OSM_LOG_FRAMES))
328                 osm_dump_sa_mad(p_ctrl->p_log, p_sa_mad, OSM_LOG_FRAMES);
329
330         /*
331          * C15-0.1.5 - Table 185: SA Header - p884
332          * SM_key should be either 0 or match the current SM_Key
333          * otherwise discard the MAD.
334          */
335         if ((p_sa_mad->sm_key != 0) &&
336             (p_sa_mad->sm_key != p_ctrl->p_subn->opt.sa_key)) {
337                 OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A04: "
338                         "Non-Zero SA MAD SM_Key: 0x%" PRIx64 " != SM_Key: 0x%"
339                         PRIx64 "; MAD ignored\n", cl_ntoh64(p_sa_mad->sm_key),
340                         cl_ntoh64(p_ctrl->p_subn->opt.sa_key)
341                     );
342                 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
343                 goto Exit;
344         }
345
346         switch (p_sa_mad->method) {
347         case IB_MAD_METHOD_REPORT_RESP:
348                 /* we do not really do anything with report represses -
349                    just retire the transaction */
350                 OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
351                         "Received Report Repress. Retiring the transaction\n");
352
353                 if (p_req_madw)
354                         osm_mad_pool_put(p_ctrl->p_mad_pool, p_req_madw);
355                 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
356
357                 break;
358
359         case IB_MAD_METHOD_GET:
360         case IB_MAD_METHOD_GETTABLE:
361 #if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
362         case IB_MAD_METHOD_GETMULTI:
363 #endif
364         case IB_MAD_METHOD_SET:
365         case IB_MAD_METHOD_DELETE:
366                 __osm_sa_mad_ctrl_process(p_ctrl, p_madw);
367                 break;
368
369         default:
370                 cl_atomic_inc(&p_ctrl->p_stats->sa_mads_rcvd_unknown);
371                 OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A05: "
372                         "Unsupported method = 0x%X\n", p_sa_mad->method);
373                 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
374                 goto Exit;
375         }
376
377 Exit:
378         OSM_LOG_EXIT(p_ctrl->p_log);
379 }
380
381 /*
382  * PARAMETERS
383  *
384  * RETURN VALUES
385  *
386  * NOTES
387  *
388  * SEE ALSO
389  *********/
390
391 /****f* opensm: SA/__osm_sa_mad_ctrl_send_err_callback
392  * NAME
393  * __osm_sa_mad_ctrl_send_err_callback
394  *
395  * DESCRIPTION
396  * This is the callback from the transport layer for send errors
397  * on MADs that were expecting a response.
398  *
399  * SYNOPSIS
400  */
401 static void
402 __osm_sa_mad_ctrl_send_err_callback(IN void *bind_context,
403                                     IN osm_madw_t * p_madw)
404 {
405         osm_sa_mad_ctrl_t *p_ctrl = (osm_sa_mad_ctrl_t *) bind_context;
406         cl_status_t status;
407
408         OSM_LOG_ENTER(p_ctrl->p_log);
409
410         OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A06: "
411                 "MAD transaction completed in error\n");
412
413         /*
414            We should never be here since the SA never originates a request.
415            Unless we generated a Report(Notice)
416          */
417
418         CL_ASSERT(p_madw);
419
420         /*
421            An error occurred.  No response was received to a request MAD.
422            Retire the original request MAD.
423          */
424
425         osm_dump_sa_mad(p_ctrl->p_log, osm_madw_get_sa_mad_ptr(p_madw),
426                         OSM_LOG_ERROR);
427
428         /*  __osm_sm_mad_ctrl_update_wire_stats( p_ctrl ); */
429
430         if (osm_madw_get_err_msg(p_madw) != CL_DISP_MSGID_NONE) {
431                 OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG,
432                         "Posting Dispatcher message %s\n",
433                         osm_get_disp_msg_str(osm_madw_get_err_msg(p_madw)));
434
435                 status = cl_disp_post(p_ctrl->h_disp,
436                                       osm_madw_get_err_msg(p_madw),
437                                       p_madw,
438                                       __osm_sa_mad_ctrl_disp_done_callback,
439                                       p_ctrl);
440                 if (status != CL_SUCCESS) {
441                         OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A07: "
442                                 "Dispatcher post message failed (%s)\n",
443                                 CL_STATUS_MSG(status));
444                 }
445         } else {
446                 /*
447                    No error message was provided, just retire the MAD.
448                  */
449                 osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw);
450         }
451
452         OSM_LOG_EXIT(p_ctrl->p_log);
453 }
454
455 /*
456  * PARAMETERS
457  *
458  * RETURN VALUES
459  *
460  * NOTES
461  *
462  * SEE ALSO
463  *********/
464
465 /**********************************************************************
466  **********************************************************************/
467 void osm_sa_mad_ctrl_construct(IN osm_sa_mad_ctrl_t * const p_ctrl)
468 {
469         CL_ASSERT(p_ctrl);
470         memset(p_ctrl, 0, sizeof(*p_ctrl));
471         p_ctrl->h_disp = CL_DISP_INVALID_HANDLE;
472 }
473
474 /**********************************************************************
475  **********************************************************************/
476 void osm_sa_mad_ctrl_destroy(IN osm_sa_mad_ctrl_t * const p_ctrl)
477 {
478         CL_ASSERT(p_ctrl);
479         cl_disp_unregister(p_ctrl->h_disp);
480 }
481
482 /**********************************************************************
483  **********************************************************************/
484 ib_api_status_t
485 osm_sa_mad_ctrl_init(IN osm_sa_mad_ctrl_t * const p_ctrl,
486                      IN osm_sa_t * sa,
487                      IN osm_mad_pool_t * const p_mad_pool,
488                      IN osm_vendor_t * const p_vendor,
489                      IN osm_subn_t * const p_subn,
490                      IN osm_log_t * const p_log,
491                      IN osm_stats_t * const p_stats,
492                      IN cl_dispatcher_t * const p_disp)
493 {
494         ib_api_status_t status = IB_SUCCESS;
495
496         OSM_LOG_ENTER(p_log);
497
498         osm_sa_mad_ctrl_construct(p_ctrl);
499
500         p_ctrl->sa = sa;
501         p_ctrl->p_log = p_log;
502         p_ctrl->p_disp = p_disp;
503         p_ctrl->p_mad_pool = p_mad_pool;
504         p_ctrl->p_vendor = p_vendor;
505         p_ctrl->p_stats = p_stats;
506         p_ctrl->p_subn = p_subn;
507
508         p_ctrl->h_disp = cl_disp_register(p_disp,
509                                           CL_DISP_MSGID_NONE, NULL, p_ctrl);
510
511         if (p_ctrl->h_disp == CL_DISP_INVALID_HANDLE) {
512                 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 1A08: "
513                         "Dispatcher registration failed\n");
514                 status = IB_INSUFFICIENT_RESOURCES;
515                 goto Exit;
516         }
517
518 Exit:
519         OSM_LOG_EXIT(p_log);
520         return (status);
521 }
522
523 /**********************************************************************
524  **********************************************************************/
525 ib_api_status_t
526 osm_sa_mad_ctrl_bind(IN osm_sa_mad_ctrl_t * const p_ctrl,
527                      IN const ib_net64_t port_guid)
528 {
529         osm_bind_info_t bind_info;
530         ib_api_status_t status = IB_SUCCESS;
531
532         OSM_LOG_ENTER(p_ctrl->p_log);
533
534         if (p_ctrl->h_bind != OSM_BIND_INVALID_HANDLE) {
535                 OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A09: "
536                         "Multiple binds not allowed\n");
537                 status = IB_ERROR;
538                 goto Exit;
539         }
540
541         bind_info.class_version = 2;
542         bind_info.is_responder = TRUE;
543         bind_info.is_report_processor = FALSE;
544         bind_info.is_trap_processor = FALSE;
545         bind_info.mad_class = IB_MCLASS_SUBN_ADM;
546         bind_info.port_guid = port_guid;
547         bind_info.recv_q_size = OSM_SM_DEFAULT_QP1_RCV_SIZE;
548         bind_info.send_q_size = OSM_SM_DEFAULT_QP1_SEND_SIZE;
549
550         OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE,
551                 "Binding to port GUID 0x%" PRIx64 "\n", cl_ntoh64(port_guid));
552
553         p_ctrl->h_bind = osm_vendor_bind(p_ctrl->p_vendor,
554                                          &bind_info,
555                                          p_ctrl->p_mad_pool,
556                                          __osm_sa_mad_ctrl_rcv_callback,
557                                          __osm_sa_mad_ctrl_send_err_callback,
558                                          p_ctrl);
559
560         if (p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE) {
561                 status = IB_ERROR;
562                 OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A10: "
563                         "Vendor specific bind failed (%s)\n",
564                         ib_get_err_str(status));
565                 goto Exit;
566         }
567
568 Exit:
569         OSM_LOG_EXIT(p_ctrl->p_log);
570         return (status);
571 }
572
573 /**********************************************************************
574  **********************************************************************/
575 ib_api_status_t osm_sa_mad_ctrl_unbind(IN osm_sa_mad_ctrl_t * const p_ctrl)
576 {
577         ib_api_status_t status = IB_SUCCESS;
578
579         OSM_LOG_ENTER(p_ctrl->p_log);
580
581         if (p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE) {
582                 OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A11: "
583                         "No previous bind\n");
584                 status = IB_ERROR;
585                 goto Exit;
586         }
587
588         osm_vendor_unbind(p_ctrl->h_bind);
589 Exit:
590         OSM_LOG_EXIT(p_ctrl->p_log);
591         return (status);
592 }