]> git.openfabrics.org - ~shefty/rdma-win.git/commitdiff
[OpenSM] patches for saquery porting - 5 of 6:
authortzachid <tzachid@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Wed, 4 Feb 2009 15:24:59 +0000 (15:24 +0000)
committertzachid <tzachid@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Wed, 4 Feb 2009 15:24:59 +0000 (15:24 +0000)
change osm_sa_path_record.c
Signed off by: stan.smith@intel.com

git-svn-id: svn://openib.tc.cornell.edu/gen1@1929 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

trunk/ulp/opensm/user/opensm/osm_sa_path_record.c

index a8e60cc31179c36fd2f7595b9e8816c19b7a40b2..7fb9fb7f3d5c8cdd5b4381d1a930427566966688 100644 (file)
-/*
- * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
- * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved.
- * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
- *
- * This software is available to you under the OpenIB.org BSD license
- * below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * $Id$
- */
-
-
-/*
- * Abstract:
- *    Implementation of osm_pr_rcv_t.
- * This object represents the PathRecord Receiver object.
- * This object is part of the opensm family of objects.
- *
- * Environment:
- *    Linux User Mode
- *
- * $Revision: 1.10 $
- */
-
-#if HAVE_CONFIG_H
-#  include <config.h>
-#endif /* HAVE_CONFIG_H */
-
-#include <string.h>
-#include <iba/ib_types.h>
-#include <complib/cl_qmap.h>
-#include <complib/cl_passivelock.h>
-#include <complib/cl_debug.h>
-#include <complib/cl_qlist.h>
-#include <opensm/osm_base.h>
-#include <opensm/osm_sa_path_record.h>
-#include <opensm/osm_port.h>
-#include <opensm/osm_node.h>
-#include <opensm/osm_switch.h>
-#include <vendor/osm_vendor.h>
-#include <vendor/osm_vendor_api.h>
-#include <opensm/osm_helper.h>
-#include <opensm/osm_pkey.h>
-#include <opensm/osm_multicast.h>
-#include <opensm/osm_partition.h>
-
-#define OSM_PR_RCV_POOL_MIN_SIZE    64
-#define OSM_PR_RCV_POOL_GROW_SIZE   64
-
-typedef  struct   _osm_pr_item
-{
-  cl_pool_item_t     pool_item;
-  ib_path_rec_t      path_rec;
-} osm_pr_item_t;
-
-typedef struct _osm_path_parms
-{
-  ib_net16_t         pkey;
-  uint8_t            mtu;
-  uint8_t            rate;
-  uint8_t            sl;
-  uint8_t            pkt_life;
-  boolean_t          reversible;
-} osm_path_parms_t;
-
-typedef  struct   osm_sa_pr_mcmr_search_ctxt {
-  ib_gid_t        *p_mgid;
-  osm_mgrp_t      *p_mgrp;
-  osm_pr_rcv_t    *p_rcv;
-} osm_sa_pr_mcmr_search_ctxt_t;
-
-/**********************************************************************
- **********************************************************************/
-void
-osm_pr_rcv_construct(
-  IN osm_pr_rcv_t* const p_rcv )
-{
-  memset( p_rcv, 0, sizeof(*p_rcv) );
-  cl_qlock_pool_construct( &p_rcv->pr_pool );
-}
-
-/**********************************************************************
- **********************************************************************/
-void
-osm_pr_rcv_destroy(
-  IN osm_pr_rcv_t* const p_rcv )
-{
-  OSM_LOG_ENTER( p_rcv->p_log, osm_pr_rcv_destroy );
-  cl_qlock_pool_destroy( &p_rcv->pr_pool );
-  OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- **********************************************************************/
-ib_api_status_t
-osm_pr_rcv_init(
-  IN osm_pr_rcv_t*      const p_rcv,
-  IN osm_sa_resp_t*     const p_resp,
-  IN osm_mad_pool_t*    const p_mad_pool,
-  IN osm_subn_t*        const p_subn,
-  IN osm_log_t*         const p_log,
-  IN cl_plock_t*        const p_lock )
-{
-  ib_api_status_t       status;
-
-  OSM_LOG_ENTER( p_log, osm_pr_rcv_init );
-
-  osm_pr_rcv_construct( p_rcv );
-
-  p_rcv->p_log = p_log;
-  p_rcv->p_subn = p_subn;
-  p_rcv->p_lock = p_lock;
-  p_rcv->p_resp = p_resp;
-  p_rcv->p_mad_pool = p_mad_pool;
-
-  status = cl_qlock_pool_init( &p_rcv->pr_pool,
-                               OSM_PR_RCV_POOL_MIN_SIZE,
-                               0,
-                               OSM_PR_RCV_POOL_GROW_SIZE,
-                               sizeof(osm_pr_item_t),
-                               NULL, NULL, NULL );
-
-  OSM_LOG_EXIT( p_rcv->p_log );
-  return( status );
-}
-
-/**********************************************************************
- **********************************************************************/
-static inline boolean_t
-__osm_sa_path_rec_is_tavor_port(
-  IN const osm_port_t*     const p_port)
-{
-  osm_node_t const* p_node;
-  ib_net32_t vend_id;
-
-  p_node = osm_port_get_parent_node( p_port );
-  vend_id = ib_node_info_get_vendor_id( &p_node->node_info );
-       
-  return( (p_node->node_info.device_id == CL_HTON16(23108)) &&
-         ((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) || 
-          (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) || 
-          (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) || 
-          (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE))) );
-}
-
-/**********************************************************************
- **********************************************************************/
-static boolean_t
- __osm_sa_path_rec_apply_tavor_mtu_limit(
-  IN const ib_path_rec_t*  const p_pr,
-  IN const osm_port_t*     const p_src_port,
-  IN const osm_port_t*     const p_dest_port,
-  IN const ib_net64_t      comp_mask)
-{
-  uint8_t required_mtu;
-       
-  /* only if at least one of the ports is a Tavor device */
-  if (! __osm_sa_path_rec_is_tavor_port(p_src_port) && 
-      ! __osm_sa_path_rec_is_tavor_port(p_dest_port) )
-    return( FALSE );
-
-  /*
-    we can apply the patch if either:
-    1. No MTU required
-    2. Required MTU < 
-    3. Required MTU = 1K or 512 or 256
-    4. Required MTU > 256 or 512
-  */
-  required_mtu = ib_path_rec_mtu( p_pr );
-  if ( ( comp_mask & IB_PR_COMPMASK_MTUSELEC ) &&
-       ( comp_mask & IB_PR_COMPMASK_MTU ) )
-  {
-    switch( ib_path_rec_mtu_sel( p_pr ) )
-    {
-    case 0:    /* must be greater than */
-    case 2:    /* exact match */
-      if( IB_MTU_LEN_1024 < required_mtu )
-        return(FALSE);
-      break;
-
-    case 1:    /* must be less than */
-               /* can't be disqualified by this one */
-      break;
-
-    case 3:    /* largest available */
-               /* the ULP intentionally requested */
-               /* the largest MTU possible */
-      return(FALSE);
-      break;
-                       
-    default:
-      /* if we're here, there's a bug in ib_path_rec_mtu_sel() */
-      CL_ASSERT( FALSE );
-      break;
-    }
-  }
-
-  return(TRUE);
-}
-
-/**********************************************************************
- **********************************************************************/
-static ib_api_status_t
-__osm_pr_rcv_get_path_parms(
-  IN osm_pr_rcv_t*         const p_rcv,
-  IN const ib_path_rec_t*  const p_pr,
-  IN const osm_port_t*     const p_src_port,
-  IN const osm_port_t*     const p_dest_port,
-  IN const uint16_t        dest_lid_ho,
-  IN const ib_net64_t      comp_mask,
-  OUT osm_path_parms_t*    const p_parms )
-{
-  const osm_node_t*        p_node;
-  const osm_physp_t*       p_physp;
-  const osm_physp_t*       p_dest_physp;
-  const osm_prtn_t*        p_prtn;
-  const ib_port_info_t*    p_pi;
-  ib_api_status_t          status = IB_SUCCESS;
-  ib_net16_t               pkey;
-  uint8_t                  mtu;
-  uint8_t                  rate;
-  uint8_t                  pkt_life;
-  uint8_t                  required_mtu;
-  uint8_t                  required_rate;
-  uint8_t                  required_pkt_life;
-  uint8_t                  sl;
-  ib_net16_t               dest_lid;
-
-  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_path_parms );
-
-  dest_lid = cl_hton16( dest_lid_ho );
-
-  p_dest_physp = osm_port_get_default_phys_ptr( p_dest_port );
-  p_physp = osm_port_get_default_phys_ptr( p_src_port );
-  p_pi = osm_physp_get_port_info_ptr( p_physp );
-
-  mtu = ib_port_info_get_mtu_cap( p_pi );
-  rate = ib_port_info_compute_rate( p_pi );
-
-  /* 
-    Mellanox Tavor device performance is better using 1K MTU.
-    If required MTU and MTU selector are such that 1K is OK 
-    and at least one end of the path is Tavor we override the
-    port MTU with 1K.
-  */
-  if ( p_rcv->p_subn->opt.enable_quirks &&
-       __osm_sa_path_rec_apply_tavor_mtu_limit(
-               p_pr, p_src_port, p_dest_port, comp_mask) )
-    if (mtu > IB_MTU_LEN_1024) 
-    {
-      mtu = IB_MTU_LEN_1024;
-      osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
-              "__osm_pr_rcv_get_path_parms: "
-              "Optimized Path MTU to 1K for Mellanox Tavor device\n");
-    }
-
-  /*
-    Walk the subnet object from source to destination,
-    tracking the most restrictive rate and mtu values along the way...
-
-    If source port node is a switch, then p_physp should
-    point to the port that routes the destination lid
-  */
-
-  p_node = osm_physp_get_node_ptr( p_physp );
-
-  if( p_node->sw )
-  {
-    /*
-     * If the dest_lid_ho is equal to the lid of the switch pointed by
-     * p_sw then p_physp will be the physical port of the switch port zero.
-     */
-    p_physp = osm_switch_get_route_by_lid(p_node->sw, cl_ntoh16( dest_lid_ho ) );
-    if ( p_physp == 0 )
-    {
-      osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-               "__osm_pr_rcv_get_path_parms: ERR 1F02: "
-               "Cannot find routing to LID 0x%X from switch for GUID 0x%016" PRIx64 "\n",
-               dest_lid_ho,
-               cl_ntoh64( osm_node_get_node_guid( p_node ) ) );
-      status = IB_ERROR;
-      goto Exit;
-    }
-  }
-
-  /*
-   * Same as above
-   */
-  p_node = osm_physp_get_node_ptr( p_dest_physp );
-
-  if( p_node->sw )
-  {
-    p_dest_physp = osm_switch_get_route_by_lid( p_node->sw, cl_ntoh16( dest_lid_ho ) );
-
-    if ( p_dest_physp == 0 )
-    {
-      osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-               "__osm_pr_rcv_get_path_parms: ERR 1F03: "
-               "Cannot find routing to LID 0x%X from switch for GUID 0x%016" PRIx64 "\n",
-               dest_lid_ho,
-               cl_ntoh64( osm_node_get_node_guid( p_node ) ) );
-      status = IB_ERROR;
-      goto Exit;
-    }
-
-  }
-
-  while( p_physp != p_dest_physp )
-  {
-    p_physp = osm_physp_get_remote( p_physp );
-
-    if ( p_physp == 0 )
-    {
-      osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-               "__osm_pr_rcv_get_path_parms: ERR 1F05: "
-               "Cannot find remote phys port when routing to LID 0x%X from node GUID 0x%016" PRIx64 "\n",
-               dest_lid_ho,
-               cl_ntoh64( osm_node_get_node_guid( p_node ) ) );
-      status = IB_ERROR;
-      goto Exit;
-    }
-
-    /*
-      This is point to point case (no switch in between)
-    */
-    if( p_physp == p_dest_physp )
-      break;
-
-    p_node = osm_physp_get_node_ptr( p_physp );
-
-    if( !p_node->sw )
-    {
-      /*
-        There is some sort of problem in the subnet object!
-        If this isn't a switch, we should have reached
-        the destination by now!
-      */
-      osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-               "__osm_pr_rcv_get_path_parms: ERR 1F06: "
-               "Internal error, bad path\n" );
-      status = IB_ERROR;
-      goto Exit;
-    }
-
-    /*
-      Check parameters for the ingress port in this switch.
-    */
-    p_pi = osm_physp_get_port_info_ptr( p_physp );
-
-    if( mtu > ib_port_info_get_mtu_cap( p_pi ) )
-    {
-      mtu = ib_port_info_get_mtu_cap( p_pi );
-      if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
-      {
-        osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
-                 "__osm_pr_rcv_get_path_parms: "
-                 "New smallest MTU = %u at intervening port 0x%016" PRIx64
-                 " port num 0x%X\n",
-                 mtu,
-                 cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),
-                 osm_physp_get_port_num( p_physp ) );
-      }
-    }
-
-    if( rate > ib_port_info_compute_rate( p_pi ) )
-    {
-      rate = ib_port_info_compute_rate( p_pi );
-      if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
-      {
-        osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
-                 "__osm_pr_rcv_get_path_parms: "
-                 "New smallest rate = %u at intervening port 0x%016" PRIx64
-                 " port num 0x%X\n",
-                 rate,
-                 cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),
-                 osm_physp_get_port_num( p_physp ) );
-      }
-    }
-
-    /*
-      Continue with the egress port on this switch.
-    */
-    p_physp = osm_switch_get_route_by_lid( p_node->sw, dest_lid );
-
-    if ( p_physp == 0 )
-    {
-      osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-               "__osm_pr_rcv_get_path_parms: ERR 1F07: "
-               "Dead end on path to LID 0x%X from switch for GUID 0x%016" PRIx64 "\n",
-               dest_lid_ho,
-               cl_ntoh64( osm_node_get_node_guid( p_node ) ) );
-      status = IB_ERROR;
-      goto Exit;
-    }
-
-    CL_ASSERT( p_physp );
-    CL_ASSERT( osm_physp_is_valid( p_physp ) );
-
-    p_pi = osm_physp_get_port_info_ptr( p_physp );
-
-    if( mtu > ib_port_info_get_mtu_cap( p_pi ) )
-    {
-      mtu = ib_port_info_get_mtu_cap( p_pi );
-      if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
-      {
-        osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
-                 "__osm_pr_rcv_get_path_parms: "
-                 "New smallest MTU = %u at intervening port 0x%016" PRIx64
-                 " port num 0x%X\n",
-                 mtu,
-                 cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),
-                 osm_physp_get_port_num( p_physp ) );
-      }
-    }
-
-    if( rate > ib_port_info_compute_rate( p_pi ) )
-    {
-      rate = ib_port_info_compute_rate( p_pi );
-      if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
-      {
-        osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
-                 "__osm_pr_rcv_get_path_parms: "
-                 "New smallest rate = %u at intervening port 0x%016" PRIx64
-                 " port num 0x%X\n",
-                 rate,
-                 cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),
-                 osm_physp_get_port_num( p_physp ) );
-      }
-    }
-
-  }
-
-  /*
-    p_physp now points to the destination
-  */
-  p_pi = osm_physp_get_port_info_ptr( p_physp );
-
-  if( mtu > ib_port_info_get_mtu_cap( p_pi ) )
-  {
-    mtu = ib_port_info_get_mtu_cap( p_pi );
-    if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
-    {
-      osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
-               "__osm_pr_rcv_get_path_parms: "
-               "New smallest MTU = %u at destination port 0x%016" PRIx64 "\n",
-               mtu,
-               cl_ntoh64(osm_physp_get_port_guid( p_physp )) );
-    }
-  }
-
-  if( rate > ib_port_info_compute_rate( p_pi ) )
-  {
-    rate = ib_port_info_compute_rate( p_pi );
-    if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
-    {
-      osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
-               "__osm_pr_rcv_get_path_parms: "
-               "New smallest rate = %u at destination port 0x%016" PRIx64 "\n",
-               rate,
-               cl_ntoh64(osm_physp_get_port_guid( p_physp )) );
-    }
-  }
-
-  if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
-  {
-    osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
-             "__osm_pr_rcv_get_path_parms: "
-             "Path min MTU = %u, min rate = %u\n", mtu, rate );
-  }
-
-  /*
-    Determine if these values meet the user criteria
-    and adjust appropriately
-  */
-
-  /* we silently ignore cases where only the MTU selector is defined */
-  if ( ( comp_mask & IB_PR_COMPMASK_MTUSELEC ) &&
-       ( comp_mask & IB_PR_COMPMASK_MTU ) )
-  {
-    required_mtu = ib_path_rec_mtu( p_pr );
-    switch( ib_path_rec_mtu_sel( p_pr ) )
-    {
-    case 0:    /* must be greater than */
-      if( mtu <= required_mtu )
-        status = IB_NOT_FOUND;
-      break;
-
-    case 1:    /* must be less than */
-       if( mtu >= required_mtu )
-       {
-          /* adjust to use the highest mtu
-             lower then the required one */
-          if( required_mtu > 1 )
-            mtu = required_mtu - 1;
-          else
-            status = IB_NOT_FOUND;
-       }
-      break;
-
-    case 2:    /* exact match */
-      if( mtu < required_mtu )
-        status = IB_NOT_FOUND;
-      else
-        mtu = required_mtu;
-      break;
-
-    case 3:    /* largest available */
-      /* can't be disqualified by this one */
-      break;
-
-    default:
-      /* if we're here, there's a bug in ib_path_rec_mtu_sel() */
-      CL_ASSERT( FALSE );
-      status = IB_ERROR;
-      break;
-    }
-  }
-
-  /* we silently ignore cases where only the Rate selector is defined */
-  if ( ( comp_mask & IB_PR_COMPMASK_RATESELEC ) &&
-       ( comp_mask & IB_PR_COMPMASK_RATE ) )
-  {
-    required_rate = ib_path_rec_rate( p_pr );
-    switch( ib_path_rec_rate_sel( p_pr ) )
-    {
-    case 0:    /* must be greater than */
-      if( rate <= required_rate )
-        status = IB_NOT_FOUND;
-      break;
-
-    case 1:    /* must be less than */
-      if( rate >= required_rate )
-      {
-        /* adjust the rate to use the highest rate
-           lower then the required one */
-        if( required_rate > 2 )
-          rate = required_rate - 1;
-        else
-          status = IB_NOT_FOUND;
-      }
-      break;
-
-    case 2:    /* exact match */
-      if( rate < required_rate )
-        status = IB_NOT_FOUND;
-      else
-        rate = required_rate;
-      break;
-
-    case 3:    /* largest available */
-      /* can't be disqualified by this one */
-      break;
-
-    default:
-      /* if we're here, there's a bug in ib_path_rec_mtu_sel() */
-      CL_ASSERT( FALSE );
-      status = IB_ERROR;
-      break;
-    }
-  }
-
-  /* Verify the pkt_life_time */
-  /* According to spec definition IBA 1.2 Table 205 PacketLifeTime description,
-     for loopback paths, packetLifeTime shall be zero. */
-  if ( p_src_port == p_dest_port )
-    pkt_life = 0;      /* loopback */
-  else
-    pkt_life = OSM_DEFAULT_SUBNET_TIMEOUT;
-
-  /* we silently ignore cases where only the PktLife selector is defined */
-  if ( ( comp_mask & IB_PR_COMPMASK_PKTLIFETIMESELEC ) &&
-       ( comp_mask & IB_PR_COMPMASK_PKTLIFETIME ) )
-  {
-    required_pkt_life = ib_path_rec_pkt_life( p_pr );
-    switch( ib_path_rec_pkt_life_sel( p_pr ) )
-    {
-    case 0:    /* must be greater than */
-      if( pkt_life <= required_pkt_life )
-        status = IB_NOT_FOUND;
-      break;
-
-    case 1:    /* must be less than */
-      if( pkt_life >= required_pkt_life )
-      {
-        /* adjust the lifetime to use the highest possible
-           lower then the required one */
-        if( required_pkt_life > 1 )
-          pkt_life = required_pkt_life - 1;
-        else
-          status = IB_NOT_FOUND;
-      }
-      break;
-
-    case 2:    /* exact match */
-      if( pkt_life < required_pkt_life )
-         status = IB_NOT_FOUND;
-      else
-         pkt_life = required_pkt_life;
-      break;
-
-    case 3:    /* smallest available */
-      /* can't be disqualified by this one */
-      break;
-
-    default:
-      /* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */
-      CL_ASSERT( FALSE );
-      status = IB_ERROR;
-      break;
-    }
-  }
-
-  if (status != IB_SUCCESS)
-    goto Exit;
-
-  p_parms->mtu = mtu;
-  p_parms->rate = rate;
-  p_parms->pkt_life = pkt_life;
-
-  if( comp_mask & IB_PR_COMPMASK_RAWTRAFFIC &&
-      cl_ntoh32( p_pr->hop_flow_raw ) & ( 1<<31 ) )
-    pkey = osm_physp_find_common_pkey( p_physp, p_dest_physp );
-  else if( comp_mask & IB_PR_COMPMASK_PKEY )
-  {
-    pkey = p_pr->pkey;
-    if( !osm_physp_share_this_pkey( p_physp, p_dest_physp, pkey ) )
-    {
-      osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-               "__osm_pr_rcv_get_path_parms: ERR 1F1A: "
-               "Ports do not share specified PKey 0x%04x\n", cl_ntoh16(pkey));
-      status = IB_NOT_FOUND;
-      goto Exit;
-    }
-  }
-  else
-  {
-    pkey = osm_physp_find_common_pkey( p_physp, p_dest_physp );
-    if ( !pkey )
-    {
-      osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-               "__osm_pr_rcv_get_path_parms: ERR 1F1B: "
-               "Ports do not have any shared PKeys\n");
-      status = IB_NOT_FOUND;
-      goto Exit;
-    }
-  }
-
-  sl = OSM_DEFAULT_SL;
-
-  if (pkey) {
-    p_prtn = (osm_prtn_t *)cl_qmap_get(&p_rcv->p_subn->prtn_pkey_tbl,
-                                       pkey & cl_ntoh16((uint16_t)~0x8000));
-    if ( p_prtn == (osm_prtn_t *)cl_qmap_end(&p_rcv->p_subn->prtn_pkey_tbl) )
-    {
-      /* this may be possible when pkey tables are created somehow in
-         previous runs or things are going wrong here */
-      osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-               "__osm_pr_rcv_get_path_parms: ERR 1F1C: "
-               "No partition found for PKey 0x%04x - using default SL %d\n",
-               cl_ntoh16(pkey), sl );
-    }
-    else
-      sl = p_prtn->sl;
-
-    /* reset pkey when raw traffic */
-    if( comp_mask & IB_PR_COMPMASK_RAWTRAFFIC &&
-        cl_ntoh32( p_pr->hop_flow_raw ) & ( 1<<31 ) )
-      pkey = 0;
-  }
-
-  if ( ( comp_mask & IB_PR_COMPMASK_SL ) && ib_path_rec_sl( p_pr ) != sl )
-  {
-    status = IB_NOT_FOUND;
-    goto Exit;
-  }
-
-  p_parms->pkey = pkey;
-  p_parms->sl = sl;
-
- Exit:
-  OSM_LOG_EXIT( p_rcv->p_log );
-  return( status );
-}
-
-/**********************************************************************
- **********************************************************************/
-static void
-__osm_pr_rcv_build_pr(
-  IN osm_pr_rcv_t*         const p_rcv,
-  IN const osm_port_t*     const p_src_port,
-  IN const osm_port_t*     const p_dest_port,
-  IN const uint16_t        src_lid_ho,
-  IN const uint16_t        dest_lid_ho,
-  IN const uint8_t         preference,
-  IN const osm_path_parms_t*  const p_parms,
-  OUT ib_path_rec_t*       const p_pr )
-{
-  const osm_physp_t*       p_src_physp;
-  const osm_physp_t*       p_dest_physp;
-
-  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_build_pr );
-
-  p_src_physp = osm_port_get_default_phys_ptr( p_src_port );
-  p_dest_physp = osm_port_get_default_phys_ptr( p_dest_port );
-
-  p_pr->dgid.unicast.prefix = osm_physp_get_subnet_prefix( p_dest_physp );
-  p_pr->dgid.unicast.interface_id = osm_physp_get_port_guid( p_dest_physp );
-
-  p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix( p_src_physp );
-  p_pr->sgid.unicast.interface_id = osm_physp_get_port_guid( p_src_physp );
-
-  p_pr->dlid = cl_hton16( dest_lid_ho );
-  p_pr->slid = cl_hton16( src_lid_ho );
-
-  p_pr->hop_flow_raw &= cl_hton32(1<<31);
-
-  p_pr->pkey = p_parms->pkey;
-  p_pr->sl = cl_hton16(p_parms->sl);
-  p_pr->mtu = (uint8_t)(p_parms->mtu | 0x80);
-  p_pr->rate = (uint8_t)(p_parms->rate | 0x80);
-
-  /* According to 1.2 spec definition Table 205 PacketLifeTime description,
-     for loopback paths, packetLifeTime shall be zero. */
-  if ( p_src_port == p_dest_port )
-    p_pr->pkt_life = 0x80;     /* loopback */
-  else
-    p_pr->pkt_life = (uint8_t)(p_parms->pkt_life | 0x80);
-
-  p_pr->preference = preference;
-
-  /* always return num_path = 0 so this is only the reversible component */
-  if (p_parms->reversible)
-    p_pr->num_path = 0x80;
-
-  OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- **********************************************************************/
-static osm_pr_item_t*
-__osm_pr_rcv_get_lid_pair_path(
-  IN osm_pr_rcv_t*         const p_rcv,
-  IN const ib_path_rec_t*  const p_pr,
-  IN const osm_port_t*     const p_src_port,
-  IN const osm_port_t*     const p_dest_port,
-  IN const uint16_t        src_lid_ho,
-  IN const uint16_t        dest_lid_ho,
-  IN const ib_net64_t      comp_mask,
-  IN const uint8_t         preference )
-{
-  osm_path_parms_t         path_parms;
-  osm_path_parms_t         rev_path_parms;
-  osm_pr_item_t            *p_pr_item;
-  ib_api_status_t          status, rev_path_status;
-
-  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_lid_pair_path );
-
-  if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
-  {
-    osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
-             "__osm_pr_rcv_get_lid_pair_path: "
-             "Src LID 0x%X, Dest LID 0x%X\n",
-             src_lid_ho, dest_lid_ho );
-  }
-
-  p_pr_item = (osm_pr_item_t*)cl_qlock_pool_get( &p_rcv->pr_pool );
-  if( p_pr_item == NULL )
-  {
-    osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-             "__osm_pr_rcv_get_lid_pair_path: ERR 1F01: "
-             "Unable to allocate path record\n" );
-    goto Exit;
-  }
-
-  status = __osm_pr_rcv_get_path_parms( p_rcv, p_pr, p_src_port,
-                                        p_dest_port, dest_lid_ho,
-                                        comp_mask, &path_parms );
-
-  if( status != IB_SUCCESS )
-  {
-    cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );
-    p_pr_item = NULL;
-    goto Exit;
-  }
-
-  /* now try the reversible path */
-  rev_path_status = __osm_pr_rcv_get_path_parms( p_rcv, p_pr, p_dest_port,
-                                                 p_src_port, src_lid_ho,
-                                                 comp_mask, &rev_path_parms );
-  path_parms.reversible = ( rev_path_status == IB_SUCCESS );
-
-  /* did we get a Reversible Path compmask ? */
-  /* 
-     NOTE that if the reversible component = 0, it is a don't care
-     rather then requiring non-reversible paths ... 
-     see Vol1 Ver1.2 p900 l16
-  */
-  if( comp_mask & IB_PR_COMPMASK_REVERSIBLE )
-  {
-    if( (! path_parms.reversible && ( p_pr->num_path & 0x80 ) ) )
-    {
-      osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
-               "__osm_pr_rcv_get_lid_pair_path: "
-               "Requested reversible path but failed to get one\n");
-
-      cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );
-      p_pr_item = NULL;
-      goto Exit;
-    }
-  }
-
-  __osm_pr_rcv_build_pr( p_rcv, p_src_port, p_dest_port, src_lid_ho,
-                         dest_lid_ho, preference, &path_parms,
-                         &p_pr_item->path_rec );
-
- Exit:
-  OSM_LOG_EXIT( p_rcv->p_log );
-  return( p_pr_item );
-}
-
-/**********************************************************************
- **********************************************************************/
-static void
-__osm_pr_rcv_get_port_pair_paths(
-  IN osm_pr_rcv_t*         const p_rcv,
-  IN const osm_madw_t*     const p_madw,
-  IN const osm_port_t*     const p_req_port,
-  IN const osm_port_t*     const p_src_port,
-  IN const osm_port_t*     const p_dest_port,
-  IN const ib_net64_t      comp_mask,
-  IN cl_qlist_t*           const p_list )
-{
-  const ib_path_rec_t*     p_pr;
-  const ib_sa_mad_t*       p_sa_mad;
-  osm_pr_item_t*           p_pr_item;
-  uint16_t                 src_lid_min_ho;
-  uint16_t                 src_lid_max_ho;
-  uint16_t                 dest_lid_min_ho;
-  uint16_t                 dest_lid_max_ho;
-  uint16_t                 src_lid_ho;
-  uint16_t                 dest_lid_ho;
-  uint32_t                 path_num;
-  uint8_t                  preference;
-  uintn_t                  iterations;
-  uintn_t                  src_offset;
-  uintn_t                  dest_offset;
-
-  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_port_pair_paths );
-
-  if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
-  {
-    osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
-             "__osm_pr_rcv_get_port_pair_paths: "
-             "Src port 0x%016" PRIx64 ", "
-             "Dst port 0x%016" PRIx64 "\n",
-             cl_ntoh64( osm_port_get_guid( p_src_port ) ),
-             cl_ntoh64( osm_port_get_guid( p_dest_port ) ) );
-  }
-
-  /* Check that the req_port, src_port and dest_port all share a
-     pkey. The check is done on the default physical port of the ports. */
-  if (osm_port_share_pkey(p_rcv->p_log, p_req_port, p_src_port) == FALSE ||
-      osm_port_share_pkey(p_rcv->p_log, p_req_port, p_dest_port) == FALSE ||
-      osm_port_share_pkey(p_rcv->p_log, p_src_port, p_dest_port) == FALSE )
-  {
-    /* One of the pairs doesn't share a pkey so the path is disqualified. */
-    goto Exit;
-  }
-
-  p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
-  p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
-
-  /*
-    We shouldn't be here if the paths are disqualified in some way...
-    Thus, we assume every possible connection is valid.
-
-    We desire to return high-quality paths first.
-    In OpenSM, higher quality means least overlap with other paths.
-    This is acheived in practice by returning paths with
-    different LID value on each end, which means these
-    paths are more redundant that paths with the same LID repeated
-    on one side.  For example, in OpenSM the paths between two
-    endpoints with LMC = 1 might be as follows:
-
-    Port A, LID 1 <-> Port B, LID 3
-    Port A, LID 1 <-> Port B, LID 4
-    Port A, LID 2 <-> Port B, LID 3
-    Port A, LID 2 <-> Port B, LID 4
-
-    The OpenSM unicast routing algorithms attempt to disperse each path
-    to as varied a physical path as is reasonable.  1<->3 and 1<->4 have
-    more physical overlap (hence less redundancy) than 1<->3 and 2<->4.
-
-    OpenSM ranks paths in three preference groups:
-
-    Preference Value    Description
-    ----------------    -------------------------------------------
-    0             Redundant in both directions with other
-    pref value = 0 paths
-
-    1             Redundant in one direction with other
-    pref value = 0 and pref value = 1 paths
-
-    2             Not redundant in either direction with
-    other paths
-
-    3-FF          Unused
-
-
-    SA clients don't need to know these details, only that the lower
-    preference paths are preferred, as stated in the spec.  The paths
-    may not actually be physically redundant depending on the topology
-    of the subnet, but the point of LMC > 0 is to offer redundancy,
-    so it is assumed that the subnet is physically appropriate for the
-    specified LMC value.  A more advanced implementation would inspect for 
-    physical redundancy, but I'm not going to bother with that now.
-  */
-
-  /*
-    Refine our search if the client specified end-point LIDs
-  */
-  if( comp_mask & IB_PR_COMPMASK_DLID )
-  {
-    dest_lid_min_ho = cl_ntoh16( p_pr->dlid );
-    dest_lid_max_ho = cl_ntoh16( p_pr->dlid );
-  }
-  else
-  {
-    osm_port_get_lid_range_ho( p_dest_port, &dest_lid_min_ho,
-                               &dest_lid_max_ho );
-  }
-
-  if( comp_mask & IB_PR_COMPMASK_SLID )
-  {
-    src_lid_min_ho = cl_ntoh16( p_pr->slid );
-    src_lid_max_ho = cl_ntoh16( p_pr->slid );
-  }
-  else
-  {
-    osm_port_get_lid_range_ho( p_src_port, &src_lid_min_ho,
-                               &src_lid_max_ho );
-  }
-
-  if ( src_lid_min_ho == 0 )
-  {
-    osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-             "__osm_pr_rcv_get_port_pair_paths: ERR 1F20:"
-             "Obtained source LID of 0. No such LID possible\n");
-     goto Exit;
-  }
-
-  if ( dest_lid_min_ho == 0 )
-  {
-    osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-             "__osm_pr_rcv_get_port_pair_paths: ERR 1F21:"
-             "Obtained destination LID of 0. No such LID possible\n");
-     goto Exit;
-  }
-
-  if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
-  {
-    osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
-             "__osm_pr_rcv_get_port_pair_paths: "
-             "Src LIDs [0x%X-0x%X], "
-             "Dest LIDs [0x%X-0x%X]\n",
-             src_lid_min_ho, src_lid_max_ho,
-             dest_lid_min_ho, dest_lid_max_ho );
-  }
-
-  src_lid_ho = src_lid_min_ho;
-  dest_lid_ho = dest_lid_min_ho;
-
-  /*
-    Preferred paths come first in OpenSM
-  */
-  preference = 0;
-  path_num = 0;
-
-  /* If SubnAdmGet, assume NumbPaths 1 (1.2 erratum) */
-  if( p_sa_mad->method != IB_MAD_METHOD_GET )
-    if( comp_mask & IB_PR_COMPMASK_NUMBPATH )
-      iterations = ib_path_rec_num_path( p_pr );
-    else
-      iterations = (uintn_t)(-1);
-  else
-    iterations = 1;
-
-  while( path_num < iterations )
-  {
-    /*
-      These paths are "fully redundant"
-    */
-
-    p_pr_item = __osm_pr_rcv_get_lid_pair_path( p_rcv, p_pr,
-                                                p_src_port, p_dest_port,
-                                                src_lid_ho, dest_lid_ho,
-                                                comp_mask, preference );
-
-    if( p_pr_item )
-    {
-      cl_qlist_insert_tail( p_list,
-                            (cl_list_item_t*)&p_pr_item->pool_item );
-      ++path_num;
-    }
-
-    if( ++src_lid_ho > src_lid_max_ho )
-      break;
-
-    if( ++dest_lid_ho > dest_lid_max_ho )
-      break;
-  }
-
-  /*
-    Check if we've accumulated all the paths that the user cares to see
-  */
-  if( path_num == iterations )
-    goto Exit;
-
-  /*
-    Don't bother reporting preference 1 paths for now.
-    It's more trouble than it's worth and can only occur
-    if ports have different LMC values, which isn't supported
-    by OpenSM right now anyway.
-  */
-  preference = 2;
-  src_lid_ho = src_lid_min_ho;
-  dest_lid_ho = dest_lid_min_ho;
-  src_offset = 0;
-  dest_offset = 0;
-
-  /*
-    Iterate over the remaining paths
-  */
-  while( path_num < iterations )
-  {
-    dest_offset++;
-    dest_lid_ho++;
-
-    if( dest_lid_ho > dest_lid_max_ho )
-    {
-      src_offset++;
-      src_lid_ho++;
-
-      if( src_lid_ho > src_lid_max_ho )
-        break;    /* done */
-
-      dest_offset = 0;
-      dest_lid_ho = dest_lid_min_ho;
-    }
-
-    /*
-      These paths are "fully non-redundant" with paths already
-      identified above and consequently not of much value.
-
-      Don't return paths we already identified above, as indicated
-      by the offset values being equal.
-    */
-    if( src_offset == dest_offset )
-      continue;      /* already reported */
-
-    p_pr_item = __osm_pr_rcv_get_lid_pair_path( p_rcv, p_pr,
-                                                p_src_port, p_dest_port,
-                                                src_lid_ho, dest_lid_ho,
-                                                comp_mask, preference );
-
-    if( p_pr_item )
-    {
-      cl_qlist_insert_tail( p_list,
-                            (cl_list_item_t*)&p_pr_item->pool_item );
-      ++path_num;
-    }
-  }
-
- Exit:
-  OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- **********************************************************************/
-static ib_net16_t
-__osm_pr_rcv_get_end_points(
-  IN osm_pr_rcv_t*         const p_rcv,
-  IN const osm_madw_t*     const p_madw,
-  OUT const osm_port_t**   const pp_src_port,
-  OUT const osm_port_t**   const pp_dest_port )
-{
-  const ib_path_rec_t*     p_pr;
-  const ib_sa_mad_t*       p_sa_mad;
-  ib_net64_t               comp_mask;
-  ib_api_status_t          status;
-  ib_net16_t               sa_status = IB_SA_MAD_STATUS_SUCCESS;
-
-  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_end_points );
-
-  /*
-    Determine what fields are valid and then get a pointer
-    to the source and destination port objects, if possible.
-  */
-
-  p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
-  p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
-
-  comp_mask = p_sa_mad->comp_mask;
-
-  /*
-    Check a few easy disqualifying cases up front before getting
-    into the endpoints.
-  */
-
-  if( comp_mask & IB_PR_COMPMASK_SGID )
-  {
-    if ( ! ib_gid_is_link_local ( &p_pr->sgid ) )
-    {
-      if ( ib_gid_get_subnet_prefix ( &p_pr->sgid ) != p_rcv->p_subn->opt.subnet_prefix )
-      {
-        /*
-          This 'error' is the client's fault (bad gid) so
-          don't enter it as an error in our own log.
-          Return an error response to the client.
-        */
-        osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
-                 "__osm_pr_rcv_get_end_points: "
-                 "Non local SGID subnet prefix 0x%016" PRIx64 "\n",
-                 cl_ntoh64( p_pr->sgid.unicast.prefix ) );
-
-        sa_status = IB_SA_MAD_STATUS_INVALID_GID;
-        goto Exit;
-      }
-    }
-
-    *pp_src_port = (osm_port_t*)cl_qmap_get(
-      &p_rcv->p_subn->port_guid_tbl,
-      p_pr->sgid.unicast.interface_id );
-
-    if( *pp_src_port == (osm_port_t*)cl_qmap_end(
-          &p_rcv->p_subn->port_guid_tbl ) )
-    {
-      /*
-        This 'error' is the client's fault (bad gid) so
-        don't enter it as an error in our own log.
-        Return an error response to the client.
-      */
-      osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
-               "__osm_pr_rcv_get_end_points: "
-               "No source port with GUID 0x%016" PRIx64 "\n",
-               cl_ntoh64( p_pr->sgid.unicast.interface_id) );
-
-      sa_status = IB_SA_MAD_STATUS_INVALID_GID;
-      goto Exit;
-    }
-  }
-  else
-  {
-    *pp_src_port = 0;
-    if( comp_mask & IB_PR_COMPMASK_SLID )
-    {
-      status = cl_ptr_vector_at( &p_rcv->p_subn->port_lid_tbl,
-                                 cl_ntoh16(p_pr->slid), (void**)pp_src_port );
-
-      if( (status != CL_SUCCESS) || (*pp_src_port == NULL) )
-      {
-        /*
-          This 'error' is the client's fault (bad lid) so
-          don't enter it as an error in our own log.
-          Return an error response to the client.
-        */
-        osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
-                 "__osm_pr_rcv_get_end_points: "
-                 "No source port with LID = 0x%X\n",
-                 cl_ntoh16( p_pr->slid) );
-
-        sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
-        goto Exit;
-      }
-    }
-  }
-
-  if( comp_mask & IB_PR_COMPMASK_DGID )
-  {
-    if ( ! ib_gid_is_link_local ( &p_pr->dgid ) )
-    {
-      if ( ! ib_gid_is_multicast ( &p_pr->dgid ) &&
-             ib_gid_get_subnet_prefix ( &p_pr->dgid ) != p_rcv->p_subn->opt.subnet_prefix )
-      {
-        /*
-          This 'error' is the client's fault (bad gid) so
-          don't enter it as an error in our own log.
-          Return an error response to the client.
-        */
-        osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
-                 "__osm_pr_rcv_get_end_points: "
-                 "Non local DGID subnet prefix 0x%016" PRIx64 "\n",
-                 cl_ntoh64( p_pr->dgid.unicast.prefix ) );
-
-        sa_status = IB_SA_MAD_STATUS_INVALID_GID;
-        goto Exit;
-      }
-    }
-
-    *pp_dest_port = (osm_port_t*)cl_qmap_get(
-      &p_rcv->p_subn->port_guid_tbl,
-      p_pr->dgid.unicast.interface_id );
-
-    if( *pp_dest_port == (osm_port_t*)cl_qmap_end(
-          &p_rcv->p_subn->port_guid_tbl ) )
-    {
-      /*
-        This 'error' is the client's fault (bad gid) so
-        don't enter it as an error in our own log.
-        Return an error response to the client.
-      */
-      osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
-               "__osm_pr_rcv_get_end_points: "
-               "No dest port with GUID 0x%016" PRIx64 "\n",
-               cl_ntoh64( p_pr->dgid.unicast.interface_id) );
-
-      sa_status = IB_SA_MAD_STATUS_INVALID_GID;
-      goto Exit;
-    }
-  }
-  else
-  {
-    *pp_dest_port = 0;
-    if( comp_mask & IB_PR_COMPMASK_DLID )
-    {
-      status = cl_ptr_vector_at( &p_rcv->p_subn->port_lid_tbl,
-                                 cl_ntoh16(p_pr->dlid),  (void**)pp_dest_port );
-
-      if( (status != CL_SUCCESS) || (*pp_dest_port == NULL) )
-      {
-        /*
-          This 'error' is the client's fault (bad lid) so
-          don't enter it as an error in our own log.
-          Return an error response to the client.
-        */
-        osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
-                 "__osm_pr_rcv_get_end_points: "
-                 "No dest port with LID = 0x%X\n",
-                 cl_ntoh16( p_pr->dlid) );
-
-        sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
-        goto Exit;
-      }
-    }
-  }
-
- Exit:
-  OSM_LOG_EXIT( p_rcv->p_log );
-  return( sa_status );
-}
-
-/**********************************************************************
- **********************************************************************/
-static void
-__osm_pr_rcv_process_world(
-  IN osm_pr_rcv_t*         const p_rcv,
-  IN const osm_madw_t*     const p_madw,
-  IN const osm_port_t*     const requester_port,
-  IN const ib_net64_t      comp_mask,
-  IN cl_qlist_t*           const p_list )
-{
-  const cl_qmap_t*         p_tbl;
-  const osm_port_t*        p_dest_port;
-  const osm_port_t*        p_src_port;
-
-  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_process_world );
-
-  /*
-    Iterate the entire port space over itself.
-    A path record from a port to itself is legit, so no
-    need for a special case there.
-
-    We compute both A -> B and B -> A, since we don't have
-    any check to determine the reversability of the paths.
-  */
-  p_tbl = &p_rcv->p_subn->port_guid_tbl;
-
-  p_dest_port = (osm_port_t*)cl_qmap_head( p_tbl );
-  while( p_dest_port != (osm_port_t*)cl_qmap_end( p_tbl ) )
-  {
-    p_src_port = (osm_port_t*)cl_qmap_head( p_tbl );
-    while( p_src_port != (osm_port_t*)cl_qmap_end( p_tbl ) )
-    {
-      __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw, requester_port, p_src_port,
-                                        p_dest_port, comp_mask, p_list );
-
-      p_src_port = (osm_port_t*)cl_qmap_next( &p_src_port->map_item );
-    }
-
-    p_dest_port = (osm_port_t*)cl_qmap_next( &p_dest_port->map_item );
-  }
-
-  OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- **********************************************************************/
-static void
-__osm_pr_rcv_process_half(
-  IN osm_pr_rcv_t*         const p_rcv,
-  IN const osm_madw_t*     const p_madw,
-  IN const osm_port_t*     const requester_port,
-  IN const osm_port_t*     const p_src_port,
-  IN const osm_port_t*     const p_dest_port,
-  IN const ib_net64_t      comp_mask,
-  IN cl_qlist_t*           const p_list )
-{
-  const cl_qmap_t*         p_tbl;
-  const osm_port_t*        p_port;
-
-  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_process_half );
-
-  /*
-    Iterate over every port, looking for matches...
-    A path record from a port to itself is legit, so no
-    need to special case that one.
-  */
-  p_tbl = &p_rcv->p_subn->port_guid_tbl;
-
-  if( p_src_port )
-  {
-    /*
-      The src port if fixed, so iterate over destination ports.
-    */
-    p_port = (osm_port_t*)cl_qmap_head( p_tbl );
-    while( p_port != (osm_port_t*)cl_qmap_end( p_tbl ) )
-    {
-      __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw , requester_port, p_src_port,
-                                        p_port, comp_mask, p_list );
-      p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item );
-    }
-  }
-  else
-  {
-    /*
-      The dest port if fixed, so iterate over source ports.
-    */
-    p_port = (osm_port_t*)cl_qmap_head( p_tbl );
-    while( p_port != (osm_port_t*)cl_qmap_end( p_tbl ) )
-    {
-      __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw, requester_port, p_port,
-                                        p_dest_port, comp_mask, p_list );
-      p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item );
-    }
-  }
-
-  OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- **********************************************************************/
-static void
-__osm_pr_rcv_process_pair(
-  IN osm_pr_rcv_t*         const p_rcv,
-  IN const osm_madw_t*     const p_madw,
-  IN const osm_port_t*     const requester_port,
-  IN const osm_port_t*     const p_src_port,
-  IN const osm_port_t*     const p_dest_port,
-  IN const ib_net64_t      comp_mask,
-  IN cl_qlist_t*           const p_list )
-{
-  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_process_pair );
-
-  __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw, requester_port, p_src_port,
-                                    p_dest_port, comp_mask, p_list );
-
-  OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- *********************************************************************/
-static void
-__search_mgrp_by_mgid(
-  IN  cl_map_item_t* const      p_map_item,
-  IN  void*                     context )
-{
-  osm_mgrp_t*                   p_mgrp = (osm_mgrp_t*)p_map_item;
-  osm_sa_pr_mcmr_search_ctxt_t *p_ctxt = (osm_sa_pr_mcmr_search_ctxt_t *) context;
-  const ib_gid_t               *p_recvd_mgid;
-  osm_pr_rcv_t                 *p_rcv;
-  /* uint32_t  i; */
-
-  p_recvd_mgid = p_ctxt->p_mgid;
-  p_rcv = p_ctxt->p_rcv;
-
-  /* ignore groups marked for deletion */
-  if ( p_mgrp->to_be_deleted )
-    return;
-
-  /* compare entire MGID so different scope will not sneak in for
-     the same MGID */
-  if ( memcmp( &p_mgrp->mcmember_rec.mgid,
-                p_recvd_mgid,
-                sizeof(ib_gid_t) ) )
-    return;
-
-#if 0
-  for ( i = 0 ; i < sizeof(p_mgrp->mcmember_rec.mgid.multicast.raw_group_id); i++)
-  {
-    if ( p_mgrp->mcmember_rec.mgid.multicast.raw_group_id[i] !=
-         p_recvd_mgid->mgid.multicast.raw_group_id[i] )
-      return;
-  }
-#endif
-
-  if( p_ctxt->p_mgrp )
-  {
-    osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-             "__search_mgrp_by_mgid: ERR 1F08: "
-             "Multiple MC groups for same MGID\n" );
-    return;
-  }
-  p_ctxt->p_mgrp = p_mgrp;
-}
-
-/**********************************************************************
- **********************************************************************/
-static ib_api_status_t
-__get_mgrp_by_mgid(
-  IN osm_pr_rcv_t*             const p_rcv,
-  IN ib_path_rec_t*            p_recvd_path_rec,
-  OUT osm_mgrp_t **            pp_mgrp )
-{
-  osm_sa_pr_mcmr_search_ctxt_t mcmr_search_context;
-
-  mcmr_search_context.p_mgid = &p_recvd_path_rec->dgid;
-  mcmr_search_context.p_rcv = p_rcv;
-  mcmr_search_context.p_mgrp = NULL;
-
-  cl_qmap_apply_func( &p_rcv->p_subn->mgrp_mlid_tbl,
-                      __search_mgrp_by_mgid,
-                      &mcmr_search_context);
-
-  if( mcmr_search_context.p_mgrp == NULL )
-  {
-    return IB_NOT_FOUND;
-  }
-
-  *pp_mgrp = mcmr_search_context.p_mgrp;
-  return IB_SUCCESS;
-}
-
-/**********************************************************************
- **********************************************************************/
-static osm_mgrp_t *
-__get_mgrp_by_mlid(
-  IN const osm_pr_rcv_t* const p_rcv,
-  IN ib_net16_t          const mlid )
-{
-  cl_map_item_t *        map_item;
-
-  map_item = cl_qmap_get( &p_rcv->p_subn->mgrp_mlid_tbl, mlid );
-
-  if( map_item == cl_qmap_end(&p_rcv->p_subn->mgrp_mlid_tbl) )
-  {
-    return NULL;
-  }
-
-  return (osm_mgrp_t *)map_item;
-}
-
-/**********************************************************************
- **********************************************************************/
-static void
-__osm_pr_get_mgrp(
-  IN osm_pr_rcv_t*         const p_rcv,
-  IN const osm_madw_t*     const p_madw,
-  OUT osm_mgrp_t           **pp_mgrp )
-{
-  ib_path_rec_t*           p_pr;
-  const ib_sa_mad_t*       p_sa_mad;
-  ib_net64_t               comp_mask;
-  ib_api_status_t          status;
-
-  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_get_mgrp );
-
-  p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
-  p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
-
-  comp_mask = p_sa_mad->comp_mask;
-
-  if( comp_mask & IB_PR_COMPMASK_DGID )
-  {
-    status = __get_mgrp_by_mgid( p_rcv, p_pr, pp_mgrp );
-    if( status != IB_SUCCESS )
-    {
-      osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-               "__osm_pr_get_mgrp: ERR 1F09: "
-               "No MC group found for PathRecord destination GID\n" );
-      goto Exit;
-    }
-  }
-
-  if( comp_mask & IB_PR_COMPMASK_DLID )
-  {
-    if( *pp_mgrp)
-    {
-      /* check that the MLID in the MC group is */
-      /* the same as the DLID in the PathRecord */
-      if( (*pp_mgrp)->mlid != p_pr->dlid )
-      {
-       /* Note: perhaps this might be better indicated as an invalid request */
-        osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-                 "__osm_pr_get_mgrp: ERR 1F10: "
-                 "MC group MLID does not match PathRecord destination LID\n" );
-        *pp_mgrp = NULL;
-        goto Exit;
-      }
-    }
-    else
-    {
-      *pp_mgrp = __get_mgrp_by_mlid( p_rcv, p_pr->dlid );
-      if( *pp_mgrp == NULL)
-      {
-        osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-                 "__osm_pr_get_mgrp: ERR 1F11: "
-                 "No MC group found for PathRecord destination LID\n" );
-      }
-    }
-  }
-
- Exit:
-  OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- **********************************************************************/
-static ib_api_status_t
-__osm_pr_match_mgrp_attributes(
-  IN osm_pr_rcv_t*         const p_rcv,
-  IN const osm_madw_t*     const p_madw,
-  IN const osm_mgrp_t*     const p_mgrp )
-{
-  const ib_path_rec_t*     p_pr;
-  const ib_sa_mad_t*       p_sa_mad;
-  ib_net64_t               comp_mask;
-  ib_api_status_t          status = IB_ERROR;
-  uint32_t                 flow_label;
-  uint8_t                  sl;
-  uint8_t                  hop_limit;
-
-  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_match_mgrp_attributes );
-
-  p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
-  p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
-
-  comp_mask = p_sa_mad->comp_mask;
-
-  /* If SGID and/or SLID specified, should validate as member of MC group */
-  /* Also, MTU, rate, packet lifetime, and raw traffic requested are not currently checked */
-  if( comp_mask & IB_PR_COMPMASK_PKEY )
-  {
-    if( p_pr->pkey != p_mgrp->mcmember_rec.pkey )
-      goto Exit;
-  }
-
-  ib_member_get_sl_flow_hop( p_mgrp->mcmember_rec.sl_flow_hop,
-                             &sl, &flow_label, &hop_limit );
-
-  if( comp_mask & IB_PR_COMPMASK_SL )
-  {
-    if( ib_path_rec_sl( p_pr ) != sl )
-      goto Exit;
-  }
-
-  /* If SubnAdmGet, assume NumbPaths of 1 (1.2 erratum) */
-  if( ( comp_mask & IB_PR_COMPMASK_NUMBPATH ) &&
-      ( p_sa_mad->method != IB_MAD_METHOD_GET ) )
-  {
-    if( ib_path_rec_num_path( p_pr ) == 0 )
-      goto Exit;
-  }
-
-  if( comp_mask & IB_PR_COMPMASK_FLOWLABEL )
-  {
-    if( ib_path_rec_flow_lbl( p_pr ) != flow_label )
-      goto Exit;
-  }
-
-  if( comp_mask & IB_PR_COMPMASK_HOPLIMIT )
-  {
-    if( ib_path_rec_hop_limit( p_pr ) != hop_limit )
-      goto Exit;
-  }
-
-  if( comp_mask & IB_PR_COMPMASK_TCLASS )
-  {
-    if( p_pr->tclass != p_mgrp->mcmember_rec.tclass )
-      goto Exit;
-  }
-
-  status = IB_SUCCESS;
-
- Exit:
-  OSM_LOG_EXIT( p_rcv->p_log );
-  return( status );
-}
-
-/**********************************************************************
- **********************************************************************/
-static int
-__osm_pr_rcv_check_mcast_dest(
-  IN osm_pr_rcv_t*         const p_rcv,
-  IN const osm_madw_t*     const p_madw )
-{
-  const ib_path_rec_t*     p_pr;
-  const ib_sa_mad_t*       p_sa_mad;
-  ib_net64_t               comp_mask;
-  int                      is_multicast = 0;
-
-  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_check_mcast_dest );
-
-  p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
-  p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
-
-  comp_mask = p_sa_mad->comp_mask;
-
-  if( comp_mask & IB_PR_COMPMASK_DGID )
-  {
-    is_multicast = ib_gid_is_multicast( &p_pr->dgid );
-    if( !is_multicast )
-      goto Exit;
-  }
-
-  if( comp_mask & IB_PR_COMPMASK_DLID )
-  {
-    if( cl_ntoh16( p_pr->dlid ) >= IB_LID_MCAST_START_HO &&
-        cl_ntoh16( p_pr->dlid ) <= IB_LID_MCAST_END_HO )
-      is_multicast = 1;
-    else if( is_multicast )
-    {
-      osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-               "__osm_pr_rcv_check_mcast_dest: ERR 1F12: "
-               "PathRecord request indicates MGID but not MLID\n" );
-      is_multicast = -1;
-    }
-  }
-
- Exit:
-  OSM_LOG_EXIT( p_rcv->p_log );
-  return( is_multicast );
-}
-
-/**********************************************************************
- **********************************************************************/
-static void
-__osm_pr_rcv_respond(
-  IN osm_pr_rcv_t*         const p_rcv,
-  IN const osm_madw_t*     const p_madw,
-  IN cl_qlist_t*           const p_list )
-{
-  osm_madw_t*              p_resp_madw;
-  const ib_sa_mad_t*       p_sa_mad;
-  ib_sa_mad_t*             p_resp_sa_mad;
-  size_t                   num_rec, pre_trim_num_rec;
-#ifndef VENDOR_RMPP_SUPPORT
-  size_t                  trim_num_rec;
-#endif
-  ib_path_rec_t*           p_resp_pr;
-  ib_api_status_t          status;
-  const ib_sa_mad_t*       p_rcvd_mad = osm_madw_get_sa_mad_ptr( p_madw );
-  osm_pr_item_t*           p_pr_item;
-  uint32_t                 i;
-
-  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_respond );
-
-  num_rec = cl_qlist_count( p_list );
-
-  /*
-   * C15-0.1.30:
-   * If we do a SubnAdmGet and got more than one record it is an error !
-   */
-  if (p_rcvd_mad->method == IB_MAD_METHOD_GET)
-  {
-    if (num_rec == 0)
-    {
-      osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS );
-      goto Exit;
-    }
-    if (num_rec > 1)
-    {
-      osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-               "__osm_pr_rcv_respond: ERR 1F13: "
-               "Got more than one record for SubnAdmGet (%zu)\n",
-               num_rec );
-      osm_sa_send_error( p_rcv->p_resp, p_madw,
-                         IB_SA_MAD_STATUS_TOO_MANY_RECORDS );
-      /* need to set the mem free ... */
-      p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );
-      while( p_pr_item != (osm_pr_item_t*)cl_qlist_end( p_list ) )
-      {
-        cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );
-        p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );
-      }
-      goto Exit;
-    }
-  }
-
-  pre_trim_num_rec = num_rec;
-#ifndef VENDOR_RMPP_SUPPORT
-  trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_path_rec_t);
-  if (trim_num_rec < num_rec)
-  {
-    osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
-             "__osm_pr_rcv_respond: "
-             "Number of records:%u trimmed to:%u to fit in one MAD\n",
-             num_rec,trim_num_rec );
-    num_rec = trim_num_rec;
-  }
-#endif
-
-  osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
-           "__osm_pr_rcv_respond: "
-           "Generating response with %zu records\n", num_rec );
-
-  if ((p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec == 0))
-  {
-    osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS );
-    goto Exit;
-  }
-
-  /*
-   * Get a MAD to reply. Address of Mad is in the received mad_wrapper
-   */
-  p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, p_madw->h_bind,
-                                  num_rec * sizeof(ib_path_rec_t) + IB_SA_MAD_HDR_SIZE,
-                                  &p_madw->mad_addr );
-  if( !p_resp_madw )
-  {
-    osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-             "__osm_pr_rcv_respond: ERR 1F14: "
-             "Unable to allocate MAD\n" );
-
-    for( i = 0; i < num_rec; i++ )
-    {
-      p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );
-      cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );
-    }
-
-    osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES );
-    goto Exit;
-  }
-
-  p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
-  p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_resp_madw );
-
-  memcpy( p_resp_sa_mad, p_sa_mad, IB_SA_MAD_HDR_SIZE );
-  p_resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;
-  /* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) */
-  p_resp_sa_mad->sm_key = 0;
-  /* Fill in the offset (paylen will be done by the rmpp SAR) */
-  p_resp_sa_mad->attr_offset = ib_get_attr_offset( sizeof(ib_path_rec_t) );
-
-  p_resp_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_resp_sa_mad );
-
-#ifndef VENDOR_RMPP_SUPPORT
-  /* we support only one packet RMPP - so we will set the first and
-     last flags for gettable */
-  if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP)
-  {
-    p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA;
-    p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_FIRST | IB_RMPP_FLAG_LAST | IB_RMPP_FLAG_ACTIVE;
-  }
-#else
-  /* forcefully define the packet as RMPP one */
-  if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP)
-    p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE;
-#endif
-
-  for ( i = 0; i < pre_trim_num_rec; i++ )
-  {
-    p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );
-    /* copy only if not trimmed */
-    if (i < num_rec)
-        *p_resp_pr = p_pr_item->path_rec;
-
-    cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );
-    p_resp_pr++;
-  }
-
-  CL_ASSERT( cl_is_qlist_empty( p_list ) );
-
-  status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE );
-
-  if( status != IB_SUCCESS )
-  {
-    osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-             "__osm_pr_rcv_respond: ERR 1F15: "
-             "Unable to send MAD (%s)\n", ib_get_err_str( status ) );
-    /*  osm_mad_pool_put( p_rcv->p_mad_pool, p_resp_madw ); */
-  }
-
- Exit:
-  OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- **********************************************************************/
-void
-osm_pr_rcv_process(
-  IN osm_pr_rcv_t*         const p_rcv,
-  IN const osm_madw_t*     const p_madw )
-{
-  const ib_path_rec_t*     p_pr;
-  const ib_sa_mad_t*       p_sa_mad;
-  const osm_port_t*        p_src_port;
-  const osm_port_t*        p_dest_port;
-  cl_qlist_t               pr_list;
-  ib_net16_t               sa_status;
-  osm_port_t*              requester_port;
-  int ret;
-
-  OSM_LOG_ENTER( p_rcv->p_log, osm_pr_rcv_process );
-
-  CL_ASSERT( p_madw );
-
-  p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
-  p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
-
-  CL_ASSERT( p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD );
-
-  /* we only support SubnAdmGet and SubnAdmGetTable methods */
-  if ((p_sa_mad->method != IB_MAD_METHOD_GET) &&
-      (p_sa_mad->method != IB_MAD_METHOD_GETTABLE)) {
-    osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-             "osm_pr_rcv_process: ERR 1F17: " 
-             "Unsupported Method (%s)\n",
-             ib_get_sa_method_str( p_sa_mad->method ) );
-    osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR );
-    goto Exit;
-  }
-
-  /* update the requester physical port. */
-  requester_port = osm_get_port_by_mad_addr( p_rcv->p_log, p_rcv->p_subn,
-                                             osm_madw_get_mad_addr_ptr( p_madw ) );
-  if( requester_port == NULL )
-  {
-    osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-             "osm_pr_rcv_process: ERR 1F16: "
-             "Cannot find requester physical port\n" );
-    goto Exit;
-  }
-
-  if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
-    osm_dump_path_record( p_rcv->p_log, p_pr, OSM_LOG_DEBUG );
-
-  cl_qlist_init( &pr_list );
-
-  /*
-    Most SA functions (including this one) are read-only on the
-    subnet object, so we grab the lock non-exclusively.
-  */
-  cl_plock_acquire( p_rcv->p_lock );
-
-  /* Handle multicast destinations separately */
-  if( (ret = __osm_pr_rcv_check_mcast_dest( p_rcv, p_madw )) < 0 )
-  {
-    /* Multicast DGID with unicast DLID */
-    cl_plock_release( p_rcv->p_lock );
-    osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_INVALID_FIELD );
-    goto Exit;
-  }
-
-  if(ret > 0)
-    goto McastDest;
-
-  osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
-           "osm_pr_rcv_process: "
-           "Unicast destination requested\n" );
-
-  sa_status = __osm_pr_rcv_get_end_points( p_rcv, p_madw,
-                                           &p_src_port, &p_dest_port );
-
-  if( sa_status == IB_SA_MAD_STATUS_SUCCESS )
-  {
-    /*
-      What happens next depends on the type of endpoint information
-      that was specified....
-    */
-    if( p_src_port )
-    {
-      if( p_dest_port )
-        __osm_pr_rcv_process_pair( p_rcv, p_madw, requester_port,
-                                   p_src_port, p_dest_port,
-                                   p_sa_mad->comp_mask, &pr_list );
-      else
-        __osm_pr_rcv_process_half( p_rcv, p_madw, requester_port,
-                                   p_src_port, NULL,
-                                   p_sa_mad->comp_mask, &pr_list );
-    }
-    else
-    {
-      if( p_dest_port )
-        __osm_pr_rcv_process_half( p_rcv, p_madw, requester_port,
-                                   NULL, p_dest_port,
-                                   p_sa_mad->comp_mask, &pr_list );
-      else
-        /*
-          Katie, bar the door!
-        */
-        __osm_pr_rcv_process_world( p_rcv, p_madw, requester_port,
-                                    p_sa_mad->comp_mask, &pr_list );
-    }
-  }
-  goto Unlock;
-
- McastDest:
-  osm_log(p_rcv->p_log, OSM_LOG_DEBUG,
-             "osm_pr_rcv_process: "
-             "Multicast destination requested\n" );
-  {
-    osm_mgrp_t *p_mgrp = NULL;
-    ib_api_status_t status;
-    osm_pr_item_t* p_pr_item;
-    uint32_t flow_label;
-    uint8_t  sl;
-    uint8_t  hop_limit;
-
-    /* First, get the MC info */
-    __osm_pr_get_mgrp( p_rcv, p_madw, &p_mgrp );
-
-    if ( p_mgrp )
-    {
-      /* Make sure the rest of the PathRecord matches the MC group attributes */
-      status = __osm_pr_match_mgrp_attributes( p_rcv, p_madw, p_mgrp );
-      if ( status == IB_SUCCESS )
-      {
-        p_pr_item = (osm_pr_item_t*)cl_qlock_pool_get( &p_rcv->pr_pool );
-        if( p_pr_item == NULL )
-        {
-          osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-                   "osm_pr_rcv_process: ERR 1F18: "
-                   "Unable to allocate path record for MC group\n" );
-        }
-        else
-        {
-         /* Copy PathRecord request into response */
-          p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
-          p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
-          p_pr_item->path_rec = *p_pr;
-
-          /* Now, use the MC info to cruft up the PathRecord response */        
-          p_pr_item->path_rec.dgid = p_mgrp->mcmember_rec.mgid;
-          p_pr_item->path_rec.dlid = p_mgrp->mcmember_rec.mlid;
-         p_pr_item->path_rec.tclass = p_mgrp->mcmember_rec.tclass;
-         p_pr_item->path_rec.num_path = 1;
-         p_pr_item->path_rec.pkey = p_mgrp->mcmember_rec.pkey;
-
-         /* MTU, rate, and packet lifetime should be exactly */
-         p_pr_item->path_rec.mtu = (2<<6) | p_mgrp->mcmember_rec.mtu;
-          p_pr_item->path_rec.rate = (2<<6) | p_mgrp->mcmember_rec.rate;
-          p_pr_item->path_rec.pkt_life = (2<<6) | p_mgrp->mcmember_rec.pkt_life;
-
-         /* SL, Hop Limit, and Flow Label */
-          ib_member_get_sl_flow_hop( p_mgrp->mcmember_rec.sl_flow_hop,
-                                     &sl, &flow_label, &hop_limit );
-         p_pr_item->path_rec.sl = cl_hton16( sl );
-          p_pr_item->path_rec.hop_flow_raw = (uint32_t)(hop_limit) |
-                                             (flow_label << 8);
-
-          cl_qlist_insert_tail( &pr_list,
-                                (cl_list_item_t*)&p_pr_item->pool_item );
-
-        }
-      }
-      else
-      {
-        osm_log( p_rcv->p_log, OSM_LOG_ERROR,
-                 "osm_pr_rcv_process: ERR 1F19: "
-                 "MC group attributes don't match PathRecord request\n" );
-      }
-    }
-  }
-
- Unlock:
-  cl_plock_release( p_rcv->p_lock );
-
-  /* Now, (finally) respond to the PathRecord request */
-  __osm_pr_rcv_respond( p_rcv, p_madw, &pr_list );
-
- Exit:
-  OSM_LOG_EXIT( p_rcv->p_log );
-}
-
+/*\r
+ * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.\r
+ * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved.\r
+ * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+/*\r
+ * Abstract:\r
+ *    Implementation of osm_pr_rcv_t.\r
+ * This object represents the PathRecord Receiver object.\r
+ * This object is part of the opensm family of objects.\r
+ *\r
+ * Environment:\r
+ *    Linux User Mode\r
+ *\r
+ * $Revision: 1.10 $\r
+ */\r
+\r
+#if HAVE_CONFIG_H\r
+#  include <config.h>\r
+#endif /* HAVE_CONFIG_H */\r
+\r
+#include <string.h>\r
+#include <iba/ib_types.h>\r
+#include <complib/cl_qmap.h>\r
+#include <complib/cl_passivelock.h>\r
+#include <complib/cl_debug.h>\r
+#include <complib/cl_qlist.h>\r
+#include <opensm/osm_base.h>\r
+#include <opensm/osm_sa_path_record.h>\r
+#include <opensm/osm_port.h>\r
+#include <opensm/osm_node.h>\r
+#include <opensm/osm_switch.h>\r
+#include <vendor/osm_vendor.h>\r
+#include <vendor/osm_vendor_api.h>\r
+#include <opensm/osm_helper.h>\r
+#include <opensm/osm_pkey.h>\r
+#include <opensm/osm_multicast.h>\r
+#include <opensm/osm_partition.h>\r
+\r
+#define OSM_PR_RCV_POOL_MIN_SIZE    64\r
+#define OSM_PR_RCV_POOL_GROW_SIZE   64\r
+\r
+typedef  struct   _osm_pr_item\r
+{\r
+  cl_pool_item_t     pool_item;\r
+  ib_path_rec_t      path_rec;\r
+} osm_pr_item_t;\r
+\r
+typedef struct _osm_path_parms\r
+{\r
+  ib_net16_t         pkey;\r
+  uint8_t            mtu;\r
+  uint8_t            rate;\r
+  uint8_t            sl;\r
+  uint8_t            pkt_life;\r
+  boolean_t          reversible;\r
+} osm_path_parms_t;\r
+\r
+typedef  struct   osm_sa_pr_mcmr_search_ctxt {\r
+  ib_gid_t        *p_mgid;\r
+  osm_mgrp_t      *p_mgrp;\r
+  osm_pr_rcv_t    *p_rcv;\r
+} osm_sa_pr_mcmr_search_ctxt_t;\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+void\r
+osm_pr_rcv_construct(\r
+  IN osm_pr_rcv_t* const p_rcv )\r
+{\r
+  memset( p_rcv, 0, sizeof(*p_rcv) );\r
+  cl_qlock_pool_construct( &p_rcv->pr_pool );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+void\r
+osm_pr_rcv_destroy(\r
+  IN osm_pr_rcv_t* const p_rcv )\r
+{\r
+  OSM_LOG_ENTER( p_rcv->p_log, osm_pr_rcv_destroy );\r
+  cl_qlock_pool_destroy( &p_rcv->pr_pool );\r
+  OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+ib_api_status_t\r
+osm_pr_rcv_init(\r
+  IN osm_pr_rcv_t*      const p_rcv,\r
+  IN osm_sa_resp_t*     const p_resp,\r
+  IN osm_mad_pool_t*    const p_mad_pool,\r
+  IN osm_subn_t*        const p_subn,\r
+  IN osm_log_t*         const p_log,\r
+  IN cl_plock_t*        const p_lock )\r
+{\r
+  ib_api_status_t       status;\r
+\r
+  OSM_LOG_ENTER( p_log, osm_pr_rcv_init );\r
+\r
+  osm_pr_rcv_construct( p_rcv );\r
+\r
+  p_rcv->p_log = p_log;\r
+  p_rcv->p_subn = p_subn;\r
+  p_rcv->p_lock = p_lock;\r
+  p_rcv->p_resp = p_resp;\r
+  p_rcv->p_mad_pool = p_mad_pool;\r
+\r
+  status = cl_qlock_pool_init( &p_rcv->pr_pool,\r
+                               OSM_PR_RCV_POOL_MIN_SIZE,\r
+                               0,\r
+                               OSM_PR_RCV_POOL_GROW_SIZE,\r
+                               sizeof(osm_pr_item_t),\r
+                               NULL, NULL, NULL );\r
+\r
+  OSM_LOG_EXIT( p_rcv->p_log );\r
+  return( status );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static inline boolean_t\r
+__osm_sa_path_rec_is_tavor_port(\r
+  IN const osm_port_t*     const p_port)\r
+{\r
+  osm_node_t const* p_node;\r
+  ib_net32_t vend_id;\r
+\r
+  p_node = osm_port_get_parent_node( p_port );\r
+  vend_id = ib_node_info_get_vendor_id( &p_node->node_info );\r
+       \r
+  return( (p_node->node_info.device_id == CL_HTON16(23108)) &&\r
+         ((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) || \r
+          (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) || \r
+          (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) || \r
+          (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE))) );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static boolean_t\r
+ __osm_sa_path_rec_apply_tavor_mtu_limit(\r
+  IN const ib_path_rec_t*  const p_pr,\r
+  IN const osm_port_t*     const p_src_port,\r
+  IN const osm_port_t*     const p_dest_port,\r
+  IN const ib_net64_t      comp_mask)\r
+{\r
+  uint8_t required_mtu;\r
+       \r
+  /* only if at least one of the ports is a Tavor device */\r
+  if (! __osm_sa_path_rec_is_tavor_port(p_src_port) && \r
+      ! __osm_sa_path_rec_is_tavor_port(p_dest_port) )\r
+    return( FALSE );\r
+\r
+  /*\r
+    we can apply the patch if either:\r
+    1. No MTU required\r
+    2. Required MTU < \r
+    3. Required MTU = 1K or 512 or 256\r
+    4. Required MTU > 256 or 512\r
+  */\r
+  required_mtu = ib_path_rec_mtu( p_pr );\r
+  if ( ( comp_mask & IB_PR_COMPMASK_MTUSELEC ) &&\r
+       ( comp_mask & IB_PR_COMPMASK_MTU ) )\r
+  {\r
+    switch( ib_path_rec_mtu_sel( p_pr ) )\r
+    {\r
+    case 0:    /* must be greater than */\r
+    case 2:    /* exact match */\r
+      if( IB_MTU_LEN_1024 < required_mtu )\r
+        return(FALSE);\r
+      break;\r
+\r
+    case 1:    /* must be less than */\r
+               /* can't be disqualified by this one */\r
+      break;\r
+\r
+    case 3:    /* largest available */\r
+               /* the ULP intentionally requested */\r
+               /* the largest MTU possible */\r
+      return(FALSE);\r
+      break;\r
+                       \r
+    default:\r
+      /* if we're here, there's a bug in ib_path_rec_mtu_sel() */\r
+      CL_ASSERT( FALSE );\r
+      break;\r
+    }\r
+  }\r
+\r
+  return(TRUE);\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static ib_api_status_t\r
+__osm_pr_rcv_get_path_parms(\r
+  IN osm_pr_rcv_t*         const p_rcv,\r
+  IN const ib_path_rec_t*  const p_pr,\r
+  IN const osm_port_t*     const p_src_port,\r
+  IN const osm_port_t*     const p_dest_port,\r
+  IN const uint16_t        dest_lid_ho,\r
+  IN const ib_net64_t      comp_mask,\r
+  OUT osm_path_parms_t*    const p_parms )\r
+{\r
+  const osm_node_t*        p_node;\r
+  const osm_physp_t*       p_physp;\r
+  const osm_physp_t*       p_dest_physp;\r
+  const osm_prtn_t*        p_prtn;\r
+  const ib_port_info_t*    p_pi;\r
+  ib_api_status_t          status = IB_SUCCESS;\r
+  ib_net16_t               pkey;\r
+  uint8_t                  mtu;\r
+  uint8_t                  rate;\r
+  uint8_t                  pkt_life;\r
+  uint8_t                  required_mtu;\r
+  uint8_t                  required_rate;\r
+  uint8_t                  required_pkt_life;\r
+  uint8_t                  sl;\r
+  ib_net16_t               dest_lid;\r
+\r
+  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_path_parms );\r
+\r
+  dest_lid = cl_hton16( dest_lid_ho );\r
+\r
+  p_dest_physp = osm_port_get_default_phys_ptr( p_dest_port );\r
+  p_physp = osm_port_get_default_phys_ptr( p_src_port );\r
+  p_pi = osm_physp_get_port_info_ptr( p_physp );\r
+\r
+  mtu = ib_port_info_get_mtu_cap( p_pi );\r
+  rate = ib_port_info_compute_rate( p_pi );\r
+\r
+  /* \r
+    Mellanox Tavor device performance is better using 1K MTU.\r
+    If required MTU and MTU selector are such that 1K is OK \r
+    and at least one end of the path is Tavor we override the\r
+    port MTU with 1K.\r
+  */\r
+  if ( p_rcv->p_subn->opt.enable_quirks &&\r
+       __osm_sa_path_rec_apply_tavor_mtu_limit(\r
+               p_pr, p_src_port, p_dest_port, comp_mask) )\r
+    if (mtu > IB_MTU_LEN_1024) \r
+    {\r
+      mtu = IB_MTU_LEN_1024;\r
+      osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+              "__osm_pr_rcv_get_path_parms: "\r
+              "Optimized Path MTU to 1K for Mellanox Tavor device\n");\r
+    }\r
+\r
+  /*\r
+    Walk the subnet object from source to destination,\r
+    tracking the most restrictive rate and mtu values along the way...\r
+\r
+    If source port node is a switch, then p_physp should\r
+    point to the port that routes the destination lid\r
+  */\r
+\r
+  p_node = osm_physp_get_node_ptr( p_physp );\r
+\r
+  if( p_node->sw )\r
+  {\r
+    /*\r
+     * If the dest_lid_ho is equal to the lid of the switch pointed by\r
+     * p_sw then p_physp will be the physical port of the switch port zero.\r
+     */\r
+    p_physp = osm_switch_get_route_by_lid(p_node->sw, cl_ntoh16( dest_lid_ho ) );\r
+    if ( p_physp == 0 )\r
+    {\r
+      osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+               "__osm_pr_rcv_get_path_parms: ERR 1F02: "\r
+               "Cannot find routing to LID 0x%X from switch for GUID 0x%016" PRIx64 "\n",\r
+               dest_lid_ho,\r
+               cl_ntoh64( osm_node_get_node_guid( p_node ) ) );\r
+      status = IB_ERROR;\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+  /*\r
+   * Same as above\r
+   */\r
+  p_node = osm_physp_get_node_ptr( p_dest_physp );\r
+\r
+  if( p_node->sw )\r
+  {\r
+    p_dest_physp = osm_switch_get_route_by_lid( p_node->sw, cl_ntoh16( dest_lid_ho ) );\r
+\r
+    if ( p_dest_physp == 0 )\r
+    {\r
+      osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+               "__osm_pr_rcv_get_path_parms: ERR 1F03: "\r
+               "Cannot find routing to LID 0x%X from switch for GUID 0x%016" PRIx64 "\n",\r
+               dest_lid_ho,\r
+               cl_ntoh64( osm_node_get_node_guid( p_node ) ) );\r
+      status = IB_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+  }\r
+\r
+  while( p_physp != p_dest_physp )\r
+  {\r
+    p_physp = osm_physp_get_remote( p_physp );\r
+\r
+    if ( p_physp == 0 )\r
+    {\r
+      osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+               "__osm_pr_rcv_get_path_parms: ERR 1F05: "\r
+               "Cannot find remote phys port when routing to LID 0x%X from node GUID 0x%016" PRIx64 "\n",\r
+               dest_lid_ho,\r
+               cl_ntoh64( osm_node_get_node_guid( p_node ) ) );\r
+      status = IB_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+    /*\r
+      This is point to point case (no switch in between)\r
+    */\r
+    if( p_physp == p_dest_physp )\r
+      break;\r
+\r
+    p_node = osm_physp_get_node_ptr( p_physp );\r
+\r
+    if( !p_node->sw )\r
+    {\r
+      /*\r
+        There is some sort of problem in the subnet object!\r
+        If this isn't a switch, we should have reached\r
+        the destination by now!\r
+      */\r
+      osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+               "__osm_pr_rcv_get_path_parms: ERR 1F06: "\r
+               "Internal error, bad path\n" );\r
+      status = IB_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+    /*\r
+      Check parameters for the ingress port in this switch.\r
+    */\r
+    p_pi = osm_physp_get_port_info_ptr( p_physp );\r
+\r
+    if( mtu > ib_port_info_get_mtu_cap( p_pi ) )\r
+    {\r
+      mtu = ib_port_info_get_mtu_cap( p_pi );\r
+      if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+      {\r
+        osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+                 "__osm_pr_rcv_get_path_parms: "\r
+                 "New smallest MTU = %u at intervening port 0x%016" PRIx64\r
+                 " port num 0x%X\n",\r
+                 mtu,\r
+                 cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),\r
+                 osm_physp_get_port_num( p_physp ) );\r
+      }\r
+    }\r
+\r
+    if( rate > ib_port_info_compute_rate( p_pi ) )\r
+    {\r
+      rate = ib_port_info_compute_rate( p_pi );\r
+      if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+      {\r
+        osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+                 "__osm_pr_rcv_get_path_parms: "\r
+                 "New smallest rate = %u at intervening port 0x%016" PRIx64\r
+                 " port num 0x%X\n",\r
+                 rate,\r
+                 cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),\r
+                 osm_physp_get_port_num( p_physp ) );\r
+      }\r
+    }\r
+\r
+    /*\r
+      Continue with the egress port on this switch.\r
+    */\r
+    p_physp = osm_switch_get_route_by_lid( p_node->sw, dest_lid );\r
+\r
+    if ( p_physp == 0 )\r
+    {\r
+      osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+               "__osm_pr_rcv_get_path_parms: ERR 1F07: "\r
+               "Dead end on path to LID 0x%X from switch for GUID 0x%016" PRIx64 "\n",\r
+               dest_lid_ho,\r
+               cl_ntoh64( osm_node_get_node_guid( p_node ) ) );\r
+      status = IB_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+    CL_ASSERT( p_physp );\r
+    CL_ASSERT( osm_physp_is_valid( p_physp ) );\r
+\r
+    p_pi = osm_physp_get_port_info_ptr( p_physp );\r
+\r
+    if( mtu > ib_port_info_get_mtu_cap( p_pi ) )\r
+    {\r
+      mtu = ib_port_info_get_mtu_cap( p_pi );\r
+      if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+      {\r
+        osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+                 "__osm_pr_rcv_get_path_parms: "\r
+                 "New smallest MTU = %u at intervening port 0x%016" PRIx64\r
+                 " port num 0x%X\n",\r
+                 mtu,\r
+                 cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),\r
+                 osm_physp_get_port_num( p_physp ) );\r
+      }\r
+    }\r
+\r
+    if( rate > ib_port_info_compute_rate( p_pi ) )\r
+    {\r
+      rate = ib_port_info_compute_rate( p_pi );\r
+      if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+      {\r
+        osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+                 "__osm_pr_rcv_get_path_parms: "\r
+                 "New smallest rate = %u at intervening port 0x%016" PRIx64\r
+                 " port num 0x%X\n",\r
+                 rate,\r
+                 cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),\r
+                 osm_physp_get_port_num( p_physp ) );\r
+      }\r
+    }\r
+\r
+  }\r
+\r
+  /*\r
+    p_physp now points to the destination\r
+  */\r
+  p_pi = osm_physp_get_port_info_ptr( p_physp );\r
+\r
+  if( mtu > ib_port_info_get_mtu_cap( p_pi ) )\r
+  {\r
+    mtu = ib_port_info_get_mtu_cap( p_pi );\r
+    if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+    {\r
+      osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+               "__osm_pr_rcv_get_path_parms: "\r
+               "New smallest MTU = %u at destination port 0x%016" PRIx64 "\n",\r
+               mtu,\r
+               cl_ntoh64(osm_physp_get_port_guid( p_physp )) );\r
+    }\r
+  }\r
+\r
+  if( rate > ib_port_info_compute_rate( p_pi ) )\r
+  {\r
+    rate = ib_port_info_compute_rate( p_pi );\r
+    if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+    {\r
+      osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+               "__osm_pr_rcv_get_path_parms: "\r
+               "New smallest rate = %u at destination port 0x%016" PRIx64 "\n",\r
+               rate,\r
+               cl_ntoh64(osm_physp_get_port_guid( p_physp )) );\r
+    }\r
+  }\r
+\r
+  if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+  {\r
+    osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+             "__osm_pr_rcv_get_path_parms: "\r
+             "Path min MTU = %u, min rate = %u\n", mtu, rate );\r
+  }\r
+\r
+  /*\r
+    Determine if these values meet the user criteria\r
+    and adjust appropriately\r
+  */\r
+\r
+  /* we silently ignore cases where only the MTU selector is defined */\r
+  if ( ( comp_mask & IB_PR_COMPMASK_MTUSELEC ) &&\r
+       ( comp_mask & IB_PR_COMPMASK_MTU ) )\r
+  {\r
+    required_mtu = ib_path_rec_mtu( p_pr );\r
+    switch( ib_path_rec_mtu_sel( p_pr ) )\r
+    {\r
+    case 0:    /* must be greater than */\r
+      if( mtu <= required_mtu )\r
+        status = IB_NOT_FOUND;\r
+      break;\r
+\r
+    case 1:    /* must be less than */\r
+       if( mtu >= required_mtu )\r
+       {\r
+          /* adjust to use the highest mtu\r
+             lower then the required one */\r
+          if( required_mtu > 1 )\r
+            mtu = required_mtu - 1;\r
+          else\r
+            status = IB_NOT_FOUND;\r
+       }\r
+      break;\r
+\r
+    case 2:    /* exact match */\r
+      if( mtu < required_mtu )\r
+        status = IB_NOT_FOUND;\r
+      else\r
+        mtu = required_mtu;\r
+      break;\r
+\r
+    case 3:    /* largest available */\r
+      /* can't be disqualified by this one */\r
+      break;\r
+\r
+    default:\r
+      /* if we're here, there's a bug in ib_path_rec_mtu_sel() */\r
+      CL_ASSERT( FALSE );\r
+      status = IB_ERROR;\r
+      break;\r
+    }\r
+  }\r
+\r
+  /* we silently ignore cases where only the Rate selector is defined */\r
+  if ( ( comp_mask & IB_PR_COMPMASK_RATESELEC ) &&\r
+       ( comp_mask & IB_PR_COMPMASK_RATE ) )\r
+  {\r
+    required_rate = ib_path_rec_rate( p_pr );\r
+    switch( ib_path_rec_rate_sel( p_pr ) )\r
+    {\r
+    case 0:    /* must be greater than */\r
+      if( rate <= required_rate )\r
+        status = IB_NOT_FOUND;\r
+      break;\r
+\r
+    case 1:    /* must be less than */\r
+      if( rate >= required_rate )\r
+      {\r
+        /* adjust the rate to use the highest rate\r
+           lower then the required one */\r
+        if( required_rate > 2 )\r
+          rate = required_rate - 1;\r
+        else\r
+          status = IB_NOT_FOUND;\r
+      }\r
+      break;\r
+\r
+    case 2:    /* exact match */\r
+      if( rate < required_rate )\r
+        status = IB_NOT_FOUND;\r
+      else\r
+        rate = required_rate;\r
+      break;\r
+\r
+    case 3:    /* largest available */\r
+      /* can't be disqualified by this one */\r
+      break;\r
+\r
+    default:\r
+      /* if we're here, there's a bug in ib_path_rec_mtu_sel() */\r
+      CL_ASSERT( FALSE );\r
+      status = IB_ERROR;\r
+      break;\r
+    }\r
+  }\r
+\r
+  /* Verify the pkt_life_time */\r
+  /* According to spec definition IBA 1.2 Table 205 PacketLifeTime description,\r
+     for loopback paths, packetLifeTime shall be zero. */\r
+  if ( p_src_port == p_dest_port )\r
+    pkt_life = 0;      /* loopback */\r
+  else\r
+    pkt_life = OSM_DEFAULT_SUBNET_TIMEOUT;\r
+\r
+  /* we silently ignore cases where only the PktLife selector is defined */\r
+  if ( ( comp_mask & IB_PR_COMPMASK_PKTLIFETIMESELEC ) &&\r
+       ( comp_mask & IB_PR_COMPMASK_PKTLIFETIME ) )\r
+  {\r
+    required_pkt_life = ib_path_rec_pkt_life( p_pr );\r
+    switch( ib_path_rec_pkt_life_sel( p_pr ) )\r
+    {\r
+    case 0:    /* must be greater than */\r
+      if( pkt_life <= required_pkt_life )\r
+        status = IB_NOT_FOUND;\r
+      break;\r
+\r
+    case 1:    /* must be less than */\r
+      if( pkt_life >= required_pkt_life )\r
+      {\r
+        /* adjust the lifetime to use the highest possible\r
+           lower then the required one */\r
+        if( required_pkt_life > 1 )\r
+          pkt_life = required_pkt_life - 1;\r
+        else\r
+          status = IB_NOT_FOUND;\r
+      }\r
+      break;\r
+\r
+    case 2:    /* exact match */\r
+      if( pkt_life < required_pkt_life )\r
+         status = IB_NOT_FOUND;\r
+      else\r
+         pkt_life = required_pkt_life;\r
+      break;\r
+\r
+    case 3:    /* smallest available */\r
+      /* can't be disqualified by this one */\r
+      break;\r
+\r
+    default:\r
+      /* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */\r
+      CL_ASSERT( FALSE );\r
+      status = IB_ERROR;\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (status != IB_SUCCESS)\r
+    goto Exit;\r
+\r
+  p_parms->mtu = mtu;\r
+  p_parms->rate = rate;\r
+  p_parms->pkt_life = pkt_life;\r
+\r
+  if( comp_mask & IB_PR_COMPMASK_RAWTRAFFIC &&\r
+      cl_ntoh32( p_pr->hop_flow_raw ) & ( 1<<31 ) )\r
+    pkey = osm_physp_find_common_pkey( p_physp, p_dest_physp );\r
+  else if( comp_mask & IB_PR_COMPMASK_PKEY )\r
+  {\r
+    pkey = p_pr->pkey;\r
+    if( !osm_physp_share_this_pkey( p_physp, p_dest_physp, pkey ) )\r
+    {\r
+      osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+               "__osm_pr_rcv_get_path_parms: ERR 1F1A: "\r
+               "Ports do not share specified PKey 0x%04x\n", cl_ntoh16(pkey));\r
+      status = IB_NOT_FOUND;\r
+      goto Exit;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    pkey = osm_physp_find_common_pkey( p_physp, p_dest_physp );\r
+    if ( !pkey )\r
+    {\r
+      osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+               "__osm_pr_rcv_get_path_parms: ERR 1F1B: "\r
+               "Ports do not have any shared PKeys\n");\r
+      status = IB_NOT_FOUND;\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+  sl = OSM_DEFAULT_SL;\r
+\r
+  if (pkey) {\r
+    p_prtn = (osm_prtn_t *)cl_qmap_get(&p_rcv->p_subn->prtn_pkey_tbl,\r
+                                       pkey & cl_ntoh16((uint16_t)~0x8000));\r
+    if ( p_prtn == (osm_prtn_t *)cl_qmap_end(&p_rcv->p_subn->prtn_pkey_tbl) )\r
+    {\r
+      /* this may be possible when pkey tables are created somehow in\r
+         previous runs or things are going wrong here */\r
+      osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+               "__osm_pr_rcv_get_path_parms: ERR 1F1C: "\r
+               "No partition found for PKey 0x%04x - using default SL %d\n",\r
+               cl_ntoh16(pkey), sl );\r
+    }\r
+    else\r
+      sl = p_prtn->sl;\r
+\r
+    /* reset pkey when raw traffic */\r
+    if( comp_mask & IB_PR_COMPMASK_RAWTRAFFIC &&\r
+        cl_ntoh32( p_pr->hop_flow_raw ) & ( 1<<31 ) )\r
+      pkey = 0;\r
+  }\r
+\r
+  if ( ( comp_mask & IB_PR_COMPMASK_SL ) && ib_path_rec_sl( p_pr ) != sl )\r
+  {\r
+    status = IB_NOT_FOUND;\r
+    goto Exit;\r
+  }\r
+\r
+  p_parms->pkey = pkey;\r
+  p_parms->sl = sl;\r
+\r
+ Exit:\r
+  OSM_LOG_EXIT( p_rcv->p_log );\r
+  return( status );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static void\r
+__osm_pr_rcv_build_pr(\r
+  IN osm_pr_rcv_t*         const p_rcv,\r
+  IN const osm_port_t*     const p_src_port,\r
+  IN const osm_port_t*     const p_dest_port,\r
+  IN const uint16_t        src_lid_ho,\r
+  IN const uint16_t        dest_lid_ho,\r
+  IN const uint8_t         preference,\r
+  IN const osm_path_parms_t*  const p_parms,\r
+  OUT ib_path_rec_t*       const p_pr )\r
+{\r
+  const osm_physp_t*       p_src_physp;\r
+  const osm_physp_t*       p_dest_physp;\r
+\r
+  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_build_pr );\r
+\r
+  p_src_physp = osm_port_get_default_phys_ptr( p_src_port );\r
+  p_dest_physp = osm_port_get_default_phys_ptr( p_dest_port );\r
+\r
+  p_pr->dgid.unicast.prefix = osm_physp_get_subnet_prefix( p_dest_physp );\r
+  p_pr->dgid.unicast.interface_id = osm_physp_get_port_guid( p_dest_physp );\r
+\r
+  p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix( p_src_physp );\r
+  p_pr->sgid.unicast.interface_id = osm_physp_get_port_guid( p_src_physp );\r
+\r
+  p_pr->dlid = cl_hton16( dest_lid_ho );\r
+  p_pr->slid = cl_hton16( src_lid_ho );\r
+\r
+  p_pr->hop_flow_raw &= cl_hton32(1<<31);\r
+\r
+  p_pr->pkey = p_parms->pkey;\r
+  p_pr->qos_class_sl = cl_hton16(p_parms->sl);\r
+  p_pr->mtu = (uint8_t)(p_parms->mtu | 0x80);\r
+  p_pr->rate = (uint8_t)(p_parms->rate | 0x80);\r
+\r
+  /* According to 1.2 spec definition Table 205 PacketLifeTime description,\r
+     for loopback paths, packetLifeTime shall be zero. */\r
+  if ( p_src_port == p_dest_port )\r
+    p_pr->pkt_life = 0x80;     /* loopback */\r
+  else\r
+    p_pr->pkt_life = (uint8_t)(p_parms->pkt_life | 0x80);\r
+\r
+  p_pr->preference = preference;\r
+\r
+  /* always return num_path = 0 so this is only the reversible component */\r
+  if (p_parms->reversible)\r
+    p_pr->num_path = 0x80;\r
+\r
+  OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static osm_pr_item_t*\r
+__osm_pr_rcv_get_lid_pair_path(\r
+  IN osm_pr_rcv_t*         const p_rcv,\r
+  IN const ib_path_rec_t*  const p_pr,\r
+  IN const osm_port_t*     const p_src_port,\r
+  IN const osm_port_t*     const p_dest_port,\r
+  IN const uint16_t        src_lid_ho,\r
+  IN const uint16_t        dest_lid_ho,\r
+  IN const ib_net64_t      comp_mask,\r
+  IN const uint8_t         preference )\r
+{\r
+  osm_path_parms_t         path_parms;\r
+  osm_path_parms_t         rev_path_parms;\r
+  osm_pr_item_t            *p_pr_item;\r
+  ib_api_status_t          status, rev_path_status;\r
+\r
+  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_lid_pair_path );\r
+\r
+  if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+  {\r
+    osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+             "__osm_pr_rcv_get_lid_pair_path: "\r
+             "Src LID 0x%X, Dest LID 0x%X\n",\r
+             src_lid_ho, dest_lid_ho );\r
+  }\r
+\r
+  p_pr_item = (osm_pr_item_t*)cl_qlock_pool_get( &p_rcv->pr_pool );\r
+  if( p_pr_item == NULL )\r
+  {\r
+    osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+             "__osm_pr_rcv_get_lid_pair_path: ERR 1F01: "\r
+             "Unable to allocate path record\n" );\r
+    goto Exit;\r
+  }\r
+\r
+  status = __osm_pr_rcv_get_path_parms( p_rcv, p_pr, p_src_port,\r
+                                        p_dest_port, dest_lid_ho,\r
+                                        comp_mask, &path_parms );\r
+\r
+  if( status != IB_SUCCESS )\r
+  {\r
+    cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );\r
+    p_pr_item = NULL;\r
+    goto Exit;\r
+  }\r
+\r
+  /* now try the reversible path */\r
+  rev_path_status = __osm_pr_rcv_get_path_parms( p_rcv, p_pr, p_dest_port,\r
+                                                 p_src_port, src_lid_ho,\r
+                                                 comp_mask, &rev_path_parms );\r
+  path_parms.reversible = ( rev_path_status == IB_SUCCESS );\r
+\r
+  /* did we get a Reversible Path compmask ? */\r
+  /* \r
+     NOTE that if the reversible component = 0, it is a don't care\r
+     rather then requiring non-reversible paths ... \r
+     see Vol1 Ver1.2 p900 l16\r
+  */\r
+  if( comp_mask & IB_PR_COMPMASK_REVERSIBLE )\r
+  {\r
+    if( (! path_parms.reversible && ( p_pr->num_path & 0x80 ) ) )\r
+    {\r
+      osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+               "__osm_pr_rcv_get_lid_pair_path: "\r
+               "Requested reversible path but failed to get one\n");\r
+\r
+      cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );\r
+      p_pr_item = NULL;\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+  __osm_pr_rcv_build_pr( p_rcv, p_src_port, p_dest_port, src_lid_ho,\r
+                         dest_lid_ho, preference, &path_parms,\r
+                         &p_pr_item->path_rec );\r
+\r
+ Exit:\r
+  OSM_LOG_EXIT( p_rcv->p_log );\r
+  return( p_pr_item );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static void\r
+__osm_pr_rcv_get_port_pair_paths(\r
+  IN osm_pr_rcv_t*         const p_rcv,\r
+  IN const osm_madw_t*     const p_madw,\r
+  IN const osm_port_t*     const p_req_port,\r
+  IN const osm_port_t*     const p_src_port,\r
+  IN const osm_port_t*     const p_dest_port,\r
+  IN const ib_net64_t      comp_mask,\r
+  IN cl_qlist_t*           const p_list )\r
+{\r
+  const ib_path_rec_t*     p_pr;\r
+  const ib_sa_mad_t*       p_sa_mad;\r
+  osm_pr_item_t*           p_pr_item;\r
+  uint16_t                 src_lid_min_ho;\r
+  uint16_t                 src_lid_max_ho;\r
+  uint16_t                 dest_lid_min_ho;\r
+  uint16_t                 dest_lid_max_ho;\r
+  uint16_t                 src_lid_ho;\r
+  uint16_t                 dest_lid_ho;\r
+  uint32_t                 path_num;\r
+  uint8_t                  preference;\r
+  uintn_t                  iterations;\r
+  uintn_t                  src_offset;\r
+  uintn_t                  dest_offset;\r
+\r
+  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_port_pair_paths );\r
+\r
+  if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+  {\r
+    osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+             "__osm_pr_rcv_get_port_pair_paths: "\r
+             "Src port 0x%016" PRIx64 ", "\r
+             "Dst port 0x%016" PRIx64 "\n",\r
+             cl_ntoh64( osm_port_get_guid( p_src_port ) ),\r
+             cl_ntoh64( osm_port_get_guid( p_dest_port ) ) );\r
+  }\r
+\r
+  /* Check that the req_port, src_port and dest_port all share a\r
+     pkey. The check is done on the default physical port of the ports. */\r
+  if (osm_port_share_pkey(p_rcv->p_log, p_req_port, p_src_port) == FALSE ||\r
+      osm_port_share_pkey(p_rcv->p_log, p_req_port, p_dest_port) == FALSE ||\r
+      osm_port_share_pkey(p_rcv->p_log, p_src_port, p_dest_port) == FALSE )\r
+  {\r
+    /* One of the pairs doesn't share a pkey so the path is disqualified. */\r
+    goto Exit;\r
+  }\r
+\r
+  p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+  p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );\r
+\r
+  /*\r
+    We shouldn't be here if the paths are disqualified in some way...\r
+    Thus, we assume every possible connection is valid.\r
+\r
+    We desire to return high-quality paths first.\r
+    In OpenSM, higher quality means least overlap with other paths.\r
+    This is acheived in practice by returning paths with\r
+    different LID value on each end, which means these\r
+    paths are more redundant that paths with the same LID repeated\r
+    on one side.  For example, in OpenSM the paths between two\r
+    endpoints with LMC = 1 might be as follows:\r
+\r
+    Port A, LID 1 <-> Port B, LID 3\r
+    Port A, LID 1 <-> Port B, LID 4\r
+    Port A, LID 2 <-> Port B, LID 3\r
+    Port A, LID 2 <-> Port B, LID 4\r
+\r
+    The OpenSM unicast routing algorithms attempt to disperse each path\r
+    to as varied a physical path as is reasonable.  1<->3 and 1<->4 have\r
+    more physical overlap (hence less redundancy) than 1<->3 and 2<->4.\r
+\r
+    OpenSM ranks paths in three preference groups:\r
+\r
+    Preference Value    Description\r
+    ----------------    -------------------------------------------\r
+    0             Redundant in both directions with other\r
+    pref value = 0 paths\r
+\r
+    1             Redundant in one direction with other\r
+    pref value = 0 and pref value = 1 paths\r
+\r
+    2             Not redundant in either direction with\r
+    other paths\r
+\r
+    3-FF          Unused\r
+\r
+\r
+    SA clients don't need to know these details, only that the lower\r
+    preference paths are preferred, as stated in the spec.  The paths\r
+    may not actually be physically redundant depending on the topology\r
+    of the subnet, but the point of LMC > 0 is to offer redundancy,\r
+    so it is assumed that the subnet is physically appropriate for the\r
+    specified LMC value.  A more advanced implementation would inspect for \r
+    physical redundancy, but I'm not going to bother with that now.\r
+  */\r
+\r
+  /*\r
+    Refine our search if the client specified end-point LIDs\r
+  */\r
+  if( comp_mask & IB_PR_COMPMASK_DLID )\r
+  {\r
+    dest_lid_min_ho = cl_ntoh16( p_pr->dlid );\r
+    dest_lid_max_ho = cl_ntoh16( p_pr->dlid );\r
+  }\r
+  else\r
+  {\r
+    osm_port_get_lid_range_ho( p_dest_port, &dest_lid_min_ho,\r
+                               &dest_lid_max_ho );\r
+  }\r
+\r
+  if( comp_mask & IB_PR_COMPMASK_SLID )\r
+  {\r
+    src_lid_min_ho = cl_ntoh16( p_pr->slid );\r
+    src_lid_max_ho = cl_ntoh16( p_pr->slid );\r
+  }\r
+  else\r
+  {\r
+    osm_port_get_lid_range_ho( p_src_port, &src_lid_min_ho,\r
+                               &src_lid_max_ho );\r
+  }\r
+\r
+  if ( src_lid_min_ho == 0 )\r
+  {\r
+    osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+             "__osm_pr_rcv_get_port_pair_paths: ERR 1F20:"\r
+             "Obtained source LID of 0. No such LID possible\n");\r
+     goto Exit;\r
+  }\r
+\r
+  if ( dest_lid_min_ho == 0 )\r
+  {\r
+    osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+             "__osm_pr_rcv_get_port_pair_paths: ERR 1F21:"\r
+             "Obtained destination LID of 0. No such LID possible\n");\r
+     goto Exit;\r
+  }\r
+\r
+  if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+  {\r
+    osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+             "__osm_pr_rcv_get_port_pair_paths: "\r
+             "Src LIDs [0x%X-0x%X], "\r
+             "Dest LIDs [0x%X-0x%X]\n",\r
+             src_lid_min_ho, src_lid_max_ho,\r
+             dest_lid_min_ho, dest_lid_max_ho );\r
+  }\r
+\r
+  src_lid_ho = src_lid_min_ho;\r
+  dest_lid_ho = dest_lid_min_ho;\r
+\r
+  /*\r
+    Preferred paths come first in OpenSM\r
+  */\r
+  preference = 0;\r
+  path_num = 0;\r
+\r
+  /* If SubnAdmGet, assume NumbPaths 1 (1.2 erratum) */\r
+  if( p_sa_mad->method != IB_MAD_METHOD_GET )\r
+    if( comp_mask & IB_PR_COMPMASK_NUMBPATH )\r
+      iterations = ib_path_rec_num_path( p_pr );\r
+    else\r
+      iterations = (uintn_t)(-1);\r
+  else\r
+    iterations = 1;\r
+\r
+  while( path_num < iterations )\r
+  {\r
+    /*\r
+      These paths are "fully redundant"\r
+    */\r
+\r
+    p_pr_item = __osm_pr_rcv_get_lid_pair_path( p_rcv, p_pr,\r
+                                                p_src_port, p_dest_port,\r
+                                                src_lid_ho, dest_lid_ho,\r
+                                                comp_mask, preference );\r
+\r
+    if( p_pr_item )\r
+    {\r
+      cl_qlist_insert_tail( p_list,\r
+                            (cl_list_item_t*)&p_pr_item->pool_item );\r
+      ++path_num;\r
+    }\r
+\r
+    if( ++src_lid_ho > src_lid_max_ho )\r
+      break;\r
+\r
+    if( ++dest_lid_ho > dest_lid_max_ho )\r
+      break;\r
+  }\r
+\r
+  /*\r
+    Check if we've accumulated all the paths that the user cares to see\r
+  */\r
+  if( path_num == iterations )\r
+    goto Exit;\r
+\r
+  /*\r
+    Don't bother reporting preference 1 paths for now.\r
+    It's more trouble than it's worth and can only occur\r
+    if ports have different LMC values, which isn't supported\r
+    by OpenSM right now anyway.\r
+  */\r
+  preference = 2;\r
+  src_lid_ho = src_lid_min_ho;\r
+  dest_lid_ho = dest_lid_min_ho;\r
+  src_offset = 0;\r
+  dest_offset = 0;\r
+\r
+  /*\r
+    Iterate over the remaining paths\r
+  */\r
+  while( path_num < iterations )\r
+  {\r
+    dest_offset++;\r
+    dest_lid_ho++;\r
+\r
+    if( dest_lid_ho > dest_lid_max_ho )\r
+    {\r
+      src_offset++;\r
+      src_lid_ho++;\r
+\r
+      if( src_lid_ho > src_lid_max_ho )\r
+        break;    /* done */\r
+\r
+      dest_offset = 0;\r
+      dest_lid_ho = dest_lid_min_ho;\r
+    }\r
+\r
+    /*\r
+      These paths are "fully non-redundant" with paths already\r
+      identified above and consequently not of much value.\r
+\r
+      Don't return paths we already identified above, as indicated\r
+      by the offset values being equal.\r
+    */\r
+    if( src_offset == dest_offset )\r
+      continue;      /* already reported */\r
+\r
+    p_pr_item = __osm_pr_rcv_get_lid_pair_path( p_rcv, p_pr,\r
+                                                p_src_port, p_dest_port,\r
+                                                src_lid_ho, dest_lid_ho,\r
+                                                comp_mask, preference );\r
+\r
+    if( p_pr_item )\r
+    {\r
+      cl_qlist_insert_tail( p_list,\r
+                            (cl_list_item_t*)&p_pr_item->pool_item );\r
+      ++path_num;\r
+    }\r
+  }\r
+\r
+ Exit:\r
+  OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static ib_net16_t\r
+__osm_pr_rcv_get_end_points(\r
+  IN osm_pr_rcv_t*         const p_rcv,\r
+  IN const osm_madw_t*     const p_madw,\r
+  OUT const osm_port_t**   const pp_src_port,\r
+  OUT const osm_port_t**   const pp_dest_port )\r
+{\r
+  const ib_path_rec_t*     p_pr;\r
+  const ib_sa_mad_t*       p_sa_mad;\r
+  ib_net64_t               comp_mask;\r
+  ib_api_status_t          status;\r
+  ib_net16_t               sa_status = IB_SA_MAD_STATUS_SUCCESS;\r
+\r
+  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_end_points );\r
+\r
+  /*\r
+    Determine what fields are valid and then get a pointer\r
+    to the source and destination port objects, if possible.\r
+  */\r
+\r
+  p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+  p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );\r
+\r
+  comp_mask = p_sa_mad->comp_mask;\r
+\r
+  /*\r
+    Check a few easy disqualifying cases up front before getting\r
+    into the endpoints.\r
+  */\r
+\r
+  if( comp_mask & IB_PR_COMPMASK_SGID )\r
+  {\r
+    if ( ! ib_gid_is_link_local ( &p_pr->sgid ) )\r
+    {\r
+      if ( ib_gid_get_subnet_prefix ( &p_pr->sgid ) != p_rcv->p_subn->opt.subnet_prefix )\r
+      {\r
+        /*\r
+          This 'error' is the client's fault (bad gid) so\r
+          don't enter it as an error in our own log.\r
+          Return an error response to the client.\r
+        */\r
+        osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,\r
+                 "__osm_pr_rcv_get_end_points: "\r
+                 "Non local SGID subnet prefix 0x%016" PRIx64 "\n",\r
+                 cl_ntoh64( p_pr->sgid.unicast.prefix ) );\r
+\r
+        sa_status = IB_SA_MAD_STATUS_INVALID_GID;\r
+        goto Exit;\r
+      }\r
+    }\r
+\r
+    *pp_src_port = (osm_port_t*)cl_qmap_get(\r
+      &p_rcv->p_subn->port_guid_tbl,\r
+      p_pr->sgid.unicast.interface_id );\r
+\r
+    if( *pp_src_port == (osm_port_t*)cl_qmap_end(\r
+          &p_rcv->p_subn->port_guid_tbl ) )\r
+    {\r
+      /*\r
+        This 'error' is the client's fault (bad gid) so\r
+        don't enter it as an error in our own log.\r
+        Return an error response to the client.\r
+      */\r
+      osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,\r
+               "__osm_pr_rcv_get_end_points: "\r
+               "No source port with GUID 0x%016" PRIx64 "\n",\r
+               cl_ntoh64( p_pr->sgid.unicast.interface_id) );\r
+\r
+      sa_status = IB_SA_MAD_STATUS_INVALID_GID;\r
+      goto Exit;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    *pp_src_port = 0;\r
+    if( comp_mask & IB_PR_COMPMASK_SLID )\r
+    {\r
+      status = cl_ptr_vector_at( &p_rcv->p_subn->port_lid_tbl,\r
+                                 cl_ntoh16(p_pr->slid), (void**)pp_src_port );\r
+\r
+      if( (status != CL_SUCCESS) || (*pp_src_port == NULL) )\r
+      {\r
+        /*\r
+          This 'error' is the client's fault (bad lid) so\r
+          don't enter it as an error in our own log.\r
+          Return an error response to the client.\r
+        */\r
+        osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,\r
+                 "__osm_pr_rcv_get_end_points: "\r
+                 "No source port with LID = 0x%X\n",\r
+                 cl_ntoh16( p_pr->slid) );\r
+\r
+        sa_status = IB_SA_MAD_STATUS_NO_RECORDS;\r
+        goto Exit;\r
+      }\r
+    }\r
+  }\r
+\r
+  if( comp_mask & IB_PR_COMPMASK_DGID )\r
+  {\r
+    if ( ! ib_gid_is_link_local ( &p_pr->dgid ) )\r
+    {\r
+      if ( ! ib_gid_is_multicast ( &p_pr->dgid ) &&\r
+             ib_gid_get_subnet_prefix ( &p_pr->dgid ) != p_rcv->p_subn->opt.subnet_prefix )\r
+      {\r
+        /*\r
+          This 'error' is the client's fault (bad gid) so\r
+          don't enter it as an error in our own log.\r
+          Return an error response to the client.\r
+        */\r
+        osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,\r
+                 "__osm_pr_rcv_get_end_points: "\r
+                 "Non local DGID subnet prefix 0x%016" PRIx64 "\n",\r
+                 cl_ntoh64( p_pr->dgid.unicast.prefix ) );\r
+\r
+        sa_status = IB_SA_MAD_STATUS_INVALID_GID;\r
+        goto Exit;\r
+      }\r
+    }\r
+\r
+    *pp_dest_port = (osm_port_t*)cl_qmap_get(\r
+      &p_rcv->p_subn->port_guid_tbl,\r
+      p_pr->dgid.unicast.interface_id );\r
+\r
+    if( *pp_dest_port == (osm_port_t*)cl_qmap_end(\r
+          &p_rcv->p_subn->port_guid_tbl ) )\r
+    {\r
+      /*\r
+        This 'error' is the client's fault (bad gid) so\r
+        don't enter it as an error in our own log.\r
+        Return an error response to the client.\r
+      */\r
+      osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,\r
+               "__osm_pr_rcv_get_end_points: "\r
+               "No dest port with GUID 0x%016" PRIx64 "\n",\r
+               cl_ntoh64( p_pr->dgid.unicast.interface_id) );\r
+\r
+      sa_status = IB_SA_MAD_STATUS_INVALID_GID;\r
+      goto Exit;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    *pp_dest_port = 0;\r
+    if( comp_mask & IB_PR_COMPMASK_DLID )\r
+    {\r
+      status = cl_ptr_vector_at( &p_rcv->p_subn->port_lid_tbl,\r
+                                 cl_ntoh16(p_pr->dlid),  (void**)pp_dest_port );\r
+\r
+      if( (status != CL_SUCCESS) || (*pp_dest_port == NULL) )\r
+      {\r
+        /*\r
+          This 'error' is the client's fault (bad lid) so\r
+          don't enter it as an error in our own log.\r
+          Return an error response to the client.\r
+        */\r
+        osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,\r
+                 "__osm_pr_rcv_get_end_points: "\r
+                 "No dest port with LID = 0x%X\n",\r
+                 cl_ntoh16( p_pr->dlid) );\r
+\r
+        sa_status = IB_SA_MAD_STATUS_NO_RECORDS;\r
+        goto Exit;\r
+      }\r
+    }\r
+  }\r
+\r
+ Exit:\r
+  OSM_LOG_EXIT( p_rcv->p_log );\r
+  return( sa_status );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static void\r
+__osm_pr_rcv_process_world(\r
+  IN osm_pr_rcv_t*         const p_rcv,\r
+  IN const osm_madw_t*     const p_madw,\r
+  IN const osm_port_t*     const requester_port,\r
+  IN const ib_net64_t      comp_mask,\r
+  IN cl_qlist_t*           const p_list )\r
+{\r
+  const cl_qmap_t*         p_tbl;\r
+  const osm_port_t*        p_dest_port;\r
+  const osm_port_t*        p_src_port;\r
+\r
+  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_process_world );\r
+\r
+  /*\r
+    Iterate the entire port space over itself.\r
+    A path record from a port to itself is legit, so no\r
+    need for a special case there.\r
+\r
+    We compute both A -> B and B -> A, since we don't have\r
+    any check to determine the reversability of the paths.\r
+  */\r
+  p_tbl = &p_rcv->p_subn->port_guid_tbl;\r
+\r
+  p_dest_port = (osm_port_t*)cl_qmap_head( p_tbl );\r
+  while( p_dest_port != (osm_port_t*)cl_qmap_end( p_tbl ) )\r
+  {\r
+    p_src_port = (osm_port_t*)cl_qmap_head( p_tbl );\r
+    while( p_src_port != (osm_port_t*)cl_qmap_end( p_tbl ) )\r
+    {\r
+      __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw, requester_port, p_src_port,\r
+                                        p_dest_port, comp_mask, p_list );\r
+\r
+      p_src_port = (osm_port_t*)cl_qmap_next( &p_src_port->map_item );\r
+    }\r
+\r
+    p_dest_port = (osm_port_t*)cl_qmap_next( &p_dest_port->map_item );\r
+  }\r
+\r
+  OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static void\r
+__osm_pr_rcv_process_half(\r
+  IN osm_pr_rcv_t*         const p_rcv,\r
+  IN const osm_madw_t*     const p_madw,\r
+  IN const osm_port_t*     const requester_port,\r
+  IN const osm_port_t*     const p_src_port,\r
+  IN const osm_port_t*     const p_dest_port,\r
+  IN const ib_net64_t      comp_mask,\r
+  IN cl_qlist_t*           const p_list )\r
+{\r
+  const cl_qmap_t*         p_tbl;\r
+  const osm_port_t*        p_port;\r
+\r
+  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_process_half );\r
+\r
+  /*\r
+    Iterate over every port, looking for matches...\r
+    A path record from a port to itself is legit, so no\r
+    need to special case that one.\r
+  */\r
+  p_tbl = &p_rcv->p_subn->port_guid_tbl;\r
+\r
+  if( p_src_port )\r
+  {\r
+    /*\r
+      The src port if fixed, so iterate over destination ports.\r
+    */\r
+    p_port = (osm_port_t*)cl_qmap_head( p_tbl );\r
+    while( p_port != (osm_port_t*)cl_qmap_end( p_tbl ) )\r
+    {\r
+      __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw , requester_port, p_src_port,\r
+                                        p_port, comp_mask, p_list );\r
+      p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item );\r
+    }\r
+  }\r
+  else\r
+  {\r
+    /*\r
+      The dest port if fixed, so iterate over source ports.\r
+    */\r
+    p_port = (osm_port_t*)cl_qmap_head( p_tbl );\r
+    while( p_port != (osm_port_t*)cl_qmap_end( p_tbl ) )\r
+    {\r
+      __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw, requester_port, p_port,\r
+                                        p_dest_port, comp_mask, p_list );\r
+      p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item );\r
+    }\r
+  }\r
+\r
+  OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static void\r
+__osm_pr_rcv_process_pair(\r
+  IN osm_pr_rcv_t*         const p_rcv,\r
+  IN const osm_madw_t*     const p_madw,\r
+  IN const osm_port_t*     const requester_port,\r
+  IN const osm_port_t*     const p_src_port,\r
+  IN const osm_port_t*     const p_dest_port,\r
+  IN const ib_net64_t      comp_mask,\r
+  IN cl_qlist_t*           const p_list )\r
+{\r
+  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_process_pair );\r
+\r
+  __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw, requester_port, p_src_port,\r
+                                    p_dest_port, comp_mask, p_list );\r
+\r
+  OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ *********************************************************************/\r
+static void\r
+__search_mgrp_by_mgid(\r
+  IN  cl_map_item_t* const      p_map_item,\r
+  IN  void*                     context )\r
+{\r
+  osm_mgrp_t*                   p_mgrp = (osm_mgrp_t*)p_map_item;\r
+  osm_sa_pr_mcmr_search_ctxt_t *p_ctxt = (osm_sa_pr_mcmr_search_ctxt_t *) context;\r
+  const ib_gid_t               *p_recvd_mgid;\r
+  osm_pr_rcv_t                 *p_rcv;\r
+  /* uint32_t  i; */\r
+\r
+  p_recvd_mgid = p_ctxt->p_mgid;\r
+  p_rcv = p_ctxt->p_rcv;\r
+\r
+  /* ignore groups marked for deletion */\r
+  if ( p_mgrp->to_be_deleted )\r
+    return;\r
+\r
+  /* compare entire MGID so different scope will not sneak in for\r
+     the same MGID */\r
+  if ( memcmp( &p_mgrp->mcmember_rec.mgid,\r
+                p_recvd_mgid,\r
+                sizeof(ib_gid_t) ) )\r
+    return;\r
+\r
+#if 0\r
+  for ( i = 0 ; i < sizeof(p_mgrp->mcmember_rec.mgid.multicast.raw_group_id); i++)\r
+  {\r
+    if ( p_mgrp->mcmember_rec.mgid.multicast.raw_group_id[i] !=\r
+         p_recvd_mgid->mgid.multicast.raw_group_id[i] )\r
+      return;\r
+  }\r
+#endif\r
+\r
+  if( p_ctxt->p_mgrp )\r
+  {\r
+    osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+             "__search_mgrp_by_mgid: ERR 1F08: "\r
+             "Multiple MC groups for same MGID\n" );\r
+    return;\r
+  }\r
+  p_ctxt->p_mgrp = p_mgrp;\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static ib_api_status_t\r
+__get_mgrp_by_mgid(\r
+  IN osm_pr_rcv_t*             const p_rcv,\r
+  IN ib_path_rec_t*            p_recvd_path_rec,\r
+  OUT osm_mgrp_t **            pp_mgrp )\r
+{\r
+  osm_sa_pr_mcmr_search_ctxt_t mcmr_search_context;\r
+\r
+  mcmr_search_context.p_mgid = &p_recvd_path_rec->dgid;\r
+  mcmr_search_context.p_rcv = p_rcv;\r
+  mcmr_search_context.p_mgrp = NULL;\r
+\r
+  cl_qmap_apply_func( &p_rcv->p_subn->mgrp_mlid_tbl,\r
+                      __search_mgrp_by_mgid,\r
+                      &mcmr_search_context);\r
+\r
+  if( mcmr_search_context.p_mgrp == NULL )\r
+  {\r
+    return IB_NOT_FOUND;\r
+  }\r
+\r
+  *pp_mgrp = mcmr_search_context.p_mgrp;\r
+  return IB_SUCCESS;\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static osm_mgrp_t *\r
+__get_mgrp_by_mlid(\r
+  IN const osm_pr_rcv_t* const p_rcv,\r
+  IN ib_net16_t          const mlid )\r
+{\r
+  cl_map_item_t *        map_item;\r
+\r
+  map_item = cl_qmap_get( &p_rcv->p_subn->mgrp_mlid_tbl, mlid );\r
+\r
+  if( map_item == cl_qmap_end(&p_rcv->p_subn->mgrp_mlid_tbl) )\r
+  {\r
+    return NULL;\r
+  }\r
+\r
+  return (osm_mgrp_t *)map_item;\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static void\r
+__osm_pr_get_mgrp(\r
+  IN osm_pr_rcv_t*         const p_rcv,\r
+  IN const osm_madw_t*     const p_madw,\r
+  OUT osm_mgrp_t           **pp_mgrp )\r
+{\r
+  ib_path_rec_t*           p_pr;\r
+  const ib_sa_mad_t*       p_sa_mad;\r
+  ib_net64_t               comp_mask;\r
+  ib_api_status_t          status;\r
+\r
+  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_get_mgrp );\r
+\r
+  p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+  p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );\r
+\r
+  comp_mask = p_sa_mad->comp_mask;\r
+\r
+  if( comp_mask & IB_PR_COMPMASK_DGID )\r
+  {\r
+    status = __get_mgrp_by_mgid( p_rcv, p_pr, pp_mgrp );\r
+    if( status != IB_SUCCESS )\r
+    {\r
+      osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+               "__osm_pr_get_mgrp: ERR 1F09: "\r
+               "No MC group found for PathRecord destination GID\n" );\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+  if( comp_mask & IB_PR_COMPMASK_DLID )\r
+  {\r
+    if( *pp_mgrp)\r
+    {\r
+      /* check that the MLID in the MC group is */\r
+      /* the same as the DLID in the PathRecord */\r
+      if( (*pp_mgrp)->mlid != p_pr->dlid )\r
+      {\r
+       /* Note: perhaps this might be better indicated as an invalid request */\r
+        osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+                 "__osm_pr_get_mgrp: ERR 1F10: "\r
+                 "MC group MLID does not match PathRecord destination LID\n" );\r
+        *pp_mgrp = NULL;\r
+        goto Exit;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      *pp_mgrp = __get_mgrp_by_mlid( p_rcv, p_pr->dlid );\r
+      if( *pp_mgrp == NULL)\r
+      {\r
+        osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+                 "__osm_pr_get_mgrp: ERR 1F11: "\r
+                 "No MC group found for PathRecord destination LID\n" );\r
+      }\r
+    }\r
+  }\r
+\r
+ Exit:\r
+  OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static ib_api_status_t\r
+__osm_pr_match_mgrp_attributes(\r
+  IN osm_pr_rcv_t*         const p_rcv,\r
+  IN const osm_madw_t*     const p_madw,\r
+  IN const osm_mgrp_t*     const p_mgrp )\r
+{\r
+  const ib_path_rec_t*     p_pr;\r
+  const ib_sa_mad_t*       p_sa_mad;\r
+  ib_net64_t               comp_mask;\r
+  ib_api_status_t          status = IB_ERROR;\r
+  uint32_t                 flow_label;\r
+  uint8_t                  sl;\r
+  uint8_t                  hop_limit;\r
+\r
+  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_match_mgrp_attributes );\r
+\r
+  p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+  p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );\r
+\r
+  comp_mask = p_sa_mad->comp_mask;\r
+\r
+  /* If SGID and/or SLID specified, should validate as member of MC group */\r
+  /* Also, MTU, rate, packet lifetime, and raw traffic requested are not currently checked */\r
+  if( comp_mask & IB_PR_COMPMASK_PKEY )\r
+  {\r
+    if( p_pr->pkey != p_mgrp->mcmember_rec.pkey )\r
+      goto Exit;\r
+  }\r
+\r
+  ib_member_get_sl_flow_hop( p_mgrp->mcmember_rec.sl_flow_hop,\r
+                             &sl, &flow_label, &hop_limit );\r
+\r
+  if( comp_mask & IB_PR_COMPMASK_SL )\r
+  {\r
+    if( ib_path_rec_sl( p_pr ) != sl )\r
+      goto Exit;\r
+  }\r
+\r
+  /* If SubnAdmGet, assume NumbPaths of 1 (1.2 erratum) */\r
+  if( ( comp_mask & IB_PR_COMPMASK_NUMBPATH ) &&\r
+      ( p_sa_mad->method != IB_MAD_METHOD_GET ) )\r
+  {\r
+    if( ib_path_rec_num_path( p_pr ) == 0 )\r
+      goto Exit;\r
+  }\r
+\r
+  if( comp_mask & IB_PR_COMPMASK_FLOWLABEL )\r
+  {\r
+    if( ib_path_rec_flow_lbl( p_pr ) != flow_label )\r
+      goto Exit;\r
+  }\r
+\r
+  if( comp_mask & IB_PR_COMPMASK_HOPLIMIT )\r
+  {\r
+    if( ib_path_rec_hop_limit( p_pr ) != hop_limit )\r
+      goto Exit;\r
+  }\r
+\r
+  if( comp_mask & IB_PR_COMPMASK_TCLASS )\r
+  {\r
+    if( p_pr->tclass != p_mgrp->mcmember_rec.tclass )\r
+      goto Exit;\r
+  }\r
+\r
+  status = IB_SUCCESS;\r
+\r
+ Exit:\r
+  OSM_LOG_EXIT( p_rcv->p_log );\r
+  return( status );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static int\r
+__osm_pr_rcv_check_mcast_dest(\r
+  IN osm_pr_rcv_t*         const p_rcv,\r
+  IN const osm_madw_t*     const p_madw )\r
+{\r
+  const ib_path_rec_t*     p_pr;\r
+  const ib_sa_mad_t*       p_sa_mad;\r
+  ib_net64_t               comp_mask;\r
+  int                      is_multicast = 0;\r
+\r
+  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_check_mcast_dest );\r
+\r
+  p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+  p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );\r
+\r
+  comp_mask = p_sa_mad->comp_mask;\r
+\r
+  if( comp_mask & IB_PR_COMPMASK_DGID )\r
+  {\r
+    is_multicast = ib_gid_is_multicast( &p_pr->dgid );\r
+    if( !is_multicast )\r
+      goto Exit;\r
+  }\r
+\r
+  if( comp_mask & IB_PR_COMPMASK_DLID )\r
+  {\r
+    if( cl_ntoh16( p_pr->dlid ) >= IB_LID_MCAST_START_HO &&\r
+        cl_ntoh16( p_pr->dlid ) <= IB_LID_MCAST_END_HO )\r
+      is_multicast = 1;\r
+    else if( is_multicast )\r
+    {\r
+      osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+               "__osm_pr_rcv_check_mcast_dest: ERR 1F12: "\r
+               "PathRecord request indicates MGID but not MLID\n" );\r
+      is_multicast = -1;\r
+    }\r
+  }\r
+\r
+ Exit:\r
+  OSM_LOG_EXIT( p_rcv->p_log );\r
+  return( is_multicast );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static void\r
+__osm_pr_rcv_respond(\r
+  IN osm_pr_rcv_t*         const p_rcv,\r
+  IN const osm_madw_t*     const p_madw,\r
+  IN cl_qlist_t*           const p_list )\r
+{\r
+  osm_madw_t*              p_resp_madw;\r
+  const ib_sa_mad_t*       p_sa_mad;\r
+  ib_sa_mad_t*             p_resp_sa_mad;\r
+  size_t                   num_rec, pre_trim_num_rec;\r
+#ifndef VENDOR_RMPP_SUPPORT\r
+  size_t                  trim_num_rec;\r
+#endif\r
+  ib_path_rec_t*           p_resp_pr;\r
+  ib_api_status_t          status;\r
+  const ib_sa_mad_t*       p_rcvd_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+  osm_pr_item_t*           p_pr_item;\r
+  uint32_t                 i;\r
+\r
+  OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_respond );\r
+\r
+  num_rec = cl_qlist_count( p_list );\r
+\r
+  /*\r
+   * C15-0.1.30:\r
+   * If we do a SubnAdmGet and got more than one record it is an error !\r
+   */\r
+  if (p_rcvd_mad->method == IB_MAD_METHOD_GET)\r
+  {\r
+    if (num_rec == 0)\r
+    {\r
+      osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS );\r
+      goto Exit;\r
+    }\r
+    if (num_rec > 1)\r
+    {\r
+      osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+               "__osm_pr_rcv_respond: ERR 1F13: "\r
+               "Got more than one record for SubnAdmGet (%zu)\n",\r
+               num_rec );\r
+      osm_sa_send_error( p_rcv->p_resp, p_madw,\r
+                         IB_SA_MAD_STATUS_TOO_MANY_RECORDS );\r
+      /* need to set the mem free ... */\r
+      p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );\r
+      while( p_pr_item != (osm_pr_item_t*)cl_qlist_end( p_list ) )\r
+      {\r
+        cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );\r
+        p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );\r
+      }\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+  pre_trim_num_rec = num_rec;\r
+#ifndef VENDOR_RMPP_SUPPORT\r
+  trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_path_rec_t);\r
+  if (trim_num_rec < num_rec)\r
+  {\r
+    osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,\r
+             "__osm_pr_rcv_respond: "\r
+             "Number of records:%u trimmed to:%u to fit in one MAD\n",\r
+             num_rec,trim_num_rec );\r
+    num_rec = trim_num_rec;\r
+  }\r
+#endif\r
+\r
+  osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+           "__osm_pr_rcv_respond: "\r
+           "Generating response with %zu records\n", num_rec );\r
+\r
+  if ((p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec == 0))\r
+  {\r
+    osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS );\r
+    goto Exit;\r
+  }\r
+\r
+  /*\r
+   * Get a MAD to reply. Address of Mad is in the received mad_wrapper\r
+   */\r
+  p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, p_madw->h_bind,\r
+                                  num_rec * sizeof(ib_path_rec_t) + IB_SA_MAD_HDR_SIZE,\r
+                                  &p_madw->mad_addr );\r
+  if( !p_resp_madw )\r
+  {\r
+    osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+             "__osm_pr_rcv_respond: ERR 1F14: "\r
+             "Unable to allocate MAD\n" );\r
+\r
+    for( i = 0; i < num_rec; i++ )\r
+    {\r
+      p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );\r
+      cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );\r
+    }\r
+\r
+    osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES );\r
+    goto Exit;\r
+  }\r
+\r
+  p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+  p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_resp_madw );\r
+\r
+  memcpy( p_resp_sa_mad, p_sa_mad, IB_SA_MAD_HDR_SIZE );\r
+  p_resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;\r
+  /* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) */\r
+  p_resp_sa_mad->sm_key = 0;\r
+  /* Fill in the offset (paylen will be done by the rmpp SAR) */\r
+  p_resp_sa_mad->attr_offset = ib_get_attr_offset( sizeof(ib_path_rec_t) );\r
+\r
+  p_resp_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_resp_sa_mad );\r
+\r
+#ifndef VENDOR_RMPP_SUPPORT\r
+  /* we support only one packet RMPP - so we will set the first and\r
+     last flags for gettable */\r
+  if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP)\r
+  {\r
+    p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA;\r
+    p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_FIRST | IB_RMPP_FLAG_LAST | IB_RMPP_FLAG_ACTIVE;\r
+  }\r
+#else\r
+  /* forcefully define the packet as RMPP one */\r
+  if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP)\r
+    p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE;\r
+#endif\r
+\r
+  for ( i = 0; i < pre_trim_num_rec; i++ )\r
+  {\r
+    p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );\r
+    /* copy only if not trimmed */\r
+    if (i < num_rec)\r
+        *p_resp_pr = p_pr_item->path_rec;\r
+\r
+    cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );\r
+    p_resp_pr++;\r
+  }\r
+\r
+  CL_ASSERT( cl_is_qlist_empty( p_list ) );\r
+\r
+  status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE );\r
+\r
+  if( status != IB_SUCCESS )\r
+  {\r
+    osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+             "__osm_pr_rcv_respond: ERR 1F15: "\r
+             "Unable to send MAD (%s)\n", ib_get_err_str( status ) );\r
+    /*  osm_mad_pool_put( p_rcv->p_mad_pool, p_resp_madw ); */\r
+  }\r
+\r
+ Exit:\r
+  OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+void\r
+osm_pr_rcv_process(\r
+  IN osm_pr_rcv_t*         const p_rcv,\r
+  IN const osm_madw_t*     const p_madw )\r
+{\r
+  const ib_path_rec_t*     p_pr;\r
+  const ib_sa_mad_t*       p_sa_mad;\r
+  const osm_port_t*        p_src_port;\r
+  const osm_port_t*        p_dest_port;\r
+  cl_qlist_t               pr_list;\r
+  ib_net16_t               sa_status;\r
+  osm_port_t*              requester_port;\r
+  int ret;\r
+\r
+  OSM_LOG_ENTER( p_rcv->p_log, osm_pr_rcv_process );\r
+\r
+  CL_ASSERT( p_madw );\r
+\r
+  p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+  p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );\r
+\r
+  CL_ASSERT( p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD );\r
+\r
+  /* we only support SubnAdmGet and SubnAdmGetTable methods */\r
+  if ((p_sa_mad->method != IB_MAD_METHOD_GET) &&\r
+      (p_sa_mad->method != IB_MAD_METHOD_GETTABLE)) {\r
+    osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+             "osm_pr_rcv_process: ERR 1F17: " \r
+             "Unsupported Method (%s)\n",\r
+             ib_get_sa_method_str( p_sa_mad->method ) );\r
+    osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR );\r
+    goto Exit;\r
+  }\r
+\r
+  /* update the requester physical port. */\r
+  requester_port = osm_get_port_by_mad_addr( p_rcv->p_log, p_rcv->p_subn,\r
+                                             osm_madw_get_mad_addr_ptr( p_madw ) );\r
+  if( requester_port == NULL )\r
+  {\r
+    osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+             "osm_pr_rcv_process: ERR 1F16: "\r
+             "Cannot find requester physical port\n" );\r
+    goto Exit;\r
+  }\r
+\r
+  if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+    osm_dump_path_record( p_rcv->p_log, p_pr, OSM_LOG_DEBUG );\r
+\r
+  cl_qlist_init( &pr_list );\r
+\r
+  /*\r
+    Most SA functions (including this one) are read-only on the\r
+    subnet object, so we grab the lock non-exclusively.\r
+  */\r
+  cl_plock_acquire( p_rcv->p_lock );\r
+\r
+  /* Handle multicast destinations separately */\r
+  if( (ret = __osm_pr_rcv_check_mcast_dest( p_rcv, p_madw )) < 0 )\r
+  {\r
+    /* Multicast DGID with unicast DLID */\r
+    cl_plock_release( p_rcv->p_lock );\r
+    osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_INVALID_FIELD );\r
+    goto Exit;\r
+  }\r
+\r
+  if(ret > 0)\r
+    goto McastDest;\r
+\r
+  osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+           "osm_pr_rcv_process: "\r
+           "Unicast destination requested\n" );\r
+\r
+  sa_status = __osm_pr_rcv_get_end_points( p_rcv, p_madw,\r
+                                           &p_src_port, &p_dest_port );\r
+\r
+  if( sa_status == IB_SA_MAD_STATUS_SUCCESS )\r
+  {\r
+    /*\r
+      What happens next depends on the type of endpoint information\r
+      that was specified....\r
+    */\r
+    if( p_src_port )\r
+    {\r
+      if( p_dest_port )\r
+        __osm_pr_rcv_process_pair( p_rcv, p_madw, requester_port,\r
+                                   p_src_port, p_dest_port,\r
+                                   p_sa_mad->comp_mask, &pr_list );\r
+      else\r
+        __osm_pr_rcv_process_half( p_rcv, p_madw, requester_port,\r
+                                   p_src_port, NULL,\r
+                                   p_sa_mad->comp_mask, &pr_list );\r
+    }\r
+    else\r
+    {\r
+      if( p_dest_port )\r
+        __osm_pr_rcv_process_half( p_rcv, p_madw, requester_port,\r
+                                   NULL, p_dest_port,\r
+                                   p_sa_mad->comp_mask, &pr_list );\r
+      else\r
+        /*\r
+          Katie, bar the door!\r
+        */\r
+        __osm_pr_rcv_process_world( p_rcv, p_madw, requester_port,\r
+                                    p_sa_mad->comp_mask, &pr_list );\r
+    }\r
+  }\r
+  goto Unlock;\r
+\r
+ McastDest:\r
+  osm_log(p_rcv->p_log, OSM_LOG_DEBUG,\r
+             "osm_pr_rcv_process: "\r
+             "Multicast destination requested\n" );\r
+  {\r
+    osm_mgrp_t *p_mgrp = NULL;\r
+    ib_api_status_t status;\r
+    osm_pr_item_t* p_pr_item;\r
+    uint32_t flow_label;\r
+    uint8_t  sl;\r
+    uint8_t  hop_limit;\r
+\r
+    /* First, get the MC info */\r
+    __osm_pr_get_mgrp( p_rcv, p_madw, &p_mgrp );\r
+\r
+    if ( p_mgrp )\r
+    {\r
+      /* Make sure the rest of the PathRecord matches the MC group attributes */\r
+      status = __osm_pr_match_mgrp_attributes( p_rcv, p_madw, p_mgrp );\r
+      if ( status == IB_SUCCESS )\r
+      {\r
+        p_pr_item = (osm_pr_item_t*)cl_qlock_pool_get( &p_rcv->pr_pool );\r
+        if( p_pr_item == NULL )\r
+        {\r
+          osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+                   "osm_pr_rcv_process: ERR 1F18: "\r
+                   "Unable to allocate path record for MC group\n" );\r
+        }\r
+        else\r
+        {\r
+         /* Copy PathRecord request into response */\r
+          p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+          p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );\r
+          p_pr_item->path_rec = *p_pr;\r
+\r
+          /* Now, use the MC info to cruft up the PathRecord response */        \r
+          p_pr_item->path_rec.dgid = p_mgrp->mcmember_rec.mgid;\r
+          p_pr_item->path_rec.dlid = p_mgrp->mcmember_rec.mlid;\r
+         p_pr_item->path_rec.tclass = p_mgrp->mcmember_rec.tclass;\r
+         p_pr_item->path_rec.num_path = 1;\r
+         p_pr_item->path_rec.pkey = p_mgrp->mcmember_rec.pkey;\r
+\r
+         /* MTU, rate, and packet lifetime should be exactly */\r
+         p_pr_item->path_rec.mtu = (2<<6) | p_mgrp->mcmember_rec.mtu;\r
+          p_pr_item->path_rec.rate = (2<<6) | p_mgrp->mcmember_rec.rate;\r
+          p_pr_item->path_rec.pkt_life = (2<<6) | p_mgrp->mcmember_rec.pkt_life;\r
+\r
+         /* SL, Hop Limit, and Flow Label */\r
+          ib_member_get_sl_flow_hop( p_mgrp->mcmember_rec.sl_flow_hop,\r
+                                     &sl, &flow_label, &hop_limit );\r
+         p_pr_item->path_rec.qos_class_sl = cl_hton16( sl );\r
+          p_pr_item->path_rec.hop_flow_raw = (uint32_t)(hop_limit) |\r
+                                             (flow_label << 8);\r
+\r
+          cl_qlist_insert_tail( &pr_list,\r
+                                (cl_list_item_t*)&p_pr_item->pool_item );\r
+\r
+        }\r
+      }\r
+      else\r
+      {\r
+        osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+                 "osm_pr_rcv_process: ERR 1F19: "\r
+                 "MC group attributes don't match PathRecord request\n" );\r
+      }\r
+    }\r
+  }\r
+\r
+ Unlock:\r
+  cl_plock_release( p_rcv->p_lock );\r
+\r
+  /* Now, (finally) respond to the PathRecord request */\r
+  __osm_pr_rcv_respond( p_rcv, p_madw, &pr_list );\r
+\r
+ Exit:\r
+  OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r