]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ofed/management/opensm/opensm/osm_pkey.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ofed / management / opensm / opensm / osm_pkey.c
1 /*
2  * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  *
34  */
35
36 /*
37  * Abstract:
38  *    Implementation of opensm pkey manipulation functions.
39  */
40
41 #if HAVE_CONFIG_H
42 #  include <config.h>
43 #endif                          /* HAVE_CONFIG_H */
44
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <complib/cl_debug.h>
49 #include <iba/ib_types.h>
50 #include <opensm/osm_pkey.h>
51 #include <opensm/osm_log.h>
52 #include <opensm/osm_port.h>
53 #include <opensm/osm_node.h>
54 #include <opensm/osm_switch.h>
55 #include <opensm/osm_helper.h>
56
57 /**********************************************************************
58  **********************************************************************/
59 void osm_pkey_tbl_construct(IN osm_pkey_tbl_t * p_pkey_tbl)
60 {
61         cl_ptr_vector_construct(&p_pkey_tbl->blocks);
62         cl_ptr_vector_construct(&p_pkey_tbl->new_blocks);
63         cl_map_construct(&p_pkey_tbl->keys);
64 }
65
66 /**********************************************************************
67  **********************************************************************/
68 void osm_pkey_tbl_destroy(IN osm_pkey_tbl_t * p_pkey_tbl)
69 {
70         ib_pkey_table_t *p_block;
71         uint16_t num_blocks, i;
72
73         num_blocks = (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->blocks));
74         for (i = 0; i < num_blocks; i++)
75                 if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, i)))
76                         free(p_block);
77         cl_ptr_vector_destroy(&p_pkey_tbl->blocks);
78
79         num_blocks =
80             (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks));
81         for (i = 0; i < num_blocks; i++)
82                 if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, i)))
83                         free(p_block);
84         cl_ptr_vector_destroy(&p_pkey_tbl->new_blocks);
85
86         cl_map_remove_all(&p_pkey_tbl->keys);
87         cl_map_destroy(&p_pkey_tbl->keys);
88 }
89
90 /**********************************************************************
91  **********************************************************************/
92 ib_api_status_t osm_pkey_tbl_init(IN osm_pkey_tbl_t * p_pkey_tbl)
93 {
94         cl_ptr_vector_init(&p_pkey_tbl->blocks, 0, 1);
95         cl_ptr_vector_init(&p_pkey_tbl->new_blocks, 0, 1);
96         cl_map_init(&p_pkey_tbl->keys, 1);
97         cl_qlist_init(&p_pkey_tbl->pending);
98         p_pkey_tbl->used_blocks = 0;
99         p_pkey_tbl->max_blocks = 0;
100         return (IB_SUCCESS);
101 }
102
103 /**********************************************************************
104  **********************************************************************/
105 void osm_pkey_tbl_init_new_blocks(IN const osm_pkey_tbl_t * p_pkey_tbl)
106 {
107         ib_pkey_table_t *p_block;
108         size_t b, num_blocks = cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks);
109
110         for (b = 0; b < num_blocks; b++)
111                 if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, b)))
112                         memset(p_block, 0, sizeof(*p_block));
113 }
114
115 /**********************************************************************
116  **********************************************************************/
117 void osm_pkey_tbl_cleanup_pending(IN osm_pkey_tbl_t * p_pkey_tbl)
118 {
119         cl_list_item_t *p_item;
120
121         p_item = cl_qlist_remove_head(&p_pkey_tbl->pending);
122         while (p_item != cl_qlist_end(&p_pkey_tbl->pending)) {
123                 free((osm_pending_pkey_t *) p_item);
124         }
125 }
126
127 /**********************************************************************
128  **********************************************************************/
129 ib_api_status_t
130 osm_pkey_tbl_set(IN osm_pkey_tbl_t * p_pkey_tbl,
131                  IN uint16_t block, IN ib_pkey_table_t * p_tbl)
132 {
133         uint16_t b, i;
134         ib_pkey_table_t *p_pkey_block;
135         uint16_t *p_prev_pkey;
136         ib_net16_t pkey;
137
138         /* make sure the block is allocated */
139         if (cl_ptr_vector_get_size(&p_pkey_tbl->blocks) > block)
140                 p_pkey_block =
141                     (ib_pkey_table_t *) cl_ptr_vector_get(&p_pkey_tbl->blocks,
142                                                           block);
143         else
144                 p_pkey_block = NULL;
145
146         if (!p_pkey_block) {
147                 p_pkey_block =
148                     (ib_pkey_table_t *) malloc(sizeof(ib_pkey_table_t));
149                 if (!p_pkey_block)
150                         return (IB_ERROR);
151                 memset(p_pkey_block, 0, sizeof(ib_pkey_table_t));
152                 cl_ptr_vector_set(&p_pkey_tbl->blocks, block, p_pkey_block);
153         }
154
155         /* sets the block values */
156         memcpy(p_pkey_block, p_tbl, sizeof(ib_pkey_table_t));
157
158         /*
159            NOTE: as the spec does not require uniqueness of PKeys in
160            tables there is no other way but to refresh the entire keys map.
161
162            Moreover, if the same key exists but with full membership it should
163            have precedence on the key with limited membership !
164          */
165         cl_map_remove_all(&p_pkey_tbl->keys);
166
167         for (b = 0; b < cl_ptr_vector_get_size(&p_pkey_tbl->blocks); b++) {
168
169                 p_pkey_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, b);
170                 if (!p_pkey_block)
171                         continue;
172
173                 for (i = 0; i < IB_NUM_PKEY_ELEMENTS_IN_BLOCK; i++) {
174                         pkey = p_pkey_block->pkey_entry[i];
175                         if (ib_pkey_is_invalid(pkey))
176                                 continue;
177
178                         /*
179                            ignore the PKey Full Member bit in the key but store
180                            the pointer to the table element as the map value
181                          */
182                         p_prev_pkey =
183                             cl_map_get(&p_pkey_tbl->keys,
184                                        ib_pkey_get_base(pkey));
185
186                         /* we only insert if no previous or it is not full member */
187                         if ((p_prev_pkey == NULL) ||
188                             (cl_ntoh16(*p_prev_pkey) < cl_ntoh16(pkey)))
189                                 cl_map_insert(&p_pkey_tbl->keys,
190                                               ib_pkey_get_base(pkey),
191                                               &(p_pkey_block->pkey_entry[i])
192                                     );
193                 }
194         }
195         return (IB_SUCCESS);
196 }
197
198 /**********************************************************************
199  **********************************************************************/
200 /*
201   Store the given pkey in the "new" blocks array.
202   Also, make sure the regular block exists.
203 */
204 ib_api_status_t
205 osm_pkey_tbl_set_new_entry(IN osm_pkey_tbl_t * p_pkey_tbl,
206                            IN uint16_t block_idx,
207                            IN uint8_t pkey_idx, IN uint16_t pkey)
208 {
209         ib_pkey_table_t *p_block;
210
211         if (!(p_block = osm_pkey_tbl_new_block_get(p_pkey_tbl, block_idx))) {
212                 p_block = (ib_pkey_table_t *) malloc(sizeof(ib_pkey_table_t));
213                 if (!p_block)
214                         return (IB_ERROR);
215                 memset(p_block, 0, sizeof(ib_pkey_table_t));
216                 cl_ptr_vector_set(&p_pkey_tbl->new_blocks, block_idx, p_block);
217         }
218
219         p_block->pkey_entry[pkey_idx] = pkey;
220         if (p_pkey_tbl->used_blocks <= block_idx)
221                 p_pkey_tbl->used_blocks = block_idx + 1;
222
223         return (IB_SUCCESS);
224 }
225
226 /**********************************************************************
227  **********************************************************************/
228 boolean_t
229 osm_pkey_find_next_free_entry(IN osm_pkey_tbl_t * p_pkey_tbl,
230                               OUT uint16_t * p_block_idx,
231                               OUT uint8_t * p_pkey_idx)
232 {
233         ib_pkey_table_t *p_new_block;
234
235         CL_ASSERT(p_block_idx);
236         CL_ASSERT(p_pkey_idx);
237
238         while (*p_block_idx < p_pkey_tbl->max_blocks) {
239                 if (*p_pkey_idx > IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) {
240                         *p_pkey_idx = 0;
241                         (*p_block_idx)++;
242                         if (*p_block_idx >= p_pkey_tbl->max_blocks)
243                                 return FALSE;
244                 }
245
246                 p_new_block =
247                     osm_pkey_tbl_new_block_get(p_pkey_tbl, *p_block_idx);
248
249                 if (!p_new_block ||
250                     ib_pkey_is_invalid(p_new_block->pkey_entry[*p_pkey_idx]))
251                         return TRUE;
252                 else
253                         (*p_pkey_idx)++;
254         }
255         return FALSE;
256 }
257
258 /**********************************************************************
259  **********************************************************************/
260 ib_api_status_t
261 osm_pkey_tbl_get_block_and_idx(IN osm_pkey_tbl_t * p_pkey_tbl,
262                                IN uint16_t * p_pkey,
263                                OUT uint16_t * p_block_idx,
264                                OUT uint8_t * p_pkey_idx)
265 {
266         uint16_t num_of_blocks;
267         uint16_t block_index;
268         ib_pkey_table_t *block;
269
270         CL_ASSERT(p_block_idx != NULL);
271         CL_ASSERT(p_pkey_idx != NULL);
272
273         num_of_blocks = (uint16_t) cl_ptr_vector_get_size(&p_pkey_tbl->blocks);
274         for (block_index = 0; block_index < num_of_blocks; block_index++) {
275                 block = osm_pkey_tbl_block_get(p_pkey_tbl, block_index);
276                 if ((block->pkey_entry <= p_pkey) &&
277                     (p_pkey <
278                      block->pkey_entry + IB_NUM_PKEY_ELEMENTS_IN_BLOCK)) {
279                         *p_block_idx = block_index;
280                         *p_pkey_idx = (uint8_t) (p_pkey - block->pkey_entry);
281                         return (IB_SUCCESS);
282                 }
283         }
284         return (IB_NOT_FOUND);
285 }
286
287 /**********************************************************************
288  **********************************************************************/
289 static boolean_t
290 __osm_match_pkey(IN const ib_net16_t * pkey1, IN const ib_net16_t * pkey2)
291 {
292
293         /* if both pkeys are not full member - this is not a match */
294         if (!(ib_pkey_is_full_member(*pkey1) || ib_pkey_is_full_member(*pkey2)))
295                 return (FALSE);
296
297         /* compare if the bases are the same. if they are - then
298            this is a match */
299         if (ib_pkey_get_base(*pkey1) != ib_pkey_get_base(*pkey2))
300                 return (FALSE);
301
302         return (TRUE);
303 }
304
305 /**********************************************************************
306  **********************************************************************/
307 boolean_t
308 osm_physp_share_this_pkey(IN const osm_physp_t * const p_physp1,
309                           IN const osm_physp_t * const p_physp2,
310                           IN const ib_net16_t pkey)
311 {
312         ib_net16_t *pkey1, *pkey2;
313
314         pkey1 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp1))->keys,
315                            ib_pkey_get_base(pkey));
316         pkey2 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp2))->keys,
317                            ib_pkey_get_base(pkey));
318         return (pkey1 && pkey2 && __osm_match_pkey(pkey1, pkey2));
319 }
320
321 /**********************************************************************
322  **********************************************************************/
323 ib_net16_t
324 osm_physp_find_common_pkey(IN const osm_physp_t * const p_physp1,
325                            IN const osm_physp_t * const p_physp2)
326 {
327         ib_net16_t *pkey1, *pkey2;
328         uint64_t pkey1_base, pkey2_base;
329         const osm_pkey_tbl_t *pkey_tbl1, *pkey_tbl2;
330         cl_map_iterator_t map_iter1, map_iter2;
331
332         pkey_tbl1 = osm_physp_get_pkey_tbl(p_physp1);
333         pkey_tbl2 = osm_physp_get_pkey_tbl(p_physp2);
334
335         map_iter1 = cl_map_head(&pkey_tbl1->keys);
336         map_iter2 = cl_map_head(&pkey_tbl2->keys);
337
338         /* we rely on the fact the map are sorted by pkey */
339         while ((map_iter1 != cl_map_end(&pkey_tbl1->keys)) &&
340                (map_iter2 != cl_map_end(&pkey_tbl2->keys))) {
341                 pkey1 = (ib_net16_t *) cl_map_obj(map_iter1);
342                 pkey2 = (ib_net16_t *) cl_map_obj(map_iter2);
343
344                 if (__osm_match_pkey(pkey1, pkey2))
345                         return *pkey1;
346
347                 /* advance the lower value if they are not equal */
348                 pkey1_base = cl_map_key(map_iter1);
349                 pkey2_base = cl_map_key(map_iter2);
350                 if (pkey2_base == pkey1_base) {
351                         map_iter1 = cl_map_next(map_iter1);
352                         map_iter2 = cl_map_next(map_iter2);
353                 } else if (pkey2_base < pkey1_base)
354                         map_iter2 = cl_map_next(map_iter2);
355                 else
356                         map_iter1 = cl_map_next(map_iter1);
357         }
358
359         return 0;
360 }
361
362 /**********************************************************************
363  **********************************************************************/
364 boolean_t
365 osm_physp_share_pkey(IN osm_log_t * p_log,
366                      IN const osm_physp_t * const p_physp_1,
367                      IN const osm_physp_t * const p_physp_2)
368 {
369         const osm_pkey_tbl_t *pkey_tbl1, *pkey_tbl2;
370
371         if (p_physp_1 == p_physp_2)
372                 return TRUE;
373
374         pkey_tbl1 = osm_physp_get_pkey_tbl(p_physp_1);
375         pkey_tbl2 = osm_physp_get_pkey_tbl(p_physp_2);
376
377         /*
378            The spec: 10.9.2 does not require each phys port to have PKey Table.
379            So actually if it does not, we need to use the default port instead.
380
381            HACK: meanwhile we will ignore the check
382          */
383         if (cl_is_map_empty(&pkey_tbl1->keys)
384             || cl_is_map_empty(&pkey_tbl2->keys))
385                 return TRUE;
386
387         return
388             !ib_pkey_is_invalid(osm_physp_find_common_pkey
389                                 (p_physp_1, p_physp_2));
390 }
391
392 /**********************************************************************
393  **********************************************************************/
394 boolean_t
395 osm_port_share_pkey(IN osm_log_t * p_log,
396                     IN const osm_port_t * const p_port_1,
397                     IN const osm_port_t * const p_port_2)
398 {
399
400         osm_physp_t *p_physp1, *p_physp2;
401         boolean_t ret;
402
403         OSM_LOG_ENTER(p_log);
404
405         if (!p_port_1 || !p_port_2) {
406                 ret = FALSE;
407                 goto Exit;
408         }
409
410         p_physp1 = p_port_1->p_physp;
411         p_physp2 = p_port_2->p_physp;
412
413         if (!p_physp1 || !p_physp2) {
414                 ret = FALSE;
415                 goto Exit;
416         }
417
418         ret = osm_physp_share_pkey(p_log, p_physp1, p_physp2);
419
420 Exit:
421         OSM_LOG_EXIT(p_log);
422         return ret;
423 }
424
425 /**********************************************************************
426  **********************************************************************/
427 boolean_t
428 osm_physp_has_pkey(IN osm_log_t * p_log,
429                    IN const ib_net16_t pkey,
430                    IN const osm_physp_t * const p_physp)
431 {
432
433         ib_net16_t *p_pkey, pkey_base;
434         const osm_pkey_tbl_t *pkey_tbl;
435         boolean_t res = FALSE;
436
437         OSM_LOG_ENTER(p_log);
438
439         OSM_LOG(p_log, OSM_LOG_DEBUG,
440                 "Search for PKey: 0x%04x\n", cl_ntoh16(pkey));
441
442         /* if the pkey given is an invalid pkey - return TRUE. */
443         if (ib_pkey_is_invalid(pkey)) {
444                 OSM_LOG(p_log, OSM_LOG_DEBUG,
445                         "Given invalid PKey - we treat it loosely and allow it\n");
446                 res = TRUE;
447                 goto Exit;
448         }
449
450         pkey_base = ib_pkey_get_base(pkey);
451
452         pkey_tbl = osm_physp_get_pkey_tbl(p_physp);
453
454         p_pkey = cl_map_get(&pkey_tbl->keys, pkey_base);
455         if (p_pkey) {
456                 res = TRUE;
457                 OSM_LOG(p_log, OSM_LOG_DEBUG,
458                         "PKey 0x%04x was found\n", cl_ntoh16(pkey));
459         } else {
460                 OSM_LOG(p_log, OSM_LOG_DEBUG,
461                         "PKey 0x%04x was not found\n", cl_ntoh16(pkey));
462         }
463
464 Exit:
465         OSM_LOG_EXIT(p_log);
466         return res;
467 }