]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/opensm/opensm/osm_torus.c
MFV r353623: 10473 zfs(1M) missing cross-reference to zfs-program(1M)
[FreeBSD/FreeBSD.git] / contrib / ofed / opensm / opensm / osm_torus.c
1 /*
2  * Copyright 2009 Sandia Corporation.  Under the terms of Contract
3  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
4  * certain rights in this software.
5  * Copyright (c) 2009-2011 ZIH, TU Dresden, Federal Republic of Germany. All rights reserved.
6  * Copyright (c) 2010-2012 Mellanox Technologies LTD. All rights reserved.
7  *
8  * This software is available to you under a choice of one of two
9  * licenses.  You may choose to be licensed under the terms of the GNU
10  * General Public License (GPL) Version 2, available from the file
11  * COPYING in the main directory of this source tree, or the
12  * OpenIB.org BSD license below:
13  *
14  *     Redistribution and use in source and binary forms, with or
15  *     without modification, are permitted provided that the following
16  *     conditions are met:
17  *
18  *      - Redistributions of source code must retain the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer.
21  *
22  *      - Redistributions in binary form must reproduce the above
23  *        copyright notice, this list of conditions and the following
24  *        disclaimer in the documentation and/or other materials
25  *        provided with the distribution.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
31  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34  * SOFTWARE.
35  *
36  */
37
38 #define _WITH_GETLINE   /* for getline() */
39 #include <stdint.h>
40 #include <stdbool.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <unistd.h>
44 #include <errno.h>
45 #include <string.h>
46
47 #if HAVE_CONFIG_H
48 #  include <config.h>
49 #endif                          /* HAVE_CONFIG_H */
50
51 #include <opensm/osm_file_ids.h>
52 #define FILE_ID OSM_FILE_TORUS_C
53 #include <opensm/osm_log.h>
54 #include <opensm/osm_port.h>
55 #include <opensm/osm_switch.h>
56 #include <opensm/osm_node.h>
57 #include <opensm/osm_opensm.h>
58
59 #define TORUS_MAX_DIM        3
60 #define PORTGRP_MAX_PORTS    16
61 #define SWITCH_MAX_PORTGRPS  (1 + 2 * TORUS_MAX_DIM)
62 #define DEFAULT_MAX_CHANGES  32
63
64 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
65
66 typedef ib_net64_t guid_t;
67
68 /*
69  * An endpoint terminates a link, and is one of three types:
70  *   UNKNOWN  - Uninitialized endpoint.
71  *   SRCSINK  - generates or consumes traffic, and thus has an associated LID;
72  *                i.e. a CA or router port.
73  *   PASSTHRU - Has no associated LID; i.e. a switch port.
74  *
75  * If it is possible to communicate in-band with a switch, it will require
76  * a port with a GUID in the switch to source/sink that traffic, but there
77  * will be no attached link.  This code assumes there is only one such port.
78  *
79  * Here is an endpoint taxonomy:
80  *
81  *   type == SRCSINK
82  *   link == pointer to a valid struct link
83  *     ==> This endpoint is a CA or router port connected via a link to
84  *           either a switch or another CA/router.  Thus:
85  *         n_id ==> identifies the CA/router node GUID
86  *         sw   ==> NULL
87  *         port ==> identifies the port on the CA/router this endpoint uses
88  *         pgrp ==> NULL
89  *
90  *   type == SRCSINK
91  *   link == NULL pointer
92  *     ==> This endpoint is the switch port used for in-band communication
93  *           with the switch itself.  Thus:
94  *         n_id ==> identifies the node GUID used to talk to the switch
95  *                    containing this endpoint
96  *         sw   ==> pointer to valid struct switch containing this endpoint
97  *         port ==> identifies the port on the switch this endpoint uses
98  *         pgrp ==> NULL, or pointer to the valid struct port_grp holding
99  *                    the port in a t_switch.
100  *
101  *   type == PASSTHRU
102  *   link == pointer to valid struct link
103  *     ==> This endpoint is a switch port connected via a link to either
104  *           another switch or a CA/router.  Thus:
105  *         n_id ==> identifies the node GUID used to talk to the switch
106  *                    containing this endpoint - since each switch is assumed
107  *                    to have only one in-band communication port, this is a
108  *                    convenient unique name for the switch itself.
109  *         sw   ==> pointer to valid struct switch containing this endpoint,
110  *                    or NULL, in the case of a fabric link that has been
111  *                    disconnected after being transferred to a torus link.
112  *         port ==> identifies the port on the switch this endpoint uses.
113  *                    Note that in the special case of the coordinate direction
114  *                    links, the port value is -1, as those links aren't
115  *                    really connected to anything.
116  *         pgrp ==> NULL, or pointer to the valid struct port_grp holding
117  *                    the port in a t_switch.
118  */
119 enum endpt_type { UNKNOWN = 0, SRCSINK, PASSTHRU };
120 struct torus;
121 struct t_switch;
122 struct port_grp;
123
124 struct endpoint {
125         enum endpt_type type;
126         int port;
127         guid_t n_id;            /* IBA node GUID */
128         void *sw;               /* void* can point to either switch type */
129         struct link *link;
130         struct port_grp *pgrp;
131         void *tmp;
132         /*
133          * Note: osm_port is only guaranteed to contain a valid pointer
134          * when the call stack contains torus_build_lfts() or
135          * osm_port_relink_endpoint().
136          *
137          * Otherwise, the opensm core could have deleted an osm_port object
138          * without notifying us, invalidating the pointer we hold.
139          *
140          * When presented with a pointer to an osm_port_t, it is generally
141          * safe and required to cast osm_port_t:priv to struct endpoint, and
142          * check that the endpoint's osm_port is the same as the original
143          * osm_port_t pointer.  Failure to do so means that invalidated
144          * pointers will go undetected.
145          */
146         struct osm_port *osm_port;
147 };
148
149 struct link {
150         struct endpoint end[2];
151 };
152
153 /*
154  * A port group is a collection of endpoints on a switch that share certain
155  * characteristics.  All the endpoints in a port group must have the same
156  * type.  Furthermore, if that type is PASSTHRU, then the connected links:
157  *   1) are parallel to a given coordinate direction
158  *   2) share the same two switches as endpoints.
159  *
160  * Torus-2QoS uses one master spanning tree for multicast, of which every
161  * multicast group spanning tree is a subtree.  to_stree_root is a pointer
162  * to the next port_grp on the path to the master spanning tree root.
163  * to_stree_tip is a pointer to the next port_grp on the path to a master
164  * spanning tree branch tip.
165  *
166  * Each t_switch can have at most one port_grp with a non-NULL to_stree_root.
167  * Exactly one t_switch in the fabric will have all port_grp objects with
168  * to_stree_root NULL; it is the master spanning tree root.
169  *
170  * A t_switch with all port_grp objects where to_stree_tip is NULL is at a
171  * master spanning tree branch tip.
172  */
173 struct port_grp {
174         enum endpt_type type;
175         size_t port_cnt;        /* number of attached ports in group */
176         size_t port_grp;        /* what switch port_grp we're in */
177         unsigned sw_dlid_cnt;   /* switch dlids routed through this group */
178         unsigned ca_dlid_cnt;   /* CA dlids routed through this group */
179         struct t_switch *sw;    /* what switch we're attached to */
180         struct port_grp *to_stree_root;
181         struct port_grp *to_stree_tip;
182         struct endpoint **port;
183 };
184
185 /*
186  * A struct t_switch is used to represent a switch as placed in a torus.
187  *
188  * A t_switch used to build an N-dimensional torus will have 2N+1 port groups,
189  * used as follows, assuming 0 <= d < N:
190  *   port_grp[2d]   => links leaving in negative direction for coordinate d
191  *   port_grp[2d+1] => links leaving in positive direction for coordinate d
192  *   port_grp[2N]   => endpoints local to switch; i.e., hosts on switch
193  *
194  * struct link objects referenced by a t_switch are assumed to be oriented:
195  * traversing a link from link.end[0] to link.end[1] is always in the positive
196  * coordinate direction.
197  */
198 struct t_switch {
199         guid_t n_id;            /* IBA node GUID */
200         int i, j, k;
201         unsigned port_cnt;      /* including management port */
202         struct torus *torus;
203         void *tmp;
204         /*
205          * Note: osm_switch is only guaranteed to contain a valid pointer
206          * when the call stack contains torus_build_lfts().
207          *
208          * Otherwise, the opensm core could have deleted an osm_switch object
209          * without notifying us, invalidating the pointer we hold.
210          *
211          * When presented with a pointer to an osm_switch_t, it is generally
212          * safe and required to cast osm_switch_t:priv to struct t_switch, and
213          * check that the switch's osm_switch is the same as the original
214          * osm_switch_t pointer.  Failure to do so means that invalidated
215          * pointers will go undetected.
216          */
217         struct osm_switch *osm_switch;
218
219         struct port_grp ptgrp[SWITCH_MAX_PORTGRPS];
220         struct endpoint **port;
221 };
222
223 /*
224  * We'd like to be able to discover the torus topology in a pile of switch
225  * links if we can.  We'll use a struct f_switch to store raw topology for a
226  * fabric description, then contruct the torus topology from struct t_switch
227  * objects as we process the fabric and recover it.
228  */
229 struct f_switch {
230         guid_t n_id;            /* IBA node GUID */
231         unsigned port_cnt;      /* including management port */
232         void *tmp;
233         /*
234          * Same rules apply here as for a struct t_switch member osm_switch.
235          */
236         struct osm_switch *osm_switch;
237         struct endpoint **port;
238 };
239
240 struct fabric {
241         osm_opensm_t *osm;
242         unsigned ca_cnt;
243         unsigned link_cnt;
244         unsigned switch_cnt;
245
246         unsigned link_cnt_max;
247         unsigned switch_cnt_max;
248
249         struct link **link;
250         struct f_switch **sw;
251 };
252
253 struct coord_dirs {
254         /*
255          * These links define the coordinate directions for the torus.
256          * They are duplicates of links connected to switches.  Each of
257          * these links must connect to a common switch.
258          *
259          * In the event that a failed switch was specified as one of these
260          * link endpoints, our algorithm would not be able to find the
261          * torus in the fabric.  So, we'll allow multiple instances of
262          * this in the config file to allow improved resiliency.
263          */
264         struct link xm_link, ym_link, zm_link;
265         struct link xp_link, yp_link, zp_link;
266         /*
267          * A torus dimension has coordinate values 0, 1, ..., radix - 1.
268          * The dateline, where we need to change VLs to avoid credit loops,
269          * for a torus dimension is always between coordinate values
270          * radix - 1 and 0.  The following specify the dateline location
271          * relative to the coordinate links shared switch location.
272          *
273          * E.g. if the shared switch is at 0,0,0, the following are all
274          * zero; if the shared switch is at 1,1,1, the following are all
275          * -1, etc.
276          *
277          * Since our SL/VL assignment for a path depends on the position
278          * of the path endpoints relative to the torus datelines, we need
279          * this information to keep SL/VL assignment constant in the event
280          * one of the switches used to specify coordinate directions fails.
281          */
282         int x_dateline, y_dateline, z_dateline;
283 };
284
285 struct torus {
286         osm_opensm_t *osm;
287         unsigned ca_cnt;
288         unsigned link_cnt;
289         unsigned switch_cnt;
290         unsigned seed_cnt, seed_idx;
291         unsigned x_sz, y_sz, z_sz;
292
293         unsigned port_order[IB_NODE_NUM_PORTS_MAX+1];
294
295         unsigned sw_pool_sz;
296         unsigned link_pool_sz;
297         unsigned seed_sz;
298         unsigned portgrp_sz;    /* max ports for port groups in this torus */
299
300         struct fabric *fabric;
301         struct t_switch **sw_pool;
302         struct link *link_pool;
303
304         struct coord_dirs *seed;
305         struct t_switch ****sw;
306         struct t_switch *master_stree_root;
307
308         unsigned flags;
309         unsigned max_changes;
310         int debug;
311 };
312
313 /*
314  * Bits to use in torus.flags
315  */
316 #define X_MESH (1U << 0)
317 #define Y_MESH (1U << 1)
318 #define Z_MESH (1U << 2)
319 #define MSG_DEADLOCK (1U << 29)
320 #define NOTIFY_CHANGES (1U << 30)
321
322 #define ALL_MESH(flags) \
323         ((flags & (X_MESH | Y_MESH | Z_MESH)) == (X_MESH | Y_MESH | Z_MESH))
324
325
326 struct torus_context {
327         osm_opensm_t *osm;
328         struct torus *torus;
329         struct fabric fabric;
330 };
331
332 static
333 void teardown_fabric(struct fabric *f)
334 {
335         unsigned l, p, s;
336         struct endpoint *port;
337         struct f_switch *sw;
338
339         if (!f)
340                 return;
341
342         if (f->sw) {
343                 /*
344                  * Need to free switches, and also find/free the endpoints
345                  * we allocated for switch management ports.
346                  */
347                 for (s = 0; s < f->switch_cnt; s++) {
348                         sw = f->sw[s];
349                         if (!sw)
350                                 continue;
351
352                         for (p = 0; p < sw->port_cnt; p++) {
353                                 port = sw->port[p];
354                                 if (port && !port->link)
355                                         free(port);     /* management port */
356                         }
357                         free(sw);
358                 }
359                 free(f->sw);
360         }
361         if (f->link) {
362                 for (l = 0; l < f->link_cnt; l++)
363                         if (f->link[l])
364                                 free(f->link[l]);
365
366                 free(f->link);
367         }
368         memset(f, 0, sizeof(*f));
369 }
370
371 void teardown_torus(struct torus *t)
372 {
373         unsigned p, s;
374         struct endpoint *port;
375         struct t_switch *sw;
376
377         if (!t)
378                 return;
379
380         if (t->sw_pool) {
381                 /*
382                  * Need to free switches, and also find/free the endpoints
383                  * we allocated for switch management ports.
384                  */
385                 for (s = 0; s < t->switch_cnt; s++) {
386                         sw = t->sw_pool[s];
387                         if (!sw)
388                                 continue;
389
390                         for (p = 0; p < sw->port_cnt; p++) {
391                                 port = sw->port[p];
392                                 if (port && !port->link)
393                                         free(port);     /* management port */
394                         }
395                         free(sw);
396                 }
397                 free(t->sw_pool);
398         }
399         if (t->link_pool)
400                 free(t->link_pool);
401
402         if (t->sw)
403                 free(t->sw);
404
405         if (t->seed)
406                 free(t->seed);
407
408         free(t);
409 }
410
411 static
412 struct torus_context *torus_context_create(osm_opensm_t *osm)
413 {
414         struct torus_context *ctx;
415
416         ctx = calloc(1, sizeof(*ctx));
417         if (ctx)
418                 ctx->osm = osm;
419         else
420                 OSM_LOG(&osm->log, OSM_LOG_ERROR,
421                         "ERR 4E01: calloc: %s\n", strerror(errno));
422
423         return ctx;
424 }
425
426 static
427 void torus_context_delete(void *context)
428 {
429         struct torus_context *ctx = context;
430
431         teardown_fabric(&ctx->fabric);
432         if (ctx->torus)
433                 teardown_torus(ctx->torus);
434         free(ctx);
435 }
436
437 static
438 bool grow_seed_array(struct torus *t, int new_seeds)
439 {
440         unsigned cnt;
441         void *ptr;
442
443         cnt = t->seed_cnt + new_seeds;
444         if (cnt > t->seed_sz) {
445                 cnt += 2 + cnt / 2;
446                 ptr = realloc(t->seed, cnt * sizeof(*t->seed));
447                 if (!ptr)
448                         return false;
449                 t->seed = ptr;
450                 t->seed_sz = cnt;
451                 memset(&t->seed[t->seed_cnt], 0,
452                        (cnt - t->seed_cnt) * sizeof(*t->seed));
453         }
454         return true;
455 }
456
457 static
458 struct f_switch *find_f_sw(struct fabric *f, guid_t sw_guid)
459 {
460         unsigned s;
461         struct f_switch *sw;
462
463         if (f->sw) {
464                 for (s = 0; s < f->switch_cnt; s++) {
465                         sw = f->sw[s];
466                         if (sw->n_id == sw_guid)
467                                 return sw;
468                 }
469         }
470         return NULL;
471 }
472
473 static
474 struct link *find_f_link(struct fabric *f,
475                          guid_t guid0, int port0, guid_t guid1, int port1)
476 {
477         unsigned l;
478         struct link *link;
479
480         if (f->link) {
481                 for (l = 0; l < f->link_cnt; l++) {
482                         link = f->link[l];
483                         if ((link->end[0].n_id == guid0 &&
484                              link->end[0].port == port0 &&
485                              link->end[1].n_id == guid1 &&
486                              link->end[1].port == port1) ||
487                             (link->end[0].n_id == guid1 &&
488                              link->end[0].port == port1 &&
489                              link->end[1].n_id == guid0 &&
490                              link->end[1].port == port0))
491                                 return link;
492                 }
493         }
494         return NULL;
495 }
496
497 static
498 struct f_switch *alloc_fswitch(struct fabric *f,
499                                guid_t sw_id, unsigned port_cnt)
500 {
501         size_t new_sw_sz;
502         unsigned cnt_max;
503         struct f_switch *sw = NULL;
504         void *ptr;
505
506         if (f->switch_cnt >= f->switch_cnt_max) {
507
508                 cnt_max = 16 + 5 * f->switch_cnt_max / 4;
509                 ptr = realloc(f->sw, cnt_max * sizeof(*f->sw));
510                 if (!ptr) {
511                         OSM_LOG(&f->osm->log, OSM_LOG_ERROR,
512                                 "ERR 4E02: realloc: %s\n", strerror(errno));
513                         goto out;
514                 }
515                 f->sw = ptr;
516                 f->switch_cnt_max = cnt_max;
517                 memset(&f->sw[f->switch_cnt], 0,
518                        (f->switch_cnt_max - f->switch_cnt)*sizeof(*f->sw));
519         }
520         new_sw_sz = sizeof(*sw) + port_cnt * sizeof(*sw->port);
521         sw = calloc(1, new_sw_sz);
522         if (!sw) {
523                 OSM_LOG(&f->osm->log, OSM_LOG_ERROR,
524                         "ERR 4E03: calloc: %s\n", strerror(errno));
525                 goto out;
526         }
527         sw->port = (void *)(sw + 1);
528         sw->n_id = sw_id;
529         sw->port_cnt = port_cnt;
530         f->sw[f->switch_cnt++] = sw;
531 out:
532         return sw;
533 }
534
535 static
536 struct link *alloc_flink(struct fabric *f)
537 {
538         unsigned cnt_max;
539         struct link *l = NULL;
540         void *ptr;
541
542         if (f->link_cnt >= f->link_cnt_max) {
543
544                 cnt_max = 16 + 5 * f->link_cnt_max / 4;
545                 ptr = realloc(f->link, cnt_max * sizeof(*f->link));
546                 if (!ptr) {
547                         OSM_LOG(&f->osm->log, OSM_LOG_ERROR,
548                                 "ERR 4E04: realloc: %s\n", strerror(errno));
549                         goto out;
550                 }
551                 f->link = ptr;
552                 f->link_cnt_max = cnt_max;
553                 memset(&f->link[f->link_cnt], 0,
554                        (f->link_cnt_max - f->link_cnt) * sizeof(*f->link));
555         }
556         l = calloc(1, sizeof(*l));
557         if (!l) {
558                 OSM_LOG(&f->osm->log, OSM_LOG_ERROR,
559                         "ERR 4E05: calloc: %s\n", strerror(errno));
560                 goto out;
561         }
562         f->link[f->link_cnt++] = l;
563 out:
564         return l;
565 }
566
567 /*
568  * Caller must ensure osm_port points to a valid port which contains
569  * a valid osm_physp_t pointer for port 0, the switch management port.
570  */
571 static
572 bool build_sw_endpoint(struct fabric *f, osm_port_t *osm_port)
573 {
574         int sw_port;
575         guid_t sw_guid;
576         struct osm_switch *osm_sw;
577         struct f_switch *sw;
578         struct endpoint *ep;
579         bool success = false;
580
581         sw_port = osm_physp_get_port_num(osm_port->p_physp);
582         sw_guid = osm_node_get_node_guid(osm_port->p_node);
583         osm_sw = osm_port->p_node->sw;
584
585         /*
586          * The switch must already exist.
587          */
588         sw = find_f_sw(f, sw_guid);
589         if (!sw) {
590                 OSM_LOG(&f->osm->log, OSM_LOG_ERROR,
591                         "ERR 4E06: missing switch w/GUID 0x%04"PRIx64"\n",
592                         cl_ntoh64(sw_guid));
593                 goto out;
594         }
595         /*
596          * The endpoint may already exist.
597          */
598         if (sw->port[sw_port]) {
599                 if (sw->port[sw_port]->n_id == sw_guid) {
600                         ep = sw->port[sw_port];
601                         goto success;
602                 } else
603                         OSM_LOG(&f->osm->log, OSM_LOG_ERROR,
604                                 "ERR 4E07: switch port %d has id "
605                                 "0x%04"PRIx64", expected 0x%04"PRIx64"\n",
606                                 sw_port, cl_ntoh64(sw->port[sw_port]->n_id),
607                                 cl_ntoh64(sw_guid));
608                 goto out;
609         }
610         ep = calloc(1, sizeof(*ep));
611         if (!ep) {
612                 OSM_LOG(&f->osm->log, OSM_LOG_ERROR,
613                         "ERR 4E08: allocating endpoint: %s\n", strerror(errno));
614                 goto out;
615         }
616         ep->type = SRCSINK;
617         ep->port = sw_port;
618         ep->n_id = sw_guid;
619         ep->link = NULL;
620         ep->sw = sw;
621
622         sw->port[sw_port] = ep;
623
624 success:
625         /*
626          * Fabric objects are temporary, so don't set osm_sw/osm_port priv
627          * pointers using them.  Wait until torus objects get constructed.
628          */
629         sw->osm_switch = osm_sw;
630         ep->osm_port = osm_port;
631
632         success = true;
633 out:
634         return success;
635 }
636
637 static
638 bool build_ca_link(struct fabric *f,
639                    osm_port_t *osm_port_ca, guid_t sw_guid, int sw_port)
640 {
641         int ca_port;
642         guid_t ca_guid;
643         struct link *l;
644         struct f_switch *sw;
645         bool success = false;
646
647         ca_port = osm_physp_get_port_num(osm_port_ca->p_physp);
648         ca_guid = osm_node_get_node_guid(osm_port_ca->p_node);
649
650         /*
651          * The link may already exist.
652          */
653         l = find_f_link(f, sw_guid, sw_port, ca_guid, ca_port);
654         if (l) {
655                 success = true;
656                 goto out;
657         }
658         /*
659          * The switch must already exist.
660          */
661         sw = find_f_sw(f, sw_guid);
662         if (!sw) {
663                 OSM_LOG(&f->osm->log, OSM_LOG_ERROR,
664                         "ERR 4E09: missing switch w/GUID 0x%04"PRIx64"\n",
665                         cl_ntoh64(sw_guid));
666                 goto out;
667         }
668         l = alloc_flink(f);
669         if (!l)
670                 goto out;
671
672         l->end[0].type = PASSTHRU;
673         l->end[0].port = sw_port;
674         l->end[0].n_id = sw_guid;
675         l->end[0].sw = sw;
676         l->end[0].link = l;
677
678         sw->port[sw_port] = &l->end[0];
679
680         l->end[1].type = SRCSINK;
681         l->end[1].port = ca_port;
682         l->end[1].n_id = ca_guid;
683         l->end[1].sw = NULL;            /* Correct for a CA */
684         l->end[1].link = l;
685
686         /*
687          * Fabric objects are temporary, so don't set osm_sw/osm_port priv
688          * pointers using them.  Wait until torus objects get constructed.
689          */
690         l->end[1].osm_port = osm_port_ca;
691
692         ++f->ca_cnt;
693         success = true;
694 out:
695         return success;
696 }
697
698 static
699 bool build_link(struct fabric *f,
700                 guid_t sw_guid0, int sw_port0, guid_t sw_guid1, int sw_port1)
701 {
702         struct link *l;
703         struct f_switch *sw0, *sw1;
704         bool success = false;
705
706         /*
707          * The link may already exist.
708          */
709         l = find_f_link(f, sw_guid0, sw_port0, sw_guid1, sw_port1);
710         if (l) {
711                 success = true;
712                 goto out;
713         }
714         /*
715          * The switches must already exist.
716          */
717         sw0 = find_f_sw(f, sw_guid0);
718         if (!sw0) {
719                 OSM_LOG(&f->osm->log, OSM_LOG_ERROR,
720                         "ERR 4E0A: missing switch w/GUID 0x%04"PRIx64"\n",
721                         cl_ntoh64(sw_guid0));
722                 goto out;
723         }
724         sw1 = find_f_sw(f, sw_guid1);
725         if (!sw1) {
726                 OSM_LOG(&f->osm->log, OSM_LOG_ERROR,
727                         "ERR 4E0B: missing switch w/GUID 0x%04"PRIx64"\n",
728                         cl_ntoh64(sw_guid1));
729                 goto out;
730         }
731         l = alloc_flink(f);
732         if (!l)
733                 goto out;
734
735         l->end[0].type = PASSTHRU;
736         l->end[0].port = sw_port0;
737         l->end[0].n_id = sw_guid0;
738         l->end[0].sw = sw0;
739         l->end[0].link = l;
740
741         sw0->port[sw_port0] = &l->end[0];
742
743         l->end[1].type = PASSTHRU;
744         l->end[1].port = sw_port1;
745         l->end[1].n_id = sw_guid1;
746         l->end[1].sw = sw1;
747         l->end[1].link = l;
748
749         sw1->port[sw_port1] = &l->end[1];
750
751         success = true;
752 out:
753         return success;
754 }
755
756 static
757 bool parse_size(unsigned *tsz, unsigned *tflags, unsigned mask,
758                 const char *parse_sep)
759 {
760         char *val, *nextchar;
761
762         val = strtok(NULL, parse_sep);
763         if (!val)
764                 return false;
765         *tsz = strtoul(val, &nextchar, 0);
766         if (*tsz) {
767                 if (*nextchar == 't' || *nextchar == 'T')
768                         *tflags &= ~mask;
769                 else if (*nextchar == 'm' || *nextchar == 'M')
770                         *tflags |= mask;
771                 /*
772                  * A torus of radix two is also a mesh of radix two
773                  * with multiple links between switches in that direction.
774                  *
775                  * Make it so always, otherwise the failure case routing
776                  * logic gets confused.
777                  */
778                 if (*tsz == 2)
779                         *tflags |= mask;
780         }
781         return true;
782 }
783
784 static
785 bool parse_torus(struct torus *t, const char *parse_sep)
786 {
787         unsigned i, j, k, cnt;
788         char *ptr;
789         bool success = false;
790
791         /*
792          * There can be only one.  Ignore the imposters.
793          */
794         if (t->sw_pool)
795                 goto out;
796
797         if (!parse_size(&t->x_sz, &t->flags, X_MESH, parse_sep))
798                 goto out;
799
800         if (!parse_size(&t->y_sz, &t->flags, Y_MESH, parse_sep))
801                 goto out;
802
803         if (!parse_size(&t->z_sz, &t->flags, Z_MESH, parse_sep))
804                 goto out;
805
806         /*
807          * Set up a linear array of switch pointers big enough to hold
808          * all expected switches.
809          */
810         t->sw_pool_sz = t->x_sz * t->y_sz * t->z_sz;
811         t->sw_pool = calloc(t->sw_pool_sz, sizeof(*t->sw_pool));
812         if (!t->sw_pool) {
813                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
814                         "ERR 4E0C: Torus switch array calloc: %s\n",
815                         strerror(errno));
816                 goto out;
817         }
818         /*
819          * Set things up so that t->sw[i][j][k] can point to the i,j,k switch.
820          */
821         cnt = t->x_sz * (1 + t->y_sz * (1 + t->z_sz));
822         t->sw = malloc(cnt * sizeof(void *));
823         if (!t->sw) {
824                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
825                         "ERR 4E0D: Torus switch array malloc: %s\n",
826                         strerror(errno));
827                 goto out;
828         }
829         ptr = (void *)(t->sw);
830
831         ptr += t->x_sz * sizeof(void *);
832         for (i = 0; i < t->x_sz; i++) {
833                 t->sw[i] = (void *)ptr;
834                 ptr += t->y_sz * sizeof(void *);
835         }
836         for (i = 0; i < t->x_sz; i++)
837                 for (j = 0; j < t->y_sz; j++) {
838                         t->sw[i][j] = (void *)ptr;
839                         ptr += t->z_sz * sizeof(void *);
840                 }
841
842         for (i = 0; i < t->x_sz; i++)
843                 for (j = 0; j < t->y_sz; j++)
844                         for (k = 0; k < t->z_sz; k++)
845                                 t->sw[i][j][k] = NULL;
846
847         success = true;
848 out:
849         return success;
850 }
851
852 static
853 bool parse_unsigned(unsigned *result, const char *parse_sep)
854 {
855         char *val, *nextchar;
856
857         val = strtok(NULL, parse_sep);
858         if (!val)
859                 return false;
860         *result = strtoul(val, &nextchar, 0);
861         return true;
862 }
863
864 static
865 bool parse_port_order(struct torus *t, const char *parse_sep)
866 {
867         unsigned i, j, k, n;
868
869         for (i = 0; i < ARRAY_SIZE(t->port_order); i++) {
870                 if (!parse_unsigned(&(t->port_order[i]), parse_sep))
871                         break;
872
873                 for (j = 0; j < i; j++) {
874                         if (t->port_order[j] == t->port_order[i]) {
875                                 OSM_LOG(&t->osm->log, OSM_LOG_INFO,
876                                         "Ignored duplicate port %u in"
877                                         " port_order parsing\n",
878                                         t->port_order[j]);
879                                 i--;    /* Ignore duplicate port number */
880                                 break;
881                         }
882                 }
883         }
884
885         n = i;
886         for (j = 0; j < ARRAY_SIZE(t->port_order); j++) {
887                 for (k = 0; k < i; k++)
888                         if (t->port_order[k] == j)
889                                 break;
890                 if (k >= i)
891                         t->port_order[n++] = j;
892         }
893
894         return true;
895 }
896
897 static
898 bool parse_guid(struct torus *t, guid_t *guid, const char *parse_sep)
899 {
900         char *val;
901         bool success = false;
902
903         val = strtok(NULL, parse_sep);
904         if (!val)
905                 goto out;
906         *guid = strtoull(val, NULL, 0);
907         *guid = cl_hton64(*guid);
908
909         success = true;
910 out:
911         return success;
912 }
913
914 static
915 bool parse_dir_link(int c_dir, struct torus *t, const char *parse_sep)
916 {
917         guid_t sw_guid0, sw_guid1;
918         struct link *l;
919         bool success = false;
920
921         if (!parse_guid(t, &sw_guid0, parse_sep))
922                 goto out;
923
924         if (!parse_guid(t, &sw_guid1, parse_sep))
925                 goto out;
926
927         if (!t) {
928                 success = true;
929                 goto out;
930         }
931
932         switch (c_dir) {
933         case -1:
934                 l = &t->seed[t->seed_cnt - 1].xm_link;
935                 break;
936         case  1:
937                 l = &t->seed[t->seed_cnt - 1].xp_link;
938                 break;
939         case -2:
940                 l = &t->seed[t->seed_cnt - 1].ym_link;
941                 break;
942         case  2:
943                 l = &t->seed[t->seed_cnt - 1].yp_link;
944                 break;
945         case -3:
946                 l = &t->seed[t->seed_cnt - 1].zm_link;
947                 break;
948         case  3:
949                 l = &t->seed[t->seed_cnt - 1].zp_link;
950                 break;
951         default:
952                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
953                         "ERR 4E0E: unknown link direction %d\n", c_dir);
954                 goto out;
955         }
956         l->end[0].type = PASSTHRU;
957         l->end[0].port = -1;            /* We don't really connect. */
958         l->end[0].n_id = sw_guid0;
959         l->end[0].sw = NULL;            /* Fix this up later. */
960         l->end[0].link = NULL;          /* Fix this up later. */
961
962         l->end[1].type = PASSTHRU;
963         l->end[1].port = -1;            /* We don't really connect. */
964         l->end[1].n_id = sw_guid1;
965         l->end[1].sw = NULL;            /* Fix this up later. */
966         l->end[1].link = NULL;          /* Fix this up later. */
967
968         success = true;
969 out:
970         return success;
971 }
972
973 static
974 bool parse_dir_dateline(int c_dir, struct torus *t, const char *parse_sep)
975 {
976         char *val;
977         int *dl, max_dl;
978         bool success = false;
979
980         val = strtok(NULL, parse_sep);
981         if (!val)
982                 goto out;
983
984         if (!t) {
985                 success = true;
986                 goto out;
987         }
988
989         switch (c_dir) {
990         case  1:
991                 dl = &t->seed[t->seed_cnt - 1].x_dateline;
992                 max_dl = t->x_sz;
993                 break;
994         case  2:
995                 dl = &t->seed[t->seed_cnt - 1].y_dateline;
996                 max_dl = t->y_sz;
997                 break;
998         case  3:
999                 dl = &t->seed[t->seed_cnt - 1].z_dateline;
1000                 max_dl = t->z_sz;
1001                 break;
1002         default:
1003                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1004                         "ERR 4E0F: unknown dateline direction %d\n", c_dir);
1005                 goto out;
1006         }
1007         *dl = strtol(val, NULL, 0);
1008
1009         if ((*dl < 0 && *dl <= -max_dl) || *dl >= max_dl)
1010                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1011                         "ERR 4E10: dateline value for coordinate direction %d "
1012                         "must be %d < dl < %d\n",
1013                         c_dir, -max_dl, max_dl);
1014         else
1015                 success = true;
1016 out:
1017         return success;
1018 }
1019
1020 static
1021 bool parse_config(const char *fn, struct fabric *f, struct torus *t)
1022 {
1023         FILE *fp;
1024         unsigned i;
1025         char *keyword;
1026         char *line_buf = NULL;
1027         const char *parse_sep = " \n\t\015";
1028         size_t line_buf_sz = 0;
1029         size_t line_cntr = 0;
1030         ssize_t llen;
1031         bool kw_success, success = true;
1032
1033         if (!grow_seed_array(t, 2))
1034                 return false;
1035
1036         for (i = 0; i < ARRAY_SIZE(t->port_order); i++)
1037                 t->port_order[i] = i;
1038
1039         fp = fopen(fn, "r");
1040         if (!fp) {
1041                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1042                         "ERR 4E11: Opening %s: %s\n", fn, strerror(errno));
1043                 return false;
1044         }
1045         t->flags |= NOTIFY_CHANGES;
1046         t->portgrp_sz = PORTGRP_MAX_PORTS;
1047         t->max_changes = DEFAULT_MAX_CHANGES;
1048
1049 next_line:
1050         llen = getline(&line_buf, &line_buf_sz, fp);
1051         if (llen < 0)
1052                 goto out;
1053
1054         ++line_cntr;
1055
1056         keyword = strtok(line_buf, parse_sep);
1057         if (!keyword)
1058                 goto next_line;
1059
1060         if (strcmp("torus", keyword) == 0) {
1061                 kw_success = parse_torus(t, parse_sep);
1062         } else if (strcmp("mesh", keyword) == 0) {
1063                 t->flags |= X_MESH | Y_MESH | Z_MESH;
1064                 kw_success = parse_torus(t, parse_sep);
1065         } else if (strcmp("port_order", keyword) == 0) {
1066                 kw_success = parse_port_order(t, parse_sep);
1067         } else if (strcmp("next_seed", keyword) == 0) {
1068                 kw_success = grow_seed_array(t, 1);
1069                 t->seed_cnt++;
1070         } else if (strcmp("portgroup_max_ports", keyword) == 0) {
1071                 kw_success = parse_unsigned(&t->portgrp_sz, parse_sep);
1072         } else if (strcmp("xp_link", keyword) == 0) {
1073                 if (!t->seed_cnt)
1074                         t->seed_cnt++;
1075                 kw_success = parse_dir_link(1, t, parse_sep);
1076         } else if (strcmp("xm_link", keyword) == 0) {
1077                 if (!t->seed_cnt)
1078                         t->seed_cnt++;
1079                 kw_success = parse_dir_link(-1, t, parse_sep);
1080         } else if (strcmp("x_dateline", keyword) == 0) {
1081                 if (!t->seed_cnt)
1082                         t->seed_cnt++;
1083                 kw_success = parse_dir_dateline(1, t, parse_sep);
1084         } else if (strcmp("yp_link", keyword) == 0) {
1085                 if (!t->seed_cnt)
1086                         t->seed_cnt++;
1087                 kw_success = parse_dir_link(2, t, parse_sep);
1088         } else if (strcmp("ym_link", keyword) == 0) {
1089                 if (!t->seed_cnt)
1090                         t->seed_cnt++;
1091                 kw_success = parse_dir_link(-2, t, parse_sep);
1092         } else if (strcmp("y_dateline", keyword) == 0) {
1093                 if (!t->seed_cnt)
1094                         t->seed_cnt++;
1095                 kw_success = parse_dir_dateline(2, t, parse_sep);
1096         } else if (strcmp("zp_link", keyword) == 0) {
1097                 if (!t->seed_cnt)
1098                         t->seed_cnt++;
1099                 kw_success = parse_dir_link(3, t, parse_sep);
1100         } else if (strcmp("zm_link", keyword) == 0) {
1101                 if (!t->seed_cnt)
1102                         t->seed_cnt++;
1103                 kw_success = parse_dir_link(-3, t, parse_sep);
1104         } else if (strcmp("z_dateline", keyword) == 0) {
1105                 if (!t->seed_cnt)
1106                         t->seed_cnt++;
1107                 kw_success = parse_dir_dateline(3, t, parse_sep);
1108         } else if (strcmp("max_changes", keyword) == 0) {
1109                 kw_success = parse_unsigned(&t->max_changes, parse_sep);
1110         } else if (keyword[0] == '#')
1111                 goto next_line;
1112         else {
1113                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1114                         "ERR 4E12: no keyword found: line %u\n",
1115                         (unsigned)line_cntr);
1116                 kw_success = false;
1117         }
1118         if (!kw_success) {
1119                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1120                         "ERR 4E13: parsing '%s': line %u\n",
1121                         keyword, (unsigned)line_cntr);
1122         }
1123         success = success && kw_success;
1124         goto next_line;
1125
1126 out:
1127         if (line_buf)
1128                 free(line_buf);
1129         fclose(fp);
1130         return success;
1131 }
1132
1133 static
1134 bool capture_fabric(struct fabric *fabric)
1135 {
1136         osm_subn_t *subnet = &fabric->osm->subn;
1137         osm_switch_t *osm_sw;
1138         osm_physp_t *lphysp, *rphysp;
1139         osm_port_t *lport;
1140         osm_node_t *osm_node;
1141         cl_map_item_t *item;
1142         uint8_t ltype, rtype;
1143         int p, port_cnt;
1144         guid_t sw_guid;
1145         bool success = true;
1146
1147         OSM_LOG_ENTER(&fabric->osm->log);
1148
1149         /*
1150          * On OpenSM data structures:
1151          *
1152          * Apparently, every port in a fabric has an associated osm_physp_t,
1153          * but not every port has an associated osm_port_t.  Apparently every
1154          * osm_port_t has an associated osm_physp_t.
1155          *
1156          * So, in order to find the inter-switch links we need to walk the
1157          * switch list and examine each port, via its osm_physp_t object.
1158          *
1159          * But, we need to associate our CA and switch management port
1160          * endpoints with the corresponding osm_port_t objects, in order
1161          * to simplify computation of LFT entries and perform SL lookup for
1162          * path records. Since it is apparently difficult to locate the
1163          * osm_port_t that corresponds to a given osm_physp_t, we also
1164          * need to walk the list of ports indexed by GUID to get access
1165          * to the appropriate osm_port_t objects.
1166          *
1167          * Need to allocate our switches before we do anything else.
1168          */
1169         item = cl_qmap_head(&subnet->sw_guid_tbl);
1170         while (item != cl_qmap_end(&subnet->sw_guid_tbl)) {
1171
1172                 osm_sw = (osm_switch_t *)item;
1173                 item = cl_qmap_next(item);
1174                 osm_sw->priv = NULL;  /* avoid stale pointer dereferencing */
1175                 osm_node = osm_sw->p_node;
1176
1177                 if (osm_node_get_type(osm_node) != IB_NODE_TYPE_SWITCH)
1178                         continue;
1179
1180                 port_cnt = osm_node_get_num_physp(osm_node);
1181                 sw_guid = osm_node_get_node_guid(osm_node);
1182
1183                 success = alloc_fswitch(fabric, sw_guid, port_cnt);
1184                 if (!success)
1185                         goto out;
1186         }
1187         /*
1188          * Now build all our endpoints.
1189          */
1190         item = cl_qmap_head(&subnet->port_guid_tbl);
1191         while (item != cl_qmap_end(&subnet->port_guid_tbl)) {
1192
1193                 lport = (osm_port_t *)item;
1194                 item = cl_qmap_next(item);
1195                 lport->priv = NULL;  /* avoid stale pointer dereferencing */
1196
1197                 lphysp = lport->p_physp;
1198                 if (!(lphysp && osm_physp_is_valid(lphysp)))
1199                         continue;
1200
1201                 ltype = osm_node_get_type(lphysp->p_node);
1202                 /*
1203                  * Switch management port is always port 0.
1204                  */
1205                 if (lphysp->port_num == 0 && ltype == IB_NODE_TYPE_SWITCH) {
1206                         success = build_sw_endpoint(fabric, lport);
1207                         if (!success)
1208                                 goto out;
1209                         continue;
1210                 }
1211                 rphysp = lphysp->p_remote_physp;
1212                 if (!(rphysp && osm_physp_is_valid(rphysp)))
1213                         continue;
1214
1215                 rtype = osm_node_get_type(rphysp->p_node);
1216
1217                 if ((ltype != IB_NODE_TYPE_CA &&
1218                      ltype != IB_NODE_TYPE_ROUTER) ||
1219                     rtype != IB_NODE_TYPE_SWITCH)
1220                         continue;
1221
1222                 success =
1223                         build_ca_link(fabric, lport,
1224                                       osm_node_get_node_guid(rphysp->p_node),
1225                                       osm_physp_get_port_num(rphysp));
1226                 if (!success)
1227                         goto out;
1228         }
1229         /*
1230          * Lastly, build all our interswitch links.
1231          */
1232         item = cl_qmap_head(&subnet->sw_guid_tbl);
1233         while (item != cl_qmap_end(&subnet->sw_guid_tbl)) {
1234
1235                 osm_sw = (osm_switch_t *)item;
1236                 item = cl_qmap_next(item);
1237
1238                 port_cnt = osm_node_get_num_physp(osm_sw->p_node);
1239                 for (p = 0; p < port_cnt; p++) {
1240
1241                         lphysp = osm_node_get_physp_ptr(osm_sw->p_node, p);
1242                         if (!(lphysp && osm_physp_is_valid(lphysp)))
1243                                 continue;
1244
1245                         rphysp = lphysp->p_remote_physp;
1246                         if (!(rphysp && osm_physp_is_valid(rphysp)))
1247                                 continue;
1248
1249                         if (lphysp == rphysp)
1250                                 continue;       /* ignore loopbacks */
1251
1252                         ltype = osm_node_get_type(lphysp->p_node);
1253                         rtype = osm_node_get_type(rphysp->p_node);
1254
1255                         if (ltype != IB_NODE_TYPE_SWITCH ||
1256                             rtype != IB_NODE_TYPE_SWITCH)
1257                                 continue;
1258
1259                         success =
1260                                 build_link(fabric,
1261                                            osm_node_get_node_guid(lphysp->p_node),
1262                                            osm_physp_get_port_num(lphysp),
1263                                            osm_node_get_node_guid(rphysp->p_node),
1264                                            osm_physp_get_port_num(rphysp));
1265                         if (!success)
1266                                 goto out;
1267                 }
1268         }
1269 out:
1270         OSM_LOG_EXIT(&fabric->osm->log);
1271         return success;
1272 }
1273
1274 /*
1275  * diagnose_fabric() is just intended to report on fabric elements that
1276  * could not be placed into the torus.  We want to warn that there were
1277  * non-torus fabric elements, but they will be ignored for routing purposes.
1278  * Having them is not an error, and diagnose_fabric() thus has no return
1279  * value.
1280  */
1281 static
1282 void diagnose_fabric(struct fabric *f)
1283 {
1284         struct link *l;
1285         struct endpoint *ep;
1286         unsigned k, p;
1287
1288         /*
1289          * Report on any links that didn't get transferred to the torus.
1290          */
1291         for (k = 0; k < f->link_cnt; k++) {
1292                 l = f->link[k];
1293
1294                 if (!(l->end[0].sw && l->end[1].sw))
1295                         continue;
1296
1297                 OSM_LOG(&f->osm->log, OSM_LOG_INFO,
1298                         "Found non-torus fabric link:"
1299                         " sw GUID 0x%04"PRIx64" port %d <->"
1300                         " sw GUID 0x%04"PRIx64" port %d\n",
1301                         cl_ntoh64(l->end[0].n_id), l->end[0].port,
1302                         cl_ntoh64(l->end[1].n_id), l->end[1].port);
1303         }
1304         /*
1305          * Report on any switches with ports using endpoints that didn't
1306          * get transferred to the torus.
1307          */
1308         for (k = 0; k < f->switch_cnt; k++)
1309                 for (p = 0; p < f->sw[k]->port_cnt; p++) {
1310
1311                         if (!f->sw[k]->port[p])
1312                                 continue;
1313
1314                         ep = f->sw[k]->port[p];
1315
1316                         /*
1317                          * We already reported on inter-switch links above.
1318                          */
1319                         if (ep->type == PASSTHRU)
1320                                 continue;
1321
1322                         OSM_LOG(&f->osm->log, OSM_LOG_INFO,
1323                                 "Found non-torus fabric port:"
1324                                 " sw GUID 0x%04"PRIx64" port %d\n",
1325                                 cl_ntoh64(f->sw[k]->n_id), p);
1326                 }
1327 }
1328
1329 static
1330 struct t_switch *alloc_tswitch(struct torus *t, struct f_switch *fsw)
1331 {
1332         unsigned g;
1333         size_t new_sw_sz;
1334         struct t_switch *sw = NULL;
1335         void *ptr;
1336
1337         if (!fsw)
1338                 goto out;
1339
1340         if (t->switch_cnt >= t->sw_pool_sz) {
1341                 /*
1342                  * This should never happen, but occasionally a particularly
1343                  * pathological fabric can induce it.  So log an error.
1344                  */
1345                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1346                         "ERR 4E14: unexpectedly requested too many switch "
1347                         "structures!\n");
1348                 goto out;
1349         }
1350         new_sw_sz = sizeof(*sw)
1351                 + fsw->port_cnt * sizeof(*sw->port)
1352                 + SWITCH_MAX_PORTGRPS * t->portgrp_sz * sizeof(*sw->ptgrp[0].port);
1353         sw = calloc(1, new_sw_sz);
1354         if (!sw) {
1355                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1356                         "ERR 4E15: calloc: %s\n", strerror(errno));
1357                 goto out;
1358         }
1359         sw->port = (void *)(sw + 1);
1360         sw->n_id = fsw->n_id;
1361         sw->port_cnt = fsw->port_cnt;
1362         sw->torus = t;
1363         sw->tmp = fsw;
1364
1365         ptr = &sw->port[sw->port_cnt];
1366
1367         for (g = 0; g < SWITCH_MAX_PORTGRPS; g++) {
1368                 sw->ptgrp[g].port_grp = g;
1369                 sw->ptgrp[g].sw = sw;
1370                 sw->ptgrp[g].port = ptr;
1371                 ptr = &sw->ptgrp[g].port[t->portgrp_sz];
1372         }
1373         t->sw_pool[t->switch_cnt++] = sw;
1374 out:
1375         return sw;
1376 }
1377
1378 /*
1379  * install_tswitch() expects the switch coordinates i,j,k to be canonicalized
1380  * by caller.
1381  */
1382 static
1383 bool install_tswitch(struct torus *t,
1384                      int i, int j, int k, struct f_switch *fsw)
1385 {
1386         struct t_switch **sw = &t->sw[i][j][k];
1387
1388         if (!*sw)
1389                 *sw = alloc_tswitch(t, fsw);
1390
1391         if (*sw) {
1392                 (*sw)->i = i;
1393                 (*sw)->j = j;
1394                 (*sw)->k = k;
1395         }
1396         return !!*sw;
1397 }
1398
1399 static
1400 struct link *alloc_tlink(struct torus *t)
1401 {
1402         if (t->link_cnt >= t->link_pool_sz) {
1403                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1404                         "ERR 4E16: unexpectedly out of pre-allocated link "
1405                         "structures!\n");
1406                 return NULL;
1407         }
1408         return &t->link_pool[t->link_cnt++];
1409 }
1410
1411 static
1412 int canonicalize(int v, int vmax)
1413 {
1414         if (v >= 0 && v < vmax)
1415                 return v;
1416
1417         if (v < 0)
1418                 v += vmax * (1 - v/vmax);
1419
1420         return v % vmax;
1421 }
1422
1423 static
1424 unsigned set_fp_bit(bool present, int i, int j, int k)
1425 {
1426         return (unsigned)(!present) << (i + 2 * j + 4 * k);
1427 }
1428
1429 /*
1430  * Returns an 11-bit fingerprint of what switches are absent in a cube of
1431  * neighboring switches.  Each bit 0-7 corresponds to a corner of the cube;
1432  * if a bit is set the corresponding switch is absent.
1433  *
1434  * Bits 8-10 distinguish between 2D and 3D cases.  If bit 8+d is set,
1435  * for 0 <= d < 3;  the d dimension of the desired torus has radix greater
1436  * than 1. Thus, if all bits 8-10 are set, the desired torus is 3D.
1437  */
1438 static
1439 unsigned fingerprint(struct torus *t, int i, int j, int k)
1440 {
1441         unsigned fp;
1442         int ip1, jp1, kp1;
1443         int x_sz_gt1, y_sz_gt1, z_sz_gt1;
1444
1445         x_sz_gt1 = t->x_sz > 1;
1446         y_sz_gt1 = t->y_sz > 1;
1447         z_sz_gt1 = t->z_sz > 1;
1448
1449         ip1 = canonicalize(i + 1, t->x_sz);
1450         jp1 = canonicalize(j + 1, t->y_sz);
1451         kp1 = canonicalize(k + 1, t->z_sz);
1452
1453         fp  = set_fp_bit(t->sw[i][j][k], 0, 0, 0);
1454         fp |= set_fp_bit(t->sw[ip1][j][k], x_sz_gt1, 0, 0);
1455         fp |= set_fp_bit(t->sw[i][jp1][k], 0, y_sz_gt1, 0);
1456         fp |= set_fp_bit(t->sw[ip1][jp1][k], x_sz_gt1, y_sz_gt1, 0);
1457         fp |= set_fp_bit(t->sw[i][j][kp1], 0, 0, z_sz_gt1);
1458         fp |= set_fp_bit(t->sw[ip1][j][kp1], x_sz_gt1, 0, z_sz_gt1);
1459         fp |= set_fp_bit(t->sw[i][jp1][kp1], 0, y_sz_gt1, z_sz_gt1);
1460         fp |= set_fp_bit(t->sw[ip1][jp1][kp1], x_sz_gt1, y_sz_gt1, z_sz_gt1);
1461
1462         fp |= x_sz_gt1 << 8;
1463         fp |= y_sz_gt1 << 9;
1464         fp |= z_sz_gt1 << 10;
1465
1466         return fp;
1467 }
1468
1469 static
1470 bool connect_tlink(struct port_grp *pg0, struct endpoint *f_ep0,
1471                    struct port_grp *pg1, struct endpoint *f_ep1,
1472                    struct torus *t)
1473 {
1474         struct link *l;
1475         bool success = false;
1476
1477         if (pg0->port_cnt == t->portgrp_sz) {
1478                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1479                         "ERR 4E17: exceeded port group max "
1480                         "port count (%d): switch GUID 0x%04"PRIx64"\n",
1481                         t->portgrp_sz, cl_ntoh64(pg0->sw->n_id));
1482                 goto out;
1483         }
1484         if (pg1->port_cnt == t->portgrp_sz) {
1485                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1486                         "ERR 4E18: exceeded port group max "
1487                         "port count (%d): switch GUID 0x%04"PRIx64"\n",
1488                         t->portgrp_sz, cl_ntoh64(pg1->sw->n_id));
1489                 goto out;
1490         }
1491         l = alloc_tlink(t);
1492         if (!l)
1493                 goto out;
1494
1495         l->end[0].type = f_ep0->type;
1496         l->end[0].port = f_ep0->port;
1497         l->end[0].n_id = f_ep0->n_id;
1498         l->end[0].sw = pg0->sw;
1499         l->end[0].link = l;
1500         l->end[0].pgrp = pg0;
1501         pg0->port[pg0->port_cnt++] = &l->end[0];
1502         pg0->sw->port[f_ep0->port] = &l->end[0];
1503
1504         if (f_ep0->osm_port) {
1505                 l->end[0].osm_port = f_ep0->osm_port;
1506                 l->end[0].osm_port->priv = &l->end[0];
1507                 f_ep0->osm_port = NULL;
1508         }
1509
1510         l->end[1].type = f_ep1->type;
1511         l->end[1].port = f_ep1->port;
1512         l->end[1].n_id = f_ep1->n_id;
1513         l->end[1].sw = pg1->sw;
1514         l->end[1].link = l;
1515         l->end[1].pgrp = pg1;
1516         pg1->port[pg1->port_cnt++] = &l->end[1];
1517         pg1->sw->port[f_ep1->port] = &l->end[1];
1518
1519         if (f_ep1->osm_port) {
1520                 l->end[1].osm_port = f_ep1->osm_port;
1521                 l->end[1].osm_port->priv = &l->end[1];
1522                 f_ep1->osm_port = NULL;
1523         }
1524         /*
1525          * Disconnect fabric link, so that later we can see if any were
1526          * left unconnected in the torus.
1527          */
1528         ((struct f_switch *)f_ep0->sw)->port[f_ep0->port] = NULL;
1529         f_ep0->sw = NULL;
1530         f_ep0->port = -1;
1531
1532         ((struct f_switch *)f_ep1->sw)->port[f_ep1->port] = NULL;
1533         f_ep1->sw = NULL;
1534         f_ep1->port = -1;
1535
1536         success = true;
1537 out:
1538         return success;
1539 }
1540
1541 static
1542 bool link_tswitches(struct torus *t, int cdir,
1543                     struct t_switch *t_sw0, struct t_switch *t_sw1)
1544 {
1545         int p;
1546         struct port_grp *pg0, *pg1;
1547         struct f_switch *f_sw0, *f_sw1;
1548         const char *cdir_name = "unknown";
1549         unsigned port_cnt;
1550         int success = false;
1551
1552         /*
1553          * If this is a 2D torus, it is possible for this function to be
1554          * called with its two switch arguments being the same switch, in
1555          * which case there are no links to install.
1556          */
1557         if (t_sw0 == t_sw1 &&
1558             ((cdir == 0 && t->x_sz == 1) ||
1559              (cdir == 1 && t->y_sz == 1) ||
1560              (cdir == 2 && t->z_sz == 1))) {
1561                 success = true;
1562                 goto out;
1563         }
1564         /*
1565          * Ensure that t_sw1 is in the positive cdir direction wrt. t_sw0.
1566          * ring_next_sw() relies on it.
1567          */
1568         switch (cdir) {
1569         case 0:
1570                 if (t->x_sz > 1 &&
1571                     canonicalize(t_sw0->i + 1, t->x_sz) != t_sw1->i) {
1572                         cdir_name = "x";
1573                         goto cdir_error;
1574                 }
1575                 break;
1576         case 1:
1577                 if (t->y_sz > 1 &&
1578                     canonicalize(t_sw0->j + 1, t->y_sz) != t_sw1->j) {
1579                         cdir_name = "y";
1580                         goto cdir_error;
1581                 }
1582                 break;
1583         case 2:
1584                 if (t->z_sz > 1 &&
1585                     canonicalize(t_sw0->k + 1, t->z_sz) != t_sw1->k) {
1586                         cdir_name = "z";
1587                         goto cdir_error;
1588                 }
1589                 break;
1590         default:
1591         cdir_error:
1592                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR, "ERR 4E19: "
1593                         "sw 0x%04"PRIx64" (%d,%d,%d) <--> "
1594                         "sw 0x%04"PRIx64" (%d,%d,%d) "
1595                         "invalid torus %s link orientation\n",
1596                         cl_ntoh64(t_sw0->n_id), t_sw0->i, t_sw0->j, t_sw0->k,
1597                         cl_ntoh64(t_sw1->n_id), t_sw1->i, t_sw1->j, t_sw1->k,
1598                         cdir_name);
1599                 goto out;
1600         }
1601
1602         f_sw0 = t_sw0->tmp;
1603         f_sw1 = t_sw1->tmp;
1604
1605         if (!f_sw0 || !f_sw1) {
1606                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1607                         "ERR 4E1A: missing fabric switches!\n"
1608                         "  switch GUIDs: 0x%04"PRIx64" 0x%04"PRIx64"\n",
1609                         cl_ntoh64(t_sw0->n_id), cl_ntoh64(t_sw1->n_id));
1610                 goto out;
1611         }
1612         pg0 = &t_sw0->ptgrp[2*cdir + 1];
1613         pg0->type = PASSTHRU;
1614
1615         pg1 = &t_sw1->ptgrp[2*cdir];
1616         pg1->type = PASSTHRU;
1617
1618         port_cnt = f_sw0->port_cnt;
1619         /*
1620          * Find all the links between these two switches.
1621          */
1622         for (p = 0; p < port_cnt; p++) {
1623                 struct endpoint *f_ep0 = NULL, *f_ep1 = NULL;
1624
1625                 if (!f_sw0->port[p] || !f_sw0->port[p]->link)
1626                         continue;
1627
1628                 if (f_sw0->port[p]->link->end[0].n_id == t_sw0->n_id &&
1629                     f_sw0->port[p]->link->end[1].n_id == t_sw1->n_id) {
1630
1631                         f_ep0 = &f_sw0->port[p]->link->end[0];
1632                         f_ep1 = &f_sw0->port[p]->link->end[1];
1633                 } else if (f_sw0->port[p]->link->end[1].n_id == t_sw0->n_id &&
1634                            f_sw0->port[p]->link->end[0].n_id == t_sw1->n_id) {
1635
1636                         f_ep0 = &f_sw0->port[p]->link->end[1];
1637                         f_ep1 = &f_sw0->port[p]->link->end[0];
1638                 } else
1639                         continue;
1640
1641                 if (!(f_ep0->type == PASSTHRU && f_ep1->type == PASSTHRU)) {
1642                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1643                                 "ERR 4E1B: not interswitch "
1644                                 "link:\n  0x%04"PRIx64"/%d <-> 0x%04"PRIx64"/%d\n",
1645                                 cl_ntoh64(f_ep0->n_id), f_ep0->port,
1646                                 cl_ntoh64(f_ep1->n_id), f_ep1->port);
1647                         goto out;
1648                 }
1649                 /*
1650                  * Skip over links that already have been established in the
1651                  * torus.
1652                  */
1653                 if (!(f_ep0->sw && f_ep1->sw))
1654                         continue;
1655
1656                 if (!connect_tlink(pg0, f_ep0, pg1, f_ep1, t))
1657                         goto out;
1658         }
1659         success = true;
1660 out:
1661         return success;
1662 }
1663
1664 static
1665 bool link_srcsink(struct torus *t, int i, int j, int k)
1666 {
1667         struct endpoint *f_ep0;
1668         struct endpoint *f_ep1;
1669         struct t_switch *tsw;
1670         struct f_switch *fsw;
1671         struct port_grp *pg;
1672         struct link *fl, *tl;
1673         unsigned p, port_cnt;
1674         bool success = false;
1675
1676         i = canonicalize(i, t->x_sz);
1677         j = canonicalize(j, t->y_sz);
1678         k = canonicalize(k, t->z_sz);
1679
1680         tsw = t->sw[i][j][k];
1681         if (!tsw)
1682                 return true;
1683
1684         fsw = tsw->tmp;
1685         /*
1686          * link_srcsink is supposed to get called once for every switch in
1687          * the fabric.  At this point every fsw we encounter must have a
1688          * non-null osm_switch.  Otherwise something has gone horribly
1689          * wrong with topology discovery; the most likely reason is that
1690          * the fabric contains a radix-4 torus dimension, but the user gave
1691          * a config that didn't say so, breaking all the checking in
1692          * safe_x_perpendicular and friends.
1693          */
1694         if (!(fsw && fsw->osm_switch)) {
1695                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1696                         "ERR 4E1C: Invalid topology discovery. "
1697                         "Verify torus-2QoS.conf contents.\n");
1698                 return false;
1699         }
1700
1701         pg = &tsw->ptgrp[2 * TORUS_MAX_DIM];
1702         pg->type = SRCSINK;
1703         tsw->osm_switch = fsw->osm_switch;
1704         tsw->osm_switch->priv = tsw;
1705         fsw->osm_switch = NULL;
1706
1707         port_cnt = fsw->port_cnt;
1708         for (p = 0; p < port_cnt; p++) {
1709
1710                 if (!fsw->port[p])
1711                         continue;
1712
1713                 if (fsw->port[p]->type == SRCSINK) {
1714                         /*
1715                          * If the endpoint is the switch port used for in-band
1716                          * communication with the switch itself, move it to
1717                          * the torus.
1718                          */
1719                         if (pg->port_cnt == t->portgrp_sz) {
1720                                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1721                                         "ERR 4E1D: exceeded port group max port "
1722                                         "count (%d): switch GUID 0x%04"PRIx64"\n",
1723                                         t->portgrp_sz, cl_ntoh64(tsw->n_id));
1724                                 goto out;
1725                         }
1726                         fsw->port[p]->sw = tsw;
1727                         fsw->port[p]->pgrp = pg;
1728                         tsw->port[p] = fsw->port[p];
1729                         tsw->port[p]->osm_port->priv = tsw->port[p];
1730                         pg->port[pg->port_cnt++] = fsw->port[p];
1731                         fsw->port[p] = NULL;
1732
1733                 } else if (fsw->port[p]->link &&
1734                            fsw->port[p]->type == PASSTHRU) {
1735                         /*
1736                          * If the endpoint is a link to a CA, create a new link
1737                          * in the torus.  Disconnect the fabric link.
1738                          */
1739
1740                         fl = fsw->port[p]->link;
1741
1742                         if (fl->end[0].sw == fsw) {
1743                                 f_ep0 = &fl->end[0];
1744                                 f_ep1 = &fl->end[1];
1745                         } else if (fl->end[1].sw == fsw) {
1746                                 f_ep1 = &fl->end[0];
1747                                 f_ep0 = &fl->end[1];
1748                         } else
1749                                 continue;
1750
1751                         if (f_ep1->type != SRCSINK)
1752                                 continue;
1753
1754                         if (pg->port_cnt == t->portgrp_sz) {
1755                                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1756                                         "ERR 4E1E: exceeded port group max port "
1757                                         "count (%d): switch GUID 0x%04"PRIx64"\n",
1758                                         t->portgrp_sz, cl_ntoh64(tsw->n_id));
1759                                 goto out;
1760                         }
1761                         /*
1762                          * Switch ports connected to links don't get
1763                          * associated with osm_port_t objects; see
1764                          * capture_fabric().  So just check CA end.
1765                          */
1766                         if (!f_ep1->osm_port) {
1767                                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
1768                                         "ERR 4E1F: NULL osm_port->priv port "
1769                                         "GUID 0x%04"PRIx64"\n",
1770                                         cl_ntoh64(f_ep1->n_id));
1771                                 goto out;
1772                         }
1773                         tl = alloc_tlink(t);
1774                         if (!tl)
1775                                 continue;
1776
1777                         tl->end[0].type = f_ep0->type;
1778                         tl->end[0].port = f_ep0->port;
1779                         tl->end[0].n_id = f_ep0->n_id;
1780                         tl->end[0].sw = tsw;
1781                         tl->end[0].link = tl;
1782                         tl->end[0].pgrp = pg;
1783                         pg->port[pg->port_cnt++] = &tl->end[0];
1784                         pg->sw->port[f_ep0->port] =  &tl->end[0];
1785
1786                         tl->end[1].type = f_ep1->type;
1787                         tl->end[1].port = f_ep1->port;
1788                         tl->end[1].n_id = f_ep1->n_id;
1789                         tl->end[1].sw = NULL;   /* Correct for a CA */
1790                         tl->end[1].link = tl;
1791                         tl->end[1].pgrp = NULL; /* Correct for a CA */
1792
1793                         tl->end[1].osm_port = f_ep1->osm_port;
1794                         tl->end[1].osm_port->priv = &tl->end[1];
1795                         f_ep1->osm_port = NULL;
1796
1797                         t->ca_cnt++;
1798                         f_ep0->sw = NULL;
1799                         f_ep0->port = -1;
1800                         fsw->port[p] = NULL;
1801                 }
1802         }
1803         success = true;
1804 out:
1805         return success;
1806 }
1807
1808 static
1809 struct f_switch *ffind_face_corner(struct f_switch *fsw0,
1810                                    struct f_switch *fsw1,
1811                                    struct f_switch *fsw2)
1812 {
1813         int p0, p3;
1814         struct link *l;
1815         struct endpoint *far_end;
1816         struct f_switch *fsw, *fsw3 = NULL;
1817
1818         if (!(fsw0 && fsw1 && fsw2))
1819                 goto out;
1820
1821         for (p0 = 0; p0 < fsw0->port_cnt; p0++) {
1822                 /*
1823                  * Ignore everything except switch links that haven't
1824                  * been installed into the torus.
1825                  */
1826                 if (!(fsw0->port[p0] && fsw0->port[p0]->sw &&
1827                       fsw0->port[p0]->type == PASSTHRU))
1828                         continue;
1829
1830                 l = fsw0->port[p0]->link;
1831
1832                 if (l->end[0].n_id == fsw0->n_id)
1833                         far_end = &l->end[1];
1834                 else
1835                         far_end = &l->end[0];
1836
1837                 /*
1838                  * Ignore CAs
1839                  */
1840                 if (!(far_end->type == PASSTHRU && far_end->sw))
1841                         continue;
1842
1843                 fsw3 = far_end->sw;
1844                 if (fsw3->n_id == fsw1->n_id)   /* existing corner */
1845                         continue;
1846
1847                 for (p3 = 0; p3 < fsw3->port_cnt; p3++) {
1848                         /*
1849                          * Ignore everything except switch links that haven't
1850                          * been installed into the torus.
1851                          */
1852                         if (!(fsw3->port[p3] && fsw3->port[p3]->sw &&
1853                               fsw3->port[p3]->type == PASSTHRU))
1854                                 continue;
1855
1856                         l = fsw3->port[p3]->link;
1857
1858                         if (l->end[0].n_id == fsw3->n_id)
1859                                 far_end = &l->end[1];
1860                         else
1861                                 far_end = &l->end[0];
1862
1863                         /*
1864                          * Ignore CAs
1865                          */
1866                         if (!(far_end->type == PASSTHRU && far_end->sw))
1867                                 continue;
1868
1869                         fsw = far_end->sw;
1870                         if (fsw->n_id == fsw2->n_id)
1871                                 goto out;
1872                 }
1873         }
1874         fsw3 = NULL;
1875 out:
1876         return fsw3;
1877 }
1878
1879 static
1880 struct f_switch *tfind_face_corner(struct t_switch *tsw0,
1881                                    struct t_switch *tsw1,
1882                                    struct t_switch *tsw2)
1883 {
1884         if (!(tsw0 && tsw1 && tsw2))
1885                 return NULL;
1886
1887         return ffind_face_corner(tsw0->tmp, tsw1->tmp, tsw2->tmp);
1888 }
1889
1890 /*
1891  * This code can break on any torus with a dimension that has radix four.
1892  *
1893  * What is supposed to happen is that this code will find the
1894  * two faces whose shared edge is the desired perpendicular.
1895  *
1896  * What actually happens is while searching we send two connected
1897  * edges that are colinear in a torus dimension with radix four to
1898  * ffind_face_corner(), which tries to complete a face by finding a
1899  * 4-loop of edges.
1900  *
1901  * In the radix four torus case, it can find a 4-loop which is a ring in a
1902  * dimension with radix four, rather than the desired face.  It thus returns
1903  * true when it shouldn't, so the wrong edge is returned as the perpendicular.
1904  *
1905  * The appropriate instance of safe_N_perpendicular() (where N == x, y, z)
1906  * should be used to determine if it is safe to call ffind_perpendicular();
1907  * these functions will return false it there is a possibility of finding
1908  * a wrong perpendicular.
1909  */
1910 struct f_switch *ffind_3d_perpendicular(struct f_switch *fsw0,
1911                                         struct f_switch *fsw1,
1912                                         struct f_switch *fsw2,
1913                                         struct f_switch *fsw3)
1914 {
1915         int p1;
1916         struct link *l;
1917         struct endpoint *far_end;
1918         struct f_switch *fsw4 = NULL;
1919
1920         if (!(fsw0 && fsw1 && fsw2 && fsw3))
1921                 goto out;
1922
1923         /*
1924          * Look at all the ports on the switch, fsw1,  that is the base of
1925          * the perpendicular.
1926          */
1927         for (p1 = 0; p1 < fsw1->port_cnt; p1++) {
1928                 /*
1929                  * Ignore everything except switch links that haven't
1930                  * been installed into the torus.
1931                  */
1932                 if (!(fsw1->port[p1] && fsw1->port[p1]->sw &&
1933                       fsw1->port[p1]->type == PASSTHRU))
1934                         continue;
1935
1936                 l = fsw1->port[p1]->link;
1937
1938                 if (l->end[0].n_id == fsw1->n_id)
1939                         far_end = &l->end[1];
1940                 else
1941                         far_end = &l->end[0];
1942                 /*
1943                  * Ignore CAs
1944                  */
1945                 if (!(far_end->type == PASSTHRU && far_end->sw))
1946                         continue;
1947
1948                 fsw4 = far_end->sw;
1949                 if (fsw4->n_id == fsw3->n_id)   /* wrong perpendicular */
1950                         continue;
1951
1952                 if (ffind_face_corner(fsw0, fsw1, fsw4) &&
1953                     ffind_face_corner(fsw2, fsw1, fsw4))
1954                         goto out;
1955         }
1956         fsw4 = NULL;
1957 out:
1958         return fsw4;
1959 }
1960 struct f_switch *ffind_2d_perpendicular(struct f_switch *fsw0,
1961                                         struct f_switch *fsw1,
1962                                         struct f_switch *fsw2)
1963 {
1964         int p1;
1965         struct link *l;
1966         struct endpoint *far_end;
1967         struct f_switch *fsw3 = NULL;
1968
1969         if (!(fsw0 && fsw1 && fsw2))
1970                 goto out;
1971
1972         /*
1973          * Look at all the ports on the switch, fsw1,  that is the base of
1974          * the perpendicular.
1975          */
1976         for (p1 = 0; p1 < fsw1->port_cnt; p1++) {
1977                 /*
1978                  * Ignore everything except switch links that haven't
1979                  * been installed into the torus.
1980                  */
1981                 if (!(fsw1->port[p1] && fsw1->port[p1]->sw &&
1982                       fsw1->port[p1]->type == PASSTHRU))
1983                         continue;
1984
1985                 l = fsw1->port[p1]->link;
1986
1987                 if (l->end[0].n_id == fsw1->n_id)
1988                         far_end = &l->end[1];
1989                 else
1990                         far_end = &l->end[0];
1991                 /*
1992                  * Ignore CAs
1993                  */
1994                 if (!(far_end->type == PASSTHRU && far_end->sw))
1995                         continue;
1996
1997                 fsw3 = far_end->sw;
1998                 if (fsw3->n_id == fsw2->n_id)   /* wrong perpendicular */
1999                         continue;
2000
2001                 if (ffind_face_corner(fsw0, fsw1, fsw3))
2002                         goto out;
2003         }
2004         fsw3 = NULL;
2005 out:
2006         return fsw3;
2007 }
2008
2009 static
2010 struct f_switch *tfind_3d_perpendicular(struct t_switch *tsw0,
2011                                         struct t_switch *tsw1,
2012                                         struct t_switch *tsw2,
2013                                         struct t_switch *tsw3)
2014 {
2015         if (!(tsw0 && tsw1 && tsw2 && tsw3))
2016                 return NULL;
2017
2018         return ffind_3d_perpendicular(tsw0->tmp, tsw1->tmp,
2019                                       tsw2->tmp, tsw3->tmp);
2020 }
2021
2022 static
2023 struct f_switch *tfind_2d_perpendicular(struct t_switch *tsw0,
2024                                         struct t_switch *tsw1,
2025                                         struct t_switch *tsw2)
2026 {
2027         if (!(tsw0 && tsw1 && tsw2))
2028                 return NULL;
2029
2030         return ffind_2d_perpendicular(tsw0->tmp, tsw1->tmp, tsw2->tmp);
2031 }
2032
2033 static
2034 bool safe_x_ring(struct torus *t, int i, int j, int k)
2035 {
2036         int im1, ip1, ip2;
2037         bool success = true;
2038
2039         /*
2040          * If this x-direction radix-4 ring has at least two links
2041          * already installed into the torus,  then this ring does not
2042          * prevent us from looking for y or z direction perpendiculars.
2043          *
2044          * It is easier to check for the appropriate switches being installed
2045          * into the torus than it is to check for the links, so force the
2046          * link installation if the appropriate switches are installed.
2047          *
2048          * Recall that canonicalize(n - 2, 4) == canonicalize(n + 2, 4).
2049          */
2050         if (t->x_sz != 4 || t->flags & X_MESH)
2051                 goto out;
2052
2053         im1 = canonicalize(i - 1, t->x_sz);
2054         ip1 = canonicalize(i + 1, t->x_sz);
2055         ip2 = canonicalize(i + 2, t->x_sz);
2056
2057         if (!!t->sw[im1][j][k] +
2058             !!t->sw[ip1][j][k] + !!t->sw[ip2][j][k] < 2) {
2059                 success = false;
2060                 goto out;
2061         }
2062         if (t->sw[ip2][j][k] && t->sw[im1][j][k])
2063                 success = link_tswitches(t, 0,
2064                                          t->sw[ip2][j][k],
2065                                          t->sw[im1][j][k])
2066                         && success;
2067
2068         if (t->sw[im1][j][k] && t->sw[i][j][k])
2069                 success = link_tswitches(t, 0,
2070                                          t->sw[im1][j][k],
2071                                          t->sw[i][j][k])
2072                         && success;
2073
2074         if (t->sw[i][j][k] && t->sw[ip1][j][k])
2075                 success = link_tswitches(t, 0,
2076                                          t->sw[i][j][k],
2077                                          t->sw[ip1][j][k])
2078                         && success;
2079
2080         if (t->sw[ip1][j][k] && t->sw[ip2][j][k])
2081                 success = link_tswitches(t, 0,
2082                                          t->sw[ip1][j][k],
2083                                          t->sw[ip2][j][k])
2084                         && success;
2085 out:
2086         return success;
2087 }
2088
2089 static
2090 bool safe_y_ring(struct torus *t, int i, int j, int k)
2091 {
2092         int jm1, jp1, jp2;
2093         bool success = true;
2094
2095         /*
2096          * If this y-direction radix-4 ring has at least two links
2097          * already installed into the torus,  then this ring does not
2098          * prevent us from looking for x or z direction perpendiculars.
2099          *
2100          * It is easier to check for the appropriate switches being installed
2101          * into the torus than it is to check for the links, so force the
2102          * link installation if the appropriate switches are installed.
2103          *
2104          * Recall that canonicalize(n - 2, 4) == canonicalize(n + 2, 4).
2105          */
2106         if (t->y_sz != 4 || (t->flags & Y_MESH))
2107                 goto out;
2108
2109         jm1 = canonicalize(j - 1, t->y_sz);
2110         jp1 = canonicalize(j + 1, t->y_sz);
2111         jp2 = canonicalize(j + 2, t->y_sz);
2112
2113         if (!!t->sw[i][jm1][k] +
2114             !!t->sw[i][jp1][k] + !!t->sw[i][jp2][k] < 2) {
2115                 success = false;
2116                 goto out;
2117         }
2118         if (t->sw[i][jp2][k] && t->sw[i][jm1][k])
2119                 success = link_tswitches(t, 1,
2120                                          t->sw[i][jp2][k],
2121                                          t->sw[i][jm1][k])
2122                         && success;
2123
2124         if (t->sw[i][jm1][k] && t->sw[i][j][k])
2125                 success = link_tswitches(t, 1,
2126                                          t->sw[i][jm1][k],
2127                                          t->sw[i][j][k])
2128                         && success;
2129
2130         if (t->sw[i][j][k] && t->sw[i][jp1][k])
2131                 success = link_tswitches(t, 1,
2132                                          t->sw[i][j][k],
2133                                          t->sw[i][jp1][k])
2134                         && success;
2135
2136         if (t->sw[i][jp1][k] && t->sw[i][jp2][k])
2137                 success = link_tswitches(t, 1,
2138                                          t->sw[i][jp1][k],
2139                                          t->sw[i][jp2][k])
2140                         && success;
2141 out:
2142         return success;
2143 }
2144
2145 static
2146 bool safe_z_ring(struct torus *t, int i, int j, int k)
2147 {
2148         int km1, kp1, kp2;
2149         bool success = true;
2150
2151         /*
2152          * If this z-direction radix-4 ring has at least two links
2153          * already installed into the torus,  then this ring does not
2154          * prevent us from looking for x or y direction perpendiculars.
2155          *
2156          * It is easier to check for the appropriate switches being installed
2157          * into the torus than it is to check for the links, so force the
2158          * link installation if the appropriate switches are installed.
2159          *
2160          * Recall that canonicalize(n - 2, 4) == canonicalize(n + 2, 4).
2161          */
2162         if (t->z_sz != 4 || t->flags & Z_MESH)
2163                 goto out;
2164
2165         km1 = canonicalize(k - 1, t->z_sz);
2166         kp1 = canonicalize(k + 1, t->z_sz);
2167         kp2 = canonicalize(k + 2, t->z_sz);
2168
2169         if (!!t->sw[i][j][km1] +
2170             !!t->sw[i][j][kp1] + !!t->sw[i][j][kp2] < 2) {
2171                 success = false;
2172                 goto out;
2173         }
2174         if (t->sw[i][j][kp2] && t->sw[i][j][km1])
2175                 success = link_tswitches(t, 2,
2176                                          t->sw[i][j][kp2],
2177                                          t->sw[i][j][km1])
2178                         && success;
2179
2180         if (t->sw[i][j][km1] && t->sw[i][j][k])
2181                 success = link_tswitches(t, 2,
2182                                          t->sw[i][j][km1],
2183                                          t->sw[i][j][k])
2184                         && success;
2185
2186         if (t->sw[i][j][k] && t->sw[i][j][kp1])
2187                 success = link_tswitches(t, 2,
2188                                          t->sw[i][j][k],
2189                                          t->sw[i][j][kp1])
2190                         && success;
2191
2192         if (t->sw[i][j][kp1] && t->sw[i][j][kp2])
2193                 success = link_tswitches(t, 2,
2194                                          t->sw[i][j][kp1],
2195                                          t->sw[i][j][kp2])
2196                         && success;
2197 out:
2198         return success;
2199 }
2200
2201 /*
2202  * These functions return true when it safe to call
2203  * tfind_3d_perpendicular()/ffind_3d_perpendicular().
2204  */
2205 static
2206 bool safe_x_perpendicular(struct torus *t, int i, int j, int k)
2207 {
2208         /*
2209          * If the dimensions perpendicular to the search direction are
2210          * not radix 4 torus dimensions, it is always safe to search for
2211          * a perpendicular.
2212          *
2213          * Here we are checking for enough appropriate links having been
2214          * installed into the torus to prevent an incorrect link from being
2215          * considered as a perpendicular candidate.
2216          */
2217         return safe_y_ring(t, i, j, k) && safe_z_ring(t, i, j, k);
2218 }
2219
2220 static
2221 bool safe_y_perpendicular(struct torus *t, int i, int j, int k)
2222 {
2223         /*
2224          * If the dimensions perpendicular to the search direction are
2225          * not radix 4 torus dimensions, it is always safe to search for
2226          * a perpendicular.
2227          *
2228          * Here we are checking for enough appropriate links having been
2229          * installed into the torus to prevent an incorrect link from being
2230          * considered as a perpendicular candidate.
2231          */
2232         return safe_x_ring(t, i, j, k) && safe_z_ring(t, i, j, k);
2233 }
2234
2235 static
2236 bool safe_z_perpendicular(struct torus *t, int i, int j, int k)
2237 {
2238         /*
2239          * If the dimensions perpendicular to the search direction are
2240          * not radix 4 torus dimensions, it is always safe to search for
2241          * a perpendicular.
2242          *
2243          * Implement this by checking for enough appropriate links having
2244          * been installed into the torus to prevent an incorrect link from
2245          * being considered as a perpendicular candidate.
2246          */
2247         return safe_x_ring(t, i, j, k) && safe_y_ring(t, i, j, k);
2248 }
2249
2250 /*
2251  * Templates for determining 2D/3D case fingerprints. Recall that if
2252  * a fingerprint bit is set the corresponding switch is absent from
2253  * the all-switches-present template.
2254  *
2255  * I.e., for the 2D case where the x,y dimensions have a radix greater
2256  * than one, and the z dimension has radix 1, fingerprint bits 4-7 are
2257  * always zero.
2258  *
2259  * For the 2D case where the x,z dimensions have a radix greater than
2260  * one, and the y dimension has radix 1, fingerprint bits 2,3,6,7 are
2261  * always zero.
2262  *
2263  * For the 2D case where the y,z dimensions have a radix greater than
2264  * one, and the x dimension has radix 1, fingerprint bits 1,3,5,7 are
2265  * always zero.
2266  *
2267  * Recall also that bits 8-10 distinguish between 2D and 3D cases.
2268  * If bit 8+d is set, for 0 <= d < 3;  the d dimension of the desired
2269  * torus has radix greater than 1.
2270  */
2271
2272 /*
2273  * 2D case 0x300
2274  *  b0: t->sw[i  ][j  ][0  ]
2275  *  b1: t->sw[i+1][j  ][0  ]
2276  *  b2: t->sw[i  ][j+1][0  ]
2277  *  b3: t->sw[i+1][j+1][0  ]
2278  *                                    O . . . . . O
2279  * 2D case 0x500                      .           .
2280  *  b0: t->sw[i  ][0  ][k  ]          .           .
2281  *  b1: t->sw[i+1][0  ][k  ]          .           .
2282  *  b4: t->sw[i  ][0  ][k+1]          .           .
2283  *  b5: t->sw[i+1][0  ][k+1]          .           .
2284  *                                    @ . . . . . O
2285  * 2D case 0x600
2286  *  b0: t->sw[0  ][j  ][k  ]
2287  *  b2: t->sw[0  ][j+1][k  ]
2288  *  b4: t->sw[0  ][j  ][k+1]
2289  *  b6: t->sw[0  ][j+1][k+1]
2290  */
2291
2292 /*
2293  * 3D case 0x700:                           O
2294  *                                        . . .
2295  *  b0: t->sw[i  ][j  ][k  ]            .   .   .
2296  *  b1: t->sw[i+1][j  ][k  ]          .     .     .
2297  *  b2: t->sw[i  ][j+1][k  ]        .       .       .
2298  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
2299  *  b4: t->sw[i  ][j  ][k+1]      . .       O       . .
2300  *  b5: t->sw[i+1][j  ][k+1]      .   .   .   .   .   .
2301  *  b6: t->sw[i  ][j+1][k+1]      .     .       .     .
2302  *  b7: t->sw[i+1][j+1][k+1]      .   .   .   .   .   .
2303  *                                . .       O       . .
2304  *                                O         .         O
2305  *                                  .       .       .
2306  *                                    .     .     .
2307  *                                      .   .   .
2308  *                                        . . .
2309  *                                          @
2310  */
2311
2312 static
2313 void log_no_crnr(struct torus *t, unsigned n,
2314                  int case_i, int case_j, int case_k,
2315                  int crnr_i, int crnr_j, int crnr_k)
2316 {
2317         if (t->debug)
2318                 OSM_LOG(&t->osm->log, OSM_LOG_INFO, "Case 0x%03x "
2319                         "@ %d %d %d: no corner @ %d %d %d\n",
2320                         n, case_i, case_j, case_k, crnr_i, crnr_j, crnr_k);
2321 }
2322
2323 static
2324 void log_no_perp(struct torus *t, unsigned n,
2325                  int case_i, int case_j, int case_k,
2326                  int perp_i, int perp_j, int perp_k)
2327 {
2328         if (t->debug)
2329                 OSM_LOG(&t->osm->log, OSM_LOG_INFO, "Case 0x%03x "
2330                         "@ %d %d %d: no perpendicular @ %d %d %d\n",
2331                         n, case_i, case_j, case_k, perp_i, perp_j, perp_k);
2332 }
2333
2334 /*
2335  * Handle the 2D cases with a single existing edge.
2336  *
2337  */
2338
2339 /*
2340  * 2D case 0x30c
2341  *  b0: t->sw[i  ][j  ][0  ]
2342  *  b1: t->sw[i+1][j  ][0  ]
2343  *  b2:
2344  *  b3:
2345  *                                    O           O
2346  * 2D case 0x530
2347  *  b0: t->sw[i  ][0  ][k  ]
2348  *  b1: t->sw[i+1][0  ][k  ]
2349  *  b4:
2350  *  b5:
2351  *                                    @ . . . . . O
2352  * 2D case 0x650
2353  *  b0: t->sw[0  ][j  ][k  ]
2354  *  b2: t->sw[0  ][j+1][k  ]
2355  *  b4:
2356  *  b6:
2357  */
2358 static
2359 bool handle_case_0x30c(struct torus *t, int i, int j, int k)
2360 {
2361         int ip1 = canonicalize(i + 1, t->x_sz);
2362         int jm1 = canonicalize(j - 1, t->y_sz);
2363         int jp1 = canonicalize(j + 1, t->y_sz);
2364
2365         if (safe_y_perpendicular(t, i, j, k) &&
2366             install_tswitch(t, i, jp1, k,
2367                             tfind_2d_perpendicular(t->sw[ip1][j][k],
2368                                                    t->sw[i][j][k],
2369                                                    t->sw[i][jm1][k]))) {
2370                 return true;
2371         }
2372         log_no_perp(t, 0x30c, i, j, k, i, j, k);
2373
2374         if (safe_y_perpendicular(t, ip1, j, k) &&
2375             install_tswitch(t, ip1, jp1, k,
2376                             tfind_2d_perpendicular(t->sw[i][j][k],
2377                                                    t->sw[ip1][j][k],
2378                                                    t->sw[ip1][jm1][k]))) {
2379                 return true;
2380         }
2381         log_no_perp(t, 0x30c, i, j, k, ip1, j, k);
2382         return false;
2383 }
2384
2385 static
2386 bool handle_case_0x530(struct torus *t, int i, int j, int k)
2387 {
2388         int ip1 = canonicalize(i + 1, t->x_sz);
2389         int km1 = canonicalize(k - 1, t->z_sz);
2390         int kp1 = canonicalize(k + 1, t->z_sz);
2391
2392         if (safe_z_perpendicular(t, i, j, k) &&
2393             install_tswitch(t, i, j, kp1,
2394                             tfind_2d_perpendicular(t->sw[ip1][j][k],
2395                                                    t->sw[i][j][k],
2396                                                    t->sw[i][j][km1]))) {
2397                 return true;
2398         }
2399         log_no_perp(t, 0x530, i, j, k, i, j, k);
2400
2401         if (safe_z_perpendicular(t, ip1, j, k) &&
2402               install_tswitch(t, ip1, j, kp1,
2403                               tfind_2d_perpendicular(t->sw[i][j][k],
2404                                                      t->sw[ip1][j][k],
2405                                                      t->sw[ip1][j][km1]))) {
2406                 return true;
2407         }
2408         log_no_perp(t, 0x530, i, j, k, ip1, j, k);
2409         return false;
2410 }
2411
2412 static
2413 bool handle_case_0x650(struct torus *t, int i, int j, int k)
2414 {
2415         int jp1 = canonicalize(j + 1, t->y_sz);
2416         int km1 = canonicalize(k - 1, t->z_sz);
2417         int kp1 = canonicalize(k + 1, t->z_sz);
2418
2419         if (safe_z_perpendicular(t, i, j, k) &&
2420             install_tswitch(t, i, j, kp1,
2421                             tfind_2d_perpendicular(t->sw[i][jp1][k],
2422                                                    t->sw[i][j][k],
2423                                                    t->sw[i][j][km1]))) {
2424                 return true;
2425         }
2426         log_no_perp(t, 0x650, i, j, k, i, j, k);
2427
2428         if (safe_z_perpendicular(t, i, jp1, k) &&
2429             install_tswitch(t, i, jp1, kp1,
2430                             tfind_2d_perpendicular(t->sw[i][j][k],
2431                                                    t->sw[i][jp1][k],
2432                                                    t->sw[i][jp1][km1]))) {
2433                 return true;
2434         }
2435         log_no_perp(t, 0x650, i, j, k, i, jp1, k);
2436         return false;
2437 }
2438
2439 /*
2440  * 2D case 0x305
2441  *  b0:
2442  *  b1: t->sw[i+1][j  ][0  ]
2443  *  b2:
2444  *  b3: t->sw[i+1][j+1][0  ]
2445  *                                    O           O
2446  * 2D case 0x511                                  .
2447  *  b0:                                           .
2448  *  b1: t->sw[i+1][0  ][k  ]                      .
2449  *  b4:                                           .
2450  *  b5: t->sw[i+1][0  ][k+1]                      .
2451  *                                    @           O
2452  * 2D case 0x611
2453  *  b0:
2454  *  b2: t->sw[0  ][j+1][k  ]
2455  *  b4:
2456  *  b6: t->sw[0  ][j+1][k+1]
2457  */
2458 static
2459 bool handle_case_0x305(struct torus *t, int i, int j, int k)
2460 {
2461         int ip1 = canonicalize(i + 1, t->x_sz);
2462         int ip2 = canonicalize(i + 2, t->x_sz);
2463         int jp1 = canonicalize(j + 1, t->y_sz);
2464
2465         if (safe_x_perpendicular(t, ip1, j, k) &&
2466             install_tswitch(t, i, j, k,
2467                             tfind_2d_perpendicular(t->sw[ip1][jp1][k],
2468                                                    t->sw[ip1][j][k],
2469                                                    t->sw[ip2][j][k]))) {
2470                 return true;
2471         }
2472         log_no_perp(t, 0x305, i, j, k, ip1, j, k);
2473
2474         if (safe_x_perpendicular(t, ip1, jp1, k) &&
2475             install_tswitch(t, i, jp1, k,
2476                             tfind_2d_perpendicular(t->sw[ip1][j][k],
2477                                                    t->sw[ip1][jp1][k],
2478                                                    t->sw[ip2][jp1][k]))) {
2479                 return true;
2480         }
2481         log_no_perp(t, 0x305, i, j, k, ip1, jp1, k);
2482         return false;
2483 }
2484
2485 static
2486 bool handle_case_0x511(struct torus *t, int i, int j, int k)
2487 {
2488         int ip1 = canonicalize(i + 1, t->x_sz);
2489         int ip2 = canonicalize(i + 2, t->x_sz);
2490         int kp1 = canonicalize(k + 1, t->z_sz);
2491
2492         if (safe_x_perpendicular(t, ip1, j, k) &&
2493             install_tswitch(t, i, j, k,
2494                             tfind_2d_perpendicular(t->sw[ip1][j][kp1],
2495                                                    t->sw[ip1][j][k],
2496                                                    t->sw[ip2][j][k]))) {
2497                 return true;
2498         }
2499         log_no_perp(t, 0x511, i, j, k, ip1, j, k);
2500
2501         if (safe_x_perpendicular(t, ip1, j, kp1) &&
2502             install_tswitch(t, i, j, kp1,
2503                             tfind_2d_perpendicular(t->sw[ip1][j][k],
2504                                                    t->sw[ip1][j][kp1],
2505                                                    t->sw[ip2][j][kp1]))) {
2506                 return true;
2507         }
2508         log_no_perp(t, 0x511, i, j, k, ip1, j, kp1);
2509         return false;
2510 }
2511
2512 static
2513 bool handle_case_0x611(struct torus *t, int i, int j, int k)
2514 {
2515         int jp1 = canonicalize(j + 1, t->y_sz);
2516         int jp2 = canonicalize(j + 2, t->y_sz);
2517         int kp1 = canonicalize(k + 1, t->z_sz);
2518
2519         if (safe_y_perpendicular(t, i, jp1, k) &&
2520             install_tswitch(t, i, j, k,
2521                             tfind_2d_perpendicular(t->sw[i][jp1][kp1],
2522                                                    t->sw[i][jp1][k],
2523                                                    t->sw[i][jp2][k]))) {
2524                 return true;
2525         }
2526         log_no_perp(t, 0x611, i, j, k, i, jp1, k);
2527
2528         if (safe_y_perpendicular(t, i, jp1, kp1) &&
2529             install_tswitch(t, i, j, kp1,
2530                             tfind_2d_perpendicular(t->sw[i][jp1][k],
2531                                                    t->sw[i][jp1][kp1],
2532                                                    t->sw[i][jp2][kp1]))) {
2533                 return true;
2534         }
2535         log_no_perp(t, 0x611, i, j, k, i, jp1, kp1);
2536         return false;
2537 }
2538
2539 /*
2540  * 2D case 0x303
2541  *  b0:
2542  *  b1:
2543  *  b2: t->sw[i  ][j+1][0  ]
2544  *  b3: t->sw[i+1][j+1][0  ]
2545  *                                    O . . . . . O
2546  * 2D case 0x503
2547  *  b0:
2548  *  b1:
2549  *  b4: t->sw[i  ][0  ][k+1]
2550  *  b5: t->sw[i+1][0  ][k+1]
2551  *                                    @           O
2552  * 2D case 0x605
2553  *  b0:
2554  *  b2:
2555  *  b4: t->sw[0  ][j  ][k+1]
2556  *  b6: t->sw[0  ][j+1][k+1]
2557  */
2558 static
2559 bool handle_case_0x303(struct torus *t, int i, int j, int k)
2560 {
2561         int ip1 = canonicalize(i + 1, t->x_sz);
2562         int jp1 = canonicalize(j + 1, t->y_sz);
2563         int jp2 = canonicalize(j + 2, t->y_sz);
2564
2565         if (safe_y_perpendicular(t, i, jp1, k) &&
2566             install_tswitch(t, i, j, k,
2567                             tfind_2d_perpendicular(t->sw[ip1][jp1][k],
2568                                                    t->sw[i][jp1][k],
2569                                                    t->sw[i][jp2][k]))) {
2570                 return true;
2571         }
2572         log_no_perp(t, 0x303, i, j, k, i, jp1, k);
2573
2574         if (safe_y_perpendicular(t, ip1, jp1, k) &&
2575             install_tswitch(t, ip1, j, k,
2576                             tfind_2d_perpendicular(t->sw[i][jp1][k],
2577                                                    t->sw[ip1][jp1][k],
2578                                                    t->sw[ip1][jp2][k]))) {
2579                 return true;
2580         }
2581         log_no_perp(t, 0x303, i, j, k, ip1, jp1, k);
2582         return false;
2583 }
2584
2585 static
2586 bool handle_case_0x503(struct torus *t, int i, int j, int k)
2587 {
2588         int ip1 = canonicalize(i + 1, t->x_sz);
2589         int kp1 = canonicalize(k + 1, t->z_sz);
2590         int kp2 = canonicalize(k + 2, t->z_sz);
2591
2592         if (safe_z_perpendicular(t, i, j, kp1) &&
2593             install_tswitch(t, i, j, k,
2594                             tfind_2d_perpendicular(t->sw[ip1][j][kp1],
2595                                                    t->sw[i][j][kp1],
2596                                                    t->sw[i][j][kp2]))) {
2597                 return true;
2598         }
2599         log_no_perp(t, 0x503, i, j, k, i, j, kp1);
2600
2601         if (safe_z_perpendicular(t, ip1, j, kp1) &&
2602             install_tswitch(t, ip1, j, k,
2603                             tfind_2d_perpendicular(t->sw[i][j][kp1],
2604                                                    t->sw[ip1][j][kp1],
2605                                                    t->sw[ip1][j][kp2]))) {
2606                 return true;
2607         }
2608         log_no_perp(t, 0x503, i, j, k, ip1, j, kp1);
2609         return false;
2610 }
2611
2612 static
2613 bool handle_case_0x605(struct torus *t, int i, int j, int k)
2614 {
2615         int jp1 = canonicalize(j + 1, t->y_sz);
2616         int kp1 = canonicalize(k + 1, t->z_sz);
2617         int kp2 = canonicalize(k + 2, t->z_sz);
2618
2619         if (safe_z_perpendicular(t, i, j, kp1) &&
2620             install_tswitch(t, i, j, k,
2621                             tfind_2d_perpendicular(t->sw[i][jp1][kp1],
2622                                                    t->sw[i][j][kp1],
2623                                                    t->sw[i][j][kp2]))) {
2624                 return true;
2625         }
2626         log_no_perp(t, 0x605, i, j, k, i, j, kp1);
2627
2628         if (safe_z_perpendicular(t, i, jp1, kp1) &&
2629             install_tswitch(t, i, jp1, k,
2630                             tfind_2d_perpendicular(t->sw[i][j][kp1],
2631                                                    t->sw[i][jp1][kp1],
2632                                                    t->sw[i][jp1][kp2]))) {
2633                 return true;
2634         }
2635         log_no_perp(t, 0x605, i, j, k, i, jp1, kp1);
2636         return false;
2637 }
2638
2639 /*
2640  * 2D case 0x30a
2641  *  b0: t->sw[i  ][j  ][0  ]
2642  *  b1:
2643  *  b2: t->sw[i  ][j+1][0  ]
2644  *  b3:
2645  *                                    O           O
2646  * 2D case 0x522                      .
2647  *  b0: t->sw[i  ][0  ][k  ]          .
2648  *  b1:                               .
2649  *  b4: t->sw[i  ][0  ][k+1]          .
2650  *  b5:                               .
2651  *                                    @           O
2652  * 2D case 0x644
2653  *  b0: t->sw[0  ][j  ][k  ]
2654  *  b2:
2655  *  b4: t->sw[0  ][j  ][k+1]
2656  *  b6:
2657  */
2658 static
2659 bool handle_case_0x30a(struct torus *t, int i, int j, int k)
2660 {
2661         int im1 = canonicalize(i - 1, t->x_sz);
2662         int ip1 = canonicalize(i + 1, t->x_sz);
2663         int jp1 = canonicalize(j + 1, t->y_sz);
2664
2665         if (safe_x_perpendicular(t, i, j, k) &&
2666             install_tswitch(t, ip1, j, k,
2667                             tfind_2d_perpendicular(t->sw[i][jp1][k],
2668                                                    t->sw[i][j][k],
2669                                                    t->sw[im1][j][k]))) {
2670                 return true;
2671         }
2672         log_no_perp(t, 0x30a, i, j, k, i, j, k);
2673
2674         if (safe_x_perpendicular(t, i, jp1, k) &&
2675             install_tswitch(t, ip1, jp1, k,
2676                             tfind_2d_perpendicular(t->sw[i][j][k],
2677                                                    t->sw[i][jp1][k],
2678                                                    t->sw[im1][jp1][k]))) {
2679                 return true;
2680         }
2681         log_no_perp(t, 0x30a, i, j, k, i, jp1, k);
2682         return false;
2683 }
2684
2685 static
2686 bool handle_case_0x522(struct torus *t, int i, int j, int k)
2687 {
2688         int im1 = canonicalize(i - 1, t->x_sz);
2689         int ip1 = canonicalize(i + 1, t->x_sz);
2690         int kp1 = canonicalize(k + 1, t->z_sz);
2691
2692         if (safe_x_perpendicular(t, i, j, k) &&
2693             install_tswitch(t, ip1, j, k,
2694                             tfind_2d_perpendicular(t->sw[i][j][kp1],
2695                                                    t->sw[i][j][k],
2696                                                    t->sw[im1][j][k]))) {
2697                 return true;
2698         }
2699         log_no_perp(t, 0x522, i, j, k, i, j, k);
2700
2701         if (safe_x_perpendicular(t, i, j, kp1) &&
2702             install_tswitch(t, ip1, j, kp1,
2703                             tfind_2d_perpendicular(t->sw[i][j][k],
2704                                                    t->sw[i][j][kp1],
2705                                                    t->sw[im1][j][kp1]))) {
2706                 return true;
2707         }
2708         log_no_perp(t, 0x522, i, j, k, i, j, kp1);
2709         return false;
2710 }
2711
2712 static
2713 bool handle_case_0x644(struct torus *t, int i, int j, int k)
2714 {
2715         int jm1 = canonicalize(j - 1, t->y_sz);
2716         int jp1 = canonicalize(j + 1, t->y_sz);
2717         int kp1 = canonicalize(k + 1, t->z_sz);
2718
2719         if (safe_y_perpendicular(t, i, j, k) &&
2720             install_tswitch(t, i, jp1, k,
2721                             tfind_2d_perpendicular(t->sw[i][j][kp1],
2722                                                    t->sw[i][j][k],
2723                                                    t->sw[i][jm1][k]))) {
2724                 return true;
2725         }
2726         log_no_perp(t, 0x644, i, j, k, i, j, k);
2727
2728         if (safe_y_perpendicular(t, i, j, kp1) &&
2729             install_tswitch(t, i, jp1, kp1,
2730                             tfind_2d_perpendicular(t->sw[i][j][k],
2731                                                    t->sw[i][j][kp1],
2732                                                    t->sw[i][jm1][kp1]))) {
2733                 return true;
2734         }
2735         log_no_perp(t, 0x644, i, j, k, i, j, kp1);
2736         return false;
2737 }
2738
2739 /*
2740  * Handle the 2D cases where two existing edges meet at a corner.
2741  *
2742  */
2743
2744 /*
2745  * 2D case 0x301
2746  *  b0:
2747  *  b1: t->sw[i+1][j  ][0  ]
2748  *  b2: t->sw[i  ][j+1][0  ]
2749  *  b3: t->sw[i+1][j+1][0  ]
2750  *                                    O . . . . . O
2751  * 2D case 0x501                                  .
2752  *  b0:                                           .
2753  *  b1: t->sw[i+1][0  ][k  ]                      .
2754  *  b4: t->sw[i  ][0  ][k+1]                      .
2755  *  b5: t->sw[i+1][0  ][k+1]                      .
2756  *                                    @           O
2757  * 2D case 0x601
2758  *  b0:
2759  *  b2: t->sw[0  ][j+1][k  ]
2760  *  b4: t->sw[0  ][j  ][k+1]
2761  *  b6: t->sw[0  ][j+1][k+1]
2762  */
2763 static
2764 bool handle_case_0x301(struct torus *t, int i, int j, int k)
2765 {
2766         int ip1 = canonicalize(i + 1, t->x_sz);
2767         int jp1 = canonicalize(j + 1, t->y_sz);
2768
2769         if (install_tswitch(t, i, j, k,
2770                             tfind_face_corner(t->sw[ip1][j][k],
2771                                               t->sw[ip1][jp1][k],
2772                                               t->sw[i][jp1][k]))) {
2773                 return true;
2774         }
2775         log_no_crnr(t, 0x301, i, j, k, i, j, k);
2776         return false;
2777 }
2778
2779 static
2780 bool handle_case_0x501(struct torus *t, int i, int j, int k)
2781 {
2782         int ip1 = canonicalize(i + 1, t->x_sz);
2783         int kp1 = canonicalize(k + 1, t->z_sz);
2784
2785         if (install_tswitch(t, i, j, k,
2786                             tfind_face_corner(t->sw[ip1][j][k],
2787                                               t->sw[ip1][j][kp1],
2788                                               t->sw[i][j][kp1]))) {
2789                 return true;
2790         }
2791         log_no_crnr(t, 0x501, i, j, k, i, j, k);
2792         return false;
2793 }
2794
2795 static
2796 bool handle_case_0x601(struct torus *t, int i, int j, int k)
2797 {
2798         int jp1 = canonicalize(j + 1, t->y_sz);
2799         int kp1 = canonicalize(k + 1, t->z_sz);
2800
2801         if (install_tswitch(t, i, j, k,
2802                             tfind_face_corner(t->sw[i][jp1][k],
2803                                               t->sw[i][jp1][kp1],
2804                                               t->sw[i][j][kp1]))) {
2805                 return true;
2806         }
2807         log_no_crnr(t, 0x601, i, j, k, i, j, k);
2808         return false;
2809 }
2810
2811 /*
2812  * 2D case 0x302
2813  *  b0: t->sw[i  ][j  ][0  ]
2814  *  b1:
2815  *  b2: t->sw[i  ][j+1][0  ]
2816  *  b3: t->sw[i+1][j+1][0  ]
2817  *                                    O . . . . . O
2818  * 2D case 0x502                      .
2819  *  b0: t->sw[i  ][0  ][k  ]          .
2820  *  b1:                               .
2821  *  b4: t->sw[i  ][0  ][k+1]          .
2822  *  b5: t->sw[i+1][0  ][k+1]          .
2823  *                                    @           O
2824  * 2D case 0x604
2825  *  b0: t->sw[0  ][j  ][k  ]
2826  *  b2:
2827  *  b4: t->sw[0  ][j  ][k+1]
2828  *  b6: t->sw[0  ][j+1][k+1]
2829  */
2830 static
2831 bool handle_case_0x302(struct torus *t, int i, int j, int k)
2832 {
2833         int ip1 = canonicalize(i + 1, t->x_sz);
2834         int jp1 = canonicalize(j + 1, t->y_sz);
2835
2836         if (install_tswitch(t, ip1, j, k,
2837                             tfind_face_corner(t->sw[i][j][k],
2838                                               t->sw[i][jp1][k],
2839                                               t->sw[ip1][jp1][k]))) {
2840                 return true;
2841         }
2842         log_no_crnr(t, 0x302, i, j, k, ip1, j, k);
2843         return false;
2844 }
2845
2846 static
2847 bool handle_case_0x502(struct torus *t, int i, int j, int k)
2848 {
2849         int ip1 = canonicalize(i + 1, t->x_sz);
2850         int kp1 = canonicalize(k + 1, t->z_sz);
2851
2852         if (install_tswitch(t, ip1, j, k,
2853                             tfind_face_corner(t->sw[i][j][k],
2854                                               t->sw[i][j][kp1],
2855                                               t->sw[ip1][j][kp1]))) {
2856                 return true;
2857         }
2858         log_no_crnr(t, 0x502, i, j, k, ip1, j, k);
2859         return false;
2860 }
2861
2862 static
2863 bool handle_case_0x604(struct torus *t, int i, int j, int k)
2864 {
2865         int jp1 = canonicalize(j + 1, t->y_sz);
2866         int kp1 = canonicalize(k + 1, t->z_sz);
2867
2868         if (install_tswitch(t, i, jp1, k,
2869                             tfind_face_corner(t->sw[i][j][k],
2870                                               t->sw[i][j][kp1],
2871                                               t->sw[i][jp1][kp1]))) {
2872                 return true;
2873         }
2874         log_no_crnr(t, 0x604, i, j, k, i, jp1, k);
2875         return false;
2876 }
2877
2878
2879 /*
2880  * 2D case 0x308
2881  *  b0: t->sw[i  ][j  ][0  ]
2882  *  b1: t->sw[i+1][j  ][0  ]
2883  *  b2: t->sw[i  ][j+1][0  ]
2884  *  b3:
2885  *                                    O           O
2886  * 2D case 0x520                      .
2887  *  b0: t->sw[i  ][0  ][k  ]          .
2888  *  b1: t->sw[i+1][0  ][k  ]          .
2889  *  b4: t->sw[i  ][0  ][k+1]          .
2890  *  b5:                               .
2891  *                                    @ . . . . . O
2892  * 2D case 0x640
2893  *  b0: t->sw[0  ][j  ][k  ]
2894  *  b2: t->sw[0  ][j+1][k  ]
2895  *  b4: t->sw[0  ][j  ][k+1]
2896  *  b6:
2897  */
2898 static
2899 bool handle_case_0x308(struct torus *t, int i, int j, int k)
2900 {
2901         int ip1 = canonicalize(i + 1, t->x_sz);
2902         int jp1 = canonicalize(j + 1, t->y_sz);
2903
2904         if (install_tswitch(t, ip1, jp1, k,
2905                             tfind_face_corner(t->sw[ip1][j][k],
2906                                               t->sw[i][j][k],
2907                                               t->sw[i][jp1][k]))) {
2908                 return true;
2909         }
2910         log_no_crnr(t, 0x308, i, j, k, ip1, jp1, k);
2911         return false;
2912 }
2913
2914 static
2915 bool handle_case_0x520(struct torus *t, int i, int j, int k)
2916 {
2917         int ip1 = canonicalize(i + 1, t->x_sz);
2918         int kp1 = canonicalize(k + 1, t->z_sz);
2919
2920         if (install_tswitch(t, ip1, j, kp1,
2921                             tfind_face_corner(t->sw[ip1][j][k],
2922                                               t->sw[i][j][k],
2923                                               t->sw[i][j][kp1]))) {
2924                 return true;
2925         }
2926         log_no_crnr(t, 0x520, i, j, k, ip1, j, kp1);
2927         return false;
2928 }
2929
2930 static
2931 bool handle_case_0x640(struct torus *t, int i, int j, int k)
2932 {
2933         int jp1 = canonicalize(j + 1, t->y_sz);
2934         int kp1 = canonicalize(k + 1, t->z_sz);
2935
2936         if (install_tswitch(t, i, jp1, kp1,
2937                             tfind_face_corner(t->sw[i][jp1][k],
2938                                               t->sw[i][j][k],
2939                                               t->sw[i][j][kp1]))) {
2940                 return true;
2941         }
2942         log_no_crnr(t, 0x640, i, j, k, i, jp1, kp1);
2943         return false;
2944 }
2945
2946 /*
2947  * 2D case 0x304
2948  *  b0: t->sw[i  ][j  ][0  ]
2949  *  b1: t->sw[i+1][j  ][0  ]
2950  *  b2:
2951  *  b3: t->sw[i+1][j+1][0  ]
2952  *                                    O           O
2953  * 2D case 0x510                                  .
2954  *  b0: t->sw[i  ][0  ][k  ]                      .
2955  *  b1: t->sw[i+1][0  ][k  ]                      .
2956  *  b4:                                           .
2957  *  b5: t->sw[i+1][0  ][k+1]                      .
2958  *                                    @ . . . . . O
2959  * 2D case 0x610
2960  *  b0: t->sw[0  ][j  ][k  ]
2961  *  b2: t->sw[0  ][j+1][k  ]
2962  *  b4:
2963  *  b6: t->sw[0  ][j+1][k+1]
2964  */
2965 static
2966 bool handle_case_0x304(struct torus *t, int i, int j, int k)
2967 {
2968         int ip1 = canonicalize(i + 1, t->x_sz);
2969         int jp1 = canonicalize(j + 1, t->y_sz);
2970
2971         if (install_tswitch(t, i, jp1, k,
2972                             tfind_face_corner(t->sw[i][j][k],
2973                                               t->sw[ip1][j][k],
2974                                               t->sw[ip1][jp1][k]))) {
2975                 return true;
2976         }
2977         log_no_crnr(t, 0x304, i, j, k, i, jp1, k);
2978         return false;
2979 }
2980
2981 static
2982 bool handle_case_0x510(struct torus *t, int i, int j, int k)
2983 {
2984         int ip1 = canonicalize(i + 1, t->x_sz);
2985         int kp1 = canonicalize(k + 1, t->z_sz);
2986
2987         if (install_tswitch(t, i, j, kp1,
2988                             tfind_face_corner(t->sw[i][j][k],
2989                                               t->sw[ip1][j][k],
2990                                               t->sw[ip1][j][kp1]))) {
2991                 return true;
2992         }
2993         log_no_crnr(t, 0x510, i, j, k, i, j, kp1);
2994         return false;
2995 }
2996
2997 static
2998 bool handle_case_0x610(struct torus *t, int i, int j, int k)
2999 {
3000         int jp1 = canonicalize(j + 1, t->y_sz);
3001         int kp1 = canonicalize(k + 1, t->z_sz);
3002
3003         if (install_tswitch(t, i, j, kp1,
3004                             tfind_face_corner(t->sw[i][j][k],
3005                                               t->sw[i][jp1][k],
3006                                               t->sw[i][jp1][kp1]))) {
3007                 return true;
3008         }
3009         log_no_crnr(t, 0x610, i, j, k, i, j, kp1);
3010         return false;
3011 }
3012
3013 /*
3014  * Handle the 3D cases where two existing edges meet at a corner.
3015  *
3016  */
3017
3018 /*
3019  * 3D case 0x71f:                           O
3020  *                                        .   .
3021  *  b0:                                 .       .
3022  *  b1:                               .           .
3023  *  b2:                             .               .
3024  *  b3:                           O                   O
3025  *  b4:                                     O
3026  *  b5: t->sw[i+1][j  ][k+1]
3027  *  b6: t->sw[i  ][j+1][k+1]
3028  *  b7: t->sw[i+1][j+1][k+1]
3029  *                                          O
3030  *                                O                   O
3031  *
3032  *
3033  *
3034  *
3035  *                                          @
3036  */
3037 static
3038 bool handle_case_0x71f(struct torus *t, int i, int j, int k)
3039 {
3040         int ip1 = canonicalize(i + 1, t->x_sz);
3041         int jp1 = canonicalize(j + 1, t->y_sz);
3042         int kp1 = canonicalize(k + 1, t->z_sz);
3043         int kp2 = canonicalize(k + 2, t->z_sz);
3044
3045         if (safe_z_perpendicular(t, ip1, jp1, kp1) &&
3046             install_tswitch(t, ip1, jp1, k,
3047                             tfind_3d_perpendicular(t->sw[ip1][j][kp1],
3048                                                    t->sw[ip1][jp1][kp1],
3049                                                    t->sw[i][jp1][kp1],
3050                                                    t->sw[ip1][jp1][kp2]))) {
3051                 return true;
3052         }
3053         log_no_perp(t, 0x71f, i, j, k, ip1, jp1, kp1);
3054         return false;
3055 }
3056
3057 /*
3058  * 3D case 0x72f:                           O
3059  *                                        .
3060  *  b0:                                 .
3061  *  b1:                               .
3062  *  b2:                             .
3063  *  b3:                           O                   O
3064  *  b4: t->sw[i  ][j  ][k+1]        .       O
3065  *  b5:                               .
3066  *  b6: t->sw[i  ][j+1][k+1]            .
3067  *  b7: t->sw[i+1][j+1][k+1]              .
3068  *                                          O
3069  *                                O                   O
3070  *
3071  *
3072  *
3073  *
3074  *                                          @
3075  */
3076 static
3077 bool handle_case_0x72f(struct torus *t, int i, int j, int k)
3078 {
3079         int ip1 = canonicalize(i + 1, t->x_sz);
3080         int jp1 = canonicalize(j + 1, t->y_sz);
3081         int kp1 = canonicalize(k + 1, t->z_sz);
3082         int kp2 = canonicalize(k + 2, t->z_sz);
3083
3084         if (safe_z_perpendicular(t, i, jp1, kp1) &&
3085             install_tswitch(t, i, jp1, k,
3086                             tfind_3d_perpendicular(t->sw[i][j][kp1],
3087                                                    t->sw[i][jp1][kp1],
3088                                                    t->sw[ip1][jp1][kp1],
3089                                                    t->sw[i][jp1][kp2]))) {
3090                 return true;
3091         }
3092         log_no_perp(t, 0x72f, i, j, k, i, jp1, kp1);
3093         return false;
3094 }
3095
3096 /*
3097  * 3D case 0x737:                           O
3098  *                                        . .
3099  *  b0:                                 .   .
3100  *  b1:                               .     .
3101  *  b2:                             .       .
3102  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
3103  *  b4:                                     O
3104  *  b5:
3105  *  b6: t->sw[i  ][j+1][k+1]
3106  *  b7: t->sw[i+1][j+1][k+1]
3107  *                                          O
3108  *                                O                   O
3109  *
3110  *
3111  *
3112  *
3113  *                                          @
3114  */
3115 static
3116 bool handle_case_0x737(struct torus *t, int i, int j, int k)
3117 {
3118         int ip1 = canonicalize(i + 1, t->x_sz);
3119         int jp1 = canonicalize(j + 1, t->y_sz);
3120         int jp2 = canonicalize(j + 2, t->y_sz);
3121         int kp1 = canonicalize(k + 1, t->z_sz);
3122
3123         if (safe_y_perpendicular(t, ip1, jp1, kp1) &&
3124             install_tswitch(t, ip1, j, kp1,
3125                             tfind_3d_perpendicular(t->sw[i][jp1][kp1],
3126                                                    t->sw[ip1][jp1][kp1],
3127                                                    t->sw[ip1][jp1][k],
3128                                                    t->sw[ip1][jp2][kp1]))) {
3129                 return true;
3130         }
3131         log_no_perp(t, 0x737, i, j, k, ip1, jp1, kp1);
3132         return false;
3133 }
3134
3135 /*
3136  * 3D case 0x73b:                           O
3137  *                                        .
3138  *  b0:                                 .
3139  *  b1:                               .
3140  *  b2: t->sw[i  ][j+1][k  ]        .
3141  *  b3:                           O                   O
3142  *  b4:                           .         O
3143  *  b5:                           .
3144  *  b6: t->sw[i  ][j+1][k+1]      .
3145  *  b7: t->sw[i+1][j+1][k+1]      .
3146  *                                .         O
3147  *                                O                   O
3148  *
3149  *
3150  *
3151  *
3152  *                                          @
3153  */
3154 static
3155 bool handle_case_0x73b(struct torus *t, int i, int j, int k)
3156 {
3157         int ip1 = canonicalize(i + 1, t->x_sz);
3158         int jp1 = canonicalize(j + 1, t->y_sz);
3159         int jp2 = canonicalize(j + 2, t->y_sz);
3160         int kp1 = canonicalize(k + 1, t->z_sz);
3161
3162         if (safe_y_perpendicular(t, i, jp1, kp1) &&
3163             install_tswitch(t, i, j, kp1,
3164                             tfind_3d_perpendicular(t->sw[i][jp1][k],
3165                                                    t->sw[i][jp1][kp1],
3166                                                    t->sw[ip1][jp1][kp1],
3167                                                    t->sw[i][jp2][kp1]))) {
3168                 return true;
3169         }
3170         log_no_perp(t, 0x73b, i, j, k, i, jp1, kp1);
3171         return false;
3172 }
3173
3174 /*
3175  * 3D case 0x74f:                           O
3176  *                                            .
3177  *  b0:                                         .
3178  *  b1:                                           .
3179  *  b2:                                             .
3180  *  b3:                           O                   O
3181  *  b4: t->sw[i  ][j  ][k+1]                O       .
3182  *  b5: t->sw[i+1][j  ][k+1]                      .
3183  *  b6:                                         .
3184  *  b7: t->sw[i+1][j+1][k+1]                  .
3185  *                                          O
3186  *                                O                   O
3187  *
3188  *
3189  *
3190  *
3191  *                                          @
3192  */
3193 static
3194 bool handle_case_0x74f(struct torus *t, int i, int j, int k)
3195 {
3196         int ip1 = canonicalize(i + 1, t->x_sz);
3197         int jp1 = canonicalize(j + 1, t->y_sz);
3198         int kp1 = canonicalize(k + 1, t->z_sz);
3199         int kp2 = canonicalize(k + 2, t->z_sz);
3200
3201         if (safe_z_perpendicular(t, ip1, j, kp1) &&
3202             install_tswitch(t, ip1, j, k,
3203                             tfind_3d_perpendicular(t->sw[i][j][kp1],
3204                                                    t->sw[ip1][j][kp1],
3205                                                    t->sw[ip1][jp1][kp1],
3206                                                    t->sw[ip1][j][kp2]))) {
3207                 return true;
3208         }
3209         log_no_perp(t, 0x74f, i, j, k, ip1, j, kp1);
3210         return false;
3211 }
3212
3213 /*
3214  * 3D case 0x757:                           O
3215  *                                          . .
3216  *  b0:                                     .   .
3217  *  b1:                                     .     .
3218  *  b2:                                     .       .
3219  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
3220  *  b4:                                     O
3221  *  b5: t->sw[i+1][j  ][k+1]
3222  *  b6:
3223  *  b7: t->sw[i+1][j+1][k+1]
3224  *                                          O
3225  *                                O                   O
3226  *
3227  *
3228  *
3229  *
3230  *                                          @
3231  */
3232 static
3233 bool handle_case_0x757(struct torus *t, int i, int j, int k)
3234 {
3235         int ip1 = canonicalize(i + 1, t->x_sz);
3236         int ip2 = canonicalize(i + 2, t->x_sz);
3237         int jp1 = canonicalize(j + 1, t->y_sz);
3238         int kp1 = canonicalize(k + 1, t->z_sz);
3239
3240         if (safe_x_perpendicular(t, ip1, jp1, kp1) &&
3241             install_tswitch(t, i, jp1, kp1,
3242                             tfind_3d_perpendicular(t->sw[ip1][j][kp1],
3243                                                    t->sw[ip1][jp1][kp1],
3244                                                    t->sw[ip1][jp1][k],
3245                                                    t->sw[ip2][jp1][kp1]))) {
3246                 return true;
3247         }
3248         log_no_perp(t, 0x757, i, j, k, ip1, jp1, kp1);
3249         return false;
3250 }
3251
3252 /*
3253  * 3D case 0x75d:                           O
3254  *                                            .
3255  *  b0:                                         .
3256  *  b1: t->sw[i+1][j  ][k  ]                      .
3257  *  b2:                                             .
3258  *  b3:                           O                   O
3259  *  b4:                                     O         .
3260  *  b5: t->sw[i+1][j  ][k+1]                          .
3261  *  b6:                                               .
3262  *  b7: t->sw[i+1][j+1][k+1]                          .
3263  *                                          O         .
3264  *                                O                   O
3265  *
3266  *
3267  *
3268  *
3269  *                                          @
3270  */
3271 static
3272 bool handle_case_0x75d(struct torus *t, int i, int j, int k)
3273 {
3274         int ip1 = canonicalize(i + 1, t->x_sz);
3275         int ip2 = canonicalize(i + 2, t->x_sz);
3276         int jp1 = canonicalize(j + 1, t->y_sz);
3277         int kp1 = canonicalize(k + 1, t->z_sz);
3278
3279         if (safe_x_perpendicular(t, ip1, j, kp1) &&
3280             install_tswitch(t, i, j, kp1,
3281                             tfind_3d_perpendicular(t->sw[ip1][j][k],
3282                                                    t->sw[ip1][j][kp1],
3283                                                    t->sw[ip1][jp1][kp1],
3284                                                    t->sw[ip2][j][kp1]))) {
3285                 return true;
3286         }
3287         log_no_perp(t, 0x75d, i, j, k, ip1, j, kp1);
3288         return false;
3289 }
3290
3291 /*
3292  * 3D case 0x773:                           O
3293  *                                          .
3294  *  b0:                                     .
3295  *  b1:                                     .
3296  *  b2: t->sw[i  ][j+1][k  ]                .
3297  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
3298  *  b4:                                     O
3299  *  b5:                                   .
3300  *  b6:                                 .
3301  *  b7: t->sw[i+1][j+1][k+1]          .
3302  *                                  .       O
3303  *                                O                   O
3304  *
3305  *
3306  *
3307  *
3308  *                                          @
3309  */
3310 static
3311 bool handle_case_0x773(struct torus *t, int i, int j, int k)
3312 {
3313         int ip1 = canonicalize(i + 1, t->x_sz);
3314         int jp1 = canonicalize(j + 1, t->y_sz);
3315         int jp2 = canonicalize(j + 2, t->y_sz);
3316         int kp1 = canonicalize(k + 1, t->z_sz);
3317
3318         if (safe_y_perpendicular(t, ip1, jp1, k) &&
3319             install_tswitch(t, ip1, j, k,
3320                             tfind_3d_perpendicular(t->sw[i][jp1][k],
3321                                                    t->sw[ip1][jp1][k],
3322                                                    t->sw[ip1][jp1][kp1],
3323                                                    t->sw[ip1][jp2][k]))) {
3324                 return true;
3325         }
3326         log_no_perp(t, 0x773, i, j, k, ip1, jp1, k);
3327         return false;
3328 }
3329
3330 /*
3331  * 3D case 0x775:                           O
3332  *                                          .
3333  *  b0:                                     .
3334  *  b1: t->sw[i+1][j  ][k  ]                .
3335  *  b2:                                     .
3336  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
3337  *  b4:                                     O
3338  *  b5:                                       .
3339  *  b6:                                         .
3340  *  b7: t->sw[i+1][j+1][k+1]                      .
3341  *                                          O       .
3342  *                                O                   O
3343  *
3344  *
3345  *
3346  *
3347  *                                          @
3348  */
3349 static
3350 bool handle_case_0x775(struct torus *t, int i, int j, int k)
3351 {
3352         int ip1 = canonicalize(i + 1, t->x_sz);
3353         int ip2 = canonicalize(i + 2, t->x_sz);
3354         int jp1 = canonicalize(j + 1, t->y_sz);
3355         int kp1 = canonicalize(k + 1, t->z_sz);
3356
3357         if (safe_x_perpendicular(t, ip1, jp1, k) &&
3358             install_tswitch(t, i, jp1, k,
3359                             tfind_3d_perpendicular(t->sw[ip1][j][k],
3360                                                    t->sw[ip1][jp1][k],
3361                                                    t->sw[ip1][jp1][kp1],
3362                                                    t->sw[ip2][jp1][k]))) {
3363                 return true;
3364         }
3365         log_no_perp(t, 0x775, i, j, k, ip1, jp1, k);
3366         return false;
3367 }
3368
3369 /*
3370  * 3D case 0x78f:                           O
3371  *
3372  *  b0:
3373  *  b1:
3374  *  b2:
3375  *  b3:                           O                   O
3376  *  b4: t->sw[i  ][j  ][k+1]        .       O       .
3377  *  b5: t->sw[i+1][j  ][k+1]          .           .
3378  *  b6: t->sw[i  ][j+1][k+1]            .       .
3379  *  b7:                                   .   .
3380  *                                          O
3381  *                                O                   O
3382  *
3383  *
3384  *
3385  *
3386  *                                          @
3387  */
3388 static
3389 bool handle_case_0x78f(struct torus *t, int i, int j, int k)
3390 {
3391         int ip1 = canonicalize(i + 1, t->x_sz);
3392         int jp1 = canonicalize(j + 1, t->y_sz);
3393         int kp1 = canonicalize(k + 1, t->z_sz);
3394         int kp2 = canonicalize(k + 2, t->z_sz);
3395
3396         if (safe_z_perpendicular(t, i, j, kp1) &&
3397             install_tswitch(t, i, j, k,
3398                             tfind_3d_perpendicular(t->sw[ip1][j][kp1],
3399                                                    t->sw[i][j][kp1],
3400                                                    t->sw[i][jp1][kp1],
3401                                                    t->sw[i][j][kp2]))) {
3402                 return true;
3403         }
3404         log_no_perp(t, 0x78f, i, j, k, i, j, kp1);
3405         return false;
3406 }
3407
3408 /*
3409  * 3D case 0x7ab:                           O
3410  *
3411  *  b0:
3412  *  b1:
3413  *  b2: t->sw[i  ][j+1][k  ]
3414  *  b3:                           O                   O
3415  *  b4: t->sw[i  ][j  ][k+1]      . .       O
3416  *  b5:                           .   .
3417  *  b6: t->sw[i  ][j+1][k+1]      .     .
3418  *  b7:                           .       .
3419  *                                .         O
3420  *                                O                   O
3421  *
3422  *
3423  *
3424  *
3425  *                                          @
3426  */
3427 static
3428 bool handle_case_0x7ab(struct torus *t, int i, int j, int k)
3429 {
3430         int im1 = canonicalize(i - 1, t->x_sz);
3431         int ip1 = canonicalize(i + 1, t->x_sz);
3432         int jp1 = canonicalize(j + 1, t->y_sz);
3433         int kp1 = canonicalize(k + 1, t->z_sz);
3434
3435         if (safe_x_perpendicular(t, i, jp1, kp1) &&
3436             install_tswitch(t, ip1, jp1, kp1,
3437                             tfind_3d_perpendicular(t->sw[i][j][kp1],
3438                                                    t->sw[i][jp1][kp1],
3439                                                    t->sw[i][jp1][k],
3440                                                    t->sw[im1][jp1][kp1]))) {
3441                 return true;
3442         }
3443         log_no_perp(t, 0x7ab, i, j, k, i, jp1, kp1);
3444         return false;
3445 }
3446
3447 /*
3448  * 3D case 0x7ae:                           O
3449  *
3450  *  b0: t->sw[i  ][j  ][k  ]
3451  *  b1:
3452  *  b2:
3453  *  b3:                           O                   O
3454  *  b4: t->sw[i  ][j  ][k+1]        .       O
3455  *  b5:                               .
3456  *  b6: t->sw[i  ][j+1][k+1]            .
3457  *  b7:                                   .
3458  *                                          O
3459  *                                O         .         O
3460  *                                          .
3461  *                                          .
3462  *                                          .
3463  *                                          .
3464  *                                          @
3465  */
3466 static
3467 bool handle_case_0x7ae(struct torus *t, int i, int j, int k)
3468 {
3469         int im1 = canonicalize(i - 1, t->x_sz);
3470         int ip1 = canonicalize(i + 1, t->x_sz);
3471         int jp1 = canonicalize(j + 1, t->y_sz);
3472         int kp1 = canonicalize(k + 1, t->z_sz);
3473
3474         if (safe_x_perpendicular(t, i, j, kp1) &&
3475             install_tswitch(t, ip1, j, kp1,
3476                             tfind_3d_perpendicular(t->sw[i][j][k],
3477                                                    t->sw[i][j][kp1],
3478                                                    t->sw[i][jp1][kp1],
3479                                                    t->sw[im1][j][kp1]))) {
3480                 return true;
3481         }
3482         log_no_perp(t, 0x7ae, i, j, k, i, j, kp1);
3483         return false;
3484 }
3485
3486 /*
3487  * 3D case 0x7b3:                           O
3488  *
3489  *  b0:
3490  *  b1:
3491  *  b2: t->sw[i  ][j+1][k  ]
3492  *  b3: t->sw[i+1][j+1][k  ]      O                   O
3493  *  b4:                           .         O
3494  *  b5:                           .       .
3495  *  b6: t->sw[i  ][j+1][k+1]      .     .
3496  *  b7:                           .   .
3497  *                                . .       O
3498  *                                O                   O
3499  *
3500  *
3501  *
3502  *
3503  *                                          @
3504  */
3505 static
3506 bool handle_case_0x7b3(struct torus *t, int i, int j, int k)
3507 {
3508         int ip1 = canonicalize(i + 1, t->x_sz);
3509         int jp1 = canonicalize(j + 1, t->y_sz);
3510         int jp2 = canonicalize(j + 2, t->y_sz);
3511         int kp1 = canonicalize(k + 1, t->z_sz);
3512
3513         if (safe_y_perpendicular(t, i, jp1, k) &&
3514             install_tswitch(t, i, j, k,
3515                             tfind_3d_perpendicular(t->sw[i][jp1][kp1],
3516                                                    t->sw[i][jp1][k],
3517                                                    t->sw[ip1][jp1][k],
3518                                                    t->sw[i][jp2][k]))) {
3519                 return true;
3520         }
3521         log_no_perp(t, 0x7b3, i, j, k, i, jp1, k);
3522         return false;
3523 }
3524
3525 /*
3526  * 3D case 0x7ba:                           O
3527  *
3528  *  b0: t->sw[i  ][j  ][k  ]
3529  *  b1:
3530  *  b2: t->sw[i  ][j+1][k  ]
3531  *  b3:                           O                   O
3532  *  b4:                           .         O
3533  *  b5:                           .
3534  *  b6: t->sw[i  ][j+1][k+1]      .
3535  *  b7:                           .
3536  *                                .         O
3537  *                                O                   O
3538  *                                  .
3539  *                                    .
3540  *                                      .
3541  *                                        .
3542  *                                          @
3543  */
3544 static
3545 bool handle_case_0x7ba(struct torus *t, int i, int j, int k)
3546 {
3547         int im1 = canonicalize(i - 1, t->x_sz);
3548         int ip1 = canonicalize(i + 1, t->x_sz);
3549         int jp1 = canonicalize(j + 1, t->y_sz);
3550         int kp1 = canonicalize(k + 1, t->z_sz);
3551
3552         if (safe_x_perpendicular(t, i, jp1, k) &&
3553             install_tswitch(t, ip1, jp1, k,
3554                             tfind_3d_perpendicular(t->sw[i][j][k],
3555                                                    t->sw[i][jp1][k],
3556                                                    t->sw[i][jp1][kp1],
3557                                                    t->sw[im1][jp1][k]))) {
3558                 return true;
3559         }
3560         log_no_perp(t, 0x7ba, i, j, k, i, jp1, k);
3561         return false;
3562 }
3563
3564 /*
3565  * 3D case 0x7cd:                           O
3566  *
3567  *  b0:
3568  *  b1: t->sw[i+1][j  ][k  ]
3569  *  b2:
3570  *  b3:                           O                   O
3571  *  b4: t->sw[i  ][j  ][k+1]                O       . .
3572  *  b5: t->sw[i+1][j  ][k+1]                      .   .
3573  *  b6:                                         .     .
3574  *  b7:                                       .       .
3575  *                                          O         .
3576  *                                O                   O
3577  *
3578  *
3579  *
3580  *
3581  *                                          @
3582  */
3583 static
3584 bool handle_case_0x7cd(struct torus *t, int i, int j, int k)
3585 {
3586         int ip1 = canonicalize(i + 1, t->x_sz);
3587         int jp1 = canonicalize(j + 1, t->y_sz);
3588         int jm1 = canonicalize(j - 1, t->y_sz);
3589         int kp1 = canonicalize(k + 1, t->z_sz);
3590
3591         if (safe_y_perpendicular(t, ip1, j, kp1) &&
3592             install_tswitch(t, ip1, jp1, kp1,
3593                             tfind_3d_perpendicular(t->sw[i][j][kp1],
3594                                                    t->sw[ip1][j][kp1],
3595                                                    t->sw[ip1][j][k],
3596                                                    t->sw[ip1][jm1][kp1]))) {
3597                 return true;
3598         }
3599         log_no_perp(t, 0x7cd, i, j, k, ip1, j, kp1);
3600         return false;
3601 }
3602
3603 /*
3604  * 3D case 0x7ce:                           O
3605  *
3606  *  b0: t->sw[i  ][j  ][k  ]
3607  *  b1:
3608  *  b2:
3609  *  b3:                           O                   O
3610  *  b4: t->sw[i  ][j  ][k+1]                O       .
3611  *  b5: t->sw[i+1][j  ][k+1]                      .
3612  *  b6:                                         .
3613  *  b7:                                       .
3614  *                                          O
3615  *                                O         .         O
3616  *                                          .
3617  *                                          .
3618  *                                          .
3619  *                                          .
3620  *                                          @
3621  */
3622 static
3623 bool handle_case_0x7ce(struct torus *t, int i, int j, int k)
3624 {
3625         int ip1 = canonicalize(i + 1, t->x_sz);
3626         int jp1 = canonicalize(j + 1, t->y_sz);
3627         int jm1 = canonicalize(j - 1, t->y_sz);
3628         int kp1 = canonicalize(k + 1, t->z_sz);
3629
3630         if (safe_y_perpendicular(t, i, j, kp1) &&
3631             install_tswitch(t, i, jp1, kp1,
3632                             tfind_3d_perpendicular(t->sw[i][j][k],
3633                                                    t->sw[i][j][kp1],
3634                                                    t->sw[ip1][j][kp1],
3635                                                    t->sw[i][jm1][kp1]))) {
3636                 return true;
3637         }
3638         log_no_perp(t, 0x7ce, i, j, k, i, j, kp1);
3639         return false;
3640 }
3641
3642 /*
3643  * 3D case 0x7d5:                           O
3644  *
3645  *  b0:
3646  *  b1: t->sw[i+1][j  ][k  ]
3647  *  b2:
3648  *  b3: t->sw[i+1][j+1][k  ]      O                   O
3649  *  b4:                                     O         .
3650  *  b5: t->sw[i+1][j  ][k+1]                  .       .
3651  *  b6:                                         .     .
3652  *  b7:                                           .   .
3653  *                                          O       . .
3654  *                                O                   O
3655  *
3656  *
3657  *
3658  *
3659  *                                          @
3660  */
3661 static
3662 bool handle_case_0x7d5(struct torus *t, int i, int j, int k)
3663 {
3664         int ip1 = canonicalize(i + 1, t->x_sz);
3665         int ip2 = canonicalize(i + 2, t->x_sz);
3666         int jp1 = canonicalize(j + 1, t->y_sz);
3667         int kp1 = canonicalize(k + 1, t->z_sz);
3668
3669         if (safe_x_perpendicular(t, ip1, j, k) &&
3670             install_tswitch(t, i, j, k,
3671                             tfind_3d_perpendicular(t->sw[ip1][j][kp1],
3672                                                    t->sw[ip1][j][k],
3673                                                    t->sw[ip1][jp1][k],
3674                                                    t->sw[ip2][j][k]))) {
3675                 return true;
3676         }
3677         log_no_perp(t, 0x7d5, i, j, k, ip1, j, k);
3678         return false;
3679 }
3680
3681 /*
3682  * 3D case 0x7dc:                           O
3683  *
3684  *  b0: t->sw[i  ][j  ][k  ]
3685  *  b1: t->sw[i+1][j  ][k  ]
3686  *  b2:
3687  *  b3:                           O                   O
3688  *  b4:                                     O         .
3689  *  b5: t->sw[i+1][j  ][k+1]                          .
3690  *  b6:                                               .
3691  *  b7:                                               .
3692  *                                          O         .
3693  *                                O                   O
3694  *                                                  .
3695  *                                                .
3696  *                                              .
3697  *                                            .
3698  *                                          @
3699  */
3700 static
3701 bool handle_case_0x7dc(struct torus *t, int i, int j, int k)
3702 {
3703         int ip1 = canonicalize(i + 1, t->x_sz);
3704         int jp1 = canonicalize(j + 1, t->y_sz);
3705         int jm1 = canonicalize(j - 1, t->y_sz);
3706         int kp1 = canonicalize(k + 1, t->z_sz);
3707
3708         if (safe_y_perpendicular(t, ip1, j, k) &&
3709             install_tswitch(t, ip1, jp1, k,
3710                             tfind_3d_perpendicular(t->sw[i][j][k],
3711                                                    t->sw[ip1][j][k],
3712                                                    t->sw[ip1][j][kp1],
3713                                                    t->sw[ip1][jm1][k]))) {
3714                 return true;
3715         }
3716         log_no_perp(t, 0x7dc, i, j, k, ip1, j, k);
3717         return false;
3718 }
3719
3720 /*
3721  * 3D case 0x7ea:                           O
3722  *
3723  *  b0: t->sw[i  ][j  ][k  ]
3724  *  b1:
3725  *  b2: t->sw[i  ][j+1][k  ]
3726  *  b3:                            O                   O
3727  *  b4: t->sw[i  ][j  ][k+1]                 O
3728  *  b5:
3729  *  b6:
3730  *  b7:
3731  *                                          O
3732  *                                O         .         O
3733  *                                  .       .
3734  *                                    .     .
3735  *                                      .   .
3736  *                                        . .
3737  *                                          @
3738  */
3739 static
3740 bool handle_case_0x7ea(struct torus *t, int i, int j, int k)
3741 {
3742         int im1 = canonicalize(i - 1, t->x_sz);
3743         int ip1 = canonicalize(i + 1, t->x_sz);
3744         int jp1 = canonicalize(j + 1, t->y_sz);
3745         int kp1 = canonicalize(k + 1, t->z_sz);
3746
3747         if (safe_x_perpendicular(t, i, j, k) &&
3748             install_tswitch(t, ip1, j, k,
3749                             tfind_3d_perpendicular(t->sw[i][j][kp1],
3750                                                    t->sw[i][j][k],
3751                                                    t->sw[i][jp1][k],
3752                                                    t->sw[im1][j][k]))) {
3753                 return true;
3754         }
3755         log_no_perp(t, 0x7ea, i, j, k, i, j, k);
3756         return false;
3757 }
3758
3759 /*
3760  * 3D case 0x7ec:                           O
3761  *
3762  *  b0: t->sw[i  ][j  ][k  ]
3763  *  b1: t->sw[i+1][j  ][k  ]
3764  *  b2:
3765  *  b3:                           O                   O
3766  *  b4: t->sw[i  ][j  ][k+1]                O
3767  *  b5:
3768  *  b6:
3769  *  b7:
3770  *                                          O
3771  *                                O         .         O
3772  *                                          .       .
3773  *                                          .     .
3774  *                                          .   .
3775  *                                          . .
3776  *                                          @
3777  */
3778 static
3779 bool handle_case_0x7ec(struct torus *t, int i, int j, int k)
3780 {
3781         int ip1 = canonicalize(i + 1, t->x_sz);
3782         int jp1 = canonicalize(j + 1, t->y_sz);
3783         int jm1 = canonicalize(j - 1, t->y_sz);
3784         int kp1 = canonicalize(k + 1, t->z_sz);
3785
3786         if (safe_y_perpendicular(t, i, j, k) &&
3787             install_tswitch(t, i, jp1, k,
3788                             tfind_3d_perpendicular(t->sw[i][j][kp1],
3789                                                    t->sw[i][j][k],
3790                                                    t->sw[ip1][j][k],
3791                                                    t->sw[i][jm1][k]))) {
3792                 return true;
3793         }
3794         log_no_perp(t, 0x7ec, i, j, k, i, j, k);
3795         return false;
3796 }
3797
3798 /*
3799  * 3D case 0x7f1:                           O
3800  *
3801  *  b0:
3802  *  b1: t->sw[i+1][j  ][k  ]
3803  *  b2: t->sw[i  ][j+1][k  ]
3804  *  b3: t->sw[i+1][j+1][k  ]      O                   O
3805  *  b4:                                     O
3806  *  b5:                                   .   .
3807  *  b6:                                 .       .
3808  *  b7:                               .           .
3809  *                                  .       O       .
3810  *                                O                   O
3811  *
3812  *
3813  *
3814  *
3815  *                                          @
3816  */
3817 static
3818 bool handle_case_0x7f1(struct torus *t, int i, int j, int k)
3819 {
3820         int ip1 = canonicalize(i + 1, t->x_sz);
3821         int jp1 = canonicalize(j + 1, t->y_sz);
3822         int km1 = canonicalize(k - 1, t->z_sz);
3823         int kp1 = canonicalize(k + 1, t->z_sz);
3824
3825         if (safe_z_perpendicular(t, ip1, jp1, k) &&
3826             install_tswitch(t, ip1, jp1, kp1,
3827                             tfind_3d_perpendicular(t->sw[ip1][j][k],
3828                                                    t->sw[ip1][jp1][k],
3829                                                    t->sw[i][jp1][k],
3830                                                    t->sw[ip1][jp1][km1]))) {
3831                 return true;
3832         }
3833         log_no_perp(t, 0x7f1, i, j, k, ip1, jp1, k);
3834         return false;
3835 }
3836
3837 /*
3838  * 3D case 0x7f2:                           O
3839  *
3840  *  b0: t->sw[i  ][j  ][k  ]
3841  *  b1:
3842  *  b2: t->sw[i  ][j+1][k  ]
3843  *  b3: t->sw[i+1][j+1][k  ]      O                   O
3844  *  b4:                                     O
3845  *  b5:                                   .
3846  *  b6:                                 .
3847  *  b7:                               .
3848  *                                  .       O
3849  *                                O                   O
3850  *                                  .
3851  *                                    .
3852  *                                      .
3853  *                                        .
3854  *                                          @
3855  */
3856 static
3857 bool handle_case_0x7f2(struct torus *t, int i, int j, int k)
3858 {
3859         int ip1 = canonicalize(i + 1, t->x_sz);
3860         int jp1 = canonicalize(j + 1, t->y_sz);
3861         int km1 = canonicalize(k - 1, t->z_sz);
3862         int kp1 = canonicalize(k + 1, t->z_sz);
3863
3864         if (safe_z_perpendicular(t, i, jp1, k) &&
3865             install_tswitch(t, i, jp1, kp1,
3866                             tfind_3d_perpendicular(t->sw[i][j][k],
3867                                                    t->sw[i][jp1][k],
3868                                                    t->sw[ip1][jp1][k],
3869                                                    t->sw[i][jp1][km1]))) {
3870                 return true;
3871         }
3872         log_no_perp(t, 0x7f2, i, j, k, i, jp1, k);
3873         return false;
3874 }
3875
3876 /*
3877  * 3D case 0x7f4:                           O
3878  *
3879  *  b0: t->sw[i  ][j  ][k  ]
3880  *  b1: t->sw[i+1][j  ][k  ]
3881  *  b2:
3882  *  b3: t->sw[i+1][j+1][k  ]      O                   O
3883  *  b4:                                     O
3884  *  b5:                                       .
3885  *  b6:                                         .
3886  *  b7:                                           .
3887  *                                          O       .
3888  *                                O                   O
3889  *                                                  .
3890  *                                                .
3891  *                                              .
3892  *                                            .
3893  *                                          @
3894  */
3895 static
3896 bool handle_case_0x7f4(struct torus *t, int i, int j, int k)
3897 {
3898         int ip1 = canonicalize(i + 1, t->x_sz);
3899         int jp1 = canonicalize(j + 1, t->y_sz);
3900         int km1 = canonicalize(k - 1, t->z_sz);
3901         int kp1 = canonicalize(k + 1, t->z_sz);
3902
3903         if (safe_z_perpendicular(t, ip1, j, k) &&
3904             install_tswitch(t, ip1, j, kp1,
3905                             tfind_3d_perpendicular(t->sw[i][j][k],
3906                                                    t->sw[ip1][j][k],
3907                                                    t->sw[ip1][jp1][k],
3908                                                    t->sw[ip1][j][km1]))) {
3909                 return true;
3910         }
3911         log_no_perp(t, 0x7f4, i, j, k, ip1, j, k);
3912         return false;
3913 }
3914
3915 /*
3916  * 3D case 0x7f8:                           O
3917  *
3918  *  b0: t->sw[i  ][j  ][k  ]
3919  *  b1: t->sw[i+1][j  ][k  ]
3920  *  b2: t->sw[i  ][j+1][k  ]
3921  *  b3:                           O                   O
3922  *  b4:                                     O
3923  *  b5:
3924  *  b6:
3925  *  b7:
3926  *                                          O
3927  *                                O                   O
3928  *                                  .               .
3929  *                                    .           .
3930  *                                      .       .
3931  *                                        .   .
3932  *                                          @
3933  */
3934 static
3935 bool handle_case_0x7f8(struct torus *t, int i, int j, int k)
3936 {
3937         int ip1 = canonicalize(i + 1, t->x_sz);
3938         int jp1 = canonicalize(j + 1, t->y_sz);
3939         int km1 = canonicalize(k - 1, t->z_sz);
3940         int kp1 = canonicalize(k + 1, t->z_sz);
3941
3942         if (safe_z_perpendicular(t, i, j, k) &&
3943             install_tswitch(t, i, j, kp1,
3944                             tfind_3d_perpendicular(t->sw[ip1][j][k],
3945                                                    t->sw[i][j][k],
3946                                                    t->sw[i][jp1][k],
3947                                                    t->sw[i][j][km1]))) {
3948                 return true;
3949         }
3950         log_no_perp(t, 0x7f8, i, j, k, i, j, k);
3951         return false;
3952 }
3953
3954 /*
3955  * Handle the cases where three existing edges meet at a corner.
3956  */
3957
3958 /*
3959  * 3D case 0x717:                           O
3960  *                                        . . .
3961  *  b0:                                 .   .   .
3962  *  b1:                               .     .     .
3963  *  b2:                             .       .       .
3964  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
3965  *  b4:                                     O
3966  *  b5: t->sw[i+1][j  ][k+1]
3967  *  b6: t->sw[i  ][j+1][k+1]
3968  *  b7: t->sw[i+1][j+1][k+1]
3969  *                                          O
3970  *                                O                   O
3971  *
3972  *
3973  *
3974  *
3975  *                                          @
3976  */
3977 static
3978 bool handle_case_0x717(struct torus *t, int i, int j, int k)
3979 {
3980         int ip1 = canonicalize(i + 1, t->x_sz);
3981         int jp1 = canonicalize(j + 1, t->y_sz);
3982         int kp1 = canonicalize(k + 1, t->z_sz);
3983
3984         if (install_tswitch(t, i, j, kp1,
3985                             tfind_face_corner(t->sw[i][jp1][kp1],
3986                                               t->sw[ip1][jp1][kp1],
3987                                               t->sw[ip1][j][kp1]))) {
3988                 return true;
3989         }
3990         log_no_crnr(t, 0x717, i, j, k, i, j, kp1);
3991
3992         if (install_tswitch(t, ip1, j, k,
3993                             tfind_face_corner(t->sw[ip1][jp1][k],
3994                                               t->sw[ip1][jp1][kp1],
3995                                               t->sw[ip1][j][kp1]))) {
3996                 return true;
3997         }
3998         log_no_crnr(t, 0x717, i, j, k, ip1, j, k);
3999
4000         if (install_tswitch(t, i, jp1, k,
4001                             tfind_face_corner(t->sw[ip1][jp1][k],
4002                                               t->sw[ip1][jp1][kp1],
4003                                               t->sw[i][jp1][kp1]))) {
4004                 return true;
4005         }
4006         log_no_crnr(t, 0x717, i, j, k, i, jp1, k);
4007         return false;
4008 }
4009
4010 /*
4011  * 3D case 0x72b:                           O
4012  *                                        .
4013  *  b0:                                 .
4014  *  b1:                               .
4015  *  b2: t->sw[i  ][j+1][k  ]        .
4016  *  b3:                           O                   O
4017  *  b4: t->sw[i  ][j  ][k+1]      . .       O
4018  *  b5:                           .   .
4019  *  b6: t->sw[i  ][j+1][k+1]      .     .
4020  *  b7: t->sw[i+1][j+1][k+1]      .       .
4021  *                                .         O
4022  *                                O                   O
4023  *
4024  *
4025  *
4026  *
4027  *                                          @
4028  */
4029 static
4030 bool handle_case_0x72b(struct torus *t, int i, int j, int k)
4031 {
4032         int ip1 = canonicalize(i + 1, t->x_sz);
4033         int jp1 = canonicalize(j + 1, t->y_sz);
4034         int kp1 = canonicalize(k + 1, t->z_sz);
4035
4036         if (install_tswitch(t, ip1, j, kp1,
4037                             tfind_face_corner(t->sw[i][j][kp1],
4038                                               t->sw[i][jp1][kp1],
4039                                               t->sw[ip1][jp1][kp1]))) {
4040                 return true;
4041         }
4042         log_no_crnr(t, 0x72b, i, j, k, ip1, j, kp1);
4043
4044         if (install_tswitch(t, i, j, k,
4045                             tfind_face_corner(t->sw[i][jp1][k],
4046                                               t->sw[i][jp1][kp1],
4047                                               t->sw[i][j][kp1]))) {
4048                 return true;
4049         }
4050         log_no_crnr(t, 0x72b, i, j, k, i, j, k);
4051
4052         if (install_tswitch(t, ip1, jp1, k,
4053                             tfind_face_corner(t->sw[i][jp1][k],
4054                                               t->sw[i][jp1][kp1],
4055                                               t->sw[ip1][jp1][kp1]))) {
4056                 return true;
4057         }
4058         log_no_crnr(t, 0x72b, i, j, k, ip1, jp1, k);
4059         return false;
4060 }
4061
4062 /*
4063  * 3D case 0x74d:                           O
4064  *                                            .
4065  *  b0:                                         .
4066  *  b1: t->sw[i+1][j  ][k  ]                      .
4067  *  b2:                                             .
4068  *  b3:                           O                   O
4069  *  b4: t->sw[i  ][j  ][k+1]                O       . .
4070  *  b5: t->sw[i+1][j  ][k+1]                      .   .
4071  *  b6:                                         .     .
4072  *  b7: t->sw[i+1][j+1][k+1]                  .       .
4073  *                                          O         .
4074  *                                O                   O
4075  *
4076  *
4077  *
4078  *
4079  *                                          @
4080  */
4081 static
4082 bool handle_case_0x74d(struct torus *t, int i, int j, int k)
4083 {
4084         int ip1 = canonicalize(i + 1, t->x_sz);
4085         int jp1 = canonicalize(j + 1, t->y_sz);
4086         int kp1 = canonicalize(k + 1, t->z_sz);
4087
4088         if (install_tswitch(t, i, jp1, kp1,
4089                             tfind_face_corner(t->sw[i][j][kp1],
4090                                               t->sw[ip1][j][kp1],
4091                                               t->sw[ip1][jp1][kp1]))) {
4092                 return true;
4093         }
4094         log_no_crnr(t, 0x74d, i, j, k, i, jp1, kp1);
4095
4096         if (install_tswitch(t, i, j, k,
4097                             tfind_face_corner(t->sw[ip1][j][k],
4098                                               t->sw[ip1][j][kp1],
4099                                               t->sw[i][j][kp1]))) {
4100                 return true;
4101         }
4102         log_no_crnr(t, 0x74d, i, j, k, i, j, k);
4103
4104         if (install_tswitch(t, ip1, jp1, k,
4105                             tfind_face_corner(t->sw[ip1][j][k],
4106                                               t->sw[ip1][j][kp1],
4107                                               t->sw[ip1][jp1][kp1]))) {
4108                 return true;
4109         }
4110         log_no_crnr(t, 0x74d, i, j, k, ip1, jp1, k);
4111         return false;
4112 }
4113
4114 /*
4115  * 3D case 0x771:                           O
4116  *                                          .
4117  *  b0:                                     .
4118  *  b1: t->sw[i+1][j  ][k  ]                .
4119  *  b2: t->sw[i  ][j+1][k  ]                .
4120  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
4121  *  b4:                                     O
4122  *  b5:                                   .   .
4123  *  b6:                                 .       .
4124  *  b7: t->sw[i+1][j+1][k+1]          .           .
4125  *                                  .       O       .
4126  *                                O                   O
4127  *
4128  *
4129  *
4130  *
4131  *                                          @
4132  */
4133 static
4134 bool handle_case_0x771(struct torus *t, int i, int j, int k)
4135 {
4136         int ip1 = canonicalize(i + 1, t->x_sz);
4137         int jp1 = canonicalize(j + 1, t->y_sz);
4138         int kp1 = canonicalize(k + 1, t->z_sz);
4139
4140         if (install_tswitch(t, i, j, k,
4141                             tfind_face_corner(t->sw[i][jp1][k],
4142                                               t->sw[ip1][jp1][k],
4143                                               t->sw[ip1][j][k]))) {
4144                 return true;
4145         }
4146         log_no_crnr(t, 0x771, i, j, k, i, j, k);
4147
4148         if (install_tswitch(t, ip1, j, kp1,
4149                             tfind_face_corner(t->sw[ip1][jp1][kp1],
4150                                               t->sw[ip1][jp1][k],
4151                                               t->sw[ip1][j][k]))) {
4152                 return true;
4153         }
4154         log_no_crnr(t, 0x771, i, j, k, ip1, j, kp1);
4155
4156         if (install_tswitch(t, i, jp1, kp1,
4157                             tfind_face_corner(t->sw[ip1][jp1][kp1],
4158                                               t->sw[ip1][jp1][k],
4159                                               t->sw[i][jp1][k]))) {
4160                 return true;
4161         }
4162         log_no_crnr(t, 0x771, i, j, k, i, jp1, kp1);
4163         return false;
4164 }
4165
4166 /*
4167  * 3D case 0x78e:                           O
4168  *
4169  *  b0: t->sw[i  ][j  ][k  ]
4170  *  b1:
4171  *  b2:
4172  *  b3:                           O                   O
4173  *  b4: t->sw[i  ][j  ][k+1]        .       O       .
4174  *  b5: t->sw[i+1][j  ][k+1]          .           .
4175  *  b6: t->sw[i  ][j+1][k+1]            .       .
4176  *  b7:                                   .   .
4177  *                                          O
4178  *                                O         .         O
4179  *                                          .
4180  *                                          .
4181  *                                          .
4182  *                                          .
4183  *                                          @
4184  */
4185 static
4186 bool handle_case_0x78e(struct torus *t, int i, int j, int k)
4187 {
4188         int ip1 = canonicalize(i + 1, t->x_sz);
4189         int jp1 = canonicalize(j + 1, t->y_sz);
4190         int kp1 = canonicalize(k + 1, t->z_sz);
4191
4192         if (install_tswitch(t, ip1, jp1, kp1,
4193                             tfind_face_corner(t->sw[ip1][j][kp1],
4194                                               t->sw[i][j][kp1],
4195                                               t->sw[i][jp1][kp1]))) {
4196                 return true;
4197         }
4198         log_no_crnr(t, 0x78e, i, j, k, ip1, jp1, kp1);
4199
4200         if (install_tswitch(t, ip1, j, k,
4201                             tfind_face_corner(t->sw[i][j][k],
4202                                               t->sw[i][j][kp1],
4203                                               t->sw[ip1][j][kp1]))) {
4204                 return true;
4205         }
4206         log_no_crnr(t, 0x78e, i, j, k, ip1, j, k);
4207
4208         if (install_tswitch(t, i, jp1, k,
4209                             tfind_face_corner(t->sw[i][j][k],
4210                                               t->sw[i][j][kp1],
4211                                               t->sw[i][jp1][kp1]))) {
4212                 return true;
4213         }
4214         log_no_crnr(t, 0x78e, i, j, k, i, jp1, k);
4215         return false;
4216 }
4217
4218 /*
4219  * 3D case 0x7b2:                           O
4220  *
4221  *  b0: t->sw[i  ][j  ][k  ]
4222  *  b1:
4223  *  b2: t->sw[i  ][j+1][k  ]
4224  *  b3: t->sw[i+1][j+1][k  ]      O                   O
4225  *  b4:                           .         O
4226  *  b5:                           .       .
4227  *  b6: t->sw[i  ][j+1][k+1]      .     .
4228  *  b7:                           .   .
4229  *                                . .       O
4230  *                                O                   O
4231  *                                  .
4232  *                                    .
4233  *                                      .
4234  *                                        .
4235  *                                          @
4236  */
4237 static
4238 bool handle_case_0x7b2(struct torus *t, int i, int j, int k)
4239 {
4240         int ip1 = canonicalize(i + 1, t->x_sz);
4241         int jp1 = canonicalize(j + 1, t->y_sz);
4242         int kp1 = canonicalize(k + 1, t->z_sz);
4243
4244         if (install_tswitch(t, ip1, j, k,
4245                             tfind_face_corner(t->sw[i][j][k],
4246                                               t->sw[i][jp1][k],
4247                                               t->sw[ip1][jp1][k]))) {
4248                 return true;
4249         }
4250         log_no_crnr(t, 0x7b2, i, j, k, ip1, j, k);
4251
4252         if (install_tswitch(t, ip1, jp1, kp1,
4253                             tfind_face_corner(t->sw[i][jp1][kp1],
4254                                               t->sw[i][jp1][k],
4255                                               t->sw[ip1][jp1][k]))) {
4256                 return true;
4257         }
4258         log_no_crnr(t, 0x7b2, i, j, k, ip1, jp1, kp1);
4259
4260         if (install_tswitch(t, i, j, kp1,
4261                             tfind_face_corner(t->sw[i][jp1][kp1],
4262                                               t->sw[i][jp1][k],
4263                                               t->sw[i][j][k]))) {
4264                 return true;
4265         }
4266         log_no_crnr(t, 0x7b2, i, j, k, i, j, kp1);
4267         return false;
4268 }
4269
4270 /*
4271  * 3D case 0x7d4:                           O
4272  *
4273  *  b0: t->sw[i  ][j  ][k  ]
4274  *  b1: t->sw[i+1][j  ][k  ]
4275  *  b2:
4276  *  b3: t->sw[i+1][j+1][k  ]      O                   O
4277  *  b4:                                     O         .
4278  *  b5: t->sw[i+1][j  ][k+1]                  .       .
4279  *  b6:                                         .     .
4280  *  b7:                                           .   .
4281  *                                          O       . .
4282  *                                O                   O
4283  *                                                  .
4284  *                                                .
4285  *                                              .
4286  *                                            .
4287  *                                          @
4288  */
4289 static
4290 bool handle_case_0x7d4(struct torus *t, int i, int j, int k)
4291 {
4292         int ip1 = canonicalize(i + 1, t->x_sz);
4293         int jp1 = canonicalize(j + 1, t->y_sz);
4294         int kp1 = canonicalize(k + 1, t->z_sz);
4295
4296         if (install_tswitch(t, i, jp1, k,
4297                             tfind_face_corner(t->sw[i][j][k],
4298                                               t->sw[ip1][j][k],
4299                                               t->sw[ip1][jp1][k]))) {
4300                 return true;
4301         }
4302         log_no_crnr(t, 0x7d4, i, j, k, i, jp1, k);
4303
4304         if (install_tswitch(t, i, j, kp1,
4305                             tfind_face_corner(t->sw[ip1][j][kp1],
4306                                               t->sw[ip1][j][k],
4307                                               t->sw[i][j][k]))) {
4308                 return true;
4309         }
4310         log_no_crnr(t, 0x7d4, i, j, k, i, j, kp1);
4311
4312         if (install_tswitch(t, ip1, jp1, kp1,
4313                             tfind_face_corner(t->sw[ip1][j][kp1],
4314                                               t->sw[ip1][j][k],
4315                                               t->sw[ip1][jp1][k]))) {
4316                 return true;
4317         }
4318         log_no_crnr(t, 0x7d4, i, j, k, ip1, jp1, kp1);
4319         return false;
4320 }
4321
4322 /*
4323  * 3D case 0x7e8:                           O
4324  *
4325  *  b0: t->sw[i  ][j  ][k  ]
4326  *  b1: t->sw[i+1][j  ][k  ]
4327  *  b2: t->sw[i  ][j+1][k  ]
4328  *  b3:                           O                   O
4329  *  b4: t->sw[i  ][j  ][k+1]                O
4330  *  b5:
4331  *  b6:
4332  *  b7:
4333  *                                          O
4334  *                                O         .         O
4335  *                                  .       .       .
4336  *                                    .     .     .
4337  *                                      .   .   .
4338  *                                        . . .
4339  *                                          @
4340  */
4341 static
4342 bool handle_case_0x7e8(struct torus *t, int i, int j, int k)
4343 {
4344         int ip1 = canonicalize(i + 1, t->x_sz);
4345         int jp1 = canonicalize(j + 1, t->y_sz);
4346         int kp1 = canonicalize(k + 1, t->z_sz);
4347
4348         if (install_tswitch(t, ip1, jp1, k,
4349                             tfind_face_corner(t->sw[ip1][j][k],
4350                                               t->sw[i][j][k],
4351                                               t->sw[i][jp1][k]))) {
4352                 return true;
4353         }
4354         log_no_crnr(t, 0x7e8, i, j, k, ip1, jp1, k);
4355
4356         if (install_tswitch(t, ip1, j, kp1,
4357                             tfind_face_corner(t->sw[ip1][j][k],
4358                                               t->sw[i][j][k],
4359                                               t->sw[i][j][kp1]))) {
4360                 return true;
4361         }
4362         log_no_crnr(t, 0x7e8, i, j, k, ip1, j, kp1);
4363
4364         if (install_tswitch(t, i, jp1, kp1,
4365                             tfind_face_corner(t->sw[i][jp1][k],
4366                                               t->sw[i][j][k],
4367                                               t->sw[i][j][kp1]))) {
4368                 return true;
4369         }
4370         log_no_crnr(t, 0x7e8, i, j, k, i, jp1, kp1);
4371         return false;
4372 }
4373
4374 /*
4375  * Handle the cases where four corners on a single face are missing.
4376  */
4377
4378 /*
4379  * 3D case 0x70f:                           O
4380  *                                        .   .
4381  *  b0:                                 .       .
4382  *  b1:                               .           .
4383  *  b2:                             .               .
4384  *  b3:                           O                   O
4385  *  b4: t->sw[i  ][j  ][k+1]        .       O       .
4386  *  b5: t->sw[i+1][j  ][k+1]          .           .
4387  *  b6: t->sw[i  ][j+1][k+1]            .       .
4388  *  b7: t->sw[i+1][j+1][k+1]              .   .
4389  *                                          O
4390  *                                O                   O
4391  *
4392  *
4393  *
4394  *
4395  *                                          @
4396  */
4397 static
4398 bool handle_case_0x70f(struct torus *t, int i, int j, int k)
4399 {
4400         if (handle_case_0x71f(t, i, j, k))
4401                 return true;
4402
4403         if (handle_case_0x72f(t, i, j, k))
4404                 return true;
4405
4406         if (handle_case_0x74f(t, i, j, k))
4407                 return true;
4408
4409         return handle_case_0x78f(t, i, j, k);
4410 }
4411
4412 /*
4413  * 3D case 0x733:                           O
4414  *                                        . .
4415  *  b0:                                 .   .
4416  *  b1:                               .     .
4417  *  b2: t->sw[i  ][j+1][k  ]        .       .
4418  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
4419  *  b4:                           .         O
4420  *  b5:                           .       .
4421  *  b6: t->sw[i  ][j+1][k+1]      .     .
4422  *  b7: t->sw[i+1][j+1][k+1]      .   .
4423  *                                . .       O
4424  *                                O                   O
4425  *
4426  *
4427  *
4428  *
4429  *                                          @
4430  */
4431 static
4432 bool handle_case_0x733(struct torus *t, int i, int j, int k)
4433 {
4434         if (handle_case_0x737(t, i, j, k))
4435                 return true;
4436
4437         if (handle_case_0x73b(t, i, j, k))
4438                 return true;
4439
4440         if (handle_case_0x773(t, i, j, k))
4441                 return true;
4442
4443         return handle_case_0x7b3(t, i, j, k);
4444 }
4445
4446 /*
4447  * 3D case 0x755:                           O
4448  *                                          . .
4449  *  b0:                                     .   .
4450  *  b1: t->sw[i+1][j  ][k  ]                .     .
4451  *  b2:                                     .       .
4452  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
4453  *  b4:                                     O         .
4454  *  b5: t->sw[i+1][j  ][k+1]                  .       .
4455  *  b6:                                         .     .
4456  *  b7: t->sw[i+1][j+1][k+1]                      .   .
4457  *                                          O       . .
4458  *                                O                   O
4459  *
4460  *
4461  *
4462  *
4463  *                                          @
4464  */
4465 static
4466 bool handle_case_0x755(struct torus *t, int i, int j, int k)
4467 {
4468         if (handle_case_0x757(t, i, j, k))
4469                 return true;
4470
4471         if (handle_case_0x75d(t, i, j, k))
4472                 return true;
4473
4474         if (handle_case_0x775(t, i, j, k))
4475                 return true;
4476
4477         return handle_case_0x7d5(t, i, j, k);
4478 }
4479
4480 /*
4481  * 3D case 0x7aa:                           O
4482  *
4483  *  b0: t->sw[i  ][j  ][k  ]
4484  *  b1:
4485  *  b2: t->sw[i  ][j+1][k  ]
4486  *  b3:                           O                   O
4487  *  b4: t->sw[i  ][j  ][k+1]      . .       O
4488  *  b5:                           .   .
4489  *  b6: t->sw[i  ][j+1][k+1]      .     .
4490  *  b7:                           .       .
4491  *                                .         O
4492  *                                O         .         O
4493  *                                  .       .
4494  *                                    .     .
4495  *                                      .   .
4496  *                                        . .
4497  *                                          @
4498  */
4499 static
4500 bool handle_case_0x7aa(struct torus *t, int i, int j, int k)
4501 {
4502         if (handle_case_0x7ab(t, i, j, k))
4503                 return true;
4504
4505         if (handle_case_0x7ae(t, i, j, k))
4506                 return true;
4507
4508         if (handle_case_0x7ba(t, i, j, k))
4509                 return true;
4510
4511         return handle_case_0x7ea(t, i, j, k);
4512 }
4513
4514 /*
4515  * 3D case 0x7cc:                           O
4516  *
4517  *  b0: t->sw[i  ][j  ][k  ]
4518  *  b1: t->sw[i+1][j  ][k  ]
4519  *  b2:
4520  *  b3:                           O                   O
4521  *  b4: t->sw[i  ][j  ][k+1]                O       . .
4522  *  b5: t->sw[i+1][j  ][k+1]                      .   .
4523  *  b6:                                         .     .
4524  *  b7:                                       .       .
4525  *                                          O         .
4526  *                                O         .         O
4527  *                                          .       .
4528  *                                          .     .
4529  *                                          .   .
4530  *                                          . .
4531  *                                          @
4532  */
4533 static
4534 bool handle_case_0x7cc(struct torus *t, int i, int j, int k)
4535 {
4536         if (handle_case_0x7cd(t, i, j, k))
4537                 return true;
4538
4539         if (handle_case_0x7ce(t, i, j, k))
4540                 return true;
4541
4542         if (handle_case_0x7dc(t, i, j, k))
4543                 return true;
4544
4545         return handle_case_0x7ec(t, i, j, k);
4546 }
4547
4548 /*
4549  * 3D case 0x7f0:                           O
4550  *
4551  *  b0: t->sw[i  ][j  ][k  ]
4552  *  b1: t->sw[i+1][j  ][k  ]
4553  *  b2: t->sw[i  ][j+1][k  ]
4554  *  b3: t->sw[i+1][j+1][k  ]      O                   O
4555  *  b4:                                     O
4556  *  b5:                                   .   .
4557  *  b6:                                 .       .
4558  *  b7:                               .           .
4559  *                                  .       O       .
4560  *                                O                   O
4561  *                                  .               .
4562  *                                    .           .
4563  *                                      .       .
4564  *                                        .   .
4565  *                                          @
4566  */
4567 static
4568 bool handle_case_0x7f0(struct torus *t, int i, int j, int k)
4569 {
4570         if (handle_case_0x7f1(t, i, j, k))
4571                 return true;
4572
4573         if (handle_case_0x7f2(t, i, j, k))
4574                 return true;
4575
4576         if (handle_case_0x7f4(t, i, j, k))
4577                 return true;
4578
4579         return handle_case_0x7f8(t, i, j, k);
4580 }
4581
4582 /*
4583  * Handle the cases where three corners on a single face are missing.
4584  */
4585
4586
4587 /*
4588  * 3D case 0x707:                           O
4589  *                                        . . .
4590  *  b0:                                 .   .   .
4591  *  b1:                               .     .     .
4592  *  b2:                             .       .       .
4593  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
4594  *  b4: t->sw[i  ][j  ][k+1]        .       O       .
4595  *  b5: t->sw[i+1][j  ][k+1]          .           .
4596  *  b6: t->sw[i  ][j+1][k+1]            .       .
4597  *  b7: t->sw[i+1][j+1][k+1]              .   .
4598  *                                          O
4599  *                                O                   O
4600  *
4601  *
4602  *
4603  *
4604  *                                          @
4605  */
4606 static
4607 bool handle_case_0x707(struct torus *t, int i, int j, int k)
4608 {
4609         int ip1 = canonicalize(i + 1, t->x_sz);
4610         int jp1 = canonicalize(j + 1, t->y_sz);
4611         int kp1 = canonicalize(k + 1, t->z_sz);
4612
4613         if (install_tswitch(t, ip1, j, k,
4614                             tfind_face_corner(t->sw[ip1][jp1][k],
4615                                               t->sw[ip1][jp1][kp1],
4616                                               t->sw[ip1][j][kp1]))) {
4617                 return true;
4618         }
4619         log_no_crnr(t, 0x707, i, j, k, ip1, j, k);
4620
4621         if (install_tswitch(t, i, jp1, k,
4622                             tfind_face_corner(t->sw[ip1][jp1][k],
4623                                               t->sw[ip1][jp1][kp1],
4624                                               t->sw[i][jp1][kp1]))) {
4625                 return true;
4626         }
4627         log_no_crnr(t, 0x707, i, j, k, i, jp1, k);
4628         return false;
4629 }
4630
4631 /*
4632  * 3D case 0x70b:                           O
4633  *                                        .   .
4634  *  b0:                                 .       .
4635  *  b1:                               .           .
4636  *  b2: t->sw[i  ][j+1][k  ]        .               .
4637  *  b3:                           O                   O
4638  *  b4: t->sw[i  ][j  ][k+1]      . .       O       .
4639  *  b5: t->sw[i+1][j  ][k+1]      .   .           .
4640  *  b6: t->sw[i  ][j+1][k+1]      .     .       .
4641  *  b7: t->sw[i+1][j+1][k+1]      .       .   .
4642  *                                .         O
4643  *                                O                   O
4644  *
4645  *
4646  *
4647  *
4648  *                                          @
4649  */
4650 static
4651 bool handle_case_0x70b(struct torus *t, int i, int j, int k)
4652 {
4653         int ip1 = canonicalize(i + 1, t->x_sz);
4654         int jp1 = canonicalize(j + 1, t->y_sz);
4655         int kp1 = canonicalize(k + 1, t->z_sz);
4656
4657         if (install_tswitch(t, i, j, k,
4658                             tfind_face_corner(t->sw[i][jp1][k],
4659                                               t->sw[i][jp1][kp1],
4660                                               t->sw[i][j][kp1]))) {
4661                 return true;
4662         }
4663         log_no_crnr(t, 0x70b, i, j, k, i, j, k);
4664
4665         if (install_tswitch(t, ip1, jp1, k,
4666                             tfind_face_corner(t->sw[i][jp1][k],
4667                                               t->sw[i][jp1][kp1],
4668                                               t->sw[ip1][jp1][kp1]))) {
4669                 return true;
4670         }
4671         log_no_crnr(t, 0x70b, i, j, k, ip1, jp1, k);
4672         return false;
4673 }
4674
4675 /*
4676  * 3D case 0x70d:                           O
4677  *                                        .   .
4678  *  b0:                                 .       .
4679  *  b1: t->sw[i+1][j  ][k  ]          .           .
4680  *  b2:                             .               .
4681  *  b3:                           O                   O
4682  *  b4: t->sw[i  ][j  ][k+1]        .       O       . .
4683  *  b5: t->sw[i+1][j  ][k+1]          .           .   .
4684  *  b6: t->sw[i  ][j+1][k+1]            .       .     .
4685  *  b7: t->sw[i+1][j+1][k+1]              .   .       .
4686  *                                          O         .
4687  *                                O                   O
4688  *
4689  *
4690  *
4691  *
4692  *                                          @
4693  */
4694 static
4695 bool handle_case_0x70d(struct torus *t, int i, int j, int k)
4696 {
4697         int ip1 = canonicalize(i + 1, t->x_sz);
4698         int jp1 = canonicalize(j + 1, t->y_sz);
4699         int kp1 = canonicalize(k + 1, t->z_sz);
4700
4701         if (install_tswitch(t, i, j, k,
4702                             tfind_face_corner(t->sw[ip1][j][k],
4703                                               t->sw[ip1][j][kp1],
4704                                               t->sw[i][j][kp1]))) {
4705                 return true;
4706         }
4707         log_no_crnr(t, 0x70d, i, j, k, i, j, k);
4708
4709         if (install_tswitch(t, ip1, jp1, k,
4710                             tfind_face_corner(t->sw[ip1][j][k],
4711                                               t->sw[ip1][j][kp1],
4712                                               t->sw[ip1][jp1][kp1]))) {
4713                 return true;
4714         }
4715         log_no_crnr(t, 0x70d, i, j, k, ip1, jp1, k);
4716         return false;
4717 }
4718
4719 /*
4720  * 3D case 0x70e:                           O
4721  *                                        .   .
4722  *  b0: t->sw[i  ][j  ][k  ]            .       .
4723  *  b1:                               .           .
4724  *  b2:                             .               .
4725  *  b3:                           O                   O
4726  *  b4: t->sw[i  ][j  ][k+1]        .       O       .
4727  *  b5: t->sw[i+1][j  ][k+1]          .           .
4728  *  b6: t->sw[i  ][j+1][k+1]            .       .
4729  *  b7: t->sw[i+1][j+1][k+1]              .   .
4730  *                                          O
4731  *                                O         .         O
4732  *                                          .
4733  *                                          .
4734  *                                          .
4735  *                                          .
4736  *                                          @
4737  */
4738 static
4739 bool handle_case_0x70e(struct torus *t, int i, int j, int k)
4740 {
4741         int ip1 = canonicalize(i + 1, t->x_sz);
4742         int jp1 = canonicalize(j + 1, t->y_sz);
4743         int kp1 = canonicalize(k + 1, t->z_sz);
4744
4745         if (install_tswitch(t, ip1, j, k,
4746                             tfind_face_corner(t->sw[i][j][k],
4747                                               t->sw[i][j][kp1],
4748                                               t->sw[ip1][j][kp1]))) {
4749                 return true;
4750         }
4751         log_no_crnr(t, 0x70e, i, j, k, ip1, j, k);
4752
4753         if (install_tswitch(t, i, jp1, k,
4754                             tfind_face_corner(t->sw[i][j][k],
4755                                               t->sw[i][j][kp1],
4756                                               t->sw[i][jp1][kp1]))) {
4757                 return true;
4758         }
4759         log_no_crnr(t, 0x70e, i, j, k, i, jp1, k);
4760         return false;
4761 }
4762
4763 /*
4764  * 3D case 0x713:                           O
4765  *                                        . . .
4766  *  b0:                                 .   .   .
4767  *  b1:                               .     .     .
4768  *  b2: t->sw[i  ][j+1][k  ]        .       .       .
4769  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
4770  *  b4:                           .         O
4771  *  b5: t->sw[i+1][j  ][k+1]      .       .
4772  *  b6: t->sw[i  ][j+1][k+1]      .     .
4773  *  b7: t->sw[i+1][j+1][k+1]      .   .
4774  *                                . .       O
4775  *                                O                   O
4776  *
4777  *
4778  *
4779  *
4780  *                                          @
4781  */
4782 static
4783 bool handle_case_0x713(struct torus *t, int i, int j, int k)
4784 {
4785         int ip1 = canonicalize(i + 1, t->x_sz);
4786         int jp1 = canonicalize(j + 1, t->y_sz);
4787         int kp1 = canonicalize(k + 1, t->z_sz);
4788
4789         if (install_tswitch(t, ip1, j, k,
4790                             tfind_face_corner(t->sw[ip1][jp1][k],
4791                                               t->sw[ip1][jp1][kp1],
4792                                               t->sw[ip1][j][kp1]))) {
4793                 return true;
4794         }
4795         log_no_crnr(t, 0x713, i, j, k, ip1, j, k);
4796
4797         if (install_tswitch(t, i, j, kp1,
4798                             tfind_face_corner(t->sw[ip1][j][kp1],
4799                                               t->sw[ip1][jp1][kp1],
4800                                               t->sw[i][jp1][kp1]))) {
4801                 return true;
4802         }
4803         log_no_crnr(t, 0x713, i, j, k, i, j, kp1);
4804         return false;
4805 }
4806
4807 /*
4808  * 3D case 0x715:                           O
4809  *                                        . . .
4810  *  b0:                                 .   .   .
4811  *  b1: t->sw[i+1][j  ][k  ]          .     .     .
4812  *  b2:                             .       .       .
4813  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
4814  *  b4:                                     O         .
4815  *  b5: t->sw[i+1][j  ][k+1]                  .       .
4816  *  b6: t->sw[i  ][j+1][k+1]                    .     .
4817  *  b7: t->sw[i+1][j+1][k+1]                      .   .
4818  *                                          O       . .
4819  *                                O                   O
4820  *
4821  *
4822  *
4823  *
4824  *                                          @
4825  */
4826 static
4827 bool handle_case_0x715(struct torus *t, int i, int j, int k)
4828 {
4829         int ip1 = canonicalize(i + 1, t->x_sz);
4830         int jp1 = canonicalize(j + 1, t->y_sz);
4831         int kp1 = canonicalize(k + 1, t->z_sz);
4832
4833         if (install_tswitch(t, i, jp1, k,
4834                             tfind_face_corner(t->sw[ip1][jp1][k],
4835                                               t->sw[ip1][jp1][kp1],
4836                                               t->sw[i][jp1][kp1]))) {
4837                 return true;
4838         }
4839         log_no_crnr(t, 0x715, i, j, k, i, jp1, k);
4840
4841         if (install_tswitch(t, i, j, kp1,
4842                             tfind_face_corner(t->sw[ip1][j][kp1],
4843                                               t->sw[ip1][jp1][kp1],
4844                                               t->sw[i][jp1][kp1]))) {
4845                 return true;
4846         }
4847         log_no_crnr(t, 0x715, i, j, k, i, j, kp1);
4848         return false;
4849 }
4850
4851 /*
4852  * 3D case 0x723:                           O
4853  *                                        . .
4854  *  b0:                                 .   .
4855  *  b1:                               .     .
4856  *  b2: t->sw[i  ][j+1][k  ]        .       .
4857  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
4858  *  b4: t->sw[i  ][j  ][k+1]      . .       O
4859  *  b5:                           .   .   .
4860  *  b6: t->sw[i  ][j+1][k+1]      .     .
4861  *  b7: t->sw[i+1][j+1][k+1]      .   .   .
4862  *                                . .       O
4863  *                                O                   O
4864  *
4865  *
4866  *
4867  *
4868  *                                          @
4869  */
4870 static
4871 bool handle_case_0x723(struct torus *t, int i, int j, int k)
4872 {
4873         int ip1 = canonicalize(i + 1, t->x_sz);
4874         int jp1 = canonicalize(j + 1, t->y_sz);
4875         int kp1 = canonicalize(k + 1, t->z_sz);
4876
4877         if (install_tswitch(t, i, j, k,
4878                             tfind_face_corner(t->sw[i][jp1][k],
4879                                               t->sw[i][jp1][kp1],
4880                                               t->sw[i][j][kp1]))) {
4881                 return true;
4882         }
4883         log_no_crnr(t, 0x723, i, j, k, i, j, k);
4884
4885         if (install_tswitch(t, ip1, j, kp1,
4886                             tfind_face_corner(t->sw[i][j][kp1],
4887                                               t->sw[i][jp1][kp1],
4888                                               t->sw[ip1][jp1][kp1]))) {
4889                 return true;
4890         }
4891         log_no_crnr(t, 0x723, i, j, k, ip1, j, kp1);
4892         return false;
4893 }
4894
4895 /*
4896  * 3D case 0x72a:                           O
4897  *                                        .
4898  *  b0: t->sw[i  ][j  ][k  ]            .
4899  *  b1:                               .
4900  *  b2: t->sw[i  ][j+1][k  ]        .
4901  *  b3:                           O                   O
4902  *  b4: t->sw[i  ][j  ][k+1]      . .       O
4903  *  b5:                           .   .
4904  *  b6: t->sw[i  ][j+1][k+1]      .     .
4905  *  b7: t->sw[i+1][j+1][k+1]      .       .
4906  *                                .         O
4907  *                                O         .         O
4908  *                                  .       .
4909  *                                    .     .
4910  *                                      .   .
4911  *                                        . .
4912  *                                          @
4913  */
4914 static
4915 bool handle_case_0x72a(struct torus *t, int i, int j, int k)
4916 {
4917         int ip1 = canonicalize(i + 1, t->x_sz);
4918         int jp1 = canonicalize(j + 1, t->y_sz);
4919         int kp1 = canonicalize(k + 1, t->z_sz);
4920
4921         if (install_tswitch(t, ip1, jp1, k,
4922                             tfind_face_corner(t->sw[i][jp1][k],
4923                                               t->sw[i][jp1][kp1],
4924                                               t->sw[ip1][jp1][kp1]))) {
4925                 return true;
4926         }
4927         log_no_crnr(t, 0x72a, i, j, k, ip1, jp1, k);
4928
4929         if (install_tswitch(t, ip1, j, kp1,
4930                             tfind_face_corner(t->sw[i][j][kp1],
4931                                               t->sw[i][jp1][kp1],
4932                                               t->sw[ip1][jp1][kp1]))) {
4933                 return true;
4934         }
4935         log_no_crnr(t, 0x72a, i, j, k, ip1, j, kp1);
4936         return false;
4937 }
4938
4939 /*
4940  * 3D case 0x731:                           O
4941  *                                        . .
4942  *  b0:                                 .   .
4943  *  b1: t->sw[i+1][j  ][k  ]          .     .
4944  *  b2: t->sw[i  ][j+1][k  ]        .       .
4945  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
4946  *  b4:                           .         O
4947  *  b5:                           .       .   .
4948  *  b6: t->sw[i  ][j+1][k+1]      .     .       .
4949  *  b7: t->sw[i+1][j+1][k+1]      .   .           .
4950  *                                . .       O       .
4951  *                                O                   O
4952  *
4953  *
4954  *
4955  *
4956  *                                          @
4957  */
4958 static
4959 bool handle_case_0x731(struct torus *t, int i, int j, int k)
4960 {
4961         int ip1 = canonicalize(i + 1, t->x_sz);
4962         int jp1 = canonicalize(j + 1, t->y_sz);
4963         int kp1 = canonicalize(k + 1, t->z_sz);
4964
4965         if (install_tswitch(t, i, j, k,
4966                             tfind_face_corner(t->sw[ip1][j][k],
4967                                               t->sw[ip1][jp1][k],
4968                                               t->sw[i][jp1][k]))) {
4969                 return true;
4970         }
4971         log_no_crnr(t, 0x731, i, j, k, i, j, k);
4972
4973         if (install_tswitch(t, ip1, j, kp1,
4974                             tfind_face_corner(t->sw[ip1][j][k],
4975                                               t->sw[ip1][jp1][k],
4976                                               t->sw[ip1][jp1][kp1]))) {
4977                 return true;
4978         }
4979         log_no_crnr(t, 0x731, i, j, k, ip1, j, kp1);
4980         return false;
4981 }
4982
4983 /*
4984  * 3D case 0x732:                           O
4985  *                                        . .
4986  *  b0: t->sw[i  ][j  ][k  ]            .   .
4987  *  b1:                               .     .
4988  *  b2: t->sw[i  ][j+1][k  ]        .       .
4989  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
4990  *  b4:                           .         O
4991  *  b5:                           .       .
4992  *  b6: t->sw[i  ][j+1][k+1]      .     .
4993  *  b7: t->sw[i+1][j+1][k+1]      .   .
4994  *                                . .       O
4995  *                                O                   O
4996  *                                  .
4997  *                                    .
4998  *                                      .
4999  *                                        .
5000  *                                          @
5001  */
5002 static
5003 bool handle_case_0x732(struct torus *t, int i, int j, int k)
5004 {
5005         int ip1 = canonicalize(i + 1, t->x_sz);
5006         int jp1 = canonicalize(j + 1, t->y_sz);
5007         int kp1 = canonicalize(k + 1, t->z_sz);
5008
5009         if (install_tswitch(t, ip1, j, k,
5010                             tfind_face_corner(t->sw[i][j][k],
5011                                               t->sw[i][jp1][k],
5012                                               t->sw[ip1][jp1][k]))) {
5013                 return true;
5014         }
5015         log_no_crnr(t, 0x732, i, j, k, ip1, j, k);
5016
5017         if (install_tswitch(t, i, j, kp1,
5018                             tfind_face_corner(t->sw[i][j][k],
5019                                               t->sw[i][jp1][k],
5020                                               t->sw[i][jp1][kp1]))) {
5021                 return true;
5022         }
5023         log_no_crnr(t, 0x732, i, j, k, i, j, kp1);
5024         return false;
5025 }
5026
5027 /*
5028  * 3D case 0x745:                           O
5029  *                                          . .
5030  *  b0:                                     .   .
5031  *  b1: t->sw[i+1][j  ][k  ]                .     .
5032  *  b2:                                     .       .
5033  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
5034  *  b4: t->sw[i  ][j  ][k+1]                O       . .
5035  *  b5: t->sw[i+1][j  ][k+1]                  .   .   .
5036  *  b6:                                         .     .
5037  *  b7: t->sw[i+1][j+1][k+1]                  .   .   .
5038  *                                          O       . .
5039  *                                O                   O
5040  *
5041  *
5042  *
5043  *
5044  *                                          @
5045  */
5046 static
5047 bool handle_case_0x745(struct torus *t, int i, int j, int k)
5048 {
5049         int ip1 = canonicalize(i + 1, t->x_sz);
5050         int jp1 = canonicalize(j + 1, t->y_sz);
5051         int kp1 = canonicalize(k + 1, t->z_sz);
5052
5053         if (install_tswitch(t, i, j, k,
5054                             tfind_face_corner(t->sw[ip1][j][k],
5055                                               t->sw[ip1][j][kp1],
5056                                               t->sw[i][j][kp1]))) {
5057                 return true;
5058         }
5059         log_no_crnr(t, 0x745, i, j, k, i, j, k);
5060
5061         if (install_tswitch(t, i, jp1, kp1,
5062                             tfind_face_corner(t->sw[i][j][kp1],
5063                                               t->sw[ip1][j][kp1],
5064                                               t->sw[ip1][jp1][kp1]))) {
5065                 return true;
5066         }
5067         log_no_crnr(t, 0x745, i, j, k, i, jp1, kp1);
5068         return false;
5069 }
5070
5071 /*
5072  * 3D case 0x74c:                           O
5073  *                                            .
5074  *  b0: t->sw[i  ][j  ][k  ]                    .
5075  *  b1: t->sw[i+1][j  ][k  ]                      .
5076  *  b2:                                             .
5077  *  b3:                           O                   O
5078  *  b4: t->sw[i  ][j  ][k+1]                O       . .
5079  *  b5: t->sw[i+1][j  ][k+1]                      .   .
5080  *  b6:                                         .     .
5081  *  b7: t->sw[i+1][j+1][k+1]                  .       .
5082  *                                          O         .
5083  *                                O         .         O
5084  *                                          .       .
5085  *                                          .     .
5086  *                                          .   .
5087  *                                          . .
5088  *                                          @
5089  */
5090 static
5091 bool handle_case_0x74c(struct torus *t, int i, int j, int k)
5092 {
5093         int ip1 = canonicalize(i + 1, t->x_sz);
5094         int jp1 = canonicalize(j + 1, t->y_sz);
5095         int kp1 = canonicalize(k + 1, t->z_sz);
5096
5097         if (install_tswitch(t, ip1, jp1, k,
5098                             tfind_face_corner(t->sw[ip1][j][k],
5099                                               t->sw[ip1][j][kp1],
5100                                               t->sw[ip1][jp1][kp1]))) {
5101                 return true;
5102         }
5103         log_no_crnr(t, 0x74c, i, j, k, ip1, jp1, k);
5104
5105         if (install_tswitch(t, i, jp1, kp1,
5106                             tfind_face_corner(t->sw[i][j][kp1],
5107                                               t->sw[ip1][j][kp1],
5108                                               t->sw[ip1][jp1][kp1]))) {
5109                 return true;
5110         }
5111         log_no_crnr(t, 0x74c, i, j, k, i, jp1, kp1);
5112         return false;
5113 }
5114
5115 /*
5116  * 3D case 0x751:                           O
5117  *                                          . .
5118  *  b0:                                     .   .
5119  *  b1: t->sw[i+1][j  ][k  ]                .     .
5120  *  b2: t->sw[i  ][j+1][k  ]                .       .
5121  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
5122  *  b4:                                     O         .
5123  *  b5: t->sw[i+1][j  ][k+1]              .   .       .
5124  *  b6:                                 .       .     .
5125  *  b7: t->sw[i+1][j+1][k+1]          .           .   .
5126  *                                  .       O       . .
5127  *                                O                   O
5128  *
5129  *
5130  *
5131  *
5132  *                                          @
5133  */
5134 static
5135 bool handle_case_0x751(struct torus *t, int i, int j, int k)
5136 {
5137         int ip1 = canonicalize(i + 1, t->x_sz);
5138         int jp1 = canonicalize(j + 1, t->y_sz);
5139         int kp1 = canonicalize(k + 1, t->z_sz);
5140
5141         if (install_tswitch(t, i, j, k,
5142                             tfind_face_corner(t->sw[ip1][j][k],
5143                                               t->sw[ip1][jp1][k],
5144                                               t->sw[i][jp1][k]))) {
5145                 return true;
5146         }
5147         log_no_crnr(t, 0x751, i, j, k, i, j, k);
5148
5149         if (install_tswitch(t, i, jp1, kp1,
5150                             tfind_face_corner(t->sw[i][jp1][k],
5151                                               t->sw[ip1][jp1][k],
5152                                               t->sw[ip1][jp1][kp1]))) {
5153                 return true;
5154         }
5155         log_no_crnr(t, 0x751, i, j, k, i, jp1, kp1);
5156         return false;
5157 }
5158
5159 /*
5160  * 3D case 0x754:                           O
5161  *                                          . .
5162  *  b0: t->sw[i  ][j  ][k  ]                .   .
5163  *  b1: t->sw[i+1][j  ][k  ]                .     .
5164  *  b2:                                     .       .
5165  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
5166  *  b4:                                     O         .
5167  *  b5: t->sw[i+1][j  ][k+1]                  .       .
5168  *  b6:                                         .     .
5169  *  b7: t->sw[i+1][j+1][k+1]                      .   .
5170  *                                          O       . .
5171  *                                O                   O
5172  *                                                  .
5173  *                                                .
5174  *                                              .
5175  *                                            .
5176  *                                          @
5177  */
5178 static
5179 bool handle_case_0x754(struct torus *t, int i, int j, int k)
5180 {
5181         int ip1 = canonicalize(i + 1, t->x_sz);
5182         int jp1 = canonicalize(j + 1, t->y_sz);
5183         int kp1 = canonicalize(k + 1, t->z_sz);
5184
5185         if (install_tswitch(t, i, jp1, k,
5186                             tfind_face_corner(t->sw[i][j][k],
5187                                               t->sw[ip1][j][k],
5188                                               t->sw[ip1][jp1][k]))) {
5189                 return true;
5190         }
5191         log_no_crnr(t, 0x754, i, j, k, i, jp1, k);
5192
5193         if (install_tswitch(t, i, j, kp1,
5194                             tfind_face_corner(t->sw[i][j][k],
5195                                               t->sw[ip1][j][k],
5196                                               t->sw[ip1][j][kp1]))) {
5197                 return true;
5198         }
5199         log_no_crnr(t, 0x754, i, j, k, i, j, kp1);
5200         return false;
5201 }
5202
5203 /*
5204  * 3D case 0x770:                           O
5205  *                                          .
5206  *  b0: t->sw[i  ][j  ][k  ]                .
5207  *  b1: t->sw[i+1][j  ][k  ]                .
5208  *  b2: t->sw[i  ][j+1][k  ]                .
5209  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
5210  *  b4:                                     O
5211  *  b5:                                   .   .
5212  *  b6:                                 .       .
5213  *  b7: t->sw[i+1][j+1][k+1]          .           .
5214  *                                  .       O       .
5215  *                                O                   O
5216  *                                  .               .
5217  *                                    .           .
5218  *                                      .       .
5219  *                                        .   .
5220  *                                          @
5221  */
5222 static
5223 bool handle_case_0x770(struct torus *t, int i, int j, int k)
5224 {
5225         int ip1 = canonicalize(i + 1, t->x_sz);
5226         int jp1 = canonicalize(j + 1, t->y_sz);
5227         int kp1 = canonicalize(k + 1, t->z_sz);
5228
5229         if (install_tswitch(t, ip1, j, kp1,
5230                             tfind_face_corner(t->sw[ip1][j][k],
5231                                               t->sw[ip1][jp1][k],
5232                                               t->sw[ip1][jp1][kp1]))) {
5233                 return true;
5234         }
5235         log_no_crnr(t, 0x770, i, j, k, ip1, j, kp1);
5236
5237         if (install_tswitch(t, i, jp1, kp1,
5238                             tfind_face_corner(t->sw[i][jp1][k],
5239                                               t->sw[ip1][jp1][k],
5240                                               t->sw[ip1][jp1][kp1]))) {
5241                 return true;
5242         }
5243         log_no_crnr(t, 0x770, i, j, k, i, jp1, kp1);
5244         return false;
5245 }
5246
5247 /*
5248  * 3D case 0x78a:                           O
5249  *
5250  *  b0: t->sw[i  ][j  ][k  ]
5251  *  b1:
5252  *  b2: t->sw[i  ][j+1][k  ]
5253  *  b3:                           O                   O
5254  *  b4: t->sw[i  ][j  ][k+1]      . .       O       .
5255  *  b5: t->sw[i+1][j  ][k+1]      .   .           .
5256  *  b6: t->sw[i  ][j+1][k+1]      .     .       .
5257  *  b7:                           .       .   .
5258  *                                .         O
5259  *                                O         .         O
5260  *                                  .       .
5261  *                                    .     .
5262  *                                      .   .
5263  *                                        . .
5264  *                                          @
5265  */
5266 static
5267 bool handle_case_0x78a(struct torus *t, int i, int j, int k)
5268 {
5269         int ip1 = canonicalize(i + 1, t->x_sz);
5270         int jp1 = canonicalize(j + 1, t->y_sz);
5271         int kp1 = canonicalize(k + 1, t->z_sz);
5272
5273         if (install_tswitch(t, ip1, j, k,
5274                             tfind_face_corner(t->sw[i][j][k],
5275                                               t->sw[i][j][kp1],
5276                                               t->sw[ip1][j][kp1]))) {
5277                 return true;
5278         }
5279         log_no_crnr(t, 0x78a, i, j, k, ip1, j, k);
5280
5281         if (install_tswitch(t, ip1, jp1, kp1,
5282                             tfind_face_corner(t->sw[ip1][j][kp1],
5283                                               t->sw[i][j][kp1],
5284                                               t->sw[i][jp1][kp1]))) {
5285                 return true;
5286         }
5287         log_no_crnr(t, 0x78a, i, j, k, ip1, jp1, kp1);
5288         return false;
5289 }
5290
5291 /*
5292  * 3D case 0x78c:                           O
5293  *
5294  *  b0: t->sw[i  ][j  ][k  ]
5295  *  b1: t->sw[i+1][j  ][k  ]
5296  *  b2:
5297  *  b3:                           O                   O
5298  *  b4: t->sw[i  ][j  ][k+1]        .       O       . .
5299  *  b5: t->sw[i+1][j  ][k+1]          .           .   .
5300  *  b6: t->sw[i  ][j+1][k+1]            .       .     .
5301  *  b7:                                   .   .       .
5302  *                                          O         .
5303  *                                O         .         O
5304  *                                          .       .
5305  *                                          .     .
5306  *                                          .   .
5307  *                                          . .
5308  *                                          @
5309  */
5310 static
5311 bool handle_case_0x78c(struct torus *t, int i, int j, int k)
5312 {
5313         int ip1 = canonicalize(i + 1, t->x_sz);
5314         int jp1 = canonicalize(j + 1, t->y_sz);
5315         int kp1 = canonicalize(k + 1, t->z_sz);
5316
5317         if (install_tswitch(t, i, jp1, k,
5318                             tfind_face_corner(t->sw[i][j][k],
5319                                               t->sw[i][j][kp1],
5320                                               t->sw[i][jp1][kp1]))) {
5321                 return true;
5322         }
5323         log_no_crnr(t, 0x78c, i, j, k, i, jp1, k);
5324
5325         if (install_tswitch(t, ip1, jp1, kp1,
5326                             tfind_face_corner(t->sw[ip1][j][kp1],
5327                                               t->sw[i][j][kp1],
5328                                               t->sw[i][jp1][kp1]))) {
5329                 return true;
5330         }
5331         log_no_crnr(t, 0x78c, i, j, k, ip1, jp1, kp1);
5332         return false;
5333 }
5334
5335 /*
5336  * 3D case 0x7a2:                           O
5337  *
5338  *  b0: t->sw[i  ][j  ][k  ]
5339  *  b1:
5340  *  b2: t->sw[i  ][j+1][k  ]
5341  *  b3: t->sw[i+1][j+1][k  ]      O                   O
5342  *  b4: t->sw[i  ][j  ][k+1]      . .       O
5343  *  b5:                           .   .   .
5344  *  b6: t->sw[i  ][j+1][k+1]      .     .
5345  *  b7:                           .   .   .
5346  *                                . .       O
5347  *                                O         .         O
5348  *                                  .       .
5349  *                                    .     .
5350  *                                      .   .
5351  *                                        . .
5352  *                                          @
5353  */
5354 static
5355 bool handle_case_0x7a2(struct torus *t, int i, int j, int k)
5356 {
5357         int ip1 = canonicalize(i + 1, t->x_sz);
5358         int jp1 = canonicalize(j + 1, t->y_sz);
5359         int kp1 = canonicalize(k + 1, t->z_sz);
5360
5361         if (install_tswitch(t, ip1, j, k,
5362                             tfind_face_corner(t->sw[i][j][k],
5363                                               t->sw[i][jp1][k],
5364                                               t->sw[ip1][jp1][k]))) {
5365                 return true;
5366         }
5367         log_no_crnr(t, 0x7a2, i, j, k, ip1, j, k);
5368
5369         if (install_tswitch(t, ip1, jp1, kp1,
5370                             tfind_face_corner(t->sw[i][jp1][kp1],
5371                                               t->sw[i][jp1][k],
5372                                               t->sw[ip1][jp1][k]))) {
5373                 return true;
5374         }
5375         log_no_crnr(t, 0x7a2, i, j, k, ip1, jp1, kp1);
5376         return false;
5377 }
5378
5379 /*
5380  * 3D case 0x7a8:                           O
5381  *
5382  *  b0: t->sw[i  ][j  ][k  ]
5383  *  b1: t->sw[ip1][j  ][k  ]
5384  *  b2: t->sw[i  ][j+1][k  ]
5385  *  b3:                           O                   O
5386  *  b4: t->sw[i  ][j  ][k+1]      . .       O
5387  *  b5:                           .   .
5388  *  b6: t->sw[i  ][j+1][k+1]      .     .
5389  *  b7:                           .       .
5390  *                                .         O
5391  *                                O         .         O
5392  *                                  .       .       .
5393  *                                    .     .     .
5394  *                                      .   .   .
5395  *                                        . . .
5396  *                                          @
5397  */
5398 static
5399 bool handle_case_0x7a8(struct torus *t, int i, int j, int k)
5400 {
5401         int ip1 = canonicalize(i + 1, t->x_sz);
5402         int jp1 = canonicalize(j + 1, t->y_sz);
5403         int kp1 = canonicalize(k + 1, t->z_sz);
5404
5405         if (install_tswitch(t, ip1, jp1, k,
5406                             tfind_face_corner(t->sw[ip1][j][k],
5407                                               t->sw[i][j][k],
5408                                               t->sw[i][jp1][k]))) {
5409                 return true;
5410         }
5411         log_no_crnr(t, 0x7a8, i, j, k, ip1, jp1, k);
5412
5413         if (install_tswitch(t, ip1, j, kp1,
5414                             tfind_face_corner(t->sw[i][j][kp1],
5415                                               t->sw[i][j][k],
5416                                               t->sw[ip1][j][k]))) {
5417                 return true;
5418         }
5419         log_no_crnr(t, 0x7a8, i, j, k, ip1, j, kp1);
5420         return false;
5421 }
5422
5423 /*
5424  * 3D case 0x7b0:                           O
5425  *
5426  *  b0: t->sw[i  ][j  ][k  ]
5427  *  b1: t->sw[i+1][j  ][k  ]
5428  *  b2: t->sw[i  ][j+1][k  ]
5429  *  b3: t->sw[i+1][j+1][k  ]      O                   O
5430  *  b4:                           .         O
5431  *  b5:                           .       .   .
5432  *  b6: t->sw[i  ][j+1][k+1]      .     .       .
5433  *  b7:                           .   .           .
5434  *                                . .       O       .
5435  *                                O                   O
5436  *                                  .               .
5437  *                                    .           .
5438  *                                      .       .
5439  *                                        .   .
5440  *                                          @
5441  */
5442 static
5443 bool handle_case_0x7b0(struct torus *t, int i, int j, int k)
5444 {
5445         int ip1 = canonicalize(i + 1, t->x_sz);
5446         int jp1 = canonicalize(j + 1, t->y_sz);
5447         int kp1 = canonicalize(k + 1, t->z_sz);
5448
5449         if (install_tswitch(t, i, j, kp1,
5450                             tfind_face_corner(t->sw[i][j][k],
5451                                               t->sw[i][jp1][k],
5452                                               t->sw[i][jp1][kp1]))) {
5453                 return true;
5454         }
5455         log_no_crnr(t, 0x7b0, i, j, k, i, j, kp1);
5456
5457         if (install_tswitch(t, ip1, jp1, kp1,
5458                             tfind_face_corner(t->sw[i][jp1][kp1],
5459                                               t->sw[i][jp1][k],
5460                                               t->sw[ip1][jp1][k]))) {
5461                 return true;
5462         }
5463         log_no_crnr(t, 0x7b0, i, j, k, ip1, jp1, kp1);
5464         return false;
5465 }
5466
5467 /*
5468  * 3D case 0x7c4:                           O
5469  *
5470  *  b0: t->sw[i  ][j  ][k  ]
5471  *  b1: t->sw[i+1][j  ][k  ]
5472  *  b2:
5473  *  b3: t->sw[i+1][j+1][k  ]      O                   O
5474  *  b4: t->sw[i  ][j  ][k+1]                O       . .
5475  *  b5: t->sw[i+1][j  ][k+1]                  .   .   .
5476  *  b6:                                         .     .
5477  *  b7:                                       .   .   .
5478  *                                          O       . .
5479  *                                O         .         O
5480  *                                          .       .
5481  *                                          .     .
5482  *                                          .   .
5483  *                                          . .
5484  *                                          @
5485  */
5486 static
5487 bool handle_case_0x7c4(struct torus *t, int i, int j, int k)
5488 {
5489         int ip1 = canonicalize(i + 1, t->x_sz);
5490         int jp1 = canonicalize(j + 1, t->y_sz);
5491         int kp1 = canonicalize(k + 1, t->z_sz);
5492
5493         if (install_tswitch(t, i, jp1, k,
5494                             tfind_face_corner(t->sw[i][j][k],
5495                                               t->sw[ip1][j][k],
5496                                               t->sw[ip1][jp1][k]))) {
5497                 return true;
5498         }
5499         log_no_crnr(t, 0x7c4, i, j, k, i, jp1, k);
5500
5501         if (install_tswitch(t, ip1, jp1, kp1,
5502                             tfind_face_corner(t->sw[ip1][j][kp1],
5503                                               t->sw[ip1][j][k],
5504                                               t->sw[ip1][jp1][k]))) {
5505                 return true;
5506         }
5507         log_no_crnr(t, 0x7c4, i, j, k, ip1, jp1, kp1);
5508         return false;
5509 }
5510
5511 /*
5512  * 3D case 0x7c8:                           O
5513  *
5514  *  b0: t->sw[i  ][j  ][k  ]
5515  *  b1: t->sw[i+1][j  ][k  ]
5516  *  b2: t->sw[i  ][j+1][k  ]
5517  *  b3:                           O                   O
5518  *  b4: t->sw[i  ][j  ][k+1]                O       . .
5519  *  b5: t->sw[i+1][j  ][k+1]                      .   .
5520  *  b6:                                         .     .
5521  *  b7:                                       .       .
5522  *                                          O         .
5523  *                                O         .         O
5524  *                                  .       .       .
5525  *                                    .     .     .
5526  *                                      .   .   .
5527  *                                        . . .
5528  *                                          @
5529  */
5530 static
5531 bool handle_case_0x7c8(struct torus *t, int i, int j, int k)
5532 {
5533         int ip1 = canonicalize(i + 1, t->x_sz);
5534         int jp1 = canonicalize(j + 1, t->y_sz);
5535         int kp1 = canonicalize(k + 1, t->z_sz);
5536
5537         if (install_tswitch(t, ip1, jp1, k,
5538                             tfind_face_corner(t->sw[ip1][j][k],
5539                                               t->sw[i][j][k],
5540                                               t->sw[i][jp1][k]))) {
5541                 return true;
5542         }
5543         log_no_crnr(t, 0x7c8, i, j, k, ip1, jp1, k);
5544
5545         if (install_tswitch(t, i, jp1, kp1,
5546                             tfind_face_corner(t->sw[i][j][kp1],
5547                                               t->sw[i][j][k],
5548                                               t->sw[i][jp1][k]))) {
5549                 return true;
5550         }
5551         log_no_crnr(t, 0x7c8, i, j, k, i, jp1, kp1);
5552         return false;
5553 }
5554
5555 /*
5556  * 3D case 0x7d0:                           O
5557  *
5558  *  b0: t->sw[i  ][j  ][k  ]
5559  *  b1: t->sw[i+1][j  ][k  ]
5560  *  b2: t->sw[i  ][j+1][k  ]
5561  *  b3: t->sw[i+1][j+1][k  ]      O                   O
5562  *  b4:                                     O         .
5563  *  b5: t->sw[i+1][j  ][k+1]              .   .       .
5564  *  b6:                                 .       .     .
5565  *  b7:                               .           .   .
5566  *                                  .       O       . .
5567  *                                O                   O
5568  *                                  .               .
5569  *                                    .           .
5570  *                                      .       .
5571  *                                        .   .
5572  *                                          @
5573  */
5574 static
5575 bool handle_case_0x7d0(struct torus *t, int i, int j, int k)
5576 {
5577         int ip1 = canonicalize(i + 1, t->x_sz);
5578         int jp1 = canonicalize(j + 1, t->y_sz);
5579         int kp1 = canonicalize(k + 1, t->z_sz);
5580
5581         if (install_tswitch(t, i, j, kp1,
5582                             tfind_face_corner(t->sw[i][j][k],
5583                                               t->sw[ip1][j][k],
5584                                               t->sw[ip1][j][kp1]))) {
5585                 return true;
5586         }
5587         log_no_crnr(t, 0x7d0, i, j, k, i, j, kp1);
5588
5589         if (install_tswitch(t, ip1, jp1, kp1,
5590                             tfind_face_corner(t->sw[ip1][j][kp1],
5591                                               t->sw[ip1][j][k],
5592                                               t->sw[ip1][jp1][k]))) {
5593                 return true;
5594         }
5595         log_no_crnr(t, 0x7d0, i, j, k, ip1, jp1, kp1);
5596         return false;
5597 }
5598
5599 /*
5600  * 3D case 0x7e0:                           O
5601  *
5602  *  b0: t->sw[i  ][j  ][k  ]
5603  *  b1: t->sw[i+1][j  ][k  ]
5604  *  b2: t->sw[i  ][j+1][k  ]
5605  *  b3: t->sw[i+1][j+1][k  ]      O                   O
5606  *  b4: t->sw[i  ][j  ][k+1]                O
5607  *  b5:                                   .   .
5608  *  b6:                                 .       .
5609  *  b7:                               .           .
5610  *                                  .       O       .
5611  *                                O         .         O
5612  *                                  .       .       .
5613  *                                    .     .     .
5614  *                                      .   .   .
5615  *                                        . . .
5616  *                                          @
5617  */
5618 static
5619 bool handle_case_0x7e0(struct torus *t, int i, int j, int k)
5620 {
5621         int ip1 = canonicalize(i + 1, t->x_sz);
5622         int jp1 = canonicalize(j + 1, t->y_sz);
5623         int kp1 = canonicalize(k + 1, t->z_sz);
5624
5625         if (install_tswitch(t, ip1, j, kp1,
5626                             tfind_face_corner(t->sw[i][j][kp1],
5627                                               t->sw[i][j][k],
5628                                               t->sw[ip1][j][k]))) {
5629                 return true;
5630         }
5631         log_no_crnr(t, 0x7e0, i, j, k, ip1, j, kp1);
5632
5633         if (install_tswitch(t, i, jp1, kp1,
5634                             tfind_face_corner(t->sw[i][j][kp1],
5635                                               t->sw[i][j][k],
5636                                               t->sw[i][jp1][k]))) {
5637                 return true;
5638         }
5639         log_no_crnr(t, 0x7e0, i, j, k, i, jp1, kp1);
5640         return false;
5641 }
5642
5643 /*
5644  * Handle the cases where two corners on a single edge are missing.
5645  */
5646
5647 /*
5648  * 3D case 0x703:                           O
5649  *                                        . . .
5650  *  b0:                                 .   .   .
5651  *  b1:                               .     .     .
5652  *  b2: t->sw[i  ][j+1][k  ]        .       .       .
5653  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
5654  *  b4: t->sw[i  ][j  ][k+1]      . .       O       .
5655  *  b5: t->sw[i+1][j  ][k+1]      .   .   .       .
5656  *  b6: t->sw[i  ][j+1][k+1]      .     .       .
5657  *  b7: t->sw[i+1][j+1][k+1]      .   .   .   .
5658  *                                . .       O
5659  *                                O                   O
5660  *
5661  *
5662  *
5663  *
5664  *                                          @
5665  */
5666 static
5667 bool handle_case_0x703(struct torus *t, int i, int j, int k)
5668 {
5669         int ip1 = canonicalize(i + 1, t->x_sz);
5670         int jp1 = canonicalize(j + 1, t->y_sz);
5671         int kp1 = canonicalize(k + 1, t->z_sz);
5672
5673         if (install_tswitch(t, i, j, k,
5674                             tfind_face_corner(t->sw[i][jp1][k],
5675                                               t->sw[i][jp1][kp1],
5676                                               t->sw[i][j][kp1]))) {
5677                 return true;
5678         }
5679         log_no_crnr(t, 0x703, i, j, k, i, j, k);
5680
5681         if (install_tswitch(t, ip1, j, k,
5682                             tfind_face_corner(t->sw[ip1][jp1][k],
5683                                               t->sw[ip1][jp1][kp1],
5684                                               t->sw[ip1][j][kp1]))) {
5685                 return true;
5686         }
5687         log_no_crnr(t, 0x703, i, j, k, ip1, j, k);
5688         return false;
5689 }
5690
5691 /*
5692  * 3D case 0x705:                           O
5693  *                                        . . .
5694  *  b0:                                 .   .   .
5695  *  b1: t->sw[i+1][j  ][k  ]          .     .     .
5696  *  b2:                             .       .       .
5697  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
5698  *  b4: t->sw[i  ][j  ][k+1]        .       O       . .
5699  *  b5: t->sw[i+1][j  ][k+1]          .       .   .   .
5700  *  b6: t->sw[i  ][j+1][k+1]            .       .     .
5701  *  b7: t->sw[i+1][j+1][k+1]              .   .   .   .
5702  *                                          O       . .
5703  *                                O                   O
5704  *
5705  *
5706  *
5707  *
5708  *                                          @
5709  */
5710 static
5711 bool handle_case_0x705(struct torus *t, int i, int j, int k)
5712 {
5713         int ip1 = canonicalize(i + 1, t->x_sz);
5714         int jp1 = canonicalize(j + 1, t->y_sz);
5715         int kp1 = canonicalize(k + 1, t->z_sz);
5716
5717         if (install_tswitch(t, i, j, k,
5718                             tfind_face_corner(t->sw[ip1][j][k],
5719                                               t->sw[ip1][j][kp1],
5720                                               t->sw[i][j][kp1]))) {
5721                 return true;
5722         }
5723         log_no_crnr(t, 0x705, i, j, k, i, j, k);
5724
5725         if (install_tswitch(t, i, jp1, k,
5726                             tfind_face_corner(t->sw[ip1][jp1][k],
5727                                               t->sw[ip1][jp1][kp1],
5728                                               t->sw[i][jp1][kp1]))) {
5729                 return true;
5730         }
5731         log_no_crnr(t, 0x705, i, j, k, i, jp1, k);
5732         return false;
5733 }
5734
5735 /*
5736  * 3D case 0x70a:                           O
5737  *                                        . . .
5738  *  b0: t->sw[i  ][j  ][k  ]            .       .
5739  *  b1:                               .           .
5740  *  b2: t->sw[i  ][j+1][k  ]        .               .
5741  *  b3:                           O                   O
5742  *  b4: t->sw[i  ][j  ][k+1]      . .       O       .
5743  *  b5: t->sw[i+1][j  ][k+1]      .   .           .
5744  *  b6: t->sw[i  ][j+1][k+1]      .     .       .
5745  *  b7: t->sw[i+1][j+1][k+1]      .       .   .
5746  *                                .         O
5747  *                                O         .         O
5748  *                                  .       .
5749  *                                    .     .
5750  *                                      .   .
5751  *                                        . .
5752  *                                          @
5753  */
5754 static
5755 bool handle_case_0x70a(struct torus *t, int i, int j, int k)
5756 {
5757         int ip1 = canonicalize(i + 1, t->x_sz);
5758         int jp1 = canonicalize(j + 1, t->y_sz);
5759         int kp1 = canonicalize(k + 1, t->z_sz);
5760
5761         if (install_tswitch(t, ip1, j, k,
5762                             tfind_face_corner(t->sw[i][j][k],
5763                                               t->sw[i][j][kp1],
5764                                               t->sw[ip1][j][kp1]))) {
5765                 return true;
5766         }
5767         log_no_crnr(t, 0x70a, i, j, k, ip1, j, k);
5768
5769         if (install_tswitch(t, ip1, jp1, k,
5770                             tfind_face_corner(t->sw[i][jp1][k],
5771                                               t->sw[i][jp1][kp1],
5772                                               t->sw[ip1][jp1][kp1]))) {
5773                 return true;
5774         }
5775         log_no_crnr(t, 0x70a, i, j, k, ip1, jp1, k);
5776         return false;
5777 }
5778
5779 /*
5780  * 3D case 0x70c:                           O
5781  *                                        .   .
5782  *  b0: t->sw[i  ][j  ][k  ]            .       .
5783  *  b1: t->sw[i+1][j  ][k  ]          .           .
5784  *  b2:                             .               .
5785  *  b3:                           O                   O
5786  *  b4: t->sw[i  ][j  ][k+1]        .       O       . .
5787  *  b5: t->sw[i+1][j  ][k+1]          .           .   .
5788  *  b6: t->sw[i  ][j+1][k+1]            .       .     .
5789  *  b7: t->sw[i+1][j+1][k+1]              .   .       .
5790  *                                          O         .
5791  *                                O         .         O
5792  *                                          .       .
5793  *                                          .     .
5794  *                                          .   .
5795  *                                          . .
5796  *                                          @
5797  */
5798 static
5799 bool handle_case_0x70c(struct torus *t, int i, int j, int k)
5800 {
5801         int ip1 = canonicalize(i + 1, t->x_sz);
5802         int jp1 = canonicalize(j + 1, t->y_sz);
5803         int kp1 = canonicalize(k + 1, t->z_sz);
5804
5805         if (install_tswitch(t, i, jp1, k,
5806                             tfind_face_corner(t->sw[i][j][k],
5807                                               t->sw[i][j][kp1],
5808                                               t->sw[i][jp1][kp1]))) {
5809                 return true;
5810         }
5811         log_no_crnr(t, 0x70c, i, j, k, i, jp1, k);
5812
5813         if (install_tswitch(t, ip1, jp1, k,
5814                             tfind_face_corner(t->sw[ip1][j][k],
5815                                               t->sw[ip1][j][kp1],
5816                                               t->sw[ip1][jp1][kp1]))) {
5817                 return true;
5818         }
5819         log_no_crnr(t, 0x70c, i, j, k, ip1, jp1, k);
5820         return false;
5821 }
5822
5823 /*
5824  * 3D case 0x711:                           O
5825  *                                        . . .
5826  *  b0:                                 .   .   .
5827  *  b1: t->sw[i+1][j  ][k  ]          .     .     .
5828  *  b2: t->sw[i  ][j+1][k  ]        .       .       .
5829  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
5830  *  b4:                           .         O         .
5831  *  b5: t->sw[i+1][j  ][k+1]      .       .   .       .
5832  *  b6: t->sw[i  ][j+1][k+1]      .     .       .     .
5833  *  b7: t->sw[i+1][j+1][k+1]      .   .           .   .
5834  *                                . .       O       . .
5835  *                                O                   O
5836  *
5837  *
5838  *
5839  *
5840  *                                          @
5841  */
5842 static
5843 bool handle_case_0x711(struct torus *t, int i, int j, int k)
5844 {
5845         int ip1 = canonicalize(i + 1, t->x_sz);
5846         int jp1 = canonicalize(j + 1, t->y_sz);
5847         int kp1 = canonicalize(k + 1, t->z_sz);
5848
5849         if (install_tswitch(t, i, j, k,
5850                             tfind_face_corner(t->sw[ip1][j][k],
5851                                               t->sw[ip1][jp1][k],
5852                                               t->sw[i][jp1][k]))) {
5853                 return true;
5854         }
5855         log_no_crnr(t, 0x711, i, j, k, i, j, k);
5856
5857         if (install_tswitch(t, i, j, kp1,
5858                             tfind_face_corner(t->sw[ip1][j][kp1],
5859                                               t->sw[ip1][jp1][kp1],
5860                                               t->sw[i][jp1][kp1]))) {
5861                 return true;
5862         }
5863         log_no_crnr(t, 0x711, i, j, k, i, j, kp1);
5864         return false;
5865 }
5866
5867 /*
5868  * 3D case 0x722:                           O
5869  *                                        . .
5870  *  b0: t->sw[i  ][j  ][k  ]            .   .
5871  *  b1:                               .     .
5872  *  b2: t->sw[i  ][j+1][k  ]        .       .
5873  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
5874  *  b4: t->sw[i  ][j  ][k+1]      . .       O
5875  *  b5:                           .   .   .
5876  *  b6: t->sw[i  ][j+1][k+1]      .     .
5877  *  b7: t->sw[i+1][j+1][k+1]      .   .   .
5878  *                                . .       O
5879  *                                O         .         O
5880  *                                  .       .
5881  *                                    .     .
5882  *                                      .   .
5883  *                                        . .
5884  *                                          @
5885  */
5886 static
5887 bool handle_case_0x722(struct torus *t, int i, int j, int k)
5888 {
5889         int ip1 = canonicalize(i + 1, t->x_sz);
5890         int jp1 = canonicalize(j + 1, t->y_sz);
5891         int kp1 = canonicalize(k + 1, t->z_sz);
5892
5893         if (install_tswitch(t, ip1, j, k,
5894                             tfind_face_corner(t->sw[i][j][k],
5895                                               t->sw[i][jp1][k],
5896                                               t->sw[ip1][jp1][k]))) {
5897                 return true;
5898         }
5899         log_no_crnr(t, 0x722, i, j, k, ip1, j, k);
5900
5901         if (install_tswitch(t, ip1, j, kp1,
5902                             tfind_face_corner(t->sw[i][j][kp1],
5903                                               t->sw[i][jp1][kp1],
5904                                               t->sw[ip1][jp1][kp1]))) {
5905                 return true;
5906         }
5907         log_no_crnr(t, 0x722, i, j, k, ip1, j, kp1);
5908         return false;
5909 }
5910
5911 /*
5912  * 3D case 0x730:                           O
5913  *                                        . .
5914  *  b0: t->sw[i  ][j  ][k  ]            .   .
5915  *  b1: t->sw[i+1][j  ][k  ]          .     .
5916  *  b2: t->sw[i  ][j+1][k  ]        .       .
5917  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
5918  *  b4:                           .         O
5919  *  b5:                           .       .   .
5920  *  b6: t->sw[i  ][j+1][k+1]      .     .       .
5921  *  b7: t->sw[i+1][j+1][k+1]      .   .           .
5922  *                                . .       O       .
5923  *                                O                   O
5924  *                                  .               .
5925  *                                    .           .
5926  *                                      .       .
5927  *                                        .   .
5928  *                                          @
5929  */
5930 static
5931 bool handle_case_0x730(struct torus *t, int i, int j, int k)
5932 {
5933         int ip1 = canonicalize(i + 1, t->x_sz);
5934         int jp1 = canonicalize(j + 1, t->y_sz);
5935         int kp1 = canonicalize(k + 1, t->z_sz);
5936
5937         if (install_tswitch(t, i, j, kp1,
5938                             tfind_face_corner(t->sw[i][j][k],
5939                                               t->sw[i][jp1][k],
5940                                               t->sw[i][jp1][kp1]))) {
5941                 return true;
5942         }
5943         log_no_crnr(t, 0x730, i, j, k, i, j, kp1);
5944
5945         if (install_tswitch(t, ip1, j, kp1,
5946                             tfind_face_corner(t->sw[ip1][j][k],
5947                                               t->sw[ip1][jp1][k],
5948                                               t->sw[ip1][jp1][kp1]))) {
5949                 return true;
5950         }
5951         log_no_crnr(t, 0x730, i, j, k, ip1, j, kp1);
5952         return false;
5953 }
5954
5955 /*
5956  * 3D case 0x744:                           O
5957  *                                          . .
5958  *  b0: t->sw[i  ][j  ][k  ]                .   .
5959  *  b1: t->sw[i+1][j  ][k  ]                .     .
5960  *  b2:                                     .       .
5961  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
5962  *  b4: t->sw[i  ][j  ][k+1]                O       . .
5963  *  b5: t->sw[i+1][j  ][k+1]                  .   .   .
5964  *  b6:                                         .     .
5965  *  b7: t->sw[i+1][j+1][k+1]                  .   .   .
5966  *                                          O       . .
5967  *                                O         .         O
5968  *                                          .       .
5969  *                                          .     .
5970  *                                          .   .
5971  *                                          . .
5972  *                                          @
5973  */
5974 static
5975 bool handle_case_0x744(struct torus *t, int i, int j, int k)
5976 {
5977         int ip1 = canonicalize(i + 1, t->x_sz);
5978         int jp1 = canonicalize(j + 1, t->y_sz);
5979         int kp1 = canonicalize(k + 1, t->z_sz);
5980
5981         if (install_tswitch(t, i, jp1, k,
5982                             tfind_face_corner(t->sw[i][j][k],
5983                                               t->sw[ip1][j][k],
5984                                               t->sw[ip1][jp1][k]))) {
5985                 return true;
5986         }
5987         log_no_crnr(t, 0x744, i, j, k, i, jp1, k);
5988
5989         if (install_tswitch(t, i, jp1, kp1,
5990                             tfind_face_corner(t->sw[i][j][kp1],
5991                                               t->sw[ip1][j][kp1],
5992                                               t->sw[ip1][jp1][kp1]))) {
5993                 return true;
5994         }
5995         log_no_crnr(t, 0x744, i, j, k, i, jp1, kp1);
5996         return false;
5997 }
5998
5999 /*
6000  * 3D case 0x750:                           O
6001  *                                          . .
6002  *  b0: t->sw[i  ][j  ][k  ]                .   .
6003  *  b1: t->sw[i+1][j  ][k  ]                .     .
6004  *  b2: t->sw[i  ][j+1][k  ]                .       .
6005  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
6006  *  b4:                                     O         .
6007  *  b5: t->sw[i+1][j  ][k+1]              .   .       .
6008  *  b6:                                 .       .     .
6009  *  b7: t->sw[i+1][j+1][k+1]          .           .   .
6010  *                                  .       O       . .
6011  *                                O                   O
6012  *                                  .               .
6013  *                                    .           .
6014  *                                      .       .
6015  *                                        .   .
6016  *                                          @
6017  */
6018 static
6019 bool handle_case_0x750(struct torus *t, int i, int j, int k)
6020 {
6021         int ip1 = canonicalize(i + 1, t->x_sz);
6022         int jp1 = canonicalize(j + 1, t->y_sz);
6023         int kp1 = canonicalize(k + 1, t->z_sz);
6024
6025         if (install_tswitch(t, i, j, kp1,
6026                             tfind_face_corner(t->sw[i][j][k],
6027                                               t->sw[ip1][j][k],
6028                                               t->sw[ip1][j][kp1]))) {
6029                 return true;
6030         }
6031         log_no_crnr(t, 0x750, i, j, k, i, j, kp1);
6032
6033         if (install_tswitch(t, i, jp1, kp1,
6034                             tfind_face_corner(t->sw[i][jp1][k],
6035                                               t->sw[ip1][jp1][k],
6036                                               t->sw[ip1][jp1][kp1]))) {
6037                 return true;
6038         }
6039         log_no_crnr(t, 0x750, i, j, k, i, jp1, kp1);
6040         return false;
6041 }
6042
6043 /*
6044  * 3D case 0x788:                           O
6045  *
6046  *  b0: t->sw[i  ][j  ][k  ]
6047  *  b1: t->sw[ip1][j  ][k  ]
6048  *  b2: t->sw[i  ][j+1][k  ]
6049  *  b3:                           O                   O
6050  *  b4: t->sw[i  ][j  ][k+1]      . .       O       . .
6051  *  b5: t->sw[i+1][j  ][k+1]      .   .           .   .
6052  *  b6: t->sw[i  ][j+1][k+1]      .     .       .     .
6053  *  b7:                           .       .   .       .
6054  *                                .         O         .
6055  *                                O         .         O
6056  *                                  .       .       .
6057  *                                    .     .     .
6058  *                                      .   .   .
6059  *                                        . . .
6060  *                                          @
6061  */
6062 static
6063 bool handle_case_0x788(struct torus *t, int i, int j, int k)
6064 {
6065         int ip1 = canonicalize(i + 1, t->x_sz);
6066         int jp1 = canonicalize(j + 1, t->y_sz);
6067         int kp1 = canonicalize(k + 1, t->z_sz);
6068
6069         if (install_tswitch(t, ip1, jp1, k,
6070                             tfind_face_corner(t->sw[ip1][j][k],
6071                                               t->sw[i][j][k],
6072                                               t->sw[i][jp1][k]))) {
6073                 return true;
6074         }
6075         log_no_crnr(t, 0x788, i, j, k, ip1, jp1, k);
6076
6077         if (install_tswitch(t, ip1, jp1, kp1,
6078                             tfind_face_corner(t->sw[ip1][j][kp1],
6079                                               t->sw[i][j][kp1],
6080                                               t->sw[i][jp1][kp1]))) {
6081                 return true;
6082         }
6083         log_no_crnr(t, 0x788, i, j, k, ip1, jp1, kp1);
6084         return false;
6085 }
6086
6087 /*
6088  * 3D case 0x7a0:                           O
6089  *
6090  *  b0: t->sw[i  ][j  ][k  ]
6091  *  b1: t->sw[i+1][j  ][k  ]
6092  *  b2: t->sw[i  ][j+1][k  ]
6093  *  b3: t->sw[i+1][j+1][k  ]      O                   O
6094  *  b4: t->sw[i  ][j  ][k+1]      . .       O
6095  *  b5:                           .   .   .   .
6096  *  b6: t->sw[i  ][j+1][k+1]      .     .       .
6097  *  b7:                           .   .   .       .
6098  *                                . .       O       .
6099  *                                O         .         O
6100  *                                  .       .       .
6101  *                                    .     .     .
6102  *                                      .   .   .
6103  *                                        . . .
6104  *                                          @
6105  */
6106 static
6107 bool handle_case_0x7a0(struct torus *t, int i, int j, int k)
6108 {
6109         int ip1 = canonicalize(i + 1, t->x_sz);
6110         int jp1 = canonicalize(j + 1, t->y_sz);
6111         int kp1 = canonicalize(k + 1, t->z_sz);
6112
6113         if (install_tswitch(t, ip1, j, kp1,
6114                             tfind_face_corner(t->sw[i][j][kp1],
6115                                               t->sw[i][j][k],
6116                                               t->sw[ip1][j][k]))) {
6117                 return true;
6118         }
6119         log_no_crnr(t, 0x7a0, i, j, k, ip1, j, kp1);
6120
6121         if (install_tswitch(t, ip1, jp1, kp1,
6122                             tfind_face_corner(t->sw[i][jp1][kp1],
6123                                               t->sw[i][jp1][k],
6124                                               t->sw[ip1][jp1][k]))) {
6125                 return true;
6126         }
6127         log_no_crnr(t, 0x7a0, i, j, k, ip1, jp1, kp1);
6128         return false;
6129 }
6130
6131 /*
6132  * 3D case 0x7c0:                           O
6133  *
6134  *  b0: t->sw[i  ][j  ][k  ]
6135  *  b1: t->sw[i+1][j  ][k  ]
6136  *  b2: t->sw[i  ][j+1][k  ]
6137  *  b3: t->sw[i+1][j+1][k  ]      O                   O
6138  *  b4: t->sw[i  ][j  ][k+1]                O       . .
6139  *  b5: t->sw[i+1][j  ][k+1]              .   .   .   .
6140  *  b6:                                 .       .     .
6141  *  b7:                               .       .   .   .
6142  *                                  .       O       . .
6143  *                                O         .         O
6144  *                                  .       .       .
6145  *                                    .     .     .
6146  *                                      .   .   .
6147  *                                        . . .
6148  *                                          @
6149  */
6150 static
6151 bool handle_case_0x7c0(struct torus *t, int i, int j, int k)
6152 {
6153         int ip1 = canonicalize(i + 1, t->x_sz);
6154         int jp1 = canonicalize(j + 1, t->y_sz);
6155         int kp1 = canonicalize(k + 1, t->z_sz);
6156
6157         if (install_tswitch(t, i, jp1, kp1,
6158                             tfind_face_corner(t->sw[i][j][kp1],
6159                                               t->sw[i][j][k],
6160                                               t->sw[i][jp1][k]))) {
6161                 return true;
6162         }
6163         log_no_crnr(t, 0x7c0, i, j, k, i, jp1, kp1);
6164
6165         if (install_tswitch(t, ip1, jp1, kp1,
6166                             tfind_face_corner(t->sw[ip1][j][kp1],
6167                                               t->sw[ip1][j][k],
6168                                               t->sw[ip1][jp1][k]))) {
6169                 return true;
6170         }
6171         log_no_crnr(t, 0x7c0, i, j, k, ip1, jp1, kp1);
6172         return false;
6173 }
6174
6175 /*
6176  * Handle the cases where a single corner is missing.
6177  */
6178
6179 /*
6180  * 3D case 0x701:                           O
6181  *                                        . . .
6182  *  b0:                                     .   .   .
6183  *  b1: t->sw[i+1][j  ][k  ]          .     .     .
6184  *  b2: t->sw[i  ][j+1][k  ]        .       .       .
6185  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
6186  *  b4: t->sw[i  ][j  ][k+1]      . .       O       . .
6187  *  b5: t->sw[i+1][j  ][k+1]      .   .   .   .   .   .
6188  *  b6: t->sw[i  ][j+1][k+1]      .     .       .     .
6189  *  b7: t->sw[i+1][j+1][k+1]      .   .   .   .   .   .
6190  *                                . .       O       . .
6191  *                                O                   O
6192  *
6193  *
6194  *
6195  *
6196  *                                          @
6197  */
6198 static
6199 bool handle_case_0x701(struct torus *t, int i, int j, int k)
6200 {
6201         int ip1 = canonicalize(i + 1, t->x_sz);
6202         int jp1 = canonicalize(j + 1, t->y_sz);
6203
6204         if (install_tswitch(t, i, j, k,
6205                             tfind_face_corner(t->sw[i][jp1][k],
6206                                               t->sw[ip1][jp1][k],
6207                                               t->sw[ip1][j][k]))) {
6208                 return true;
6209         }
6210         log_no_crnr(t, 0x701, i, j, k, i, j, k);
6211         return false;
6212 }
6213
6214 /*
6215  * 3D case 0x702:                           O
6216  *                                        . . .
6217  *  b0: t->sw[i  ][j  ][k  ]            .   .   .
6218  *  b1:                               .     .     .
6219  *  b2: t->sw[i  ][j+1][k  ]        .       .       .
6220  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
6221  *  b4: t->sw[i  ][j  ][k+1]      . .       O       .
6222  *  b5: t->sw[i+1][j  ][k+1]      .   .   .       .
6223  *  b6: t->sw[i  ][j+1][k+1]      .     .       .
6224  *  b7: t->sw[i+1][j+1][k+1]      .   .   .   .
6225  *                                . .       O
6226  *                                O         .         O
6227  *                                  .       .
6228  *                                    .     .
6229  *                                      .   .
6230  *                                        . .
6231  *                                          @
6232  */
6233 static
6234 bool handle_case_0x702(struct torus *t, int i, int j, int k)
6235 {
6236         int ip1 = canonicalize(i + 1, t->x_sz);
6237         int kp1 = canonicalize(k + 1, t->z_sz);
6238
6239         if (install_tswitch(t, ip1, j, k,
6240                             tfind_face_corner(t->sw[i][j][k],
6241                                               t->sw[i][j][kp1],
6242                                               t->sw[ip1][j][kp1]))) {
6243                 return true;
6244         }
6245         log_no_crnr(t, 0x702, i, j, k, ip1, j, k);
6246         return false;
6247 }
6248
6249 /*
6250  * 3D case 0x704:                           O
6251  *                                        . . .
6252  *  b0: t->sw[i  ][j  ][k  ]            .   .   .
6253  *  b1: t->sw[i+1][j  ][k  ]          .     .     .
6254  *  b2:                             .       .       .
6255  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
6256  *  b4: t->sw[i  ][j  ][k+1]        .       O       . .
6257  *  b5: t->sw[i+1][j  ][k+1]          .       .   .   .
6258  *  b6: t->sw[i  ][j+1][k+1]            .       .     .
6259  *  b7: t->sw[i+1][j+1][k+1]              .   .   .   .
6260  *                                          O       . .
6261  *                                O         .         O
6262  *                                          .       .
6263  *                                          .     .
6264  *                                          .   .
6265  *                                          . .
6266  *                                          @
6267  */
6268 static
6269 bool handle_case_0x704(struct torus *t, int i, int j, int k)
6270 {
6271         int jp1 = canonicalize(j + 1, t->y_sz);
6272         int kp1 = canonicalize(k + 1, t->z_sz);
6273
6274         if (install_tswitch(t, i, jp1, k,
6275                             tfind_face_corner(t->sw[i][j][k],
6276                                               t->sw[i][j][kp1],
6277                                               t->sw[i][jp1][kp1]))) {
6278                 return true;
6279         }
6280         log_no_crnr(t, 0x704, i, j, k, i, jp1, k);
6281         return false;
6282 }
6283
6284 /*
6285  * 3D case 0x708:                           O
6286  *                                        .   .
6287  *  b0: t->sw[i  ][j  ][k  ]            .       .
6288  *  b1: t->sw[i+1][j  ][k  ]          .           .
6289  *  b2: t->sw[i  ][j+1][k  ]        .               .
6290  *  b3:                           O                   O
6291  *  b4: t->sw[i  ][j  ][k+1]      . .       O       . .
6292  *  b5: t->sw[i+1][j  ][k+1]      .   .           .   .
6293  *  b6: t->sw[i  ][j+1][k+1]      .     .       .     .
6294  *  b7: t->sw[i+1][j+1][k+1]      .       .   .       .
6295  *                                .         O         .
6296  *                                O         .         O
6297  *                                  .       .       .
6298  *                                    .     .     .
6299  *                                      .   .   .
6300  *                                        . . .
6301  *                                          @
6302  */
6303 static
6304 bool handle_case_0x708(struct torus *t, int i, int j, int k)
6305 {
6306         int ip1 = canonicalize(i + 1, t->x_sz);
6307         int jp1 = canonicalize(j + 1, t->y_sz);
6308
6309         if (install_tswitch(t, ip1, jp1, k,
6310                             tfind_face_corner(t->sw[i][jp1][k],
6311                                               t->sw[i][j][k],
6312                                               t->sw[ip1][j][k]))) {
6313                 return true;
6314         }
6315         log_no_crnr(t, 0x708, i, j, k, ip1, jp1, k);
6316         return false;
6317 }
6318
6319 /*
6320  * 3D case 0x710:                           O
6321  *                                        . . .
6322  *  b0: t->sw[i  ][j  ][k  ]            .   .   .
6323  *  b1: t->sw[i+1][j  ][k  ]          .     .     .
6324  *  b2: t->sw[i  ][j+1][k  ]        .       .       .
6325  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
6326  *  b4:                           .         O         .
6327  *  b5: t->sw[i+1][j  ][k+1]      .       .   .       .
6328  *  b6: t->sw[i  ][j+1][k+1]      .     .       .     .
6329  *  b7: t->sw[i+1][j+1][k+1]      .   .           .   .
6330  *                                . .       O       . .
6331  *                                O                   O
6332  *                                  .               .
6333  *                                    .           .
6334  *                                      .       .
6335  *                                        .   .
6336  *                                          @
6337  */
6338 static
6339 bool handle_case_0x710(struct torus *t, int i, int j, int k)
6340 {
6341         int ip1 = canonicalize(i + 1, t->x_sz);
6342         int kp1 = canonicalize(k + 1, t->z_sz);
6343
6344         if (install_tswitch(t, i, j, kp1,
6345                             tfind_face_corner(t->sw[i][j][k],
6346                                               t->sw[ip1][j][k],
6347                                               t->sw[ip1][j][kp1]))) {
6348                 return true;
6349         }
6350         log_no_crnr(t, 0x710, i, j, k, i, j, kp1);
6351         return false;
6352 }
6353
6354 /*
6355  * 3D case 0x720:                           O
6356  *                                        . .
6357  *  b0: t->sw[i  ][j  ][k  ]            .   .
6358  *  b1: t->sw[i+1][j  ][k  ]          .     .
6359  *  b2: t->sw[i  ][j+1][k  ]        .       .
6360  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
6361  *  b4: t->sw[i  ][j  ][k+1]      . .       O
6362  *  b5:                           .   .   .   .
6363  *  b6: t->sw[i  ][j+1][k+1]      .     .       .
6364  *  b7: t->sw[i+1][j+1][k+1]      .   .   .       .
6365  *                                . .       O       .
6366  *                                O         .         O
6367  *                                  .       .       .
6368  *                                    .     .     .
6369  *                                      .   .   .
6370  *                                        . . .
6371  *                                          @
6372  */
6373 static
6374 bool handle_case_0x720(struct torus *t, int i, int j, int k)
6375 {
6376         int ip1 = canonicalize(i + 1, t->x_sz);
6377         int kp1 = canonicalize(k + 1, t->z_sz);
6378
6379         if (install_tswitch(t, ip1, j, kp1,
6380                             tfind_face_corner(t->sw[ip1][j][k],
6381                                               t->sw[i][j][k],
6382                                               t->sw[i][j][kp1]))) {
6383                 return true;
6384         }
6385         log_no_crnr(t, 0x720, i, j, k, ip1, j, kp1);
6386         return false;
6387 }
6388
6389 /*
6390  * 3D case 0x740:                           O
6391  *                                          . .
6392  *  b0: t->sw[i  ][j  ][k  ]                .   .
6393  *  b1: t->sw[i+1][j  ][k  ]                .     .
6394  *  b2: t->sw[i  ][j+1][k  ]                .       .
6395  *  b3: t->sw[i+1][j+1][k  ]      O         .         O
6396  *  b4: t->sw[i  ][j  ][k+1]                O       . .
6397  *  b5: t->sw[i+1][j  ][k+1]              .   .   .   .
6398  *  b6:                                 .       .     .
6399  *  b7: t->sw[i+1][j+1][k+1]          .       .   .   .
6400  *                                  .       O       . .
6401  *                                O         .         O
6402  *                                  .       .       .
6403  *                                    .     .     .
6404  *                                      .   .   .
6405  *                                        . . .
6406  *                                          @
6407  */
6408 static
6409 bool handle_case_0x740(struct torus *t, int i, int j, int k)
6410 {
6411         int jp1 = canonicalize(j + 1, t->y_sz);
6412         int kp1 = canonicalize(k + 1, t->z_sz);
6413
6414         if (install_tswitch(t, i, jp1, kp1,
6415                             tfind_face_corner(t->sw[i][jp1][k],
6416                                               t->sw[i][j][k],
6417                                               t->sw[i][j][kp1]))) {
6418                 return true;
6419         }
6420         log_no_crnr(t, 0x740, i, j, k, i, jp1, kp1);
6421         return false;
6422 }
6423
6424 /*
6425  * 3D case 0x780:                           O
6426  *
6427  *  b0: t->sw[i  ][j  ][k  ]
6428  *  b1: t->sw[i+1][j  ][k  ]
6429  *  b2: t->sw[i  ][j+1][k  ]
6430  *  b3: t->sw[i+1][j+1][k  ]      O                   O
6431  *  b4: t->sw[i  ][j  ][k+1]      . .       O       . .
6432  *  b5: t->sw[i+1][j  ][k+1]      .   .   .   .   .   .
6433  *  b6: t->sw[i  ][j+1][k+1]      .     .       .     .
6434  *  b7:                           .   .   .   .   .   .
6435  *                                . .       O       . .
6436  *                                O         .         O
6437  *                                  .       .       .
6438  *                                    .     .     .
6439  *                                      .   .   .
6440  *                                        . . .
6441  *                                          @
6442  */
6443 static
6444 bool handle_case_0x780(struct torus *t, int i, int j, int k)
6445 {
6446         int ip1 = canonicalize(i + 1, t->x_sz);
6447         int jp1 = canonicalize(j + 1, t->y_sz);
6448         int kp1 = canonicalize(k + 1, t->z_sz);
6449
6450         if (install_tswitch(t, ip1, jp1, kp1,
6451                             tfind_face_corner(t->sw[i][jp1][kp1],
6452                                               t->sw[i][j][kp1],
6453                                               t->sw[ip1][j][kp1]))) {
6454                 return true;
6455         }
6456         log_no_crnr(t, 0x780, i, j, k, ip1, jp1, kp1);
6457         return false;
6458 }
6459
6460 /*
6461  * Make sure links between all known torus/mesh switches are installed.
6462  *
6463  * We don't have to worry about links that wrap on a mesh coordinate, as
6464  * there shouldn't be any; if there are it indicates an input error.
6465  */
6466 static
6467 void check_tlinks(struct torus *t, int i, int j, int k)
6468 {
6469         struct t_switch ****sw = t->sw;
6470         int ip1 = canonicalize(i + 1, t->x_sz);
6471         int jp1 = canonicalize(j + 1, t->y_sz);
6472         int kp1 = canonicalize(k + 1, t->z_sz);
6473
6474         /*
6475          * Don't waste time/code checking return status of link_tswitches()
6476          * here.  It is unlikely to fail, and the result of any failure here
6477          * will be caught elsewhere anyway.
6478          */
6479         if (sw[i][j][k] && sw[ip1][j][k])
6480                 link_tswitches(t, 0, sw[i][j][k], sw[ip1][j][k]);
6481
6482         if (sw[i][jp1][k] && sw[ip1][jp1][k])
6483                 link_tswitches(t, 0, sw[i][jp1][k], sw[ip1][jp1][k]);
6484
6485         if (sw[i][j][kp1] && sw[ip1][j][kp1])
6486                 link_tswitches(t, 0, sw[i][j][kp1], sw[ip1][j][kp1]);
6487
6488         if (sw[i][jp1][kp1] && sw[ip1][jp1][kp1])
6489                 link_tswitches(t, 0, sw[i][jp1][kp1], sw[ip1][jp1][kp1]);
6490
6491
6492         if (sw[i][j][k] && sw[i][jp1][k])
6493                 link_tswitches(t, 1, sw[i][j][k], sw[i][jp1][k]);
6494
6495         if (sw[ip1][j][k] && sw[ip1][jp1][k])
6496                 link_tswitches(t, 1, sw[ip1][j][k], sw[ip1][jp1][k]);
6497
6498         if (sw[i][j][kp1] && sw[i][jp1][kp1])
6499                 link_tswitches(t, 1, sw[i][j][kp1], sw[i][jp1][kp1]);
6500
6501         if (sw[ip1][j][kp1] && sw[ip1][jp1][kp1])
6502                 link_tswitches(t, 1, sw[ip1][j][kp1], sw[ip1][jp1][kp1]);
6503
6504
6505         if (sw[i][j][k] && sw[i][j][kp1])
6506                 link_tswitches(t, 2, sw[i][j][k], sw[i][j][kp1]);
6507
6508         if (sw[ip1][j][k] && sw[ip1][j][kp1])
6509                 link_tswitches(t, 2, sw[ip1][j][k], sw[ip1][j][kp1]);
6510
6511         if (sw[i][jp1][k] && sw[i][jp1][kp1])
6512                 link_tswitches(t, 2, sw[i][jp1][k], sw[i][jp1][kp1]);
6513
6514         if (sw[ip1][jp1][k] && sw[ip1][jp1][kp1])
6515                 link_tswitches(t, 2, sw[ip1][jp1][k], sw[ip1][jp1][kp1]);
6516 }
6517
6518 static
6519 void locate_sw(struct torus *t, int i, int j, int k)
6520 {
6521         unsigned fp;
6522         bool success;
6523
6524         i = canonicalize(i, t->x_sz);
6525         j = canonicalize(j, t->y_sz);
6526         k = canonicalize(k, t->z_sz);
6527
6528         /*
6529          * By definition, if a coordinate direction is meshed, we don't
6530          * allow it to wrap to zero.
6531          */
6532         if (t->flags & X_MESH) {
6533                 int ip1 = canonicalize(i + 1, t->x_sz);
6534                 if (ip1 < i)
6535                         goto out;
6536         }
6537         if (t->flags & Y_MESH) {
6538                 int jp1 = canonicalize(j + 1, t->y_sz);
6539                 if (jp1 < j)
6540                         goto out;
6541         }
6542         if (t->flags & Z_MESH) {
6543                 int kp1 = canonicalize(k + 1, t->z_sz);
6544                 if (kp1 < k)
6545                         goto out;
6546         }
6547         /*
6548          * There are various reasons that the links are not installed between
6549          * known torus switches.  These include cases where the search for
6550          * new switches only partially succeeds due to missing switches, and
6551          * cases where we haven't processed this position yet, but processing
6552          * of multiple independent neighbor positions has installed switches
6553          * into corners of our case.
6554          *
6555          * In any event, the topology assumptions made in handling the
6556          * fingerprint for this position require that all links be installed
6557          * between installed switches for this position.
6558          */
6559 again:
6560         check_tlinks(t, i, j, k);
6561         fp = fingerprint(t, i, j, k);
6562
6563         switch (fp) {
6564         /*
6565          * When all switches are present, we are done.  Otherwise, one of
6566          * the cases below will be unsuccessful, and we'll be done also.
6567          *
6568          * Note that check_tlinks() above will ensure all links that are
6569          * present are connected, in the event that all our switches are
6570          * present due to successful case handling in the surrounding
6571          * torus/mesh.
6572          */
6573         case 0x300:
6574         case 0x500:
6575         case 0x600:
6576         case 0x700:
6577                 goto out;
6578         /*
6579          * Ignore the 2D cases where there isn't enough information to uniquely
6580          * locate/place a switch into the cube.
6581          */
6582         case 0x30f:     /* 0 corners available */
6583         case 0x533:     /* 0 corners available */
6584         case 0x655:     /* 0 corners available */
6585         case 0x30e:     /* 1 corner available */
6586         case 0x532:     /* 1 corner available */
6587         case 0x654:     /* 1 corner available */
6588         case 0x30d:     /* 1 corner available */
6589         case 0x531:     /* 1 corner available */
6590         case 0x651:     /* 1 corner available */
6591         case 0x30b:     /* 1 corner available */
6592         case 0x523:     /* 1 corner available */
6593         case 0x645:     /* 1 corner available */
6594         case 0x307:     /* 1 corner available */
6595         case 0x513:     /* 1 corner available */
6596         case 0x615:     /* 1 corner available */
6597                 goto out;
6598         /*
6599          * Handle the 2D cases with a single existing edge.
6600          *
6601          */
6602         case 0x30c:
6603                 success = handle_case_0x30c(t, i, j, k);
6604                 break;
6605         case 0x303:
6606                 success = handle_case_0x303(t, i, j, k);
6607                 break;
6608         case 0x305:
6609                 success = handle_case_0x305(t, i, j, k);
6610                 break;
6611         case 0x30a:
6612                 success = handle_case_0x30a(t, i, j, k);
6613                 break;
6614         case 0x503:
6615                 success = handle_case_0x503(t, i, j, k);
6616                 break;
6617         case 0x511:
6618                 success = handle_case_0x511(t, i, j, k);
6619                 break;
6620         case 0x522:
6621                 success = handle_case_0x522(t, i, j, k);
6622                 break;
6623         case 0x530:
6624                 success = handle_case_0x530(t, i, j, k);
6625                 break;
6626         case 0x605:
6627                 success = handle_case_0x605(t, i, j, k);
6628                 break;
6629         case 0x611:
6630                 success = handle_case_0x611(t, i, j, k);
6631                 break;
6632         case 0x644:
6633                 success = handle_case_0x644(t, i, j, k);
6634                 break;
6635         case 0x650:
6636                 success = handle_case_0x650(t, i, j, k);
6637                 break;
6638         /*
6639          * Handle the 2D cases where two existing edges meet at a corner.
6640          */
6641         case 0x301:
6642                 success = handle_case_0x301(t, i, j, k);
6643                 break;
6644         case 0x302:
6645                 success = handle_case_0x302(t, i, j, k);
6646                 break;
6647         case 0x304:
6648                 success = handle_case_0x304(t, i, j, k);
6649                 break;
6650         case 0x308:
6651                 success = handle_case_0x308(t, i, j, k);
6652                 break;
6653         case 0x501:
6654                 success = handle_case_0x501(t, i, j, k);
6655                 break;
6656         case 0x502:
6657                 success = handle_case_0x502(t, i, j, k);
6658                 break;
6659         case 0x520:
6660                 success = handle_case_0x520(t, i, j, k);
6661                 break;
6662         case 0x510:
6663                 success = handle_case_0x510(t, i, j, k);
6664                 break;
6665         case 0x601:
6666                 success = handle_case_0x601(t, i, j, k);
6667                 break;
6668         case 0x604:
6669                 success = handle_case_0x604(t, i, j, k);
6670                 break;
6671         case 0x610:
6672                 success = handle_case_0x610(t, i, j, k);
6673                 break;
6674         case 0x640:
6675                 success = handle_case_0x640(t, i, j, k);
6676                 break;
6677         /*
6678          * Ignore the 3D cases where there isn't enough information to uniquely
6679          * locate/place a switch into the cube.
6680          */
6681         case 0x7ff:     /* 0 corners available */
6682         case 0x7fe:     /* 1 corner available */
6683         case 0x7fd:     /* 1 corner available */
6684         case 0x7fb:     /* 1 corner available */
6685         case 0x7f7:     /* 1 corner available */
6686         case 0x7ef:     /* 1 corner available */
6687         case 0x7df:     /* 1 corner available */
6688         case 0x7bf:     /* 1 corner available */
6689         case 0x77f:     /* 1 corner available */
6690         case 0x7fc:     /* 2 adj corners available */
6691         case 0x7fa:     /* 2 adj corners available */
6692         case 0x7f5:     /* 2 adj corners available */
6693         case 0x7f3:     /* 2 adj corners available */
6694         case 0x7cf:     /* 2 adj corners available */
6695         case 0x7af:     /* 2 adj corners available */
6696         case 0x75f:     /* 2 adj corners available */
6697         case 0x73f:     /* 2 adj corners available */
6698         case 0x7ee:     /* 2 adj corners available */
6699         case 0x7dd:     /* 2 adj corners available */
6700         case 0x7bb:     /* 2 adj corners available */
6701         case 0x777:     /* 2 adj corners available */
6702                 goto out;
6703         /*
6704          * Handle the 3D cases where two existing edges meet at a corner.
6705          *
6706          */
6707         case 0x71f:
6708                 success = handle_case_0x71f(t, i, j, k);
6709                 break;
6710         case 0x72f:
6711                 success = handle_case_0x72f(t, i, j, k);
6712                 break;
6713         case 0x737:
6714                 success = handle_case_0x737(t, i, j, k);
6715                 break;
6716         case 0x73b:
6717                 success = handle_case_0x73b(t, i, j, k);
6718                 break;
6719         case 0x74f:
6720                 success = handle_case_0x74f(t, i, j, k);
6721                 break;
6722         case 0x757:
6723                 success = handle_case_0x757(t, i, j, k);
6724                 break;
6725         case 0x75d:
6726                 success = handle_case_0x75d(t, i, j, k);
6727                 break;
6728         case 0x773:
6729                 success = handle_case_0x773(t, i, j, k);
6730                 break;
6731         case 0x775:
6732                 success = handle_case_0x775(t, i, j, k);
6733                 break;
6734         case 0x78f:
6735                 success = handle_case_0x78f(t, i, j, k);
6736                 break;
6737         case 0x7ab:
6738                 success = handle_case_0x7ab(t, i, j, k);
6739                 break;
6740         case 0x7ae:
6741                 success = handle_case_0x7ae(t, i, j, k);
6742                 break;
6743         case 0x7b3:
6744                 success = handle_case_0x7b3(t, i, j, k);
6745                 break;
6746         case 0x7ba:
6747                 success = handle_case_0x7ba(t, i, j, k);
6748                 break;
6749         case 0x7cd:
6750                 success = handle_case_0x7cd(t, i, j, k);
6751                 break;
6752         case 0x7ce:
6753                 success = handle_case_0x7ce(t, i, j, k);
6754                 break;
6755         case 0x7d5:
6756                 success = handle_case_0x7d5(t, i, j, k);
6757                 break;
6758         case 0x7dc:
6759                 success = handle_case_0x7dc(t, i, j, k);
6760                 break;
6761         case 0x7ea:
6762                 success = handle_case_0x7ea(t, i, j, k);
6763                 break;
6764         case 0x7ec:
6765                 success = handle_case_0x7ec(t, i, j, k);
6766                 break;
6767         case 0x7f1:
6768                 success = handle_case_0x7f1(t, i, j, k);
6769                 break;
6770         case 0x7f2:
6771                 success = handle_case_0x7f2(t, i, j, k);
6772                 break;
6773         case 0x7f4:
6774                 success = handle_case_0x7f4(t, i, j, k);
6775                 break;
6776         case 0x7f8:
6777                 success = handle_case_0x7f8(t, i, j, k);
6778                 break;
6779         /*
6780          * Handle the cases where three existing edges meet at a corner.
6781          *
6782          */
6783         case 0x717:
6784                 success = handle_case_0x717(t, i, j, k);
6785                 break;
6786         case 0x72b:
6787                 success = handle_case_0x72b(t, i, j, k);
6788                 break;
6789         case 0x74d:
6790                 success = handle_case_0x74d(t, i, j, k);
6791                 break;
6792         case 0x771:
6793                 success = handle_case_0x771(t, i, j, k);
6794                 break;
6795         case 0x78e:
6796                 success = handle_case_0x78e(t, i, j, k);
6797                 break;
6798         case 0x7b2:
6799                 success = handle_case_0x7b2(t, i, j, k);
6800                 break;
6801         case 0x7d4:
6802                 success = handle_case_0x7d4(t, i, j, k);
6803                 break;
6804         case 0x7e8:
6805                 success = handle_case_0x7e8(t, i, j, k);
6806                 break;
6807         /*
6808          * Handle the cases where four corners on a single face are missing.
6809          */
6810         case 0x70f:
6811                 success = handle_case_0x70f(t, i, j, k);
6812                 break;
6813         case 0x733:
6814                 success = handle_case_0x733(t, i, j, k);
6815                 break;
6816         case 0x755:
6817                 success = handle_case_0x755(t, i, j, k);
6818                 break;
6819         case 0x7aa:
6820                 success = handle_case_0x7aa(t, i, j, k);
6821                 break;
6822         case 0x7cc:
6823                 success = handle_case_0x7cc(t, i, j, k);
6824                 break;
6825         case 0x7f0:
6826                 success = handle_case_0x7f0(t, i, j, k);
6827                 break;
6828         /*
6829          * Handle the cases where three corners on a single face are missing.
6830          */
6831         case 0x707:
6832                 success = handle_case_0x707(t, i, j, k);
6833                 break;
6834         case 0x70b:
6835                 success = handle_case_0x70b(t, i, j, k);
6836                 break;
6837         case 0x70d:
6838                 success = handle_case_0x70d(t, i, j, k);
6839                 break;
6840         case 0x70e:
6841                 success = handle_case_0x70e(t, i, j, k);
6842                 break;
6843         case 0x713:
6844                 success = handle_case_0x713(t, i, j, k);
6845                 break;
6846         case 0x715:
6847                 success = handle_case_0x715(t, i, j, k);
6848                 break;
6849         case 0x723:
6850                 success = handle_case_0x723(t, i, j, k);
6851                 break;
6852         case 0x72a:
6853                 success = handle_case_0x72a(t, i, j, k);
6854                 break;
6855         case 0x731:
6856                 success = handle_case_0x731(t, i, j, k);
6857                 break;
6858         case 0x732:
6859                 success = handle_case_0x732(t, i, j, k);
6860                 break;
6861         case 0x745:
6862                 success = handle_case_0x745(t, i, j, k);
6863                 break;
6864         case 0x74c:
6865                 success = handle_case_0x74c(t, i, j, k);
6866                 break;
6867         case 0x751:
6868                 success = handle_case_0x751(t, i, j, k);
6869                 break;
6870         case 0x754:
6871                 success = handle_case_0x754(t, i, j, k);
6872                 break;
6873         case 0x770:
6874                 success = handle_case_0x770(t, i, j, k);
6875                 break;
6876         case 0x78a:
6877                 success = handle_case_0x78a(t, i, j, k);
6878                 break;
6879         case 0x78c:
6880                 success = handle_case_0x78c(t, i, j, k);
6881                 break;
6882         case 0x7a2:
6883                 success = handle_case_0x7a2(t, i, j, k);
6884                 break;
6885         case 0x7a8:
6886                 success = handle_case_0x7a8(t, i, j, k);
6887                 break;
6888         case 0x7b0:
6889                 success = handle_case_0x7b0(t, i, j, k);
6890                 break;
6891         case 0x7c4:
6892                 success = handle_case_0x7c4(t, i, j, k);
6893                 break;
6894         case 0x7c8:
6895                 success = handle_case_0x7c8(t, i, j, k);
6896                 break;
6897         case 0x7d0:
6898                 success = handle_case_0x7d0(t, i, j, k);
6899                 break;
6900         case 0x7e0:
6901                 success = handle_case_0x7e0(t, i, j, k);
6902                 break;
6903         /*
6904          * Handle the cases where two corners on a single edge are missing.
6905          */
6906         case 0x703:
6907                 success = handle_case_0x703(t, i, j, k);
6908                 break;
6909         case 0x705:
6910                 success = handle_case_0x705(t, i, j, k);
6911                 break;
6912         case 0x70a:
6913                 success = handle_case_0x70a(t, i, j, k);
6914                 break;
6915         case 0x70c:
6916                 success = handle_case_0x70c(t, i, j, k);
6917                 break;
6918         case 0x711:
6919                 success = handle_case_0x711(t, i, j, k);
6920                 break;
6921         case 0x722:
6922                 success = handle_case_0x722(t, i, j, k);
6923                 break;
6924         case 0x730:
6925                 success = handle_case_0x730(t, i, j, k);
6926                 break;
6927         case 0x744:
6928                 success = handle_case_0x744(t, i, j, k);
6929                 break;
6930         case 0x750:
6931                 success = handle_case_0x750(t, i, j, k);
6932                 break;
6933         case 0x788:
6934                 success = handle_case_0x788(t, i, j, k);
6935                 break;
6936         case 0x7a0:
6937                 success = handle_case_0x7a0(t, i, j, k);
6938                 break;
6939         case 0x7c0:
6940                 success = handle_case_0x7c0(t, i, j, k);
6941                 break;
6942         /*
6943          * Handle the cases where a single corner is missing.
6944          */
6945         case 0x701:
6946                 success = handle_case_0x701(t, i, j, k);
6947                 break;
6948         case 0x702:
6949                 success = handle_case_0x702(t, i, j, k);
6950                 break;
6951         case 0x704:
6952                 success = handle_case_0x704(t, i, j, k);
6953                 break;
6954         case 0x708:
6955                 success = handle_case_0x708(t, i, j, k);
6956                 break;
6957         case 0x710:
6958                 success = handle_case_0x710(t, i, j, k);
6959                 break;
6960         case 0x720:
6961                 success = handle_case_0x720(t, i, j, k);
6962                 break;
6963         case 0x740:
6964                 success = handle_case_0x740(t, i, j, k);
6965                 break;
6966         case 0x780:
6967                 success = handle_case_0x780(t, i, j, k);
6968                 break;
6969
6970         default:
6971                 /*
6972                  * There's lots of unhandled cases still, but it's not clear
6973                  * we care.  Let debugging show us what they are so we can
6974                  * learn if we care.
6975                  */
6976                 if (t->debug)
6977                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
6978                                 "Unhandled fingerprint 0x%03x @ %d %d %d\n",
6979                                 fp, i, j, k);
6980                 goto out;
6981         }
6982         /*
6983          * If we successfully handled a case, we may be able to make more
6984          * progress at this position, so try again.  Otherwise, even though
6985          * we didn't successfully handle a case, we may have installed a
6986          * switch into the torus/mesh, so try to install links as well.
6987          * Then we'll have another go at the next position.
6988          */
6989         if (success) {
6990                 if (t->debug)
6991                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
6992                                 "Success on fingerprint 0x%03x @ %d %d %d\n",
6993                                 fp, i, j, k);
6994                 goto again;
6995         } else {
6996                 check_tlinks(t, i, j, k);
6997                 if (t->debug)
6998                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
6999                                 "Failed on fingerprint 0x%03x @ %d %d %d\n",
7000                                 fp, i, j, k);
7001         }
7002 out:
7003         return;
7004 }
7005
7006 #define LINK_ERR_STR " direction link required for topology seed configuration since radix == 4! See torus-2QoS.conf(5).\n"
7007 #define LINK_ERR2_STR " direction link required for topology seed configuration! See torus-2QoS.conf(5).\n"
7008 #define SEED_ERR_STR " direction links for topology seed do not share a common switch! See torus-2QoS.conf(5).\n"
7009
7010 static
7011 bool verify_setup(struct torus *t, struct fabric *f)
7012 {
7013         struct coord_dirs *o;
7014         struct f_switch *sw;
7015         unsigned p, s, n = 0;
7016         bool success = false;
7017         bool all_sw_present, need_seed = true;
7018
7019         if (!(t->x_sz && t->y_sz && t->z_sz)) {
7020                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7021                         "ERR 4E20: missing required torus size specification!\n");
7022                 goto out;
7023         }
7024         if (t->osm->subn.min_sw_data_vls < 2) {
7025                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7026                         "ERR 4E48: Too few data VLs to support torus routing "
7027                         "without credit loops (have switchport %d need 2)\n",
7028                         (int)t->osm->subn.min_sw_data_vls);
7029                 goto out;
7030         }
7031         if (t->osm->subn.min_sw_data_vls < 4)
7032                 OSM_LOG(&t->osm->log, OSM_LOG_INFO,
7033                         "Warning: Too few data VLs to support torus routing "
7034                         "with a failed switch without credit loops "
7035                         "(have switchport %d need 4)\n",
7036                         (int)t->osm->subn.min_sw_data_vls);
7037         if (t->osm->subn.min_sw_data_vls < 8)
7038                 OSM_LOG(&t->osm->log, OSM_LOG_INFO,
7039                         "Warning: Too few data VLs to support torus routing "
7040                         "with two QoS levels (have switchport %d need 8)\n",
7041                         (int)t->osm->subn.min_sw_data_vls);
7042         if (t->osm->subn.min_data_vls < 2)
7043                 OSM_LOG(&t->osm->log, OSM_LOG_INFO,
7044                         "Warning: Too few data VLs to support torus routing "
7045                         "with two QoS levels (have endport %d need 2)\n",
7046                         (int)t->osm->subn.min_data_vls);
7047         /*
7048          * Be sure all the switches in the torus support the port
7049          * ordering that might have been configured.
7050          */
7051         for (s = 0; s < f->switch_cnt; s++) {
7052                 sw = f->sw[s];
7053                 for (p = 0; p < sw->port_cnt; p++) {
7054                         if (t->port_order[p] >= sw->port_cnt) {
7055                                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7056                                         "ERR 4E21: port_order configured using "
7057                                         "port %u, but only %u ports in "
7058                                         "switch w/ GUID 0x%04"PRIx64"\n",
7059                                         t->port_order[p], sw->port_cnt - 1,
7060                                         cl_ntoh64(sw->n_id));
7061                                 goto out;
7062                         }
7063                 }
7064         }
7065         /*
7066          * Unfortunately, there is a problem with non-unique topology for any
7067          * torus dimension which has radix four.  This problem requires extra
7068          * input, in the form of specifying both the positive and negative
7069          * coordinate directions from a common switch, for any torus dimension
7070          * with radix four (see also build_torus()).
7071          *
7072          * Do the checking required to ensure that the required information
7073          * is present, but more than the needed information is not required.
7074          *
7075          * So, verify that we learned the coordinate directions correctly for
7076          * the fabric.  The coordinate direction links get an invalid port
7077          * set on their ends when parsed.
7078          */
7079 again:
7080         all_sw_present = true;
7081         o = &t->seed[n];
7082
7083         if (t->x_sz == 4 && !(t->flags & X_MESH)) {
7084                 if (o->xp_link.end[0].port >= 0) {
7085                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7086                                 "ERR 4E22: Positive x" LINK_ERR_STR);
7087                         goto out;
7088                 }
7089                 if (o->xm_link.end[0].port >= 0) {
7090                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7091                                 "ERR 4E23: Negative x" LINK_ERR_STR);
7092                         goto out;
7093                 }
7094                 if (o->xp_link.end[0].n_id != o->xm_link.end[0].n_id) {
7095                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7096                                 "ERR 4E24: Positive/negative x" SEED_ERR_STR);
7097                         goto out;
7098                 }
7099         }
7100         if (t->y_sz == 4 && !(t->flags & Y_MESH)) {
7101                 if (o->yp_link.end[0].port >= 0) {
7102                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7103                                 "ERR 4E25: Positive y" LINK_ERR_STR);
7104                         goto out;
7105                 }
7106                 if (o->ym_link.end[0].port >= 0) {
7107                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7108                                 "ERR 4E26: Negative y" LINK_ERR_STR);
7109                         goto out;
7110                 }
7111                 if (o->yp_link.end[0].n_id != o->ym_link.end[0].n_id) {
7112                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7113                                 "ERR 4E27: Positive/negative y" SEED_ERR_STR);
7114                         goto out;
7115                 }
7116         }
7117         if (t->z_sz == 4 && !(t->flags & Z_MESH)) {
7118                 if (o->zp_link.end[0].port >= 0) {
7119                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7120                                 "ERR 4E28: Positive z" LINK_ERR_STR);
7121                         goto out;
7122                 }
7123                 if (o->zm_link.end[0].port >= 0) {
7124                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7125                                 "ERR 4E29: Negative z" LINK_ERR_STR);
7126                         goto out;
7127                 }
7128                 if (o->zp_link.end[0].n_id != o->zm_link.end[0].n_id) {
7129                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7130                                 "ERR 4E2A: Positive/negative z" SEED_ERR_STR);
7131                         goto out;
7132                 }
7133         }
7134         if (t->x_sz > 1) {
7135                 if (o->xp_link.end[0].port >= 0 &&
7136                     o->xm_link.end[0].port >= 0) {
7137                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7138                                 "ERR 4E2B: Positive or negative x" LINK_ERR2_STR);
7139                         goto out;
7140                 }
7141                 if (o->xp_link.end[0].port < 0 &&
7142                     !find_f_sw(f, o->xp_link.end[0].n_id))
7143                         all_sw_present = false;
7144
7145                 if (o->xp_link.end[1].port < 0 &&
7146                     !find_f_sw(f, o->xp_link.end[1].n_id))
7147                         all_sw_present = false;
7148
7149                 if (o->xm_link.end[0].port < 0 &&
7150                     !find_f_sw(f, o->xm_link.end[0].n_id))
7151                         all_sw_present = false;
7152
7153                 if (o->xm_link.end[1].port < 0 &&
7154                     !find_f_sw(f, o->xm_link.end[1].n_id))
7155                         all_sw_present = false;
7156         }
7157         if (t->z_sz > 1) {
7158                 if (o->zp_link.end[0].port >= 0 &&
7159                     o->zm_link.end[0].port >= 0) {
7160                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7161                                 "ERR 4E2C: Positive or negative z" LINK_ERR2_STR);
7162                         goto out;
7163                 }
7164                 if ((o->xp_link.end[0].port < 0 &&
7165                      o->zp_link.end[0].port < 0 &&
7166                      o->zp_link.end[0].n_id != o->xp_link.end[0].n_id) ||
7167
7168                     (o->xp_link.end[0].port < 0 &&
7169                      o->zm_link.end[0].port < 0 &&
7170                      o->zm_link.end[0].n_id != o->xp_link.end[0].n_id) ||
7171
7172                     (o->xm_link.end[0].port < 0 &&
7173                      o->zp_link.end[0].port < 0 &&
7174                      o->zp_link.end[0].n_id != o->xm_link.end[0].n_id) ||
7175
7176                     (o->xm_link.end[0].port < 0 &&
7177                      o->zm_link.end[0].port < 0 &&
7178                      o->zm_link.end[0].n_id != o->xm_link.end[0].n_id)) {
7179
7180                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7181                                 "ERR 4E2D: x and z" SEED_ERR_STR);
7182                         goto out;
7183                 }
7184                 if (o->zp_link.end[0].port < 0 &&
7185                     !find_f_sw(f, o->zp_link.end[0].n_id))
7186                         all_sw_present = false;
7187
7188                 if (o->zp_link.end[1].port < 0 &&
7189                     !find_f_sw(f, o->zp_link.end[1].n_id))
7190                         all_sw_present = false;
7191
7192                 if (o->zm_link.end[0].port < 0 &&
7193                     !find_f_sw(f, o->zm_link.end[0].n_id))
7194                         all_sw_present = false;
7195
7196                 if (o->zm_link.end[1].port < 0 &&
7197                     !find_f_sw(f, o->zm_link.end[1].n_id))
7198                         all_sw_present = false;
7199         }
7200         if (t->y_sz > 1) {
7201                 if (o->yp_link.end[0].port >= 0 &&
7202                     o->ym_link.end[0].port >= 0) {
7203                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7204                                 "ERR 4E2E: Positive or negative y" LINK_ERR2_STR);
7205                         goto out;
7206                 }
7207                 if ((o->xp_link.end[0].port < 0 &&
7208                      o->yp_link.end[0].port < 0 &&
7209                      o->yp_link.end[0].n_id != o->xp_link.end[0].n_id) ||
7210
7211                     (o->xp_link.end[0].port < 0 &&
7212                      o->ym_link.end[0].port < 0 &&
7213                      o->ym_link.end[0].n_id != o->xp_link.end[0].n_id) ||
7214
7215                     (o->xm_link.end[0].port < 0 &&
7216                      o->yp_link.end[0].port < 0 &&
7217                      o->yp_link.end[0].n_id != o->xm_link.end[0].n_id) ||
7218
7219                     (o->xm_link.end[0].port < 0 &&
7220                      o->ym_link.end[0].port < 0 &&
7221                      o->ym_link.end[0].n_id != o->xm_link.end[0].n_id)) {
7222
7223                         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7224                                 "ERR 4E2F: x and y" SEED_ERR_STR);
7225                         goto out;
7226                 }
7227                 if (o->yp_link.end[0].port < 0 &&
7228                     !find_f_sw(f, o->yp_link.end[0].n_id))
7229                         all_sw_present = false;
7230
7231                 if (o->yp_link.end[1].port < 0 &&
7232                     !find_f_sw(f, o->yp_link.end[1].n_id))
7233                         all_sw_present = false;
7234
7235                 if (o->ym_link.end[0].port < 0 &&
7236                     !find_f_sw(f, o->ym_link.end[0].n_id))
7237                         all_sw_present = false;
7238
7239                 if (o->ym_link.end[1].port < 0 &&
7240                     !find_f_sw(f, o->ym_link.end[1].n_id))
7241                         all_sw_present = false;
7242         }
7243         if (all_sw_present && need_seed) {
7244                 t->seed_idx = n;
7245                 need_seed = false;
7246         }
7247         if (++n < t->seed_cnt)
7248                 goto again;
7249
7250         if (need_seed)
7251                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7252                         "ERR 4E30: Every configured torus seed has at "
7253                         "least one switch missing in fabric! See "
7254                         "torus-2QoS.conf(5) and TORUS TOPOLOGY DISCOVERY "
7255                         "in torus-2QoS(8)\n");
7256         else
7257                 success = true;
7258 out:
7259         return success;
7260 }
7261
7262 static
7263 bool build_torus(struct fabric *f, struct torus *t)
7264 {
7265         int i, j, k;
7266         int im1, jm1, km1;
7267         int ip1, jp1, kp1;
7268         unsigned nlink;
7269         struct coord_dirs *o;
7270         struct f_switch *fsw0, *fsw1;
7271         struct t_switch ****sw = t->sw;
7272         bool success = true;
7273
7274         t->link_pool_sz = f->link_cnt;
7275         t->link_pool = calloc(1, t->link_pool_sz * sizeof(*t->link_pool));
7276         if (!t->link_pool) {
7277                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7278                         "ERR 4E31: Allocating torus link pool: %s\n",
7279                         strerror(errno));
7280                 goto out;
7281         }
7282         t->fabric = f;
7283
7284         /*
7285          * Get things started by locating the up to seven switches that
7286          * define the torus "seed", coordinate directions, and datelines.
7287          */
7288         o = &t->seed[t->seed_idx];
7289
7290         i = canonicalize(-o->x_dateline, t->x_sz);
7291         j = canonicalize(-o->y_dateline, t->y_sz);
7292         k = canonicalize(-o->z_dateline, t->z_sz);
7293
7294         if (o->xp_link.end[0].port < 0) {
7295                 ip1 = canonicalize(1 - o->x_dateline, t->x_sz);
7296                 fsw0 = find_f_sw(f, o->xp_link.end[0].n_id);
7297                 fsw1 = find_f_sw(f, o->xp_link.end[1].n_id);
7298                 success =
7299                         install_tswitch(t, i, j, k, fsw0) &&
7300                         install_tswitch(t, ip1, j, k, fsw1) && success;
7301         }
7302         if (o->xm_link.end[0].port < 0) {
7303                 im1 = canonicalize(-1 - o->x_dateline, t->x_sz);
7304                 fsw0 = find_f_sw(f, o->xm_link.end[0].n_id);
7305                 fsw1 = find_f_sw(f, o->xm_link.end[1].n_id);
7306                 success =
7307                         install_tswitch(t, i, j, k, fsw0) &&
7308                         install_tswitch(t, im1, j, k, fsw1) && success;
7309         }
7310         if (o->yp_link.end[0].port < 0) {
7311                 jp1 = canonicalize(1 - o->y_dateline, t->y_sz);
7312                 fsw0 = find_f_sw(f, o->yp_link.end[0].n_id);
7313                 fsw1 = find_f_sw(f, o->yp_link.end[1].n_id);
7314                 success =
7315                         install_tswitch(t, i, j, k, fsw0) &&
7316                         install_tswitch(t, i, jp1, k, fsw1) && success;
7317         }
7318         if (o->ym_link.end[0].port < 0) {
7319                 jm1 = canonicalize(-1 - o->y_dateline, t->y_sz);
7320                 fsw0 = find_f_sw(f, o->ym_link.end[0].n_id);
7321                 fsw1 = find_f_sw(f, o->ym_link.end[1].n_id);
7322                 success =
7323                         install_tswitch(t, i, j, k, fsw0) &&
7324                         install_tswitch(t, i, jm1, k, fsw1) && success;
7325         }
7326         if (o->zp_link.end[0].port < 0) {
7327                 kp1 = canonicalize(1 - o->z_dateline, t->z_sz);
7328                 fsw0 = find_f_sw(f, o->zp_link.end[0].n_id);
7329                 fsw1 = find_f_sw(f, o->zp_link.end[1].n_id);
7330                 success =
7331                         install_tswitch(t, i, j, k, fsw0) &&
7332                         install_tswitch(t, i, j, kp1, fsw1) && success;
7333         }
7334         if (o->zm_link.end[0].port < 0) {
7335                 km1 = canonicalize(-1 - o->z_dateline, t->z_sz);
7336                 fsw0 = find_f_sw(f, o->zm_link.end[0].n_id);
7337                 fsw1 = find_f_sw(f, o->zm_link.end[1].n_id);
7338                 success =
7339                         install_tswitch(t, i, j, k, fsw0) &&
7340                         install_tswitch(t, i, j, km1, fsw1) && success;
7341         }
7342         if (!success)
7343                 goto out;
7344
7345         if (!t->seed_idx)
7346                 OSM_LOG(&t->osm->log, OSM_LOG_INFO,
7347                         "Using torus seed configured as default "
7348                         "(seed sw %d,%d,%d GUID 0x%04"PRIx64").\n",
7349                         i, j, k, cl_ntoh64(sw[i][j][k]->n_id));
7350         else
7351                 OSM_LOG(&t->osm->log, OSM_LOG_INFO,
7352                         "Using torus seed configured as backup #%u "
7353                         "(seed sw %d,%d,%d GUID 0x%04"PRIx64").\n",
7354                         t->seed_idx, i, j, k, cl_ntoh64(sw[i][j][k]->n_id));
7355
7356         /*
7357          * Search the fabric and construct the expected torus topology.
7358          *
7359          * The algorithm is to consider the "cube" formed by eight switch
7360          * locations bounded by the corners i, j, k and i+1, j+1, k+1.
7361          * For each such cube look at the topology of the switches already
7362          * placed in the torus, and deduce which new switches can be placed
7363          * into their proper locations in the torus.  Examine each cube
7364          * multiple times, until the number of links moved into the torus
7365          * topology does not change.
7366          */
7367 again:
7368         nlink = t->link_cnt;
7369
7370         for (k = 0; k < (int)t->z_sz; k++)
7371                 for (j = 0; j < (int)t->y_sz; j++)
7372                         for (i = 0; i < (int)t->x_sz; i++)
7373                                 locate_sw(t, i, j, k);
7374
7375         if (t->link_cnt != nlink)
7376                 goto again;
7377
7378         /*
7379          * Move all other endpoints into torus/mesh.
7380          */
7381         for (k = 0; k < (int)t->z_sz; k++)
7382                 for (j = 0; j < (int)t->y_sz; j++)
7383                         for (i = 0; i < (int)t->x_sz; i++)
7384                                 if (!link_srcsink(t, i, j, k)) {
7385                                         success = false;
7386                                         goto out;
7387                                 }
7388 out:
7389         return success;
7390 }
7391
7392 /*
7393  * Returns a count of differences between old and new switches.
7394  */
7395 static
7396 unsigned tsw_changes(struct t_switch *nsw, struct t_switch *osw)
7397 {
7398         unsigned p, cnt = 0, port_cnt;
7399         struct endpoint *npt, *opt;
7400         struct endpoint *rnpt, *ropt;
7401
7402         if (nsw && !osw) {
7403                 cnt++;
7404                 OSM_LOG(&nsw->torus->osm->log, OSM_LOG_INFO,
7405                         "New torus switch %d,%d,%d GUID 0x%04"PRIx64"\n",
7406                         nsw->i, nsw->j, nsw->k, cl_ntoh64(nsw->n_id));
7407                 goto out;
7408         }
7409         if (osw && !nsw) {
7410                 cnt++;
7411                 OSM_LOG(&osw->torus->osm->log, OSM_LOG_INFO,
7412                         "Lost torus switch %d,%d,%d GUID 0x%04"PRIx64"\n",
7413                         osw->i, osw->j, osw->k, cl_ntoh64(osw->n_id));
7414                 goto out;
7415         }
7416         if (!(nsw && osw))
7417                 goto out;
7418
7419         if (nsw->n_id != osw->n_id) {
7420                 cnt++;
7421                 OSM_LOG(&nsw->torus->osm->log, OSM_LOG_INFO,
7422                         "Torus switch %d,%d,%d GUID "
7423                         "was 0x%04"PRIx64", now 0x%04"PRIx64"\n",
7424                         nsw->i, nsw->j, nsw->k,
7425                         cl_ntoh64(osw->n_id), cl_ntoh64(nsw->n_id));
7426         }
7427
7428         if (nsw->port_cnt != osw->port_cnt) {
7429                 cnt++;
7430                 OSM_LOG(&nsw->torus->osm->log, OSM_LOG_INFO,
7431                         "Torus switch %d,%d,%d GUID 0x%04"PRIx64" "
7432                         "had %d ports, now has %d\n",
7433                         nsw->i, nsw->j, nsw->k, cl_ntoh64(nsw->n_id),
7434                         osw->port_cnt, nsw->port_cnt);
7435         }
7436         port_cnt = nsw->port_cnt;
7437         if (port_cnt > osw->port_cnt)
7438                 port_cnt = osw->port_cnt;
7439
7440         for (p = 0; p < port_cnt; p++) {
7441                 npt = nsw->port[p];
7442                 opt = osw->port[p];
7443
7444                 if (npt && npt->link) {
7445                         if (&npt->link->end[0] == npt)
7446                                 rnpt = &npt->link->end[1];
7447                         else
7448                                 rnpt = &npt->link->end[0];
7449                 } else
7450                         rnpt = NULL;
7451
7452                 if (opt && opt->link) {
7453                         if (&opt->link->end[0] == opt)
7454                                 ropt = &opt->link->end[1];
7455                         else
7456                                 ropt = &opt->link->end[0];
7457                 } else
7458                         ropt = NULL;
7459
7460                 if (rnpt && !ropt) {
7461                         ++cnt;
7462                         OSM_LOG(&nsw->torus->osm->log, OSM_LOG_INFO,
7463                                 "Torus switch %d,%d,%d GUID 0x%04"PRIx64"[%d] "
7464                                 "remote now %s GUID 0x%04"PRIx64"[%d], "
7465                                 "was missing\n",
7466                                 nsw->i, nsw->j, nsw->k, cl_ntoh64(nsw->n_id),
7467                                 p, rnpt->type == PASSTHRU ? "sw" : "node",
7468                                 cl_ntoh64(rnpt->n_id), rnpt->port);
7469                         continue;
7470                 }
7471                 if (ropt && !rnpt) {
7472                         ++cnt;
7473                         OSM_LOG(&nsw->torus->osm->log, OSM_LOG_INFO,
7474                                 "Torus switch %d,%d,%d GUID 0x%04"PRIx64"[%d] "
7475                                 "remote now missing, "
7476                                 "was %s GUID 0x%04"PRIx64"[%d]\n",
7477                                 osw->i, osw->j, osw->k, cl_ntoh64(nsw->n_id),
7478                                 p, ropt->type == PASSTHRU ? "sw" : "node",
7479                                 cl_ntoh64(ropt->n_id), ropt->port);
7480                         continue;
7481                 }
7482                 if (!(rnpt && ropt))
7483                         continue;
7484
7485                 if (rnpt->n_id != ropt->n_id) {
7486                         ++cnt;
7487                         OSM_LOG(&nsw->torus->osm->log, OSM_LOG_INFO,
7488                                 "Torus switch %d,%d,%d GUID 0x%04"PRIx64"[%d] "
7489                                 "remote now %s GUID 0x%04"PRIx64"[%d], "
7490                                 "was %s GUID 0x%04"PRIx64"[%d]\n",
7491                                 nsw->i, nsw->j, nsw->k, cl_ntoh64(nsw->n_id),
7492                                 p, rnpt->type == PASSTHRU ? "sw" : "node",
7493                                 cl_ntoh64(rnpt->n_id), rnpt->port,
7494                                 ropt->type == PASSTHRU ? "sw" : "node",
7495                                 cl_ntoh64(ropt->n_id), ropt->port);
7496                         continue;
7497                 }
7498         }
7499 out:
7500         return cnt;
7501 }
7502
7503 static
7504 void dump_torus(struct torus *t)
7505 {
7506         unsigned i, j, k;
7507         unsigned x_sz = t->x_sz;
7508         unsigned y_sz = t->y_sz;
7509         unsigned z_sz = t->z_sz;
7510         char path[1024];
7511         FILE *file;
7512
7513         snprintf(path, sizeof(path), "%s/%s", t->osm->subn.opt.dump_files_dir,
7514                  "opensm-torus.dump");
7515         file = fopen(path, "w");
7516         if (!file) {
7517                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7518                         "ERR 4E47: cannot create file \'%s\'\n", path);
7519                 return;
7520         }
7521
7522         for (k = 0; k < z_sz; k++)
7523                 for (j = 0; j < y_sz; j++)
7524                         for (i = 0; i < x_sz; i++)
7525                                 if (t->sw[i][j][k])
7526                                         fprintf(file, "switch %u,%u,%u GUID 0x%04"
7527                                                 PRIx64 " (%s)\n",
7528                                                 i, j, k,
7529                                                 cl_ntoh64(t->sw[i][j][k]->n_id),
7530                                                 t->sw[i][j][k]->osm_switch->p_node->print_desc);
7531         fclose(file);
7532 }
7533
7534 static
7535 void report_torus_changes(struct torus *nt, struct torus *ot)
7536 {
7537         unsigned cnt = 0;
7538         unsigned i, j, k;
7539         unsigned x_sz = nt->x_sz;
7540         unsigned y_sz = nt->y_sz;
7541         unsigned z_sz = nt->z_sz;
7542         unsigned max_changes = nt->max_changes;
7543
7544         if (OSM_LOG_IS_ACTIVE_V2(&nt->osm->log, OSM_LOG_ROUTING))
7545                 dump_torus(nt);
7546
7547         if (!ot)
7548                 return;
7549
7550         if (x_sz != ot->x_sz) {
7551                 cnt++;
7552                 OSM_LOG(&nt->osm->log, OSM_LOG_INFO,
7553                         "Torus x radix was %d now %d\n",
7554                         ot->x_sz, nt->x_sz);
7555                 if (x_sz > ot->x_sz)
7556                         x_sz = ot->x_sz;
7557         }
7558         if (y_sz != ot->y_sz) {
7559                 cnt++;
7560                 OSM_LOG(&nt->osm->log, OSM_LOG_INFO,
7561                         "Torus y radix was %d now %d\n",
7562                         ot->y_sz, nt->y_sz);
7563                 if (y_sz > ot->y_sz)
7564                         y_sz = ot->y_sz;
7565         }
7566         if (z_sz != ot->z_sz) {
7567                 cnt++;
7568                 OSM_LOG(&nt->osm->log, OSM_LOG_INFO,
7569                         "Torus z radix was %d now %d\n",
7570                         ot->z_sz, nt->z_sz);
7571                 if (z_sz > ot->z_sz)
7572                         z_sz = ot->z_sz;
7573         }
7574
7575         for (k = 0; k < z_sz; k++)
7576                 for (j = 0; j < y_sz; j++)
7577                         for (i = 0; i < x_sz; i++) {
7578                                 cnt += tsw_changes(nt->sw[i][j][k],
7579                                                    ot->sw[i][j][k]);
7580                                 /*
7581                                  * Booting a big fabric will cause lots of
7582                                  * changes as hosts come up, so don't spew.
7583                                  * We want to log changes to learn more about
7584                                  * bouncing links, etc, so they can be fixed.
7585                                  */
7586                                 if (cnt > max_changes) {
7587                                         OSM_LOG(&nt->osm->log, OSM_LOG_INFO,
7588                                                 "Too many torus changes; "
7589                                                 "stopping reporting early\n");
7590                                         return;
7591                                 }
7592                         }
7593 }
7594
7595 static
7596 void rpt_torus_missing(struct torus *t, int i, int j, int k,
7597                        struct t_switch *sw, int *missing_z)
7598 {
7599         uint64_t guid_ho;
7600
7601         if (!sw) {
7602                 /*
7603                  * We can have multiple missing switches without deadlock
7604                  * if and only if they are adajacent in the Z direction.
7605                  */
7606                 if ((t->switch_cnt + 1) < t->sw_pool_sz) {
7607                         if (t->sw[i][j][canonicalize(k - 1, t->z_sz)] &&
7608                             t->sw[i][j][canonicalize(k + 1, t->z_sz)])
7609                                 t->flags |= MSG_DEADLOCK;
7610                 }
7611                 /*
7612                  * There can be only one such Z-column of missing switches.
7613                  */
7614                 if (*missing_z < 0)
7615                         *missing_z = i + j * t->x_sz;
7616                 else if (*missing_z != i + j * t->x_sz)
7617                         t->flags |= MSG_DEADLOCK;
7618
7619                 OSM_LOG(&t->osm->log, OSM_LOG_INFO,
7620                         "Missing torus switch at %d,%d,%d\n", i, j, k);
7621                 return;
7622         }
7623         guid_ho = cl_ntoh64(sw->n_id);
7624
7625         if (!(sw->ptgrp[0].port_cnt || (t->x_sz == 1) ||
7626               ((t->flags & X_MESH) && i == 0)))
7627                 OSM_LOG(&t->osm->log, OSM_LOG_INFO,
7628                         "Missing torus -x link on "
7629                         "switch %d,%d,%d GUID 0x%04"PRIx64"\n",
7630                         i, j, k, guid_ho);
7631         if (!(sw->ptgrp[1].port_cnt || (t->x_sz == 1) ||
7632               ((t->flags & X_MESH) && (i + 1) == t->x_sz)))
7633                 OSM_LOG(&t->osm->log, OSM_LOG_INFO,
7634                         "Missing torus +x link on "
7635                         "switch %d,%d,%d GUID 0x%04"PRIx64"\n",
7636                         i, j, k, guid_ho);
7637         if (!(sw->ptgrp[2].port_cnt || (t->y_sz == 1) ||
7638               ((t->flags & Y_MESH) && j == 0)))
7639                 OSM_LOG(&t->osm->log, OSM_LOG_INFO,
7640                         "Missing torus -y link on "
7641                         "switch %d,%d,%d GUID 0x%04"PRIx64"\n",
7642                         i, j, k, guid_ho);
7643         if (!(sw->ptgrp[3].port_cnt || (t->y_sz == 1) ||
7644               ((t->flags & Y_MESH) && (j + 1) == t->y_sz)))
7645                 OSM_LOG(&t->osm->log, OSM_LOG_INFO,
7646                         "Missing torus +y link on "
7647                         "switch %d,%d,%d GUID 0x%04"PRIx64"\n",
7648                         i, j, k, guid_ho);
7649         if (!(sw->ptgrp[4].port_cnt || (t->z_sz == 1) ||
7650               ((t->flags & Z_MESH) && k == 0)))
7651                 OSM_LOG(&t->osm->log, OSM_LOG_INFO,
7652                         "Missing torus -z link on "
7653                         "switch %d,%d,%d GUID 0x%04"PRIx64"\n",
7654                         i, j, k, guid_ho);
7655         if (!(sw->ptgrp[5].port_cnt || (t->z_sz == 1) ||
7656               ((t->flags & Z_MESH) && (k + 1) == t->z_sz)))
7657                 OSM_LOG(&t->osm->log, OSM_LOG_INFO,
7658                         "Missing torus +z link on "
7659                         "switch %d,%d,%d GUID 0x%04"PRIx64"\n",
7660                         i, j, k, guid_ho);
7661 }
7662
7663 /*
7664  * Returns true if the torus can be successfully routed, false otherwise.
7665  */
7666 static
7667 bool routable_torus(struct torus *t, struct fabric *f)
7668 {
7669         int i, j, k, tmp = -1;
7670         unsigned b2g_cnt, g2b_cnt;
7671         bool success = true;
7672
7673         t->flags &= ~MSG_DEADLOCK;
7674
7675         if (t->link_cnt != f->link_cnt || t->switch_cnt != f->switch_cnt)
7676                 OSM_LOG(&t->osm->log, OSM_LOG_INFO,
7677                         "Warning: Could not construct torus using all "
7678                         "known fabric switches and/or links.\n");
7679
7680         for (k = 0; k < (int)t->z_sz; k++)
7681                 for (j = 0; j < (int)t->y_sz; j++)
7682                         for (i = 0; i < (int)t->x_sz; i++)
7683                                 rpt_torus_missing(t, i, j, k,
7684                                                   t->sw[i][j][k], &tmp);
7685         /*
7686          * Check for multiple failures that create disjoint regions on a ring.
7687          */
7688         for (k = 0; k < (int)t->z_sz; k++)
7689                 for (j = 0; j < (int)t->y_sz; j++) {
7690                         b2g_cnt = 0;
7691                         g2b_cnt = 0;
7692                         for (i = 0; i < (int)t->x_sz; i++) {
7693
7694                                 if (!t->sw[i][j][k])
7695                                         continue;
7696
7697                                 if (!t->sw[i][j][k]->ptgrp[0].port_cnt)
7698                                         b2g_cnt++;
7699                                 if (!t->sw[i][j][k]->ptgrp[1].port_cnt)
7700                                         g2b_cnt++;
7701                         }
7702                         if (b2g_cnt != g2b_cnt) {
7703                                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7704                                         "ERR 4E32: strange failures in "
7705                                         "x ring at y=%d  z=%d"
7706                                         " b2g_cnt %u g2b_cnt %u\n",
7707                                         j, k, b2g_cnt, g2b_cnt);
7708                                 success = false;
7709                         }
7710                         if (b2g_cnt > 1) {
7711                                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7712                                         "ERR 4E33: disjoint failures in "
7713                                         "x ring at y=%d  z=%d\n", j, k);
7714                                 success = false;
7715                         }
7716                 }
7717
7718         for (i = 0; i < (int)t->x_sz; i++)
7719                 for (k = 0; k < (int)t->z_sz; k++) {
7720                         b2g_cnt = 0;
7721                         g2b_cnt = 0;
7722                         for (j = 0; j < (int)t->y_sz; j++) {
7723
7724                                 if (!t->sw[i][j][k])
7725                                         continue;
7726
7727                                 if (!t->sw[i][j][k]->ptgrp[2].port_cnt)
7728                                         b2g_cnt++;
7729                                 if (!t->sw[i][j][k]->ptgrp[3].port_cnt)
7730                                         g2b_cnt++;
7731                         }
7732                         if (b2g_cnt != g2b_cnt) {
7733                                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7734                                         "ERR 4E34: strange failures in "
7735                                         "y ring at x=%d  z=%d"
7736                                         " b2g_cnt %u g2b_cnt %u\n",
7737                                         i, k, b2g_cnt, g2b_cnt);
7738                                 success = false;
7739                         }
7740                         if (b2g_cnt > 1) {
7741                                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7742                                         "ERR 4E35: disjoint failures in "
7743                                         "y ring at x=%d  z=%d\n", i, k);
7744                                 success = false;
7745                         }
7746                 }
7747
7748         for (j = 0; j < (int)t->y_sz; j++)
7749                 for (i = 0; i < (int)t->x_sz; i++) {
7750                         b2g_cnt = 0;
7751                         g2b_cnt = 0;
7752                         for (k = 0; k < (int)t->z_sz; k++) {
7753
7754                                 if (!t->sw[i][j][k])
7755                                         continue;
7756
7757                                 if (!t->sw[i][j][k]->ptgrp[4].port_cnt)
7758                                         b2g_cnt++;
7759                                 if (!t->sw[i][j][k]->ptgrp[5].port_cnt)
7760                                         g2b_cnt++;
7761                         }
7762                         if (b2g_cnt != g2b_cnt) {
7763                                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7764                                         "ERR 4E36: strange failures in "
7765                                         "z ring at x=%d  y=%d"
7766                                         " b2g_cnt %u g2b_cnt %u\n",
7767                                         i, j, b2g_cnt, g2b_cnt);
7768                                 success = false;
7769                         }
7770                         if (b2g_cnt > 1) {
7771                                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7772                                         "ERR 4E37: disjoint failures in "
7773                                         "z ring at x=%d  y=%d\n", i, j);
7774                                 success = false;
7775                         }
7776                 }
7777
7778         if (t->flags & MSG_DEADLOCK) {
7779                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
7780                         "ERR 4E38: missing switch topology "
7781                         "==> message deadlock!\n");
7782                 success = false;
7783         }
7784         return success;
7785 }
7786
7787 /*
7788  * Use this function to re-establish the pointers between a torus endpoint
7789  * and an opensm osm_port_t.
7790  *
7791  * Typically this is only needed when "opensm --ucast-cache" is used, and
7792  * a CA link bounces.  When the CA port goes away, the osm_port_t object
7793  * is destroyed, invalidating the endpoint osm_port_t pointer.  When the
7794  * link comes back, a new osm_port_t object is created with a NULL priv
7795  * member.  Thus, when osm_get_torus_sl() is called it is missing the data
7796  * needed to do its work.  Use this function to fix things up.
7797  */
7798 static
7799 struct endpoint *osm_port_relink_endpoint(const osm_port_t *osm_port)
7800 {
7801         guid_t node_guid;
7802         uint8_t port_num, r_port_num;
7803         struct t_switch *sw;
7804         struct endpoint *ep = NULL;
7805         osm_switch_t *osm_sw;
7806         osm_physp_t *osm_physp;
7807         osm_node_t *osm_node, *r_osm_node;
7808
7809         /*
7810          * We need to find the torus endpoint that has the same GUID as
7811          * the osm_port.  Rather than search the entire set of endpoints,
7812          * we'll try to follow pointers.
7813          */
7814         osm_physp = osm_port->p_physp;
7815         osm_node = osm_port->p_node;
7816         port_num = osm_physp_get_port_num(osm_physp);
7817         node_guid = osm_node_get_node_guid(osm_node);
7818         /*
7819          * Switch management port?
7820          */
7821         if (port_num == 0 &&
7822             osm_node_get_type(osm_node) == IB_NODE_TYPE_SWITCH) {
7823
7824                 osm_sw = osm_node->sw;
7825                 if (osm_sw && osm_sw->priv) {
7826                         sw = osm_sw->priv;
7827                         if (sw->osm_switch == osm_sw &&
7828                             sw->port[0]->n_id == node_guid) {
7829
7830                                 ep = sw->port[0];
7831                                 goto relink_priv;
7832                         }
7833                 }
7834         }
7835         /*
7836          * CA port?  Try other end of link.  This should also catch a
7837          * router port if it is connected to a switch.
7838          */
7839         r_osm_node = osm_node_get_remote_node(osm_node, port_num, &r_port_num);
7840         if (!r_osm_node)
7841                 goto out;
7842
7843         osm_sw = r_osm_node->sw;
7844         if (!osm_sw)
7845                 goto out;
7846
7847         sw = osm_sw->priv;
7848         if (!(sw && sw->osm_switch == osm_sw))
7849                 goto out;
7850
7851         ep = sw->port[r_port_num];
7852         if (!(ep && ep->link))
7853                 goto out;
7854
7855         if (ep->link->end[0].n_id == node_guid) {
7856                 ep = &ep->link->end[0];
7857                 goto relink_priv;
7858         }
7859         if (ep->link->end[1].n_id == node_guid) {
7860                 ep = &ep->link->end[1];
7861                 goto relink_priv;
7862         }
7863         ep = NULL;
7864         goto out;
7865
7866 relink_priv:
7867         /* FIXME:
7868          * Unfortunately, we need to cast away const to rebuild the links
7869          * between the torus endpoint and the osm_port_t.
7870          *
7871          * What is really needed is to check whether pr_rcv_get_path_parms()
7872          * needs its port objects to be const.  If so, why, and whether
7873          * anything can be done about it.
7874          */
7875         ((osm_port_t *)osm_port)->priv = ep;
7876         ep->osm_port = (osm_port_t *)osm_port;
7877 out:
7878         return ep;
7879 }
7880
7881 /*
7882  * Computing LFT entries and path SL values:
7883  *
7884  * For a pristine torus, we compute LFT entries using XYZ DOR, and select
7885  * which direction to route on a ring (i.e., the 1-D torus for the coordinate
7886  * in question) based on shortest path.  We compute the SL to use for the
7887  * path based on whether we crossed a dateline (where a ring coordinate
7888  * wraps to zero) for each coordinate.
7889  *
7890  * When there is a link/switch failure, we want to compute LFT entries
7891  * to route around the failure, without changing the path SL.  I.e., we
7892  * want the SL to reach a given destination from a given source to be
7893  * independent of the presence or number of failed components in the fabric.
7894  *
7895  * In order to make this feasible, we will assume that no ring is broken
7896  * into disjoint pieces by multiple failures
7897  *
7898  * We handle failure by attempting to take the long way around any ring
7899  * with connectivity interrupted by failed components, unless the path
7900  * requires a turn on a failed switch.
7901  *
7902  * For paths that require a turn on a failed switch, we head towards the
7903  * failed switch, then turn when progress is blocked by a failure, using a
7904  * turn allowed under XYZ DOR.  However, such a path will also require a turn
7905  * that is not a legal XYZ DOR turn, so we construct the SL2VL mapping tables
7906  * such that XYZ DOR turns use one set of VLs and ZYX DOR turns use a
7907  * separate set of VLs.
7908  *
7909  * Under these rules the algorithm guarantees credit-loop-free routing for a
7910  * single failed switch, without any change in path SL values.  We can also
7911  * guarantee credit-loop-free routing for failures of multiple switches, if
7912  * they are adjacent in the last DOR direction.  Since we use XYZ-DOR,
7913  * that means failed switches at i,j,k and i,j,k+1 will not cause credit
7914  * loops.
7915  *
7916  * These failure routing rules are intended to prevent paths that cross any
7917  * coordinate dateline twice (over and back), so we don't need to worry about
7918  * any ambiguity over which SL to use for such a case.  Also, we cannot have
7919  * a ring deadlock when a ring is broken by failure and we route the long
7920  * way around, so we don't need to worry about the impact of such routing
7921  * on SL choice.
7922  */
7923
7924 /*
7925  * Functions to set our SL bit encoding for routing/QoS info.  Combine the
7926  * resuts of these functions with bitwise or to get final SL.
7927  *
7928  * SL bits 0-2 encode whether we "looped" in a given direction
7929  * on the torus on the path from source to destination.
7930  *
7931  * SL bit 3 encodes the QoS level.  We only support two QoS levels.
7932  *
7933  * Below we assume TORUS_MAX_DIM == 3 and 0 <= coord_dir < TORUS_MAX_DIM.
7934  */
7935 static inline
7936 unsigned sl_set_use_loop_vl(bool use_loop_vl, unsigned coord_dir)
7937 {
7938         return (coord_dir < TORUS_MAX_DIM)
7939                 ? ((unsigned)use_loop_vl << coord_dir) : 0;
7940 }
7941
7942 static inline
7943 unsigned sl_set_qos(unsigned qos)
7944 {
7945         return (unsigned)(!!qos) << TORUS_MAX_DIM;
7946 }
7947
7948 /*
7949  * Functions to crack our SL bit encoding for routing/QoS info.
7950  */
7951 static inline
7952 bool sl_get_use_loop_vl(unsigned sl, unsigned coord_dir)
7953 {
7954         return (coord_dir < TORUS_MAX_DIM)
7955                 ? (sl >> coord_dir) & 0x1 : false;
7956 }
7957
7958 static inline
7959 unsigned sl_get_qos(unsigned sl)
7960 {
7961         return (sl >> TORUS_MAX_DIM) & 0x1;
7962 }
7963
7964 /*
7965  * Functions to encode routing/QoS info into VL bits.  Combine the resuts of
7966  * these functions with bitwise or to get final VL.
7967  *
7968  * For interswitch links:
7969  * VL bit 0 encodes whether we need to leave on the "loop" VL.
7970  *
7971  * VL bit 1 encodes whether turn is XYZ DOR or ZYX DOR. A 3d mesh/torus
7972  * has 6 turn types: x-y, y-z, x-z, y-x, z-y, z-x.  The first three are
7973  * legal XYZ DOR turns, and the second three are legal ZYX DOR turns.
7974  * Straight-through (x-x, y-y, z-z) paths are legal in both DOR variants,
7975  * so we'll assign them to XYZ DOR VLs.
7976  *
7977  * Note that delivery to switch-local ports (i.e. those that source/sink
7978  * traffic, rather than forwarding it) cannot cause a deadlock, so that
7979  * can also use either XYZ or ZYX DOR.
7980  *
7981  * VL bit 2 encodes QoS level.
7982  *
7983  * For end port links:
7984  * VL bit 0 encodes QoS level.
7985  *
7986  * Note that if VL bit encodings are changed here, the available fabric VL
7987  * verification in verify_setup() needs to be updated as well.
7988  */
7989 static inline
7990 unsigned vl_set_loop_vl(bool use_loop_vl)
7991 {
7992         return use_loop_vl;
7993 }
7994
7995 static inline
7996 unsigned vl_set_qos_vl(unsigned qos)
7997 {
7998         return (qos & 0x1) << 2;
7999 }
8000
8001 static inline
8002 unsigned vl_set_ca_qos_vl(unsigned qos)
8003 {
8004         return qos & 0x1;
8005 }
8006
8007 static inline
8008 unsigned vl_set_turn_vl(unsigned in_coord_dir, unsigned out_coord_dir)
8009 {
8010         unsigned vl = 0;
8011
8012         if (in_coord_dir != TORUS_MAX_DIM &&
8013             out_coord_dir != TORUS_MAX_DIM)
8014                 vl = (in_coord_dir > out_coord_dir)
8015                         ? 0x1 << 1 : 0;
8016
8017         return vl;
8018 }
8019
8020 static
8021 unsigned sl2vl_entry(struct torus *t, struct t_switch *sw,
8022                      int input_pt, int output_pt, unsigned sl)
8023 {
8024         unsigned id, od, vl, data_vls;
8025
8026         if (sw && sw->port[input_pt])
8027                 id = sw->port[input_pt]->pgrp->port_grp / 2;
8028         else
8029                 id = TORUS_MAX_DIM;
8030
8031         if (sw && sw->port[output_pt])
8032                 od = sw->port[output_pt]->pgrp->port_grp / 2;
8033         else
8034                 od = TORUS_MAX_DIM;
8035
8036         if (sw)
8037                 data_vls = t->osm->subn.min_sw_data_vls;
8038         else
8039                 data_vls = t->osm->subn.min_data_vls;
8040
8041         vl = 0;
8042         if (sw && od != TORUS_MAX_DIM) {
8043                 if (data_vls >= 2)
8044                         vl |= vl_set_loop_vl(sl_get_use_loop_vl(sl, od));
8045                 if (data_vls >= 4)
8046                         vl |= vl_set_turn_vl(id, od);
8047                 if (data_vls >= 8)
8048                         vl |= vl_set_qos_vl(sl_get_qos(sl));
8049         } else {
8050                 if (data_vls >= 2)
8051                         vl |= vl_set_ca_qos_vl(sl_get_qos(sl));
8052         }
8053         return vl;
8054 }
8055
8056 static
8057 void torus_update_osm_sl2vl(void *context, osm_physp_t *osm_phys_port,
8058                             uint8_t iport_num, uint8_t oport_num,
8059                             ib_slvl_table_t *osm_oport_sl2vl)
8060 {
8061         osm_node_t *node = osm_physp_get_node_ptr(osm_phys_port);
8062         struct torus_context *ctx = context;
8063         struct t_switch *sw = NULL;
8064         int sl, vl;
8065
8066         if (node->sw) {
8067                 sw = node->sw->priv;
8068                 if (sw && sw->osm_switch != node->sw) {
8069                         osm_log_t *log = &ctx->osm->log;
8070                         guid_t guid;
8071
8072                         guid = osm_node_get_node_guid(node);
8073                         OSM_LOG(log, OSM_LOG_INFO,
8074                                 "Note: osm_switch (GUID 0x%04"PRIx64") "
8075                                 "not in torus fabric description\n",
8076                                 cl_ntoh64(guid));
8077                         return;
8078                 }
8079         }
8080         for (sl = 0; sl < 16; sl++) {
8081                 vl = sl2vl_entry(ctx->torus, sw, iport_num, oport_num, sl);
8082                 ib_slvl_table_set(osm_oport_sl2vl, sl, vl);
8083         }
8084 }
8085
8086 static
8087 void torus_update_osm_vlarb(void *context, osm_physp_t *osm_phys_port,
8088                             uint8_t port_num, ib_vl_arb_table_t *block,
8089                             unsigned block_length, unsigned block_num)
8090 {
8091         osm_node_t *node = osm_physp_get_node_ptr(osm_phys_port);
8092         struct torus_context *ctx = context;
8093         struct t_switch *sw = NULL;
8094         unsigned i, next;
8095
8096         if (node->sw) {
8097                 sw = node->sw->priv;
8098                 if (sw && sw->osm_switch != node->sw) {
8099                         osm_log_t *log = &ctx->osm->log;
8100                         guid_t guid;
8101
8102                         guid = osm_node_get_node_guid(node);
8103                         OSM_LOG(log, OSM_LOG_INFO,
8104                                 "Note: osm_switch (GUID 0x%04"PRIx64") "
8105                                 "not in torus fabric description\n",
8106                                 cl_ntoh64(guid));
8107                         return;
8108                 }
8109         }
8110
8111         /*
8112          * If osm_phys_port is a switch port that connects to a CA, then
8113          * we're using at most VL 0 (for QoS level 0) and VL 1 (for QoS
8114          * level 1).  We've been passed the VLarb values for a switch
8115          * external port, so we need to fix them up to avoid unexpected
8116          * results depending on how the switch handles VLarb values for
8117          * unprogrammed VLs.
8118          *
8119          * For inter-switch links torus-2QoS uses VLs 0-3 to implement
8120          * QoS level 0, and VLs 4-7 to implement QoS level 1.
8121          *
8122          * So, leave VL 0 alone, remap VL 4 to VL 1, zero out the rest,
8123          * and compress out the zero entries to the end.
8124          */
8125         if (!sw || !port_num || !sw->port[port_num] ||
8126             sw->port[port_num]->pgrp->port_grp != 2 * TORUS_MAX_DIM)
8127                 return;
8128
8129         next = 0;
8130         for (i = 0; i < block_length; i++) {
8131                 switch (block->vl_entry[i].vl) {
8132                 case 4:
8133                         block->vl_entry[i].vl = 1;
8134                         /* fall through */
8135                 case 0:
8136                         block->vl_entry[next].vl = block->vl_entry[i].vl;
8137                         block->vl_entry[next].weight = block->vl_entry[i].weight;
8138                         next++;
8139                         /*
8140                          * If we didn't update vl_entry[i] in place,
8141                          * fall through to zero it out.
8142                          */
8143                         if (next > i)
8144                                 break;
8145                 default:
8146                         block->vl_entry[i].vl = 0;
8147                         block->vl_entry[i].weight = 0;
8148                         break;
8149                 }
8150         }
8151 }
8152
8153 /*
8154  * Computes the path lengths *vl0_len and *vl1_len to get from src
8155  * to dst on a ring with count switches.
8156  *
8157  * *vl0_len is the path length for a direct path; it corresponds to a path
8158  * that should be assigned to use VL0 in a switch.  *vl1_len is the path
8159  * length for a path that wraps aroung the ring, i.e. where the ring index
8160  * goes from count to zero or from zero to count.  It corresponds to the path
8161  * that should be assigned to use VL1 in a switch.
8162  */
8163 static
8164 void get_pathlen(unsigned src, unsigned dst, unsigned count,
8165                  unsigned *vl0_len, unsigned *vl1_len)
8166 {
8167         unsigned s, l;          /* assume s < l */
8168
8169         if (dst > src) {
8170                 s = src;
8171                 l = dst;
8172         } else {
8173                 s = dst;
8174                 l = src;
8175         }
8176         *vl0_len = l - s;
8177         *vl1_len = s + count - l;
8178 }
8179
8180 /*
8181  * Returns a positive number if we should take the "positive" ring direction
8182  * to reach dst from src, a negative number if we should take the "negative"
8183  * ring direction, and 0 if src and dst are the same.  The choice is strictly
8184  * based on which path is shorter.
8185  */
8186 static
8187 int ring_dir_idx(unsigned src, unsigned dst, unsigned count)
8188 {
8189         int r;
8190         unsigned vl0_len, vl1_len;
8191
8192         if (dst == src)
8193                 return 0;
8194
8195         get_pathlen(src, dst, count, &vl0_len, &vl1_len);
8196
8197         if (dst > src)
8198                 r = vl0_len <= vl1_len ? 1 : -1;
8199         else
8200                 r = vl0_len <= vl1_len ? -1 : 1;
8201
8202         return r;
8203 }
8204
8205 /*
8206  * Returns true if the VL1 path should be used to reach src from dst on a
8207  * ring, based on which path is shorter.
8208  */
8209 static
8210 bool use_vl1(unsigned src, unsigned dst, unsigned count)
8211 {
8212         unsigned vl0_len, vl1_len;
8213
8214         get_pathlen(src, dst, count, &vl0_len, &vl1_len);
8215
8216         return vl0_len <= vl1_len ? false : true;
8217 }
8218
8219 /*
8220  * Returns the next switch in the ring of switches along coordinate direction
8221  * cdir, in the positive ring direction if rdir is positive, and in the
8222  * negative ring direction if rdir is negative.
8223  *
8224  * Returns NULL if rdir is zero, or there is no next switch.
8225  */
8226 static
8227 struct t_switch *ring_next_sw(struct t_switch *sw, unsigned cdir, int rdir)
8228 {
8229         unsigned pt_grp, far_end = 0;
8230
8231         if (!rdir)
8232                 return NULL;
8233         /*
8234          * Recall that links are installed into the torus so that their 1 end
8235          * is in the "positive" coordinate direction relative to their 0 end
8236          * (see link_tswitches() and connect_tlink()).  Recall also that for
8237          * interswitch links, all links in a given switch port group have the
8238          * same endpoints, so we just need to look at the first link.
8239          */
8240         pt_grp = 2 * cdir;
8241         if (rdir > 0) {
8242                 pt_grp++;
8243                 far_end = 1;
8244         }
8245
8246         if (!sw->ptgrp[pt_grp].port_cnt)
8247                 return NULL;
8248
8249         return sw->ptgrp[pt_grp].port[0]->link->end[far_end].sw;
8250 }
8251
8252 /*
8253  * Returns a positive number if we should take the "positive" ring direction
8254  * to reach dsw from ssw, a negative number if we should take the "negative"
8255  * ring direction, and 0 if src and dst are the same, or if dsw is not
8256  * reachable from ssw because the path is interrupted by failure.
8257  */
8258 static
8259 int ring_dir_path(struct torus *t, unsigned cdir,
8260                   struct t_switch *ssw, struct t_switch *dsw)
8261 {
8262         int d = 0;
8263         struct t_switch *sw;
8264
8265         switch (cdir) {
8266         case 0:
8267                 d = ring_dir_idx(ssw->i, dsw->i, t->x_sz);
8268                 break;
8269         case 1:
8270                 d = ring_dir_idx(ssw->j, dsw->j, t->y_sz);
8271                 break;
8272         case 2:
8273                 d = ring_dir_idx(ssw->k, dsw->k, t->z_sz);
8274                 break;
8275         default:
8276                 break;
8277         }
8278         if (!d)
8279                 goto out;
8280
8281         sw = ssw;
8282         while (sw) {
8283                 sw = ring_next_sw(sw, cdir, d);
8284                 if (sw == dsw)
8285                         goto out;
8286         }
8287         d *= -1;
8288         sw = ssw;
8289         while (sw) {
8290                 sw = ring_next_sw(sw, cdir, d);
8291                 if (sw == dsw)
8292                         goto out;
8293         }
8294         d = 0;
8295 out:
8296         return d;
8297 }
8298
8299 /*
8300  * Returns true, and sets *pt_grp to the port group index to use for the
8301  * next hop, if it is possible to make progress from ssw to dsw along the
8302  * coordinate direction cdir, taking into account whether there are
8303  * interruptions in the path.
8304  *
8305  * This next hop result can be used without worrying about ring deadlocks -
8306  * if we don't choose the shortest path it is because there is a failure in
8307  * the ring, which removes the possibilility of a ring deadlock on that ring.
8308  */
8309 static
8310 bool next_hop_path(struct torus *t, unsigned cdir,
8311                    struct t_switch *ssw, struct t_switch *dsw,
8312                    unsigned *pt_grp)
8313 {
8314         struct t_switch *tsw = NULL;
8315         bool success = false;
8316         int d;
8317
8318         /*
8319          * If the path from ssw to dsw turns, this is the switch where the
8320          * turn happens.
8321          */
8322         switch (cdir) {
8323         case 0:
8324                 tsw = t->sw[dsw->i][ssw->j][ssw->k];
8325                 break;
8326         case 1:
8327                 tsw = t->sw[ssw->i][dsw->j][ssw->k];
8328                 break;
8329         case 2:
8330                 tsw = t->sw[ssw->i][ssw->j][dsw->k];
8331                 break;
8332         default:
8333                 goto out;
8334         }
8335         if (tsw) {
8336                 d = ring_dir_path(t, cdir, ssw, tsw);
8337                 cdir *= 2;
8338                 if (d > 0)
8339                         *pt_grp = cdir + 1;
8340                 else if (d < 0)
8341                         *pt_grp = cdir;
8342                 else
8343                         goto out;
8344                 success = true;
8345         }
8346 out:
8347         return success;
8348 }
8349
8350 /*
8351  * Returns true, and sets *pt_grp to the port group index to use for the
8352  * next hop, if it is possible to make progress from ssw to dsw along the
8353  * coordinate direction cdir.  This decision is made strictly on a
8354  * shortest-path basis without regard for path availability.
8355  */
8356 static
8357 bool next_hop_idx(struct torus *t, unsigned cdir,
8358                   struct t_switch *ssw, struct t_switch *dsw,
8359                   unsigned *pt_grp)
8360 {
8361         int d;
8362         unsigned g;
8363         bool success = false;
8364
8365         switch (cdir) {
8366         case 0:
8367                 d = ring_dir_idx(ssw->i, dsw->i, t->x_sz);
8368                 break;
8369         case 1:
8370                 d = ring_dir_idx(ssw->j, dsw->j, t->y_sz);
8371                 break;
8372         case 2:
8373                 d = ring_dir_idx(ssw->k, dsw->k, t->z_sz);
8374                 break;
8375         default:
8376                 goto out;
8377         }
8378
8379         cdir *= 2;
8380         if (d > 0)
8381                 g = cdir + 1;
8382         else if (d < 0)
8383                 g = cdir;
8384         else
8385                 goto out;
8386
8387         if (!ssw->ptgrp[g].port_cnt)
8388                 goto out;
8389
8390         *pt_grp = g;
8391         success = true;
8392 out:
8393         return success;
8394 }
8395
8396 static
8397 void warn_on_routing(const char *msg,
8398                      struct t_switch *sw, struct t_switch *dsw)
8399 {
8400         OSM_LOG(&sw->torus->osm->log, OSM_LOG_ERROR,
8401                 "%s from sw 0x%04"PRIx64" (%d,%d,%d) "
8402                 "to sw 0x%04"PRIx64" (%d,%d,%d)\n",
8403                 msg, cl_ntoh64(sw->n_id), sw->i, sw->j, sw->k,
8404                 cl_ntoh64(dsw->n_id), dsw->i, dsw->j, dsw->k);
8405 }
8406
8407 static
8408 bool next_hop_x(struct torus *t,
8409                 struct t_switch *ssw, struct t_switch *dsw, unsigned *pt_grp)
8410 {
8411         if (t->sw[dsw->i][ssw->j][ssw->k])
8412                 /*
8413                  * The next turning switch on this path is available,
8414                  * so head towards it by the shortest available path.
8415                  */
8416                 return next_hop_path(t, 0, ssw, dsw, pt_grp);
8417         else
8418                 /*
8419                  * The next turning switch on this path is not
8420                  * available, so head towards it in the shortest
8421                  * path direction.
8422                  */
8423                 return next_hop_idx(t, 0, ssw, dsw, pt_grp);
8424 }
8425
8426 static
8427 bool next_hop_y(struct torus *t,
8428                 struct t_switch *ssw, struct t_switch *dsw, unsigned *pt_grp)
8429 {
8430         if (t->sw[ssw->i][dsw->j][ssw->k])
8431                 /*
8432                  * The next turning switch on this path is available,
8433                  * so head towards it by the shortest available path.
8434                  */
8435                 return next_hop_path(t, 1, ssw, dsw, pt_grp);
8436         else
8437                 /*
8438                  * The next turning switch on this path is not
8439                  * available, so head towards it in the shortest
8440                  * path direction.
8441                  */
8442                 return next_hop_idx(t, 1, ssw, dsw, pt_grp);
8443 }
8444
8445 static
8446 bool next_hop_z(struct torus *t,
8447                 struct t_switch *ssw, struct t_switch *dsw, unsigned *pt_grp)
8448 {
8449         return next_hop_path(t, 2, ssw, dsw, pt_grp);
8450 }
8451
8452 /*
8453  * Returns the port number on *sw to use to reach *dsw, or -1 if unable to
8454  * route.
8455  */
8456 static
8457 int lft_port(struct torus *t,
8458              struct t_switch *sw, struct t_switch *dsw,
8459              bool update_port_cnt, bool ca)
8460 {
8461         unsigned g, p;
8462         struct port_grp *pg;
8463
8464         /*
8465          * The IBA does not provide a way to preserve path history for
8466          * routing decisions and VL assignment, and the only mechanism to
8467          * provide global fabric knowledge to the routing engine is via
8468          * the four SL bits.  This severely constrains the ability to deal
8469          * with missing/dead switches.
8470          *
8471          * Also, if routing a torus with XYZ-DOR, the only way to route
8472          * around a missing/dead switch is to introduce a turn that is
8473          * illegal under XYZ-DOR.
8474          *
8475          * But here's what we can do:
8476          *
8477          * We have a VL bit we use to flag illegal turns, thus putting the
8478          * hop directly after an illegal turn on a separate set of VLs.
8479          * Unfortunately, since there is no path history,  the _second_
8480          * and subsequent hops after an illegal turn use the standard
8481          * XYZ-DOR VL set.  This is enough to introduce credit loops in
8482          * many cases.
8483          *
8484          * To minimize the number of cases such illegal turns can introduce
8485          * credit loops, we try to introduce the illegal turn as late in a
8486          * path as possible.
8487          *
8488          * Define a turning switch as a switch where a path turns from one
8489          * coordinate direction onto another.  If a turning switch in a path
8490          * is missing, construct the LFT entries so that the path progresses
8491          * as far as possible on the shortest path to the turning switch.
8492          * When progress is not possible, turn onto the next coordinate
8493          * direction.
8494          *
8495          * The next turn after that will be an illegal turn, after which
8496          * point the path will continue to use a standard XYZ-DOR path.
8497          */
8498         if (dsw->i != sw->i) {
8499
8500                 if (next_hop_x(t, sw, dsw, &g))
8501                         goto done;
8502                 /*
8503                  * This path has made as much progress in this direction as
8504                  * is possible, so turn it now.
8505                  */
8506                 if (dsw->j != sw->j && next_hop_y(t, sw, dsw, &g))
8507                         goto done;
8508
8509                 if (dsw->k != sw->k && next_hop_z(t, sw, dsw, &g))
8510                         goto done;
8511
8512                 warn_on_routing("Error: unable to route", sw, dsw);
8513                 goto no_route;
8514         } else if (dsw->j != sw->j) {
8515
8516                 if (next_hop_y(t, sw, dsw, &g))
8517                         goto done;
8518
8519                 if (dsw->k != sw->k && next_hop_z(t, sw, dsw, &g))
8520                         goto done;
8521
8522                 warn_on_routing("Error: unable to route", sw, dsw);
8523                 goto no_route;
8524         } else {
8525                 if (dsw->k == sw->k)
8526                         warn_on_routing("Warning: bad routing", sw, dsw);
8527
8528                 if (next_hop_z(t, sw, dsw, &g))
8529                         goto done;
8530
8531                 warn_on_routing("Error: unable to route", sw, dsw);
8532                 goto no_route;
8533         }
8534 done:
8535         pg = &sw->ptgrp[g];
8536         if (!pg->port_cnt)
8537                 goto no_route;
8538
8539         if (update_port_cnt) {
8540                 if (ca)
8541                         p = pg->ca_dlid_cnt++ % pg->port_cnt;
8542                 else
8543                         p = pg->sw_dlid_cnt++ % pg->port_cnt;
8544         } else {
8545                 /*
8546                  * If we're not updating port counts, then we're just running
8547                  * routes for SL path checking, and it doesn't matter which
8548                  * of several parallel links we use.  Use the first one.
8549                  */
8550                 p = 0;
8551         }
8552         p = pg->port[p]->port;
8553
8554         return p;
8555
8556 no_route:
8557         /*
8558          * We can't get there from here.
8559          */
8560         OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
8561                 "ERR 4E39: routing on sw 0x%04"PRIx64": sending "
8562                 "traffic for dest sw 0x%04"PRIx64" to port %u\n",
8563                 cl_ntoh64(sw->n_id), cl_ntoh64(dsw->n_id), OSM_NO_PATH);
8564         return -1;
8565 }
8566
8567 static
8568 bool get_lid(struct port_grp *pg, unsigned p,
8569              uint16_t *dlid_base, uint8_t *dlid_lmc, bool *ca)
8570 {
8571         struct endpoint *ep;
8572         osm_port_t *osm_port;
8573
8574         if (p >= pg->port_cnt) {
8575                 OSM_LOG(&pg->sw->torus->osm->log, OSM_LOG_ERROR,
8576                         "ERR 4E3A: Port group index %u too large: sw "
8577                         "0x%04"PRIx64" pt_grp %u pt_grp_cnt %u\n",
8578                         p, cl_ntoh64(pg->sw->n_id),
8579                         (unsigned)pg->port_grp, (unsigned)pg->port_cnt);
8580                 return false;
8581         }
8582         if (pg->port[p]->type == SRCSINK) {
8583                 ep = pg->port[p];
8584                 if (ca)
8585                         *ca = false;
8586         } else if (pg->port[p]->type == PASSTHRU &&
8587                    pg->port[p]->link->end[1].type == SRCSINK) {
8588                 /*
8589                  * If this port is connected via a link to a CA, then we
8590                  * know link->end[0] is the switch end and link->end[1] is
8591                  * the CA end; see build_ca_link() and link_srcsink().
8592                  */
8593                 ep = &pg->port[p]->link->end[1];
8594                 if (ca)
8595                         *ca = true;
8596         } else {
8597                 OSM_LOG(&pg->sw->torus->osm->log, OSM_LOG_ERROR,
8598                         "ERR 4E3B: Switch 0x%04"PRIx64" port %d improperly connected\n",
8599                         cl_ntoh64(pg->sw->n_id), pg->port[p]->port);
8600                 return false;
8601         }
8602         osm_port = ep->osm_port;
8603         if (!(osm_port && osm_port->priv == ep)) {
8604                 OSM_LOG(&pg->sw->torus->osm->log, OSM_LOG_ERROR,
8605                         "ERR 4E3C: ep->osm_port->priv != ep "
8606                         "for sw 0x%04"PRIx64" port %d\n",
8607                         cl_ntoh64(((struct t_switch *)(ep->sw))->n_id), ep->port);
8608                 return false;
8609         }
8610         *dlid_base = cl_ntoh16(osm_physp_get_base_lid(osm_port->p_physp));
8611         *dlid_lmc = osm_physp_get_lmc(osm_port->p_physp);
8612
8613         return true;
8614 }
8615
8616 static
8617 bool torus_lft(struct torus *t, struct t_switch *sw)
8618 {
8619         bool success = true;
8620         int dp;
8621         unsigned p, s;
8622         uint16_t l, dlid_base;
8623         uint8_t dlid_lmc;
8624         bool ca;
8625         struct port_grp *pgrp;
8626         struct t_switch *dsw;
8627         osm_switch_t *osm_sw;
8628         uint8_t order[IB_NODE_NUM_PORTS_MAX+1];
8629
8630         if (!(sw->osm_switch && sw->osm_switch->priv == sw)) {
8631                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
8632                         "ERR 4E3D: sw->osm_switch->priv != sw "
8633                         "for sw 0x%04"PRIx64"\n", cl_ntoh64(sw->n_id));
8634                 return false;
8635         }
8636         osm_sw = sw->osm_switch;
8637         memset(osm_sw->new_lft, OSM_NO_PATH, osm_sw->lft_size);
8638
8639         for (s = 0; s < t->switch_cnt; s++) {
8640
8641                 dsw = t->sw_pool[s];
8642                 pgrp = &dsw->ptgrp[2 * TORUS_MAX_DIM];
8643
8644                 memset(order, IB_INVALID_PORT_NUM, sizeof(order));
8645                 for (p = 0; p < pgrp->port_cnt; p++)
8646                         order[pgrp->port[p]->port] = p;
8647
8648                 for (p = 0; p < ARRAY_SIZE(order); p++) {
8649
8650                         uint8_t px = order[t->port_order[p]];
8651
8652                         if (px == IB_INVALID_PORT_NUM)
8653                                 continue;
8654
8655                         if (!get_lid(pgrp, px, &dlid_base, &dlid_lmc, &ca))
8656                                 return false;
8657
8658                         if (sw->n_id == dsw->n_id)
8659                                 dp = pgrp->port[px]->port;
8660                         else
8661                                 dp = lft_port(t, sw, dsw, true, ca);
8662                         /*
8663                          * LMC > 0 doesn't really make sense for torus-2QoS.
8664                          * So, just make sure traffic gets delivered if
8665                          * non-zero LMC is used.
8666                          */
8667                         if (dp >= 0)
8668                                 for (l = 0; l < (1U << dlid_lmc); l++)
8669                                         osm_sw->new_lft[dlid_base + l] = dp;
8670                         else
8671                                 success = false;
8672                 }
8673         }
8674         return success;
8675 }
8676
8677 static
8678 osm_mtree_node_t *mcast_stree_branch(struct t_switch *sw, osm_switch_t *osm_sw,
8679                                      osm_mgrp_box_t *mgb, unsigned depth,
8680                                      unsigned *port_cnt, unsigned *max_depth)
8681 {
8682         osm_mtree_node_t *mtn = NULL;
8683         osm_mcast_tbl_t *mcast_tbl, *ds_mcast_tbl;
8684         osm_node_t *ds_node;
8685         struct t_switch *ds_sw;
8686         struct port_grp *ptgrp;
8687         struct link *link;
8688         struct endpoint *port;
8689         unsigned g, p;
8690         unsigned mcast_fwd_ports = 0, mcast_end_ports = 0;
8691
8692         depth++;
8693
8694         if (osm_sw->priv != sw) {
8695                 OSM_LOG(&sw->torus->osm->log, OSM_LOG_ERROR,
8696                         "ERR 4E3E: osm_sw (GUID 0x%04"PRIx64") "
8697                         "not in torus fabric description\n",
8698                         cl_ntoh64(osm_node_get_node_guid(osm_sw->p_node)));
8699                 goto out;
8700         }
8701         if (!osm_switch_supports_mcast(osm_sw)) {
8702                 OSM_LOG(&sw->torus->osm->log, OSM_LOG_ERROR,
8703                         "ERR 4E3F: osm_sw (GUID 0x%04"PRIx64") "
8704                         "does not support multicast\n",
8705                         cl_ntoh64(osm_node_get_node_guid(osm_sw->p_node)));
8706                 goto out;
8707         }
8708         mtn = osm_mtree_node_new(osm_sw);
8709         if (!mtn) {
8710                 OSM_LOG(&sw->torus->osm->log, OSM_LOG_ERROR,
8711                         "ERR 4E46: Insufficient memory to build multicast tree\n");
8712                 goto out;
8713         }
8714         mcast_tbl = osm_switch_get_mcast_tbl_ptr(osm_sw);
8715         /*
8716          * Recurse to downstream switches, i.e. those closer to master
8717          * spanning tree branch tips.
8718          *
8719          * Note that if there are multiple ports in this port group, i.e.,
8720          * multiple parallel links, we can pick any one of them to use for
8721          * any individual MLID without causing loops.  Pick one based on MLID
8722          * for now, until someone turns up evidence we need to be smarter.
8723          *
8724          * Also, it might be we got called in a window between a switch getting
8725          * removed from the fabric, and torus-2QoS getting to rebuild its
8726          * fabric representation.  If that were to happen, our next hop
8727          * osm_switch pointer might be stale.  Look it up via opensm's fabric
8728          * description to be sure it's not.
8729          */
8730         for (g = 0; g < 2 * TORUS_MAX_DIM; g++) {
8731                 ptgrp = &sw->ptgrp[g];
8732                 if (!ptgrp->to_stree_tip)
8733                         continue;
8734
8735                 p = mgb->mlid % ptgrp->port_cnt;/* port # in port group */
8736                 p = ptgrp->port[p]->port;       /* now port # in switch */
8737
8738                 ds_node = osm_node_get_remote_node(osm_sw->p_node, p, NULL);
8739                 ds_sw = ptgrp->to_stree_tip->sw;
8740
8741                 if (!(ds_node && ds_node->sw &&
8742                       ds_sw->osm_switch == ds_node->sw)) {
8743                         OSM_LOG(&sw->torus->osm->log, OSM_LOG_ERROR,
8744                                 "ERR 4E40: stale pointer to osm_sw "
8745                                 "(GUID 0x%04"PRIx64")\n", cl_ntoh64(ds_sw->n_id));
8746                         continue;
8747                 }
8748                 mtn->child_array[p] =
8749                         mcast_stree_branch(ds_sw, ds_node->sw, mgb,
8750                                            depth, port_cnt, max_depth);
8751                 if (!mtn->child_array[p])
8752                         continue;
8753
8754                 osm_mcast_tbl_set(mcast_tbl, mgb->mlid, p);
8755                 mcast_fwd_ports++;
8756                 /*
8757                  * Since we forward traffic for this multicast group on this
8758                  * port, cause the switch on the other end of the link
8759                  * to forward traffic back to us.  Do it now since have at
8760                  * hand the link used; otherwise it'll be hard to figure out
8761                  * later, and if we get it wrong we get a MC routing loop.
8762                  */
8763                 link = sw->port[p]->link;
8764                 ds_mcast_tbl = osm_switch_get_mcast_tbl_ptr(ds_node->sw);
8765
8766                 if (&link->end[0] == sw->port[p])
8767                         osm_mcast_tbl_set(ds_mcast_tbl, mgb->mlid,
8768                                           link->end[1].port);
8769                 else
8770                         osm_mcast_tbl_set(ds_mcast_tbl, mgb->mlid,
8771                                           link->end[0].port);
8772         }
8773         /*
8774          * Add any host ports marked as in mcast group into spanning tree.
8775          */
8776         ptgrp = &sw->ptgrp[2 * TORUS_MAX_DIM];
8777         for (p = 0; p < ptgrp->port_cnt; p++) {
8778                 port = ptgrp->port[p];
8779                 if (port->tmp) {
8780                         port->tmp = NULL;
8781                         mtn->child_array[port->port] = OSM_MTREE_LEAF;
8782                         osm_mcast_tbl_set(mcast_tbl, mgb->mlid, port->port);
8783                         mcast_end_ports++;
8784                 }
8785         }
8786         if (!(mcast_end_ports || mcast_fwd_ports)) {
8787                 osm_mtree_destroy(mtn);
8788                 mtn = NULL;
8789         } else if (depth > *max_depth)
8790                 *max_depth = depth;
8791
8792         *port_cnt += mcast_end_ports;
8793 out:
8794         return mtn;
8795 }
8796
8797 static
8798 osm_port_t *next_mgrp_box_port(osm_mgrp_box_t *mgb,
8799                                cl_list_item_t **list_iterator,
8800                                cl_map_item_t **map_iterator)
8801 {
8802         osm_mgrp_t *mgrp;
8803         osm_mcm_port_t *mcm_port;
8804         osm_port_t *osm_port = NULL;
8805         cl_map_item_t *m_item = *map_iterator;
8806         cl_list_item_t *l_item = *list_iterator;
8807
8808 next_mgrp:
8809         if (!l_item)
8810                 l_item = cl_qlist_head(&mgb->mgrp_list);
8811         if (l_item == cl_qlist_end(&mgb->mgrp_list)) {
8812                 l_item = NULL;
8813                 goto out;
8814         }
8815         mgrp = cl_item_obj(l_item, mgrp, list_item);
8816
8817         if (!m_item)
8818                 m_item = cl_qmap_head(&mgrp->mcm_port_tbl);
8819         if (m_item == cl_qmap_end(&mgrp->mcm_port_tbl)) {
8820                 m_item = NULL;
8821                 l_item = cl_qlist_next(l_item);
8822                 goto next_mgrp;
8823         }
8824         mcm_port = cl_item_obj(m_item, mcm_port, map_item);
8825         m_item = cl_qmap_next(m_item);
8826         osm_port = mcm_port->port;
8827 out:
8828         *list_iterator = l_item;
8829         *map_iterator = m_item;
8830         return osm_port;
8831 }
8832
8833 static
8834 ib_api_status_t torus_mcast_stree(void *context, osm_mgrp_box_t *mgb)
8835 {
8836         struct torus_context *ctx = context;
8837         struct torus *t = ctx->torus;
8838         cl_map_item_t *m_item = NULL;
8839         cl_list_item_t *l_item = NULL;
8840         osm_port_t *osm_port;
8841         osm_switch_t *osm_sw;
8842         struct endpoint *port;
8843         unsigned port_cnt = 0, max_depth = 0;
8844
8845         osm_purge_mtree(&ctx->osm->sm, mgb);
8846
8847         /*
8848          * Build a spanning tree for a multicast group by first marking
8849          * the torus endpoints that are participating in the group.
8850          * Then do a depth-first search of the torus master spanning
8851          * tree to build up the spanning tree specific to this group.
8852          *
8853          * Since the torus master spanning tree is constructed specifically
8854          * to guarantee that multicast will not deadlock against unicast
8855          * when they share VLs, we can be sure that any multicast group
8856          * spanning tree constructed this way has the same property.
8857          */
8858         while ((osm_port = next_mgrp_box_port(mgb, &l_item, &m_item))) {
8859                 port = osm_port->priv;
8860                 if (!(port && port->osm_port == osm_port)) {
8861                         port = osm_port_relink_endpoint(osm_port);
8862                         if (!port) {
8863                                 guid_t id;
8864                                 id = osm_node_get_node_guid(osm_port->p_node);
8865                                 OSM_LOG(&ctx->osm->log, OSM_LOG_ERROR,
8866                                         "ERR 4E41: osm_port (GUID 0x%04"PRIx64") "
8867                                         "not in torus fabric description\n",
8868                                         cl_ntoh64(id));
8869                                 continue;
8870                         }
8871                 }
8872                 /*
8873                  * If this is a CA port, mark the switch port at the
8874                  * other end of this port's link.
8875                  *
8876                  * By definition, a CA port is connected to end[1] of a link,
8877                  * and the switch port is end[0].  See build_ca_link() and
8878                  * link_srcsink().
8879                  */
8880                 if (port->link)
8881                         port = &port->link->end[0];
8882                 port->tmp = osm_port;
8883         }
8884         /*
8885          * It might be we got called in a window between a switch getting
8886          * removed from the fabric, and torus-2QoS getting to rebuild its
8887          * fabric representation.  If that were to happen, our
8888          * master_stree_root->osm_switch pointer might be stale.  Look up
8889          * the osm_switch by GUID to be sure it's not.
8890          *
8891          * Also, call into mcast_stree_branch with depth = -1, because
8892          * depth at root switch needs to be 0.
8893          */
8894         osm_sw = (osm_switch_t *)cl_qmap_get(&ctx->osm->subn.sw_guid_tbl,
8895                                              t->master_stree_root->n_id);
8896         if (!(osm_sw && t->master_stree_root->osm_switch == osm_sw)) {
8897                 OSM_LOG(&ctx->osm->log, OSM_LOG_ERROR,
8898                         "ERR 4E42: stale pointer to osm_sw (GUID 0x%04"PRIx64")\n",
8899                         cl_ntoh64(t->master_stree_root->n_id));
8900                 return IB_ERROR;
8901         }
8902         mgb->root = mcast_stree_branch(t->master_stree_root, osm_sw,
8903                                        mgb, -1, &port_cnt, &max_depth);
8904
8905         OSM_LOG(&ctx->osm->log, OSM_LOG_VERBOSE,
8906                 "Configured MLID 0x%X for %u ports, max tree depth = %u\n",
8907                 mgb->mlid, port_cnt, max_depth);
8908
8909         return IB_SUCCESS;
8910 }
8911
8912 static
8913 bool good_xy_ring(struct torus *t, const int x, const int y, const int z)
8914 {
8915         struct t_switch ****sw = t->sw;
8916         bool good_ring = true;
8917         int x_tst, y_tst;
8918
8919         for (x_tst = 0; x_tst < t->x_sz && good_ring; x_tst++)
8920                 good_ring = sw[x_tst][y][z];
8921
8922         for (y_tst = 0; y_tst < t->y_sz && good_ring; y_tst++)
8923                 good_ring = sw[x][y_tst][z];
8924
8925         return good_ring;
8926 }
8927
8928 static
8929 struct t_switch *find_plane_mid(struct torus *t, const int z)
8930 {
8931         int x, dx, xm = t->x_sz / 2;
8932         int y, dy, ym = t->y_sz / 2;
8933         struct t_switch ****sw = t->sw;
8934
8935         if (good_xy_ring(t, xm, ym, z))
8936                 return sw[xm][ym][z];
8937
8938         for (dx = 1, dy = 1; dx <= xm && dy <= ym; dx++, dy++) {
8939
8940                 x = canonicalize(xm - dx, t->x_sz);
8941                 y = canonicalize(ym - dy, t->y_sz);
8942                 if (good_xy_ring(t, x, y, z))
8943                         return sw[x][y][z];
8944
8945                 x = canonicalize(xm + dx, t->x_sz);
8946                 y = canonicalize(ym + dy, t->y_sz);
8947                 if (good_xy_ring(t, x, y, z))
8948                         return sw[x][y][z];
8949         }
8950         return NULL;
8951 }
8952
8953 static
8954 struct t_switch *find_stree_root(struct torus *t)
8955 {
8956         int x, y, z, dz, zm = t->z_sz / 2;
8957         struct t_switch ****sw = t->sw;
8958         struct t_switch *root;
8959         bool good_plane;
8960
8961         /*
8962          * Look for a switch near the "center" (wrt. the datelines) of the
8963          * torus, as that will be the most optimum spanning tree root.  Use
8964          * a search that is not exhaustive, on the theory that this routing
8965          * engine isn't useful anyway if too many switches are missing.
8966          *
8967          * Also, want to pick an x-y plane with no missing switches, so that
8968          * the master spanning tree construction algorithm doesn't have to
8969          * deal with needing a turn on a missing switch.
8970          */
8971         for (dz = 0; dz <= zm; dz++) {
8972
8973                 z = canonicalize(zm - dz, t->z_sz);
8974                 good_plane = true;
8975                 for (y = 0; y < t->y_sz && good_plane; y++)
8976                         for (x = 0; x < t->x_sz && good_plane; x++)
8977                                 good_plane = sw[x][y][z];
8978
8979                 if (good_plane) {
8980                         root = find_plane_mid(t, z);
8981                         if (root)
8982                                 goto out;
8983                 }
8984                 if (!dz)
8985                         continue;
8986
8987                 z = canonicalize(zm + dz, t->z_sz);
8988                 good_plane = true;
8989                 for (y = 0; y < t->y_sz && good_plane; y++)
8990                         for (x = 0; x < t->x_sz && good_plane; x++)
8991                                 good_plane = sw[x][y][z];
8992
8993                 if (good_plane) {
8994                         root = find_plane_mid(t, z);
8995                         if (root)
8996                                 goto out;
8997                 }
8998         }
8999         /*
9000          * Note that torus-2QoS can route a torus that is missing an entire
9001          * column (switches with x,y constant, for all z values) without
9002          * deadlocks.
9003          *
9004          * if we've reached this point, we must have a column of missing
9005          * switches, as routable_torus() would have returned false for
9006          * any other configuration of missing switches that made it through
9007          * the above.
9008          *
9009          * So any switch in the mid-z plane will do as the root.
9010          */
9011         root = find_plane_mid(t, zm);
9012 out:
9013         return root;
9014 }
9015
9016 static
9017 bool sw_in_master_stree(struct t_switch *sw)
9018 {
9019         int g;
9020         bool connected;
9021
9022         connected = sw == sw->torus->master_stree_root;
9023         for (g = 0; g < 2 * TORUS_MAX_DIM; g++)
9024                 connected = connected || sw->ptgrp[g].to_stree_root;
9025
9026         return connected;
9027 }
9028
9029 static
9030 void grow_master_stree_branch(struct t_switch *root, struct t_switch *tip,
9031                               unsigned to_root_pg, unsigned to_tip_pg)
9032 {
9033         root->ptgrp[to_tip_pg].to_stree_tip = &tip->ptgrp[to_root_pg];
9034         tip->ptgrp[to_root_pg].to_stree_root = &root->ptgrp[to_tip_pg];
9035 }
9036
9037 static
9038 void build_master_stree_branch(struct t_switch *branch_root, int cdir)
9039 {
9040         struct t_switch *sw, *n_sw, *p_sw;
9041         unsigned l, idx, cnt, pg, ng;
9042
9043         switch (cdir) {
9044         case 0:
9045                 idx = branch_root->i;
9046                 cnt = branch_root->torus->x_sz;
9047                 break;
9048         case 1:
9049                 idx = branch_root->j;
9050                 cnt = branch_root->torus->y_sz;
9051                 break;
9052         case 2:
9053                 idx = branch_root->k;
9054                 cnt = branch_root->torus->z_sz;
9055                 break;
9056         default:
9057                 goto out;
9058         }
9059         /*
9060          * This algorithm intends that a spanning tree branch never crosses
9061          * a dateline unless the 1-D ring for which we're building the branch
9062          * is interrupted by failure.  We need that guarantee to prevent
9063          * multicast/unicast credit loops.
9064          */
9065         n_sw = branch_root;             /* tip of negative cdir branch */
9066         ng = 2 * cdir;                  /* negative cdir port group index */
9067         p_sw = branch_root;             /* tip of positive cdir branch */
9068         pg = 2 * cdir + 1;              /* positive cdir port group index */
9069
9070         for (l = idx; n_sw && l >= 1; l--) {
9071                 sw = ring_next_sw(n_sw, cdir, -1);
9072                 if (sw && !sw_in_master_stree(sw)) {
9073                         grow_master_stree_branch(n_sw, sw, pg, ng);
9074                         n_sw = sw;
9075                 } else
9076                         n_sw = NULL;
9077         }
9078         for (l = idx; p_sw && l < (cnt - 1); l++) {
9079                 sw = ring_next_sw(p_sw, cdir, 1);
9080                 if (sw && !sw_in_master_stree(sw)) {
9081                         grow_master_stree_branch(p_sw, sw, ng, pg);
9082                         p_sw = sw;
9083                 } else
9084                         p_sw = NULL;
9085         }
9086         if (n_sw && p_sw)
9087                 goto out;
9088         /*
9089          * At least one branch couldn't grow to the dateline for this ring.
9090          * That means it is acceptable to grow the branch by crossing the
9091          * dateline.
9092          */
9093         for (l = 0; l < cnt; l++) {
9094                 if (n_sw) {
9095                         sw = ring_next_sw(n_sw, cdir, -1);
9096                         if (sw && !sw_in_master_stree(sw)) {
9097                                 grow_master_stree_branch(n_sw, sw, pg, ng);
9098                                 n_sw = sw;
9099                         } else
9100                                 n_sw = NULL;
9101                 }
9102                 if (p_sw) {
9103                         sw = ring_next_sw(p_sw, cdir, 1);
9104                         if (sw && !sw_in_master_stree(sw)) {
9105                                 grow_master_stree_branch(p_sw, sw, ng, pg);
9106                                 p_sw = sw;
9107                         } else
9108                                 p_sw = NULL;
9109                 }
9110                 if (!(n_sw || p_sw))
9111                         break;
9112         }
9113 out:
9114         return;
9115 }
9116
9117 static
9118 bool torus_master_stree(struct torus *t)
9119 {
9120         int i, j, k;
9121         bool success = false;
9122         struct t_switch *stree_root = find_stree_root(t);
9123
9124         if (stree_root)
9125                 build_master_stree_branch(stree_root, 0);
9126         else
9127                 goto out;
9128
9129         k = stree_root->k;
9130         for (i = 0; i < t->x_sz; i++) {
9131                 j = stree_root->j;
9132                 if (t->sw[i][j][k])
9133                         build_master_stree_branch(t->sw[i][j][k], 1);
9134
9135                 for (j = 0; j < t->y_sz; j++)
9136                         if (t->sw[i][j][k])
9137                                 build_master_stree_branch(t->sw[i][j][k], 2);
9138         }
9139         t->master_stree_root = stree_root;
9140         /*
9141          * At this point we should have a master spanning tree that contains
9142          * every present switch, for all fabrics that torus-2QoS can route
9143          * without deadlocks.  Make sure this is the case; otherwise warn
9144          * and return failure so we get bug reports.
9145          */
9146         success = true;
9147         for (i = 0; i < t->x_sz; i++)
9148                 for (j = 0; j < t->y_sz; j++)
9149                         for (k = 0; k < t->z_sz; k++) {
9150                                 struct t_switch *sw = t->sw[i][j][k];
9151                                 if (!sw || sw_in_master_stree(sw))
9152                                         continue;
9153
9154                                 success = false;
9155                                 OSM_LOG(&t->osm->log, OSM_LOG_ERROR,
9156                                         "ERR 4E43: sw 0x%04"PRIx64" (%d,%d,%d) not in "
9157                                         "torus multicast master spanning tree\n",
9158                                         cl_ntoh64(sw->n_id), i, j, k);
9159                         }
9160 out:
9161         return success;
9162 }
9163
9164 int route_torus(struct torus *t)
9165 {
9166         int s;
9167         bool success = true;
9168
9169         for (s = 0; s < (int)t->switch_cnt; s++)
9170                 success = torus_lft(t, t->sw_pool[s]) && success;
9171
9172         success = success && torus_master_stree(t);
9173
9174         return success ? 0 : -1;
9175 }
9176
9177 uint8_t torus_path_sl(void *context, uint8_t path_sl_hint,
9178                       const ib_net16_t slid, const ib_net16_t dlid)
9179 {
9180         struct torus_context *ctx = context;
9181         osm_opensm_t *p_osm = ctx->osm;
9182         osm_log_t *log = &p_osm->log;
9183         osm_port_t *osm_sport, *osm_dport;
9184         struct endpoint *sport, *dport;
9185         struct t_switch *ssw, *dsw;
9186         struct torus *t;
9187         guid_t guid;
9188         unsigned sl = 0;
9189
9190         osm_sport = osm_get_port_by_lid(&p_osm->subn, slid);
9191         if (!osm_sport)
9192                 goto out;
9193
9194         osm_dport = osm_get_port_by_lid(&p_osm->subn, dlid);
9195         if (!osm_dport)
9196                 goto out;
9197
9198         sport = osm_sport->priv;
9199         if (!(sport && sport->osm_port == osm_sport)) {
9200                 sport = osm_port_relink_endpoint(osm_sport);
9201                 if (!sport) {
9202                         guid = osm_node_get_node_guid(osm_sport->p_node);
9203                         OSM_LOG(log, OSM_LOG_INFO,
9204                                 "Note: osm_sport (GUID 0x%04"PRIx64") "
9205                                 "not in torus fabric description\n",
9206                                 cl_ntoh64(guid));
9207                         goto out;
9208                 }
9209         }
9210         dport = osm_dport->priv;
9211         if (!(dport && dport->osm_port == osm_dport)) {
9212                 dport = osm_port_relink_endpoint(osm_dport);
9213                 if (!dport) {
9214                         guid = osm_node_get_node_guid(osm_dport->p_node);
9215                         OSM_LOG(log, OSM_LOG_INFO,
9216                                 "Note: osm_dport (GUID 0x%04"PRIx64") "
9217                                 "not in torus fabric description\n",
9218                                 cl_ntoh64(guid));
9219                         goto out;
9220                 }
9221         }
9222         /*
9223          * We're only supposed to be called for CA ports, and maybe
9224          * switch management ports.
9225          */
9226         if (sport->type != SRCSINK) {
9227                 guid = osm_node_get_node_guid(osm_sport->p_node);
9228                 OSM_LOG(log, OSM_LOG_INFO,
9229                         "Error: osm_sport (GUID 0x%04"PRIx64") "
9230                         "not a data src/sink port\n", cl_ntoh64(guid));
9231                 goto out;
9232         }
9233         if (dport->type != SRCSINK) {
9234                 guid = osm_node_get_node_guid(osm_dport->p_node);
9235                 OSM_LOG(log, OSM_LOG_INFO,
9236                         "Error: osm_dport (GUID 0x%04"PRIx64") "
9237                         "not a data src/sink port\n", cl_ntoh64(guid));
9238                 goto out;
9239         }
9240         /*
9241          * By definition, a CA port is connected to end[1] of a link, and
9242          * the switch port is end[0].  See build_ca_link() and link_srcsink().
9243          */
9244         if (sport->link) {
9245                 ssw = sport->link->end[0].sw;
9246         } else {
9247                 ssw = sport->sw;
9248         }
9249         if (dport->link)
9250                 dsw = dport->link->end[0].sw;
9251         else
9252                 dsw = dport->sw;
9253
9254         t = ssw->torus;
9255
9256         sl  = sl_set_use_loop_vl(use_vl1(ssw->i, dsw->i, t->x_sz), 0);
9257         sl |= sl_set_use_loop_vl(use_vl1(ssw->j, dsw->j, t->y_sz), 1);
9258         sl |= sl_set_use_loop_vl(use_vl1(ssw->k, dsw->k, t->z_sz), 2);
9259         sl |= sl_set_qos(sl_get_qos(path_sl_hint));
9260 out:
9261         return sl;
9262 }
9263
9264 static
9265 void sum_vlarb_weights(const char *vlarb_str,
9266                        unsigned total_weight[IB_MAX_NUM_VLS])
9267 {
9268         unsigned i = 0, v, vl = 0;
9269         char *end;
9270
9271         while (*vlarb_str && i++ < 2 * IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK) {
9272                 v = strtoul(vlarb_str, &end, 0);
9273                 if (*end)
9274                         end++;
9275                 vlarb_str = end;
9276                 if (i & 0x1)
9277                         vl = v & 0xf;
9278                 else
9279                         total_weight[vl] += v & 0xff;
9280         }
9281 }
9282
9283 static
9284 int uniform_vlarb_weight_value(unsigned *weight, unsigned count)
9285 {
9286         int i, v = weight[0];
9287
9288         for (i = 1; i < count; i++) {
9289                 if (v != weight[i])
9290                         return -1;
9291         }
9292         return v;
9293 }
9294
9295 static
9296 void check_vlarb_config(const char *vlarb_str, bool is_default,
9297                         const char *str, const char *pri, osm_log_t *log)
9298 {
9299         unsigned total_weight[IB_MAX_NUM_VLS] = {0,};
9300
9301         sum_vlarb_weights(vlarb_str, total_weight);
9302         if (!(uniform_vlarb_weight_value(&total_weight[0], 4) >= 0 &&
9303               uniform_vlarb_weight_value(&total_weight[4], 4) >= 0))
9304                 OSM_LOG(log, OSM_LOG_INFO,
9305                         "Warning: torus-2QoS requires same VLarb weights for "
9306                         "VLs 0-3; also for VLs 4-7: not true for %s "
9307                         "%s_vlarb_%s\n",
9308                         (is_default ? "default" : "configured"), str, pri);
9309 }
9310
9311 /*
9312  * Use this to check the qos_config for switch external ports.
9313  */
9314 static
9315 void check_qos_swe_config(osm_qos_options_t *opt,
9316                           osm_qos_options_t *def, osm_log_t *log)
9317 {
9318         const char *vlarb_str, *tstr;
9319         bool is_default;
9320         unsigned max_vls;
9321
9322         max_vls = def->max_vls;
9323         if (opt->max_vls > 0)
9324                 max_vls = opt->max_vls;
9325
9326         if (max_vls > 0 && max_vls < 8)
9327                 OSM_LOG(log, OSM_LOG_INFO,
9328                         "Warning: full torus-2QoS functionality not available "
9329                         "for configured %s_max_vls = %d\n",
9330                         (opt->max_vls > 0 ? "qos_swe" : "qos"), opt->max_vls);
9331
9332         vlarb_str = opt->vlarb_high;
9333         is_default = false;
9334         tstr = "qos_swe";
9335         if (!vlarb_str) {
9336                 vlarb_str = def->vlarb_high;
9337                 tstr = "qos";
9338         }
9339         if (!vlarb_str) {
9340                 vlarb_str = OSM_DEFAULT_QOS_VLARB_HIGH;
9341                 is_default = true;
9342         }
9343         check_vlarb_config(vlarb_str, is_default, tstr, "high", log);
9344
9345         vlarb_str = opt->vlarb_low;
9346         is_default = false;
9347         tstr = "qos_swe";
9348         if (!vlarb_str) {
9349                 vlarb_str = def->vlarb_low;
9350                 tstr = "qos";
9351         }
9352         if (!vlarb_str) {
9353                 vlarb_str = OSM_DEFAULT_QOS_VLARB_LOW;
9354                 is_default = true;
9355         }
9356         check_vlarb_config(vlarb_str, is_default, tstr, "low", log);
9357
9358         if (opt->sl2vl)
9359                 OSM_LOG(log, OSM_LOG_INFO,
9360                         "Warning: torus-2QoS must override configured "
9361                         "qos_swe_sl2vl to generate deadlock-free routes\n");
9362 }
9363
9364 static
9365 void check_ep_vlarb_config(const char *vlarb_str,
9366                            bool is_default, bool is_specific,
9367                            const char *str, const char *pri, osm_log_t *log)
9368 {
9369         unsigned i, total_weight[IB_MAX_NUM_VLS] = {0,};
9370         int val = 0;
9371
9372         sum_vlarb_weights(vlarb_str, total_weight);
9373         for (i = 2; i < 8; i++) {
9374                 val += total_weight[i];
9375         }
9376         if (!val)
9377                 return;
9378
9379         if (is_specific)
9380                 OSM_LOG(log, OSM_LOG_INFO,
9381                         "Warning: torus-2QoS recommends 0 VLarb weights"
9382                         " for VLs 2-7 on endpoint links; not true for "
9383                         " configured %s_vlarb_%s\n", str, pri);
9384         else
9385                 OSM_LOG(log, OSM_LOG_INFO,
9386                         "Warning: torus-2QoS recommends 0 VLarb weights "
9387                         "for VLs 2-7 on endpoint links; not true for %s "
9388                         "qos_vlarb_%s values used for %s_vlarb_%s\n",
9389                         (is_default ? "default" : "configured"), pri, str, pri);
9390 }
9391
9392 /*
9393  * Use this to check the qos_config for endports
9394  */
9395 static
9396 void check_qos_ep_config(osm_qos_options_t *opt, osm_qos_options_t *def,
9397                          const char *str, osm_log_t *log)
9398 {
9399         const char *vlarb_str;
9400         bool is_default, is_specific;
9401         unsigned max_vls;
9402
9403         max_vls = def->max_vls;
9404         if (opt->max_vls > 0)
9405                 max_vls = opt->max_vls;
9406
9407         if (max_vls > 0 && max_vls < 2)
9408                 OSM_LOG(log, OSM_LOG_INFO,
9409                         "Warning: full torus-2QoS functionality not available "
9410                         "for configured %s_max_vls = %d\n",
9411                         (opt->max_vls > 0 ? str : "qos"), opt->max_vls);
9412
9413         vlarb_str = opt->vlarb_high;
9414         is_default = false;
9415         is_specific = true;
9416         if (!vlarb_str) {
9417                 vlarb_str = def->vlarb_high;
9418                 is_specific = false;
9419         }
9420         if (!vlarb_str) {
9421                 vlarb_str = OSM_DEFAULT_QOS_VLARB_HIGH;
9422                 is_default = true;
9423         }
9424         check_ep_vlarb_config(vlarb_str, is_default, is_specific,
9425                               str, "high", log);
9426
9427         vlarb_str = opt->vlarb_low;
9428         is_default = false;
9429         is_specific = true;
9430         if (!vlarb_str) {
9431                 vlarb_str = def->vlarb_low;
9432                 is_specific = false;
9433         }
9434         if (!vlarb_str) {
9435                 vlarb_str = OSM_DEFAULT_QOS_VLARB_LOW;
9436                 is_default = true;
9437         }
9438         check_ep_vlarb_config(vlarb_str, is_default, is_specific,
9439                               str, "low", log);
9440
9441         if (opt->sl2vl)
9442                 OSM_LOG(log, OSM_LOG_INFO,
9443                         "Warning: torus-2QoS must override configured "
9444                         "%s_sl2vl to generate deadlock-free routes\n", str);
9445 }
9446
9447 static
9448 int torus_build_lfts(void *context)
9449 {
9450         int status = -1;
9451         struct torus_context *ctx = context;
9452         struct fabric *fabric;
9453         struct torus *torus;
9454
9455         if (!ctx->osm->subn.opt.qos) {
9456                 OSM_LOG(&ctx->osm->log, OSM_LOG_ERROR,
9457                         "ERR 4E44: Routing engine list contains torus-2QoS. "
9458                         "Enable QoS for correct operation "
9459                         "(-Q or 'qos TRUE' in opensm.conf).\n");
9460                 return status;
9461         }
9462
9463         fabric = &ctx->fabric;
9464         teardown_fabric(fabric);
9465
9466         torus = calloc(1, sizeof(*torus));
9467         if (!torus) {
9468                 OSM_LOG(&ctx->osm->log, OSM_LOG_ERROR,
9469                         "ERR 4E45: allocating torus: %s\n", strerror(errno));
9470                 goto out;
9471         }
9472         torus->osm = ctx->osm;
9473         fabric->osm = ctx->osm;
9474
9475         if (!parse_config(ctx->osm->subn.opt.torus_conf_file,
9476                           fabric, torus))
9477                 goto out;
9478
9479         if (!capture_fabric(fabric))
9480                 goto out;
9481
9482         OSM_LOG(&torus->osm->log, OSM_LOG_INFO,
9483                 "Found fabric w/ %d links, %d switches, %d CA ports, "
9484                 "minimum data VLs: endport %d, switchport %d\n",
9485                 (int)fabric->link_cnt, (int)fabric->switch_cnt,
9486                 (int)fabric->ca_cnt, (int)ctx->osm->subn.min_data_vls,
9487                 (int)ctx->osm->subn.min_sw_data_vls);
9488
9489         if (!verify_setup(torus, fabric))
9490                 goto out;
9491
9492         OSM_LOG(&torus->osm->log, OSM_LOG_INFO,
9493                 "Looking for %d x %d x %d %s\n",
9494                 (int)torus->x_sz, (int)torus->y_sz, (int)torus->z_sz,
9495                 (ALL_MESH(torus->flags) ? "mesh" : "torus"));
9496
9497         if (!build_torus(fabric, torus)) {
9498                 OSM_LOG(&torus->osm->log, OSM_LOG_ERROR, "ERR 4E57: "
9499                         "build_torus finished with errors\n");
9500                 goto out;
9501         }
9502
9503         OSM_LOG(&torus->osm->log, OSM_LOG_INFO,
9504                 "Built %d x %d x %d %s w/ %d links, %d switches, %d CA ports\n",
9505                 (int)torus->x_sz, (int)torus->y_sz, (int)torus->z_sz,
9506                 (ALL_MESH(torus->flags) ? "mesh" : "torus"),
9507                 (int)torus->link_cnt, (int)torus->switch_cnt,
9508                 (int)torus->ca_cnt);
9509
9510         diagnose_fabric(fabric);
9511         /*
9512          * Since we found some sort of torus fabric, report on any topology
9513          * changes vs. the last torus we found.
9514          */
9515         if (torus->flags & NOTIFY_CHANGES)
9516                 report_torus_changes(torus, ctx->torus);
9517
9518         if (routable_torus(torus, fabric))
9519                 status = route_torus(torus);
9520
9521 out:
9522         if (status) {           /* bad torus!! */
9523                 if (torus)
9524                         teardown_torus(torus);
9525         } else {
9526                 osm_subn_opt_t *opt = &torus->osm->subn.opt;
9527                 osm_log_t *log = &torus->osm->log;
9528
9529                 if (ctx->torus)
9530                         teardown_torus(ctx->torus);
9531                 ctx->torus = torus;
9532
9533                 check_qos_swe_config(&opt->qos_swe_options, &opt->qos_options,
9534                                      log);
9535
9536                 check_qos_ep_config(&opt->qos_ca_options,
9537                                     &opt->qos_options, "qos_ca", log);
9538                 check_qos_ep_config(&opt->qos_sw0_options,
9539                                     &opt->qos_options, "qos_sw0", log);
9540                 check_qos_ep_config(&opt->qos_rtr_options,
9541                                     &opt->qos_options, "qos_rtr", log);
9542         }
9543         teardown_fabric(fabric);
9544         return status;
9545 }
9546
9547 int osm_ucast_torus2QoS_setup(struct osm_routing_engine *r,
9548                               osm_opensm_t *osm)
9549 {
9550         struct torus_context *ctx;
9551
9552         ctx = torus_context_create(osm);
9553         if (!ctx)
9554                 return -1;
9555
9556         r->context = ctx;
9557         r->ucast_build_fwd_tables = torus_build_lfts;
9558         r->build_lid_matrices = ucast_dummy_build_lid_matrices;
9559         r->update_sl2vl = torus_update_osm_sl2vl;
9560         r->update_vlarb = torus_update_osm_vlarb;
9561         r->path_sl = torus_path_sl;
9562         r->mcast_build_stree = torus_mcast_stree;
9563         r->destroy = torus_context_delete;
9564         return 0;
9565 }