OpenSM: Don't obtain PKeyTables on switch when partition enforcement
[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 defined 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 management 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   uint32_t attr_mod_ho;
409   osm_switch_t* p_switch;
410
411   OSM_LOG_ENTER( p_log, osm_physp_has_pkey );
412
413   path = *osm_physp_get_dr_path_ptr( p_physp );
414
415   context.pkey_context.node_guid =
416     osm_node_get_node_guid( p_node );
417   context.pkey_context.port_guid =
418     osm_physp_get_port_guid( p_physp );
419   context.pkey_context.set_method = FALSE;
420
421   port_num = p_physp->port_num;
422
423   if (osm_node_get_type( p_node ) != IB_NODE_TYPE_SWITCH ||
424       port_num == 0 )
425   {
426     /* The maximum blocks is defined on the node info partition cap for CA, routers and
427        switch management ports. */
428     max_blocks = (cl_ntoh16(p_node->node_info.partition_cap)+IB_NUM_PKEY_ELEMENTS_IN_BLOCK -1)
429       / IB_NUM_PKEY_ELEMENTS_IN_BLOCK ;
430   }
431   else
432   {
433     /* This is a switch, and not a management port. The maximum blocks is defined
434        in the switch info partition enforcement cap. */
435     p_switch = osm_get_switch_by_guid(p_subn, p_node->node_info.node_guid);
436
437     if (! p_switch)
438     {
439       osm_log( p_log, OSM_LOG_ERROR,
440                "osm_physp_has_pkey: ERR 4A02: "
441                "Cannot find switch by guid: %" PRIx64 "\n",
442                cl_ntoh64(p_node->node_info.node_guid) );
443       goto Exit;
444     }
445
446     /* bail out if this is a switch with no partition enforcement capability */
447     if (cl_ntoh16(p_switch->switch_info.enforce_cap) == 0)
448       goto Exit;
449
450     max_blocks = (cl_ntoh16(p_switch->switch_info.enforce_cap)+IB_NUM_PKEY_ELEMENTS_IN_BLOCK -1)
451       / IB_NUM_PKEY_ELEMENTS_IN_BLOCK ;
452   }
453
454   for (block_num = 0 ; block_num < max_blocks  ; block_num++)
455   {
456     if (osm_node_get_type( p_node ) != IB_NODE_TYPE_SWITCH)
457       attr_mod_ho = block_num;
458     else
459       attr_mod_ho = block_num | (port_num << 16);
460     status = osm_req_get( p_req,
461                           &path,
462                           IB_MAD_ATTR_P_KEY_TABLE,
463                           cl_hton32(attr_mod_ho),
464                           CL_DISP_MSGID_NONE,
465                           &context );
466
467     if( status != IB_SUCCESS )
468     {
469       osm_log( p_log, OSM_LOG_ERROR,
470                "osm_physp_has_pkey: ERR 4A03: "
471                "Failure initiating PkeyTable request (%s).\n",
472                ib_get_err_str(status));
473       goto Exit;
474     }
475   }
476
477  Exit:
478   OSM_LOG_EXIT( p_log );
479 }
480
481 /**********************************************************************
482  **********************************************************************/
483 void
484 __osm_pi_rcv_get_pkey_slvl_vla_tables(
485   IN const osm_pi_rcv_t* const p_rcv,
486   IN osm_node_t* const p_node,
487   IN osm_physp_t* const p_physp )
488 {
489   OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_get_pkey_slvl_vla_tables );
490
491   osm_pkey_get_tables( p_rcv->p_log, p_rcv->p_req, p_rcv->p_subn,
492                        p_node, p_physp );
493
494   OSM_LOG_EXIT( p_rcv->p_log );
495 }
496
497 /**********************************************************************
498  **********************************************************************/
499 void
500 osm_pi_rcv_construct(
501   IN osm_pi_rcv_t* const p_rcv )
502 {
503   cl_memclr( p_rcv, sizeof(*p_rcv) );
504 }
505
506 /**********************************************************************
507  **********************************************************************/
508 void
509 osm_pi_rcv_destroy(
510   IN osm_pi_rcv_t* const p_rcv )
511 {
512   OSM_LOG_ENTER( p_rcv->p_log, osm_pi_rcv_destroy );
513
514   CL_ASSERT( p_rcv );
515   OSM_LOG_EXIT( p_rcv->p_log );
516 }
517
518 /**********************************************************************
519  **********************************************************************/
520 ib_api_status_t
521 osm_pi_rcv_init(
522   IN osm_pi_rcv_t* const p_rcv,
523   IN osm_req_t* const p_req,
524   IN osm_subn_t* const p_subn,
525   IN osm_log_t* const p_log,
526   IN osm_state_mgr_t* const p_state_mgr,
527   IN cl_plock_t* const p_lock )
528 {
529   ib_api_status_t status = IB_SUCCESS;
530   OSM_LOG_ENTER( p_log, osm_pi_rcv_init );
531
532   osm_pi_rcv_construct( p_rcv );
533
534   p_rcv->p_log = p_log;
535   p_rcv->p_subn = p_subn;
536   p_rcv->p_lock = p_lock;
537   p_rcv->p_req = p_req;
538   p_rcv->p_state_mgr = p_state_mgr;
539
540   OSM_LOG_EXIT( p_log );
541   return( status );
542 }
543
544 /**********************************************************************
545  **********************************************************************/
546 void
547 osm_pi_rcv_process_set(
548   IN const osm_pi_rcv_t* const p_rcv,
549   IN osm_port_t* const p_port,
550   IN const uint8_t port_num,
551   IN osm_madw_t* const p_madw )
552 {
553   osm_physp_t *p_physp;
554   osm_node_t *p_node;
555   ib_net64_t port_guid;
556   ib_smp_t *p_smp;
557   ib_port_info_t *p_pi;
558   osm_pi_context_t *p_context;
559
560   OSM_LOG_ENTER( p_rcv->p_log, osm_pi_rcv_process_set );
561
562   p_context = osm_madw_get_pi_context_ptr( p_madw );
563
564   p_physp = osm_port_get_phys_ptr( p_port, port_num );
565   CL_ASSERT( p_physp );
566   CL_ASSERT( osm_physp_is_valid( p_physp ) );
567
568   port_guid = osm_physp_get_port_guid( p_physp );
569   p_node = osm_port_get_parent_node( p_port );
570   CL_ASSERT( p_node );
571
572   p_smp = osm_madw_get_smp_ptr( p_madw );
573   p_pi = (ib_port_info_t*)ib_smp_get_payload_ptr( p_smp );
574
575   /* check for error */
576   if (!p_context->ignore_errors && (cl_ntoh16(p_smp->status) & 0x7fff))
577   {
578     osm_log( p_rcv->p_log, OSM_LOG_ERROR,
579              "osm_pi_rcv_process_set: ERR 0F10: "
580              "Received Error Status for SetResp()\n");
581     osm_dump_port_info(
582       p_rcv->p_log,
583       osm_node_get_node_guid( p_node ),
584       port_guid,
585       port_num,
586       p_pi,
587       OSM_LOG_ERROR);
588   }
589
590   if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
591   {
592     osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
593              "osm_pi_rcv_process_set: "
594              "Received logical SetResp() for GUID = 0x%" PRIx64
595              ", port num = %u"
596              "\n\t\t\t\tfor parent node GUID = 0x%" PRIx64
597              " TID = 0x%" PRIx64 ".\n",
598              cl_ntoh64( port_guid ),
599              port_num,
600              cl_ntoh64( osm_node_get_node_guid( p_node ) ),
601              cl_ntoh64( p_smp->trans_id ) );
602   }
603
604   osm_physp_set_port_info( p_physp, p_pi );
605
606   /* We got a PortInfoSetResp - set the got_set_resp flag to TRUE */
607   p_physp->got_set_resp = TRUE;
608
609   OSM_LOG_EXIT( p_rcv->p_log );
610 }
611
612 /**********************************************************************
613  **********************************************************************/
614 void
615 osm_pi_rcv_process(
616   IN const osm_pi_rcv_t* const p_rcv,
617   IN osm_madw_t* const p_madw )
618 {
619   cl_qmap_t *p_guid_tbl;
620   ib_port_info_t *p_pi;
621   ib_smp_t *p_smp;
622   osm_port_t *p_port;
623   osm_physp_t *p_physp;
624   osm_dr_path_t *p_dr_path;
625   osm_node_t *p_node;
626   osm_pi_context_t *p_context;
627   ib_net64_t port_guid;
628   ib_net64_t node_guid;
629   uint8_t port_num;
630
631   OSM_LOG_ENTER( p_rcv->p_log, osm_pi_rcv_process );
632
633   CL_ASSERT( p_rcv );
634   CL_ASSERT( p_madw );
635
636   p_smp = osm_madw_get_smp_ptr( p_madw );
637   p_context = osm_madw_get_pi_context_ptr( p_madw );
638   p_pi = (ib_port_info_t*)ib_smp_get_payload_ptr( p_smp );
639   port_num = (uint8_t)cl_ntoh32( p_smp->attr_mod );
640
641   port_guid = p_context->port_guid;
642   node_guid = p_context->node_guid;
643
644   CL_ASSERT( p_smp->attr_id == IB_MAD_ATTR_PORT_INFO );
645
646   osm_dump_port_info(
647     p_rcv->p_log, node_guid, port_guid, port_num, p_pi, OSM_LOG_DEBUG);
648
649   /* 
650      we might get a response during a light sweep looking for a change in 
651      the status of a remote port that did not respond in earlier sweeps.
652      So if the context of the Get was light_sweep - we do not need to 
653      do anything with the response - just flag that we need a heavy sweep
654   */
655   if (p_context->light_sweep == TRUE) 
656   {
657     osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
658              "osm_pi_rcv_process: "
659              "Got light sweep response from remote port of parent node GUID = 0x%" PRIx64
660              " port = %u, Commencing heavy sweep.\n",
661              cl_ntoh64( node_guid ),
662              cl_ntoh64( port_guid ) );
663     osm_state_mgr_process( p_rcv->p_state_mgr,
664                            OSM_SIGNAL_CHANGE_DETECTED );
665     goto Exit;
666   }
667   
668   p_guid_tbl = &p_rcv->p_subn->port_guid_tbl;
669   CL_PLOCK_EXCL_ACQUIRE( p_rcv->p_lock );
670   p_port = (osm_port_t*)cl_qmap_get( p_guid_tbl, port_guid );
671
672   if( p_port == (osm_port_t*)cl_qmap_end( p_guid_tbl) )
673   {
674     CL_PLOCK_RELEASE( p_rcv->p_lock );
675     osm_log( p_rcv->p_log, OSM_LOG_ERROR,
676              "osm_pi_rcv_process: ERR 0F06: "
677              "No Port object for port with GUID = 0x%" PRIx64
678              "\n\t\t\t\tfor parent node GUID = 0x%" PRIx64
679              ", TID = 0x%" PRIx64 ".\n",
680              cl_ntoh64( port_guid ),
681              cl_ntoh64( node_guid ),
682              cl_ntoh64( p_smp->trans_id ) );
683     goto Exit;
684   }
685
686   /*
687     If we were setting the PortInfo, then receiving
688     this attribute was not part of sweeping the subent.
689     In this case, just update the PortInfo attribute.
690
691     In an unfortunate blunder, the IB spec defines the
692     return method for Set() as a GetResp().  Thus, we can't
693     use the method (what would have been SetResp()) to determine
694     our course of action.  So, we have to carry this extra
695     boolean around to determine if we were doing Get() or Set().
696   */
697   if( p_context->set_method )
698   {
699     osm_pi_rcv_process_set( p_rcv, p_port, port_num, p_madw );
700   }
701   else
702   {
703     osm_port_discovery_count_inc( p_port );
704
705     /*
706       This PortInfo arrived because we did a Get() method,
707       most likely due to a subnet sweep in progress.
708     */
709     if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) )
710     {
711       osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
712                "osm_pi_rcv_process: "
713                "Discovered port num %u with GUID = 0x%" PRIx64
714                " for parent node GUID = 0x%" PRIx64
715                ", TID = 0x%" PRIx64 ".\n",
716                port_num,
717                cl_ntoh64( port_guid ),
718                cl_ntoh64( node_guid ),
719                cl_ntoh64( p_smp->trans_id ) );
720     }
721
722     p_node = osm_port_get_parent_node( p_port );
723     p_physp = osm_node_get_physp_ptr( p_node, port_num );
724
725     CL_ASSERT( p_node );
726     CL_ASSERT( p_physp );
727
728     /*
729       Determine if we encountered a new Physical Port.
730       If so, initialize the new Physical Port  then
731       continue processing as normal.
732     */
733     if( !osm_physp_is_valid( p_physp ) )
734     {
735       if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) )
736       {
737         osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
738                  "osm_pi_rcv_process: "
739                  "Initializing port number 0x%X.\n",
740                  port_num );
741       }
742
743       osm_physp_init( p_physp,
744                       port_guid,
745                       port_num,
746                       p_node,
747                       osm_madw_get_bind_handle( p_madw ),
748                       p_smp->hop_count,
749                       p_smp->initial_path );
750
751       osm_port_add_new_physp( p_port, port_num );
752     }
753     else
754     {
755       /*
756         Update the directed route path to this port
757         in case the old path is no longer usable.
758       */
759       p_dr_path = osm_physp_get_dr_path_ptr( p_physp );
760       osm_dr_path_init( p_dr_path,
761                         osm_madw_get_bind_handle( p_madw ),
762                         p_smp->hop_count, p_smp->initial_path );
763     }
764
765     osm_dump_port_info( p_rcv->p_log,
766                         node_guid, port_guid, port_num, p_pi,
767                         OSM_LOG_DEBUG );
768
769     /*
770       Check if the update_sm_base_lid in the context is on TRUE.
771       If it is - then update the master_sm_base_lid of the variable
772       in the subnet.
773     */
774     if (p_context->update_master_sm_base_lid == TRUE)
775     {
776       osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
777                "osm_pi_rcv_process: "
778                "update_master_sm is TRUE. "
779                "Updating master_sm_base_lid to:%u\n",
780                p_pi->master_sm_base_lid );
781
782       p_rcv->p_subn->master_sm_base_lid = p_pi->master_sm_base_lid;
783     }
784
785     switch( osm_node_get_type( p_node ) )
786     {
787     case IB_NODE_TYPE_CA:
788       __osm_pi_rcv_process_ca_port( p_rcv,
789                                     p_node, p_physp, p_pi );
790       break;
791     case IB_NODE_TYPE_ROUTER:
792       __osm_pi_rcv_process_router_port( p_rcv,
793                                         p_node, p_physp, p_pi );
794       break;
795     case IB_NODE_TYPE_SWITCH:
796       __osm_pi_rcv_process_switch_port( p_rcv,
797                                         p_node, p_physp, p_pi );
798       break;
799     default:
800       osm_log( p_rcv->p_log, OSM_LOG_ERROR,
801                "osm_pi_rcv_process: ERR 0F07: "
802                "Unknown node type %u with GUID = 0x%" PRIx64 ".\n",
803                osm_node_get_type( p_node ),
804                cl_ntoh64( node_guid ) );
805       break;
806     }
807
808     /*
809       Get the tables on the physp.
810     */
811     __osm_pi_rcv_get_pkey_slvl_vla_tables( p_rcv, p_node, p_physp );
812
813   }
814
815   CL_PLOCK_RELEASE( p_rcv->p_lock );
816
817  Exit:
818   /*
819     Release the lock before jumping here!!
820   */
821   OSM_LOG_EXIT( p_rcv->p_log );
822 }