Hi Hal

This is a 5th take after incorporating Sasha's last reported bug 
on bad assignment of the used_blocks.

This code was run again through my verification flow and also Sasha
had run some tests too.

Eitan

Signed-off-by:  Eitan Zahavi <[EMAIL PROTECTED]>

Index: include/opensm/osm_port.h
===================================================================
--- include/opensm/osm_port.h   (revision 8113)
+++ include/opensm/osm_port.h   (working copy)
@@ -591,6 +591,39 @@ osm_physp_get_pkey_tbl( IN const osm_phy
 *  Port, Physical Port
 *********/
 
+/****f* OpenSM: Physical Port/osm_physp_get_mod_pkey_tbl
+* NAME
+*  osm_physp_get_mod_pkey_tbl
+*
+* DESCRIPTION
+*  Returns a NON CONST pointer to the P_Key table object of the Physical Port 
object.
+*
+* SYNOPSIS
+*/
+static inline osm_pkey_tbl_t *
+osm_physp_get_mod_pkey_tbl( IN osm_physp_t* const p_physp )
+{
+  CL_ASSERT( osm_physp_is_valid( p_physp ) );
+  /*
+    (14.2.5.7) - the block number valid values are 0-2047, and are further
+    limited by the size of the P_Key table specified by the PartitionCap on 
the node. 
+  */
+  return( &p_physp->pkeys );
+};
+/*
+* PARAMETERS
+*  p_physp
+*     [in] Pointer to an osm_physp_t object.
+*
+* RETURN VALUES
+*  The pointer to the P_Key table object.
+*
+* NOTES
+*
+* SEE ALSO
+*  Port, Physical Port
+*********/
+
 /****f* OpenSM: Physical Port/osm_physp_set_slvl_tbl
 * NAME
 *      osm_physp_set_slvl_tbl
Index: include/opensm/osm_pkey.h
===================================================================
--- include/opensm/osm_pkey.h   (revision 8113)
+++ include/opensm/osm_pkey.h   (working copy)
@@ -92,6 +92,9 @@ typedef struct _osm_pkey_tbl
   cl_ptr_vector_t blocks;
   cl_ptr_vector_t new_blocks;
   cl_map_t        keys;
+  cl_qlist_t      pending;
+  uint16_t        used_blocks;
+  uint16_t        max_blocks;
 } osm_pkey_tbl_t;
 /*
 * FIELDS
@@ -104,6 +107,18 @@ typedef struct _osm_pkey_tbl
 *      keys
 *              A set holding all keys
 *
+*  pending
+*     A list osm_pending_pkey structs that is temporarily set by the 
+*     pkey mgr and used during pkey mgr algorithm only
+*
+*  used_blocks
+*     Tracks the number of blocks having non-zero pkeys
+*
+*  max_blocks
+*     The maximal number of blocks this partition table might hold
+*     this value is based on node_info (for port 0 or CA) or switch_info
+*     updated on receiving the node_info or switch_info GetResp
+*
 * NOTES
 * 'blocks' vector should be used to store pkey values obtained from
 * the port and SM pkey manager should not change it directly, for this
@@ -114,6 +129,39 @@ typedef struct _osm_pkey_tbl
 *
 *********/
 
+/****s* OpenSM: osm_pending_pkey_t
+* NAME
+*      osm_pending_pkey_t
+*
+* DESCRIPTION
+*      This objects stores temporary information on pkeys their target block 
and index
+*  during the pkey manager operation
+*
+* SYNOPSIS
+*/
+typedef struct _osm_pending_pkey {
+  cl_list_item_t list_item;
+  uint16_t               pkey;
+  uint32_t               block;
+  uint8_t                index;
+  boolean_t              is_new;
+} osm_pending_pkey_t;
+/*
+* FIELDS
+*      pkey
+*              The actual P_Key
+*
+*      block
+*              The block index based on the previous table extracted from the 
device
+*
+*      index
+*              The index of the pky within the block
+*
+*  is_new
+*     TRUE for new P_Keys such that the block and index are invalid in that 
case
+*
+*********/
+
 /****f* OpenSM: osm_pkey_tbl_construct
 * NAME
 *  osm_pkey_tbl_construct
@@ -142,7 +190,8 @@ void osm_pkey_tbl_construct( 
 *
 * SYNOPSIS
 */
-int osm_pkey_tbl_init( 
+ib_api_status_t 
+osm_pkey_tbl_init( 
   IN osm_pkey_tbl_t *p_pkey_tbl);
 /*
 *  p_pkey_tbl
@@ -209,8 +258,8 @@ osm_pkey_tbl_get_num_blocks( 
 static inline ib_pkey_table_t *osm_pkey_tbl_block_get( 
   const osm_pkey_tbl_t *p_pkey_tbl, uint16_t block)
 {
-  CL_ASSERT(block < cl_ptr_vector_get_size(&p_pkey_tbl->blocks));
-  return(cl_ptr_vector_get(&p_pkey_tbl->blocks, block));
+       return( (block < cl_ptr_vector_get_size(&p_pkey_tbl->blocks)) ?
+                         cl_ptr_vector_get(&p_pkey_tbl->blocks, block) : NULL);
 };
 /*
 *  p_pkey_tbl
@@ -244,16 +293,117 @@ static inline ib_pkey_table_t *osm_pkey_
 /*
  *********/
 
-/****f* OpenSM: osm_pkey_tbl_sync_new_blocks
+
+/****f* OpenSM: osm_pkey_tbl_make_block_pair
+* NAME
+*  osm_pkey_tbl_make_block_pair
+*
+* DESCRIPTION
+*  Find or create a pair of "old" and "new" blocks for the
+*  given block index
+*
+* SYNOPSIS
+*/
+ib_api_status_t
+osm_pkey_tbl_make_block_pair( 
+       osm_pkey_tbl_t   *p_pkey_tbl, 
+       uint16_t          block_idx,
+       ib_pkey_table_t **pp_old_block,
+       ib_pkey_table_t **pp_new_block);
+/*
+* p_pkey_tbl
+*   [in] Pointer to the PKey table 
+*
+* block_idx
+*   [in] The block index to use
+*
+* pp_old_block
+*   [out] Pointer to the old block pointer arg
+*
+* pp_new_block
+*   [out] Pointer to the new block pointer arg
+*
+* RETURN VALUES
+*   IB_SUCCESS if OK IB_ERROR if failed
+* 
+*********/
+
+/****f* OpenSM: osm_pkey_tbl_set_new_entry
 * NAME
-*  osm_pkey_tbl_sync_new_blocks
+*  osm_pkey_tbl_set_new_entry
 *
 * DESCRIPTION
-*  Syncs new_blocks vector content with current pkey table blocks
+*   stores the given pkey in the "new" blocks array and update
+*   the "map" to show that on the "old" blocks
 *
 * SYNOPSIS
 */
-void osm_pkey_tbl_sync_new_blocks( 
+ib_api_status_t
+osm_pkey_tbl_set_new_entry( 
+       IN osm_pkey_tbl_t *p_pkey_tbl,
+       IN uint16_t        block_idx,
+       IN uint8_t         pkey_idx,
+       IN uint16_t        pkey);
+/*
+* p_pkey_tbl
+*   [in] Pointer to the PKey table 
+*
+* block_idx
+*   [in] The block index to use
+*
+* pkey_idx
+*   [in] The index within the block
+*
+* pkey
+*   [in] PKey to store
+*
+* RETURN VALUES
+*   IB_SUCCESS if OK IB_ERROR if failed
+* 
+*********/
+
+/****f* OpenSM: osm_pkey_find_next_free_entry
+* NAME
+*  osm_pkey_find_next_free_entry
+*
+* DESCRIPTION
+*  Find the next free entry in the PKey table. Starting at the given
+*  index and block number. The user should increment pkey_idx before 
+*  next call
+*  Inspect the "new" blocks array for empty space.
+*
+* SYNOPSIS
+*/
+boolean_t
+osm_pkey_find_next_free_entry(
+       IN osm_pkey_tbl_t *p_pkey_tbl, 
+       OUT uint16_t      *p_block_idx,
+       OUT uint8_t       *p_pkey_idx);
+/*
+* p_pkey_tbl
+*   [in] Pointer to the PKey table 
+*
+* p_block_idx
+*   [out] The block index to use
+*
+* p_pkey_idx
+*   [out] The index within the block to use
+*
+* RETURN VALUES
+*   TRUE if found FALSE if did not find
+* 
+*********/
+
+/****f* OpenSM: osm_pkey_tbl_init_new_blocks
+* NAME
+*  osm_pkey_tbl_init_new_blocks
+*
+* DESCRIPTION
+*  Initializes new_blocks vector content (clear and allocate)
+*
+* SYNOPSIS
+*/
+void osm_pkey_tbl_init_new_blocks( 
   const osm_pkey_tbl_t *p_pkey_tbl);
 /*
 *  p_pkey_tbl
@@ -263,6 +413,41 @@ void osm_pkey_tbl_sync_new_blocks( 
 *
 *********/
 
+/****f* OpenSM: osm_pkey_tbl_get_block_and_idx
+* NAME
+*  osm_pkey_tbl_get_block_and_idx
+*
+* DESCRIPTION
+*  set the block index and pkey index the given
+*  pkey is found in. return IB_NOT_FOUND if cound not find 
+*  it, IB_SUCCESS if OK
+*
+* SYNOPSIS
+*/
+ib_api_status_t
+osm_pkey_tbl_get_block_and_idx(
+  IN  osm_pkey_tbl_t *p_pkey_tbl, 
+  IN  uint16_t       *p_pkey,
+  OUT uint32_t       *block_idx,
+  OUT uint8_t        *pkey_index);
+/*
+*  p_pkey_tbl
+*     [in] Pointer to osm_pkey_tbl_t object.
+*  
+*  p_pkey
+*     [in] Pointer to the P_Key entry searched
+*
+*  p_block_idx
+*     [out] Pointer to the block index to be updated
+*
+*  p_pkey_idx 
+*     [out] Pointer to the pkey index (in the block) to be updated
+*
+*
+* NOTES
+*
+*********/
+
 /****f* OpenSM: osm_pkey_tbl_set
 * NAME
 *  osm_pkey_tbl_set
@@ -272,7 +457,8 @@ void osm_pkey_tbl_sync_new_blocks( 
 *
 * SYNOPSIS
 */
-int osm_pkey_tbl_set( 
+ib_api_status_t
+osm_pkey_tbl_set( 
   IN osm_pkey_tbl_t *p_pkey_tbl,
   IN uint16_t block, 
   IN ib_pkey_table_t *p_tbl);
Index: opensm/osm_pkey.c
===================================================================
--- opensm/osm_pkey.c   (revision 8113)
+++ opensm/osm_pkey.c   (working copy)
@@ -94,18 +94,22 @@ void osm_pkey_tbl_destroy( 
 
 /**********************************************************************
  **********************************************************************/
-int osm_pkey_tbl_init( 
+ib_api_status_t
+osm_pkey_tbl_init(
   IN osm_pkey_tbl_t *p_pkey_tbl)
 {
   cl_ptr_vector_init( &p_pkey_tbl->blocks, 0, 1);
   cl_ptr_vector_init( &p_pkey_tbl->new_blocks, 0, 1);
   cl_map_init( &p_pkey_tbl->keys, 1 );
+       cl_qlist_init( &p_pkey_tbl->pending );
+       p_pkey_tbl->used_blocks = 0;
+       p_pkey_tbl->max_blocks = 0;
   return(IB_SUCCESS);
 }
 
 /**********************************************************************
  **********************************************************************/
-void osm_pkey_tbl_sync_new_blocks(
+void osm_pkey_tbl_init_new_blocks(
   IN const osm_pkey_tbl_t *p_pkey_tbl)
 {
   ib_pkey_table_t *p_block, *p_new_block;
@@ -123,16 +127,31 @@ void osm_pkey_tbl_sync_new_blocks(
       p_new_block = (ib_pkey_table_t *)malloc(sizeof(*p_new_block));
       if (!p_new_block)
         break;
+                       cl_ptr_vector_set(&((osm_pkey_tbl_t 
*)p_pkey_tbl)->new_blocks, 
+                                                                       b, 
p_new_block);
+               }
+
       memset(p_new_block, 0, sizeof(*p_new_block));
-      cl_ptr_vector_set(&((osm_pkey_tbl_t *)p_pkey_tbl)->new_blocks, b, 
p_new_block);
     }
-    memcpy(p_new_block, p_block, sizeof(*p_new_block));
+}
+
+/**********************************************************************
+ **********************************************************************/
+void osm_pkey_tbl_cleanup_pending(
+       IN osm_pkey_tbl_t *p_pkey_tbl)
+{
+       cl_list_item_t  *p_item;
+       p_item = cl_qlist_remove_head( &p_pkey_tbl->pending );
+       while (p_item != cl_qlist_end( &p_pkey_tbl->pending ) )
+       {
+               free( (osm_pending_pkey_t *)p_item );
   }
 }
 
 /**********************************************************************
  **********************************************************************/
-int osm_pkey_tbl_set( 
+ib_api_status_t
+osm_pkey_tbl_set(
   IN osm_pkey_tbl_t *p_pkey_tbl,
   IN uint16_t block, 
   IN ib_pkey_table_t *p_tbl)
@@ -203,7 +222,138 @@ int osm_pkey_tbl_set( 
 
 /**********************************************************************
  **********************************************************************/
-static boolean_t __osm_match_pkey (
+ib_api_status_t
+osm_pkey_tbl_make_block_pair( 
+       osm_pkey_tbl_t   *p_pkey_tbl, 
+       uint16_t          block_idx,
+       ib_pkey_table_t **pp_old_block,
+       ib_pkey_table_t **pp_new_block)
+{
+       if (block_idx >= p_pkey_tbl->max_blocks) return(IB_ERROR);
+
+       if (pp_old_block)
+       {
+               *pp_old_block = osm_pkey_tbl_block_get( p_pkey_tbl, block_idx );
+               if (! *pp_old_block)
+               {
+                       *pp_old_block = (ib_pkey_table_t 
*)malloc(sizeof(ib_pkey_table_t));
+                       if (!*pp_old_block) return(IB_ERROR);
+                       memset(*pp_old_block, 0, sizeof(ib_pkey_table_t));
+                       cl_ptr_vector_set(&p_pkey_tbl->blocks, block_idx, 
*pp_old_block);
+               }
+       }
+       
+       if (pp_new_block)
+       {
+               *pp_new_block = osm_pkey_tbl_new_block_get( p_pkey_tbl, 
block_idx );
+               if (! *pp_new_block)
+               {
+                       *pp_new_block = (ib_pkey_table_t 
*)malloc(sizeof(ib_pkey_table_t));
+                       if (!*pp_new_block) return(IB_ERROR);
+                       memset(*pp_new_block, 0, sizeof(ib_pkey_table_t));
+                       cl_ptr_vector_set(&p_pkey_tbl->new_blocks, block_idx, 
*pp_new_block);
+               }
+       }
+       return( IB_SUCCESS );
+}
+
+/**********************************************************************
+ **********************************************************************/
+/*
+  store the given pkey in the "new" blocks array 
+  also makes sure the regular block exists.
+*/
+ib_api_status_t
+osm_pkey_tbl_set_new_entry( 
+       IN osm_pkey_tbl_t *p_pkey_tbl,
+       IN uint16_t        block_idx,
+       IN uint8_t         pkey_idx,
+       IN uint16_t        pkey)
+{  
+       ib_pkey_table_t *p_old_block;
+       ib_pkey_table_t *p_new_block;
+       
+       if (osm_pkey_tbl_make_block_pair(
+                        p_pkey_tbl, block_idx, &p_old_block, &p_new_block))
+               return( IB_ERROR );
+               
+       p_new_block->pkey_entry[pkey_idx] = pkey;
+       if (p_pkey_tbl->used_blocks <= block_idx)
+               p_pkey_tbl->used_blocks = block_idx + 1;
+
+       return( IB_SUCCESS );
+}
+
+/**********************************************************************
+ **********************************************************************/
+boolean_t
+osm_pkey_find_next_free_entry(
+       IN osm_pkey_tbl_t *p_pkey_tbl, 
+       OUT uint16_t      *p_block_idx,
+       OUT uint8_t       *p_pkey_idx)
+{
+       ib_pkey_table_t *p_new_block;
+       
+       CL_ASSERT(p_block_idx);
+       CL_ASSERT(p_pkey_idx);
+
+       while ( *p_block_idx < p_pkey_tbl->max_blocks)
+       {
+               if (*p_pkey_idx > IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1)
+               {
+                       *p_pkey_idx = 0;
+                       (*p_block_idx)++;
+                       if (*p_block_idx >= p_pkey_tbl->max_blocks) 
+                               return FALSE;
+               }
+
+               p_new_block = osm_pkey_tbl_new_block_get( p_pkey_tbl, 
*p_block_idx);
+
+               if ( !p_new_block || 
+                         
ib_pkey_is_invalid(p_new_block->pkey_entry[*p_pkey_idx]))
+                       return TRUE;
+               else
+                       (*p_pkey_idx)++;
+       }
+       return FALSE;
+}
+
+/**********************************************************************
+ **********************************************************************/
+ib_api_status_t
+osm_pkey_tbl_get_block_and_idx(
+       IN       osm_pkey_tbl_t *p_pkey_tbl,
+       IN       uint16_t                *p_pkey,
+       OUT uint32_t             *p_block_idx,
+       OUT uint8_t                      *p_pkey_index)
+{
+       uint32_t                          num_of_blocks;
+       uint32_t                          block_index;
+       ib_pkey_table_t *block;
+
+       CL_ASSERT( p_pkey_tbl );
+       CL_ASSERT( p_block_idx != NULL );
+       CL_ASSERT( p_pkey_idx != NULL );
+ 
+       num_of_blocks = cl_ptr_vector_get_size( &p_pkey_tbl->blocks);
+       for ( block_index = 0; block_index < num_of_blocks; block_index++ )
+       {
+               block = osm_pkey_tbl_block_get( p_pkey_tbl, block_index );
+               if ( ( block->pkey_entry <= p_pkey ) &&
+                         ( p_pkey < block->pkey_entry + 
IB_NUM_PKEY_ELEMENTS_IN_BLOCK))
+               {
+                       *p_block_idx = block_index;
+                       *p_pkey_index = p_pkey - block->pkey_entry;
+                       return( IB_SUCCESS );
+               }
+       }
+       return( IB_NOT_FOUND );
+}
+
+/**********************************************************************
+ **********************************************************************/
+static boolean_t 
+__osm_match_pkey (
   IN const ib_net16_t *pkey1,
   IN const ib_net16_t *pkey2 ) {
 
@@ -306,7 +456,8 @@ osm_physp_share_pkey(
   if (cl_is_map_empty(&pkey_tbl1->keys) || cl_is_map_empty(&pkey_tbl2->keys))
     return TRUE;
 
-  return !ib_pkey_is_invalid(osm_physp_find_common_pkey(p_physp_1, p_physp_2));
+       return 
+               !ib_pkey_is_invalid(osm_physp_find_common_pkey(p_physp_1, 
p_physp_2));
 }
 
 /**********************************************************************
@@ -322,7 +473,8 @@ osm_port_share_pkey(
 
   OSM_LOG_ENTER( p_log, osm_port_share_pkey );
 
-  if (!p_port_1 || !p_port_2) {
+       if (!p_port_1 || !p_port_2)
+       {
        ret = FALSE;
        goto Exit;
   }
@@ -330,7 +482,8 @@ osm_port_share_pkey(
   p_physp1 = osm_port_get_default_phys_ptr(p_port_1);
   p_physp2 = osm_port_get_default_phys_ptr(p_port_2);
 
-  if (!p_physp1 || !p_physp2) {
+       if (!p_physp1 || !p_physp2)
+       {
        ret = FALSE;
        goto Exit;
   }
Index: opensm/osm_pkey_mgr.c
===================================================================
--- opensm/osm_pkey_mgr.c       (revision 8113)
+++ opensm/osm_pkey_mgr.c       (working copy)
@@ -62,6 +62,131 @@
 
 /**********************************************************************
  **********************************************************************/
+/*
+  the max number of pkey blocks for a physical port is located in
+  different place for switch external ports (SwitchInfo) and the
+  rest of the ports (NodeInfo)
+*/
+static int 
+pkey_mgr_get_physp_max_blocks(
+       IN const osm_subn_t *p_subn,
+       IN const osm_physp_t *p_physp)
+{
+       osm_node_t *p_node = osm_physp_get_node_ptr(p_physp);
+       osm_switch_t *p_sw;
+       uint16_t num_pkeys = 0;
+
+       if ( (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH) ||
+                 (osm_physp_get_port_num( p_physp ) == 0))
+               num_pkeys = cl_ntoh16( p_node->node_info.partition_cap );
+       else
+       {
+               p_sw = osm_get_switch_by_guid(p_subn, 
p_node->node_info.node_guid);
+               if (p_sw)
+                       num_pkeys = cl_ntoh16( p_sw->switch_info.enforce_cap );
+       }
+       return( (num_pkeys + 31) / 32 );
+}
+
+/**********************************************************************
+ **********************************************************************/
+/*
+ * Insert the new pending pkey entry to the specific port pkey table
+ * pending pkeys. new entries are inserted at the back.
+ */
+static void 
+pkey_mgr_process_physical_port(
+       IN osm_log_t *p_log,
+       IN const osm_req_t *p_req,
+       IN const ib_net16_t pkey,
+       IN osm_physp_t *p_physp )
+{
+       osm_node_t *p_node = osm_physp_get_node_ptr( p_physp );
+       osm_pkey_tbl_t *p_pkey_tbl;
+       ib_net16_t *p_orig_pkey;
+       char *stat = NULL;
+       osm_pending_pkey_t *p_pending;
+
+       p_pkey_tbl = osm_physp_get_mod_pkey_tbl( p_physp );
+       p_pending = (osm_pending_pkey_t *)malloc(sizeof(osm_pending_pkey_t));
+       if (! p_pending)
+       {
+               osm_log( p_log, OSM_LOG_ERROR,
+                                       "pkey_mgr_process_physical_port: ERR 
0502: "
+                                       "Fail to allocate new pending pkey 
entry for node "
+                                       "0x%016" PRIx64 " port %u\n",
+                                       cl_ntoh64( osm_node_get_node_guid( 
p_node ) ),
+                                       osm_physp_get_port_num( p_physp ) );
+               return;
+       }
+       p_pending->pkey = pkey;
+       p_orig_pkey = cl_map_get( &p_pkey_tbl->keys, ib_pkey_get_base( pkey ) );
+       if ( !p_orig_pkey )
+       {
+               p_pending->is_new = TRUE;
+               cl_qlist_insert_tail(&p_pkey_tbl->pending, 
(cl_list_item_t*)p_pending);
+               stat = "inserted";
+       }
+       else
+       {
+               CL_ASSERT( ib_pkey_get_base(*p_orig_pkey) == 
ib_pkey_get_base(pkey) );
+               p_pending->is_new = FALSE;
+               if (osm_pkey_tbl_get_block_and_idx(
+                                p_pkey_tbl, p_orig_pkey,
+                                &p_pending->block, &p_pending->index) != 
IB_SUCCESS)
+               {
+                       osm_log( p_log, OSM_LOG_ERROR,
+                                               
"pkey_mgr_process_physical_port: ERR 0503: "
+                                               "Fail to obtain P_Key 0x%04x 
block and index for node "
+                                               "0x%016" PRIx64 " port %u\n",
+                                               cl_ntoh64( 
osm_node_get_node_guid( p_node ) ),
+                                               osm_physp_get_port_num( p_physp 
) );
+                       return;
+               }
+               cl_qlist_insert_head(&p_pkey_tbl->pending, 
(cl_list_item_t*)p_pending);
+               stat = "updated";
+       }
+
+       osm_log( p_log, OSM_LOG_DEBUG,
+                               "pkey_mgr_process_physical_port:        "
+                               "pkey 0x%04x was %s for node 0x%016" PRIx64
+                               " port %u\n",
+                               cl_ntoh16( pkey ), stat,
+                               cl_ntoh64( osm_node_get_node_guid( p_node ) ),
+                               osm_physp_get_port_num( p_physp ) );
+}
+
+/**********************************************************************
+ **********************************************************************/
+static void
+pkey_mgr_process_partition_table(
+       osm_log_t *p_log,
+       const osm_req_t *p_req,
+       const osm_prtn_t *p_prtn,
+       const boolean_t full )
+{
+       const cl_map_t *p_tbl = 
+               full ? &p_prtn->full_guid_tbl : &p_prtn->part_guid_tbl;
+       cl_map_iterator_t i, i_next;
+       ib_net16_t pkey = p_prtn->pkey;
+       osm_physp_t *p_physp;
+
+       if ( full )
+               pkey = cl_hton16( cl_ntoh16( pkey ) | 0x8000 );
+
+       i_next = cl_map_head( p_tbl );
+       while ( i_next != cl_map_end( p_tbl ) )
+       {
+               i = i_next;
+               i_next = cl_map_next( i );
+               p_physp = cl_map_obj( i );
+               if ( p_physp && osm_physp_is_valid( p_physp ) )
+                       pkey_mgr_process_physical_port( p_log, p_req, pkey, 
p_physp );
+       }
+}
+
+/**********************************************************************
+ **********************************************************************/
 static ib_api_status_t
 pkey_mgr_update_pkey_entry(
    IN const osm_req_t *p_req,
@@ -114,7 +239,8 @@ pkey_mgr_enforce_partition(
    p_pi->state_info2 = 0;
    ib_port_info_set_port_state( p_pi, IB_LINK_NO_CHANGE );
 
-   context.pi_context.node_guid = osm_node_get_node_guid( 
osm_physp_get_node_ptr( p_physp ) );
+       context.pi_context.node_guid = 
+               osm_node_get_node_guid( osm_physp_get_node_ptr( p_physp ) );
    context.pi_context.port_guid = osm_physp_get_port_guid( p_physp );
    context.pi_context.set_method = TRUE;
    context.pi_context.update_master_sm_base_lid = FALSE;
@@ -131,80 +257,132 @@ pkey_mgr_enforce_partition(
 
 /**********************************************************************
  **********************************************************************/
-/*
- * Prepare a new entry for the pkey table for this port when this pkey
- * does not exist. Update existed entry when membership was changed.
- */
-static void pkey_mgr_process_physical_port(
-   IN osm_log_t *p_log,
-   IN const osm_req_t *p_req,
-   IN const ib_net16_t pkey,
-   IN osm_physp_t *p_physp )
+static boolean_t pkey_mgr_update_port(
+       osm_log_t *p_log,
+       osm_req_t *p_req,
+       const osm_port_t * const p_port )
 {
-   osm_node_t *p_node = osm_physp_get_node_ptr( p_physp );
-   ib_pkey_table_t *block;
+       osm_physp_t *p_physp;
+       osm_node_t *p_node;
+       ib_pkey_table_t *block, *new_block;
+       osm_pkey_tbl_t *p_pkey_tbl;
    uint16_t block_index;
+       uint8_t  pkey_index;
+       uint16_t last_free_block_index = 0;
+       uint8_t  last_free_pkey_index = 0;
    uint16_t num_of_blocks;
-   const osm_pkey_tbl_t *p_pkey_tbl;
-   ib_net16_t *p_orig_pkey;
-   char *stat = NULL;
-   uint32_t i;
+       uint16_t max_num_of_blocks;
 
-   p_pkey_tbl = osm_physp_get_pkey_tbl( p_physp );
-   num_of_blocks = osm_pkey_tbl_get_num_blocks( p_pkey_tbl );
+       ib_api_status_t status;
+       boolean_t ret_val = FALSE;
+       osm_pending_pkey_t *p_pending;
+       boolean_t found;
 
-   p_orig_pkey = cl_map_get( &p_pkey_tbl->keys, ib_pkey_get_base( pkey ) );
+       p_physp = osm_port_get_default_phys_ptr( p_port );
+       if ( !osm_physp_is_valid( p_physp ) )
+               return FALSE;
 
-   if ( !p_orig_pkey )
-   {
-      for ( block_index = 0; block_index < num_of_blocks; block_index++ )
+       p_node = osm_physp_get_node_ptr( p_physp );
+       p_pkey_tbl = osm_physp_get_mod_pkey_tbl( p_physp );
+       num_of_blocks = osm_pkey_tbl_get_num_blocks( p_pkey_tbl );
+       max_num_of_blocks = pkey_mgr_get_physp_max_blocks( p_req->p_subn, 
p_physp );
+       if (    p_pkey_tbl->max_blocks > max_num_of_blocks )
       {
-         block = osm_pkey_tbl_new_block_get( p_pkey_tbl, block_index );
-         for ( i = 0; i < IB_NUM_PKEY_ELEMENTS_IN_BLOCK; i++ )
+               osm_log( p_log, OSM_LOG_INFO,
+                                       "pkey_mgr_update_port: "
+                                       "Max number of blocks reduced from %u 
to %u " 
+                                       "for node 0x%016" PRIx64 " port %u\n",
+                                       p_pkey_tbl->max_blocks, 
max_num_of_blocks,
+                                       cl_ntoh64( osm_node_get_node_guid( 
p_node ) ),
+                                       osm_physp_get_port_num( p_physp ) );    
                        
+       }
+       p_pkey_tbl->max_blocks = max_num_of_blocks;
+
+       osm_pkey_tbl_init_new_blocks( p_pkey_tbl );
+       p_pkey_tbl->used_blocks = 0;
+
+       /* 
+               process every pending pkey in order - 
+               first must be "updated" last are "new" 
+       */
+       p_pending = 
+               (osm_pending_pkey_t *)cl_qlist_remove_head( 
&p_pkey_tbl->pending );
+       while (p_pending != 
+                        (osm_pending_pkey_t *)cl_qlist_end( 
&p_pkey_tbl->pending ) )
+       {
+               if (p_pending->is_new == FALSE)
+               {
+                       block_index = p_pending->block;
+                       pkey_index = p_pending->index;
+                       found = TRUE;
+               } 
+               else
          {
-            if ( ib_pkey_is_invalid( block->pkey_entry[i] ) )
+                       found = osm_pkey_find_next_free_entry(p_pkey_tbl, 
+                                                                               
                                          &last_free_block_index,
+                                                                               
                                          &last_free_pkey_index);
+                       if ( !found )
             {
-               block->pkey_entry[i] = pkey;
-              stat = "inserted";
-              goto _done;
+                               osm_log( p_log, OSM_LOG_ERROR,
+                                                       "pkey_mgr_update_port: 
ERR 0504: "
+                                                       "failed to find empty 
space for new pkey 0x%04x "
+                                                       "of node 0x%016" PRIx64 
" port %u\n",
+                                                       
cl_ntoh16(p_pending->pkey),
+                                                       cl_ntoh64( 
osm_node_get_node_guid( p_node ) ),
+                                                       osm_physp_get_port_num( 
p_physp ) );
             }
+                       else
+                       {
+                               block_index = last_free_block_index;
+                               pkey_index = last_free_pkey_index++;
          }
       }
+               
+               if (found) 
+               {
+                       if ( IB_SUCCESS != osm_pkey_tbl_set_new_entry( 
+                                         p_pkey_tbl, block_index, pkey_index, 
p_pending->pkey) )
+                       {
       osm_log( p_log, OSM_LOG_ERROR,
-               "pkey_mgr_process_physical_port: ERR 0501: "
-               "No empty pkey entry was found to insert 0x%04x for node "
-               "0x%016" PRIx64 " port %u\n",
-               cl_ntoh16( pkey ),
+                                                       "pkey_mgr_update_port: 
ERR 0505: "
+                                                       "failed to set PKey 
0x%04x in block %u idx %u "
+                                                       "of node 0x%016" PRIx64 
" port %u\n",
+                                                       p_pending->pkey, 
block_index, pkey_index,
                cl_ntoh64( osm_node_get_node_guid( p_node ) ),
                osm_physp_get_port_num( p_physp ) );
    }
-   else if ( *p_orig_pkey != pkey )
-   {
+               }
+
+               free( p_pending );
+               p_pending = 
+                       (osm_pending_pkey_t *)cl_qlist_remove_head( 
&p_pkey_tbl->pending );
+       }
+
+       /* now look for changes and store */
       for ( block_index = 0; block_index < num_of_blocks; block_index++ )
       {
-         /* we need real block (not just new_block) in order
-          * to resolve block/pkey indices */
          block = osm_pkey_tbl_block_get( p_pkey_tbl, block_index );
-        i = p_orig_pkey - block->pkey_entry;
-        if (i < IB_NUM_PKEY_ELEMENTS_IN_BLOCK) {
-            block = osm_pkey_tbl_new_block_get( p_pkey_tbl, block_index );
-           block->pkey_entry[i] = pkey;
-           stat = "updated";
-           goto _done;
-        }
-      }
-   }
+               new_block = osm_pkey_tbl_new_block_get( p_pkey_tbl, block_index 
);
 
- _done:
-   if (stat) {
-      osm_log( p_log, OSM_LOG_VERBOSE,
-               "pkey_mgr_process_physical_port:  "
-               "pkey 0x%04x was %s for node 0x%016" PRIx64
-               " port %u\n",
-               cl_ntoh16( pkey ), stat,
+               if (block && 
+                        (!new_block || !memcmp( new_block, block, sizeof( 
*block ) )) )
+                       continue;
+
+               status = pkey_mgr_update_pkey_entry(
+                       p_req, p_physp , new_block, block_index );
+               if (status == IB_SUCCESS)
+                       ret_val = TRUE;
+               else
+                       osm_log( p_log, OSM_LOG_ERROR,
+                                               "pkey_mgr_update_port: ERR 
0506: "
+                                               "pkey_mgr_update_pkey_entry() 
failed to update "
+                                               "pkey table block %d for node 
0x%016" PRIx64 " port %u\n",
+                                               block_index,
                cl_ntoh64( osm_node_get_node_guid( p_node ) ),
                osm_physp_get_port_num( p_physp ) );
    }
+
+       return ret_val;
 }
 
 /**********************************************************************
@@ -217,21 +395,23 @@ pkey_mgr_update_peer_port(
    const osm_port_t * const p_port,
    boolean_t enforce )
 {
-   osm_physp_t *p, *peer;
+       osm_physp_t *p_physp, *peer;
    osm_node_t *p_node;
    ib_pkey_table_t *block, *peer_block;
-   const osm_pkey_tbl_t *p_pkey_tbl, *p_peer_pkey_tbl;
+       const osm_pkey_tbl_t *p_pkey_tbl;
+       osm_pkey_tbl_t *p_peer_pkey_tbl;
    osm_switch_t *p_sw;
    ib_switch_info_t *p_si;
    uint16_t block_index;
    uint16_t num_of_blocks;
+       uint16_t peer_max_blocks;
    ib_api_status_t status = IB_SUCCESS;
    boolean_t ret_val = FALSE;
 
-   p = osm_port_get_default_phys_ptr( p_port );
-   if ( !osm_physp_is_valid( p ) )
+       p_physp = osm_port_get_default_phys_ptr( p_port );
+       if ( !osm_physp_is_valid( p_physp ) )
       return FALSE;
-   peer = osm_physp_get_remote( p );
+       peer = osm_physp_get_remote( p_physp );
    if ( !peer || !osm_physp_is_valid( peer ) )
       return FALSE;
    p_node = osm_physp_get_node_ptr( peer );
@@ -242,10 +422,26 @@ pkey_mgr_update_peer_port(
    if (!p_sw || !(p_si = osm_switch_get_si_ptr( p_sw )) || !p_si->enforce_cap)
       return FALSE;
 
+       p_pkey_tbl = osm_physp_get_pkey_tbl( p_physp );
+       p_peer_pkey_tbl = osm_physp_get_mod_pkey_tbl( peer );
+       num_of_blocks = osm_pkey_tbl_get_num_blocks( p_pkey_tbl );
+       peer_max_blocks = pkey_mgr_get_physp_max_blocks( p_subn, peer );
+       if (peer_max_blocks < p_pkey_tbl->used_blocks)
+       {
+               osm_log( p_log, OSM_LOG_ERROR,
+                                       "pkey_mgr_update_peer_port: ERR 0508: "
+                                       "not enough entries (%u < %u) on switch 
0x%016" PRIx64
+                                       " port %u. Clearing Enforcement bit.\n",
+                                       peer_max_blocks, num_of_blocks,
+                                       cl_ntoh64( osm_node_get_node_guid( 
p_node ) ),
+                                       osm_physp_get_port_num( peer ) );
+               enforce = FALSE;
+       }
+
    if (pkey_mgr_enforce_partition( p_req, peer, enforce ) != IB_SUCCESS)
    {
       osm_log( p_log, OSM_LOG_ERROR,
-               "pkey_mgr_update_peer_port: ERR 0502: "
+                                       "pkey_mgr_update_peer_port: ERR 0507: "
                "pkey_mgr_enforce_partition() failed to update "
                "node 0x%016" PRIx64 " port %u\n",
                cl_ntoh64( osm_node_get_node_guid( p_node ) ),
@@ -255,24 +451,19 @@ pkey_mgr_update_peer_port(
    if (enforce == FALSE)
       return FALSE;
 
-   p_pkey_tbl = osm_physp_get_pkey_tbl( p );
-   p_peer_pkey_tbl = osm_physp_get_pkey_tbl( peer );
-   num_of_blocks = osm_pkey_tbl_get_num_blocks( p_pkey_tbl );
-   if ( num_of_blocks > osm_pkey_tbl_get_num_blocks( p_peer_pkey_tbl ) )
-      num_of_blocks = osm_pkey_tbl_get_num_blocks( p_peer_pkey_tbl );
-
-   for ( block_index = 0; block_index < num_of_blocks; block_index++ )
+       p_peer_pkey_tbl->used_blocks = p_pkey_tbl->used_blocks;
+       for ( block_index = 0; block_index < p_pkey_tbl->used_blocks; 
block_index++)
    {
       block = osm_pkey_tbl_new_block_get( p_pkey_tbl, block_index );
       peer_block = osm_pkey_tbl_block_get( p_peer_pkey_tbl, block_index );
-      if ( memcmp( peer_block, block, sizeof( *peer_block ) ) )
+               if ( !peer_block || memcmp( peer_block, block, sizeof( 
*peer_block ) ) )
       {
          status = pkey_mgr_update_pkey_entry( p_req, peer, block, block_index 
);
          if ( status == IB_SUCCESS )
             ret_val = TRUE;
          else
             osm_log( p_log, OSM_LOG_ERROR,
-                     "pkey_mgr_update_peer_port: ERR 0503: "
+                                                       
"pkey_mgr_update_peer_port: ERR 0509: "
                      "pkey_mgr_update_pkey_entry() failed to update "
                      "pkey table block %d for node 0x%016" PRIx64
                      " port %u\n",
@@ -282,10 +473,10 @@ pkey_mgr_update_peer_port(
       }
    }
 
-   if ( ret_val == TRUE &&
-        osm_log_is_active( p_log, OSM_LOG_VERBOSE ) )
+       if ( (ret_val == TRUE) &&
+                 osm_log_is_active( p_log, OSM_LOG_DEBUG ) )
    {
-      osm_log( p_log, OSM_LOG_VERBOSE,
+               osm_log( p_log, OSM_LOG_DEBUG,
                "pkey_mgr_update_peer_port: "
                "pkey table was updated for node 0x%016" PRIx64
                " port %u\n",
@@ -298,82 +489,6 @@ pkey_mgr_update_peer_port(
 
 /**********************************************************************
  **********************************************************************/
-static boolean_t pkey_mgr_update_port(
-   osm_log_t *p_log,
-   osm_req_t *p_req,
-   const osm_port_t * const p_port )
-{
-   osm_physp_t *p;
-   osm_node_t *p_node;
-   ib_pkey_table_t *block, *new_block;
-   const osm_pkey_tbl_t *p_pkey_tbl;
-   uint16_t block_index;
-   uint16_t num_of_blocks;
-   ib_api_status_t status;
-   boolean_t ret_val = FALSE;
-
-   p = osm_port_get_default_phys_ptr( p_port );
-   if ( !osm_physp_is_valid( p ) )
-      return FALSE;
-
-   p_pkey_tbl = osm_physp_get_pkey_tbl(p);
-   num_of_blocks = osm_pkey_tbl_get_num_blocks( p_pkey_tbl );
-
-   for ( block_index = 0; block_index < num_of_blocks; block_index++ )
-   {
-      block = osm_pkey_tbl_block_get( p_pkey_tbl, block_index );
-      new_block = osm_pkey_tbl_new_block_get( p_pkey_tbl, block_index );
-
-      if (!new_block || !memcmp( new_block, block, sizeof( *block ) ) )
-         continue;
-
-      status = pkey_mgr_update_pkey_entry( p_req, p, new_block, block_index );
-      if (status == IB_SUCCESS)
-         ret_val = TRUE;
-      else
-         osm_log( p_log, OSM_LOG_ERROR,
-                  "pkey_mgr_update_port: ERR 0504: "
-                  "pkey_mgr_update_pkey_entry() failed to update "
-                  "pkey table block %d for node 0x%016" PRIx64 " port %u\n",
-                  block_index,
-                  cl_ntoh64( osm_node_get_node_guid( p_node ) ),
-                  osm_physp_get_port_num( p ) );
-   }
-
-   return ret_val;
-}
-
-/**********************************************************************
- **********************************************************************/
-static void
-pkey_mgr_process_partition_table(
-   osm_log_t *p_log,
-   const osm_req_t *p_req,
-   const osm_prtn_t *p_prtn,
-   const boolean_t full )
-{
-   const cl_map_t *p_tbl = full ?
-      &p_prtn->full_guid_tbl : &p_prtn->part_guid_tbl;
-   cl_map_iterator_t i, i_next;
-   ib_net16_t pkey = p_prtn->pkey;
-   osm_physp_t *p_physp;
-
-   if ( full )
-      pkey = cl_hton16( cl_ntoh16( pkey ) | 0x8000 );
-
-   i_next = cl_map_head( p_tbl );
-   while ( i_next != cl_map_end( p_tbl ) )
-   {
-      i = i_next;
-      i_next = cl_map_next( i );
-      p_physp = cl_map_obj( i );
-      if ( p_physp && osm_physp_is_valid( p_physp ) )
-          pkey_mgr_process_physical_port( p_log, p_req, pkey, p_physp );
-   }
-}
-
-/**********************************************************************
- **********************************************************************/
 osm_signal_t
 osm_pkey_mgr_process(
    IN osm_opensm_t *p_osm )
@@ -383,8 +498,7 @@ osm_pkey_mgr_process(
    osm_prtn_t *p_prtn;
    osm_port_t *p_port;
    osm_signal_t signal = OSM_SIGNAL_DONE;
-   osm_physp_t *p_physp;
-
+       osm_node_t *p_node;
    CL_ASSERT( p_osm );
 
    OSM_LOG_ENTER( &p_osm->log, osm_pkey_mgr_process );
@@ -394,32 +508,25 @@ osm_pkey_mgr_process(
    if ( osm_prtn_make_partitions( &p_osm->log, &p_osm->subn ) != IB_SUCCESS )
    {
       osm_log( &p_osm->log, OSM_LOG_ERROR,
-               "osm_pkey_mgr_process: ERR 0505: "
+                                       "osm_pkey_mgr_process: ERR 0510: "
                "osm_prtn_make_partitions() failed\n" );
       goto _err;
    }
 
-   p_tbl = &p_osm->subn.port_guid_tbl;
-   p_next = cl_qmap_head( p_tbl );
-   while ( p_next != cl_qmap_end( p_tbl ) )
-   {
-      p_port = ( osm_port_t * ) p_next;
-      p_next = cl_qmap_next( p_next );
-      p_physp = osm_port_get_default_phys_ptr( p_port );
-      if ( osm_physp_is_valid( p_physp ) )
-        osm_pkey_tbl_sync_new_blocks( osm_physp_get_pkey_tbl( p_physp ) );
-   }
-
+       /* populate the pending pkey entries by scanning all partitions */
    p_tbl = &p_osm->subn.prtn_pkey_tbl;
    p_next = cl_qmap_head( p_tbl );
    while ( p_next != cl_qmap_end( p_tbl ) )
    {
       p_prtn = ( osm_prtn_t * ) p_next;
       p_next = cl_qmap_next( p_next );
-      pkey_mgr_process_partition_table( &p_osm->log, &p_osm->sm.req, p_prtn, 
FALSE );
-      pkey_mgr_process_partition_table( &p_osm->log, &p_osm->sm.req, p_prtn, 
TRUE );
+               pkey_mgr_process_partition_table( 
+                       &p_osm->log, &p_osm->sm.req, p_prtn, FALSE );
+               pkey_mgr_process_partition_table( 
+                       &p_osm->log, &p_osm->sm.req, p_prtn, TRUE );
    }
 
+       /* calculate new pkey tables and set */
    p_tbl = &p_osm->subn.port_guid_tbl;
    p_next = cl_qmap_head( p_tbl );
    while ( p_next != cl_qmap_end( p_tbl ) )
@@ -428,8 +535,10 @@ osm_pkey_mgr_process(
       p_next = cl_qmap_next( p_next );
       if ( pkey_mgr_update_port( &p_osm->log, &p_osm->sm.req, p_port ) )
         signal = OSM_SIGNAL_DONE_PENDING;
-      if ( osm_node_get_type( osm_port_get_parent_node( p_port ) ) != 
IB_NODE_TYPE_SWITCH &&
-           pkey_mgr_update_peer_port( &p_osm->log, &p_osm->sm.req,
+               p_node = osm_port_get_parent_node( p_port );
+               if ( ( osm_node_get_type( p_node ) != IB_NODE_TYPE_SWITCH ) &&
+                         pkey_mgr_update_peer_port( 
+                                 &p_osm->log, &p_osm->sm.req,
                                       &p_osm->subn, p_port,
                                       
!p_osm->subn.opt.no_partition_enforcement ) )
         signal = OSM_SIGNAL_DONE_PENDING;        


_______________________________________________
openib-general mailing list
openib-general@openib.org
http://openib.org/mailman/listinfo/openib-general

To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general

Reply via email to