xref: /freebsd/contrib/ofed/opensm/opensm/osm_torus.c (revision d8a0fe102c0cfdfcd5b818f850eff09d8536c9bc)
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 }
9566