New opensm component
[mirror/winof/.git] / ulp / opensm / user / opensm / osm_port_info_rcv.c
1 /*
2  * Copyright (c) 2004, 2005 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 the OpenIB.org BSD license
7  * below:
8  *
9  *     Redistribution and use in source and binary forms, with or
10  *     without modification, are permitted provided that the following
11  *     conditions are met:
12  *
13  *      - Redistributions of source code must retain the above
14  *        copyright notice, this list of conditions and the following
15  *        disclaimer.
16  *
17  *      - Redistributions in binary form must reproduce the above
18  *        copyright notice, this list of conditions and the following
19  *        disclaimer in the documentation and/or other materials
20  *        provided with the distribution.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
26  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29  * SOFTWARE.
30  *
31  * $Id$
32  */
33
34
35 /*
36  * Abstract:
37  *    Implementation of osm_pi_rcv_t.
38  * This object represents the PortInfo Receiver object.
39  * This object is part of the opensm family of objects.
40  *
41  * Environment:
42  *    Linux User Mode
43  *
44  * $Revision: 1.8 $
45  */
46
47 #if HAVE_CONFIG_H
48 #  include <config.h>
49 #endif /* HAVE_CONFIG_H */
50
51 #include <iba/ib_types.h>
52 #include <complib/cl_memory.h>
53 #include <complib/cl_qmap.h>
54 #include <complib/cl_passivelock.h>
55 #include <complib/cl_debug.h>
56 #include <opensm/osm_port_info_rcv.h>
57 #include <opensm/osm_node_info_rcv.h>
58 #include <opensm/osm_req.h>
59 #include <opensm/osm_madw.h>
60 #include <opensm/osm_log.h>
61 #include <opensm/osm_node.h>
62 #include <opensm/osm_subnet.h>
63 #include <opensm/osm_mad_pool.h>
64 #include <opensm/osm_msgdef.h>
65 #include <opensm/osm_helper.h>
66 #include <vendor/osm_vendor_api.h>
67 #include <opensm/osm_pkey.h>
68 #include <opensm/osm_remote_sm.h>
69
70 /**********************************************************************
71  **********************************************************************/
72 static void
73 __osm_pi_rcv_set_sm(
74   IN const osm_pi_rcv_t* const p_rcv,
75   IN osm_physp_t* const p_physp )
76 {
77   osm_bind_handle_t h_bind;
78   osm_dr_path_t *p_dr_path;
79
80   OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_set_sm );
81
82   if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
83   {
84     osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
85              "__osm_pi_rcv_set_sm: "
86              "Setting 'IS_SM' bit in port attributes.\n" );
87   }
88
89   p_dr_path = osm_physp_get_dr_path_ptr( p_physp );
90   h_bind = osm_dr_path_get_bind_handle( p_dr_path );
91   /*
92     The 'IS_SM' bit isn't already set, so set it.
93   */
94   osm_vendor_set_sm( h_bind, TRUE );
95
96   OSM_LOG_EXIT( p_rcv->p_log );
97 }
98
99 /**********************************************************************
100  **********************************************************************/
101 static void
102 __osm_pi_rcv_process_endport(
103   IN const osm_pi_rcv_t* const p_rcv,
104   IN osm_physp_t* const p_physp,
105   IN const ib_port_info_t* const p_pi )
106 {
107   osm_madw_context_t context;
108   ib_api_status_t    status;
109   ib_net64_t         port_guid;
110   uint8_t            rate, mtu;
111   cl_qmap_t*         p_sm_tbl;
112   osm_remote_sm_t*   p_sm;
113
114   OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_process_endport );
115
116   port_guid = osm_physp_get_port_guid( p_physp );
117
118   /* HACK should we track extended port 0 too? */
119   if (osm_physp_get_port_num( p_physp ) != 0)
120   {
121     /* track the minimal endport MTU and rate */
122     mtu = ib_port_info_get_mtu_cap(p_pi);
123     if (mtu < p_rcv->p_subn->min_ca_mtu)
124     {
125       osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
126                "__osm_pi_rcv_process_endport: "
127                "Setting endport minimal MTU to:%u defined by port:0x%" 
128                PRIx64 ".\n",
129                mtu,
130                cl_ntoh64( port_guid ) );
131       p_rcv->p_subn->min_ca_mtu = mtu;
132     }
133     
134     rate = ib_port_info_compute_rate( p_pi );
135     if (rate < p_rcv->p_subn->min_ca_rate)
136     {
137       osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
138                "__osm_pi_rcv_process_endport: "
139                "Setting endport minimal rate to:%u defiend by port:0x%" 
140                PRIx64 ".\n",
141                rate,
142                cl_ntoh64( port_guid ) );
143       p_rcv->p_subn->min_ca_rate = rate;
144     }
145   }
146
147   if( port_guid == p_rcv->p_subn->sm_port_guid )
148   {
149     /*
150       We received the PortInfo for our own port.
151     */
152     if( !(p_pi->capability_mask & IB_PORT_CAP_IS_SM ) )
153     {
154       /*
155         Set the IS_SM bit to indicate our port hosts an SM.
156       */
157       __osm_pi_rcv_set_sm( p_rcv, p_physp );
158     }
159   }
160   else
161   {
162     /*
163        Before querying the SM - we want to make sure we clean its state, so
164        if the querying fails we recognize that this SM is not active.
165     */
166     p_sm_tbl = &p_rcv->p_subn->sm_guid_tbl;
167     p_sm = (osm_remote_sm_t*)cl_qmap_get( p_sm_tbl, port_guid );
168     if( p_sm != (osm_remote_sm_t*)cl_qmap_end( p_sm_tbl ) )
169     {
170       /* clean it up */
171       p_sm->smi.pri_state = 0xF0 & p_sm->smi.pri_state;
172     }
173
174     if( p_pi->capability_mask & IB_PORT_CAP_IS_SM )
175     {
176       if( p_rcv->p_subn->opt.ignore_other_sm )
177       {
178         osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
179                  "__osm_pi_rcv_process_endport: "
180                  "Ignoring SM on port 0x%" PRIx64 ".\n",
181                  cl_ntoh64( port_guid ) );
182       }
183       else
184       {
185         if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) )
186         {
187           osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
188                    "__osm_pi_rcv_process_endport: "
189                    "Detected another SM.  Requesting SMInfo."
190                    "\n\t\t\t\tPort 0x%" PRIx64 ".\n",
191                    cl_ntoh64( port_guid ) );
192         }
193
194         /*
195           This port indicates it's an SM, and it's not our own port.
196           Acquire the SMInfo Attribute.
197         */
198         cl_memclr( &context, sizeof(context) );
199         context.smi_context.set_method = FALSE;
200         status = osm_req_get( p_rcv->p_req,
201                               osm_physp_get_dr_path_ptr( p_physp ),
202                               IB_MAD_ATTR_SM_INFO,
203                               0,
204                               CL_DISP_MSGID_NONE,
205                               &context );
206
207         if( status != IB_SUCCESS )
208         {
209           osm_log( p_rcv->p_log, OSM_LOG_ERROR,
210                    "__osm_pi_rcv_process_endport: ERR 0F05: "
211                    "Failure requesting SMInfo (%s).\n",
212                    ib_get_err_str( status ) );
213         }
214       }
215     }
216   }
217
218   OSM_LOG_EXIT( p_rcv->p_log );
219 }
220
221 /**********************************************************************
222  The plock must be held before calling this function.
223 **********************************************************************/
224 static void
225 __osm_pi_rcv_process_switch_port(
226   IN const osm_pi_rcv_t* const p_rcv,
227   IN osm_node_t* const p_node,
228   IN osm_physp_t* const p_physp,
229   IN const ib_port_info_t* const p_pi )
230 {
231   ib_api_status_t status = IB_SUCCESS;
232   osm_madw_context_t context;
233   osm_physp_t *p_remote_physp;
234   osm_node_t *p_remote_node;
235   uint8_t port_num;
236   uint8_t remote_port_num;
237   osm_dr_path_t path;
238
239   OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_process_switch_port );
240
241   /*
242     Check the state of the physical port.
243     If there appears to be something on the other end of the wire,
244     then ask for NodeInfo.  Ignore the switch managment port.
245   */
246   port_num = osm_physp_get_port_num( p_physp );
247   /* if in_sweep_hop_0 is TRUE, then this means the SM in on the switch,
248      and we got switchInfo of our local switch. Do not continue
249      probing through the switch. */
250   if( port_num != 0 && p_rcv->p_subn->in_sweep_hop_0 == FALSE)
251   {
252     switch( ib_port_info_get_port_state( p_pi ) )
253     {
254     case IB_LINK_DOWN:
255       p_remote_physp = osm_physp_get_remote( p_physp );
256       if( p_remote_physp && osm_physp_is_valid( p_remote_physp ) )
257       {
258         p_remote_node = osm_physp_get_node_ptr( p_remote_physp );
259         remote_port_num = osm_physp_get_port_num( p_remote_physp );
260
261         osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
262                  "__osm_pi_rcv_process_switch_port: "
263                  "Unlinking local node 0x%" PRIx64 ", port 0x%X"
264                  "\n\t\t\t\tand remote node 0x%" PRIx64
265                  ", port 0x%X.\n",
266                  cl_ntoh64( osm_node_get_node_guid( p_node ) ),
267                  port_num,
268                  cl_ntoh64( osm_node_get_node_guid( p_remote_node ) ),
269                  remote_port_num );
270
271         osm_node_unlink( p_node, (uint8_t)port_num,
272                          p_remote_node, (uint8_t)remote_port_num );
273
274       }
275       break;
276
277     case IB_LINK_INIT:
278     case IB_LINK_ARMED:
279     case IB_LINK_ACTIVE:
280       /*
281         To avoid looping forever, only probe the port if it
282         is NOT the port that responded to the SMP.
283
284         Request node info from the other end of this link:
285         1) Copy the current path from the parent node.
286         2) Extend the path to the next hop thru this port.
287         3) Request node info with the new path
288         
289       */
290       if( p_pi->local_port_num != osm_physp_get_port_num( p_physp ) )
291       {
292         path = *osm_physp_get_dr_path_ptr( p_physp );
293
294         osm_dr_path_extend( &path,
295                             osm_physp_get_port_num( p_physp ) );
296
297         context.ni_context.node_guid =
298           osm_node_get_node_guid( p_node );
299         context.ni_context.port_num =
300           osm_physp_get_port_num( p_physp );
301
302         status = osm_req_get( p_rcv->p_req,
303                               &path,
304                               IB_MAD_ATTR_NODE_INFO,
305                               0,
306                               CL_DISP_MSGID_NONE,
307                               &context );
308
309         if( status != IB_SUCCESS )
310         {
311           osm_log( p_rcv->p_log, OSM_LOG_ERROR,
312                    "__osm_pi_rcv_process_switch_port: ERR 0F02: "
313                    "Failure initiating NodeInfo request (%s).\n",
314                    ib_get_err_str(status));
315         }
316       }
317       else
318       {
319         if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
320         {
321           osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
322                    "__osm_pi_rcv_process_switch_port: "
323                    "Skipping SMP responder port 0x%X.\n",
324                    p_pi->local_port_num );
325         }
326       }
327       break;
328
329     default:
330       osm_log( p_rcv->p_log, OSM_LOG_ERROR,
331                "__osm_pi_rcv_process_switch_port: ERR 0F03: "
332                "Unknown link state = %u, port = 0x%X.\n",
333                osm_physp_get_port_state( p_physp ),
334                p_pi->local_port_num );
335       break;
336     }
337   }
338
339   /*
340     Update the PortInfo attribute.
341   */
342   osm_physp_set_port_info( p_physp, p_pi );
343
344   if (port_num == 0)
345   {
346     /* This is a management port 0 */
347                 __osm_pi_rcv_process_endport(p_rcv, p_physp, p_pi);
348   }
349
350   OSM_LOG_EXIT( p_rcv->p_log );
351 }
352
353 /**********************************************************************
354  **********************************************************************/
355 static void
356 __osm_pi_rcv_process_ca_port(
357   IN const osm_pi_rcv_t* const p_rcv,
358   IN osm_node_t* const p_node,
359   IN osm_physp_t* const p_physp,
360   IN const ib_port_info_t* const p_pi )
361 {
362   OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_process_ca_port );
363
364   UNUSED_PARAM( p_node );
365
366   osm_physp_set_port_info( p_physp, p_pi );
367
368   __osm_pi_rcv_process_endport(p_rcv, p_physp, p_pi);
369
370   OSM_LOG_EXIT( p_rcv->p_log );
371 }
372
373 /**********************************************************************
374  **********************************************************************/
375 static void
376 __osm_pi_rcv_process_router_port(
377   IN const osm_pi_rcv_t* const p_rcv,
378   IN osm_node_t* const p_node,
379   IN osm_physp_t* const p_physp,
380   IN const ib_port_info_t* const p_pi )
381 {
382   OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_process_router_port );
383
384   UNUSED_PARAM( p_node );
385
386   /*
387     Update the PortInfo attribute.
388   */
389   osm_physp_set_port_info( p_physp, p_pi );
390
391   OSM_LOG_EXIT( p_rcv->p_log );
392 }
393
394 /**********************************************************************
395  **********************************************************************/
396 void osm_pkey_get_tables(
397   IN osm_log_t         *p_log,
398   IN osm_req_t         *p_req,
399   IN osm_subn_t* const  p_subn,
400   IN osm_node_t* const  p_node,
401   IN osm_physp_t* const p_physp ) {
402
403   osm_madw_context_t context;
404   ib_api_status_t status;
405   osm_dr_path_t path;
406   uint8_t  port_num;
407   uint16_t block_num, max_blocks;
408   osm_switch_t* p_switch;
409
410   OSM_LOG_ENTER( p_log, osm_physp_has_pkey );
411
412   path = *osm_physp_get_dr_path_ptr( p_physp );
413
414   context.pkey_context.node_guid =
415     osm_node_get_node_guid( p_node );
416   context.pkey_context.port_guid =
417     osm_physp_get_port_guid( p_physp );
418   context.pkey_context.set_method = FALSE;
419
420   port_num = p_physp->port_num;
421
422   if (osm_node_get_type( p_node ) != IB_NODE_TYPE_SWITCH ||
423       port_num == 0 )
424   {
425     /* The maximum blocks is defined on the node info partition cap for CA, routers and
426        switch management ports. */
427     max_blocks = (cl_ntoh16(p_node->node_info.partition_cap)+IB_NUM_PKEY_ELEMENTS_IN_BLOCK -1)
428       / IB_NUM_PKEY_ELEMENTS_IN_BLOCK ;
429   }
430   else
431   {
432     /* This is a switch, and not a management port. The maximum blocks is defined
433        on the switch info partition enforcement cap. */
434     p_switch = osm_get_switch_by_guid(p_subn, p_node->node_info.node_guid);
435
436     if (! p_switch)
437     {
438       osm_log( p_log, OSM_LOG_ERROR,
439                "osm_physp_has_pkey: ERR 4A02: "
440                "Cannot find switch by guid: %" PRIx64 "\n",
441                cl_ntoh64(p_node->node_info.node_guid) );
442       goto Exit;
443     }
444     max_blocks = (cl_ntoh16(p_switch->switch_info.enforce_cap)+IB_NUM_PKEY_ELEMENTS_IN_BLOCK -1)
445       / IB_NUM_PKEY_ELEMENTS_IN_BLOCK ;
446   }
447
448   for (block_num = 0 ; block_num < max_blocks  ; block_num++)
449   {
450     status = osm_req_get( p_req,
451                           &path,
452                           IB_MAD_ATTR_P_KEY_TABLE,
453                           cl_hton32(block_num | (port_num << 16) ),
454                           CL_DISP_MSGID_NONE,
455                           &context );
456
457     if( status != IB_SUCCESS )
458     {
459       osm_log( p_log, OSM_LOG_ERROR,
460                "osm_physp_has_pkey: ERR 4A03: "
461                "Failure initiating PkeyTable request (%s).\n",
462                ib_get_err_str(status));
463       goto Exit;
464     }
465   }
466
467  Exit:
468   OSM_LOG_EXIT( p_log );
469 }
470
471 /**********************************************************************
472  **********************************************************************/
473 void
474 __osm_pi_rcv_get_pkey_slvl_vla_tables(
475   IN const osm_pi_rcv_t* const p_rcv,
476   IN osm_node_t* const p_node,
477   IN osm_physp_t* const p_physp )
478 {
479   OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_get_pkey_slvl_vla_tables );
480
481   osm_pkey_get_tables( p_rcv->p_log, p_rcv->p_req, p_rcv->p_subn,
482                        p_node, p_physp );
483
484   OSM_LOG_EXIT( p_rcv->p_log );
485 }
486
487 /**********************************************************************
488  **********************************************************************/
489 void
490 osm_pi_rcv_construct(
491   IN osm_pi_rcv_t* const p_rcv )
492 {
493   cl_memclr( p_rcv, sizeof(*p_rcv) );
494 }
495
496 /**********************************************************************
497  **********************************************************************/
498 void
499 osm_pi_rcv_destroy(
500   IN osm_pi_rcv_t* const p_rcv )
501 {
502   OSM_LOG_ENTER( p_rcv->p_log, osm_pi_rcv_destroy );
503
504   CL_ASSERT( p_rcv );
505   OSM_LOG_EXIT( p_rcv->p_log );
506 }
507
508 /**********************************************************************
509  **********************************************************************/
510 ib_api_status_t
511 osm_pi_rcv_init(
512   IN osm_pi_rcv_t* const p_rcv,
513   IN osm_req_t* const p_req,
514   IN osm_subn_t* const p_subn,
515   IN osm_log_t* const p_log,
516   IN osm_state_mgr_t* const p_state_mgr,
517   IN cl_plock_t* const p_lock )
518 {
519   ib_api_status_t status = IB_SUCCESS;
520   OSM_LOG_ENTER( p_log, osm_pi_rcv_init );
521
522   osm_pi_rcv_construct( p_rcv );
523
524   p_rcv->p_log = p_log;
525   p_rcv->p_subn = p_subn;
526   p_rcv->p_lock = p_lock;
527   p_rcv->p_req = p_req;
528   p_rcv->p_state_mgr = p_state_mgr;
529
530   OSM_LOG_EXIT( p_log );
531   return( status );
532 }
533
534 /**********************************************************************
535  **********************************************************************/
536 void
537 osm_pi_rcv_process_set(
538   IN const osm_pi_rcv_t* const p_rcv,
539   IN osm_port_t* const p_port,
540   IN const uint8_t port_num,
541   IN osm_madw_t* const p_madw )
542 {
543   osm_physp_t *p_physp;
544   osm_node_t *p_node;
545   ib_net64_t port_guid;
546   ib_smp_t *p_smp;
547   ib_port_info_t *p_pi;
548   osm_pi_context_t *p_context;
549
550   OSM_LOG_ENTER( p_rcv->p_log, osm_pi_rcv_process_set );
551
552   p_context = osm_madw_get_pi_context_ptr( p_madw );
553
554   p_physp = osm_port_get_phys_ptr( p_port, port_num );
555   CL_ASSERT( p_physp );
556   CL_ASSERT( osm_physp_is_valid( p_physp ) );
557
558   port_guid = osm_physp_get_port_guid( p_physp );
559   p_node = osm_port_get_parent_node( p_port );
560   CL_ASSERT( p_node );
561
562   p_smp = osm_madw_get_smp_ptr( p_madw );
563   p_pi = (ib_port_info_t*)ib_smp_get_payload_ptr( p_smp );
564
565   /* check for error */
566   if (!p_context->ignore_errors && (cl_ntoh16(p_smp->status) & 0x7fff))
567   {
568     osm_log( p_rcv->p_log, OSM_LOG_ERROR,
569              "osm_pi_rcv_process_set: ERR 0F10: "
570              "Received Error Status for SetResp()\n");
571     osm_dump_port_info(
572       p_rcv->p_log,
573       osm_node_get_node_guid( p_node ),
574       port_guid,
575       port_num,
576       p_pi,
577       OSM_LOG_ERROR);
578   }
579
580   if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
581   {
582     osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
583              "osm_pi_rcv_process_set: "
584              "Received logical SetResp() for GUID = 0x%" PRIx64
585              ", port num = %u"
586              "\n\t\t\t\tfor parent node GUID = 0x%" PRIx64
587              " TID = 0x%" PRIx64 ".\n",
588              cl_ntoh64( port_guid ),
589              port_num,
590              cl_ntoh64( osm_node_get_node_guid( p_node ) ),
591              cl_ntoh64( p_smp->trans_id ) );
592   }
593
594   osm_physp_set_port_info( p_physp, p_pi );
595
596   /* We got a PortInfoSetResp - set the got_set_resp flag to TRUE */
597   p_physp->got_set_resp = TRUE;
598
599   OSM_LOG_EXIT( p_rcv->p_log );
600 }
601
602 /**********************************************************************
603  **********************************************************************/
604 void
605 osm_pi_rcv_process(
606   IN const osm_pi_rcv_t* const p_rcv,
607   IN osm_madw_t* const p_madw )
608 {
609   cl_qmap_t *p_guid_tbl;
610   ib_port_info_t *p_pi;
611   ib_smp_t *p_smp;
612   osm_port_t *p_port;
613   osm_physp_t *p_physp;
614   osm_dr_path_t *p_dr_path;
615   osm_node_t *p_node;
616   osm_pi_context_t *p_context;
617   ib_net64_t port_guid;
618   ib_net64_t node_guid;
619   uint8_t port_num;
620
621   OSM_LOG_ENTER( p_rcv->p_log, osm_pi_rcv_process );
622
623   CL_ASSERT( p_rcv );
624   CL_ASSERT( p_madw );
625
626   p_smp = osm_madw_get_smp_ptr( p_madw );
627   p_context = osm_madw_get_pi_context_ptr( p_madw );
628   p_pi = (ib_port_info_t*)ib_smp_get_payload_ptr( p_smp );
629   port_num = (uint8_t)cl_ntoh32( p_smp->attr_mod );
630
631   port_guid = p_context->port_guid;
632   node_guid = p_context->node_guid;
633
634   CL_ASSERT( p_smp->attr_id == IB_MAD_ATTR_PORT_INFO );
635
636   osm_dump_port_info(
637     p_rcv->p_log, node_guid, port_guid, port_num, p_pi, OSM_LOG_DEBUG);
638
639   /* 
640      we might get a response during a light sweep looking for a change in 
641      the status of a remote port that did not respond in earlier sweeps.
642      So if the context of the Get was light_sweep - we do not need to 
643      do anything with the response - just flag that we need a heavy sweep
644   */
645   if (p_context->light_sweep == TRUE) 
646   {
647     osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
648              "osm_pi_rcv_process: "
649              "Got light sweep response from remote port of parent node GUID = 0x%" PRIx64
650              " port = %u, Commencing heavy sweep.\n",
651              cl_ntoh64( node_guid ),
652              cl_ntoh64( port_guid ) );
653     osm_state_mgr_process( p_rcv->p_state_mgr,
654                            OSM_SIGNAL_CHANGE_DETECTED );
655     goto Exit;
656   }
657   
658   p_guid_tbl = &p_rcv->p_subn->port_guid_tbl;
659   CL_PLOCK_EXCL_ACQUIRE( p_rcv->p_lock );
660   p_port = (osm_port_t*)cl_qmap_get( p_guid_tbl, port_guid );
661
662   if( p_port == (osm_port_t*)cl_qmap_end( p_guid_tbl) )
663   {
664     CL_PLOCK_RELEASE( p_rcv->p_lock );
665     osm_log( p_rcv->p_log, OSM_LOG_ERROR,
666              "osm_pi_rcv_process: ERR 0F06: "
667              "No Port object for port with GUID = 0x%" PRIx64
668              "\n\t\t\t\tfor parent node GUID = 0x%" PRIx64
669              ", TID = 0x%" PRIx64 ".\n",
670              cl_ntoh64( port_guid ),
671              cl_ntoh64( node_guid ),
672              cl_ntoh64( p_smp->trans_id ) );
673     goto Exit;
674   }
675
676   /*
677     If we were setting the PortInfo, then receiving
678     this attribute was not part of sweeping the subent.
679     In this case, just update the PortInfo attribute.
680
681     In an unfortunate blunder, the IB spec defines the
682     return method for Set() as a GetResp().  Thus, we can't
683     use the method (what would have been SetResp()) to determine
684     our course of action.  So, we have to carry this extra
685     boolean around to determine if we were doing Get() or Set().
686   */
687   if( p_context->set_method )
688   {
689     osm_pi_rcv_process_set( p_rcv, p_port, port_num, p_madw );
690   }
691   else
692   {
693     osm_port_discovery_count_inc( p_port );
694
695     /*
696       This PortInfo arrived because we did a Get() method,
697       most likely due to a subnet sweep in progress.
698     */
699     if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) )
700     {
701       osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
702                "osm_pi_rcv_process: "
703                "Discovered port num %u with GUID = 0x%" PRIx64
704                " for parent node GUID = 0x%" PRIx64
705                ", TID = 0x%" PRIx64 ".\n",
706                port_num,
707                cl_ntoh64( port_guid ),
708                cl_ntoh64( node_guid ),
709                cl_ntoh64( p_smp->trans_id ) );
710     }
711
712     p_node = osm_port_get_parent_node( p_port );
713     p_physp = osm_node_get_physp_ptr( p_node, port_num );
714
715     CL_ASSERT( p_node );
716     CL_ASSERT( p_physp );
717
718     /*
719       Determine if we encountered a new Physical Port.
720       If so, initialize the new Physical Port  then
721       continue processing as normal.
722     */
723     if( !osm_physp_is_valid( p_physp ) )
724     {
725       if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) )
726       {
727         osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
728                  "osm_pi_rcv_process: "
729                  "Initializing port number 0x%X.\n",
730                  port_num );
731       }
732
733       osm_physp_init( p_physp,
734                       port_guid,
735                       port_num,
736                       p_node,
737                       osm_madw_get_bind_handle( p_madw ),
738                       p_smp->hop_count,
739                       p_smp->initial_path );
740
741       osm_port_add_new_physp( p_port, port_num );
742     }
743     else
744     {
745       /*
746         Update the directed route path to this port
747         in case the old path is no longer usable.
748       */
749       p_dr_path = osm_physp_get_dr_path_ptr( p_physp );
750       osm_dr_path_init( p_dr_path,
751                         osm_madw_get_bind_handle( p_madw ),
752                         p_smp->hop_count, p_smp->initial_path );
753     }
754
755     osm_dump_port_info( p_rcv->p_log,
756                         node_guid, port_guid, port_num, p_pi,
757                         OSM_LOG_DEBUG );
758
759     /*
760       Check if the update_sm_base_lid in the context is on TRUE.
761       If it is - then update the master_sm_base_lid of the variable
762       in the subnet.
763     */
764     if (p_context->update_master_sm_base_lid == TRUE)
765     {
766       osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
767                "osm_pi_rcv_process: "
768                "update_master_sm is TRUE. "
769                "Updating master_sm_base_lid to:%u\n",
770                p_pi->master_sm_base_lid );
771
772       p_rcv->p_subn->master_sm_base_lid = p_pi->master_sm_base_lid;
773     }
774
775     switch( osm_node_get_type( p_node ) )
776     {
777     case IB_NODE_TYPE_CA:
778       __osm_pi_rcv_process_ca_port( p_rcv,
779                                     p_node, p_physp, p_pi );
780       break;
781     case IB_NODE_TYPE_ROUTER:
782       __osm_pi_rcv_process_router_port( p_rcv,
783                                         p_node, p_physp, p_pi );
784       break;
785     case IB_NODE_TYPE_SWITCH:
786       __osm_pi_rcv_process_switch_port( p_rcv,
787                                         p_node, p_physp, p_pi );
788       break;
789     default:
790       osm_log( p_rcv->p_log, OSM_LOG_ERROR,
791                "osm_pi_rcv_process: ERR 0F07: "
792                "Unknown node type %u with GUID = 0x%" PRIx64 ".\n",
793                osm_node_get_type( p_node ),
794                cl_ntoh64( node_guid ) );
795       break;
796     }
797
798     /*
799       Get the tables on the physp.
800     */
801     __osm_pi_rcv_get_pkey_slvl_vla_tables( p_rcv, p_node, p_physp );
802
803   }
804
805   CL_PLOCK_RELEASE( p_rcv->p_lock );
806
807  Exit:
808   /*
809     Release the lock before jumping here!!
810   */
811   OSM_LOG_EXIT( p_rcv->p_log );
812 }