[OpenSM] - cosmetic changes
[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   ib_net16_t orig_lid;
236   uint8_t port_num;
237   uint8_t remote_port_num;
238   osm_dr_path_t path;
239
240   OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_process_switch_port );
241
242   /*
243     Check the state of the physical port.
244     If there appears to be something on the other end of the wire,
245     then ask for NodeInfo.  Ignore the switch management port.
246   */
247   port_num = osm_physp_get_port_num( p_physp );
248   /* if in_sweep_hop_0 is TRUE, then this means the SM in on the switch,
249      and we got switchInfo of our local switch. Do not continue
250      probing through the switch. */
251   if( port_num != 0 && p_rcv->p_subn->in_sweep_hop_0 == FALSE)
252   {
253     switch( ib_port_info_get_port_state( p_pi ) )
254     {
255     case IB_LINK_DOWN:
256       p_remote_physp = osm_physp_get_remote( p_physp );
257       if( p_remote_physp && osm_physp_is_valid( p_remote_physp ) )
258       {
259         p_remote_node = osm_physp_get_node_ptr( p_remote_physp );
260         remote_port_num = osm_physp_get_port_num( p_remote_physp );
261
262         osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
263                  "__osm_pi_rcv_process_switch_port: "
264                  "Unlinking local node 0x%" PRIx64 ", port 0x%X"
265                  "\n\t\t\t\tand remote node 0x%" PRIx64
266                  ", port 0x%X\n",
267                  cl_ntoh64( osm_node_get_node_guid( p_node ) ),
268                  port_num,
269                  cl_ntoh64( osm_node_get_node_guid( p_remote_node ) ),
270                  remote_port_num );
271
272         osm_node_unlink( p_node, (uint8_t)port_num,
273                          p_remote_node, (uint8_t)remote_port_num );
274
275       }
276       break;
277
278     case IB_LINK_INIT:
279     case IB_LINK_ARMED:
280     case IB_LINK_ACTIVE:
281       /*
282         To avoid looping forever, only probe the port if it
283         is NOT the port that responded to the SMP.
284
285         Request node info from the other end of this link:
286         1) Copy the current path from the parent node.
287         2) Extend the path to the next hop thru this port.
288         3) Request node info with the new path
289         
290       */
291       if( p_pi->local_port_num != osm_physp_get_port_num( p_physp ) )
292       {
293         path = *osm_physp_get_dr_path_ptr( p_physp );
294
295         osm_dr_path_extend( &path,
296                             osm_physp_get_port_num( p_physp ) );
297
298         context.ni_context.node_guid =
299           osm_node_get_node_guid( p_node );
300         context.ni_context.port_num =
301           osm_physp_get_port_num( p_physp );
302
303         status = osm_req_get( p_rcv->p_req,
304                               &path,
305                               IB_MAD_ATTR_NODE_INFO,
306                               0,
307                               CL_DISP_MSGID_NONE,
308                               &context );
309
310         if( status != IB_SUCCESS )
311         {
312           osm_log( p_rcv->p_log, OSM_LOG_ERROR,
313                    "__osm_pi_rcv_process_switch_port: ERR 0F02: "
314                    "Failure initiating NodeInfo request (%s)\n",
315                    ib_get_err_str(status) );
316         }
317       }
318       else
319       {
320         if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
321         {
322           osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
323                    "__osm_pi_rcv_process_switch_port: "
324                    "Skipping SMP responder port 0x%X\n",
325                    p_pi->local_port_num );
326         }
327       }
328       break;
329
330     default:
331       osm_log( p_rcv->p_log, OSM_LOG_ERROR,
332                "__osm_pi_rcv_process_switch_port: ERR 0F03: "
333                "Unknown link state = %u, port = 0x%X\n",
334                ib_port_info_get_port_state( p_pi ),
335                p_pi->local_port_num );
336       break;
337     }
338   }
339
340   /*
341     Update the PortInfo attribute.
342   */
343   osm_physp_set_port_info( p_physp, p_pi );
344
345   if (port_num == 0)
346   {
347         /* This is switch management port 0 */
348         if ( ( orig_lid = osm_physp_trim_base_lid_to_valid_range( p_physp ) ) )
349                 osm_log( p_rcv->p_log, OSM_LOG_ERROR,
350                          "__osm_pi_rcv_process_switch_port: ERR 0F04: "
351                          "Invalid base LID 0x%x corrected\n",
352                          cl_ntoh16( orig_lid ) );
353         __osm_pi_rcv_process_endport(p_rcv, p_physp, p_pi);
354   }
355
356   OSM_LOG_EXIT( p_rcv->p_log );
357 }
358
359 /**********************************************************************
360  **********************************************************************/
361 static void
362 __osm_pi_rcv_process_ca_port(
363   IN const osm_pi_rcv_t* const p_rcv,
364   IN osm_node_t* const p_node,
365   IN osm_physp_t* const p_physp,
366   IN const ib_port_info_t* const p_pi )
367 {
368   ib_net16_t orig_lid;
369
370   OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_process_ca_port );
371
372   UNUSED_PARAM( p_node );
373
374   osm_physp_set_port_info( p_physp, p_pi );
375   if ( (orig_lid = osm_physp_trim_base_lid_to_valid_range( p_physp ) ) )
376     osm_log( p_rcv->p_log, OSM_LOG_ERROR,
377              "__osm_pi_rcv_process_ca_port: ERR 0F08: "
378              "Invalid base LID 0x%x corrected\n",
379              cl_ntoh16 ( orig_lid ) );
380
381   __osm_pi_rcv_process_endport(p_rcv, p_physp, p_pi);
382
383   OSM_LOG_EXIT( p_rcv->p_log );
384 }
385
386 /**********************************************************************
387  **********************************************************************/
388 static void
389 __osm_pi_rcv_process_router_port(
390   IN const osm_pi_rcv_t* const p_rcv,
391   IN osm_node_t* const p_node,
392   IN osm_physp_t* const p_physp,
393   IN const ib_port_info_t* const p_pi )
394 {
395   ib_net16_t orig_lid;
396
397   OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_process_router_port );
398
399   UNUSED_PARAM( p_node );
400
401   /*
402     Update the PortInfo attribute.
403   */
404   osm_physp_set_port_info( p_physp, p_pi );
405   if ( (orig_lid = osm_physp_trim_base_lid_to_valid_range( p_physp ) ) )
406     osm_log( p_rcv->p_log, OSM_LOG_ERROR,
407              "__osm_pi_rcv_process_router_port: ERR 0F09: "
408              "Invalid base LID 0x%x corrected\n",
409              cl_ntoh16 ( orig_lid) );
410
411   __osm_pi_rcv_process_endport(p_rcv, p_physp, p_pi);
412
413   OSM_LOG_EXIT( p_rcv->p_log );
414 }
415
416 #define IBM_VENDOR_ID  (0x5076)
417 /**********************************************************************
418  **********************************************************************/
419 void osm_pkey_get_tables(
420   IN osm_log_t         *p_log,
421   IN osm_req_t         *p_req,
422   IN osm_subn_t* const  p_subn,
423   IN osm_node_t* const  p_node,
424   IN osm_physp_t* const p_physp ) {
425
426   osm_madw_context_t context;
427   ib_api_status_t status;
428   osm_dr_path_t path;
429   uint8_t  port_num;
430   uint16_t block_num, max_blocks;
431   uint32_t attr_mod_ho;
432   osm_switch_t* p_switch;
433
434   OSM_LOG_ENTER( p_log, osm_physp_has_pkey );
435
436   path = *osm_physp_get_dr_path_ptr( p_physp );
437
438   context.pkey_context.node_guid =
439     osm_node_get_node_guid( p_node );
440   context.pkey_context.port_guid =
441     osm_physp_get_port_guid( p_physp );
442   context.pkey_context.set_method = FALSE;
443
444   port_num = p_physp->port_num;
445
446   if (osm_node_get_type( p_node ) != IB_NODE_TYPE_SWITCH ||
447       port_num == 0 )
448   {
449     /* The maximum blocks is defined by the node info partition cap for CA, routers and
450        switch management ports. */
451     max_blocks = (cl_ntoh16(p_node->node_info.partition_cap)+IB_NUM_PKEY_ELEMENTS_IN_BLOCK -1)
452       / IB_NUM_PKEY_ELEMENTS_IN_BLOCK ;
453   }
454   else
455   {
456     /* This is a switch, and not a management port. The maximum blocks is defined
457        in the switch info partition enforcement cap. */
458     p_switch = osm_get_switch_by_guid(p_subn, p_node->node_info.node_guid);
459
460     if (! p_switch)
461     {
462       osm_log( p_log, OSM_LOG_ERROR,
463                "osm_physp_has_pkey: ERR 0F11: "
464                "Cannot find switch by guid: %" PRIx64 "\n",
465                cl_ntoh64(p_node->node_info.node_guid) );
466       goto Exit;
467     }
468
469     /* Check for IBM eHCA firmware defect in reporting partition enforcement cap */
470     if (cl_ntoh32(ib_node_info_get_vendor_id(&p_node->node_info)) == IBM_VENDOR_ID)
471       p_switch->switch_info.enforce_cap = 0;
472
473     /* Bail out if this is a switch with no partition enforcement capability */
474     if (cl_ntoh16(p_switch->switch_info.enforce_cap) == 0)
475       goto Exit;
476
477     max_blocks = (cl_ntoh16(p_switch->switch_info.enforce_cap)+IB_NUM_PKEY_ELEMENTS_IN_BLOCK -1)
478       / IB_NUM_PKEY_ELEMENTS_IN_BLOCK ;
479   }
480
481   for (block_num = 0 ; block_num < max_blocks  ; block_num++)
482   {
483     if (osm_node_get_type( p_node ) != IB_NODE_TYPE_SWITCH)
484       attr_mod_ho = block_num;
485     else
486       attr_mod_ho = block_num | (port_num << 16);
487     status = osm_req_get( p_req,
488                           &path,
489                           IB_MAD_ATTR_P_KEY_TABLE,
490                           cl_hton32(attr_mod_ho),
491                           CL_DISP_MSGID_NONE,
492                           &context );
493
494     if( status != IB_SUCCESS )
495     {
496       osm_log( p_log, OSM_LOG_ERROR,
497                "osm_physp_has_pkey: ERR 0F12: "
498                "Failure initiating PKeyTable request (%s)\n",
499                ib_get_err_str(status));
500       goto Exit;
501     }
502   }
503
504  Exit:
505   OSM_LOG_EXIT( p_log );
506 }
507
508 /**********************************************************************
509  **********************************************************************/
510 void
511 __osm_pi_rcv_get_pkey_slvl_vla_tables(
512   IN const osm_pi_rcv_t* const p_rcv,
513   IN osm_node_t* const p_node,
514   IN osm_physp_t* const p_physp )
515 {
516   OSM_LOG_ENTER( p_rcv->p_log, __osm_pi_rcv_get_pkey_slvl_vla_tables );
517
518   osm_pkey_get_tables( p_rcv->p_log, p_rcv->p_req, p_rcv->p_subn,
519                        p_node, p_physp );
520
521   OSM_LOG_EXIT( p_rcv->p_log );
522 }
523
524 /**********************************************************************
525  **********************************************************************/
526 void
527 osm_pi_rcv_construct(
528   IN osm_pi_rcv_t* const p_rcv )
529 {
530   cl_memclr( p_rcv, sizeof(*p_rcv) );
531 }
532
533 /**********************************************************************
534  **********************************************************************/
535 void
536 osm_pi_rcv_destroy(
537   IN osm_pi_rcv_t* const p_rcv )
538 {
539   OSM_LOG_ENTER( p_rcv->p_log, osm_pi_rcv_destroy );
540
541   CL_ASSERT( p_rcv );
542   OSM_LOG_EXIT( p_rcv->p_log );
543 }
544
545 /**********************************************************************
546  **********************************************************************/
547 ib_api_status_t
548 osm_pi_rcv_init(
549   IN osm_pi_rcv_t* const p_rcv,
550   IN osm_req_t* const p_req,
551   IN osm_subn_t* const p_subn,
552   IN osm_log_t* const p_log,
553   IN osm_state_mgr_t* const p_state_mgr,
554   IN cl_plock_t* const p_lock )
555 {
556   ib_api_status_t status = IB_SUCCESS;
557   OSM_LOG_ENTER( p_log, osm_pi_rcv_init );
558
559   osm_pi_rcv_construct( p_rcv );
560
561   p_rcv->p_log = p_log;
562   p_rcv->p_subn = p_subn;
563   p_rcv->p_lock = p_lock;
564   p_rcv->p_req = p_req;
565   p_rcv->p_state_mgr = p_state_mgr;
566
567   OSM_LOG_EXIT( p_log );
568   return( status );
569 }
570
571 /**********************************************************************
572  **********************************************************************/
573 void
574 osm_pi_rcv_process_set(
575   IN const osm_pi_rcv_t* const p_rcv,
576   IN osm_port_t* const p_port,
577   IN const uint8_t port_num,
578   IN osm_madw_t* const p_madw )
579 {
580   osm_physp_t *p_physp;
581   osm_node_t *p_node;
582   ib_net64_t port_guid;
583   ib_smp_t *p_smp;
584   ib_port_info_t *p_pi;
585   osm_pi_context_t *p_context;
586
587   OSM_LOG_ENTER( p_rcv->p_log, osm_pi_rcv_process_set );
588
589   p_context = osm_madw_get_pi_context_ptr( p_madw );
590
591   p_physp = osm_port_get_phys_ptr( p_port, port_num );
592   CL_ASSERT( p_physp );
593   CL_ASSERT( osm_physp_is_valid( p_physp ) );
594
595   port_guid = osm_physp_get_port_guid( p_physp );
596   p_node = osm_port_get_parent_node( p_port );
597   CL_ASSERT( p_node );
598
599   p_smp = osm_madw_get_smp_ptr( p_madw );
600   p_pi = (ib_port_info_t*)ib_smp_get_payload_ptr( p_smp );
601
602   /* check for error */
603   if (!p_context->ignore_errors && (cl_ntoh16(p_smp->status) & 0x7fff))
604   {
605     osm_log( p_rcv->p_log, OSM_LOG_ERROR,
606              "osm_pi_rcv_process_set: ERR 0F10: "
607              "Received error status for SetResp()\n");
608     osm_dump_port_info(
609       p_rcv->p_log,
610       osm_node_get_node_guid( p_node ),
611       port_guid,
612       port_num,
613       p_pi,
614       OSM_LOG_ERROR);
615   }
616
617   if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
618   {
619     osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
620              "osm_pi_rcv_process_set: "
621              "Received logical SetResp() for GUID = 0x%" PRIx64
622              ", port num = %u"
623              "\n\t\t\t\tfor parent node GUID = 0x%" PRIx64
624              " TID = 0x%" PRIx64 "\n",
625              cl_ntoh64( port_guid ),
626              port_num,
627              cl_ntoh64( osm_node_get_node_guid( p_node ) ),
628              cl_ntoh64( p_smp->trans_id ) );
629   }
630
631   osm_physp_set_port_info( p_physp, p_pi );
632
633   /* We got a PortInfoSetResp - set the got_set_resp flag to TRUE */
634   p_physp->got_set_resp = TRUE;
635
636   OSM_LOG_EXIT( p_rcv->p_log );
637 }
638
639 /**********************************************************************
640  **********************************************************************/
641 void
642 osm_pi_rcv_process(
643   IN const osm_pi_rcv_t* const p_rcv,
644   IN osm_madw_t* const p_madw )
645 {
646   cl_qmap_t *p_guid_tbl;
647   ib_port_info_t *p_pi;
648   ib_smp_t *p_smp;
649   osm_port_t *p_port;
650   osm_physp_t *p_physp;
651   osm_dr_path_t *p_dr_path;
652   osm_node_t *p_node;
653   osm_pi_context_t *p_context;
654   ib_net64_t port_guid;
655   ib_net64_t node_guid;
656   uint8_t port_num;
657
658   OSM_LOG_ENTER( p_rcv->p_log, osm_pi_rcv_process );
659
660   CL_ASSERT( p_rcv );
661   CL_ASSERT( p_madw );
662
663   p_smp = osm_madw_get_smp_ptr( p_madw );
664   p_context = osm_madw_get_pi_context_ptr( p_madw );
665   p_pi = (ib_port_info_t*)ib_smp_get_payload_ptr( p_smp );
666   port_num = (uint8_t)cl_ntoh32( p_smp->attr_mod );
667
668   port_guid = p_context->port_guid;
669   node_guid = p_context->node_guid;
670
671   CL_ASSERT( p_smp->attr_id == IB_MAD_ATTR_PORT_INFO );
672
673   osm_dump_port_info(
674     p_rcv->p_log, node_guid, port_guid, port_num, p_pi, OSM_LOG_DEBUG);
675
676   /* 
677      we might get a response during a light sweep looking for a change in 
678      the status of a remote port that did not respond in earlier sweeps.
679      So if the context of the Get was light_sweep - we do not need to 
680      do anything with the response - just flag that we need a heavy sweep
681   */
682   if (p_context->light_sweep == TRUE) 
683   {
684     osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
685              "osm_pi_rcv_process: "
686              "Got light sweep response from remote port of parent node GUID = 0x%" PRIx64
687              " port = %u, Commencing heavy sweep\n",
688              cl_ntoh64( node_guid ),
689              cl_ntoh64( port_guid ) );
690     osm_state_mgr_process( p_rcv->p_state_mgr,
691                            OSM_SIGNAL_CHANGE_DETECTED );
692     goto Exit;
693   }
694   
695   p_guid_tbl = &p_rcv->p_subn->port_guid_tbl;
696   CL_PLOCK_EXCL_ACQUIRE( p_rcv->p_lock );
697   p_port = (osm_port_t*)cl_qmap_get( p_guid_tbl, port_guid );
698
699   if( p_port == (osm_port_t*)cl_qmap_end( p_guid_tbl) )
700   {
701     CL_PLOCK_RELEASE( p_rcv->p_lock );
702     osm_log( p_rcv->p_log, OSM_LOG_ERROR,
703              "osm_pi_rcv_process: ERR 0F06: "
704              "No Port object for port with GUID = 0x%" PRIx64
705              "\n\t\t\t\tfor parent node GUID = 0x%" PRIx64
706              ", TID = 0x%" PRIx64 "\n",
707              cl_ntoh64( port_guid ),
708              cl_ntoh64( node_guid ),
709              cl_ntoh64( p_smp->trans_id ) );
710     goto Exit;
711   }
712
713   /*
714     If we were setting the PortInfo, then receiving
715     this attribute was not part of sweeping the subnet.
716     In this case, just update the PortInfo attribute.
717
718     In an unfortunate blunder, the IB spec defines the
719     return method for Set() as a GetResp().  Thus, we can't
720     use the method (what would have been SetResp()) to determine
721     our course of action.  So, we have to carry this extra
722     boolean around to determine if we were doing Get() or Set().
723   */
724   if( p_context->set_method )
725   {
726     osm_pi_rcv_process_set( p_rcv, p_port, port_num, p_madw );
727   }
728   else
729   {
730     osm_port_discovery_count_inc( p_port );
731
732     /*
733       This PortInfo arrived because we did a Get() method,
734       most likely due to a subnet sweep in progress.
735     */
736     if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) )
737     {
738       osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
739                "osm_pi_rcv_process: "
740                "Discovered port num %u with GUID = 0x%" PRIx64
741                " for parent node GUID = 0x%" PRIx64
742                ", TID = 0x%" PRIx64 "\n",
743                port_num,
744                cl_ntoh64( port_guid ),
745                cl_ntoh64( node_guid ),
746                cl_ntoh64( p_smp->trans_id ) );
747     }
748
749     p_node = osm_port_get_parent_node( p_port );
750     p_physp = osm_node_get_physp_ptr( p_node, port_num );
751
752     CL_ASSERT( p_node );
753     CL_ASSERT( p_physp );
754
755     /*
756       Determine if we encountered a new Physical Port.
757       If so, initialize the new Physical Port then
758       continue processing as normal.
759     */
760     if( !osm_physp_is_valid( p_physp ) )
761     {
762       if( osm_log_is_active( p_rcv->p_log, OSM_LOG_VERBOSE ) )
763       {
764         osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
765                  "osm_pi_rcv_process: "
766                  "Initializing port number 0x%X\n",
767                  port_num );
768       }
769
770       osm_physp_init( p_physp,
771                       port_guid,
772                       port_num,
773                       p_node,
774                       osm_madw_get_bind_handle( p_madw ),
775                       p_smp->hop_count,
776                       p_smp->initial_path );
777
778       osm_port_add_new_physp( p_port, port_num );
779     }
780     else
781     {
782       /*
783         Update the directed route path to this port
784         in case the old path is no longer usable.
785       */
786       p_dr_path = osm_physp_get_dr_path_ptr( p_physp );
787       osm_dr_path_init( p_dr_path,
788                         osm_madw_get_bind_handle( p_madw ),
789                         p_smp->hop_count, p_smp->initial_path );
790     }
791
792     osm_dump_port_info( p_rcv->p_log,
793                         node_guid, port_guid, port_num, p_pi,
794                         OSM_LOG_DEBUG );
795
796     /*
797       Check if the update_sm_base_lid in the context is TRUE.
798       If it is - then update the master_sm_base_lid of the variable
799       in the subnet.
800     */
801     if (p_context->update_master_sm_base_lid == TRUE)
802     {
803       osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
804                "osm_pi_rcv_process: "
805                "update_master_sm is TRUE. "
806                "Updating master_sm_base_lid to:%u\n",
807                p_pi->master_sm_base_lid );
808
809       p_rcv->p_subn->master_sm_base_lid = p_pi->master_sm_base_lid;
810     }
811
812     switch( osm_node_get_type( p_node ) )
813     {
814     case IB_NODE_TYPE_CA:
815       __osm_pi_rcv_process_ca_port( p_rcv,
816                                     p_node, p_physp, p_pi );
817       break;
818     case IB_NODE_TYPE_ROUTER:
819       __osm_pi_rcv_process_router_port( p_rcv,
820                                         p_node, p_physp, p_pi );
821       break;
822     case IB_NODE_TYPE_SWITCH:
823       __osm_pi_rcv_process_switch_port( p_rcv,
824                                         p_node, p_physp, p_pi );
825       break;
826     default:
827       osm_log( p_rcv->p_log, OSM_LOG_ERROR,
828                "osm_pi_rcv_process: ERR 0F07: "
829                "Unknown node type %u with GUID = 0x%" PRIx64 "\n",
830                osm_node_get_type( p_node ),
831                cl_ntoh64( node_guid ) );
832       break;
833     }
834
835     /*
836       Get the tables on the physp.
837     */
838     __osm_pi_rcv_get_pkey_slvl_vla_tables( p_rcv, p_node, p_physp );
839
840   }
841
842   CL_PLOCK_RELEASE( p_rcv->p_lock );
843
844  Exit:
845   /*
846     Release the lock before jumping here!!
847   */
848   OSM_LOG_EXIT( p_rcv->p_log );
849 }