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