[OPENSM] set opensm cache & config folder as %ProgramFiles%\WinOF\OpenSM; integrated...
[mirror/winof/.git] / ulp / libibnetdisc / src / chassis.c
1 /*
2  * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
3  * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
4  * Copyright (c) 2008 Lawrence Livermore National Lab.  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 /*               FABRIC SCANNER SPECIFIC DATA             */
38 /*========================================================*/
39
40 #if HAVE_CONFIG_H
41 #  include <config.h>
42 #endif                          /* HAVE_CONFIG_H */
43
44 #include <stdlib.h>
45 #include <inttypes.h>
46
47 #include <infiniband/mad.h>
48
49 #include "internal.h"
50 #include "chassis.h"
51
52 static char *ChassisTypeStr[5] =
53     { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004" };
54 static char *ChassisSlotTypeStr[4] = { "", "Line", "Spine", "SRBD" };
55
56 char *ibnd_get_chassis_type(ibnd_node_t * node)
57 {
58         if (!node) {
59                 IBND_DEBUG("node parameter NULL\n");
60                 return (NULL);
61         }
62
63         /* Currently, only if Voltaire chassis */
64         if (mad_get_field(node->info, 0, IB_NODE_VENDORID_F) != VTR_VENDOR_ID)
65                 return (NULL);
66         if (!node->chassis)
67                 return (NULL);
68         if (node->ch_type == UNRESOLVED_CT || node->ch_type > ISR2004_CT)
69                 return (NULL);
70         return ChassisTypeStr[node->ch_type];
71 }
72
73 char *ibnd_get_chassis_slot_str(ibnd_node_t * node, char *str, size_t size)
74 {
75         if (!node) {
76                 IBND_DEBUG("node parameter NULL\n");
77                 return (NULL);
78         }
79
80         /* Currently, only if Voltaire chassis */
81         if (mad_get_field(node->info, 0, IB_NODE_VENDORID_F) != VTR_VENDOR_ID)
82                 return (NULL);
83         if (!node->chassis)
84                 return (NULL);
85         if (node->ch_slot == UNRESOLVED_CS || node->ch_slot > SRBD_CS)
86                 return (NULL);
87         if (!str)
88                 return (NULL);
89         snprintf(str, size, "%s %d Chip %d", ChassisSlotTypeStr[node->ch_slot],
90                  node->ch_slotnum, node->ch_anafanum);
91         return (str);
92 }
93
94 static ibnd_chassis_t *find_chassisnum(ibnd_fabric_t * fabric,
95                                        unsigned char chassisnum)
96 {
97         ibnd_chassis_t *current;
98
99         for (current = fabric->first_chassis; current; current = current->next) {
100                 if (current->chassisnum == chassisnum)
101                         return current;
102         }
103
104         return NULL;
105 }
106
107 static uint64_t topspin_chassisguid(uint64_t guid)
108 {
109         /* Byte 3 in system image GUID is chassis type, and */
110         /* Byte 4 is location ID (slot) so just mask off byte 4 */
111         return guid & 0xffffffff00ffffffULL;
112 }
113
114 int ibnd_is_xsigo_guid(uint64_t guid)
115 {
116         if ((guid & 0xffffff0000000000ULL) == 0x0013970000000000ULL)
117                 return 1;
118         else
119                 return 0;
120 }
121
122 static int is_xsigo_leafone(uint64_t guid)
123 {
124         if ((guid & 0xffffffffff000000ULL) == 0x0013970102000000ULL)
125                 return 1;
126         else
127                 return 0;
128 }
129
130 int ibnd_is_xsigo_hca(uint64_t guid)
131 {
132         /* NodeType 2 is HCA */
133         if ((guid & 0xffffffff00000000ULL) == 0x0013970200000000ULL)
134                 return 1;
135         else
136                 return 0;
137 }
138
139 int ibnd_is_xsigo_tca(uint64_t guid)
140 {
141         /* NodeType 3 is TCA */
142         if ((guid & 0xffffffff00000000ULL) == 0x0013970300000000ULL)
143                 return 1;
144         else
145                 return 0;
146 }
147
148 static int is_xsigo_ca(uint64_t guid)
149 {
150         if (ibnd_is_xsigo_hca(guid) || ibnd_is_xsigo_tca(guid))
151                 return 1;
152         else
153                 return 0;
154 }
155
156 static int is_xsigo_switch(uint64_t guid)
157 {
158         if ((guid & 0xffffffff00000000ULL) == 0x0013970100000000ULL)
159                 return 1;
160         else
161                 return 0;
162 }
163
164 static uint64_t xsigo_chassisguid(ibnd_node_t * node)
165 {
166         uint64_t sysimgguid =
167             mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F);
168         uint64_t remote_sysimgguid;
169
170         if (!is_xsigo_ca(sysimgguid)) {
171                 /* Byte 3 is NodeType and byte 4 is PortType */
172                 /* If NodeType is 1 (switch), PortType is masked */
173                 if (is_xsigo_switch(sysimgguid))
174                         return sysimgguid & 0xffffffff00ffffffULL;
175                 else
176                         return sysimgguid;
177         } else {
178                 if (!node->ports || !node->ports[1])
179                         return (0);
180
181                 /* Is there a peer port ? */
182                 if (!node->ports[1]->remoteport)
183                         return sysimgguid;
184
185                 /* If peer port is Leaf 1, use its chassis GUID */
186                 remote_sysimgguid =
187                     mad_get_field64(node->ports[1]->remoteport->node->info, 0,
188                                     IB_NODE_SYSTEM_GUID_F);
189                 if (is_xsigo_leafone(remote_sysimgguid))
190                         return remote_sysimgguid & 0xffffffff00ffffffULL;
191                 else
192                         return sysimgguid;
193         }
194 }
195
196 static uint64_t get_chassisguid(ibnd_node_t * node)
197 {
198         uint32_t vendid = mad_get_field(node->info, 0, IB_NODE_VENDORID_F);
199         uint64_t sysimgguid =
200             mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F);
201
202         if (vendid == TS_VENDOR_ID || vendid == SS_VENDOR_ID)
203                 return topspin_chassisguid(sysimgguid);
204         else if (vendid == XS_VENDOR_ID || ibnd_is_xsigo_guid(sysimgguid))
205                 return xsigo_chassisguid(node);
206         else
207                 return sysimgguid;
208 }
209
210 static ibnd_chassis_t *find_chassisguid(ibnd_fabric_t * fabric,
211                                         ibnd_node_t * node)
212 {
213         ibnd_chassis_t *current;
214         uint64_t chguid;
215
216         chguid = get_chassisguid(node);
217         for (current = fabric->first_chassis; current; current = current->next) {
218                 if (current->chassisguid == chguid)
219                         return current;
220         }
221
222         return NULL;
223 }
224
225 uint64_t ibnd_get_chassis_guid(ibnd_fabric_t * fabric, unsigned char chassisnum)
226 {
227         ibnd_chassis_t *chassis;
228
229         if (!fabric) {
230                 IBND_DEBUG("fabric parameter NULL\n");
231                 return 0;
232         }
233
234         chassis = find_chassisnum(fabric, chassisnum);
235         if (chassis)
236                 return chassis->chassisguid;
237         else
238                 return 0;
239 }
240
241 static int is_router(ibnd_node_t * n)
242 {
243         uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
244         return (devid == VTR_DEVID_IB_FC_ROUTER ||
245                 devid == VTR_DEVID_IB_IP_ROUTER);
246 }
247
248 static int is_spine_9096(ibnd_node_t * n)
249 {
250         uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
251         return (devid == VTR_DEVID_SFB4 || devid == VTR_DEVID_SFB4_DDR);
252 }
253
254 static int is_spine_9288(ibnd_node_t * n)
255 {
256         uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
257         return (devid == VTR_DEVID_SFB12 || devid == VTR_DEVID_SFB12_DDR);
258 }
259
260 static int is_spine_2004(ibnd_node_t * n)
261 {
262         uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
263         return (devid == VTR_DEVID_SFB2004);
264 }
265
266 static int is_spine_2012(ibnd_node_t * n)
267 {
268         uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
269         return (devid == VTR_DEVID_SFB2012);
270 }
271
272 static int is_spine(ibnd_node_t * n)
273 {
274         return (is_spine_9096(n) || is_spine_9288(n) ||
275                 is_spine_2004(n) || is_spine_2012(n));
276 }
277
278 static int is_line_24(ibnd_node_t * n)
279 {
280         uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
281         return (devid == VTR_DEVID_SLB24 ||
282                 devid == VTR_DEVID_SLB24_DDR || devid == VTR_DEVID_SRB2004);
283 }
284
285 static int is_line_8(ibnd_node_t * n)
286 {
287         uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
288         return (devid == VTR_DEVID_SLB8);
289 }
290
291 static int is_line_2024(ibnd_node_t * n)
292 {
293         uint32_t devid = mad_get_field(n->info, 0, IB_NODE_DEVID_F);
294         return (devid == VTR_DEVID_SLB2024);
295 }
296
297 static int is_line(ibnd_node_t * n)
298 {
299         return (is_line_24(n) || is_line_8(n) || is_line_2024(n));
300 }
301
302 int is_chassis_switch(ibnd_node_t * n)
303 {
304         return (is_spine(n) || is_line(n));
305 }
306
307 /* these structs help find Line (Anafa) slot number while using spine portnum */
308 char line_slot_2_sfb4[25] = {
309         0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
310         4
311 };
312 char anafa_line_slot_2_sfb4[25] = {
313         0, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2,
314         2
315 };
316 char line_slot_2_sfb12[25] = {
317         0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
318         12, 12
319 };
320 char anafa_line_slot_2_sfb12[25] = {
321         0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1,
322         2
323 };
324
325 /* IPR FCR modules connectivity while using sFB4 port as reference */
326 char ipr_slot_2_sfb4_port[25] = {
327         0, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2,
328         1
329 };
330
331 /* these structs help find Spine (Anafa) slot number while using spine portnum */
332 char spine12_slot_2_slb[25] = {
333         0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
334         0
335 };
336 char anafa_spine12_slot_2_slb[25] = {
337         0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
338         0
339 };
340 char spine4_slot_2_slb[25] = {
341         0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
342         0
343 };
344 char anafa_spine4_slot_2_slb[25] = {
345         0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
346         0
347 };
348
349 /*      reference                     { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; */
350
351 static int get_sfb_slot(ibnd_node_t * node, ibnd_port_t * lineport)
352 {
353         ibnd_node_t *n = (ibnd_node_t *) node;
354
355         n->ch_slot = SPINE_CS;
356         if (is_spine_9096(node)) {
357                 n->ch_type = ISR9096_CT;
358                 n->ch_slotnum = spine4_slot_2_slb[lineport->portnum];
359                 n->ch_anafanum = anafa_spine4_slot_2_slb[lineport->portnum];
360         } else if (is_spine_9288(node)) {
361                 n->ch_type = ISR9288_CT;
362                 n->ch_slotnum = spine12_slot_2_slb[lineport->portnum];
363                 n->ch_anafanum = anafa_spine12_slot_2_slb[lineport->portnum];
364         } else if (is_spine_2012(node)) {
365                 n->ch_type = ISR2012_CT;
366                 n->ch_slotnum = spine12_slot_2_slb[lineport->portnum];
367                 n->ch_anafanum = anafa_spine12_slot_2_slb[lineport->portnum];
368         } else if (is_spine_2004(node)) {
369                 n->ch_type = ISR2004_CT;
370                 n->ch_slotnum = spine4_slot_2_slb[lineport->portnum];
371                 n->ch_anafanum = anafa_spine4_slot_2_slb[lineport->portnum];
372         } else {
373                 IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64,
374                            node->guid);
375                 return (-1);
376         }
377         return (0);
378 }
379
380 static int get_router_slot(ibnd_node_t * n, ibnd_port_t * spineport)
381 {
382         uint64_t guessnum = 0;
383
384         n->ch_found = 1;
385
386         n->ch_slot = SRBD_CS;
387         if (is_spine_9096(spineport->node)) {
388                 n->ch_type = ISR9096_CT;
389                 n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
390                 n->ch_anafanum = ipr_slot_2_sfb4_port[spineport->portnum];
391         } else if (is_spine_9288(spineport->node)) {
392                 n->ch_type = ISR9288_CT;
393                 n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
394                 /* this is a smart guess based on nodeguids order on sFB-12 module */
395                 guessnum = spineport->node->guid % 4;
396                 /* module 1 <--> remote anafa 3 */
397                 /* module 2 <--> remote anafa 2 */
398                 /* module 3 <--> remote anafa 1 */
399                 n->ch_anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2));
400         } else if (is_spine_2012(spineport->node)) {
401                 n->ch_type = ISR2012_CT;
402                 n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
403                 /* this is a smart guess based on nodeguids order on sFB-12 module */
404                 guessnum = spineport->node->guid % 4;
405                 // module 1 <--> remote anafa 3
406                 // module 2 <--> remote anafa 2
407                 // module 3 <--> remote anafa 1
408                 n->ch_anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2));
409         } else if (is_spine_2004(spineport->node)) {
410                 n->ch_type = ISR2004_CT;
411                 n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
412                 n->ch_anafanum = ipr_slot_2_sfb4_port[spineport->portnum];
413         } else {
414                 IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64,
415                            spineport->node->guid);
416                 return (-1);
417         }
418         return (0);
419 }
420
421 static int get_slb_slot(ibnd_node_t * n, ibnd_port_t * spineport)
422 {
423         n->ch_slot = LINE_CS;
424         if (is_spine_9096(spineport->node)) {
425                 n->ch_type = ISR9096_CT;
426                 n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
427                 n->ch_anafanum = anafa_line_slot_2_sfb4[spineport->portnum];
428         } else if (is_spine_9288(spineport->node)) {
429                 n->ch_type = ISR9288_CT;
430                 n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
431                 n->ch_anafanum = anafa_line_slot_2_sfb12[spineport->portnum];
432         } else if (is_spine_2012(spineport->node)) {
433                 n->ch_type = ISR2012_CT;
434                 n->ch_slotnum = line_slot_2_sfb12[spineport->portnum];
435                 n->ch_anafanum = anafa_line_slot_2_sfb12[spineport->portnum];
436         } else if (is_spine_2004(spineport->node)) {
437                 n->ch_type = ISR2004_CT;
438                 n->ch_slotnum = line_slot_2_sfb4[spineport->portnum];
439                 n->ch_anafanum = anafa_line_slot_2_sfb4[spineport->portnum];
440         } else {
441                 IBND_ERROR("Unexpected node found: guid 0x%016" PRIx64,
442                            spineport->node->guid);
443                 return (-1);
444         }
445         return (0);
446 }
447
448 /* forward declare this */
449 static void voltaire_portmap(ibnd_port_t * port);
450 /*
451         This function called for every Voltaire node in fabric
452         It could be optimized so, but time overhead is very small
453         and its only diag.util
454 */
455 static int fill_voltaire_chassis_record(ibnd_node_t * node)
456 {
457         int p = 0;
458         ibnd_port_t *port;
459         ibnd_node_t *remnode = 0;
460
461         if (node->ch_found)     /* somehow this node has already been passed */
462                 return (0);
463         node->ch_found = 1;
464
465         /* node is router only in case of using unique lid */
466         /* (which is lid of chassis router port) */
467         /* in such case node->ports is actually a requested port... */
468         if (is_router(node)) {
469                 /* find the remote node */
470                 for (p = 1; p <= node->numports; p++) {
471                         port = node->ports[p];
472                         if (port && is_spine(port->remoteport->node))
473                                 get_router_slot(node, port->remoteport);
474                 }
475         } else if (is_spine(node)) {
476                 for (p = 1; p <= node->numports; p++) {
477                         port = node->ports[p];
478                         if (!port || !port->remoteport)
479                                 continue;
480                         remnode = port->remoteport->node;
481                         if (remnode->type != IB_NODE_SWITCH) {
482                                 if (!remnode->ch_found)
483                                         get_router_slot(remnode, port);
484                                 continue;
485                         }
486                         if (!node->ch_type)
487                                 /* we assume here that remoteport belongs to line */
488                                 if (get_sfb_slot(node, port->remoteport))
489                                         return (-1);
490
491                         /* we could break here, but need to find if more routers connected */
492                 }
493
494         } else if (is_line(node)) {
495                 for (p = 1; p <= node->numports; p++) {
496                         port = node->ports[p];
497                         if (!port || port->portnum > 12 || !port->remoteport)
498                                 continue;
499                         /* we assume here that remoteport belongs to spine */
500                         if (get_slb_slot(node, port->remoteport))
501                                 return (-1);
502                         break;
503                 }
504         }
505
506         /* for each port of this node, map external ports */
507         for (p = 1; p <= node->numports; p++) {
508                 port = node->ports[p];
509                 if (!port)
510                         continue;
511                 voltaire_portmap(port);
512         }
513
514         return (0);
515 }
516
517 static int get_line_index(ibnd_node_t * node)
518 {
519         int retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum;
520
521         if (retval > LINES_MAX_NUM || retval < 1) {
522                 IBND_ERROR("Internal error\n");
523                 return (-1);
524         }
525         return retval;
526 }
527
528 static int get_spine_index(ibnd_node_t * node)
529 {
530         int retval;
531
532         if (is_spine_9288(node) || is_spine_2012(node))
533                 retval = 3 * (node->ch_slotnum - 1) + node->ch_anafanum;
534         else
535                 retval = node->ch_slotnum;
536
537         if (retval > SPINES_MAX_NUM || retval < 1) {
538                 IBND_ERROR("Internal error\n");
539                 return (-1);
540         }
541         return retval;
542 }
543
544 static int insert_line_router(ibnd_node_t * node, ibnd_chassis_t * chassis)
545 {
546         int i = get_line_index(node);
547
548         if (i < 0)
549                 return (i);
550
551         if (chassis->linenode[i])
552                 return (0);     /* already filled slot */
553
554         chassis->linenode[i] = node;
555         node->chassis = chassis;
556         return (0);
557 }
558
559 static int insert_spine(ibnd_node_t * node, ibnd_chassis_t * chassis)
560 {
561         int i = get_spine_index(node);
562
563         if (i < 0)
564                 return (i);
565
566         if (chassis->spinenode[i])
567                 return (0);     /* already filled slot */
568
569         chassis->spinenode[i] = node;
570         node->chassis = chassis;
571         return (0);
572 }
573
574 static int pass_on_lines_catch_spines(ibnd_chassis_t * chassis)
575 {
576         ibnd_node_t *node, *remnode;
577         ibnd_port_t *port;
578         int i, p;
579
580         for (i = 1; i <= LINES_MAX_NUM; i++) {
581                 node = chassis->linenode[i];
582
583                 if (!(node && is_line(node)))
584                         continue;       /* empty slot or router */
585
586                 for (p = 1; p <= node->numports; p++) {
587                         port = node->ports[p];
588                         if (!port || port->portnum > 12 || !port->remoteport)
589                                 continue;
590
591                         remnode = port->remoteport->node;
592
593                         if (!remnode->ch_found)
594                                 continue;       /* some error - spine not initialized ? FIXME */
595                         if (insert_spine(remnode, chassis))
596                                 return (-1);
597                 }
598         }
599         return (0);
600 }
601
602 static int pass_on_spines_catch_lines(ibnd_chassis_t * chassis)
603 {
604         ibnd_node_t *node, *remnode;
605         ibnd_port_t *port;
606         int i, p;
607
608         for (i = 1; i <= SPINES_MAX_NUM; i++) {
609                 node = chassis->spinenode[i];
610                 if (!node)
611                         continue;       /* empty slot */
612                 for (p = 1; p <= node->numports; p++) {
613                         port = node->ports[p];
614                         if (!port || !port->remoteport)
615                                 continue;
616                         remnode = port->remoteport->node;
617
618                         if (!remnode->ch_found)
619                                 continue;       /* some error - line/router not initialized ? FIXME */
620                         if (insert_line_router(remnode, chassis))
621                                 return (-1);
622                 }
623         }
624         return (0);
625 }
626
627 /*
628         Stupid interpolation algorithm...
629         But nothing to do - have to be compliant with VoltaireSM/NMS
630 */
631 static void pass_on_spines_interpolate_chguid(ibnd_chassis_t * chassis)
632 {
633         ibnd_node_t *node;
634         int i;
635
636         for (i = 1; i <= SPINES_MAX_NUM; i++) {
637                 node = chassis->spinenode[i];
638                 if (!node)
639                         continue;       /* skip the empty slots */
640
641                 /* take first guid minus one to be consistent with SM */
642                 chassis->chassisguid = node->guid - 1;
643                 break;
644         }
645 }
646
647 /*
648         This function fills chassis structure with all nodes
649         in that chassis
650         chassis structure = structure of one standalone chassis
651 */
652 static int build_chassis(ibnd_node_t * node, ibnd_chassis_t * chassis)
653 {
654         int p = 0;
655         ibnd_node_t *remnode = 0;
656         ibnd_port_t *port = 0;
657
658         /* we get here with node = chassis_spine */
659         if (insert_spine((ibnd_node_t *) node, chassis))
660                 return (-1);
661
662         /* loop: pass on all ports of node */
663         for (p = 1; p <= node->numports; p++) {
664                 port = node->ports[p];
665                 if (!port || !port->remoteport)
666                         continue;
667                 remnode = port->remoteport->node;
668
669                 if (!remnode->ch_found)
670                         continue;       /* some error - line or router not initialized ? FIXME */
671
672                 insert_line_router(remnode, chassis);
673         }
674
675         if (pass_on_lines_catch_spines(chassis))
676                 return (-1);
677         /* this pass needed for to catch routers, since routers connected only */
678         /* to spines in slot 1 or 4 and we could miss them first time */
679         if (pass_on_spines_catch_lines(chassis))
680                 return (-1);
681
682         /* additional 2 passes needed for to overcome a problem of pure "in-chassis" */
683         /* connectivity - extra pass to ensure that all related chips/modules */
684         /* inserted into the chassis */
685         if (pass_on_lines_catch_spines(chassis))
686                 return (-1);
687         if (pass_on_spines_catch_lines(chassis))
688                 return (-1);
689         pass_on_spines_interpolate_chguid(chassis);
690
691         return (0);
692 }
693
694 /*========================================================*/
695 /*                INTERNAL TO EXTERNAL PORT MAPPING       */
696 /*========================================================*/
697
698 /*
699 Description : On ISR9288/9096 external ports indexing
700               is not matching the internal ( anafa ) port
701               indexes. Use this MAP to translate the data you get from
702               the OpenIB diagnostics (smpquery, ibroute, ibtracert, etc.)
703
704 Module : sLB-24
705                 anafa 1             anafa 2
706 ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24
707 int port | 22 23 24 18 17 16 | 22 23 24 18 17 16
708 ext port | 1  2  3  4  5  6  | 7  8  9  10 11 12
709 int port | 19 20 21 15 14 13 | 19 20 21 15 14 13
710 ------------------------------------------------
711
712 Module : sLB-8
713                 anafa 1             anafa 2
714 ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24
715 int port | 24 23 22 18 17 16 | 24 23 22 18 17 16
716 ext port | 1  2  3  4  5  6  | 7  8  9  10 11 12
717 int port | 21 20 19 15 14 13 | 21 20 19 15 14 13
718
719 ----------->
720                 anafa 1             anafa 2
721 ext port | -  -  5  -  -  6  | -  -  7  -  -  8
722 int port | 24 23 22 18 17 16 | 24 23 22 18 17 16
723 ext port | -  -  1  -  -  2  | -  -  3  -  -  4
724 int port | 21 20 19 15 14 13 | 21 20 19 15 14 13
725 ------------------------------------------------
726
727 Module : sLB-2024
728
729 ext port | 13 14 15 16 17 18 19 20 21 22 23 24
730 A1 int port| 13 14 15 16 17 18 19 20 21 22 23 24
731 ext port | 1 2 3 4 5 6 7 8 9 10 11 12
732 A2 int port| 13 14 15 16 17 18 19 20 21 22 23 24
733 ---------------------------------------------------
734
735 */
736
737 int int2ext_map_slb24[2][25] = {
738         {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 5, 4, 18, 17, 16, 1, 2, 3,
739          13, 14, 15},
740         {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 11, 10, 24, 23, 22, 7, 8, 9,
741          19, 20, 21}
742 };
743 int int2ext_map_slb8[2][25] = {
744         {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 6, 6, 6, 1, 1, 1, 5, 5,
745          5},
746         {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 8, 8, 8, 3, 3, 3, 7, 7,
747          7}
748 };
749 int int2ext_map_slb2024[2][25] = {
750         {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20,
751          21, 22, 23, 24},
752         {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
753          11, 12}
754 };
755
756 /*      reference                       { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; */
757
758 /* map internal ports to external ports if appropriate */
759 static void voltaire_portmap(ibnd_port_t * port)
760 {
761         int portnum = port->portnum;
762         int chipnum = 0;
763         ibnd_node_t *node = port->node;
764
765         if (!node->ch_found || !is_line(node) || (portnum < 13 || portnum > 24)) {
766                 port->ext_portnum = 0;
767                 return;
768         }
769
770         if (port->node->ch_anafanum < 1 || port->node->ch_anafanum > 2) {
771                 port->ext_portnum = 0;
772                 return;
773         }
774
775         chipnum = port->node->ch_anafanum - 1;
776
777         if (is_line_24(node))
778                 port->ext_portnum = int2ext_map_slb24[chipnum][portnum];
779         else if (is_line_2024(node))
780                 port->ext_portnum = int2ext_map_slb2024[chipnum][portnum];
781         else
782                 port->ext_portnum = int2ext_map_slb8[chipnum][portnum];
783 }
784
785 static int add_chassis(ibnd_fabric_t * fabric)
786 {
787         if (!(fabric->current_chassis = calloc(1, sizeof(ibnd_chassis_t)))) {
788                 IBND_ERROR("OOM: failed to allocate chassis object\n");
789                 return (-1);
790         }
791
792         if (fabric->first_chassis == NULL) {
793                 fabric->first_chassis = fabric->current_chassis;
794                 fabric->last_chassis = fabric->current_chassis;
795         } else {
796                 fabric->last_chassis->next = fabric->current_chassis;
797                 fabric->last_chassis = fabric->current_chassis;
798         }
799         return (0);
800 }
801
802 static void add_node_to_chassis(ibnd_chassis_t * chassis, ibnd_node_t * node)
803 {
804         node->chassis = chassis;
805         node->next_chassis_node = chassis->nodes;
806         chassis->nodes = node;
807 }
808
809 /*
810         Main grouping function
811         Algorithm:
812         1. pass on every Voltaire node
813         2. catch spine chip for every Voltaire node
814                 2.1 build/interpolate chassis around this chip
815                 2.2 go to 1.
816         3. pass on non Voltaire nodes (SystemImageGUID based grouping)
817         4. now group non Voltaire nodes by SystemImageGUID
818         Returns:
819         0 on success, -1 on failure
820 */
821 int group_nodes(ibnd_fabric_t * fabric)
822 {
823         ibnd_node_t *node;
824         int dist;
825         int chassisnum = 0;
826         ibnd_chassis_t *chassis;
827
828         fabric->first_chassis = NULL;
829         fabric->current_chassis = NULL;
830
831         /* first pass on switches and build for every Voltaire node */
832         /* an appropriate chassis record (slotnum and position) */
833         /* according to internal connectivity */
834         /* not very efficient but clear code so... */
835         for (dist = 0; dist <= fabric->maxhops_discovered; dist++) {
836                 for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
837                         if (mad_get_field(node->info, 0,
838                                           IB_NODE_VENDORID_F) == VTR_VENDOR_ID)
839                                 if (fill_voltaire_chassis_record(node))
840                                         return (-1);
841                 }
842         }
843
844         /* separate every Voltaire chassis from each other and build linked list of them */
845         /* algorithm: catch spine and find all surrounding nodes */
846         for (dist = 0; dist <= fabric->maxhops_discovered; dist++) {
847                 for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
848                         if (mad_get_field(node->info, 0,
849                                           IB_NODE_VENDORID_F) != VTR_VENDOR_ID)
850                                 continue;
851                         if (!node->ch_found
852                             || (node->chassis && node->chassis->chassisnum)
853                             || !is_spine(node))
854                                 continue;
855                         if (add_chassis(fabric))
856                                 return (-1);
857                         fabric->current_chassis->chassisnum = ++chassisnum;
858                         if (build_chassis(node, fabric->current_chassis))
859                                 return (-1);
860                 }
861         }
862
863         /* now make pass on nodes for chassis which are not Voltaire */
864         /* grouped by common SystemImageGUID */
865         for (dist = 0; dist <= fabric->maxhops_discovered; dist++) {
866                 for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
867                         if (mad_get_field(node->info, 0,
868                                           IB_NODE_VENDORID_F) == VTR_VENDOR_ID)
869                                 continue;
870                         if (mad_get_field64(node->info, 0,
871                                             IB_NODE_SYSTEM_GUID_F)) {
872                                 chassis =
873                                     find_chassisguid(fabric,
874                                                      (ibnd_node_t *) node);
875                                 if (chassis)
876                                         chassis->nodecount++;
877                                 else {
878                                         /* Possible new chassis */
879                                         if (add_chassis(fabric))
880                                                 return (-1);
881                                         fabric->current_chassis->chassisguid =
882                                             get_chassisguid((ibnd_node_t *)
883                                                             node);
884                                         fabric->current_chassis->nodecount = 1;
885                                 }
886                         }
887                 }
888         }
889
890         /* now, make another pass to see which nodes are part of chassis */
891         /* (defined as chassis->nodecount > 1) */
892         for (dist = 0; dist <= MAXHOPS;) {
893                 for (node = fabric->nodesdist[dist]; node; node = node->dnext) {
894                         if (mad_get_field(node->info, 0,
895                                           IB_NODE_VENDORID_F) == VTR_VENDOR_ID)
896                                 continue;
897                         if (mad_get_field64(node->info, 0,
898                                             IB_NODE_SYSTEM_GUID_F)) {
899                                 chassis =
900                                     find_chassisguid(fabric,
901                                                      (ibnd_node_t *) node);
902                                 if (chassis && chassis->nodecount > 1) {
903                                         if (!chassis->chassisnum)
904                                                 chassis->chassisnum =
905                                                     ++chassisnum;
906                                         if (!node->ch_found) {
907                                                 node->ch_found = 1;
908                                                 add_node_to_chassis(chassis,
909                                                                     (ibnd_node_t
910                                                                      *) node);
911                                         }
912                                 }
913                         }
914                 }
915                 if (dist == fabric->maxhops_discovered)
916                         dist = MAXHOPS; /* skip to CAs */
917                 else
918                         dist++;
919         }
920
921         fabric->chassis = fabric->first_chassis;
922         return (0);
923 }