]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ofed/management/infiniband-diags/src/grouping.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ofed / management / infiniband-diags / src / grouping.c
1 /*
2  * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
3  * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
4  *
5  * This software is available to you under a choice of one of two
6  * licenses.  You may choose to be licensed under the terms of the GNU
7  * General Public License (GPL) Version 2, available from the file
8  * COPYING in the main directory of this source tree, or the
9  * OpenIB.org BSD license below:
10  *
11  *     Redistribution and use in source and binary forms, with or
12  *     without modification, are permitted provided that the following
13  *     conditions are met:
14  *
15  *      - Redistributions of source code must retain the above
16  *        copyright notice, this list of conditions and the following
17  *        disclaimer.
18  *
19  *      - Redistributions in binary form must reproduce the above
20  *        copyright notice, this list of conditions and the following
21  *        disclaimer in the documentation and/or other materials
22  *        provided with the distribution.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31  * SOFTWARE.
32  *
33  */
34
35 /*========================================================*/
36 /*               FABRIC SCANNER SPECIFIC DATA             */
37 /*========================================================*/
38
39 #if HAVE_CONFIG_H
40 #  include <config.h>
41 #endif /* HAVE_CONFIG_H */
42
43 #include <stdint.h>
44 #include <stdlib.h>
45 #include <inttypes.h>
46
47 #include <infiniband/common.h>
48 #include <infiniband/mad.h>
49
50 #include "ibnetdiscover.h"
51 #include "grouping.h"
52
53 #define OUT_BUFFER_SIZE 16
54
55
56 extern Node *nodesdist[MAXHOPS+1];      /* last is CA list */
57 extern Node *mynode;
58 extern Port *myport;
59 extern int maxhops_discovered;
60
61 AllChassisList mylist;
62
63 char *ChassisTypeStr[5] = { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004" };
64 char *ChassisSlotStr[4] = { "", "Line", "Spine", "SRBD" };
65
66
67 char *get_chassis_type(unsigned char chassistype)
68 {
69         if (chassistype == UNRESOLVED_CT || chassistype > ISR2004_CT)
70                 return NULL;
71         return ChassisTypeStr[chassistype];
72 }
73
74 char *get_chassis_slot(unsigned char chassisslot)
75 {
76         if (chassisslot == UNRESOLVED_CS || chassisslot > SRBD_CS)
77                 return NULL;
78         return ChassisSlotStr[chassisslot];
79 }
80
81 static struct ChassisList *find_chassisnum(unsigned char chassisnum)
82 {
83         ChassisList *current;
84
85         for (current = mylist.first; current; current = current->next) {
86                 if (current->chassisnum == chassisnum)
87                         return current;
88         }
89
90         return NULL;
91 }
92
93 static uint64_t topspin_chassisguid(uint64_t guid)
94 {
95         /* Byte 3 in system image GUID is chassis type, and */
96         /* Byte 4 is location ID (slot) so just mask off byte 4 */
97         return guid & 0xffffffff00ffffffULL;
98 }
99
100 int is_xsigo_guid(uint64_t guid)
101 {
102         if ((guid & 0xffffff0000000000ULL) == 0x0013970000000000ULL)
103                 return 1;
104         else
105                 return 0;
106 }
107
108 static int is_xsigo_leafone(uint64_t guid)
109 {
110         if ((guid & 0xffffffffff000000ULL) == 0x0013970102000000ULL)
111                 return 1;
112         else
113                 return 0;
114 }
115
116 int is_xsigo_hca(uint64_t guid)
117 {
118         /* NodeType 2 is HCA */
119         if ((guid & 0xffffffff00000000ULL) == 0x0013970200000000ULL)
120                 return 1;
121         else
122                 return 0;
123 }
124
125 int is_xsigo_tca(uint64_t guid)
126 {
127         /* NodeType 3 is TCA */
128         if ((guid & 0xffffffff00000000ULL) == 0x0013970300000000ULL)
129                 return 1;
130         else
131                 return 0;
132 }
133
134 static int is_xsigo_ca(uint64_t guid)
135 {
136         if (is_xsigo_hca(guid) || is_xsigo_tca(guid))
137                 return 1;
138         else
139                 return 0;
140 }
141
142 static int is_xsigo_switch(uint64_t guid)
143 {
144         if ((guid & 0xffffffff00000000ULL) == 0x0013970100000000ULL)
145                 return 1;
146         else
147                 return 0;
148 }
149
150 static uint64_t xsigo_chassisguid(Node *node)
151 {
152         if (!is_xsigo_ca(node->sysimgguid)) {
153                 /* Byte 3 is NodeType and byte 4 is PortType */
154                 /* If NodeType is 1 (switch), PortType is masked */
155                 if (is_xsigo_switch(node->sysimgguid))
156                         return node->sysimgguid & 0xffffffff00ffffffULL;
157                 else
158                         return node->sysimgguid;
159         } else {
160                 /* Is there a peer port ? */
161                 if (!node->ports->remoteport)
162                         return node->sysimgguid;
163
164                 /* If peer port is Leaf 1, use its chassis GUID */
165                 if (is_xsigo_leafone(node->ports->remoteport->node->sysimgguid))
166                         return node->ports->remoteport->node->sysimgguid &
167                                0xffffffff00ffffffULL;
168                 else
169                         return node->sysimgguid;
170         }
171 }
172
173 static uint64_t get_chassisguid(Node *node)
174 {
175         if (node->vendid == TS_VENDOR_ID || node->vendid == SS_VENDOR_ID)
176                 return topspin_chassisguid(node->sysimgguid);
177         else if (node->vendid == XS_VENDOR_ID || is_xsigo_guid(node->sysimgguid))
178                 return xsigo_chassisguid(node);
179         else
180                 return node->sysimgguid;
181 }
182
183 static struct ChassisList *find_chassisguid(Node *node)
184 {
185         ChassisList *current;
186         uint64_t chguid;
187
188         chguid = get_chassisguid(node);
189         for (current = mylist.first; current; current = current->next) {
190                 if (current->chassisguid == chguid)
191                         return current;
192         }
193
194         return NULL;
195 }
196
197 uint64_t get_chassis_guid(unsigned char chassisnum)
198 {
199         ChassisList *chassis;
200
201         chassis = find_chassisnum(chassisnum);
202         if (chassis)
203                 return chassis->chassisguid;
204         else
205                 return 0;
206 }
207
208 static int is_router(Node *node)
209 {
210         return (node->devid == VTR_DEVID_IB_FC_ROUTER ||
211                 node->devid == VTR_DEVID_IB_IP_ROUTER);
212 }
213
214 static int is_spine_9096(Node *node)
215 {
216         return (node->devid == VTR_DEVID_SFB4 ||
217                 node->devid == VTR_DEVID_SFB4_DDR);
218 }
219
220 static int is_spine_9288(Node *node)
221 {
222         return (node->devid == VTR_DEVID_SFB12 ||
223                 node->devid == VTR_DEVID_SFB12_DDR);
224 }
225
226 static int is_spine_2004(Node *node)
227 {
228         return (node->devid == VTR_DEVID_SFB2004);
229 }
230
231 static int is_spine_2012(Node *node)
232 {
233         return (node->devid == VTR_DEVID_SFB2012);
234 }
235
236 static int is_spine(Node *node)
237 {
238         return (is_spine_9096(node) || is_spine_9288(node) ||
239                 is_spine_2004(node) || is_spine_2012(node));
240 }
241
242 static int is_line_24(Node *node)
243 {
244         return (node->devid == VTR_DEVID_SLB24 ||
245                 node->devid == VTR_DEVID_SLB24_DDR ||
246                 node->devid == VTR_DEVID_SRB2004);
247 }
248
249 static int is_line_8(Node *node)
250 {
251         return (node->devid == VTR_DEVID_SLB8);
252 }
253
254 static int is_line_2024(Node *node)
255 {
256         return (node->devid == VTR_DEVID_SLB2024);
257 }
258
259 static int is_line(Node *node)
260 {
261         return (is_line_24(node) || is_line_8(node) || is_line_2024(node));
262 }
263
264 int is_chassis_switch(Node *node)
265 {
266     return (is_spine(node) || is_line(node));
267 }
268
269 /* these structs help find Line (Anafa) slot number while using spine portnum */
270 int line_slot_2_sfb4[25]        = { 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4 };
271 int anafa_line_slot_2_sfb4[25]  = { 0, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2 };
272 int line_slot_2_sfb12[25]       = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10, 10, 11, 11, 12, 12 };
273 int anafa_line_slot_2_sfb12[25] = { 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 };
274
275 /* IPR FCR modules connectivity while using sFB4 port as reference */
276 int ipr_slot_2_sfb4_port[25]    = { 0, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1 };
277
278 /* these structs help find Spine (Anafa) slot number while using spine portnum */
279 int spine12_slot_2_slb[25]      = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
280 int anafa_spine12_slot_2_slb[25]= { 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
281 int spine4_slot_2_slb[25]       = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
282 int anafa_spine4_slot_2_slb[25] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
283 /*      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 }; */
284
285 static void get_sfb_slot(Node *node, Port *lineport)
286 {
287         ChassisRecord *ch = node->chrecord;
288
289         ch->chassisslot = SPINE_CS;
290         if (is_spine_9096(node)) {
291                 ch->chassistype = ISR9096_CT;
292                 ch->slotnum = spine4_slot_2_slb[lineport->portnum];
293                 ch->anafanum = anafa_spine4_slot_2_slb[lineport->portnum];
294         } else if (is_spine_9288(node)) {
295                 ch->chassistype = ISR9288_CT;
296                 ch->slotnum = spine12_slot_2_slb[lineport->portnum];
297                 ch->anafanum = anafa_spine12_slot_2_slb[lineport->portnum];
298         } else if (is_spine_2012(node)) {
299                 ch->chassistype = ISR2012_CT;
300                 ch->slotnum = spine12_slot_2_slb[lineport->portnum];
301                 ch->anafanum = anafa_spine12_slot_2_slb[lineport->portnum];
302         } else if (is_spine_2004(node)) {
303                 ch->chassistype = ISR2004_CT;
304                 ch->slotnum = spine4_slot_2_slb[lineport->portnum];
305                 ch->anafanum = anafa_spine4_slot_2_slb[lineport->portnum];
306         } else {
307                 IBPANIC("Unexpected node found: guid 0x%016" PRIx64, node->nodeguid);
308         }
309 }
310
311 static void get_router_slot(Node *node, Port *spineport)
312 {
313         ChassisRecord *ch = node->chrecord;
314         int guessnum = 0;
315
316         if (!ch) {
317                 if (!(node->chrecord = calloc(1, sizeof(ChassisRecord))))
318                         IBPANIC("out of mem");
319                 ch = node->chrecord;
320         }
321
322         ch->chassisslot = SRBD_CS;
323         if (is_spine_9096(spineport->node)) {
324                 ch->chassistype = ISR9096_CT;
325                 ch->slotnum = line_slot_2_sfb4[spineport->portnum];
326                 ch->anafanum = ipr_slot_2_sfb4_port[spineport->portnum];
327         } else if (is_spine_9288(spineport->node)) {
328                 ch->chassistype = ISR9288_CT;
329                 ch->slotnum = line_slot_2_sfb12[spineport->portnum];
330                 /* this is a smart guess based on nodeguids order on sFB-12 module */
331                 guessnum = spineport->node->nodeguid % 4;
332                 /* module 1 <--> remote anafa 3 */
333                 /* module 2 <--> remote anafa 2 */
334                 /* module 3 <--> remote anafa 1 */
335                 ch->anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2));
336         } else if (is_spine_2012(spineport->node)) {
337                 ch->chassistype = ISR2012_CT;
338                 ch->slotnum = line_slot_2_sfb12[spineport->portnum];
339                 /* this is a smart guess based on nodeguids order on sFB-12 module */
340                 guessnum = spineport->node->nodeguid % 4;
341                 // module 1 <--> remote anafa 3
342                 // module 2 <--> remote anafa 2
343                 // module 3 <--> remote anafa 1
344                 ch->anafanum = (guessnum == 3? 1 : (guessnum == 1 ? 3 : 2));
345         } else if (is_spine_2004(spineport->node)) {
346                 ch->chassistype = ISR2004_CT;
347                 ch->slotnum = line_slot_2_sfb4[spineport->portnum];
348                 ch->anafanum = ipr_slot_2_sfb4_port[spineport->portnum];
349         } else {
350                 IBPANIC("Unexpected node found: guid 0x%016" PRIx64, spineport->node->nodeguid);
351         }
352 }
353
354 static void get_slb_slot(ChassisRecord *ch, Port *spineport)
355 {
356         ch->chassisslot = LINE_CS;
357         if (is_spine_9096(spineport->node)) {
358                 ch->chassistype = ISR9096_CT;
359                 ch->slotnum = line_slot_2_sfb4[spineport->portnum];
360                 ch->anafanum = anafa_line_slot_2_sfb4[spineport->portnum];
361         } else if (is_spine_9288(spineport->node)) {
362                 ch->chassistype = ISR9288_CT;
363                 ch->slotnum = line_slot_2_sfb12[spineport->portnum];
364                 ch->anafanum = anafa_line_slot_2_sfb12[spineport->portnum];
365         } else if (is_spine_2012(spineport->node)) {
366                 ch->chassistype = ISR2012_CT;
367                 ch->slotnum = line_slot_2_sfb12[spineport->portnum];
368                 ch->anafanum = anafa_line_slot_2_sfb12[spineport->portnum];
369         } else if (is_spine_2004(spineport->node)) {
370                 ch->chassistype = ISR2004_CT;
371                 ch->slotnum = line_slot_2_sfb4[spineport->portnum];
372                 ch->anafanum = anafa_line_slot_2_sfb4[spineport->portnum];
373         } else {
374                 IBPANIC("Unexpected node found: guid 0x%016" PRIx64, spineport->node->nodeguid);
375         }
376 }
377
378 /*
379         This function called for every Voltaire node in fabric
380         It could be optimized so, but time overhead is very small
381         and its only diag.util
382 */
383 static void fill_chassis_record(Node *node)
384 {
385         Port *port;
386         Node *remnode = 0;
387         ChassisRecord *ch = 0;
388
389         if (node->chrecord) /* somehow this node has already been passed */
390                 return;
391
392         if (!(node->chrecord = calloc(1, sizeof(ChassisRecord))))
393                 IBPANIC("out of mem");
394
395         ch = node->chrecord;
396
397         /* node is router only in case of using unique lid */
398         /* (which is lid of chassis router port) */
399         /* in such case node->ports is actually a requested port... */
400         if (is_router(node) && is_spine(node->ports->remoteport->node))
401                 get_router_slot(node, node->ports->remoteport);
402         else if (is_spine(node)) {
403                 for (port = node->ports; port; port = port->next) {
404                         if (!port->remoteport)
405                                 continue;
406                         remnode = port->remoteport->node;
407                         if (remnode->type != SWITCH_NODE) {
408                                 if (!remnode->chrecord)
409                                         get_router_slot(remnode, port);
410                                 continue;
411                         }
412                         if (!ch->chassistype)
413                                 /* we assume here that remoteport belongs to line */
414                                 get_sfb_slot(node, port->remoteport);
415
416                                 /* we could break here, but need to find if more routers connected */
417                 }
418
419         } else if (is_line(node)) {
420                 for (port = node->ports; port; port = port->next) {
421                         if (port->portnum > 12)
422                                 continue;
423                         if (!port->remoteport)
424                                 continue;
425                         /* we assume here that remoteport belongs to spine */
426                         get_slb_slot(ch, port->remoteport);
427                         break;
428                 }
429         }
430
431         return;
432 }
433
434 static int get_line_index(Node *node)
435 {
436         int retval = 3 * (node->chrecord->slotnum - 1) + node->chrecord->anafanum;
437
438         if (retval > LINES_MAX_NUM || retval < 1)
439                 IBPANIC("Internal error");
440         return retval;
441 }
442
443 static int get_spine_index(Node *node)
444 {
445         int retval;
446
447         if (is_spine_9288(node) || is_spine_2012(node))
448                 retval = 3 * (node->chrecord->slotnum - 1) + node->chrecord->anafanum;
449         else
450                 retval = node->chrecord->slotnum;
451
452         if (retval > SPINES_MAX_NUM || retval < 1)
453                 IBPANIC("Internal error");
454         return retval;
455 }
456
457 static void insert_line_router(Node *node, ChassisList *chassislist)
458 {
459         int i = get_line_index(node);
460
461         if (chassislist->linenode[i])
462                 return;         /* already filled slot */
463
464         chassislist->linenode[i] = node;
465         node->chrecord->chassisnum = chassislist->chassisnum;
466 }
467
468 static void insert_spine(Node *node, ChassisList *chassislist)
469 {
470         int i = get_spine_index(node);
471
472         if (chassislist->spinenode[i])
473                 return;         /* already filled slot */
474
475         chassislist->spinenode[i] = node;
476         node->chrecord->chassisnum = chassislist->chassisnum;
477 }
478
479 static void pass_on_lines_catch_spines(ChassisList *chassislist)
480 {
481         Node *node, *remnode;
482         Port *port;
483         int i;
484
485         for (i = 1; i <= LINES_MAX_NUM; i++) {
486                 node = chassislist->linenode[i];
487
488                 if (!(node && is_line(node)))
489                         continue;       /* empty slot or router */
490
491                 for (port = node->ports; port; port = port->next) {
492                         if (port->portnum > 12)
493                                 continue;
494
495                         if (!port->remoteport)
496                                 continue;
497                         remnode = port->remoteport->node;
498
499                         if (!remnode->chrecord)
500                                 continue;       /* some error - spine not initialized ? FIXME */
501                         insert_spine(remnode, chassislist);
502                 }
503         }
504 }
505
506 static void pass_on_spines_catch_lines(ChassisList *chassislist)
507 {
508         Node *node, *remnode;
509         Port *port;
510         int i;
511
512         for (i = 1; i <= SPINES_MAX_NUM; i++) {
513                 node = chassislist->spinenode[i];
514                 if (!node)
515                         continue;       /* empty slot */
516                 for (port = node->ports; port; port = port->next) {
517                         if (!port->remoteport)
518                                 continue;
519                         remnode = port->remoteport->node;
520
521                         if (!remnode->chrecord)
522                                 continue;       /* some error - line/router not initialized ? FIXME */
523                         insert_line_router(remnode, chassislist);
524                 }
525         }
526 }
527
528 /*
529         Stupid interpolation algorithm...
530         But nothing to do - have to be compliant with VoltaireSM/NMS
531 */
532 static void pass_on_spines_interpolate_chguid(ChassisList *chassislist)
533 {
534         Node *node;
535         int i;
536
537         for (i = 1; i <= SPINES_MAX_NUM; i++) {
538                 node = chassislist->spinenode[i];
539                 if (!node)
540                         continue;       /* skip the empty slots */
541
542                 /* take first guid minus one to be consistent with SM */
543                 chassislist->chassisguid = node->nodeguid - 1;
544                 break;
545         }
546 }
547
548 /*
549         This function fills chassislist structure with all nodes
550         in that chassis
551         chassislist structure = structure of one standalone chassis
552 */
553 static void build_chassis(Node *node, ChassisList *chassislist)
554 {
555         Node *remnode = 0;
556         Port *port = 0;
557
558         /* we get here with node = chassis_spine */
559         chassislist->chassistype = node->chrecord->chassistype;
560         insert_spine(node, chassislist);
561
562         /* loop: pass on all ports of node */
563         for (port = node->ports; port; port = port->next) {
564                 if (!port->remoteport)
565                         continue;
566                 remnode = port->remoteport->node;
567
568                 if (!remnode->chrecord)
569                         continue; /* some error - line or router not initialized ? FIXME */
570
571                 insert_line_router(remnode, chassislist);
572         }
573
574         pass_on_lines_catch_spines(chassislist);
575         /* this pass needed for to catch routers, since routers connected only */
576         /* to spines in slot 1 or 4 and we could miss them first time */
577         pass_on_spines_catch_lines(chassislist);
578
579         /* additional 2 passes needed for to overcome a problem of pure "in-chassis" */
580         /* connectivity - extra pass to ensure that all related chips/modules */
581         /* inserted into the chassislist */
582         pass_on_lines_catch_spines(chassislist);
583         pass_on_spines_catch_lines(chassislist);
584         pass_on_spines_interpolate_chguid(chassislist);
585 }
586
587 /*========================================================*/
588 /*                INTERNAL TO EXTERNAL PORT MAPPING       */
589 /*========================================================*/
590
591 /*
592 Description : On ISR9288/9096 external ports indexing
593               is not matching the internal ( anafa ) port
594               indexes. Use this MAP to translate the data you get from
595               the OpenIB diagnostics (smpquery, ibroute, ibtracert, etc.)
596
597
598 Module : sLB-24
599                 anafa 1             anafa 2
600 ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24
601 int port | 22 23 24 18 17 16 | 22 23 24 18 17 16
602 ext port | 1  2  3  4  5  6  | 7  8  9  10 11 12
603 int port | 19 20 21 15 14 13 | 19 20 21 15 14 13
604 ------------------------------------------------
605
606 Module : sLB-8
607                 anafa 1             anafa 2
608 ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24
609 int port | 24 23 22 18 17 16 | 24 23 22 18 17 16
610 ext port | 1  2  3  4  5  6  | 7  8  9  10 11 12
611 int port | 21 20 19 15 14 13 | 21 20 19 15 14 13
612
613 ----------->
614                 anafa 1             anafa 2
615 ext port | -  -  5  -  -  6  | -  -  7  -  -  8
616 int port | 24 23 22 18 17 16 | 24 23 22 18 17 16
617 ext port | -  -  1  -  -  2  | -  -  3  -  -  4
618 int port | 21 20 19 15 14 13 | 21 20 19 15 14 13
619 ------------------------------------------------
620
621 Module : sLB-2024
622
623 ext port | 13 14 15 16 17 18 19 20 21 22 23 24
624 A1 int port| 13 14 15 16 17 18 19 20 21 22 23 24
625 ext port | 1 2 3 4 5 6 7 8 9 10 11 12
626 A2 int port| 13 14 15 16 17 18 19 20 21 22 23 24
627 ---------------------------------------------------
628
629 */
630
631 int int2ext_map_slb24[2][25] = {
632                                         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 5, 4, 18, 17, 16, 1, 2, 3, 13, 14, 15 },
633                                         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 11, 10, 24, 23, 22, 7, 8, 9, 19, 20, 21 }
634                                 };
635 int int2ext_map_slb8[2][25] = {
636                                         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 6, 6, 6, 1, 1, 1, 5, 5, 5 },
637                                         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 8, 8, 8, 3, 3, 3, 7, 7, 7 }
638                                 };
639 int int2ext_map_slb2024[2][25] = {
640                                         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 },
641                                         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }
642                                 };
643 /*      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 }; */
644
645 /*
646         This function relevant only for line modules/chips
647         Returns string with external port index
648 */
649 char *portmapstring(Port *port)
650 {
651         static char mapping[OUT_BUFFER_SIZE];
652         ChassisRecord *ch = port->node->chrecord;
653         int portnum = port->portnum;
654         int chipnum = 0;
655         int pindex = 0;
656         Node *node = port->node;
657
658         if (!ch || !is_line(node) || (portnum < 13 || portnum > 24))
659                 return NULL;
660
661         if (ch->anafanum < 1 || ch->anafanum > 2)
662                 return NULL;
663
664         memset(mapping, 0, sizeof(mapping));
665
666         chipnum = ch->anafanum - 1;
667
668         if (is_line_24(node))
669                 pindex = int2ext_map_slb24[chipnum][portnum];
670         else if (is_line_2024(node))
671                 pindex = int2ext_map_slb2024[chipnum][portnum];
672         else
673                 pindex = int2ext_map_slb8[chipnum][portnum];
674
675         sprintf(mapping, "[ext %d]", pindex);
676
677         return mapping;
678 }
679
680 static void add_chassislist()
681 {
682         if (!(mylist.current = calloc(1, sizeof(ChassisList))))
683                 IBPANIC("out of mem");
684
685         if (mylist.first == NULL) {
686                 mylist.first = mylist.current;
687                 mylist.last = mylist.current;
688         } else {
689                 mylist.last->next = mylist.current;
690                 mylist.current->next = NULL;
691                 mylist.last = mylist.current;
692         }
693 }
694
695 /*
696         Main grouping function
697         Algorithm:
698         1. pass on every Voltaire node
699         2. catch spine chip for every Voltaire node
700                 2.1 build/interpolate chassis around this chip
701                 2.2 go to 1.
702         3. pass on non Voltaire nodes (SystemImageGUID based grouping)
703         4. now group non Voltaire nodes by SystemImageGUID
704 */
705 ChassisList *group_nodes()
706 {
707         Node *node;
708         int dist;
709         int chassisnum = 0;
710         struct ChassisList *chassis;
711
712         mylist.first = NULL;
713         mylist.current = NULL;
714         mylist.last = NULL;
715
716         /* first pass on switches and build for every Voltaire node */
717         /* an appropriate chassis record (slotnum and position) */
718         /* according to internal connectivity */
719         /* not very efficient but clear code so... */
720         for (dist = 0; dist <= maxhops_discovered; dist++) {
721                 for (node = nodesdist[dist]; node; node = node->dnext) {
722                         if (node->vendid == VTR_VENDOR_ID)
723                                 fill_chassis_record(node);
724                 }
725         }
726
727         /* separate every Voltaire chassis from each other and build linked list of them */
728         /* algorithm: catch spine and find all surrounding nodes */
729         for (dist = 0; dist <= maxhops_discovered; dist++) {
730                 for (node = nodesdist[dist]; node; node = node->dnext) {
731                         if (node->vendid != VTR_VENDOR_ID)
732                                 continue;
733                         if (!node->chrecord || node->chrecord->chassisnum || !is_spine(node))
734                                 continue;
735                         add_chassislist();
736                         mylist.current->chassisnum = ++chassisnum;
737                         build_chassis(node, mylist.current);
738                 }
739         }
740
741         /* now make pass on nodes for chassis which are not Voltaire */
742         /* grouped by common SystemImageGUID */
743         for (dist = 0; dist <= maxhops_discovered; dist++) {
744                 for (node = nodesdist[dist]; node; node = node->dnext) {
745                         if (node->vendid == VTR_VENDOR_ID)
746                                 continue;
747                         if (node->sysimgguid) {
748                                 chassis = find_chassisguid(node);
749                                 if (chassis)
750                                         chassis->nodecount++;
751                                 else {
752                                         /* Possible new chassis */
753                                         add_chassislist();
754                                         mylist.current->chassisguid = get_chassisguid(node);
755                                         mylist.current->nodecount = 1;
756                                 }
757                         }
758                 }
759         }
760
761         /* now, make another pass to see which nodes are part of chassis */
762         /* (defined as chassis->nodecount > 1) */
763         for (dist = 0; dist <= MAXHOPS; ) {
764                 for (node = nodesdist[dist]; node; node = node->dnext) {
765                         if (node->vendid == VTR_VENDOR_ID)
766                                 continue;
767                         if (node->sysimgguid) {
768                                 chassis = find_chassisguid(node);
769                                 if (chassis && chassis->nodecount > 1) {
770                                         if (!chassis->chassisnum)
771                                                 chassis->chassisnum = ++chassisnum;
772                                         if (!node->chrecord) {
773                                                 if (!(node->chrecord = calloc(1, sizeof(ChassisRecord))))
774                                                         IBPANIC("out of mem");
775                                                 node->chrecord->chassisnum = chassis->chassisnum;
776                                         }
777                                 }
778                         }
779                 }
780                 if (dist == maxhops_discovered)
781                         dist = MAXHOPS; /* skip to CAs */
782                 else
783                         dist++;
784         }
785
786         return (mylist.first);
787 }