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