1321936Shselasky/* 2321936Shselasky * Copyright 2009 Sandia Corporation. Under the terms of Contract 3321936Shselasky * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains 4321936Shselasky * certain rights in this software. 5321936Shselasky * Copyright (c) 2009-2011 ZIH, TU Dresden, Federal Republic of Germany. All rights reserved. 6321936Shselasky * Copyright (c) 2010-2012 Mellanox Technologies LTD. All rights reserved. 7321936Shselasky * 8321936Shselasky * This software is available to you under a choice of one of two 9321936Shselasky * licenses. You may choose to be licensed under the terms of the GNU 10321936Shselasky * General Public License (GPL) Version 2, available from the file 11321936Shselasky * COPYING in the main directory of this source tree, or the 12321936Shselasky * OpenIB.org BSD license below: 13321936Shselasky * 14321936Shselasky * Redistribution and use in source and binary forms, with or 15321936Shselasky * without modification, are permitted provided that the following 16321936Shselasky * conditions are met: 17321936Shselasky * 18321936Shselasky * - Redistributions of source code must retain the above 19321936Shselasky * copyright notice, this list of conditions and the following 20321936Shselasky * disclaimer. 21321936Shselasky * 22321936Shselasky * - Redistributions in binary form must reproduce the above 23321936Shselasky * copyright notice, this list of conditions and the following 24321936Shselasky * disclaimer in the documentation and/or other materials 25321936Shselasky * provided with the distribution. 26321936Shselasky * 27321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 28321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 29321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 30321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 31321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 32321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 33321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 34321936Shselasky * SOFTWARE. 35321936Shselasky * 36321936Shselasky */ 37321936Shselasky 38321936Shselasky#define _WITH_GETLINE /* for getline() */ 39321936Shselasky#include <stdint.h> 40321936Shselasky#include <stdbool.h> 41321936Shselasky#include <stdlib.h> 42321936Shselasky#include <stdio.h> 43321936Shselasky#include <unistd.h> 44321936Shselasky#include <errno.h> 45321936Shselasky#include <string.h> 46321936Shselasky 47321936Shselasky#if HAVE_CONFIG_H 48321936Shselasky# include <config.h> 49321936Shselasky#endif /* HAVE_CONFIG_H */ 50321936Shselasky 51321936Shselasky#include <opensm/osm_file_ids.h> 52321936Shselasky#define FILE_ID OSM_FILE_TORUS_C 53321936Shselasky#include <opensm/osm_log.h> 54321936Shselasky#include <opensm/osm_port.h> 55321936Shselasky#include <opensm/osm_switch.h> 56321936Shselasky#include <opensm/osm_node.h> 57321936Shselasky#include <opensm/osm_opensm.h> 58321936Shselasky 59321936Shselasky#define TORUS_MAX_DIM 3 60321936Shselasky#define PORTGRP_MAX_PORTS 16 61321936Shselasky#define SWITCH_MAX_PORTGRPS (1 + 2 * TORUS_MAX_DIM) 62321936Shselasky#define DEFAULT_MAX_CHANGES 32 63321936Shselasky 64321936Shselasky#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 65321936Shselasky 66321936Shselaskytypedef ib_net64_t guid_t; 67321936Shselasky 68321936Shselasky/* 69321936Shselasky * An endpoint terminates a link, and is one of three types: 70321936Shselasky * UNKNOWN - Uninitialized endpoint. 71321936Shselasky * SRCSINK - generates or consumes traffic, and thus has an associated LID; 72321936Shselasky * i.e. a CA or router port. 73321936Shselasky * PASSTHRU - Has no associated LID; i.e. a switch port. 74321936Shselasky * 75321936Shselasky * If it is possible to communicate in-band with a switch, it will require 76321936Shselasky * a port with a GUID in the switch to source/sink that traffic, but there 77321936Shselasky * will be no attached link. This code assumes there is only one such port. 78321936Shselasky * 79321936Shselasky * Here is an endpoint taxonomy: 80321936Shselasky * 81321936Shselasky * type == SRCSINK 82321936Shselasky * link == pointer to a valid struct link 83321936Shselasky * ==> This endpoint is a CA or router port connected via a link to 84321936Shselasky * either a switch or another CA/router. Thus: 85321936Shselasky * n_id ==> identifies the CA/router node GUID 86321936Shselasky * sw ==> NULL 87321936Shselasky * port ==> identifies the port on the CA/router this endpoint uses 88321936Shselasky * pgrp ==> NULL 89321936Shselasky * 90321936Shselasky * type == SRCSINK 91321936Shselasky * link == NULL pointer 92321936Shselasky * ==> This endpoint is the switch port used for in-band communication 93321936Shselasky * with the switch itself. Thus: 94321936Shselasky * n_id ==> identifies the node GUID used to talk to the switch 95321936Shselasky * containing this endpoint 96321936Shselasky * sw ==> pointer to valid struct switch containing this endpoint 97321936Shselasky * port ==> identifies the port on the switch this endpoint uses 98321936Shselasky * pgrp ==> NULL, or pointer to the valid struct port_grp holding 99321936Shselasky * the port in a t_switch. 100321936Shselasky * 101321936Shselasky * type == PASSTHRU 102321936Shselasky * link == pointer to valid struct link 103321936Shselasky * ==> This endpoint is a switch port connected via a link to either 104321936Shselasky * another switch or a CA/router. Thus: 105321936Shselasky * n_id ==> identifies the node GUID used to talk to the switch 106321936Shselasky * containing this endpoint - since each switch is assumed 107321936Shselasky * to have only one in-band communication port, this is a 108321936Shselasky * convenient unique name for the switch itself. 109321936Shselasky * sw ==> pointer to valid struct switch containing this endpoint, 110321936Shselasky * or NULL, in the case of a fabric link that has been 111321936Shselasky * disconnected after being transferred to a torus link. 112321936Shselasky * port ==> identifies the port on the switch this endpoint uses. 113321936Shselasky * Note that in the special case of the coordinate direction 114321936Shselasky * links, the port value is -1, as those links aren't 115321936Shselasky * really connected to anything. 116321936Shselasky * pgrp ==> NULL, or pointer to the valid struct port_grp holding 117321936Shselasky * the port in a t_switch. 118321936Shselasky */ 119321936Shselaskyenum endpt_type { UNKNOWN = 0, SRCSINK, PASSTHRU }; 120321936Shselaskystruct torus; 121321936Shselaskystruct t_switch; 122321936Shselaskystruct port_grp; 123321936Shselasky 124321936Shselaskystruct endpoint { 125321936Shselasky enum endpt_type type; 126321936Shselasky int port; 127321936Shselasky guid_t n_id; /* IBA node GUID */ 128321936Shselasky void *sw; /* void* can point to either switch type */ 129321936Shselasky struct link *link; 130321936Shselasky struct port_grp *pgrp; 131321936Shselasky void *tmp; 132321936Shselasky /* 133321936Shselasky * Note: osm_port is only guaranteed to contain a valid pointer 134321936Shselasky * when the call stack contains torus_build_lfts() or 135321936Shselasky * osm_port_relink_endpoint(). 136321936Shselasky * 137321936Shselasky * Otherwise, the opensm core could have deleted an osm_port object 138321936Shselasky * without notifying us, invalidating the pointer we hold. 139321936Shselasky * 140321936Shselasky * When presented with a pointer to an osm_port_t, it is generally 141321936Shselasky * safe and required to cast osm_port_t:priv to struct endpoint, and 142321936Shselasky * check that the endpoint's osm_port is the same as the original 143321936Shselasky * osm_port_t pointer. Failure to do so means that invalidated 144321936Shselasky * pointers will go undetected. 145321936Shselasky */ 146321936Shselasky struct osm_port *osm_port; 147321936Shselasky}; 148321936Shselasky 149321936Shselaskystruct link { 150321936Shselasky struct endpoint end[2]; 151321936Shselasky}; 152321936Shselasky 153321936Shselasky/* 154321936Shselasky * A port group is a collection of endpoints on a switch that share certain 155321936Shselasky * characteristics. All the endpoints in a port group must have the same 156321936Shselasky * type. Furthermore, if that type is PASSTHRU, then the connected links: 157321936Shselasky * 1) are parallel to a given coordinate direction 158321936Shselasky * 2) share the same two switches as endpoints. 159321936Shselasky * 160321936Shselasky * Torus-2QoS uses one master spanning tree for multicast, of which every 161321936Shselasky * multicast group spanning tree is a subtree. to_stree_root is a pointer 162321936Shselasky * to the next port_grp on the path to the master spanning tree root. 163321936Shselasky * to_stree_tip is a pointer to the next port_grp on the path to a master 164321936Shselasky * spanning tree branch tip. 165321936Shselasky * 166321936Shselasky * Each t_switch can have at most one port_grp with a non-NULL to_stree_root. 167321936Shselasky * Exactly one t_switch in the fabric will have all port_grp objects with 168321936Shselasky * to_stree_root NULL; it is the master spanning tree root. 169321936Shselasky * 170321936Shselasky * A t_switch with all port_grp objects where to_stree_tip is NULL is at a 171321936Shselasky * master spanning tree branch tip. 172321936Shselasky */ 173321936Shselaskystruct port_grp { 174321936Shselasky enum endpt_type type; 175321936Shselasky size_t port_cnt; /* number of attached ports in group */ 176321936Shselasky size_t port_grp; /* what switch port_grp we're in */ 177321936Shselasky unsigned sw_dlid_cnt; /* switch dlids routed through this group */ 178321936Shselasky unsigned ca_dlid_cnt; /* CA dlids routed through this group */ 179321936Shselasky struct t_switch *sw; /* what switch we're attached to */ 180321936Shselasky struct port_grp *to_stree_root; 181321936Shselasky struct port_grp *to_stree_tip; 182321936Shselasky struct endpoint **port; 183321936Shselasky}; 184321936Shselasky 185321936Shselasky/* 186321936Shselasky * A struct t_switch is used to represent a switch as placed in a torus. 187321936Shselasky * 188321936Shselasky * A t_switch used to build an N-dimensional torus will have 2N+1 port groups, 189321936Shselasky * used as follows, assuming 0 <= d < N: 190321936Shselasky * port_grp[2d] => links leaving in negative direction for coordinate d 191321936Shselasky * port_grp[2d+1] => links leaving in positive direction for coordinate d 192321936Shselasky * port_grp[2N] => endpoints local to switch; i.e., hosts on switch 193321936Shselasky * 194321936Shselasky * struct link objects referenced by a t_switch are assumed to be oriented: 195321936Shselasky * traversing a link from link.end[0] to link.end[1] is always in the positive 196321936Shselasky * coordinate direction. 197321936Shselasky */ 198321936Shselaskystruct t_switch { 199321936Shselasky guid_t n_id; /* IBA node GUID */ 200321936Shselasky int i, j, k; 201321936Shselasky unsigned port_cnt; /* including management port */ 202321936Shselasky struct torus *torus; 203321936Shselasky void *tmp; 204321936Shselasky /* 205321936Shselasky * Note: osm_switch is only guaranteed to contain a valid pointer 206321936Shselasky * when the call stack contains torus_build_lfts(). 207321936Shselasky * 208321936Shselasky * Otherwise, the opensm core could have deleted an osm_switch object 209321936Shselasky * without notifying us, invalidating the pointer we hold. 210321936Shselasky * 211321936Shselasky * When presented with a pointer to an osm_switch_t, it is generally 212321936Shselasky * safe and required to cast osm_switch_t:priv to struct t_switch, and 213321936Shselasky * check that the switch's osm_switch is the same as the original 214321936Shselasky * osm_switch_t pointer. Failure to do so means that invalidated 215321936Shselasky * pointers will go undetected. 216321936Shselasky */ 217321936Shselasky struct osm_switch *osm_switch; 218321936Shselasky 219321936Shselasky struct port_grp ptgrp[SWITCH_MAX_PORTGRPS]; 220321936Shselasky struct endpoint **port; 221321936Shselasky}; 222321936Shselasky 223321936Shselasky/* 224321936Shselasky * We'd like to be able to discover the torus topology in a pile of switch 225321936Shselasky * links if we can. We'll use a struct f_switch to store raw topology for a 226321936Shselasky * fabric description, then contruct the torus topology from struct t_switch 227321936Shselasky * objects as we process the fabric and recover it. 228321936Shselasky */ 229321936Shselaskystruct f_switch { 230321936Shselasky guid_t n_id; /* IBA node GUID */ 231321936Shselasky unsigned port_cnt; /* including management port */ 232321936Shselasky void *tmp; 233321936Shselasky /* 234321936Shselasky * Same rules apply here as for a struct t_switch member osm_switch. 235321936Shselasky */ 236321936Shselasky struct osm_switch *osm_switch; 237321936Shselasky struct endpoint **port; 238321936Shselasky}; 239321936Shselasky 240321936Shselaskystruct fabric { 241321936Shselasky osm_opensm_t *osm; 242321936Shselasky unsigned ca_cnt; 243321936Shselasky unsigned link_cnt; 244321936Shselasky unsigned switch_cnt; 245321936Shselasky 246321936Shselasky unsigned link_cnt_max; 247321936Shselasky unsigned switch_cnt_max; 248321936Shselasky 249321936Shselasky struct link **link; 250321936Shselasky struct f_switch **sw; 251321936Shselasky}; 252321936Shselasky 253321936Shselaskystruct coord_dirs { 254321936Shselasky /* 255321936Shselasky * These links define the coordinate directions for the torus. 256321936Shselasky * They are duplicates of links connected to switches. Each of 257321936Shselasky * these links must connect to a common switch. 258321936Shselasky * 259321936Shselasky * In the event that a failed switch was specified as one of these 260321936Shselasky * link endpoints, our algorithm would not be able to find the 261321936Shselasky * torus in the fabric. So, we'll allow multiple instances of 262321936Shselasky * this in the config file to allow improved resiliency. 263321936Shselasky */ 264321936Shselasky struct link xm_link, ym_link, zm_link; 265321936Shselasky struct link xp_link, yp_link, zp_link; 266321936Shselasky /* 267321936Shselasky * A torus dimension has coordinate values 0, 1, ..., radix - 1. 268321936Shselasky * The dateline, where we need to change VLs to avoid credit loops, 269321936Shselasky * for a torus dimension is always between coordinate values 270321936Shselasky * radix - 1 and 0. The following specify the dateline location 271321936Shselasky * relative to the coordinate links shared switch location. 272321936Shselasky * 273321936Shselasky * E.g. if the shared switch is at 0,0,0, the following are all 274321936Shselasky * zero; if the shared switch is at 1,1,1, the following are all 275321936Shselasky * -1, etc. 276321936Shselasky * 277321936Shselasky * Since our SL/VL assignment for a path depends on the position 278321936Shselasky * of the path endpoints relative to the torus datelines, we need 279321936Shselasky * this information to keep SL/VL assignment constant in the event 280321936Shselasky * one of the switches used to specify coordinate directions fails. 281321936Shselasky */ 282321936Shselasky int x_dateline, y_dateline, z_dateline; 283321936Shselasky}; 284321936Shselasky 285321936Shselaskystruct torus { 286321936Shselasky osm_opensm_t *osm; 287321936Shselasky unsigned ca_cnt; 288321936Shselasky unsigned link_cnt; 289321936Shselasky unsigned switch_cnt; 290321936Shselasky unsigned seed_cnt, seed_idx; 291321936Shselasky unsigned x_sz, y_sz, z_sz; 292321936Shselasky 293321936Shselasky unsigned port_order[IB_NODE_NUM_PORTS_MAX+1]; 294321936Shselasky 295321936Shselasky unsigned sw_pool_sz; 296321936Shselasky unsigned link_pool_sz; 297321936Shselasky unsigned seed_sz; 298321936Shselasky unsigned portgrp_sz; /* max ports for port groups in this torus */ 299321936Shselasky 300321936Shselasky struct fabric *fabric; 301321936Shselasky struct t_switch **sw_pool; 302321936Shselasky struct link *link_pool; 303321936Shselasky 304321936Shselasky struct coord_dirs *seed; 305321936Shselasky struct t_switch ****sw; 306321936Shselasky struct t_switch *master_stree_root; 307321936Shselasky 308321936Shselasky unsigned flags; 309321936Shselasky unsigned max_changes; 310321936Shselasky int debug; 311321936Shselasky}; 312321936Shselasky 313321936Shselasky/* 314321936Shselasky * Bits to use in torus.flags 315321936Shselasky */ 316321936Shselasky#define X_MESH (1U << 0) 317321936Shselasky#define Y_MESH (1U << 1) 318321936Shselasky#define Z_MESH (1U << 2) 319321936Shselasky#define MSG_DEADLOCK (1U << 29) 320321936Shselasky#define NOTIFY_CHANGES (1U << 30) 321321936Shselasky 322321936Shselasky#define ALL_MESH(flags) \ 323321936Shselasky ((flags & (X_MESH | Y_MESH | Z_MESH)) == (X_MESH | Y_MESH | Z_MESH)) 324321936Shselasky 325321936Shselasky 326321936Shselaskystruct torus_context { 327321936Shselasky osm_opensm_t *osm; 328321936Shselasky struct torus *torus; 329321936Shselasky struct fabric fabric; 330321936Shselasky}; 331321936Shselasky 332321936Shselaskystatic 333321936Shselaskyvoid teardown_fabric(struct fabric *f) 334321936Shselasky{ 335321936Shselasky unsigned l, p, s; 336321936Shselasky struct endpoint *port; 337321936Shselasky struct f_switch *sw; 338321936Shselasky 339321936Shselasky if (!f) 340321936Shselasky return; 341321936Shselasky 342321936Shselasky if (f->sw) { 343321936Shselasky /* 344321936Shselasky * Need to free switches, and also find/free the endpoints 345321936Shselasky * we allocated for switch management ports. 346321936Shselasky */ 347321936Shselasky for (s = 0; s < f->switch_cnt; s++) { 348321936Shselasky sw = f->sw[s]; 349321936Shselasky if (!sw) 350321936Shselasky continue; 351321936Shselasky 352321936Shselasky for (p = 0; p < sw->port_cnt; p++) { 353321936Shselasky port = sw->port[p]; 354321936Shselasky if (port && !port->link) 355321936Shselasky free(port); /* management port */ 356321936Shselasky } 357321936Shselasky free(sw); 358321936Shselasky } 359321936Shselasky free(f->sw); 360321936Shselasky } 361321936Shselasky if (f->link) { 362321936Shselasky for (l = 0; l < f->link_cnt; l++) 363321936Shselasky if (f->link[l]) 364321936Shselasky free(f->link[l]); 365321936Shselasky 366321936Shselasky free(f->link); 367321936Shselasky } 368321936Shselasky memset(f, 0, sizeof(*f)); 369321936Shselasky} 370321936Shselasky 371321936Shselaskyvoid teardown_torus(struct torus *t) 372321936Shselasky{ 373321936Shselasky unsigned p, s; 374321936Shselasky struct endpoint *port; 375321936Shselasky struct t_switch *sw; 376321936Shselasky 377321936Shselasky if (!t) 378321936Shselasky return; 379321936Shselasky 380321936Shselasky if (t->sw_pool) { 381321936Shselasky /* 382321936Shselasky * Need to free switches, and also find/free the endpoints 383321936Shselasky * we allocated for switch management ports. 384321936Shselasky */ 385321936Shselasky for (s = 0; s < t->switch_cnt; s++) { 386321936Shselasky sw = t->sw_pool[s]; 387321936Shselasky if (!sw) 388321936Shselasky continue; 389321936Shselasky 390321936Shselasky for (p = 0; p < sw->port_cnt; p++) { 391321936Shselasky port = sw->port[p]; 392321936Shselasky if (port && !port->link) 393321936Shselasky free(port); /* management port */ 394321936Shselasky } 395321936Shselasky free(sw); 396321936Shselasky } 397321936Shselasky free(t->sw_pool); 398321936Shselasky } 399321936Shselasky if (t->link_pool) 400321936Shselasky free(t->link_pool); 401321936Shselasky 402321936Shselasky if (t->sw) 403321936Shselasky free(t->sw); 404321936Shselasky 405321936Shselasky if (t->seed) 406321936Shselasky free(t->seed); 407321936Shselasky 408321936Shselasky free(t); 409321936Shselasky} 410321936Shselasky 411321936Shselaskystatic 412321936Shselaskystruct torus_context *torus_context_create(osm_opensm_t *osm) 413321936Shselasky{ 414321936Shselasky struct torus_context *ctx; 415321936Shselasky 416321936Shselasky ctx = calloc(1, sizeof(*ctx)); 417321936Shselasky if (ctx) 418321936Shselasky ctx->osm = osm; 419321936Shselasky else 420321936Shselasky OSM_LOG(&osm->log, OSM_LOG_ERROR, 421321936Shselasky "ERR 4E01: calloc: %s\n", strerror(errno)); 422321936Shselasky 423321936Shselasky return ctx; 424321936Shselasky} 425321936Shselasky 426321936Shselaskystatic 427321936Shselaskyvoid torus_context_delete(void *context) 428321936Shselasky{ 429321936Shselasky struct torus_context *ctx = context; 430321936Shselasky 431321936Shselasky teardown_fabric(&ctx->fabric); 432321936Shselasky if (ctx->torus) 433321936Shselasky teardown_torus(ctx->torus); 434321936Shselasky free(ctx); 435321936Shselasky} 436321936Shselasky 437321936Shselaskystatic 438321936Shselaskybool grow_seed_array(struct torus *t, int new_seeds) 439321936Shselasky{ 440321936Shselasky unsigned cnt; 441321936Shselasky void *ptr; 442321936Shselasky 443321936Shselasky cnt = t->seed_cnt + new_seeds; 444321936Shselasky if (cnt > t->seed_sz) { 445321936Shselasky cnt += 2 + cnt / 2; 446321936Shselasky ptr = realloc(t->seed, cnt * sizeof(*t->seed)); 447321936Shselasky if (!ptr) 448321936Shselasky return false; 449321936Shselasky t->seed = ptr; 450321936Shselasky t->seed_sz = cnt; 451321936Shselasky memset(&t->seed[t->seed_cnt], 0, 452321936Shselasky (cnt - t->seed_cnt) * sizeof(*t->seed)); 453321936Shselasky } 454321936Shselasky return true; 455321936Shselasky} 456321936Shselasky 457321936Shselaskystatic 458321936Shselaskystruct f_switch *find_f_sw(struct fabric *f, guid_t sw_guid) 459321936Shselasky{ 460321936Shselasky unsigned s; 461321936Shselasky struct f_switch *sw; 462321936Shselasky 463321936Shselasky if (f->sw) { 464321936Shselasky for (s = 0; s < f->switch_cnt; s++) { 465321936Shselasky sw = f->sw[s]; 466321936Shselasky if (sw->n_id == sw_guid) 467321936Shselasky return sw; 468321936Shselasky } 469321936Shselasky } 470321936Shselasky return NULL; 471321936Shselasky} 472321936Shselasky 473321936Shselaskystatic 474321936Shselaskystruct link *find_f_link(struct fabric *f, 475321936Shselasky guid_t guid0, int port0, guid_t guid1, int port1) 476321936Shselasky{ 477321936Shselasky unsigned l; 478321936Shselasky struct link *link; 479321936Shselasky 480321936Shselasky if (f->link) { 481321936Shselasky for (l = 0; l < f->link_cnt; l++) { 482321936Shselasky link = f->link[l]; 483321936Shselasky if ((link->end[0].n_id == guid0 && 484321936Shselasky link->end[0].port == port0 && 485321936Shselasky link->end[1].n_id == guid1 && 486321936Shselasky link->end[1].port == port1) || 487321936Shselasky (link->end[0].n_id == guid1 && 488321936Shselasky link->end[0].port == port1 && 489321936Shselasky link->end[1].n_id == guid0 && 490321936Shselasky link->end[1].port == port0)) 491321936Shselasky return link; 492321936Shselasky } 493321936Shselasky } 494321936Shselasky return NULL; 495321936Shselasky} 496321936Shselasky 497321936Shselaskystatic 498321936Shselaskystruct f_switch *alloc_fswitch(struct fabric *f, 499321936Shselasky guid_t sw_id, unsigned port_cnt) 500321936Shselasky{ 501321936Shselasky size_t new_sw_sz; 502321936Shselasky unsigned cnt_max; 503321936Shselasky struct f_switch *sw = NULL; 504321936Shselasky void *ptr; 505321936Shselasky 506321936Shselasky if (f->switch_cnt >= f->switch_cnt_max) { 507321936Shselasky 508321936Shselasky cnt_max = 16 + 5 * f->switch_cnt_max / 4; 509321936Shselasky ptr = realloc(f->sw, cnt_max * sizeof(*f->sw)); 510321936Shselasky if (!ptr) { 511321936Shselasky OSM_LOG(&f->osm->log, OSM_LOG_ERROR, 512321936Shselasky "ERR 4E02: realloc: %s\n", strerror(errno)); 513321936Shselasky goto out; 514321936Shselasky } 515321936Shselasky f->sw = ptr; 516321936Shselasky f->switch_cnt_max = cnt_max; 517321936Shselasky memset(&f->sw[f->switch_cnt], 0, 518321936Shselasky (f->switch_cnt_max - f->switch_cnt)*sizeof(*f->sw)); 519321936Shselasky } 520321936Shselasky new_sw_sz = sizeof(*sw) + port_cnt * sizeof(*sw->port); 521321936Shselasky sw = calloc(1, new_sw_sz); 522321936Shselasky if (!sw) { 523321936Shselasky OSM_LOG(&f->osm->log, OSM_LOG_ERROR, 524321936Shselasky "ERR 4E03: calloc: %s\n", strerror(errno)); 525321936Shselasky goto out; 526321936Shselasky } 527321936Shselasky sw->port = (void *)(sw + 1); 528321936Shselasky sw->n_id = sw_id; 529321936Shselasky sw->port_cnt = port_cnt; 530321936Shselasky f->sw[f->switch_cnt++] = sw; 531321936Shselaskyout: 532321936Shselasky return sw; 533321936Shselasky} 534321936Shselasky 535321936Shselaskystatic 536321936Shselaskystruct link *alloc_flink(struct fabric *f) 537321936Shselasky{ 538321936Shselasky unsigned cnt_max; 539321936Shselasky struct link *l = NULL; 540321936Shselasky void *ptr; 541321936Shselasky 542321936Shselasky if (f->link_cnt >= f->link_cnt_max) { 543321936Shselasky 544321936Shselasky cnt_max = 16 + 5 * f->link_cnt_max / 4; 545321936Shselasky ptr = realloc(f->link, cnt_max * sizeof(*f->link)); 546321936Shselasky if (!ptr) { 547321936Shselasky OSM_LOG(&f->osm->log, OSM_LOG_ERROR, 548321936Shselasky "ERR 4E04: realloc: %s\n", strerror(errno)); 549321936Shselasky goto out; 550321936Shselasky } 551321936Shselasky f->link = ptr; 552321936Shselasky f->link_cnt_max = cnt_max; 553321936Shselasky memset(&f->link[f->link_cnt], 0, 554321936Shselasky (f->link_cnt_max - f->link_cnt) * sizeof(*f->link)); 555321936Shselasky } 556321936Shselasky l = calloc(1, sizeof(*l)); 557321936Shselasky if (!l) { 558321936Shselasky OSM_LOG(&f->osm->log, OSM_LOG_ERROR, 559321936Shselasky "ERR 4E05: calloc: %s\n", strerror(errno)); 560321936Shselasky goto out; 561321936Shselasky } 562321936Shselasky f->link[f->link_cnt++] = l; 563321936Shselaskyout: 564321936Shselasky return l; 565321936Shselasky} 566321936Shselasky 567321936Shselasky/* 568321936Shselasky * Caller must ensure osm_port points to a valid port which contains 569321936Shselasky * a valid osm_physp_t pointer for port 0, the switch management port. 570321936Shselasky */ 571321936Shselaskystatic 572321936Shselaskybool build_sw_endpoint(struct fabric *f, osm_port_t *osm_port) 573321936Shselasky{ 574321936Shselasky int sw_port; 575321936Shselasky guid_t sw_guid; 576321936Shselasky struct osm_switch *osm_sw; 577321936Shselasky struct f_switch *sw; 578321936Shselasky struct endpoint *ep; 579321936Shselasky bool success = false; 580321936Shselasky 581321936Shselasky sw_port = osm_physp_get_port_num(osm_port->p_physp); 582321936Shselasky sw_guid = osm_node_get_node_guid(osm_port->p_node); 583321936Shselasky osm_sw = osm_port->p_node->sw; 584321936Shselasky 585321936Shselasky /* 586321936Shselasky * The switch must already exist. 587321936Shselasky */ 588321936Shselasky sw = find_f_sw(f, sw_guid); 589321936Shselasky if (!sw) { 590321936Shselasky OSM_LOG(&f->osm->log, OSM_LOG_ERROR, 591321936Shselasky "ERR 4E06: missing switch w/GUID 0x%04"PRIx64"\n", 592321936Shselasky cl_ntoh64(sw_guid)); 593321936Shselasky goto out; 594321936Shselasky } 595321936Shselasky /* 596321936Shselasky * The endpoint may already exist. 597321936Shselasky */ 598321936Shselasky if (sw->port[sw_port]) { 599321936Shselasky if (sw->port[sw_port]->n_id == sw_guid) { 600321936Shselasky ep = sw->port[sw_port]; 601321936Shselasky goto success; 602321936Shselasky } else 603321936Shselasky OSM_LOG(&f->osm->log, OSM_LOG_ERROR, 604321936Shselasky "ERR 4E07: switch port %d has id " 605321936Shselasky "0x%04"PRIx64", expected 0x%04"PRIx64"\n", 606321936Shselasky sw_port, cl_ntoh64(sw->port[sw_port]->n_id), 607321936Shselasky cl_ntoh64(sw_guid)); 608321936Shselasky goto out; 609321936Shselasky } 610321936Shselasky ep = calloc(1, sizeof(*ep)); 611321936Shselasky if (!ep) { 612321936Shselasky OSM_LOG(&f->osm->log, OSM_LOG_ERROR, 613321936Shselasky "ERR 4E08: allocating endpoint: %s\n", strerror(errno)); 614321936Shselasky goto out; 615321936Shselasky } 616321936Shselasky ep->type = SRCSINK; 617321936Shselasky ep->port = sw_port; 618321936Shselasky ep->n_id = sw_guid; 619321936Shselasky ep->link = NULL; 620321936Shselasky ep->sw = sw; 621321936Shselasky 622321936Shselasky sw->port[sw_port] = ep; 623321936Shselasky 624321936Shselaskysuccess: 625321936Shselasky /* 626321936Shselasky * Fabric objects are temporary, so don't set osm_sw/osm_port priv 627321936Shselasky * pointers using them. Wait until torus objects get constructed. 628321936Shselasky */ 629321936Shselasky sw->osm_switch = osm_sw; 630321936Shselasky ep->osm_port = osm_port; 631321936Shselasky 632321936Shselasky success = true; 633321936Shselaskyout: 634321936Shselasky return success; 635321936Shselasky} 636321936Shselasky 637321936Shselaskystatic 638321936Shselaskybool build_ca_link(struct fabric *f, 639321936Shselasky osm_port_t *osm_port_ca, guid_t sw_guid, int sw_port) 640321936Shselasky{ 641321936Shselasky int ca_port; 642321936Shselasky guid_t ca_guid; 643321936Shselasky struct link *l; 644321936Shselasky struct f_switch *sw; 645321936Shselasky bool success = false; 646321936Shselasky 647321936Shselasky ca_port = osm_physp_get_port_num(osm_port_ca->p_physp); 648321936Shselasky ca_guid = osm_node_get_node_guid(osm_port_ca->p_node); 649321936Shselasky 650321936Shselasky /* 651321936Shselasky * The link may already exist. 652321936Shselasky */ 653321936Shselasky l = find_f_link(f, sw_guid, sw_port, ca_guid, ca_port); 654321936Shselasky if (l) { 655321936Shselasky success = true; 656321936Shselasky goto out; 657321936Shselasky } 658321936Shselasky /* 659321936Shselasky * The switch must already exist. 660321936Shselasky */ 661321936Shselasky sw = find_f_sw(f, sw_guid); 662321936Shselasky if (!sw) { 663321936Shselasky OSM_LOG(&f->osm->log, OSM_LOG_ERROR, 664321936Shselasky "ERR 4E09: missing switch w/GUID 0x%04"PRIx64"\n", 665321936Shselasky cl_ntoh64(sw_guid)); 666321936Shselasky goto out; 667321936Shselasky } 668321936Shselasky l = alloc_flink(f); 669321936Shselasky if (!l) 670321936Shselasky goto out; 671321936Shselasky 672321936Shselasky l->end[0].type = PASSTHRU; 673321936Shselasky l->end[0].port = sw_port; 674321936Shselasky l->end[0].n_id = sw_guid; 675321936Shselasky l->end[0].sw = sw; 676321936Shselasky l->end[0].link = l; 677321936Shselasky 678321936Shselasky sw->port[sw_port] = &l->end[0]; 679321936Shselasky 680321936Shselasky l->end[1].type = SRCSINK; 681321936Shselasky l->end[1].port = ca_port; 682321936Shselasky l->end[1].n_id = ca_guid; 683321936Shselasky l->end[1].sw = NULL; /* Correct for a CA */ 684321936Shselasky l->end[1].link = l; 685321936Shselasky 686321936Shselasky /* 687321936Shselasky * Fabric objects are temporary, so don't set osm_sw/osm_port priv 688321936Shselasky * pointers using them. Wait until torus objects get constructed. 689321936Shselasky */ 690321936Shselasky l->end[1].osm_port = osm_port_ca; 691321936Shselasky 692321936Shselasky ++f->ca_cnt; 693321936Shselasky success = true; 694321936Shselaskyout: 695321936Shselasky return success; 696321936Shselasky} 697321936Shselasky 698321936Shselaskystatic 699321936Shselaskybool build_link(struct fabric *f, 700321936Shselasky guid_t sw_guid0, int sw_port0, guid_t sw_guid1, int sw_port1) 701321936Shselasky{ 702321936Shselasky struct link *l; 703321936Shselasky struct f_switch *sw0, *sw1; 704321936Shselasky bool success = false; 705321936Shselasky 706321936Shselasky /* 707321936Shselasky * The link may already exist. 708321936Shselasky */ 709321936Shselasky l = find_f_link(f, sw_guid0, sw_port0, sw_guid1, sw_port1); 710321936Shselasky if (l) { 711321936Shselasky success = true; 712321936Shselasky goto out; 713321936Shselasky } 714321936Shselasky /* 715321936Shselasky * The switches must already exist. 716321936Shselasky */ 717321936Shselasky sw0 = find_f_sw(f, sw_guid0); 718321936Shselasky if (!sw0) { 719321936Shselasky OSM_LOG(&f->osm->log, OSM_LOG_ERROR, 720321936Shselasky "ERR 4E0A: missing switch w/GUID 0x%04"PRIx64"\n", 721321936Shselasky cl_ntoh64(sw_guid0)); 722321936Shselasky goto out; 723321936Shselasky } 724321936Shselasky sw1 = find_f_sw(f, sw_guid1); 725321936Shselasky if (!sw1) { 726321936Shselasky OSM_LOG(&f->osm->log, OSM_LOG_ERROR, 727321936Shselasky "ERR 4E0B: missing switch w/GUID 0x%04"PRIx64"\n", 728321936Shselasky cl_ntoh64(sw_guid1)); 729321936Shselasky goto out; 730321936Shselasky } 731321936Shselasky l = alloc_flink(f); 732321936Shselasky if (!l) 733321936Shselasky goto out; 734321936Shselasky 735321936Shselasky l->end[0].type = PASSTHRU; 736321936Shselasky l->end[0].port = sw_port0; 737321936Shselasky l->end[0].n_id = sw_guid0; 738321936Shselasky l->end[0].sw = sw0; 739321936Shselasky l->end[0].link = l; 740321936Shselasky 741321936Shselasky sw0->port[sw_port0] = &l->end[0]; 742321936Shselasky 743321936Shselasky l->end[1].type = PASSTHRU; 744321936Shselasky l->end[1].port = sw_port1; 745321936Shselasky l->end[1].n_id = sw_guid1; 746321936Shselasky l->end[1].sw = sw1; 747321936Shselasky l->end[1].link = l; 748321936Shselasky 749321936Shselasky sw1->port[sw_port1] = &l->end[1]; 750321936Shselasky 751321936Shselasky success = true; 752321936Shselaskyout: 753321936Shselasky return success; 754321936Shselasky} 755321936Shselasky 756321936Shselaskystatic 757321936Shselaskybool parse_size(unsigned *tsz, unsigned *tflags, unsigned mask, 758321936Shselasky const char *parse_sep) 759321936Shselasky{ 760321936Shselasky char *val, *nextchar; 761321936Shselasky 762321936Shselasky val = strtok(NULL, parse_sep); 763321936Shselasky if (!val) 764321936Shselasky return false; 765321936Shselasky *tsz = strtoul(val, &nextchar, 0); 766321936Shselasky if (*tsz) { 767321936Shselasky if (*nextchar == 't' || *nextchar == 'T') 768321936Shselasky *tflags &= ~mask; 769321936Shselasky else if (*nextchar == 'm' || *nextchar == 'M') 770321936Shselasky *tflags |= mask; 771321936Shselasky /* 772321936Shselasky * A torus of radix two is also a mesh of radix two 773321936Shselasky * with multiple links between switches in that direction. 774321936Shselasky * 775321936Shselasky * Make it so always, otherwise the failure case routing 776321936Shselasky * logic gets confused. 777321936Shselasky */ 778321936Shselasky if (*tsz == 2) 779321936Shselasky *tflags |= mask; 780321936Shselasky } 781321936Shselasky return true; 782321936Shselasky} 783321936Shselasky 784321936Shselaskystatic 785321936Shselaskybool parse_torus(struct torus *t, const char *parse_sep) 786321936Shselasky{ 787321936Shselasky unsigned i, j, k, cnt; 788321936Shselasky char *ptr; 789321936Shselasky bool success = false; 790321936Shselasky 791321936Shselasky /* 792321936Shselasky * There can be only one. Ignore the imposters. 793321936Shselasky */ 794321936Shselasky if (t->sw_pool) 795321936Shselasky goto out; 796321936Shselasky 797321936Shselasky if (!parse_size(&t->x_sz, &t->flags, X_MESH, parse_sep)) 798321936Shselasky goto out; 799321936Shselasky 800321936Shselasky if (!parse_size(&t->y_sz, &t->flags, Y_MESH, parse_sep)) 801321936Shselasky goto out; 802321936Shselasky 803321936Shselasky if (!parse_size(&t->z_sz, &t->flags, Z_MESH, parse_sep)) 804321936Shselasky goto out; 805321936Shselasky 806321936Shselasky /* 807321936Shselasky * Set up a linear array of switch pointers big enough to hold 808321936Shselasky * all expected switches. 809321936Shselasky */ 810321936Shselasky t->sw_pool_sz = t->x_sz * t->y_sz * t->z_sz; 811321936Shselasky t->sw_pool = calloc(t->sw_pool_sz, sizeof(*t->sw_pool)); 812321936Shselasky if (!t->sw_pool) { 813321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 814321936Shselasky "ERR 4E0C: Torus switch array calloc: %s\n", 815321936Shselasky strerror(errno)); 816321936Shselasky goto out; 817321936Shselasky } 818321936Shselasky /* 819321936Shselasky * Set things up so that t->sw[i][j][k] can point to the i,j,k switch. 820321936Shselasky */ 821321936Shselasky cnt = t->x_sz * (1 + t->y_sz * (1 + t->z_sz)); 822321936Shselasky t->sw = malloc(cnt * sizeof(void *)); 823321936Shselasky if (!t->sw) { 824321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 825321936Shselasky "ERR 4E0D: Torus switch array malloc: %s\n", 826321936Shselasky strerror(errno)); 827321936Shselasky goto out; 828321936Shselasky } 829321936Shselasky ptr = (void *)(t->sw); 830321936Shselasky 831321936Shselasky ptr += t->x_sz * sizeof(void *); 832321936Shselasky for (i = 0; i < t->x_sz; i++) { 833321936Shselasky t->sw[i] = (void *)ptr; 834321936Shselasky ptr += t->y_sz * sizeof(void *); 835321936Shselasky } 836321936Shselasky for (i = 0; i < t->x_sz; i++) 837321936Shselasky for (j = 0; j < t->y_sz; j++) { 838321936Shselasky t->sw[i][j] = (void *)ptr; 839321936Shselasky ptr += t->z_sz * sizeof(void *); 840321936Shselasky } 841321936Shselasky 842321936Shselasky for (i = 0; i < t->x_sz; i++) 843321936Shselasky for (j = 0; j < t->y_sz; j++) 844321936Shselasky for (k = 0; k < t->z_sz; k++) 845321936Shselasky t->sw[i][j][k] = NULL; 846321936Shselasky 847321936Shselasky success = true; 848321936Shselaskyout: 849321936Shselasky return success; 850321936Shselasky} 851321936Shselasky 852321936Shselaskystatic 853321936Shselaskybool parse_unsigned(unsigned *result, const char *parse_sep) 854321936Shselasky{ 855321936Shselasky char *val, *nextchar; 856321936Shselasky 857321936Shselasky val = strtok(NULL, parse_sep); 858321936Shselasky if (!val) 859321936Shselasky return false; 860321936Shselasky *result = strtoul(val, &nextchar, 0); 861321936Shselasky return true; 862321936Shselasky} 863321936Shselasky 864321936Shselaskystatic 865321936Shselaskybool parse_port_order(struct torus *t, const char *parse_sep) 866321936Shselasky{ 867321936Shselasky unsigned i, j, k, n; 868321936Shselasky 869321936Shselasky for (i = 0; i < ARRAY_SIZE(t->port_order); i++) { 870321936Shselasky if (!parse_unsigned(&(t->port_order[i]), parse_sep)) 871321936Shselasky break; 872321936Shselasky 873321936Shselasky for (j = 0; j < i; j++) { 874321936Shselasky if (t->port_order[j] == t->port_order[i]) { 875321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, 876321936Shselasky "Ignored duplicate port %u in" 877321936Shselasky " port_order parsing\n", 878321936Shselasky t->port_order[j]); 879321936Shselasky i--; /* Ignore duplicate port number */ 880321936Shselasky break; 881321936Shselasky } 882321936Shselasky } 883321936Shselasky } 884321936Shselasky 885321936Shselasky n = i; 886321936Shselasky for (j = 0; j < ARRAY_SIZE(t->port_order); j++) { 887321936Shselasky for (k = 0; k < i; k++) 888321936Shselasky if (t->port_order[k] == j) 889321936Shselasky break; 890321936Shselasky if (k >= i) 891321936Shselasky t->port_order[n++] = j; 892321936Shselasky } 893321936Shselasky 894321936Shselasky return true; 895321936Shselasky} 896321936Shselasky 897321936Shselaskystatic 898321936Shselaskybool parse_guid(struct torus *t, guid_t *guid, const char *parse_sep) 899321936Shselasky{ 900321936Shselasky char *val; 901321936Shselasky bool success = false; 902321936Shselasky 903321936Shselasky val = strtok(NULL, parse_sep); 904321936Shselasky if (!val) 905321936Shselasky goto out; 906321936Shselasky *guid = strtoull(val, NULL, 0); 907321936Shselasky *guid = cl_hton64(*guid); 908321936Shselasky 909321936Shselasky success = true; 910321936Shselaskyout: 911321936Shselasky return success; 912321936Shselasky} 913321936Shselasky 914321936Shselaskystatic 915321936Shselaskybool parse_dir_link(int c_dir, struct torus *t, const char *parse_sep) 916321936Shselasky{ 917321936Shselasky guid_t sw_guid0, sw_guid1; 918321936Shselasky struct link *l; 919321936Shselasky bool success = false; 920321936Shselasky 921321936Shselasky if (!parse_guid(t, &sw_guid0, parse_sep)) 922321936Shselasky goto out; 923321936Shselasky 924321936Shselasky if (!parse_guid(t, &sw_guid1, parse_sep)) 925321936Shselasky goto out; 926321936Shselasky 927321936Shselasky if (!t) { 928321936Shselasky success = true; 929321936Shselasky goto out; 930321936Shselasky } 931321936Shselasky 932321936Shselasky switch (c_dir) { 933321936Shselasky case -1: 934321936Shselasky l = &t->seed[t->seed_cnt - 1].xm_link; 935321936Shselasky break; 936321936Shselasky case 1: 937321936Shselasky l = &t->seed[t->seed_cnt - 1].xp_link; 938321936Shselasky break; 939321936Shselasky case -2: 940321936Shselasky l = &t->seed[t->seed_cnt - 1].ym_link; 941321936Shselasky break; 942321936Shselasky case 2: 943321936Shselasky l = &t->seed[t->seed_cnt - 1].yp_link; 944321936Shselasky break; 945321936Shselasky case -3: 946321936Shselasky l = &t->seed[t->seed_cnt - 1].zm_link; 947321936Shselasky break; 948321936Shselasky case 3: 949321936Shselasky l = &t->seed[t->seed_cnt - 1].zp_link; 950321936Shselasky break; 951321936Shselasky default: 952321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 953321936Shselasky "ERR 4E0E: unknown link direction %d\n", c_dir); 954321936Shselasky goto out; 955321936Shselasky } 956321936Shselasky l->end[0].type = PASSTHRU; 957321936Shselasky l->end[0].port = -1; /* We don't really connect. */ 958321936Shselasky l->end[0].n_id = sw_guid0; 959321936Shselasky l->end[0].sw = NULL; /* Fix this up later. */ 960321936Shselasky l->end[0].link = NULL; /* Fix this up later. */ 961321936Shselasky 962321936Shselasky l->end[1].type = PASSTHRU; 963321936Shselasky l->end[1].port = -1; /* We don't really connect. */ 964321936Shselasky l->end[1].n_id = sw_guid1; 965321936Shselasky l->end[1].sw = NULL; /* Fix this up later. */ 966321936Shselasky l->end[1].link = NULL; /* Fix this up later. */ 967321936Shselasky 968321936Shselasky success = true; 969321936Shselaskyout: 970321936Shselasky return success; 971321936Shselasky} 972321936Shselasky 973321936Shselaskystatic 974321936Shselaskybool parse_dir_dateline(int c_dir, struct torus *t, const char *parse_sep) 975321936Shselasky{ 976321936Shselasky char *val; 977321936Shselasky int *dl, max_dl; 978321936Shselasky bool success = false; 979321936Shselasky 980321936Shselasky val = strtok(NULL, parse_sep); 981321936Shselasky if (!val) 982321936Shselasky goto out; 983321936Shselasky 984321936Shselasky if (!t) { 985321936Shselasky success = true; 986321936Shselasky goto out; 987321936Shselasky } 988321936Shselasky 989321936Shselasky switch (c_dir) { 990321936Shselasky case 1: 991321936Shselasky dl = &t->seed[t->seed_cnt - 1].x_dateline; 992321936Shselasky max_dl = t->x_sz; 993321936Shselasky break; 994321936Shselasky case 2: 995321936Shselasky dl = &t->seed[t->seed_cnt - 1].y_dateline; 996321936Shselasky max_dl = t->y_sz; 997321936Shselasky break; 998321936Shselasky case 3: 999321936Shselasky dl = &t->seed[t->seed_cnt - 1].z_dateline; 1000321936Shselasky max_dl = t->z_sz; 1001321936Shselasky break; 1002321936Shselasky default: 1003321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1004321936Shselasky "ERR 4E0F: unknown dateline direction %d\n", c_dir); 1005321936Shselasky goto out; 1006321936Shselasky } 1007321936Shselasky *dl = strtol(val, NULL, 0); 1008321936Shselasky 1009321936Shselasky if ((*dl < 0 && *dl <= -max_dl) || *dl >= max_dl) 1010321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1011321936Shselasky "ERR 4E10: dateline value for coordinate direction %d " 1012321936Shselasky "must be %d < dl < %d\n", 1013321936Shselasky c_dir, -max_dl, max_dl); 1014321936Shselasky else 1015321936Shselasky success = true; 1016321936Shselaskyout: 1017321936Shselasky return success; 1018321936Shselasky} 1019321936Shselasky 1020321936Shselaskystatic 1021321936Shselaskybool parse_config(const char *fn, struct fabric *f, struct torus *t) 1022321936Shselasky{ 1023321936Shselasky FILE *fp; 1024321936Shselasky unsigned i; 1025321936Shselasky char *keyword; 1026321936Shselasky char *line_buf = NULL; 1027321936Shselasky const char *parse_sep = " \n\t\015"; 1028321936Shselasky size_t line_buf_sz = 0; 1029321936Shselasky size_t line_cntr = 0; 1030321936Shselasky ssize_t llen; 1031321936Shselasky bool kw_success, success = true; 1032321936Shselasky 1033321936Shselasky if (!grow_seed_array(t, 2)) 1034321936Shselasky return false; 1035321936Shselasky 1036321936Shselasky for (i = 0; i < ARRAY_SIZE(t->port_order); i++) 1037321936Shselasky t->port_order[i] = i; 1038321936Shselasky 1039321936Shselasky fp = fopen(fn, "r"); 1040321936Shselasky if (!fp) { 1041321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1042321936Shselasky "ERR 4E11: Opening %s: %s\n", fn, strerror(errno)); 1043321936Shselasky return false; 1044321936Shselasky } 1045321936Shselasky t->flags |= NOTIFY_CHANGES; 1046321936Shselasky t->portgrp_sz = PORTGRP_MAX_PORTS; 1047321936Shselasky t->max_changes = DEFAULT_MAX_CHANGES; 1048321936Shselasky 1049321936Shselaskynext_line: 1050321936Shselasky llen = getline(&line_buf, &line_buf_sz, fp); 1051321936Shselasky if (llen < 0) 1052321936Shselasky goto out; 1053321936Shselasky 1054321936Shselasky ++line_cntr; 1055321936Shselasky 1056321936Shselasky keyword = strtok(line_buf, parse_sep); 1057321936Shselasky if (!keyword) 1058321936Shselasky goto next_line; 1059321936Shselasky 1060321936Shselasky if (strcmp("torus", keyword) == 0) { 1061321936Shselasky kw_success = parse_torus(t, parse_sep); 1062321936Shselasky } else if (strcmp("mesh", keyword) == 0) { 1063321936Shselasky t->flags |= X_MESH | Y_MESH | Z_MESH; 1064321936Shselasky kw_success = parse_torus(t, parse_sep); 1065321936Shselasky } else if (strcmp("port_order", keyword) == 0) { 1066321936Shselasky kw_success = parse_port_order(t, parse_sep); 1067321936Shselasky } else if (strcmp("next_seed", keyword) == 0) { 1068321936Shselasky kw_success = grow_seed_array(t, 1); 1069321936Shselasky t->seed_cnt++; 1070321936Shselasky } else if (strcmp("portgroup_max_ports", keyword) == 0) { 1071321936Shselasky kw_success = parse_unsigned(&t->portgrp_sz, parse_sep); 1072321936Shselasky } else if (strcmp("xp_link", keyword) == 0) { 1073321936Shselasky if (!t->seed_cnt) 1074321936Shselasky t->seed_cnt++; 1075321936Shselasky kw_success = parse_dir_link(1, t, parse_sep); 1076321936Shselasky } else if (strcmp("xm_link", keyword) == 0) { 1077321936Shselasky if (!t->seed_cnt) 1078321936Shselasky t->seed_cnt++; 1079321936Shselasky kw_success = parse_dir_link(-1, t, parse_sep); 1080321936Shselasky } else if (strcmp("x_dateline", keyword) == 0) { 1081321936Shselasky if (!t->seed_cnt) 1082321936Shselasky t->seed_cnt++; 1083321936Shselasky kw_success = parse_dir_dateline(1, t, parse_sep); 1084321936Shselasky } else if (strcmp("yp_link", keyword) == 0) { 1085321936Shselasky if (!t->seed_cnt) 1086321936Shselasky t->seed_cnt++; 1087321936Shselasky kw_success = parse_dir_link(2, t, parse_sep); 1088321936Shselasky } else if (strcmp("ym_link", keyword) == 0) { 1089321936Shselasky if (!t->seed_cnt) 1090321936Shselasky t->seed_cnt++; 1091321936Shselasky kw_success = parse_dir_link(-2, t, parse_sep); 1092321936Shselasky } else if (strcmp("y_dateline", keyword) == 0) { 1093321936Shselasky if (!t->seed_cnt) 1094321936Shselasky t->seed_cnt++; 1095321936Shselasky kw_success = parse_dir_dateline(2, t, parse_sep); 1096321936Shselasky } else if (strcmp("zp_link", keyword) == 0) { 1097321936Shselasky if (!t->seed_cnt) 1098321936Shselasky t->seed_cnt++; 1099321936Shselasky kw_success = parse_dir_link(3, t, parse_sep); 1100321936Shselasky } else if (strcmp("zm_link", keyword) == 0) { 1101321936Shselasky if (!t->seed_cnt) 1102321936Shselasky t->seed_cnt++; 1103321936Shselasky kw_success = parse_dir_link(-3, t, parse_sep); 1104321936Shselasky } else if (strcmp("z_dateline", keyword) == 0) { 1105321936Shselasky if (!t->seed_cnt) 1106321936Shselasky t->seed_cnt++; 1107321936Shselasky kw_success = parse_dir_dateline(3, t, parse_sep); 1108321936Shselasky } else if (strcmp("max_changes", keyword) == 0) { 1109321936Shselasky kw_success = parse_unsigned(&t->max_changes, parse_sep); 1110321936Shselasky } else if (keyword[0] == '#') 1111321936Shselasky goto next_line; 1112321936Shselasky else { 1113321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1114321936Shselasky "ERR 4E12: no keyword found: line %u\n", 1115321936Shselasky (unsigned)line_cntr); 1116321936Shselasky kw_success = false; 1117321936Shselasky } 1118321936Shselasky if (!kw_success) { 1119321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1120321936Shselasky "ERR 4E13: parsing '%s': line %u\n", 1121321936Shselasky keyword, (unsigned)line_cntr); 1122321936Shselasky } 1123321936Shselasky success = success && kw_success; 1124321936Shselasky goto next_line; 1125321936Shselasky 1126321936Shselaskyout: 1127321936Shselasky if (line_buf) 1128321936Shselasky free(line_buf); 1129321936Shselasky fclose(fp); 1130321936Shselasky return success; 1131321936Shselasky} 1132321936Shselasky 1133321936Shselaskystatic 1134321936Shselaskybool capture_fabric(struct fabric *fabric) 1135321936Shselasky{ 1136321936Shselasky osm_subn_t *subnet = &fabric->osm->subn; 1137321936Shselasky osm_switch_t *osm_sw; 1138321936Shselasky osm_physp_t *lphysp, *rphysp; 1139321936Shselasky osm_port_t *lport; 1140321936Shselasky osm_node_t *osm_node; 1141321936Shselasky cl_map_item_t *item; 1142321936Shselasky uint8_t ltype, rtype; 1143321936Shselasky int p, port_cnt; 1144321936Shselasky guid_t sw_guid; 1145321936Shselasky bool success = true; 1146321936Shselasky 1147321936Shselasky OSM_LOG_ENTER(&fabric->osm->log); 1148321936Shselasky 1149321936Shselasky /* 1150321936Shselasky * On OpenSM data structures: 1151321936Shselasky * 1152321936Shselasky * Apparently, every port in a fabric has an associated osm_physp_t, 1153321936Shselasky * but not every port has an associated osm_port_t. Apparently every 1154321936Shselasky * osm_port_t has an associated osm_physp_t. 1155321936Shselasky * 1156321936Shselasky * So, in order to find the inter-switch links we need to walk the 1157321936Shselasky * switch list and examine each port, via its osm_physp_t object. 1158321936Shselasky * 1159321936Shselasky * But, we need to associate our CA and switch management port 1160321936Shselasky * endpoints with the corresponding osm_port_t objects, in order 1161321936Shselasky * to simplify computation of LFT entries and perform SL lookup for 1162321936Shselasky * path records. Since it is apparently difficult to locate the 1163321936Shselasky * osm_port_t that corresponds to a given osm_physp_t, we also 1164321936Shselasky * need to walk the list of ports indexed by GUID to get access 1165321936Shselasky * to the appropriate osm_port_t objects. 1166321936Shselasky * 1167321936Shselasky * Need to allocate our switches before we do anything else. 1168321936Shselasky */ 1169321936Shselasky item = cl_qmap_head(&subnet->sw_guid_tbl); 1170321936Shselasky while (item != cl_qmap_end(&subnet->sw_guid_tbl)) { 1171321936Shselasky 1172321936Shselasky osm_sw = (osm_switch_t *)item; 1173321936Shselasky item = cl_qmap_next(item); 1174321936Shselasky osm_sw->priv = NULL; /* avoid stale pointer dereferencing */ 1175321936Shselasky osm_node = osm_sw->p_node; 1176321936Shselasky 1177321936Shselasky if (osm_node_get_type(osm_node) != IB_NODE_TYPE_SWITCH) 1178321936Shselasky continue; 1179321936Shselasky 1180321936Shselasky port_cnt = osm_node_get_num_physp(osm_node); 1181321936Shselasky sw_guid = osm_node_get_node_guid(osm_node); 1182321936Shselasky 1183321936Shselasky success = alloc_fswitch(fabric, sw_guid, port_cnt); 1184321936Shselasky if (!success) 1185321936Shselasky goto out; 1186321936Shselasky } 1187321936Shselasky /* 1188321936Shselasky * Now build all our endpoints. 1189321936Shselasky */ 1190321936Shselasky item = cl_qmap_head(&subnet->port_guid_tbl); 1191321936Shselasky while (item != cl_qmap_end(&subnet->port_guid_tbl)) { 1192321936Shselasky 1193321936Shselasky lport = (osm_port_t *)item; 1194321936Shselasky item = cl_qmap_next(item); 1195321936Shselasky lport->priv = NULL; /* avoid stale pointer dereferencing */ 1196321936Shselasky 1197321936Shselasky lphysp = lport->p_physp; 1198321936Shselasky if (!(lphysp && osm_physp_is_valid(lphysp))) 1199321936Shselasky continue; 1200321936Shselasky 1201321936Shselasky ltype = osm_node_get_type(lphysp->p_node); 1202321936Shselasky /* 1203321936Shselasky * Switch management port is always port 0. 1204321936Shselasky */ 1205321936Shselasky if (lphysp->port_num == 0 && ltype == IB_NODE_TYPE_SWITCH) { 1206321936Shselasky success = build_sw_endpoint(fabric, lport); 1207321936Shselasky if (!success) 1208321936Shselasky goto out; 1209321936Shselasky continue; 1210321936Shselasky } 1211321936Shselasky rphysp = lphysp->p_remote_physp; 1212321936Shselasky if (!(rphysp && osm_physp_is_valid(rphysp))) 1213321936Shselasky continue; 1214321936Shselasky 1215321936Shselasky rtype = osm_node_get_type(rphysp->p_node); 1216321936Shselasky 1217321936Shselasky if ((ltype != IB_NODE_TYPE_CA && 1218321936Shselasky ltype != IB_NODE_TYPE_ROUTER) || 1219321936Shselasky rtype != IB_NODE_TYPE_SWITCH) 1220321936Shselasky continue; 1221321936Shselasky 1222321936Shselasky success = 1223321936Shselasky build_ca_link(fabric, lport, 1224321936Shselasky osm_node_get_node_guid(rphysp->p_node), 1225321936Shselasky osm_physp_get_port_num(rphysp)); 1226321936Shselasky if (!success) 1227321936Shselasky goto out; 1228321936Shselasky } 1229321936Shselasky /* 1230321936Shselasky * Lastly, build all our interswitch links. 1231321936Shselasky */ 1232321936Shselasky item = cl_qmap_head(&subnet->sw_guid_tbl); 1233321936Shselasky while (item != cl_qmap_end(&subnet->sw_guid_tbl)) { 1234321936Shselasky 1235321936Shselasky osm_sw = (osm_switch_t *)item; 1236321936Shselasky item = cl_qmap_next(item); 1237321936Shselasky 1238321936Shselasky port_cnt = osm_node_get_num_physp(osm_sw->p_node); 1239321936Shselasky for (p = 0; p < port_cnt; p++) { 1240321936Shselasky 1241321936Shselasky lphysp = osm_node_get_physp_ptr(osm_sw->p_node, p); 1242321936Shselasky if (!(lphysp && osm_physp_is_valid(lphysp))) 1243321936Shselasky continue; 1244321936Shselasky 1245321936Shselasky rphysp = lphysp->p_remote_physp; 1246321936Shselasky if (!(rphysp && osm_physp_is_valid(rphysp))) 1247321936Shselasky continue; 1248321936Shselasky 1249321936Shselasky if (lphysp == rphysp) 1250321936Shselasky continue; /* ignore loopbacks */ 1251321936Shselasky 1252321936Shselasky ltype = osm_node_get_type(lphysp->p_node); 1253321936Shselasky rtype = osm_node_get_type(rphysp->p_node); 1254321936Shselasky 1255321936Shselasky if (ltype != IB_NODE_TYPE_SWITCH || 1256321936Shselasky rtype != IB_NODE_TYPE_SWITCH) 1257321936Shselasky continue; 1258321936Shselasky 1259321936Shselasky success = 1260321936Shselasky build_link(fabric, 1261321936Shselasky osm_node_get_node_guid(lphysp->p_node), 1262321936Shselasky osm_physp_get_port_num(lphysp), 1263321936Shselasky osm_node_get_node_guid(rphysp->p_node), 1264321936Shselasky osm_physp_get_port_num(rphysp)); 1265321936Shselasky if (!success) 1266321936Shselasky goto out; 1267321936Shselasky } 1268321936Shselasky } 1269321936Shselaskyout: 1270321936Shselasky OSM_LOG_EXIT(&fabric->osm->log); 1271321936Shselasky return success; 1272321936Shselasky} 1273321936Shselasky 1274321936Shselasky/* 1275321936Shselasky * diagnose_fabric() is just intended to report on fabric elements that 1276321936Shselasky * could not be placed into the torus. We want to warn that there were 1277321936Shselasky * non-torus fabric elements, but they will be ignored for routing purposes. 1278321936Shselasky * Having them is not an error, and diagnose_fabric() thus has no return 1279321936Shselasky * value. 1280321936Shselasky */ 1281321936Shselaskystatic 1282321936Shselaskyvoid diagnose_fabric(struct fabric *f) 1283321936Shselasky{ 1284321936Shselasky struct link *l; 1285321936Shselasky struct endpoint *ep; 1286321936Shselasky unsigned k, p; 1287321936Shselasky 1288321936Shselasky /* 1289321936Shselasky * Report on any links that didn't get transferred to the torus. 1290321936Shselasky */ 1291321936Shselasky for (k = 0; k < f->link_cnt; k++) { 1292321936Shselasky l = f->link[k]; 1293321936Shselasky 1294321936Shselasky if (!(l->end[0].sw && l->end[1].sw)) 1295321936Shselasky continue; 1296321936Shselasky 1297321936Shselasky OSM_LOG(&f->osm->log, OSM_LOG_INFO, 1298321936Shselasky "Found non-torus fabric link:" 1299321936Shselasky " sw GUID 0x%04"PRIx64" port %d <->" 1300321936Shselasky " sw GUID 0x%04"PRIx64" port %d\n", 1301321936Shselasky cl_ntoh64(l->end[0].n_id), l->end[0].port, 1302321936Shselasky cl_ntoh64(l->end[1].n_id), l->end[1].port); 1303321936Shselasky } 1304321936Shselasky /* 1305321936Shselasky * Report on any switches with ports using endpoints that didn't 1306321936Shselasky * get transferred to the torus. 1307321936Shselasky */ 1308321936Shselasky for (k = 0; k < f->switch_cnt; k++) 1309321936Shselasky for (p = 0; p < f->sw[k]->port_cnt; p++) { 1310321936Shselasky 1311321936Shselasky if (!f->sw[k]->port[p]) 1312321936Shselasky continue; 1313321936Shselasky 1314321936Shselasky ep = f->sw[k]->port[p]; 1315321936Shselasky 1316321936Shselasky /* 1317321936Shselasky * We already reported on inter-switch links above. 1318321936Shselasky */ 1319321936Shselasky if (ep->type == PASSTHRU) 1320321936Shselasky continue; 1321321936Shselasky 1322321936Shselasky OSM_LOG(&f->osm->log, OSM_LOG_INFO, 1323321936Shselasky "Found non-torus fabric port:" 1324321936Shselasky " sw GUID 0x%04"PRIx64" port %d\n", 1325321936Shselasky cl_ntoh64(f->sw[k]->n_id), p); 1326321936Shselasky } 1327321936Shselasky} 1328321936Shselasky 1329321936Shselaskystatic 1330321936Shselaskystruct t_switch *alloc_tswitch(struct torus *t, struct f_switch *fsw) 1331321936Shselasky{ 1332321936Shselasky unsigned g; 1333321936Shselasky size_t new_sw_sz; 1334321936Shselasky struct t_switch *sw = NULL; 1335321936Shselasky void *ptr; 1336321936Shselasky 1337321936Shselasky if (!fsw) 1338321936Shselasky goto out; 1339321936Shselasky 1340321936Shselasky if (t->switch_cnt >= t->sw_pool_sz) { 1341321936Shselasky /* 1342321936Shselasky * This should never happen, but occasionally a particularly 1343321936Shselasky * pathological fabric can induce it. So log an error. 1344321936Shselasky */ 1345321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1346321936Shselasky "ERR 4E14: unexpectedly requested too many switch " 1347321936Shselasky "structures!\n"); 1348321936Shselasky goto out; 1349321936Shselasky } 1350321936Shselasky new_sw_sz = sizeof(*sw) 1351321936Shselasky + fsw->port_cnt * sizeof(*sw->port) 1352321936Shselasky + SWITCH_MAX_PORTGRPS * t->portgrp_sz * sizeof(*sw->ptgrp[0].port); 1353321936Shselasky sw = calloc(1, new_sw_sz); 1354321936Shselasky if (!sw) { 1355321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1356321936Shselasky "ERR 4E15: calloc: %s\n", strerror(errno)); 1357321936Shselasky goto out; 1358321936Shselasky } 1359321936Shselasky sw->port = (void *)(sw + 1); 1360321936Shselasky sw->n_id = fsw->n_id; 1361321936Shselasky sw->port_cnt = fsw->port_cnt; 1362321936Shselasky sw->torus = t; 1363321936Shselasky sw->tmp = fsw; 1364321936Shselasky 1365321936Shselasky ptr = &sw->port[sw->port_cnt]; 1366321936Shselasky 1367321936Shselasky for (g = 0; g < SWITCH_MAX_PORTGRPS; g++) { 1368321936Shselasky sw->ptgrp[g].port_grp = g; 1369321936Shselasky sw->ptgrp[g].sw = sw; 1370321936Shselasky sw->ptgrp[g].port = ptr; 1371321936Shselasky ptr = &sw->ptgrp[g].port[t->portgrp_sz]; 1372321936Shselasky } 1373321936Shselasky t->sw_pool[t->switch_cnt++] = sw; 1374321936Shselaskyout: 1375321936Shselasky return sw; 1376321936Shselasky} 1377321936Shselasky 1378321936Shselasky/* 1379321936Shselasky * install_tswitch() expects the switch coordinates i,j,k to be canonicalized 1380321936Shselasky * by caller. 1381321936Shselasky */ 1382321936Shselaskystatic 1383321936Shselaskybool install_tswitch(struct torus *t, 1384321936Shselasky int i, int j, int k, struct f_switch *fsw) 1385321936Shselasky{ 1386321936Shselasky struct t_switch **sw = &t->sw[i][j][k]; 1387321936Shselasky 1388321936Shselasky if (!*sw) 1389321936Shselasky *sw = alloc_tswitch(t, fsw); 1390321936Shselasky 1391321936Shselasky if (*sw) { 1392321936Shselasky (*sw)->i = i; 1393321936Shselasky (*sw)->j = j; 1394321936Shselasky (*sw)->k = k; 1395321936Shselasky } 1396321936Shselasky return !!*sw; 1397321936Shselasky} 1398321936Shselasky 1399321936Shselaskystatic 1400321936Shselaskystruct link *alloc_tlink(struct torus *t) 1401321936Shselasky{ 1402321936Shselasky if (t->link_cnt >= t->link_pool_sz) { 1403321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1404321936Shselasky "ERR 4E16: unexpectedly out of pre-allocated link " 1405321936Shselasky "structures!\n"); 1406321936Shselasky return NULL; 1407321936Shselasky } 1408321936Shselasky return &t->link_pool[t->link_cnt++]; 1409321936Shselasky} 1410321936Shselasky 1411321936Shselaskystatic 1412321936Shselaskyint canonicalize(int v, int vmax) 1413321936Shselasky{ 1414321936Shselasky if (v >= 0 && v < vmax) 1415321936Shselasky return v; 1416321936Shselasky 1417321936Shselasky if (v < 0) 1418321936Shselasky v += vmax * (1 - v/vmax); 1419321936Shselasky 1420321936Shselasky return v % vmax; 1421321936Shselasky} 1422321936Shselasky 1423321936Shselaskystatic 1424321936Shselaskyunsigned set_fp_bit(bool present, int i, int j, int k) 1425321936Shselasky{ 1426321936Shselasky return (unsigned)(!present) << (i + 2 * j + 4 * k); 1427321936Shselasky} 1428321936Shselasky 1429321936Shselasky/* 1430321936Shselasky * Returns an 11-bit fingerprint of what switches are absent in a cube of 1431321936Shselasky * neighboring switches. Each bit 0-7 corresponds to a corner of the cube; 1432321936Shselasky * if a bit is set the corresponding switch is absent. 1433321936Shselasky * 1434321936Shselasky * Bits 8-10 distinguish between 2D and 3D cases. If bit 8+d is set, 1435321936Shselasky * for 0 <= d < 3; the d dimension of the desired torus has radix greater 1436321936Shselasky * than 1. Thus, if all bits 8-10 are set, the desired torus is 3D. 1437321936Shselasky */ 1438321936Shselaskystatic 1439321936Shselaskyunsigned fingerprint(struct torus *t, int i, int j, int k) 1440321936Shselasky{ 1441321936Shselasky unsigned fp; 1442321936Shselasky int ip1, jp1, kp1; 1443321936Shselasky int x_sz_gt1, y_sz_gt1, z_sz_gt1; 1444321936Shselasky 1445321936Shselasky x_sz_gt1 = t->x_sz > 1; 1446321936Shselasky y_sz_gt1 = t->y_sz > 1; 1447321936Shselasky z_sz_gt1 = t->z_sz > 1; 1448321936Shselasky 1449321936Shselasky ip1 = canonicalize(i + 1, t->x_sz); 1450321936Shselasky jp1 = canonicalize(j + 1, t->y_sz); 1451321936Shselasky kp1 = canonicalize(k + 1, t->z_sz); 1452321936Shselasky 1453321936Shselasky fp = set_fp_bit(t->sw[i][j][k], 0, 0, 0); 1454321936Shselasky fp |= set_fp_bit(t->sw[ip1][j][k], x_sz_gt1, 0, 0); 1455321936Shselasky fp |= set_fp_bit(t->sw[i][jp1][k], 0, y_sz_gt1, 0); 1456321936Shselasky fp |= set_fp_bit(t->sw[ip1][jp1][k], x_sz_gt1, y_sz_gt1, 0); 1457321936Shselasky fp |= set_fp_bit(t->sw[i][j][kp1], 0, 0, z_sz_gt1); 1458321936Shselasky fp |= set_fp_bit(t->sw[ip1][j][kp1], x_sz_gt1, 0, z_sz_gt1); 1459321936Shselasky fp |= set_fp_bit(t->sw[i][jp1][kp1], 0, y_sz_gt1, z_sz_gt1); 1460321936Shselasky fp |= set_fp_bit(t->sw[ip1][jp1][kp1], x_sz_gt1, y_sz_gt1, z_sz_gt1); 1461321936Shselasky 1462321936Shselasky fp |= x_sz_gt1 << 8; 1463321936Shselasky fp |= y_sz_gt1 << 9; 1464321936Shselasky fp |= z_sz_gt1 << 10; 1465321936Shselasky 1466321936Shselasky return fp; 1467321936Shselasky} 1468321936Shselasky 1469321936Shselaskystatic 1470321936Shselaskybool connect_tlink(struct port_grp *pg0, struct endpoint *f_ep0, 1471321936Shselasky struct port_grp *pg1, struct endpoint *f_ep1, 1472321936Shselasky struct torus *t) 1473321936Shselasky{ 1474321936Shselasky struct link *l; 1475321936Shselasky bool success = false; 1476321936Shselasky 1477321936Shselasky if (pg0->port_cnt == t->portgrp_sz) { 1478321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1479321936Shselasky "ERR 4E17: exceeded port group max " 1480321936Shselasky "port count (%d): switch GUID 0x%04"PRIx64"\n", 1481321936Shselasky t->portgrp_sz, cl_ntoh64(pg0->sw->n_id)); 1482321936Shselasky goto out; 1483321936Shselasky } 1484321936Shselasky if (pg1->port_cnt == t->portgrp_sz) { 1485321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1486321936Shselasky "ERR 4E18: exceeded port group max " 1487321936Shselasky "port count (%d): switch GUID 0x%04"PRIx64"\n", 1488321936Shselasky t->portgrp_sz, cl_ntoh64(pg1->sw->n_id)); 1489321936Shselasky goto out; 1490321936Shselasky } 1491321936Shselasky l = alloc_tlink(t); 1492321936Shselasky if (!l) 1493321936Shselasky goto out; 1494321936Shselasky 1495321936Shselasky l->end[0].type = f_ep0->type; 1496321936Shselasky l->end[0].port = f_ep0->port; 1497321936Shselasky l->end[0].n_id = f_ep0->n_id; 1498321936Shselasky l->end[0].sw = pg0->sw; 1499321936Shselasky l->end[0].link = l; 1500321936Shselasky l->end[0].pgrp = pg0; 1501321936Shselasky pg0->port[pg0->port_cnt++] = &l->end[0]; 1502321936Shselasky pg0->sw->port[f_ep0->port] = &l->end[0]; 1503321936Shselasky 1504321936Shselasky if (f_ep0->osm_port) { 1505321936Shselasky l->end[0].osm_port = f_ep0->osm_port; 1506321936Shselasky l->end[0].osm_port->priv = &l->end[0]; 1507321936Shselasky f_ep0->osm_port = NULL; 1508321936Shselasky } 1509321936Shselasky 1510321936Shselasky l->end[1].type = f_ep1->type; 1511321936Shselasky l->end[1].port = f_ep1->port; 1512321936Shselasky l->end[1].n_id = f_ep1->n_id; 1513321936Shselasky l->end[1].sw = pg1->sw; 1514321936Shselasky l->end[1].link = l; 1515321936Shselasky l->end[1].pgrp = pg1; 1516321936Shselasky pg1->port[pg1->port_cnt++] = &l->end[1]; 1517321936Shselasky pg1->sw->port[f_ep1->port] = &l->end[1]; 1518321936Shselasky 1519321936Shselasky if (f_ep1->osm_port) { 1520321936Shselasky l->end[1].osm_port = f_ep1->osm_port; 1521321936Shselasky l->end[1].osm_port->priv = &l->end[1]; 1522321936Shselasky f_ep1->osm_port = NULL; 1523321936Shselasky } 1524321936Shselasky /* 1525321936Shselasky * Disconnect fabric link, so that later we can see if any were 1526321936Shselasky * left unconnected in the torus. 1527321936Shselasky */ 1528321936Shselasky ((struct f_switch *)f_ep0->sw)->port[f_ep0->port] = NULL; 1529321936Shselasky f_ep0->sw = NULL; 1530321936Shselasky f_ep0->port = -1; 1531321936Shselasky 1532321936Shselasky ((struct f_switch *)f_ep1->sw)->port[f_ep1->port] = NULL; 1533321936Shselasky f_ep1->sw = NULL; 1534321936Shselasky f_ep1->port = -1; 1535321936Shselasky 1536321936Shselasky success = true; 1537321936Shselaskyout: 1538321936Shselasky return success; 1539321936Shselasky} 1540321936Shselasky 1541321936Shselaskystatic 1542321936Shselaskybool link_tswitches(struct torus *t, int cdir, 1543321936Shselasky struct t_switch *t_sw0, struct t_switch *t_sw1) 1544321936Shselasky{ 1545321936Shselasky int p; 1546321936Shselasky struct port_grp *pg0, *pg1; 1547321936Shselasky struct f_switch *f_sw0, *f_sw1; 1548321936Shselasky const char *cdir_name = "unknown"; 1549321936Shselasky unsigned port_cnt; 1550321936Shselasky int success = false; 1551321936Shselasky 1552321936Shselasky /* 1553321936Shselasky * If this is a 2D torus, it is possible for this function to be 1554321936Shselasky * called with its two switch arguments being the same switch, in 1555321936Shselasky * which case there are no links to install. 1556321936Shselasky */ 1557321936Shselasky if (t_sw0 == t_sw1 && 1558321936Shselasky ((cdir == 0 && t->x_sz == 1) || 1559321936Shselasky (cdir == 1 && t->y_sz == 1) || 1560321936Shselasky (cdir == 2 && t->z_sz == 1))) { 1561321936Shselasky success = true; 1562321936Shselasky goto out; 1563321936Shselasky } 1564321936Shselasky /* 1565321936Shselasky * Ensure that t_sw1 is in the positive cdir direction wrt. t_sw0. 1566321936Shselasky * ring_next_sw() relies on it. 1567321936Shselasky */ 1568321936Shselasky switch (cdir) { 1569321936Shselasky case 0: 1570321936Shselasky if (t->x_sz > 1 && 1571321936Shselasky canonicalize(t_sw0->i + 1, t->x_sz) != t_sw1->i) { 1572321936Shselasky cdir_name = "x"; 1573321936Shselasky goto cdir_error; 1574321936Shselasky } 1575321936Shselasky break; 1576321936Shselasky case 1: 1577321936Shselasky if (t->y_sz > 1 && 1578321936Shselasky canonicalize(t_sw0->j + 1, t->y_sz) != t_sw1->j) { 1579321936Shselasky cdir_name = "y"; 1580321936Shselasky goto cdir_error; 1581321936Shselasky } 1582321936Shselasky break; 1583321936Shselasky case 2: 1584321936Shselasky if (t->z_sz > 1 && 1585321936Shselasky canonicalize(t_sw0->k + 1, t->z_sz) != t_sw1->k) { 1586321936Shselasky cdir_name = "z"; 1587321936Shselasky goto cdir_error; 1588321936Shselasky } 1589321936Shselasky break; 1590321936Shselasky default: 1591321936Shselasky cdir_error: 1592321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, "ERR 4E19: " 1593321936Shselasky "sw 0x%04"PRIx64" (%d,%d,%d) <--> " 1594321936Shselasky "sw 0x%04"PRIx64" (%d,%d,%d) " 1595321936Shselasky "invalid torus %s link orientation\n", 1596321936Shselasky cl_ntoh64(t_sw0->n_id), t_sw0->i, t_sw0->j, t_sw0->k, 1597321936Shselasky cl_ntoh64(t_sw1->n_id), t_sw1->i, t_sw1->j, t_sw1->k, 1598321936Shselasky cdir_name); 1599321936Shselasky goto out; 1600321936Shselasky } 1601321936Shselasky 1602321936Shselasky f_sw0 = t_sw0->tmp; 1603321936Shselasky f_sw1 = t_sw1->tmp; 1604321936Shselasky 1605321936Shselasky if (!f_sw0 || !f_sw1) { 1606321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1607321936Shselasky "ERR 4E1A: missing fabric switches!\n" 1608321936Shselasky " switch GUIDs: 0x%04"PRIx64" 0x%04"PRIx64"\n", 1609321936Shselasky cl_ntoh64(t_sw0->n_id), cl_ntoh64(t_sw1->n_id)); 1610321936Shselasky goto out; 1611321936Shselasky } 1612321936Shselasky pg0 = &t_sw0->ptgrp[2*cdir + 1]; 1613321936Shselasky pg0->type = PASSTHRU; 1614321936Shselasky 1615321936Shselasky pg1 = &t_sw1->ptgrp[2*cdir]; 1616321936Shselasky pg1->type = PASSTHRU; 1617321936Shselasky 1618321936Shselasky port_cnt = f_sw0->port_cnt; 1619321936Shselasky /* 1620321936Shselasky * Find all the links between these two switches. 1621321936Shselasky */ 1622321936Shselasky for (p = 0; p < port_cnt; p++) { 1623321936Shselasky struct endpoint *f_ep0 = NULL, *f_ep1 = NULL; 1624321936Shselasky 1625321936Shselasky if (!f_sw0->port[p] || !f_sw0->port[p]->link) 1626321936Shselasky continue; 1627321936Shselasky 1628321936Shselasky if (f_sw0->port[p]->link->end[0].n_id == t_sw0->n_id && 1629321936Shselasky f_sw0->port[p]->link->end[1].n_id == t_sw1->n_id) { 1630321936Shselasky 1631321936Shselasky f_ep0 = &f_sw0->port[p]->link->end[0]; 1632321936Shselasky f_ep1 = &f_sw0->port[p]->link->end[1]; 1633321936Shselasky } else if (f_sw0->port[p]->link->end[1].n_id == t_sw0->n_id && 1634321936Shselasky f_sw0->port[p]->link->end[0].n_id == t_sw1->n_id) { 1635321936Shselasky 1636321936Shselasky f_ep0 = &f_sw0->port[p]->link->end[1]; 1637321936Shselasky f_ep1 = &f_sw0->port[p]->link->end[0]; 1638321936Shselasky } else 1639321936Shselasky continue; 1640321936Shselasky 1641321936Shselasky if (!(f_ep0->type == PASSTHRU && f_ep1->type == PASSTHRU)) { 1642321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1643321936Shselasky "ERR 4E1B: not interswitch " 1644321936Shselasky "link:\n 0x%04"PRIx64"/%d <-> 0x%04"PRIx64"/%d\n", 1645321936Shselasky cl_ntoh64(f_ep0->n_id), f_ep0->port, 1646321936Shselasky cl_ntoh64(f_ep1->n_id), f_ep1->port); 1647321936Shselasky goto out; 1648321936Shselasky } 1649321936Shselasky /* 1650321936Shselasky * Skip over links that already have been established in the 1651321936Shselasky * torus. 1652321936Shselasky */ 1653321936Shselasky if (!(f_ep0->sw && f_ep1->sw)) 1654321936Shselasky continue; 1655321936Shselasky 1656321936Shselasky if (!connect_tlink(pg0, f_ep0, pg1, f_ep1, t)) 1657321936Shselasky goto out; 1658321936Shselasky } 1659321936Shselasky success = true; 1660321936Shselaskyout: 1661321936Shselasky return success; 1662321936Shselasky} 1663321936Shselasky 1664321936Shselaskystatic 1665321936Shselaskybool link_srcsink(struct torus *t, int i, int j, int k) 1666321936Shselasky{ 1667321936Shselasky struct endpoint *f_ep0; 1668321936Shselasky struct endpoint *f_ep1; 1669321936Shselasky struct t_switch *tsw; 1670321936Shselasky struct f_switch *fsw; 1671321936Shselasky struct port_grp *pg; 1672321936Shselasky struct link *fl, *tl; 1673321936Shselasky unsigned p, port_cnt; 1674321936Shselasky bool success = false; 1675321936Shselasky 1676321936Shselasky i = canonicalize(i, t->x_sz); 1677321936Shselasky j = canonicalize(j, t->y_sz); 1678321936Shselasky k = canonicalize(k, t->z_sz); 1679321936Shselasky 1680321936Shselasky tsw = t->sw[i][j][k]; 1681321936Shselasky if (!tsw) 1682321936Shselasky return true; 1683321936Shselasky 1684321936Shselasky fsw = tsw->tmp; 1685321936Shselasky /* 1686321936Shselasky * link_srcsink is supposed to get called once for every switch in 1687321936Shselasky * the fabric. At this point every fsw we encounter must have a 1688321936Shselasky * non-null osm_switch. Otherwise something has gone horribly 1689321936Shselasky * wrong with topology discovery; the most likely reason is that 1690321936Shselasky * the fabric contains a radix-4 torus dimension, but the user gave 1691321936Shselasky * a config that didn't say so, breaking all the checking in 1692321936Shselasky * safe_x_perpendicular and friends. 1693321936Shselasky */ 1694321936Shselasky if (!(fsw && fsw->osm_switch)) { 1695321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1696321936Shselasky "ERR 4E1C: Invalid topology discovery. " 1697321936Shselasky "Verify torus-2QoS.conf contents.\n"); 1698321936Shselasky return false; 1699321936Shselasky } 1700321936Shselasky 1701321936Shselasky pg = &tsw->ptgrp[2 * TORUS_MAX_DIM]; 1702321936Shselasky pg->type = SRCSINK; 1703321936Shselasky tsw->osm_switch = fsw->osm_switch; 1704321936Shselasky tsw->osm_switch->priv = tsw; 1705321936Shselasky fsw->osm_switch = NULL; 1706321936Shselasky 1707321936Shselasky port_cnt = fsw->port_cnt; 1708321936Shselasky for (p = 0; p < port_cnt; p++) { 1709321936Shselasky 1710321936Shselasky if (!fsw->port[p]) 1711321936Shselasky continue; 1712321936Shselasky 1713321936Shselasky if (fsw->port[p]->type == SRCSINK) { 1714321936Shselasky /* 1715321936Shselasky * If the endpoint is the switch port used for in-band 1716321936Shselasky * communication with the switch itself, move it to 1717321936Shselasky * the torus. 1718321936Shselasky */ 1719321936Shselasky if (pg->port_cnt == t->portgrp_sz) { 1720321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1721321936Shselasky "ERR 4E1D: exceeded port group max port " 1722321936Shselasky "count (%d): switch GUID 0x%04"PRIx64"\n", 1723321936Shselasky t->portgrp_sz, cl_ntoh64(tsw->n_id)); 1724321936Shselasky goto out; 1725321936Shselasky } 1726321936Shselasky fsw->port[p]->sw = tsw; 1727321936Shselasky fsw->port[p]->pgrp = pg; 1728321936Shselasky tsw->port[p] = fsw->port[p]; 1729321936Shselasky tsw->port[p]->osm_port->priv = tsw->port[p]; 1730321936Shselasky pg->port[pg->port_cnt++] = fsw->port[p]; 1731321936Shselasky fsw->port[p] = NULL; 1732321936Shselasky 1733321936Shselasky } else if (fsw->port[p]->link && 1734321936Shselasky fsw->port[p]->type == PASSTHRU) { 1735321936Shselasky /* 1736321936Shselasky * If the endpoint is a link to a CA, create a new link 1737321936Shselasky * in the torus. Disconnect the fabric link. 1738321936Shselasky */ 1739321936Shselasky 1740321936Shselasky fl = fsw->port[p]->link; 1741321936Shselasky 1742321936Shselasky if (fl->end[0].sw == fsw) { 1743321936Shselasky f_ep0 = &fl->end[0]; 1744321936Shselasky f_ep1 = &fl->end[1]; 1745321936Shselasky } else if (fl->end[1].sw == fsw) { 1746321936Shselasky f_ep1 = &fl->end[0]; 1747321936Shselasky f_ep0 = &fl->end[1]; 1748321936Shselasky } else 1749321936Shselasky continue; 1750321936Shselasky 1751321936Shselasky if (f_ep1->type != SRCSINK) 1752321936Shselasky continue; 1753321936Shselasky 1754321936Shselasky if (pg->port_cnt == t->portgrp_sz) { 1755321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1756321936Shselasky "ERR 4E1E: exceeded port group max port " 1757321936Shselasky "count (%d): switch GUID 0x%04"PRIx64"\n", 1758321936Shselasky t->portgrp_sz, cl_ntoh64(tsw->n_id)); 1759321936Shselasky goto out; 1760321936Shselasky } 1761321936Shselasky /* 1762321936Shselasky * Switch ports connected to links don't get 1763321936Shselasky * associated with osm_port_t objects; see 1764321936Shselasky * capture_fabric(). So just check CA end. 1765321936Shselasky */ 1766321936Shselasky if (!f_ep1->osm_port) { 1767321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 1768321936Shselasky "ERR 4E1F: NULL osm_port->priv port " 1769321936Shselasky "GUID 0x%04"PRIx64"\n", 1770321936Shselasky cl_ntoh64(f_ep1->n_id)); 1771321936Shselasky goto out; 1772321936Shselasky } 1773321936Shselasky tl = alloc_tlink(t); 1774321936Shselasky if (!tl) 1775321936Shselasky continue; 1776321936Shselasky 1777321936Shselasky tl->end[0].type = f_ep0->type; 1778321936Shselasky tl->end[0].port = f_ep0->port; 1779321936Shselasky tl->end[0].n_id = f_ep0->n_id; 1780321936Shselasky tl->end[0].sw = tsw; 1781321936Shselasky tl->end[0].link = tl; 1782321936Shselasky tl->end[0].pgrp = pg; 1783321936Shselasky pg->port[pg->port_cnt++] = &tl->end[0]; 1784321936Shselasky pg->sw->port[f_ep0->port] = &tl->end[0]; 1785321936Shselasky 1786321936Shselasky tl->end[1].type = f_ep1->type; 1787321936Shselasky tl->end[1].port = f_ep1->port; 1788321936Shselasky tl->end[1].n_id = f_ep1->n_id; 1789321936Shselasky tl->end[1].sw = NULL; /* Correct for a CA */ 1790321936Shselasky tl->end[1].link = tl; 1791321936Shselasky tl->end[1].pgrp = NULL; /* Correct for a CA */ 1792321936Shselasky 1793321936Shselasky tl->end[1].osm_port = f_ep1->osm_port; 1794321936Shselasky tl->end[1].osm_port->priv = &tl->end[1]; 1795321936Shselasky f_ep1->osm_port = NULL; 1796321936Shselasky 1797321936Shselasky t->ca_cnt++; 1798321936Shselasky f_ep0->sw = NULL; 1799321936Shselasky f_ep0->port = -1; 1800321936Shselasky fsw->port[p] = NULL; 1801321936Shselasky } 1802321936Shselasky } 1803321936Shselasky success = true; 1804321936Shselaskyout: 1805321936Shselasky return success; 1806321936Shselasky} 1807321936Shselasky 1808321936Shselaskystatic 1809321936Shselaskystruct f_switch *ffind_face_corner(struct f_switch *fsw0, 1810321936Shselasky struct f_switch *fsw1, 1811321936Shselasky struct f_switch *fsw2) 1812321936Shselasky{ 1813321936Shselasky int p0, p3; 1814321936Shselasky struct link *l; 1815321936Shselasky struct endpoint *far_end; 1816321936Shselasky struct f_switch *fsw, *fsw3 = NULL; 1817321936Shselasky 1818321936Shselasky if (!(fsw0 && fsw1 && fsw2)) 1819321936Shselasky goto out; 1820321936Shselasky 1821321936Shselasky for (p0 = 0; p0 < fsw0->port_cnt; p0++) { 1822321936Shselasky /* 1823321936Shselasky * Ignore everything except switch links that haven't 1824321936Shselasky * been installed into the torus. 1825321936Shselasky */ 1826321936Shselasky if (!(fsw0->port[p0] && fsw0->port[p0]->sw && 1827321936Shselasky fsw0->port[p0]->type == PASSTHRU)) 1828321936Shselasky continue; 1829321936Shselasky 1830321936Shselasky l = fsw0->port[p0]->link; 1831321936Shselasky 1832321936Shselasky if (l->end[0].n_id == fsw0->n_id) 1833321936Shselasky far_end = &l->end[1]; 1834321936Shselasky else 1835321936Shselasky far_end = &l->end[0]; 1836321936Shselasky 1837321936Shselasky /* 1838321936Shselasky * Ignore CAs 1839321936Shselasky */ 1840321936Shselasky if (!(far_end->type == PASSTHRU && far_end->sw)) 1841321936Shselasky continue; 1842321936Shselasky 1843321936Shselasky fsw3 = far_end->sw; 1844321936Shselasky if (fsw3->n_id == fsw1->n_id) /* existing corner */ 1845321936Shselasky continue; 1846321936Shselasky 1847321936Shselasky for (p3 = 0; p3 < fsw3->port_cnt; p3++) { 1848321936Shselasky /* 1849321936Shselasky * Ignore everything except switch links that haven't 1850321936Shselasky * been installed into the torus. 1851321936Shselasky */ 1852321936Shselasky if (!(fsw3->port[p3] && fsw3->port[p3]->sw && 1853321936Shselasky fsw3->port[p3]->type == PASSTHRU)) 1854321936Shselasky continue; 1855321936Shselasky 1856321936Shselasky l = fsw3->port[p3]->link; 1857321936Shselasky 1858321936Shselasky if (l->end[0].n_id == fsw3->n_id) 1859321936Shselasky far_end = &l->end[1]; 1860321936Shselasky else 1861321936Shselasky far_end = &l->end[0]; 1862321936Shselasky 1863321936Shselasky /* 1864321936Shselasky * Ignore CAs 1865321936Shselasky */ 1866321936Shselasky if (!(far_end->type == PASSTHRU && far_end->sw)) 1867321936Shselasky continue; 1868321936Shselasky 1869321936Shselasky fsw = far_end->sw; 1870321936Shselasky if (fsw->n_id == fsw2->n_id) 1871321936Shselasky goto out; 1872321936Shselasky } 1873321936Shselasky } 1874321936Shselasky fsw3 = NULL; 1875321936Shselaskyout: 1876321936Shselasky return fsw3; 1877321936Shselasky} 1878321936Shselasky 1879321936Shselaskystatic 1880321936Shselaskystruct f_switch *tfind_face_corner(struct t_switch *tsw0, 1881321936Shselasky struct t_switch *tsw1, 1882321936Shselasky struct t_switch *tsw2) 1883321936Shselasky{ 1884321936Shselasky if (!(tsw0 && tsw1 && tsw2)) 1885321936Shselasky return NULL; 1886321936Shselasky 1887321936Shselasky return ffind_face_corner(tsw0->tmp, tsw1->tmp, tsw2->tmp); 1888321936Shselasky} 1889321936Shselasky 1890321936Shselasky/* 1891321936Shselasky * This code can break on any torus with a dimension that has radix four. 1892321936Shselasky * 1893321936Shselasky * What is supposed to happen is that this code will find the 1894321936Shselasky * two faces whose shared edge is the desired perpendicular. 1895321936Shselasky * 1896321936Shselasky * What actually happens is while searching we send two connected 1897321936Shselasky * edges that are colinear in a torus dimension with radix four to 1898321936Shselasky * ffind_face_corner(), which tries to complete a face by finding a 1899321936Shselasky * 4-loop of edges. 1900321936Shselasky * 1901321936Shselasky * In the radix four torus case, it can find a 4-loop which is a ring in a 1902321936Shselasky * dimension with radix four, rather than the desired face. It thus returns 1903321936Shselasky * true when it shouldn't, so the wrong edge is returned as the perpendicular. 1904321936Shselasky * 1905321936Shselasky * The appropriate instance of safe_N_perpendicular() (where N == x, y, z) 1906321936Shselasky * should be used to determine if it is safe to call ffind_perpendicular(); 1907321936Shselasky * these functions will return false it there is a possibility of finding 1908321936Shselasky * a wrong perpendicular. 1909321936Shselasky */ 1910321936Shselaskystruct f_switch *ffind_3d_perpendicular(struct f_switch *fsw0, 1911321936Shselasky struct f_switch *fsw1, 1912321936Shselasky struct f_switch *fsw2, 1913321936Shselasky struct f_switch *fsw3) 1914321936Shselasky{ 1915321936Shselasky int p1; 1916321936Shselasky struct link *l; 1917321936Shselasky struct endpoint *far_end; 1918321936Shselasky struct f_switch *fsw4 = NULL; 1919321936Shselasky 1920321936Shselasky if (!(fsw0 && fsw1 && fsw2 && fsw3)) 1921321936Shselasky goto out; 1922321936Shselasky 1923321936Shselasky /* 1924321936Shselasky * Look at all the ports on the switch, fsw1, that is the base of 1925321936Shselasky * the perpendicular. 1926321936Shselasky */ 1927321936Shselasky for (p1 = 0; p1 < fsw1->port_cnt; p1++) { 1928321936Shselasky /* 1929321936Shselasky * Ignore everything except switch links that haven't 1930321936Shselasky * been installed into the torus. 1931321936Shselasky */ 1932321936Shselasky if (!(fsw1->port[p1] && fsw1->port[p1]->sw && 1933321936Shselasky fsw1->port[p1]->type == PASSTHRU)) 1934321936Shselasky continue; 1935321936Shselasky 1936321936Shselasky l = fsw1->port[p1]->link; 1937321936Shselasky 1938321936Shselasky if (l->end[0].n_id == fsw1->n_id) 1939321936Shselasky far_end = &l->end[1]; 1940321936Shselasky else 1941321936Shselasky far_end = &l->end[0]; 1942321936Shselasky /* 1943321936Shselasky * Ignore CAs 1944321936Shselasky */ 1945321936Shselasky if (!(far_end->type == PASSTHRU && far_end->sw)) 1946321936Shselasky continue; 1947321936Shselasky 1948321936Shselasky fsw4 = far_end->sw; 1949321936Shselasky if (fsw4->n_id == fsw3->n_id) /* wrong perpendicular */ 1950321936Shselasky continue; 1951321936Shselasky 1952321936Shselasky if (ffind_face_corner(fsw0, fsw1, fsw4) && 1953321936Shselasky ffind_face_corner(fsw2, fsw1, fsw4)) 1954321936Shselasky goto out; 1955321936Shselasky } 1956321936Shselasky fsw4 = NULL; 1957321936Shselaskyout: 1958321936Shselasky return fsw4; 1959321936Shselasky} 1960321936Shselaskystruct f_switch *ffind_2d_perpendicular(struct f_switch *fsw0, 1961321936Shselasky struct f_switch *fsw1, 1962321936Shselasky struct f_switch *fsw2) 1963321936Shselasky{ 1964321936Shselasky int p1; 1965321936Shselasky struct link *l; 1966321936Shselasky struct endpoint *far_end; 1967321936Shselasky struct f_switch *fsw3 = NULL; 1968321936Shselasky 1969321936Shselasky if (!(fsw0 && fsw1 && fsw2)) 1970321936Shselasky goto out; 1971321936Shselasky 1972321936Shselasky /* 1973321936Shselasky * Look at all the ports on the switch, fsw1, that is the base of 1974321936Shselasky * the perpendicular. 1975321936Shselasky */ 1976321936Shselasky for (p1 = 0; p1 < fsw1->port_cnt; p1++) { 1977321936Shselasky /* 1978321936Shselasky * Ignore everything except switch links that haven't 1979321936Shselasky * been installed into the torus. 1980321936Shselasky */ 1981321936Shselasky if (!(fsw1->port[p1] && fsw1->port[p1]->sw && 1982321936Shselasky fsw1->port[p1]->type == PASSTHRU)) 1983321936Shselasky continue; 1984321936Shselasky 1985321936Shselasky l = fsw1->port[p1]->link; 1986321936Shselasky 1987321936Shselasky if (l->end[0].n_id == fsw1->n_id) 1988321936Shselasky far_end = &l->end[1]; 1989321936Shselasky else 1990321936Shselasky far_end = &l->end[0]; 1991321936Shselasky /* 1992321936Shselasky * Ignore CAs 1993321936Shselasky */ 1994321936Shselasky if (!(far_end->type == PASSTHRU && far_end->sw)) 1995321936Shselasky continue; 1996321936Shselasky 1997321936Shselasky fsw3 = far_end->sw; 1998321936Shselasky if (fsw3->n_id == fsw2->n_id) /* wrong perpendicular */ 1999321936Shselasky continue; 2000321936Shselasky 2001321936Shselasky if (ffind_face_corner(fsw0, fsw1, fsw3)) 2002321936Shselasky goto out; 2003321936Shselasky } 2004321936Shselasky fsw3 = NULL; 2005321936Shselaskyout: 2006321936Shselasky return fsw3; 2007321936Shselasky} 2008321936Shselasky 2009321936Shselaskystatic 2010321936Shselaskystruct f_switch *tfind_3d_perpendicular(struct t_switch *tsw0, 2011321936Shselasky struct t_switch *tsw1, 2012321936Shselasky struct t_switch *tsw2, 2013321936Shselasky struct t_switch *tsw3) 2014321936Shselasky{ 2015321936Shselasky if (!(tsw0 && tsw1 && tsw2 && tsw3)) 2016321936Shselasky return NULL; 2017321936Shselasky 2018321936Shselasky return ffind_3d_perpendicular(tsw0->tmp, tsw1->tmp, 2019321936Shselasky tsw2->tmp, tsw3->tmp); 2020321936Shselasky} 2021321936Shselasky 2022321936Shselaskystatic 2023321936Shselaskystruct f_switch *tfind_2d_perpendicular(struct t_switch *tsw0, 2024321936Shselasky struct t_switch *tsw1, 2025321936Shselasky struct t_switch *tsw2) 2026321936Shselasky{ 2027321936Shselasky if (!(tsw0 && tsw1 && tsw2)) 2028321936Shselasky return NULL; 2029321936Shselasky 2030321936Shselasky return ffind_2d_perpendicular(tsw0->tmp, tsw1->tmp, tsw2->tmp); 2031321936Shselasky} 2032321936Shselasky 2033321936Shselaskystatic 2034321936Shselaskybool safe_x_ring(struct torus *t, int i, int j, int k) 2035321936Shselasky{ 2036321936Shselasky int im1, ip1, ip2; 2037321936Shselasky bool success = true; 2038321936Shselasky 2039321936Shselasky /* 2040321936Shselasky * If this x-direction radix-4 ring has at least two links 2041321936Shselasky * already installed into the torus, then this ring does not 2042321936Shselasky * prevent us from looking for y or z direction perpendiculars. 2043321936Shselasky * 2044321936Shselasky * It is easier to check for the appropriate switches being installed 2045321936Shselasky * into the torus than it is to check for the links, so force the 2046321936Shselasky * link installation if the appropriate switches are installed. 2047321936Shselasky * 2048321936Shselasky * Recall that canonicalize(n - 2, 4) == canonicalize(n + 2, 4). 2049321936Shselasky */ 2050321936Shselasky if (t->x_sz != 4 || t->flags & X_MESH) 2051321936Shselasky goto out; 2052321936Shselasky 2053321936Shselasky im1 = canonicalize(i - 1, t->x_sz); 2054321936Shselasky ip1 = canonicalize(i + 1, t->x_sz); 2055321936Shselasky ip2 = canonicalize(i + 2, t->x_sz); 2056321936Shselasky 2057321936Shselasky if (!!t->sw[im1][j][k] + 2058321936Shselasky !!t->sw[ip1][j][k] + !!t->sw[ip2][j][k] < 2) { 2059321936Shselasky success = false; 2060321936Shselasky goto out; 2061321936Shselasky } 2062321936Shselasky if (t->sw[ip2][j][k] && t->sw[im1][j][k]) 2063321936Shselasky success = link_tswitches(t, 0, 2064321936Shselasky t->sw[ip2][j][k], 2065321936Shselasky t->sw[im1][j][k]) 2066321936Shselasky && success; 2067321936Shselasky 2068321936Shselasky if (t->sw[im1][j][k] && t->sw[i][j][k]) 2069321936Shselasky success = link_tswitches(t, 0, 2070321936Shselasky t->sw[im1][j][k], 2071321936Shselasky t->sw[i][j][k]) 2072321936Shselasky && success; 2073321936Shselasky 2074321936Shselasky if (t->sw[i][j][k] && t->sw[ip1][j][k]) 2075321936Shselasky success = link_tswitches(t, 0, 2076321936Shselasky t->sw[i][j][k], 2077321936Shselasky t->sw[ip1][j][k]) 2078321936Shselasky && success; 2079321936Shselasky 2080321936Shselasky if (t->sw[ip1][j][k] && t->sw[ip2][j][k]) 2081321936Shselasky success = link_tswitches(t, 0, 2082321936Shselasky t->sw[ip1][j][k], 2083321936Shselasky t->sw[ip2][j][k]) 2084321936Shselasky && success; 2085321936Shselaskyout: 2086321936Shselasky return success; 2087321936Shselasky} 2088321936Shselasky 2089321936Shselaskystatic 2090321936Shselaskybool safe_y_ring(struct torus *t, int i, int j, int k) 2091321936Shselasky{ 2092321936Shselasky int jm1, jp1, jp2; 2093321936Shselasky bool success = true; 2094321936Shselasky 2095321936Shselasky /* 2096321936Shselasky * If this y-direction radix-4 ring has at least two links 2097321936Shselasky * already installed into the torus, then this ring does not 2098321936Shselasky * prevent us from looking for x or z direction perpendiculars. 2099321936Shselasky * 2100321936Shselasky * It is easier to check for the appropriate switches being installed 2101321936Shselasky * into the torus than it is to check for the links, so force the 2102321936Shselasky * link installation if the appropriate switches are installed. 2103321936Shselasky * 2104321936Shselasky * Recall that canonicalize(n - 2, 4) == canonicalize(n + 2, 4). 2105321936Shselasky */ 2106321936Shselasky if (t->y_sz != 4 || (t->flags & Y_MESH)) 2107321936Shselasky goto out; 2108321936Shselasky 2109321936Shselasky jm1 = canonicalize(j - 1, t->y_sz); 2110321936Shselasky jp1 = canonicalize(j + 1, t->y_sz); 2111321936Shselasky jp2 = canonicalize(j + 2, t->y_sz); 2112321936Shselasky 2113321936Shselasky if (!!t->sw[i][jm1][k] + 2114321936Shselasky !!t->sw[i][jp1][k] + !!t->sw[i][jp2][k] < 2) { 2115321936Shselasky success = false; 2116321936Shselasky goto out; 2117321936Shselasky } 2118321936Shselasky if (t->sw[i][jp2][k] && t->sw[i][jm1][k]) 2119321936Shselasky success = link_tswitches(t, 1, 2120321936Shselasky t->sw[i][jp2][k], 2121321936Shselasky t->sw[i][jm1][k]) 2122321936Shselasky && success; 2123321936Shselasky 2124321936Shselasky if (t->sw[i][jm1][k] && t->sw[i][j][k]) 2125321936Shselasky success = link_tswitches(t, 1, 2126321936Shselasky t->sw[i][jm1][k], 2127321936Shselasky t->sw[i][j][k]) 2128321936Shselasky && success; 2129321936Shselasky 2130321936Shselasky if (t->sw[i][j][k] && t->sw[i][jp1][k]) 2131321936Shselasky success = link_tswitches(t, 1, 2132321936Shselasky t->sw[i][j][k], 2133321936Shselasky t->sw[i][jp1][k]) 2134321936Shselasky && success; 2135321936Shselasky 2136321936Shselasky if (t->sw[i][jp1][k] && t->sw[i][jp2][k]) 2137321936Shselasky success = link_tswitches(t, 1, 2138321936Shselasky t->sw[i][jp1][k], 2139321936Shselasky t->sw[i][jp2][k]) 2140321936Shselasky && success; 2141321936Shselaskyout: 2142321936Shselasky return success; 2143321936Shselasky} 2144321936Shselasky 2145321936Shselaskystatic 2146321936Shselaskybool safe_z_ring(struct torus *t, int i, int j, int k) 2147321936Shselasky{ 2148321936Shselasky int km1, kp1, kp2; 2149321936Shselasky bool success = true; 2150321936Shselasky 2151321936Shselasky /* 2152321936Shselasky * If this z-direction radix-4 ring has at least two links 2153321936Shselasky * already installed into the torus, then this ring does not 2154321936Shselasky * prevent us from looking for x or y direction perpendiculars. 2155321936Shselasky * 2156321936Shselasky * It is easier to check for the appropriate switches being installed 2157321936Shselasky * into the torus than it is to check for the links, so force the 2158321936Shselasky * link installation if the appropriate switches are installed. 2159321936Shselasky * 2160321936Shselasky * Recall that canonicalize(n - 2, 4) == canonicalize(n + 2, 4). 2161321936Shselasky */ 2162321936Shselasky if (t->z_sz != 4 || t->flags & Z_MESH) 2163321936Shselasky goto out; 2164321936Shselasky 2165321936Shselasky km1 = canonicalize(k - 1, t->z_sz); 2166321936Shselasky kp1 = canonicalize(k + 1, t->z_sz); 2167321936Shselasky kp2 = canonicalize(k + 2, t->z_sz); 2168321936Shselasky 2169321936Shselasky if (!!t->sw[i][j][km1] + 2170321936Shselasky !!t->sw[i][j][kp1] + !!t->sw[i][j][kp2] < 2) { 2171321936Shselasky success = false; 2172321936Shselasky goto out; 2173321936Shselasky } 2174321936Shselasky if (t->sw[i][j][kp2] && t->sw[i][j][km1]) 2175321936Shselasky success = link_tswitches(t, 2, 2176321936Shselasky t->sw[i][j][kp2], 2177321936Shselasky t->sw[i][j][km1]) 2178321936Shselasky && success; 2179321936Shselasky 2180321936Shselasky if (t->sw[i][j][km1] && t->sw[i][j][k]) 2181321936Shselasky success = link_tswitches(t, 2, 2182321936Shselasky t->sw[i][j][km1], 2183321936Shselasky t->sw[i][j][k]) 2184321936Shselasky && success; 2185321936Shselasky 2186321936Shselasky if (t->sw[i][j][k] && t->sw[i][j][kp1]) 2187321936Shselasky success = link_tswitches(t, 2, 2188321936Shselasky t->sw[i][j][k], 2189321936Shselasky t->sw[i][j][kp1]) 2190321936Shselasky && success; 2191321936Shselasky 2192321936Shselasky if (t->sw[i][j][kp1] && t->sw[i][j][kp2]) 2193321936Shselasky success = link_tswitches(t, 2, 2194321936Shselasky t->sw[i][j][kp1], 2195321936Shselasky t->sw[i][j][kp2]) 2196321936Shselasky && success; 2197321936Shselaskyout: 2198321936Shselasky return success; 2199321936Shselasky} 2200321936Shselasky 2201321936Shselasky/* 2202321936Shselasky * These functions return true when it safe to call 2203321936Shselasky * tfind_3d_perpendicular()/ffind_3d_perpendicular(). 2204321936Shselasky */ 2205321936Shselaskystatic 2206321936Shselaskybool safe_x_perpendicular(struct torus *t, int i, int j, int k) 2207321936Shselasky{ 2208321936Shselasky /* 2209321936Shselasky * If the dimensions perpendicular to the search direction are 2210321936Shselasky * not radix 4 torus dimensions, it is always safe to search for 2211321936Shselasky * a perpendicular. 2212321936Shselasky * 2213321936Shselasky * Here we are checking for enough appropriate links having been 2214321936Shselasky * installed into the torus to prevent an incorrect link from being 2215321936Shselasky * considered as a perpendicular candidate. 2216321936Shselasky */ 2217321936Shselasky return safe_y_ring(t, i, j, k) && safe_z_ring(t, i, j, k); 2218321936Shselasky} 2219321936Shselasky 2220321936Shselaskystatic 2221321936Shselaskybool safe_y_perpendicular(struct torus *t, int i, int j, int k) 2222321936Shselasky{ 2223321936Shselasky /* 2224321936Shselasky * If the dimensions perpendicular to the search direction are 2225321936Shselasky * not radix 4 torus dimensions, it is always safe to search for 2226321936Shselasky * a perpendicular. 2227321936Shselasky * 2228321936Shselasky * Here we are checking for enough appropriate links having been 2229321936Shselasky * installed into the torus to prevent an incorrect link from being 2230321936Shselasky * considered as a perpendicular candidate. 2231321936Shselasky */ 2232321936Shselasky return safe_x_ring(t, i, j, k) && safe_z_ring(t, i, j, k); 2233321936Shselasky} 2234321936Shselasky 2235321936Shselaskystatic 2236321936Shselaskybool safe_z_perpendicular(struct torus *t, int i, int j, int k) 2237321936Shselasky{ 2238321936Shselasky /* 2239321936Shselasky * If the dimensions perpendicular to the search direction are 2240321936Shselasky * not radix 4 torus dimensions, it is always safe to search for 2241321936Shselasky * a perpendicular. 2242321936Shselasky * 2243321936Shselasky * Implement this by checking for enough appropriate links having 2244321936Shselasky * been installed into the torus to prevent an incorrect link from 2245321936Shselasky * being considered as a perpendicular candidate. 2246321936Shselasky */ 2247321936Shselasky return safe_x_ring(t, i, j, k) && safe_y_ring(t, i, j, k); 2248321936Shselasky} 2249321936Shselasky 2250321936Shselasky/* 2251321936Shselasky * Templates for determining 2D/3D case fingerprints. Recall that if 2252321936Shselasky * a fingerprint bit is set the corresponding switch is absent from 2253321936Shselasky * the all-switches-present template. 2254321936Shselasky * 2255321936Shselasky * I.e., for the 2D case where the x,y dimensions have a radix greater 2256321936Shselasky * than one, and the z dimension has radix 1, fingerprint bits 4-7 are 2257321936Shselasky * always zero. 2258321936Shselasky * 2259321936Shselasky * For the 2D case where the x,z dimensions have a radix greater than 2260321936Shselasky * one, and the y dimension has radix 1, fingerprint bits 2,3,6,7 are 2261321936Shselasky * always zero. 2262321936Shselasky * 2263321936Shselasky * For the 2D case where the y,z dimensions have a radix greater than 2264321936Shselasky * one, and the x dimension has radix 1, fingerprint bits 1,3,5,7 are 2265321936Shselasky * always zero. 2266321936Shselasky * 2267321936Shselasky * Recall also that bits 8-10 distinguish between 2D and 3D cases. 2268321936Shselasky * If bit 8+d is set, for 0 <= d < 3; the d dimension of the desired 2269321936Shselasky * torus has radix greater than 1. 2270321936Shselasky */ 2271321936Shselasky 2272321936Shselasky/* 2273321936Shselasky * 2D case 0x300 2274321936Shselasky * b0: t->sw[i ][j ][0 ] 2275321936Shselasky * b1: t->sw[i+1][j ][0 ] 2276321936Shselasky * b2: t->sw[i ][j+1][0 ] 2277321936Shselasky * b3: t->sw[i+1][j+1][0 ] 2278321936Shselasky * O . . . . . O 2279321936Shselasky * 2D case 0x500 . . 2280321936Shselasky * b0: t->sw[i ][0 ][k ] . . 2281321936Shselasky * b1: t->sw[i+1][0 ][k ] . . 2282321936Shselasky * b4: t->sw[i ][0 ][k+1] . . 2283321936Shselasky * b5: t->sw[i+1][0 ][k+1] . . 2284321936Shselasky * @ . . . . . O 2285321936Shselasky * 2D case 0x600 2286321936Shselasky * b0: t->sw[0 ][j ][k ] 2287321936Shselasky * b2: t->sw[0 ][j+1][k ] 2288321936Shselasky * b4: t->sw[0 ][j ][k+1] 2289321936Shselasky * b6: t->sw[0 ][j+1][k+1] 2290321936Shselasky */ 2291321936Shselasky 2292321936Shselasky/* 2293321936Shselasky * 3D case 0x700: O 2294321936Shselasky * . . . 2295321936Shselasky * b0: t->sw[i ][j ][k ] . . . 2296321936Shselasky * b1: t->sw[i+1][j ][k ] . . . 2297321936Shselasky * b2: t->sw[i ][j+1][k ] . . . 2298321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 2299321936Shselasky * b4: t->sw[i ][j ][k+1] . . O . . 2300321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . . . . 2301321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . . 2302321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . . . . 2303321936Shselasky * . . O . . 2304321936Shselasky * O . O 2305321936Shselasky * . . . 2306321936Shselasky * . . . 2307321936Shselasky * . . . 2308321936Shselasky * . . . 2309321936Shselasky * @ 2310321936Shselasky */ 2311321936Shselasky 2312321936Shselaskystatic 2313321936Shselaskyvoid log_no_crnr(struct torus *t, unsigned n, 2314321936Shselasky int case_i, int case_j, int case_k, 2315321936Shselasky int crnr_i, int crnr_j, int crnr_k) 2316321936Shselasky{ 2317321936Shselasky if (t->debug) 2318321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, "Case 0x%03x " 2319321936Shselasky "@ %d %d %d: no corner @ %d %d %d\n", 2320321936Shselasky n, case_i, case_j, case_k, crnr_i, crnr_j, crnr_k); 2321321936Shselasky} 2322321936Shselasky 2323321936Shselaskystatic 2324321936Shselaskyvoid log_no_perp(struct torus *t, unsigned n, 2325321936Shselasky int case_i, int case_j, int case_k, 2326321936Shselasky int perp_i, int perp_j, int perp_k) 2327321936Shselasky{ 2328321936Shselasky if (t->debug) 2329321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, "Case 0x%03x " 2330321936Shselasky "@ %d %d %d: no perpendicular @ %d %d %d\n", 2331321936Shselasky n, case_i, case_j, case_k, perp_i, perp_j, perp_k); 2332321936Shselasky} 2333321936Shselasky 2334321936Shselasky/* 2335321936Shselasky * Handle the 2D cases with a single existing edge. 2336321936Shselasky * 2337321936Shselasky */ 2338321936Shselasky 2339321936Shselasky/* 2340321936Shselasky * 2D case 0x30c 2341321936Shselasky * b0: t->sw[i ][j ][0 ] 2342321936Shselasky * b1: t->sw[i+1][j ][0 ] 2343321936Shselasky * b2: 2344321936Shselasky * b3: 2345321936Shselasky * O O 2346321936Shselasky * 2D case 0x530 2347321936Shselasky * b0: t->sw[i ][0 ][k ] 2348321936Shselasky * b1: t->sw[i+1][0 ][k ] 2349321936Shselasky * b4: 2350321936Shselasky * b5: 2351321936Shselasky * @ . . . . . O 2352321936Shselasky * 2D case 0x650 2353321936Shselasky * b0: t->sw[0 ][j ][k ] 2354321936Shselasky * b2: t->sw[0 ][j+1][k ] 2355321936Shselasky * b4: 2356321936Shselasky * b6: 2357321936Shselasky */ 2358321936Shselaskystatic 2359321936Shselaskybool handle_case_0x30c(struct torus *t, int i, int j, int k) 2360321936Shselasky{ 2361321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2362321936Shselasky int jm1 = canonicalize(j - 1, t->y_sz); 2363321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 2364321936Shselasky 2365321936Shselasky if (safe_y_perpendicular(t, i, j, k) && 2366321936Shselasky install_tswitch(t, i, jp1, k, 2367321936Shselasky tfind_2d_perpendicular(t->sw[ip1][j][k], 2368321936Shselasky t->sw[i][j][k], 2369321936Shselasky t->sw[i][jm1][k]))) { 2370321936Shselasky return true; 2371321936Shselasky } 2372321936Shselasky log_no_perp(t, 0x30c, i, j, k, i, j, k); 2373321936Shselasky 2374321936Shselasky if (safe_y_perpendicular(t, ip1, j, k) && 2375321936Shselasky install_tswitch(t, ip1, jp1, k, 2376321936Shselasky tfind_2d_perpendicular(t->sw[i][j][k], 2377321936Shselasky t->sw[ip1][j][k], 2378321936Shselasky t->sw[ip1][jm1][k]))) { 2379321936Shselasky return true; 2380321936Shselasky } 2381321936Shselasky log_no_perp(t, 0x30c, i, j, k, ip1, j, k); 2382321936Shselasky return false; 2383321936Shselasky} 2384321936Shselasky 2385321936Shselaskystatic 2386321936Shselaskybool handle_case_0x530(struct torus *t, int i, int j, int k) 2387321936Shselasky{ 2388321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2389321936Shselasky int km1 = canonicalize(k - 1, t->z_sz); 2390321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 2391321936Shselasky 2392321936Shselasky if (safe_z_perpendicular(t, i, j, k) && 2393321936Shselasky install_tswitch(t, i, j, kp1, 2394321936Shselasky tfind_2d_perpendicular(t->sw[ip1][j][k], 2395321936Shselasky t->sw[i][j][k], 2396321936Shselasky t->sw[i][j][km1]))) { 2397321936Shselasky return true; 2398321936Shselasky } 2399321936Shselasky log_no_perp(t, 0x530, i, j, k, i, j, k); 2400321936Shselasky 2401321936Shselasky if (safe_z_perpendicular(t, ip1, j, k) && 2402321936Shselasky install_tswitch(t, ip1, j, kp1, 2403321936Shselasky tfind_2d_perpendicular(t->sw[i][j][k], 2404321936Shselasky t->sw[ip1][j][k], 2405321936Shselasky t->sw[ip1][j][km1]))) { 2406321936Shselasky return true; 2407321936Shselasky } 2408321936Shselasky log_no_perp(t, 0x530, i, j, k, ip1, j, k); 2409321936Shselasky return false; 2410321936Shselasky} 2411321936Shselasky 2412321936Shselaskystatic 2413321936Shselaskybool handle_case_0x650(struct torus *t, int i, int j, int k) 2414321936Shselasky{ 2415321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 2416321936Shselasky int km1 = canonicalize(k - 1, t->z_sz); 2417321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 2418321936Shselasky 2419321936Shselasky if (safe_z_perpendicular(t, i, j, k) && 2420321936Shselasky install_tswitch(t, i, j, kp1, 2421321936Shselasky tfind_2d_perpendicular(t->sw[i][jp1][k], 2422321936Shselasky t->sw[i][j][k], 2423321936Shselasky t->sw[i][j][km1]))) { 2424321936Shselasky return true; 2425321936Shselasky } 2426321936Shselasky log_no_perp(t, 0x650, i, j, k, i, j, k); 2427321936Shselasky 2428321936Shselasky if (safe_z_perpendicular(t, i, jp1, k) && 2429321936Shselasky install_tswitch(t, i, jp1, kp1, 2430321936Shselasky tfind_2d_perpendicular(t->sw[i][j][k], 2431321936Shselasky t->sw[i][jp1][k], 2432321936Shselasky t->sw[i][jp1][km1]))) { 2433321936Shselasky return true; 2434321936Shselasky } 2435321936Shselasky log_no_perp(t, 0x650, i, j, k, i, jp1, k); 2436321936Shselasky return false; 2437321936Shselasky} 2438321936Shselasky 2439321936Shselasky/* 2440321936Shselasky * 2D case 0x305 2441321936Shselasky * b0: 2442321936Shselasky * b1: t->sw[i+1][j ][0 ] 2443321936Shselasky * b2: 2444321936Shselasky * b3: t->sw[i+1][j+1][0 ] 2445321936Shselasky * O O 2446321936Shselasky * 2D case 0x511 . 2447321936Shselasky * b0: . 2448321936Shselasky * b1: t->sw[i+1][0 ][k ] . 2449321936Shselasky * b4: . 2450321936Shselasky * b5: t->sw[i+1][0 ][k+1] . 2451321936Shselasky * @ O 2452321936Shselasky * 2D case 0x611 2453321936Shselasky * b0: 2454321936Shselasky * b2: t->sw[0 ][j+1][k ] 2455321936Shselasky * b4: 2456321936Shselasky * b6: t->sw[0 ][j+1][k+1] 2457321936Shselasky */ 2458321936Shselaskystatic 2459321936Shselaskybool handle_case_0x305(struct torus *t, int i, int j, int k) 2460321936Shselasky{ 2461321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2462321936Shselasky int ip2 = canonicalize(i + 2, t->x_sz); 2463321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 2464321936Shselasky 2465321936Shselasky if (safe_x_perpendicular(t, ip1, j, k) && 2466321936Shselasky install_tswitch(t, i, j, k, 2467321936Shselasky tfind_2d_perpendicular(t->sw[ip1][jp1][k], 2468321936Shselasky t->sw[ip1][j][k], 2469321936Shselasky t->sw[ip2][j][k]))) { 2470321936Shselasky return true; 2471321936Shselasky } 2472321936Shselasky log_no_perp(t, 0x305, i, j, k, ip1, j, k); 2473321936Shselasky 2474321936Shselasky if (safe_x_perpendicular(t, ip1, jp1, k) && 2475321936Shselasky install_tswitch(t, i, jp1, k, 2476321936Shselasky tfind_2d_perpendicular(t->sw[ip1][j][k], 2477321936Shselasky t->sw[ip1][jp1][k], 2478321936Shselasky t->sw[ip2][jp1][k]))) { 2479321936Shselasky return true; 2480321936Shselasky } 2481321936Shselasky log_no_perp(t, 0x305, i, j, k, ip1, jp1, k); 2482321936Shselasky return false; 2483321936Shselasky} 2484321936Shselasky 2485321936Shselaskystatic 2486321936Shselaskybool handle_case_0x511(struct torus *t, int i, int j, int k) 2487321936Shselasky{ 2488321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2489321936Shselasky int ip2 = canonicalize(i + 2, t->x_sz); 2490321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 2491321936Shselasky 2492321936Shselasky if (safe_x_perpendicular(t, ip1, j, k) && 2493321936Shselasky install_tswitch(t, i, j, k, 2494321936Shselasky tfind_2d_perpendicular(t->sw[ip1][j][kp1], 2495321936Shselasky t->sw[ip1][j][k], 2496321936Shselasky t->sw[ip2][j][k]))) { 2497321936Shselasky return true; 2498321936Shselasky } 2499321936Shselasky log_no_perp(t, 0x511, i, j, k, ip1, j, k); 2500321936Shselasky 2501321936Shselasky if (safe_x_perpendicular(t, ip1, j, kp1) && 2502321936Shselasky install_tswitch(t, i, j, kp1, 2503321936Shselasky tfind_2d_perpendicular(t->sw[ip1][j][k], 2504321936Shselasky t->sw[ip1][j][kp1], 2505321936Shselasky t->sw[ip2][j][kp1]))) { 2506321936Shselasky return true; 2507321936Shselasky } 2508321936Shselasky log_no_perp(t, 0x511, i, j, k, ip1, j, kp1); 2509321936Shselasky return false; 2510321936Shselasky} 2511321936Shselasky 2512321936Shselaskystatic 2513321936Shselaskybool handle_case_0x611(struct torus *t, int i, int j, int k) 2514321936Shselasky{ 2515321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 2516321936Shselasky int jp2 = canonicalize(j + 2, t->y_sz); 2517321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 2518321936Shselasky 2519321936Shselasky if (safe_y_perpendicular(t, i, jp1, k) && 2520321936Shselasky install_tswitch(t, i, j, k, 2521321936Shselasky tfind_2d_perpendicular(t->sw[i][jp1][kp1], 2522321936Shselasky t->sw[i][jp1][k], 2523321936Shselasky t->sw[i][jp2][k]))) { 2524321936Shselasky return true; 2525321936Shselasky } 2526321936Shselasky log_no_perp(t, 0x611, i, j, k, i, jp1, k); 2527321936Shselasky 2528321936Shselasky if (safe_y_perpendicular(t, i, jp1, kp1) && 2529321936Shselasky install_tswitch(t, i, j, kp1, 2530321936Shselasky tfind_2d_perpendicular(t->sw[i][jp1][k], 2531321936Shselasky t->sw[i][jp1][kp1], 2532321936Shselasky t->sw[i][jp2][kp1]))) { 2533321936Shselasky return true; 2534321936Shselasky } 2535321936Shselasky log_no_perp(t, 0x611, i, j, k, i, jp1, kp1); 2536321936Shselasky return false; 2537321936Shselasky} 2538321936Shselasky 2539321936Shselasky/* 2540321936Shselasky * 2D case 0x303 2541321936Shselasky * b0: 2542321936Shselasky * b1: 2543321936Shselasky * b2: t->sw[i ][j+1][0 ] 2544321936Shselasky * b3: t->sw[i+1][j+1][0 ] 2545321936Shselasky * O . . . . . O 2546321936Shselasky * 2D case 0x503 2547321936Shselasky * b0: 2548321936Shselasky * b1: 2549321936Shselasky * b4: t->sw[i ][0 ][k+1] 2550321936Shselasky * b5: t->sw[i+1][0 ][k+1] 2551321936Shselasky * @ O 2552321936Shselasky * 2D case 0x605 2553321936Shselasky * b0: 2554321936Shselasky * b2: 2555321936Shselasky * b4: t->sw[0 ][j ][k+1] 2556321936Shselasky * b6: t->sw[0 ][j+1][k+1] 2557321936Shselasky */ 2558321936Shselaskystatic 2559321936Shselaskybool handle_case_0x303(struct torus *t, int i, int j, int k) 2560321936Shselasky{ 2561321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2562321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 2563321936Shselasky int jp2 = canonicalize(j + 2, t->y_sz); 2564321936Shselasky 2565321936Shselasky if (safe_y_perpendicular(t, i, jp1, k) && 2566321936Shselasky install_tswitch(t, i, j, k, 2567321936Shselasky tfind_2d_perpendicular(t->sw[ip1][jp1][k], 2568321936Shselasky t->sw[i][jp1][k], 2569321936Shselasky t->sw[i][jp2][k]))) { 2570321936Shselasky return true; 2571321936Shselasky } 2572321936Shselasky log_no_perp(t, 0x303, i, j, k, i, jp1, k); 2573321936Shselasky 2574321936Shselasky if (safe_y_perpendicular(t, ip1, jp1, k) && 2575321936Shselasky install_tswitch(t, ip1, j, k, 2576321936Shselasky tfind_2d_perpendicular(t->sw[i][jp1][k], 2577321936Shselasky t->sw[ip1][jp1][k], 2578321936Shselasky t->sw[ip1][jp2][k]))) { 2579321936Shselasky return true; 2580321936Shselasky } 2581321936Shselasky log_no_perp(t, 0x303, i, j, k, ip1, jp1, k); 2582321936Shselasky return false; 2583321936Shselasky} 2584321936Shselasky 2585321936Shselaskystatic 2586321936Shselaskybool handle_case_0x503(struct torus *t, int i, int j, int k) 2587321936Shselasky{ 2588321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2589321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 2590321936Shselasky int kp2 = canonicalize(k + 2, t->z_sz); 2591321936Shselasky 2592321936Shselasky if (safe_z_perpendicular(t, i, j, kp1) && 2593321936Shselasky install_tswitch(t, i, j, k, 2594321936Shselasky tfind_2d_perpendicular(t->sw[ip1][j][kp1], 2595321936Shselasky t->sw[i][j][kp1], 2596321936Shselasky t->sw[i][j][kp2]))) { 2597321936Shselasky return true; 2598321936Shselasky } 2599321936Shselasky log_no_perp(t, 0x503, i, j, k, i, j, kp1); 2600321936Shselasky 2601321936Shselasky if (safe_z_perpendicular(t, ip1, j, kp1) && 2602321936Shselasky install_tswitch(t, ip1, j, k, 2603321936Shselasky tfind_2d_perpendicular(t->sw[i][j][kp1], 2604321936Shselasky t->sw[ip1][j][kp1], 2605321936Shselasky t->sw[ip1][j][kp2]))) { 2606321936Shselasky return true; 2607321936Shselasky } 2608321936Shselasky log_no_perp(t, 0x503, i, j, k, ip1, j, kp1); 2609321936Shselasky return false; 2610321936Shselasky} 2611321936Shselasky 2612321936Shselaskystatic 2613321936Shselaskybool handle_case_0x605(struct torus *t, int i, int j, int k) 2614321936Shselasky{ 2615321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 2616321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 2617321936Shselasky int kp2 = canonicalize(k + 2, t->z_sz); 2618321936Shselasky 2619321936Shselasky if (safe_z_perpendicular(t, i, j, kp1) && 2620321936Shselasky install_tswitch(t, i, j, k, 2621321936Shselasky tfind_2d_perpendicular(t->sw[i][jp1][kp1], 2622321936Shselasky t->sw[i][j][kp1], 2623321936Shselasky t->sw[i][j][kp2]))) { 2624321936Shselasky return true; 2625321936Shselasky } 2626321936Shselasky log_no_perp(t, 0x605, i, j, k, i, j, kp1); 2627321936Shselasky 2628321936Shselasky if (safe_z_perpendicular(t, i, jp1, kp1) && 2629321936Shselasky install_tswitch(t, i, jp1, k, 2630321936Shselasky tfind_2d_perpendicular(t->sw[i][j][kp1], 2631321936Shselasky t->sw[i][jp1][kp1], 2632321936Shselasky t->sw[i][jp1][kp2]))) { 2633321936Shselasky return true; 2634321936Shselasky } 2635321936Shselasky log_no_perp(t, 0x605, i, j, k, i, jp1, kp1); 2636321936Shselasky return false; 2637321936Shselasky} 2638321936Shselasky 2639321936Shselasky/* 2640321936Shselasky * 2D case 0x30a 2641321936Shselasky * b0: t->sw[i ][j ][0 ] 2642321936Shselasky * b1: 2643321936Shselasky * b2: t->sw[i ][j+1][0 ] 2644321936Shselasky * b3: 2645321936Shselasky * O O 2646321936Shselasky * 2D case 0x522 . 2647321936Shselasky * b0: t->sw[i ][0 ][k ] . 2648321936Shselasky * b1: . 2649321936Shselasky * b4: t->sw[i ][0 ][k+1] . 2650321936Shselasky * b5: . 2651321936Shselasky * @ O 2652321936Shselasky * 2D case 0x644 2653321936Shselasky * b0: t->sw[0 ][j ][k ] 2654321936Shselasky * b2: 2655321936Shselasky * b4: t->sw[0 ][j ][k+1] 2656321936Shselasky * b6: 2657321936Shselasky */ 2658321936Shselaskystatic 2659321936Shselaskybool handle_case_0x30a(struct torus *t, int i, int j, int k) 2660321936Shselasky{ 2661321936Shselasky int im1 = canonicalize(i - 1, t->x_sz); 2662321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2663321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 2664321936Shselasky 2665321936Shselasky if (safe_x_perpendicular(t, i, j, k) && 2666321936Shselasky install_tswitch(t, ip1, j, k, 2667321936Shselasky tfind_2d_perpendicular(t->sw[i][jp1][k], 2668321936Shselasky t->sw[i][j][k], 2669321936Shselasky t->sw[im1][j][k]))) { 2670321936Shselasky return true; 2671321936Shselasky } 2672321936Shselasky log_no_perp(t, 0x30a, i, j, k, i, j, k); 2673321936Shselasky 2674321936Shselasky if (safe_x_perpendicular(t, i, jp1, k) && 2675321936Shselasky install_tswitch(t, ip1, jp1, k, 2676321936Shselasky tfind_2d_perpendicular(t->sw[i][j][k], 2677321936Shselasky t->sw[i][jp1][k], 2678321936Shselasky t->sw[im1][jp1][k]))) { 2679321936Shselasky return true; 2680321936Shselasky } 2681321936Shselasky log_no_perp(t, 0x30a, i, j, k, i, jp1, k); 2682321936Shselasky return false; 2683321936Shselasky} 2684321936Shselasky 2685321936Shselaskystatic 2686321936Shselaskybool handle_case_0x522(struct torus *t, int i, int j, int k) 2687321936Shselasky{ 2688321936Shselasky int im1 = canonicalize(i - 1, t->x_sz); 2689321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2690321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 2691321936Shselasky 2692321936Shselasky if (safe_x_perpendicular(t, i, j, k) && 2693321936Shselasky install_tswitch(t, ip1, j, k, 2694321936Shselasky tfind_2d_perpendicular(t->sw[i][j][kp1], 2695321936Shselasky t->sw[i][j][k], 2696321936Shselasky t->sw[im1][j][k]))) { 2697321936Shselasky return true; 2698321936Shselasky } 2699321936Shselasky log_no_perp(t, 0x522, i, j, k, i, j, k); 2700321936Shselasky 2701321936Shselasky if (safe_x_perpendicular(t, i, j, kp1) && 2702321936Shselasky install_tswitch(t, ip1, j, kp1, 2703321936Shselasky tfind_2d_perpendicular(t->sw[i][j][k], 2704321936Shselasky t->sw[i][j][kp1], 2705321936Shselasky t->sw[im1][j][kp1]))) { 2706321936Shselasky return true; 2707321936Shselasky } 2708321936Shselasky log_no_perp(t, 0x522, i, j, k, i, j, kp1); 2709321936Shselasky return false; 2710321936Shselasky} 2711321936Shselasky 2712321936Shselaskystatic 2713321936Shselaskybool handle_case_0x644(struct torus *t, int i, int j, int k) 2714321936Shselasky{ 2715321936Shselasky int jm1 = canonicalize(j - 1, t->y_sz); 2716321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 2717321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 2718321936Shselasky 2719321936Shselasky if (safe_y_perpendicular(t, i, j, k) && 2720321936Shselasky install_tswitch(t, i, jp1, k, 2721321936Shselasky tfind_2d_perpendicular(t->sw[i][j][kp1], 2722321936Shselasky t->sw[i][j][k], 2723321936Shselasky t->sw[i][jm1][k]))) { 2724321936Shselasky return true; 2725321936Shselasky } 2726321936Shselasky log_no_perp(t, 0x644, i, j, k, i, j, k); 2727321936Shselasky 2728321936Shselasky if (safe_y_perpendicular(t, i, j, kp1) && 2729321936Shselasky install_tswitch(t, i, jp1, kp1, 2730321936Shselasky tfind_2d_perpendicular(t->sw[i][j][k], 2731321936Shselasky t->sw[i][j][kp1], 2732321936Shselasky t->sw[i][jm1][kp1]))) { 2733321936Shselasky return true; 2734321936Shselasky } 2735321936Shselasky log_no_perp(t, 0x644, i, j, k, i, j, kp1); 2736321936Shselasky return false; 2737321936Shselasky} 2738321936Shselasky 2739321936Shselasky/* 2740321936Shselasky * Handle the 2D cases where two existing edges meet at a corner. 2741321936Shselasky * 2742321936Shselasky */ 2743321936Shselasky 2744321936Shselasky/* 2745321936Shselasky * 2D case 0x301 2746321936Shselasky * b0: 2747321936Shselasky * b1: t->sw[i+1][j ][0 ] 2748321936Shselasky * b2: t->sw[i ][j+1][0 ] 2749321936Shselasky * b3: t->sw[i+1][j+1][0 ] 2750321936Shselasky * O . . . . . O 2751321936Shselasky * 2D case 0x501 . 2752321936Shselasky * b0: . 2753321936Shselasky * b1: t->sw[i+1][0 ][k ] . 2754321936Shselasky * b4: t->sw[i ][0 ][k+1] . 2755321936Shselasky * b5: t->sw[i+1][0 ][k+1] . 2756321936Shselasky * @ O 2757321936Shselasky * 2D case 0x601 2758321936Shselasky * b0: 2759321936Shselasky * b2: t->sw[0 ][j+1][k ] 2760321936Shselasky * b4: t->sw[0 ][j ][k+1] 2761321936Shselasky * b6: t->sw[0 ][j+1][k+1] 2762321936Shselasky */ 2763321936Shselaskystatic 2764321936Shselaskybool handle_case_0x301(struct torus *t, int i, int j, int k) 2765321936Shselasky{ 2766321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2767321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 2768321936Shselasky 2769321936Shselasky if (install_tswitch(t, i, j, k, 2770321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 2771321936Shselasky t->sw[ip1][jp1][k], 2772321936Shselasky t->sw[i][jp1][k]))) { 2773321936Shselasky return true; 2774321936Shselasky } 2775321936Shselasky log_no_crnr(t, 0x301, i, j, k, i, j, k); 2776321936Shselasky return false; 2777321936Shselasky} 2778321936Shselasky 2779321936Shselaskystatic 2780321936Shselaskybool handle_case_0x501(struct torus *t, int i, int j, int k) 2781321936Shselasky{ 2782321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2783321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 2784321936Shselasky 2785321936Shselasky if (install_tswitch(t, i, j, k, 2786321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 2787321936Shselasky t->sw[ip1][j][kp1], 2788321936Shselasky t->sw[i][j][kp1]))) { 2789321936Shselasky return true; 2790321936Shselasky } 2791321936Shselasky log_no_crnr(t, 0x501, i, j, k, i, j, k); 2792321936Shselasky return false; 2793321936Shselasky} 2794321936Shselasky 2795321936Shselaskystatic 2796321936Shselaskybool handle_case_0x601(struct torus *t, int i, int j, int k) 2797321936Shselasky{ 2798321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 2799321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 2800321936Shselasky 2801321936Shselasky if (install_tswitch(t, i, j, k, 2802321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 2803321936Shselasky t->sw[i][jp1][kp1], 2804321936Shselasky t->sw[i][j][kp1]))) { 2805321936Shselasky return true; 2806321936Shselasky } 2807321936Shselasky log_no_crnr(t, 0x601, i, j, k, i, j, k); 2808321936Shselasky return false; 2809321936Shselasky} 2810321936Shselasky 2811321936Shselasky/* 2812321936Shselasky * 2D case 0x302 2813321936Shselasky * b0: t->sw[i ][j ][0 ] 2814321936Shselasky * b1: 2815321936Shselasky * b2: t->sw[i ][j+1][0 ] 2816321936Shselasky * b3: t->sw[i+1][j+1][0 ] 2817321936Shselasky * O . . . . . O 2818321936Shselasky * 2D case 0x502 . 2819321936Shselasky * b0: t->sw[i ][0 ][k ] . 2820321936Shselasky * b1: . 2821321936Shselasky * b4: t->sw[i ][0 ][k+1] . 2822321936Shselasky * b5: t->sw[i+1][0 ][k+1] . 2823321936Shselasky * @ O 2824321936Shselasky * 2D case 0x604 2825321936Shselasky * b0: t->sw[0 ][j ][k ] 2826321936Shselasky * b2: 2827321936Shselasky * b4: t->sw[0 ][j ][k+1] 2828321936Shselasky * b6: t->sw[0 ][j+1][k+1] 2829321936Shselasky */ 2830321936Shselaskystatic 2831321936Shselaskybool handle_case_0x302(struct torus *t, int i, int j, int k) 2832321936Shselasky{ 2833321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2834321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 2835321936Shselasky 2836321936Shselasky if (install_tswitch(t, ip1, j, k, 2837321936Shselasky tfind_face_corner(t->sw[i][j][k], 2838321936Shselasky t->sw[i][jp1][k], 2839321936Shselasky t->sw[ip1][jp1][k]))) { 2840321936Shselasky return true; 2841321936Shselasky } 2842321936Shselasky log_no_crnr(t, 0x302, i, j, k, ip1, j, k); 2843321936Shselasky return false; 2844321936Shselasky} 2845321936Shselasky 2846321936Shselaskystatic 2847321936Shselaskybool handle_case_0x502(struct torus *t, int i, int j, int k) 2848321936Shselasky{ 2849321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2850321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 2851321936Shselasky 2852321936Shselasky if (install_tswitch(t, ip1, j, k, 2853321936Shselasky tfind_face_corner(t->sw[i][j][k], 2854321936Shselasky t->sw[i][j][kp1], 2855321936Shselasky t->sw[ip1][j][kp1]))) { 2856321936Shselasky return true; 2857321936Shselasky } 2858321936Shselasky log_no_crnr(t, 0x502, i, j, k, ip1, j, k); 2859321936Shselasky return false; 2860321936Shselasky} 2861321936Shselasky 2862321936Shselaskystatic 2863321936Shselaskybool handle_case_0x604(struct torus *t, int i, int j, int k) 2864321936Shselasky{ 2865321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 2866321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 2867321936Shselasky 2868321936Shselasky if (install_tswitch(t, i, jp1, k, 2869321936Shselasky tfind_face_corner(t->sw[i][j][k], 2870321936Shselasky t->sw[i][j][kp1], 2871321936Shselasky t->sw[i][jp1][kp1]))) { 2872321936Shselasky return true; 2873321936Shselasky } 2874321936Shselasky log_no_crnr(t, 0x604, i, j, k, i, jp1, k); 2875321936Shselasky return false; 2876321936Shselasky} 2877321936Shselasky 2878321936Shselasky 2879321936Shselasky/* 2880321936Shselasky * 2D case 0x308 2881321936Shselasky * b0: t->sw[i ][j ][0 ] 2882321936Shselasky * b1: t->sw[i+1][j ][0 ] 2883321936Shselasky * b2: t->sw[i ][j+1][0 ] 2884321936Shselasky * b3: 2885321936Shselasky * O O 2886321936Shselasky * 2D case 0x520 . 2887321936Shselasky * b0: t->sw[i ][0 ][k ] . 2888321936Shselasky * b1: t->sw[i+1][0 ][k ] . 2889321936Shselasky * b4: t->sw[i ][0 ][k+1] . 2890321936Shselasky * b5: . 2891321936Shselasky * @ . . . . . O 2892321936Shselasky * 2D case 0x640 2893321936Shselasky * b0: t->sw[0 ][j ][k ] 2894321936Shselasky * b2: t->sw[0 ][j+1][k ] 2895321936Shselasky * b4: t->sw[0 ][j ][k+1] 2896321936Shselasky * b6: 2897321936Shselasky */ 2898321936Shselaskystatic 2899321936Shselaskybool handle_case_0x308(struct torus *t, int i, int j, int k) 2900321936Shselasky{ 2901321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2902321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 2903321936Shselasky 2904321936Shselasky if (install_tswitch(t, ip1, jp1, k, 2905321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 2906321936Shselasky t->sw[i][j][k], 2907321936Shselasky t->sw[i][jp1][k]))) { 2908321936Shselasky return true; 2909321936Shselasky } 2910321936Shselasky log_no_crnr(t, 0x308, i, j, k, ip1, jp1, k); 2911321936Shselasky return false; 2912321936Shselasky} 2913321936Shselasky 2914321936Shselaskystatic 2915321936Shselaskybool handle_case_0x520(struct torus *t, int i, int j, int k) 2916321936Shselasky{ 2917321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2918321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 2919321936Shselasky 2920321936Shselasky if (install_tswitch(t, ip1, j, kp1, 2921321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 2922321936Shselasky t->sw[i][j][k], 2923321936Shselasky t->sw[i][j][kp1]))) { 2924321936Shselasky return true; 2925321936Shselasky } 2926321936Shselasky log_no_crnr(t, 0x520, i, j, k, ip1, j, kp1); 2927321936Shselasky return false; 2928321936Shselasky} 2929321936Shselasky 2930321936Shselaskystatic 2931321936Shselaskybool handle_case_0x640(struct torus *t, int i, int j, int k) 2932321936Shselasky{ 2933321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 2934321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 2935321936Shselasky 2936321936Shselasky if (install_tswitch(t, i, jp1, kp1, 2937321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 2938321936Shselasky t->sw[i][j][k], 2939321936Shselasky t->sw[i][j][kp1]))) { 2940321936Shselasky return true; 2941321936Shselasky } 2942321936Shselasky log_no_crnr(t, 0x640, i, j, k, i, jp1, kp1); 2943321936Shselasky return false; 2944321936Shselasky} 2945321936Shselasky 2946321936Shselasky/* 2947321936Shselasky * 2D case 0x304 2948321936Shselasky * b0: t->sw[i ][j ][0 ] 2949321936Shselasky * b1: t->sw[i+1][j ][0 ] 2950321936Shselasky * b2: 2951321936Shselasky * b3: t->sw[i+1][j+1][0 ] 2952321936Shselasky * O O 2953321936Shselasky * 2D case 0x510 . 2954321936Shselasky * b0: t->sw[i ][0 ][k ] . 2955321936Shselasky * b1: t->sw[i+1][0 ][k ] . 2956321936Shselasky * b4: . 2957321936Shselasky * b5: t->sw[i+1][0 ][k+1] . 2958321936Shselasky * @ . . . . . O 2959321936Shselasky * 2D case 0x610 2960321936Shselasky * b0: t->sw[0 ][j ][k ] 2961321936Shselasky * b2: t->sw[0 ][j+1][k ] 2962321936Shselasky * b4: 2963321936Shselasky * b6: t->sw[0 ][j+1][k+1] 2964321936Shselasky */ 2965321936Shselaskystatic 2966321936Shselaskybool handle_case_0x304(struct torus *t, int i, int j, int k) 2967321936Shselasky{ 2968321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2969321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 2970321936Shselasky 2971321936Shselasky if (install_tswitch(t, i, jp1, k, 2972321936Shselasky tfind_face_corner(t->sw[i][j][k], 2973321936Shselasky t->sw[ip1][j][k], 2974321936Shselasky t->sw[ip1][jp1][k]))) { 2975321936Shselasky return true; 2976321936Shselasky } 2977321936Shselasky log_no_crnr(t, 0x304, i, j, k, i, jp1, k); 2978321936Shselasky return false; 2979321936Shselasky} 2980321936Shselasky 2981321936Shselaskystatic 2982321936Shselaskybool handle_case_0x510(struct torus *t, int i, int j, int k) 2983321936Shselasky{ 2984321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 2985321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 2986321936Shselasky 2987321936Shselasky if (install_tswitch(t, i, j, kp1, 2988321936Shselasky tfind_face_corner(t->sw[i][j][k], 2989321936Shselasky t->sw[ip1][j][k], 2990321936Shselasky t->sw[ip1][j][kp1]))) { 2991321936Shselasky return true; 2992321936Shselasky } 2993321936Shselasky log_no_crnr(t, 0x510, i, j, k, i, j, kp1); 2994321936Shselasky return false; 2995321936Shselasky} 2996321936Shselasky 2997321936Shselaskystatic 2998321936Shselaskybool handle_case_0x610(struct torus *t, int i, int j, int k) 2999321936Shselasky{ 3000321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3001321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3002321936Shselasky 3003321936Shselasky if (install_tswitch(t, i, j, kp1, 3004321936Shselasky tfind_face_corner(t->sw[i][j][k], 3005321936Shselasky t->sw[i][jp1][k], 3006321936Shselasky t->sw[i][jp1][kp1]))) { 3007321936Shselasky return true; 3008321936Shselasky } 3009321936Shselasky log_no_crnr(t, 0x610, i, j, k, i, j, kp1); 3010321936Shselasky return false; 3011321936Shselasky} 3012321936Shselasky 3013321936Shselasky/* 3014321936Shselasky * Handle the 3D cases where two existing edges meet at a corner. 3015321936Shselasky * 3016321936Shselasky */ 3017321936Shselasky 3018321936Shselasky/* 3019321936Shselasky * 3D case 0x71f: O 3020321936Shselasky * . . 3021321936Shselasky * b0: . . 3022321936Shselasky * b1: . . 3023321936Shselasky * b2: . . 3024321936Shselasky * b3: O O 3025321936Shselasky * b4: O 3026321936Shselasky * b5: t->sw[i+1][j ][k+1] 3027321936Shselasky * b6: t->sw[i ][j+1][k+1] 3028321936Shselasky * b7: t->sw[i+1][j+1][k+1] 3029321936Shselasky * O 3030321936Shselasky * O O 3031321936Shselasky * 3032321936Shselasky * 3033321936Shselasky * 3034321936Shselasky * 3035321936Shselasky * @ 3036321936Shselasky */ 3037321936Shselaskystatic 3038321936Shselaskybool handle_case_0x71f(struct torus *t, int i, int j, int k) 3039321936Shselasky{ 3040321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3041321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3042321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3043321936Shselasky int kp2 = canonicalize(k + 2, t->z_sz); 3044321936Shselasky 3045321936Shselasky if (safe_z_perpendicular(t, ip1, jp1, kp1) && 3046321936Shselasky install_tswitch(t, ip1, jp1, k, 3047321936Shselasky tfind_3d_perpendicular(t->sw[ip1][j][kp1], 3048321936Shselasky t->sw[ip1][jp1][kp1], 3049321936Shselasky t->sw[i][jp1][kp1], 3050321936Shselasky t->sw[ip1][jp1][kp2]))) { 3051321936Shselasky return true; 3052321936Shselasky } 3053321936Shselasky log_no_perp(t, 0x71f, i, j, k, ip1, jp1, kp1); 3054321936Shselasky return false; 3055321936Shselasky} 3056321936Shselasky 3057321936Shselasky/* 3058321936Shselasky * 3D case 0x72f: O 3059321936Shselasky * . 3060321936Shselasky * b0: . 3061321936Shselasky * b1: . 3062321936Shselasky * b2: . 3063321936Shselasky * b3: O O 3064321936Shselasky * b4: t->sw[i ][j ][k+1] . O 3065321936Shselasky * b5: . 3066321936Shselasky * b6: t->sw[i ][j+1][k+1] . 3067321936Shselasky * b7: t->sw[i+1][j+1][k+1] . 3068321936Shselasky * O 3069321936Shselasky * O O 3070321936Shselasky * 3071321936Shselasky * 3072321936Shselasky * 3073321936Shselasky * 3074321936Shselasky * @ 3075321936Shselasky */ 3076321936Shselaskystatic 3077321936Shselaskybool handle_case_0x72f(struct torus *t, int i, int j, int k) 3078321936Shselasky{ 3079321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3080321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3081321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3082321936Shselasky int kp2 = canonicalize(k + 2, t->z_sz); 3083321936Shselasky 3084321936Shselasky if (safe_z_perpendicular(t, i, jp1, kp1) && 3085321936Shselasky install_tswitch(t, i, jp1, k, 3086321936Shselasky tfind_3d_perpendicular(t->sw[i][j][kp1], 3087321936Shselasky t->sw[i][jp1][kp1], 3088321936Shselasky t->sw[ip1][jp1][kp1], 3089321936Shselasky t->sw[i][jp1][kp2]))) { 3090321936Shselasky return true; 3091321936Shselasky } 3092321936Shselasky log_no_perp(t, 0x72f, i, j, k, i, jp1, kp1); 3093321936Shselasky return false; 3094321936Shselasky} 3095321936Shselasky 3096321936Shselasky/* 3097321936Shselasky * 3D case 0x737: O 3098321936Shselasky * . . 3099321936Shselasky * b0: . . 3100321936Shselasky * b1: . . 3101321936Shselasky * b2: . . 3102321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 3103321936Shselasky * b4: O 3104321936Shselasky * b5: 3105321936Shselasky * b6: t->sw[i ][j+1][k+1] 3106321936Shselasky * b7: t->sw[i+1][j+1][k+1] 3107321936Shselasky * O 3108321936Shselasky * O O 3109321936Shselasky * 3110321936Shselasky * 3111321936Shselasky * 3112321936Shselasky * 3113321936Shselasky * @ 3114321936Shselasky */ 3115321936Shselaskystatic 3116321936Shselaskybool handle_case_0x737(struct torus *t, int i, int j, int k) 3117321936Shselasky{ 3118321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3119321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3120321936Shselasky int jp2 = canonicalize(j + 2, t->y_sz); 3121321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3122321936Shselasky 3123321936Shselasky if (safe_y_perpendicular(t, ip1, jp1, kp1) && 3124321936Shselasky install_tswitch(t, ip1, j, kp1, 3125321936Shselasky tfind_3d_perpendicular(t->sw[i][jp1][kp1], 3126321936Shselasky t->sw[ip1][jp1][kp1], 3127321936Shselasky t->sw[ip1][jp1][k], 3128321936Shselasky t->sw[ip1][jp2][kp1]))) { 3129321936Shselasky return true; 3130321936Shselasky } 3131321936Shselasky log_no_perp(t, 0x737, i, j, k, ip1, jp1, kp1); 3132321936Shselasky return false; 3133321936Shselasky} 3134321936Shselasky 3135321936Shselasky/* 3136321936Shselasky * 3D case 0x73b: O 3137321936Shselasky * . 3138321936Shselasky * b0: . 3139321936Shselasky * b1: . 3140321936Shselasky * b2: t->sw[i ][j+1][k ] . 3141321936Shselasky * b3: O O 3142321936Shselasky * b4: . O 3143321936Shselasky * b5: . 3144321936Shselasky * b6: t->sw[i ][j+1][k+1] . 3145321936Shselasky * b7: t->sw[i+1][j+1][k+1] . 3146321936Shselasky * . O 3147321936Shselasky * O O 3148321936Shselasky * 3149321936Shselasky * 3150321936Shselasky * 3151321936Shselasky * 3152321936Shselasky * @ 3153321936Shselasky */ 3154321936Shselaskystatic 3155321936Shselaskybool handle_case_0x73b(struct torus *t, int i, int j, int k) 3156321936Shselasky{ 3157321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3158321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3159321936Shselasky int jp2 = canonicalize(j + 2, t->y_sz); 3160321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3161321936Shselasky 3162321936Shselasky if (safe_y_perpendicular(t, i, jp1, kp1) && 3163321936Shselasky install_tswitch(t, i, j, kp1, 3164321936Shselasky tfind_3d_perpendicular(t->sw[i][jp1][k], 3165321936Shselasky t->sw[i][jp1][kp1], 3166321936Shselasky t->sw[ip1][jp1][kp1], 3167321936Shselasky t->sw[i][jp2][kp1]))) { 3168321936Shselasky return true; 3169321936Shselasky } 3170321936Shselasky log_no_perp(t, 0x73b, i, j, k, i, jp1, kp1); 3171321936Shselasky return false; 3172321936Shselasky} 3173321936Shselasky 3174321936Shselasky/* 3175321936Shselasky * 3D case 0x74f: O 3176321936Shselasky * . 3177321936Shselasky * b0: . 3178321936Shselasky * b1: . 3179321936Shselasky * b2: . 3180321936Shselasky * b3: O O 3181321936Shselasky * b4: t->sw[i ][j ][k+1] O . 3182321936Shselasky * b5: t->sw[i+1][j ][k+1] . 3183321936Shselasky * b6: . 3184321936Shselasky * b7: t->sw[i+1][j+1][k+1] . 3185321936Shselasky * O 3186321936Shselasky * O O 3187321936Shselasky * 3188321936Shselasky * 3189321936Shselasky * 3190321936Shselasky * 3191321936Shselasky * @ 3192321936Shselasky */ 3193321936Shselaskystatic 3194321936Shselaskybool handle_case_0x74f(struct torus *t, int i, int j, int k) 3195321936Shselasky{ 3196321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3197321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3198321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3199321936Shselasky int kp2 = canonicalize(k + 2, t->z_sz); 3200321936Shselasky 3201321936Shselasky if (safe_z_perpendicular(t, ip1, j, kp1) && 3202321936Shselasky install_tswitch(t, ip1, j, k, 3203321936Shselasky tfind_3d_perpendicular(t->sw[i][j][kp1], 3204321936Shselasky t->sw[ip1][j][kp1], 3205321936Shselasky t->sw[ip1][jp1][kp1], 3206321936Shselasky t->sw[ip1][j][kp2]))) { 3207321936Shselasky return true; 3208321936Shselasky } 3209321936Shselasky log_no_perp(t, 0x74f, i, j, k, ip1, j, kp1); 3210321936Shselasky return false; 3211321936Shselasky} 3212321936Shselasky 3213321936Shselasky/* 3214321936Shselasky * 3D case 0x757: O 3215321936Shselasky * . . 3216321936Shselasky * b0: . . 3217321936Shselasky * b1: . . 3218321936Shselasky * b2: . . 3219321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 3220321936Shselasky * b4: O 3221321936Shselasky * b5: t->sw[i+1][j ][k+1] 3222321936Shselasky * b6: 3223321936Shselasky * b7: t->sw[i+1][j+1][k+1] 3224321936Shselasky * O 3225321936Shselasky * O O 3226321936Shselasky * 3227321936Shselasky * 3228321936Shselasky * 3229321936Shselasky * 3230321936Shselasky * @ 3231321936Shselasky */ 3232321936Shselaskystatic 3233321936Shselaskybool handle_case_0x757(struct torus *t, int i, int j, int k) 3234321936Shselasky{ 3235321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3236321936Shselasky int ip2 = canonicalize(i + 2, t->x_sz); 3237321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3238321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3239321936Shselasky 3240321936Shselasky if (safe_x_perpendicular(t, ip1, jp1, kp1) && 3241321936Shselasky install_tswitch(t, i, jp1, kp1, 3242321936Shselasky tfind_3d_perpendicular(t->sw[ip1][j][kp1], 3243321936Shselasky t->sw[ip1][jp1][kp1], 3244321936Shselasky t->sw[ip1][jp1][k], 3245321936Shselasky t->sw[ip2][jp1][kp1]))) { 3246321936Shselasky return true; 3247321936Shselasky } 3248321936Shselasky log_no_perp(t, 0x757, i, j, k, ip1, jp1, kp1); 3249321936Shselasky return false; 3250321936Shselasky} 3251321936Shselasky 3252321936Shselasky/* 3253321936Shselasky * 3D case 0x75d: O 3254321936Shselasky * . 3255321936Shselasky * b0: . 3256321936Shselasky * b1: t->sw[i+1][j ][k ] . 3257321936Shselasky * b2: . 3258321936Shselasky * b3: O O 3259321936Shselasky * b4: O . 3260321936Shselasky * b5: t->sw[i+1][j ][k+1] . 3261321936Shselasky * b6: . 3262321936Shselasky * b7: t->sw[i+1][j+1][k+1] . 3263321936Shselasky * O . 3264321936Shselasky * O O 3265321936Shselasky * 3266321936Shselasky * 3267321936Shselasky * 3268321936Shselasky * 3269321936Shselasky * @ 3270321936Shselasky */ 3271321936Shselaskystatic 3272321936Shselaskybool handle_case_0x75d(struct torus *t, int i, int j, int k) 3273321936Shselasky{ 3274321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3275321936Shselasky int ip2 = canonicalize(i + 2, t->x_sz); 3276321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3277321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3278321936Shselasky 3279321936Shselasky if (safe_x_perpendicular(t, ip1, j, kp1) && 3280321936Shselasky install_tswitch(t, i, j, kp1, 3281321936Shselasky tfind_3d_perpendicular(t->sw[ip1][j][k], 3282321936Shselasky t->sw[ip1][j][kp1], 3283321936Shselasky t->sw[ip1][jp1][kp1], 3284321936Shselasky t->sw[ip2][j][kp1]))) { 3285321936Shselasky return true; 3286321936Shselasky } 3287321936Shselasky log_no_perp(t, 0x75d, i, j, k, ip1, j, kp1); 3288321936Shselasky return false; 3289321936Shselasky} 3290321936Shselasky 3291321936Shselasky/* 3292321936Shselasky * 3D case 0x773: O 3293321936Shselasky * . 3294321936Shselasky * b0: . 3295321936Shselasky * b1: . 3296321936Shselasky * b2: t->sw[i ][j+1][k ] . 3297321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 3298321936Shselasky * b4: O 3299321936Shselasky * b5: . 3300321936Shselasky * b6: . 3301321936Shselasky * b7: t->sw[i+1][j+1][k+1] . 3302321936Shselasky * . O 3303321936Shselasky * O O 3304321936Shselasky * 3305321936Shselasky * 3306321936Shselasky * 3307321936Shselasky * 3308321936Shselasky * @ 3309321936Shselasky */ 3310321936Shselaskystatic 3311321936Shselaskybool handle_case_0x773(struct torus *t, int i, int j, int k) 3312321936Shselasky{ 3313321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3314321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3315321936Shselasky int jp2 = canonicalize(j + 2, t->y_sz); 3316321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3317321936Shselasky 3318321936Shselasky if (safe_y_perpendicular(t, ip1, jp1, k) && 3319321936Shselasky install_tswitch(t, ip1, j, k, 3320321936Shselasky tfind_3d_perpendicular(t->sw[i][jp1][k], 3321321936Shselasky t->sw[ip1][jp1][k], 3322321936Shselasky t->sw[ip1][jp1][kp1], 3323321936Shselasky t->sw[ip1][jp2][k]))) { 3324321936Shselasky return true; 3325321936Shselasky } 3326321936Shselasky log_no_perp(t, 0x773, i, j, k, ip1, jp1, k); 3327321936Shselasky return false; 3328321936Shselasky} 3329321936Shselasky 3330321936Shselasky/* 3331321936Shselasky * 3D case 0x775: O 3332321936Shselasky * . 3333321936Shselasky * b0: . 3334321936Shselasky * b1: t->sw[i+1][j ][k ] . 3335321936Shselasky * b2: . 3336321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 3337321936Shselasky * b4: O 3338321936Shselasky * b5: . 3339321936Shselasky * b6: . 3340321936Shselasky * b7: t->sw[i+1][j+1][k+1] . 3341321936Shselasky * O . 3342321936Shselasky * O O 3343321936Shselasky * 3344321936Shselasky * 3345321936Shselasky * 3346321936Shselasky * 3347321936Shselasky * @ 3348321936Shselasky */ 3349321936Shselaskystatic 3350321936Shselaskybool handle_case_0x775(struct torus *t, int i, int j, int k) 3351321936Shselasky{ 3352321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3353321936Shselasky int ip2 = canonicalize(i + 2, t->x_sz); 3354321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3355321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3356321936Shselasky 3357321936Shselasky if (safe_x_perpendicular(t, ip1, jp1, k) && 3358321936Shselasky install_tswitch(t, i, jp1, k, 3359321936Shselasky tfind_3d_perpendicular(t->sw[ip1][j][k], 3360321936Shselasky t->sw[ip1][jp1][k], 3361321936Shselasky t->sw[ip1][jp1][kp1], 3362321936Shselasky t->sw[ip2][jp1][k]))) { 3363321936Shselasky return true; 3364321936Shselasky } 3365321936Shselasky log_no_perp(t, 0x775, i, j, k, ip1, jp1, k); 3366321936Shselasky return false; 3367321936Shselasky} 3368321936Shselasky 3369321936Shselasky/* 3370321936Shselasky * 3D case 0x78f: O 3371321936Shselasky * 3372321936Shselasky * b0: 3373321936Shselasky * b1: 3374321936Shselasky * b2: 3375321936Shselasky * b3: O O 3376321936Shselasky * b4: t->sw[i ][j ][k+1] . O . 3377321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 3378321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 3379321936Shselasky * b7: . . 3380321936Shselasky * O 3381321936Shselasky * O O 3382321936Shselasky * 3383321936Shselasky * 3384321936Shselasky * 3385321936Shselasky * 3386321936Shselasky * @ 3387321936Shselasky */ 3388321936Shselaskystatic 3389321936Shselaskybool handle_case_0x78f(struct torus *t, int i, int j, int k) 3390321936Shselasky{ 3391321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3392321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3393321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3394321936Shselasky int kp2 = canonicalize(k + 2, t->z_sz); 3395321936Shselasky 3396321936Shselasky if (safe_z_perpendicular(t, i, j, kp1) && 3397321936Shselasky install_tswitch(t, i, j, k, 3398321936Shselasky tfind_3d_perpendicular(t->sw[ip1][j][kp1], 3399321936Shselasky t->sw[i][j][kp1], 3400321936Shselasky t->sw[i][jp1][kp1], 3401321936Shselasky t->sw[i][j][kp2]))) { 3402321936Shselasky return true; 3403321936Shselasky } 3404321936Shselasky log_no_perp(t, 0x78f, i, j, k, i, j, kp1); 3405321936Shselasky return false; 3406321936Shselasky} 3407321936Shselasky 3408321936Shselasky/* 3409321936Shselasky * 3D case 0x7ab: O 3410321936Shselasky * 3411321936Shselasky * b0: 3412321936Shselasky * b1: 3413321936Shselasky * b2: t->sw[i ][j+1][k ] 3414321936Shselasky * b3: O O 3415321936Shselasky * b4: t->sw[i ][j ][k+1] . . O 3416321936Shselasky * b5: . . 3417321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 3418321936Shselasky * b7: . . 3419321936Shselasky * . O 3420321936Shselasky * O O 3421321936Shselasky * 3422321936Shselasky * 3423321936Shselasky * 3424321936Shselasky * 3425321936Shselasky * @ 3426321936Shselasky */ 3427321936Shselaskystatic 3428321936Shselaskybool handle_case_0x7ab(struct torus *t, int i, int j, int k) 3429321936Shselasky{ 3430321936Shselasky int im1 = canonicalize(i - 1, t->x_sz); 3431321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3432321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3433321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3434321936Shselasky 3435321936Shselasky if (safe_x_perpendicular(t, i, jp1, kp1) && 3436321936Shselasky install_tswitch(t, ip1, jp1, kp1, 3437321936Shselasky tfind_3d_perpendicular(t->sw[i][j][kp1], 3438321936Shselasky t->sw[i][jp1][kp1], 3439321936Shselasky t->sw[i][jp1][k], 3440321936Shselasky t->sw[im1][jp1][kp1]))) { 3441321936Shselasky return true; 3442321936Shselasky } 3443321936Shselasky log_no_perp(t, 0x7ab, i, j, k, i, jp1, kp1); 3444321936Shselasky return false; 3445321936Shselasky} 3446321936Shselasky 3447321936Shselasky/* 3448321936Shselasky * 3D case 0x7ae: O 3449321936Shselasky * 3450321936Shselasky * b0: t->sw[i ][j ][k ] 3451321936Shselasky * b1: 3452321936Shselasky * b2: 3453321936Shselasky * b3: O O 3454321936Shselasky * b4: t->sw[i ][j ][k+1] . O 3455321936Shselasky * b5: . 3456321936Shselasky * b6: t->sw[i ][j+1][k+1] . 3457321936Shselasky * b7: . 3458321936Shselasky * O 3459321936Shselasky * O . O 3460321936Shselasky * . 3461321936Shselasky * . 3462321936Shselasky * . 3463321936Shselasky * . 3464321936Shselasky * @ 3465321936Shselasky */ 3466321936Shselaskystatic 3467321936Shselaskybool handle_case_0x7ae(struct torus *t, int i, int j, int k) 3468321936Shselasky{ 3469321936Shselasky int im1 = canonicalize(i - 1, t->x_sz); 3470321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3471321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3472321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3473321936Shselasky 3474321936Shselasky if (safe_x_perpendicular(t, i, j, kp1) && 3475321936Shselasky install_tswitch(t, ip1, j, kp1, 3476321936Shselasky tfind_3d_perpendicular(t->sw[i][j][k], 3477321936Shselasky t->sw[i][j][kp1], 3478321936Shselasky t->sw[i][jp1][kp1], 3479321936Shselasky t->sw[im1][j][kp1]))) { 3480321936Shselasky return true; 3481321936Shselasky } 3482321936Shselasky log_no_perp(t, 0x7ae, i, j, k, i, j, kp1); 3483321936Shselasky return false; 3484321936Shselasky} 3485321936Shselasky 3486321936Shselasky/* 3487321936Shselasky * 3D case 0x7b3: O 3488321936Shselasky * 3489321936Shselasky * b0: 3490321936Shselasky * b1: 3491321936Shselasky * b2: t->sw[i ][j+1][k ] 3492321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 3493321936Shselasky * b4: . O 3494321936Shselasky * b5: . . 3495321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 3496321936Shselasky * b7: . . 3497321936Shselasky * . . O 3498321936Shselasky * O O 3499321936Shselasky * 3500321936Shselasky * 3501321936Shselasky * 3502321936Shselasky * 3503321936Shselasky * @ 3504321936Shselasky */ 3505321936Shselaskystatic 3506321936Shselaskybool handle_case_0x7b3(struct torus *t, int i, int j, int k) 3507321936Shselasky{ 3508321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3509321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3510321936Shselasky int jp2 = canonicalize(j + 2, t->y_sz); 3511321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3512321936Shselasky 3513321936Shselasky if (safe_y_perpendicular(t, i, jp1, k) && 3514321936Shselasky install_tswitch(t, i, j, k, 3515321936Shselasky tfind_3d_perpendicular(t->sw[i][jp1][kp1], 3516321936Shselasky t->sw[i][jp1][k], 3517321936Shselasky t->sw[ip1][jp1][k], 3518321936Shselasky t->sw[i][jp2][k]))) { 3519321936Shselasky return true; 3520321936Shselasky } 3521321936Shselasky log_no_perp(t, 0x7b3, i, j, k, i, jp1, k); 3522321936Shselasky return false; 3523321936Shselasky} 3524321936Shselasky 3525321936Shselasky/* 3526321936Shselasky * 3D case 0x7ba: O 3527321936Shselasky * 3528321936Shselasky * b0: t->sw[i ][j ][k ] 3529321936Shselasky * b1: 3530321936Shselasky * b2: t->sw[i ][j+1][k ] 3531321936Shselasky * b3: O O 3532321936Shselasky * b4: . O 3533321936Shselasky * b5: . 3534321936Shselasky * b6: t->sw[i ][j+1][k+1] . 3535321936Shselasky * b7: . 3536321936Shselasky * . O 3537321936Shselasky * O O 3538321936Shselasky * . 3539321936Shselasky * . 3540321936Shselasky * . 3541321936Shselasky * . 3542321936Shselasky * @ 3543321936Shselasky */ 3544321936Shselaskystatic 3545321936Shselaskybool handle_case_0x7ba(struct torus *t, int i, int j, int k) 3546321936Shselasky{ 3547321936Shselasky int im1 = canonicalize(i - 1, t->x_sz); 3548321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3549321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3550321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3551321936Shselasky 3552321936Shselasky if (safe_x_perpendicular(t, i, jp1, k) && 3553321936Shselasky install_tswitch(t, ip1, jp1, k, 3554321936Shselasky tfind_3d_perpendicular(t->sw[i][j][k], 3555321936Shselasky t->sw[i][jp1][k], 3556321936Shselasky t->sw[i][jp1][kp1], 3557321936Shselasky t->sw[im1][jp1][k]))) { 3558321936Shselasky return true; 3559321936Shselasky } 3560321936Shselasky log_no_perp(t, 0x7ba, i, j, k, i, jp1, k); 3561321936Shselasky return false; 3562321936Shselasky} 3563321936Shselasky 3564321936Shselasky/* 3565321936Shselasky * 3D case 0x7cd: O 3566321936Shselasky * 3567321936Shselasky * b0: 3568321936Shselasky * b1: t->sw[i+1][j ][k ] 3569321936Shselasky * b2: 3570321936Shselasky * b3: O O 3571321936Shselasky * b4: t->sw[i ][j ][k+1] O . . 3572321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 3573321936Shselasky * b6: . . 3574321936Shselasky * b7: . . 3575321936Shselasky * O . 3576321936Shselasky * O O 3577321936Shselasky * 3578321936Shselasky * 3579321936Shselasky * 3580321936Shselasky * 3581321936Shselasky * @ 3582321936Shselasky */ 3583321936Shselaskystatic 3584321936Shselaskybool handle_case_0x7cd(struct torus *t, int i, int j, int k) 3585321936Shselasky{ 3586321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3587321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3588321936Shselasky int jm1 = canonicalize(j - 1, t->y_sz); 3589321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3590321936Shselasky 3591321936Shselasky if (safe_y_perpendicular(t, ip1, j, kp1) && 3592321936Shselasky install_tswitch(t, ip1, jp1, kp1, 3593321936Shselasky tfind_3d_perpendicular(t->sw[i][j][kp1], 3594321936Shselasky t->sw[ip1][j][kp1], 3595321936Shselasky t->sw[ip1][j][k], 3596321936Shselasky t->sw[ip1][jm1][kp1]))) { 3597321936Shselasky return true; 3598321936Shselasky } 3599321936Shselasky log_no_perp(t, 0x7cd, i, j, k, ip1, j, kp1); 3600321936Shselasky return false; 3601321936Shselasky} 3602321936Shselasky 3603321936Shselasky/* 3604321936Shselasky * 3D case 0x7ce: O 3605321936Shselasky * 3606321936Shselasky * b0: t->sw[i ][j ][k ] 3607321936Shselasky * b1: 3608321936Shselasky * b2: 3609321936Shselasky * b3: O O 3610321936Shselasky * b4: t->sw[i ][j ][k+1] O . 3611321936Shselasky * b5: t->sw[i+1][j ][k+1] . 3612321936Shselasky * b6: . 3613321936Shselasky * b7: . 3614321936Shselasky * O 3615321936Shselasky * O . O 3616321936Shselasky * . 3617321936Shselasky * . 3618321936Shselasky * . 3619321936Shselasky * . 3620321936Shselasky * @ 3621321936Shselasky */ 3622321936Shselaskystatic 3623321936Shselaskybool handle_case_0x7ce(struct torus *t, int i, int j, int k) 3624321936Shselasky{ 3625321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3626321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3627321936Shselasky int jm1 = canonicalize(j - 1, t->y_sz); 3628321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3629321936Shselasky 3630321936Shselasky if (safe_y_perpendicular(t, i, j, kp1) && 3631321936Shselasky install_tswitch(t, i, jp1, kp1, 3632321936Shselasky tfind_3d_perpendicular(t->sw[i][j][k], 3633321936Shselasky t->sw[i][j][kp1], 3634321936Shselasky t->sw[ip1][j][kp1], 3635321936Shselasky t->sw[i][jm1][kp1]))) { 3636321936Shselasky return true; 3637321936Shselasky } 3638321936Shselasky log_no_perp(t, 0x7ce, i, j, k, i, j, kp1); 3639321936Shselasky return false; 3640321936Shselasky} 3641321936Shselasky 3642321936Shselasky/* 3643321936Shselasky * 3D case 0x7d5: O 3644321936Shselasky * 3645321936Shselasky * b0: 3646321936Shselasky * b1: t->sw[i+1][j ][k ] 3647321936Shselasky * b2: 3648321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 3649321936Shselasky * b4: O . 3650321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 3651321936Shselasky * b6: . . 3652321936Shselasky * b7: . . 3653321936Shselasky * O . . 3654321936Shselasky * O O 3655321936Shselasky * 3656321936Shselasky * 3657321936Shselasky * 3658321936Shselasky * 3659321936Shselasky * @ 3660321936Shselasky */ 3661321936Shselaskystatic 3662321936Shselaskybool handle_case_0x7d5(struct torus *t, int i, int j, int k) 3663321936Shselasky{ 3664321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3665321936Shselasky int ip2 = canonicalize(i + 2, t->x_sz); 3666321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3667321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3668321936Shselasky 3669321936Shselasky if (safe_x_perpendicular(t, ip1, j, k) && 3670321936Shselasky install_tswitch(t, i, j, k, 3671321936Shselasky tfind_3d_perpendicular(t->sw[ip1][j][kp1], 3672321936Shselasky t->sw[ip1][j][k], 3673321936Shselasky t->sw[ip1][jp1][k], 3674321936Shselasky t->sw[ip2][j][k]))) { 3675321936Shselasky return true; 3676321936Shselasky } 3677321936Shselasky log_no_perp(t, 0x7d5, i, j, k, ip1, j, k); 3678321936Shselasky return false; 3679321936Shselasky} 3680321936Shselasky 3681321936Shselasky/* 3682321936Shselasky * 3D case 0x7dc: O 3683321936Shselasky * 3684321936Shselasky * b0: t->sw[i ][j ][k ] 3685321936Shselasky * b1: t->sw[i+1][j ][k ] 3686321936Shselasky * b2: 3687321936Shselasky * b3: O O 3688321936Shselasky * b4: O . 3689321936Shselasky * b5: t->sw[i+1][j ][k+1] . 3690321936Shselasky * b6: . 3691321936Shselasky * b7: . 3692321936Shselasky * O . 3693321936Shselasky * O O 3694321936Shselasky * . 3695321936Shselasky * . 3696321936Shselasky * . 3697321936Shselasky * . 3698321936Shselasky * @ 3699321936Shselasky */ 3700321936Shselaskystatic 3701321936Shselaskybool handle_case_0x7dc(struct torus *t, int i, int j, int k) 3702321936Shselasky{ 3703321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3704321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3705321936Shselasky int jm1 = canonicalize(j - 1, t->y_sz); 3706321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3707321936Shselasky 3708321936Shselasky if (safe_y_perpendicular(t, ip1, j, k) && 3709321936Shselasky install_tswitch(t, ip1, jp1, k, 3710321936Shselasky tfind_3d_perpendicular(t->sw[i][j][k], 3711321936Shselasky t->sw[ip1][j][k], 3712321936Shselasky t->sw[ip1][j][kp1], 3713321936Shselasky t->sw[ip1][jm1][k]))) { 3714321936Shselasky return true; 3715321936Shselasky } 3716321936Shselasky log_no_perp(t, 0x7dc, i, j, k, ip1, j, k); 3717321936Shselasky return false; 3718321936Shselasky} 3719321936Shselasky 3720321936Shselasky/* 3721321936Shselasky * 3D case 0x7ea: O 3722321936Shselasky * 3723321936Shselasky * b0: t->sw[i ][j ][k ] 3724321936Shselasky * b1: 3725321936Shselasky * b2: t->sw[i ][j+1][k ] 3726321936Shselasky * b3: O O 3727321936Shselasky * b4: t->sw[i ][j ][k+1] O 3728321936Shselasky * b5: 3729321936Shselasky * b6: 3730321936Shselasky * b7: 3731321936Shselasky * O 3732321936Shselasky * O . O 3733321936Shselasky * . . 3734321936Shselasky * . . 3735321936Shselasky * . . 3736321936Shselasky * . . 3737321936Shselasky * @ 3738321936Shselasky */ 3739321936Shselaskystatic 3740321936Shselaskybool handle_case_0x7ea(struct torus *t, int i, int j, int k) 3741321936Shselasky{ 3742321936Shselasky int im1 = canonicalize(i - 1, t->x_sz); 3743321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3744321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3745321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3746321936Shselasky 3747321936Shselasky if (safe_x_perpendicular(t, i, j, k) && 3748321936Shselasky install_tswitch(t, ip1, j, k, 3749321936Shselasky tfind_3d_perpendicular(t->sw[i][j][kp1], 3750321936Shselasky t->sw[i][j][k], 3751321936Shselasky t->sw[i][jp1][k], 3752321936Shselasky t->sw[im1][j][k]))) { 3753321936Shselasky return true; 3754321936Shselasky } 3755321936Shselasky log_no_perp(t, 0x7ea, i, j, k, i, j, k); 3756321936Shselasky return false; 3757321936Shselasky} 3758321936Shselasky 3759321936Shselasky/* 3760321936Shselasky * 3D case 0x7ec: O 3761321936Shselasky * 3762321936Shselasky * b0: t->sw[i ][j ][k ] 3763321936Shselasky * b1: t->sw[i+1][j ][k ] 3764321936Shselasky * b2: 3765321936Shselasky * b3: O O 3766321936Shselasky * b4: t->sw[i ][j ][k+1] O 3767321936Shselasky * b5: 3768321936Shselasky * b6: 3769321936Shselasky * b7: 3770321936Shselasky * O 3771321936Shselasky * O . O 3772321936Shselasky * . . 3773321936Shselasky * . . 3774321936Shselasky * . . 3775321936Shselasky * . . 3776321936Shselasky * @ 3777321936Shselasky */ 3778321936Shselaskystatic 3779321936Shselaskybool handle_case_0x7ec(struct torus *t, int i, int j, int k) 3780321936Shselasky{ 3781321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3782321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3783321936Shselasky int jm1 = canonicalize(j - 1, t->y_sz); 3784321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3785321936Shselasky 3786321936Shselasky if (safe_y_perpendicular(t, i, j, k) && 3787321936Shselasky install_tswitch(t, i, jp1, k, 3788321936Shselasky tfind_3d_perpendicular(t->sw[i][j][kp1], 3789321936Shselasky t->sw[i][j][k], 3790321936Shselasky t->sw[ip1][j][k], 3791321936Shselasky t->sw[i][jm1][k]))) { 3792321936Shselasky return true; 3793321936Shselasky } 3794321936Shselasky log_no_perp(t, 0x7ec, i, j, k, i, j, k); 3795321936Shselasky return false; 3796321936Shselasky} 3797321936Shselasky 3798321936Shselasky/* 3799321936Shselasky * 3D case 0x7f1: O 3800321936Shselasky * 3801321936Shselasky * b0: 3802321936Shselasky * b1: t->sw[i+1][j ][k ] 3803321936Shselasky * b2: t->sw[i ][j+1][k ] 3804321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 3805321936Shselasky * b4: O 3806321936Shselasky * b5: . . 3807321936Shselasky * b6: . . 3808321936Shselasky * b7: . . 3809321936Shselasky * . O . 3810321936Shselasky * O O 3811321936Shselasky * 3812321936Shselasky * 3813321936Shselasky * 3814321936Shselasky * 3815321936Shselasky * @ 3816321936Shselasky */ 3817321936Shselaskystatic 3818321936Shselaskybool handle_case_0x7f1(struct torus *t, int i, int j, int k) 3819321936Shselasky{ 3820321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3821321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3822321936Shselasky int km1 = canonicalize(k - 1, t->z_sz); 3823321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3824321936Shselasky 3825321936Shselasky if (safe_z_perpendicular(t, ip1, jp1, k) && 3826321936Shselasky install_tswitch(t, ip1, jp1, kp1, 3827321936Shselasky tfind_3d_perpendicular(t->sw[ip1][j][k], 3828321936Shselasky t->sw[ip1][jp1][k], 3829321936Shselasky t->sw[i][jp1][k], 3830321936Shselasky t->sw[ip1][jp1][km1]))) { 3831321936Shselasky return true; 3832321936Shselasky } 3833321936Shselasky log_no_perp(t, 0x7f1, i, j, k, ip1, jp1, k); 3834321936Shselasky return false; 3835321936Shselasky} 3836321936Shselasky 3837321936Shselasky/* 3838321936Shselasky * 3D case 0x7f2: O 3839321936Shselasky * 3840321936Shselasky * b0: t->sw[i ][j ][k ] 3841321936Shselasky * b1: 3842321936Shselasky * b2: t->sw[i ][j+1][k ] 3843321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 3844321936Shselasky * b4: O 3845321936Shselasky * b5: . 3846321936Shselasky * b6: . 3847321936Shselasky * b7: . 3848321936Shselasky * . O 3849321936Shselasky * O O 3850321936Shselasky * . 3851321936Shselasky * . 3852321936Shselasky * . 3853321936Shselasky * . 3854321936Shselasky * @ 3855321936Shselasky */ 3856321936Shselaskystatic 3857321936Shselaskybool handle_case_0x7f2(struct torus *t, int i, int j, int k) 3858321936Shselasky{ 3859321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3860321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3861321936Shselasky int km1 = canonicalize(k - 1, t->z_sz); 3862321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3863321936Shselasky 3864321936Shselasky if (safe_z_perpendicular(t, i, jp1, k) && 3865321936Shselasky install_tswitch(t, i, jp1, kp1, 3866321936Shselasky tfind_3d_perpendicular(t->sw[i][j][k], 3867321936Shselasky t->sw[i][jp1][k], 3868321936Shselasky t->sw[ip1][jp1][k], 3869321936Shselasky t->sw[i][jp1][km1]))) { 3870321936Shselasky return true; 3871321936Shselasky } 3872321936Shselasky log_no_perp(t, 0x7f2, i, j, k, i, jp1, k); 3873321936Shselasky return false; 3874321936Shselasky} 3875321936Shselasky 3876321936Shselasky/* 3877321936Shselasky * 3D case 0x7f4: O 3878321936Shselasky * 3879321936Shselasky * b0: t->sw[i ][j ][k ] 3880321936Shselasky * b1: t->sw[i+1][j ][k ] 3881321936Shselasky * b2: 3882321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 3883321936Shselasky * b4: O 3884321936Shselasky * b5: . 3885321936Shselasky * b6: . 3886321936Shselasky * b7: . 3887321936Shselasky * O . 3888321936Shselasky * O O 3889321936Shselasky * . 3890321936Shselasky * . 3891321936Shselasky * . 3892321936Shselasky * . 3893321936Shselasky * @ 3894321936Shselasky */ 3895321936Shselaskystatic 3896321936Shselaskybool handle_case_0x7f4(struct torus *t, int i, int j, int k) 3897321936Shselasky{ 3898321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3899321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3900321936Shselasky int km1 = canonicalize(k - 1, t->z_sz); 3901321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3902321936Shselasky 3903321936Shselasky if (safe_z_perpendicular(t, ip1, j, k) && 3904321936Shselasky install_tswitch(t, ip1, j, kp1, 3905321936Shselasky tfind_3d_perpendicular(t->sw[i][j][k], 3906321936Shselasky t->sw[ip1][j][k], 3907321936Shselasky t->sw[ip1][jp1][k], 3908321936Shselasky t->sw[ip1][j][km1]))) { 3909321936Shselasky return true; 3910321936Shselasky } 3911321936Shselasky log_no_perp(t, 0x7f4, i, j, k, ip1, j, k); 3912321936Shselasky return false; 3913321936Shselasky} 3914321936Shselasky 3915321936Shselasky/* 3916321936Shselasky * 3D case 0x7f8: O 3917321936Shselasky * 3918321936Shselasky * b0: t->sw[i ][j ][k ] 3919321936Shselasky * b1: t->sw[i+1][j ][k ] 3920321936Shselasky * b2: t->sw[i ][j+1][k ] 3921321936Shselasky * b3: O O 3922321936Shselasky * b4: O 3923321936Shselasky * b5: 3924321936Shselasky * b6: 3925321936Shselasky * b7: 3926321936Shselasky * O 3927321936Shselasky * O O 3928321936Shselasky * . . 3929321936Shselasky * . . 3930321936Shselasky * . . 3931321936Shselasky * . . 3932321936Shselasky * @ 3933321936Shselasky */ 3934321936Shselaskystatic 3935321936Shselaskybool handle_case_0x7f8(struct torus *t, int i, int j, int k) 3936321936Shselasky{ 3937321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3938321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3939321936Shselasky int km1 = canonicalize(k - 1, t->z_sz); 3940321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3941321936Shselasky 3942321936Shselasky if (safe_z_perpendicular(t, i, j, k) && 3943321936Shselasky install_tswitch(t, i, j, kp1, 3944321936Shselasky tfind_3d_perpendicular(t->sw[ip1][j][k], 3945321936Shselasky t->sw[i][j][k], 3946321936Shselasky t->sw[i][jp1][k], 3947321936Shselasky t->sw[i][j][km1]))) { 3948321936Shselasky return true; 3949321936Shselasky } 3950321936Shselasky log_no_perp(t, 0x7f8, i, j, k, i, j, k); 3951321936Shselasky return false; 3952321936Shselasky} 3953321936Shselasky 3954321936Shselasky/* 3955321936Shselasky * Handle the cases where three existing edges meet at a corner. 3956321936Shselasky */ 3957321936Shselasky 3958321936Shselasky/* 3959321936Shselasky * 3D case 0x717: O 3960321936Shselasky * . . . 3961321936Shselasky * b0: . . . 3962321936Shselasky * b1: . . . 3963321936Shselasky * b2: . . . 3964321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 3965321936Shselasky * b4: O 3966321936Shselasky * b5: t->sw[i+1][j ][k+1] 3967321936Shselasky * b6: t->sw[i ][j+1][k+1] 3968321936Shselasky * b7: t->sw[i+1][j+1][k+1] 3969321936Shselasky * O 3970321936Shselasky * O O 3971321936Shselasky * 3972321936Shselasky * 3973321936Shselasky * 3974321936Shselasky * 3975321936Shselasky * @ 3976321936Shselasky */ 3977321936Shselaskystatic 3978321936Shselaskybool handle_case_0x717(struct torus *t, int i, int j, int k) 3979321936Shselasky{ 3980321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 3981321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 3982321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 3983321936Shselasky 3984321936Shselasky if (install_tswitch(t, i, j, kp1, 3985321936Shselasky tfind_face_corner(t->sw[i][jp1][kp1], 3986321936Shselasky t->sw[ip1][jp1][kp1], 3987321936Shselasky t->sw[ip1][j][kp1]))) { 3988321936Shselasky return true; 3989321936Shselasky } 3990321936Shselasky log_no_crnr(t, 0x717, i, j, k, i, j, kp1); 3991321936Shselasky 3992321936Shselasky if (install_tswitch(t, ip1, j, k, 3993321936Shselasky tfind_face_corner(t->sw[ip1][jp1][k], 3994321936Shselasky t->sw[ip1][jp1][kp1], 3995321936Shselasky t->sw[ip1][j][kp1]))) { 3996321936Shselasky return true; 3997321936Shselasky } 3998321936Shselasky log_no_crnr(t, 0x717, i, j, k, ip1, j, k); 3999321936Shselasky 4000321936Shselasky if (install_tswitch(t, i, jp1, k, 4001321936Shselasky tfind_face_corner(t->sw[ip1][jp1][k], 4002321936Shselasky t->sw[ip1][jp1][kp1], 4003321936Shselasky t->sw[i][jp1][kp1]))) { 4004321936Shselasky return true; 4005321936Shselasky } 4006321936Shselasky log_no_crnr(t, 0x717, i, j, k, i, jp1, k); 4007321936Shselasky return false; 4008321936Shselasky} 4009321936Shselasky 4010321936Shselasky/* 4011321936Shselasky * 3D case 0x72b: O 4012321936Shselasky * . 4013321936Shselasky * b0: . 4014321936Shselasky * b1: . 4015321936Shselasky * b2: t->sw[i ][j+1][k ] . 4016321936Shselasky * b3: O O 4017321936Shselasky * b4: t->sw[i ][j ][k+1] . . O 4018321936Shselasky * b5: . . 4019321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 4020321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . 4021321936Shselasky * . O 4022321936Shselasky * O O 4023321936Shselasky * 4024321936Shselasky * 4025321936Shselasky * 4026321936Shselasky * 4027321936Shselasky * @ 4028321936Shselasky */ 4029321936Shselaskystatic 4030321936Shselaskybool handle_case_0x72b(struct torus *t, int i, int j, int k) 4031321936Shselasky{ 4032321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4033321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4034321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4035321936Shselasky 4036321936Shselasky if (install_tswitch(t, ip1, j, kp1, 4037321936Shselasky tfind_face_corner(t->sw[i][j][kp1], 4038321936Shselasky t->sw[i][jp1][kp1], 4039321936Shselasky t->sw[ip1][jp1][kp1]))) { 4040321936Shselasky return true; 4041321936Shselasky } 4042321936Shselasky log_no_crnr(t, 0x72b, i, j, k, ip1, j, kp1); 4043321936Shselasky 4044321936Shselasky if (install_tswitch(t, i, j, k, 4045321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 4046321936Shselasky t->sw[i][jp1][kp1], 4047321936Shselasky t->sw[i][j][kp1]))) { 4048321936Shselasky return true; 4049321936Shselasky } 4050321936Shselasky log_no_crnr(t, 0x72b, i, j, k, i, j, k); 4051321936Shselasky 4052321936Shselasky if (install_tswitch(t, ip1, jp1, k, 4053321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 4054321936Shselasky t->sw[i][jp1][kp1], 4055321936Shselasky t->sw[ip1][jp1][kp1]))) { 4056321936Shselasky return true; 4057321936Shselasky } 4058321936Shselasky log_no_crnr(t, 0x72b, i, j, k, ip1, jp1, k); 4059321936Shselasky return false; 4060321936Shselasky} 4061321936Shselasky 4062321936Shselasky/* 4063321936Shselasky * 3D case 0x74d: O 4064321936Shselasky * . 4065321936Shselasky * b0: . 4066321936Shselasky * b1: t->sw[i+1][j ][k ] . 4067321936Shselasky * b2: . 4068321936Shselasky * b3: O O 4069321936Shselasky * b4: t->sw[i ][j ][k+1] O . . 4070321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 4071321936Shselasky * b6: . . 4072321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . 4073321936Shselasky * O . 4074321936Shselasky * O O 4075321936Shselasky * 4076321936Shselasky * 4077321936Shselasky * 4078321936Shselasky * 4079321936Shselasky * @ 4080321936Shselasky */ 4081321936Shselaskystatic 4082321936Shselaskybool handle_case_0x74d(struct torus *t, int i, int j, int k) 4083321936Shselasky{ 4084321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4085321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4086321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4087321936Shselasky 4088321936Shselasky if (install_tswitch(t, i, jp1, kp1, 4089321936Shselasky tfind_face_corner(t->sw[i][j][kp1], 4090321936Shselasky t->sw[ip1][j][kp1], 4091321936Shselasky t->sw[ip1][jp1][kp1]))) { 4092321936Shselasky return true; 4093321936Shselasky } 4094321936Shselasky log_no_crnr(t, 0x74d, i, j, k, i, jp1, kp1); 4095321936Shselasky 4096321936Shselasky if (install_tswitch(t, i, j, k, 4097321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 4098321936Shselasky t->sw[ip1][j][kp1], 4099321936Shselasky t->sw[i][j][kp1]))) { 4100321936Shselasky return true; 4101321936Shselasky } 4102321936Shselasky log_no_crnr(t, 0x74d, i, j, k, i, j, k); 4103321936Shselasky 4104321936Shselasky if (install_tswitch(t, ip1, jp1, k, 4105321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 4106321936Shselasky t->sw[ip1][j][kp1], 4107321936Shselasky t->sw[ip1][jp1][kp1]))) { 4108321936Shselasky return true; 4109321936Shselasky } 4110321936Shselasky log_no_crnr(t, 0x74d, i, j, k, ip1, jp1, k); 4111321936Shselasky return false; 4112321936Shselasky} 4113321936Shselasky 4114321936Shselasky/* 4115321936Shselasky * 3D case 0x771: O 4116321936Shselasky * . 4117321936Shselasky * b0: . 4118321936Shselasky * b1: t->sw[i+1][j ][k ] . 4119321936Shselasky * b2: t->sw[i ][j+1][k ] . 4120321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 4121321936Shselasky * b4: O 4122321936Shselasky * b5: . . 4123321936Shselasky * b6: . . 4124321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . 4125321936Shselasky * . O . 4126321936Shselasky * O O 4127321936Shselasky * 4128321936Shselasky * 4129321936Shselasky * 4130321936Shselasky * 4131321936Shselasky * @ 4132321936Shselasky */ 4133321936Shselaskystatic 4134321936Shselaskybool handle_case_0x771(struct torus *t, int i, int j, int k) 4135321936Shselasky{ 4136321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4137321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4138321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4139321936Shselasky 4140321936Shselasky if (install_tswitch(t, i, j, k, 4141321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 4142321936Shselasky t->sw[ip1][jp1][k], 4143321936Shselasky t->sw[ip1][j][k]))) { 4144321936Shselasky return true; 4145321936Shselasky } 4146321936Shselasky log_no_crnr(t, 0x771, i, j, k, i, j, k); 4147321936Shselasky 4148321936Shselasky if (install_tswitch(t, ip1, j, kp1, 4149321936Shselasky tfind_face_corner(t->sw[ip1][jp1][kp1], 4150321936Shselasky t->sw[ip1][jp1][k], 4151321936Shselasky t->sw[ip1][j][k]))) { 4152321936Shselasky return true; 4153321936Shselasky } 4154321936Shselasky log_no_crnr(t, 0x771, i, j, k, ip1, j, kp1); 4155321936Shselasky 4156321936Shselasky if (install_tswitch(t, i, jp1, kp1, 4157321936Shselasky tfind_face_corner(t->sw[ip1][jp1][kp1], 4158321936Shselasky t->sw[ip1][jp1][k], 4159321936Shselasky t->sw[i][jp1][k]))) { 4160321936Shselasky return true; 4161321936Shselasky } 4162321936Shselasky log_no_crnr(t, 0x771, i, j, k, i, jp1, kp1); 4163321936Shselasky return false; 4164321936Shselasky} 4165321936Shselasky 4166321936Shselasky/* 4167321936Shselasky * 3D case 0x78e: O 4168321936Shselasky * 4169321936Shselasky * b0: t->sw[i ][j ][k ] 4170321936Shselasky * b1: 4171321936Shselasky * b2: 4172321936Shselasky * b3: O O 4173321936Shselasky * b4: t->sw[i ][j ][k+1] . O . 4174321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 4175321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 4176321936Shselasky * b7: . . 4177321936Shselasky * O 4178321936Shselasky * O . O 4179321936Shselasky * . 4180321936Shselasky * . 4181321936Shselasky * . 4182321936Shselasky * . 4183321936Shselasky * @ 4184321936Shselasky */ 4185321936Shselaskystatic 4186321936Shselaskybool handle_case_0x78e(struct torus *t, int i, int j, int k) 4187321936Shselasky{ 4188321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4189321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4190321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4191321936Shselasky 4192321936Shselasky if (install_tswitch(t, ip1, jp1, kp1, 4193321936Shselasky tfind_face_corner(t->sw[ip1][j][kp1], 4194321936Shselasky t->sw[i][j][kp1], 4195321936Shselasky t->sw[i][jp1][kp1]))) { 4196321936Shselasky return true; 4197321936Shselasky } 4198321936Shselasky log_no_crnr(t, 0x78e, i, j, k, ip1, jp1, kp1); 4199321936Shselasky 4200321936Shselasky if (install_tswitch(t, ip1, j, k, 4201321936Shselasky tfind_face_corner(t->sw[i][j][k], 4202321936Shselasky t->sw[i][j][kp1], 4203321936Shselasky t->sw[ip1][j][kp1]))) { 4204321936Shselasky return true; 4205321936Shselasky } 4206321936Shselasky log_no_crnr(t, 0x78e, i, j, k, ip1, j, k); 4207321936Shselasky 4208321936Shselasky if (install_tswitch(t, i, jp1, k, 4209321936Shselasky tfind_face_corner(t->sw[i][j][k], 4210321936Shselasky t->sw[i][j][kp1], 4211321936Shselasky t->sw[i][jp1][kp1]))) { 4212321936Shselasky return true; 4213321936Shselasky } 4214321936Shselasky log_no_crnr(t, 0x78e, i, j, k, i, jp1, k); 4215321936Shselasky return false; 4216321936Shselasky} 4217321936Shselasky 4218321936Shselasky/* 4219321936Shselasky * 3D case 0x7b2: O 4220321936Shselasky * 4221321936Shselasky * b0: t->sw[i ][j ][k ] 4222321936Shselasky * b1: 4223321936Shselasky * b2: t->sw[i ][j+1][k ] 4224321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 4225321936Shselasky * b4: . O 4226321936Shselasky * b5: . . 4227321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 4228321936Shselasky * b7: . . 4229321936Shselasky * . . O 4230321936Shselasky * O O 4231321936Shselasky * . 4232321936Shselasky * . 4233321936Shselasky * . 4234321936Shselasky * . 4235321936Shselasky * @ 4236321936Shselasky */ 4237321936Shselaskystatic 4238321936Shselaskybool handle_case_0x7b2(struct torus *t, int i, int j, int k) 4239321936Shselasky{ 4240321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4241321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4242321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4243321936Shselasky 4244321936Shselasky if (install_tswitch(t, ip1, j, k, 4245321936Shselasky tfind_face_corner(t->sw[i][j][k], 4246321936Shselasky t->sw[i][jp1][k], 4247321936Shselasky t->sw[ip1][jp1][k]))) { 4248321936Shselasky return true; 4249321936Shselasky } 4250321936Shselasky log_no_crnr(t, 0x7b2, i, j, k, ip1, j, k); 4251321936Shselasky 4252321936Shselasky if (install_tswitch(t, ip1, jp1, kp1, 4253321936Shselasky tfind_face_corner(t->sw[i][jp1][kp1], 4254321936Shselasky t->sw[i][jp1][k], 4255321936Shselasky t->sw[ip1][jp1][k]))) { 4256321936Shselasky return true; 4257321936Shselasky } 4258321936Shselasky log_no_crnr(t, 0x7b2, i, j, k, ip1, jp1, kp1); 4259321936Shselasky 4260321936Shselasky if (install_tswitch(t, i, j, kp1, 4261321936Shselasky tfind_face_corner(t->sw[i][jp1][kp1], 4262321936Shselasky t->sw[i][jp1][k], 4263321936Shselasky t->sw[i][j][k]))) { 4264321936Shselasky return true; 4265321936Shselasky } 4266321936Shselasky log_no_crnr(t, 0x7b2, i, j, k, i, j, kp1); 4267321936Shselasky return false; 4268321936Shselasky} 4269321936Shselasky 4270321936Shselasky/* 4271321936Shselasky * 3D case 0x7d4: O 4272321936Shselasky * 4273321936Shselasky * b0: t->sw[i ][j ][k ] 4274321936Shselasky * b1: t->sw[i+1][j ][k ] 4275321936Shselasky * b2: 4276321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 4277321936Shselasky * b4: O . 4278321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 4279321936Shselasky * b6: . . 4280321936Shselasky * b7: . . 4281321936Shselasky * O . . 4282321936Shselasky * O O 4283321936Shselasky * . 4284321936Shselasky * . 4285321936Shselasky * . 4286321936Shselasky * . 4287321936Shselasky * @ 4288321936Shselasky */ 4289321936Shselaskystatic 4290321936Shselaskybool handle_case_0x7d4(struct torus *t, int i, int j, int k) 4291321936Shselasky{ 4292321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4293321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4294321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4295321936Shselasky 4296321936Shselasky if (install_tswitch(t, i, jp1, k, 4297321936Shselasky tfind_face_corner(t->sw[i][j][k], 4298321936Shselasky t->sw[ip1][j][k], 4299321936Shselasky t->sw[ip1][jp1][k]))) { 4300321936Shselasky return true; 4301321936Shselasky } 4302321936Shselasky log_no_crnr(t, 0x7d4, i, j, k, i, jp1, k); 4303321936Shselasky 4304321936Shselasky if (install_tswitch(t, i, j, kp1, 4305321936Shselasky tfind_face_corner(t->sw[ip1][j][kp1], 4306321936Shselasky t->sw[ip1][j][k], 4307321936Shselasky t->sw[i][j][k]))) { 4308321936Shselasky return true; 4309321936Shselasky } 4310321936Shselasky log_no_crnr(t, 0x7d4, i, j, k, i, j, kp1); 4311321936Shselasky 4312321936Shselasky if (install_tswitch(t, ip1, jp1, kp1, 4313321936Shselasky tfind_face_corner(t->sw[ip1][j][kp1], 4314321936Shselasky t->sw[ip1][j][k], 4315321936Shselasky t->sw[ip1][jp1][k]))) { 4316321936Shselasky return true; 4317321936Shselasky } 4318321936Shselasky log_no_crnr(t, 0x7d4, i, j, k, ip1, jp1, kp1); 4319321936Shselasky return false; 4320321936Shselasky} 4321321936Shselasky 4322321936Shselasky/* 4323321936Shselasky * 3D case 0x7e8: O 4324321936Shselasky * 4325321936Shselasky * b0: t->sw[i ][j ][k ] 4326321936Shselasky * b1: t->sw[i+1][j ][k ] 4327321936Shselasky * b2: t->sw[i ][j+1][k ] 4328321936Shselasky * b3: O O 4329321936Shselasky * b4: t->sw[i ][j ][k+1] O 4330321936Shselasky * b5: 4331321936Shselasky * b6: 4332321936Shselasky * b7: 4333321936Shselasky * O 4334321936Shselasky * O . O 4335321936Shselasky * . . . 4336321936Shselasky * . . . 4337321936Shselasky * . . . 4338321936Shselasky * . . . 4339321936Shselasky * @ 4340321936Shselasky */ 4341321936Shselaskystatic 4342321936Shselaskybool handle_case_0x7e8(struct torus *t, int i, int j, int k) 4343321936Shselasky{ 4344321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4345321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4346321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4347321936Shselasky 4348321936Shselasky if (install_tswitch(t, ip1, jp1, k, 4349321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 4350321936Shselasky t->sw[i][j][k], 4351321936Shselasky t->sw[i][jp1][k]))) { 4352321936Shselasky return true; 4353321936Shselasky } 4354321936Shselasky log_no_crnr(t, 0x7e8, i, j, k, ip1, jp1, k); 4355321936Shselasky 4356321936Shselasky if (install_tswitch(t, ip1, j, kp1, 4357321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 4358321936Shselasky t->sw[i][j][k], 4359321936Shselasky t->sw[i][j][kp1]))) { 4360321936Shselasky return true; 4361321936Shselasky } 4362321936Shselasky log_no_crnr(t, 0x7e8, i, j, k, ip1, j, kp1); 4363321936Shselasky 4364321936Shselasky if (install_tswitch(t, i, jp1, kp1, 4365321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 4366321936Shselasky t->sw[i][j][k], 4367321936Shselasky t->sw[i][j][kp1]))) { 4368321936Shselasky return true; 4369321936Shselasky } 4370321936Shselasky log_no_crnr(t, 0x7e8, i, j, k, i, jp1, kp1); 4371321936Shselasky return false; 4372321936Shselasky} 4373321936Shselasky 4374321936Shselasky/* 4375321936Shselasky * Handle the cases where four corners on a single face are missing. 4376321936Shselasky */ 4377321936Shselasky 4378321936Shselasky/* 4379321936Shselasky * 3D case 0x70f: O 4380321936Shselasky * . . 4381321936Shselasky * b0: . . 4382321936Shselasky * b1: . . 4383321936Shselasky * b2: . . 4384321936Shselasky * b3: O O 4385321936Shselasky * b4: t->sw[i ][j ][k+1] . O . 4386321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 4387321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 4388321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . 4389321936Shselasky * O 4390321936Shselasky * O O 4391321936Shselasky * 4392321936Shselasky * 4393321936Shselasky * 4394321936Shselasky * 4395321936Shselasky * @ 4396321936Shselasky */ 4397321936Shselaskystatic 4398321936Shselaskybool handle_case_0x70f(struct torus *t, int i, int j, int k) 4399321936Shselasky{ 4400321936Shselasky if (handle_case_0x71f(t, i, j, k)) 4401321936Shselasky return true; 4402321936Shselasky 4403321936Shselasky if (handle_case_0x72f(t, i, j, k)) 4404321936Shselasky return true; 4405321936Shselasky 4406321936Shselasky if (handle_case_0x74f(t, i, j, k)) 4407321936Shselasky return true; 4408321936Shselasky 4409321936Shselasky return handle_case_0x78f(t, i, j, k); 4410321936Shselasky} 4411321936Shselasky 4412321936Shselasky/* 4413321936Shselasky * 3D case 0x733: O 4414321936Shselasky * . . 4415321936Shselasky * b0: . . 4416321936Shselasky * b1: . . 4417321936Shselasky * b2: t->sw[i ][j+1][k ] . . 4418321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 4419321936Shselasky * b4: . O 4420321936Shselasky * b5: . . 4421321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 4422321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . 4423321936Shselasky * . . O 4424321936Shselasky * O O 4425321936Shselasky * 4426321936Shselasky * 4427321936Shselasky * 4428321936Shselasky * 4429321936Shselasky * @ 4430321936Shselasky */ 4431321936Shselaskystatic 4432321936Shselaskybool handle_case_0x733(struct torus *t, int i, int j, int k) 4433321936Shselasky{ 4434321936Shselasky if (handle_case_0x737(t, i, j, k)) 4435321936Shselasky return true; 4436321936Shselasky 4437321936Shselasky if (handle_case_0x73b(t, i, j, k)) 4438321936Shselasky return true; 4439321936Shselasky 4440321936Shselasky if (handle_case_0x773(t, i, j, k)) 4441321936Shselasky return true; 4442321936Shselasky 4443321936Shselasky return handle_case_0x7b3(t, i, j, k); 4444321936Shselasky} 4445321936Shselasky 4446321936Shselasky/* 4447321936Shselasky * 3D case 0x755: O 4448321936Shselasky * . . 4449321936Shselasky * b0: . . 4450321936Shselasky * b1: t->sw[i+1][j ][k ] . . 4451321936Shselasky * b2: . . 4452321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 4453321936Shselasky * b4: O . 4454321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 4455321936Shselasky * b6: . . 4456321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . 4457321936Shselasky * O . . 4458321936Shselasky * O O 4459321936Shselasky * 4460321936Shselasky * 4461321936Shselasky * 4462321936Shselasky * 4463321936Shselasky * @ 4464321936Shselasky */ 4465321936Shselaskystatic 4466321936Shselaskybool handle_case_0x755(struct torus *t, int i, int j, int k) 4467321936Shselasky{ 4468321936Shselasky if (handle_case_0x757(t, i, j, k)) 4469321936Shselasky return true; 4470321936Shselasky 4471321936Shselasky if (handle_case_0x75d(t, i, j, k)) 4472321936Shselasky return true; 4473321936Shselasky 4474321936Shselasky if (handle_case_0x775(t, i, j, k)) 4475321936Shselasky return true; 4476321936Shselasky 4477321936Shselasky return handle_case_0x7d5(t, i, j, k); 4478321936Shselasky} 4479321936Shselasky 4480321936Shselasky/* 4481321936Shselasky * 3D case 0x7aa: O 4482321936Shselasky * 4483321936Shselasky * b0: t->sw[i ][j ][k ] 4484321936Shselasky * b1: 4485321936Shselasky * b2: t->sw[i ][j+1][k ] 4486321936Shselasky * b3: O O 4487321936Shselasky * b4: t->sw[i ][j ][k+1] . . O 4488321936Shselasky * b5: . . 4489321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 4490321936Shselasky * b7: . . 4491321936Shselasky * . O 4492321936Shselasky * O . O 4493321936Shselasky * . . 4494321936Shselasky * . . 4495321936Shselasky * . . 4496321936Shselasky * . . 4497321936Shselasky * @ 4498321936Shselasky */ 4499321936Shselaskystatic 4500321936Shselaskybool handle_case_0x7aa(struct torus *t, int i, int j, int k) 4501321936Shselasky{ 4502321936Shselasky if (handle_case_0x7ab(t, i, j, k)) 4503321936Shselasky return true; 4504321936Shselasky 4505321936Shselasky if (handle_case_0x7ae(t, i, j, k)) 4506321936Shselasky return true; 4507321936Shselasky 4508321936Shselasky if (handle_case_0x7ba(t, i, j, k)) 4509321936Shselasky return true; 4510321936Shselasky 4511321936Shselasky return handle_case_0x7ea(t, i, j, k); 4512321936Shselasky} 4513321936Shselasky 4514321936Shselasky/* 4515321936Shselasky * 3D case 0x7cc: O 4516321936Shselasky * 4517321936Shselasky * b0: t->sw[i ][j ][k ] 4518321936Shselasky * b1: t->sw[i+1][j ][k ] 4519321936Shselasky * b2: 4520321936Shselasky * b3: O O 4521321936Shselasky * b4: t->sw[i ][j ][k+1] O . . 4522321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 4523321936Shselasky * b6: . . 4524321936Shselasky * b7: . . 4525321936Shselasky * O . 4526321936Shselasky * O . O 4527321936Shselasky * . . 4528321936Shselasky * . . 4529321936Shselasky * . . 4530321936Shselasky * . . 4531321936Shselasky * @ 4532321936Shselasky */ 4533321936Shselaskystatic 4534321936Shselaskybool handle_case_0x7cc(struct torus *t, int i, int j, int k) 4535321936Shselasky{ 4536321936Shselasky if (handle_case_0x7cd(t, i, j, k)) 4537321936Shselasky return true; 4538321936Shselasky 4539321936Shselasky if (handle_case_0x7ce(t, i, j, k)) 4540321936Shselasky return true; 4541321936Shselasky 4542321936Shselasky if (handle_case_0x7dc(t, i, j, k)) 4543321936Shselasky return true; 4544321936Shselasky 4545321936Shselasky return handle_case_0x7ec(t, i, j, k); 4546321936Shselasky} 4547321936Shselasky 4548321936Shselasky/* 4549321936Shselasky * 3D case 0x7f0: O 4550321936Shselasky * 4551321936Shselasky * b0: t->sw[i ][j ][k ] 4552321936Shselasky * b1: t->sw[i+1][j ][k ] 4553321936Shselasky * b2: t->sw[i ][j+1][k ] 4554321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 4555321936Shselasky * b4: O 4556321936Shselasky * b5: . . 4557321936Shselasky * b6: . . 4558321936Shselasky * b7: . . 4559321936Shselasky * . O . 4560321936Shselasky * O O 4561321936Shselasky * . . 4562321936Shselasky * . . 4563321936Shselasky * . . 4564321936Shselasky * . . 4565321936Shselasky * @ 4566321936Shselasky */ 4567321936Shselaskystatic 4568321936Shselaskybool handle_case_0x7f0(struct torus *t, int i, int j, int k) 4569321936Shselasky{ 4570321936Shselasky if (handle_case_0x7f1(t, i, j, k)) 4571321936Shselasky return true; 4572321936Shselasky 4573321936Shselasky if (handle_case_0x7f2(t, i, j, k)) 4574321936Shselasky return true; 4575321936Shselasky 4576321936Shselasky if (handle_case_0x7f4(t, i, j, k)) 4577321936Shselasky return true; 4578321936Shselasky 4579321936Shselasky return handle_case_0x7f8(t, i, j, k); 4580321936Shselasky} 4581321936Shselasky 4582321936Shselasky/* 4583321936Shselasky * Handle the cases where three corners on a single face are missing. 4584321936Shselasky */ 4585321936Shselasky 4586321936Shselasky 4587321936Shselasky/* 4588321936Shselasky * 3D case 0x707: O 4589321936Shselasky * . . . 4590321936Shselasky * b0: . . . 4591321936Shselasky * b1: . . . 4592321936Shselasky * b2: . . . 4593321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 4594321936Shselasky * b4: t->sw[i ][j ][k+1] . O . 4595321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 4596321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 4597321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . 4598321936Shselasky * O 4599321936Shselasky * O O 4600321936Shselasky * 4601321936Shselasky * 4602321936Shselasky * 4603321936Shselasky * 4604321936Shselasky * @ 4605321936Shselasky */ 4606321936Shselaskystatic 4607321936Shselaskybool handle_case_0x707(struct torus *t, int i, int j, int k) 4608321936Shselasky{ 4609321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4610321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4611321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4612321936Shselasky 4613321936Shselasky if (install_tswitch(t, ip1, j, k, 4614321936Shselasky tfind_face_corner(t->sw[ip1][jp1][k], 4615321936Shselasky t->sw[ip1][jp1][kp1], 4616321936Shselasky t->sw[ip1][j][kp1]))) { 4617321936Shselasky return true; 4618321936Shselasky } 4619321936Shselasky log_no_crnr(t, 0x707, i, j, k, ip1, j, k); 4620321936Shselasky 4621321936Shselasky if (install_tswitch(t, i, jp1, k, 4622321936Shselasky tfind_face_corner(t->sw[ip1][jp1][k], 4623321936Shselasky t->sw[ip1][jp1][kp1], 4624321936Shselasky t->sw[i][jp1][kp1]))) { 4625321936Shselasky return true; 4626321936Shselasky } 4627321936Shselasky log_no_crnr(t, 0x707, i, j, k, i, jp1, k); 4628321936Shselasky return false; 4629321936Shselasky} 4630321936Shselasky 4631321936Shselasky/* 4632321936Shselasky * 3D case 0x70b: O 4633321936Shselasky * . . 4634321936Shselasky * b0: . . 4635321936Shselasky * b1: . . 4636321936Shselasky * b2: t->sw[i ][j+1][k ] . . 4637321936Shselasky * b3: O O 4638321936Shselasky * b4: t->sw[i ][j ][k+1] . . O . 4639321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . 4640321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . 4641321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . 4642321936Shselasky * . O 4643321936Shselasky * O O 4644321936Shselasky * 4645321936Shselasky * 4646321936Shselasky * 4647321936Shselasky * 4648321936Shselasky * @ 4649321936Shselasky */ 4650321936Shselaskystatic 4651321936Shselaskybool handle_case_0x70b(struct torus *t, int i, int j, int k) 4652321936Shselasky{ 4653321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4654321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4655321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4656321936Shselasky 4657321936Shselasky if (install_tswitch(t, i, j, k, 4658321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 4659321936Shselasky t->sw[i][jp1][kp1], 4660321936Shselasky t->sw[i][j][kp1]))) { 4661321936Shselasky return true; 4662321936Shselasky } 4663321936Shselasky log_no_crnr(t, 0x70b, i, j, k, i, j, k); 4664321936Shselasky 4665321936Shselasky if (install_tswitch(t, ip1, jp1, k, 4666321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 4667321936Shselasky t->sw[i][jp1][kp1], 4668321936Shselasky t->sw[ip1][jp1][kp1]))) { 4669321936Shselasky return true; 4670321936Shselasky } 4671321936Shselasky log_no_crnr(t, 0x70b, i, j, k, ip1, jp1, k); 4672321936Shselasky return false; 4673321936Shselasky} 4674321936Shselasky 4675321936Shselasky/* 4676321936Shselasky * 3D case 0x70d: O 4677321936Shselasky * . . 4678321936Shselasky * b0: . . 4679321936Shselasky * b1: t->sw[i+1][j ][k ] . . 4680321936Shselasky * b2: . . 4681321936Shselasky * b3: O O 4682321936Shselasky * b4: t->sw[i ][j ][k+1] . O . . 4683321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . 4684321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . 4685321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . 4686321936Shselasky * O . 4687321936Shselasky * O O 4688321936Shselasky * 4689321936Shselasky * 4690321936Shselasky * 4691321936Shselasky * 4692321936Shselasky * @ 4693321936Shselasky */ 4694321936Shselaskystatic 4695321936Shselaskybool handle_case_0x70d(struct torus *t, int i, int j, int k) 4696321936Shselasky{ 4697321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4698321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4699321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4700321936Shselasky 4701321936Shselasky if (install_tswitch(t, i, j, k, 4702321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 4703321936Shselasky t->sw[ip1][j][kp1], 4704321936Shselasky t->sw[i][j][kp1]))) { 4705321936Shselasky return true; 4706321936Shselasky } 4707321936Shselasky log_no_crnr(t, 0x70d, i, j, k, i, j, k); 4708321936Shselasky 4709321936Shselasky if (install_tswitch(t, ip1, jp1, k, 4710321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 4711321936Shselasky t->sw[ip1][j][kp1], 4712321936Shselasky t->sw[ip1][jp1][kp1]))) { 4713321936Shselasky return true; 4714321936Shselasky } 4715321936Shselasky log_no_crnr(t, 0x70d, i, j, k, ip1, jp1, k); 4716321936Shselasky return false; 4717321936Shselasky} 4718321936Shselasky 4719321936Shselasky/* 4720321936Shselasky * 3D case 0x70e: O 4721321936Shselasky * . . 4722321936Shselasky * b0: t->sw[i ][j ][k ] . . 4723321936Shselasky * b1: . . 4724321936Shselasky * b2: . . 4725321936Shselasky * b3: O O 4726321936Shselasky * b4: t->sw[i ][j ][k+1] . O . 4727321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 4728321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 4729321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . 4730321936Shselasky * O 4731321936Shselasky * O . O 4732321936Shselasky * . 4733321936Shselasky * . 4734321936Shselasky * . 4735321936Shselasky * . 4736321936Shselasky * @ 4737321936Shselasky */ 4738321936Shselaskystatic 4739321936Shselaskybool handle_case_0x70e(struct torus *t, int i, int j, int k) 4740321936Shselasky{ 4741321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4742321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4743321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4744321936Shselasky 4745321936Shselasky if (install_tswitch(t, ip1, j, k, 4746321936Shselasky tfind_face_corner(t->sw[i][j][k], 4747321936Shselasky t->sw[i][j][kp1], 4748321936Shselasky t->sw[ip1][j][kp1]))) { 4749321936Shselasky return true; 4750321936Shselasky } 4751321936Shselasky log_no_crnr(t, 0x70e, i, j, k, ip1, j, k); 4752321936Shselasky 4753321936Shselasky if (install_tswitch(t, i, jp1, k, 4754321936Shselasky tfind_face_corner(t->sw[i][j][k], 4755321936Shselasky t->sw[i][j][kp1], 4756321936Shselasky t->sw[i][jp1][kp1]))) { 4757321936Shselasky return true; 4758321936Shselasky } 4759321936Shselasky log_no_crnr(t, 0x70e, i, j, k, i, jp1, k); 4760321936Shselasky return false; 4761321936Shselasky} 4762321936Shselasky 4763321936Shselasky/* 4764321936Shselasky * 3D case 0x713: O 4765321936Shselasky * . . . 4766321936Shselasky * b0: . . . 4767321936Shselasky * b1: . . . 4768321936Shselasky * b2: t->sw[i ][j+1][k ] . . . 4769321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 4770321936Shselasky * b4: . O 4771321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 4772321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 4773321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . 4774321936Shselasky * . . O 4775321936Shselasky * O O 4776321936Shselasky * 4777321936Shselasky * 4778321936Shselasky * 4779321936Shselasky * 4780321936Shselasky * @ 4781321936Shselasky */ 4782321936Shselaskystatic 4783321936Shselaskybool handle_case_0x713(struct torus *t, int i, int j, int k) 4784321936Shselasky{ 4785321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4786321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4787321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4788321936Shselasky 4789321936Shselasky if (install_tswitch(t, ip1, j, k, 4790321936Shselasky tfind_face_corner(t->sw[ip1][jp1][k], 4791321936Shselasky t->sw[ip1][jp1][kp1], 4792321936Shselasky t->sw[ip1][j][kp1]))) { 4793321936Shselasky return true; 4794321936Shselasky } 4795321936Shselasky log_no_crnr(t, 0x713, i, j, k, ip1, j, k); 4796321936Shselasky 4797321936Shselasky if (install_tswitch(t, i, j, kp1, 4798321936Shselasky tfind_face_corner(t->sw[ip1][j][kp1], 4799321936Shselasky t->sw[ip1][jp1][kp1], 4800321936Shselasky t->sw[i][jp1][kp1]))) { 4801321936Shselasky return true; 4802321936Shselasky } 4803321936Shselasky log_no_crnr(t, 0x713, i, j, k, i, j, kp1); 4804321936Shselasky return false; 4805321936Shselasky} 4806321936Shselasky 4807321936Shselasky/* 4808321936Shselasky * 3D case 0x715: O 4809321936Shselasky * . . . 4810321936Shselasky * b0: . . . 4811321936Shselasky * b1: t->sw[i+1][j ][k ] . . . 4812321936Shselasky * b2: . . . 4813321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 4814321936Shselasky * b4: O . 4815321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 4816321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 4817321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . 4818321936Shselasky * O . . 4819321936Shselasky * O O 4820321936Shselasky * 4821321936Shselasky * 4822321936Shselasky * 4823321936Shselasky * 4824321936Shselasky * @ 4825321936Shselasky */ 4826321936Shselaskystatic 4827321936Shselaskybool handle_case_0x715(struct torus *t, int i, int j, int k) 4828321936Shselasky{ 4829321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4830321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4831321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4832321936Shselasky 4833321936Shselasky if (install_tswitch(t, i, jp1, k, 4834321936Shselasky tfind_face_corner(t->sw[ip1][jp1][k], 4835321936Shselasky t->sw[ip1][jp1][kp1], 4836321936Shselasky t->sw[i][jp1][kp1]))) { 4837321936Shselasky return true; 4838321936Shselasky } 4839321936Shselasky log_no_crnr(t, 0x715, i, j, k, i, jp1, k); 4840321936Shselasky 4841321936Shselasky if (install_tswitch(t, i, j, kp1, 4842321936Shselasky tfind_face_corner(t->sw[ip1][j][kp1], 4843321936Shselasky t->sw[ip1][jp1][kp1], 4844321936Shselasky t->sw[i][jp1][kp1]))) { 4845321936Shselasky return true; 4846321936Shselasky } 4847321936Shselasky log_no_crnr(t, 0x715, i, j, k, i, j, kp1); 4848321936Shselasky return false; 4849321936Shselasky} 4850321936Shselasky 4851321936Shselasky/* 4852321936Shselasky * 3D case 0x723: O 4853321936Shselasky * . . 4854321936Shselasky * b0: . . 4855321936Shselasky * b1: . . 4856321936Shselasky * b2: t->sw[i ][j+1][k ] . . 4857321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 4858321936Shselasky * b4: t->sw[i ][j ][k+1] . . O 4859321936Shselasky * b5: . . . 4860321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 4861321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . 4862321936Shselasky * . . O 4863321936Shselasky * O O 4864321936Shselasky * 4865321936Shselasky * 4866321936Shselasky * 4867321936Shselasky * 4868321936Shselasky * @ 4869321936Shselasky */ 4870321936Shselaskystatic 4871321936Shselaskybool handle_case_0x723(struct torus *t, int i, int j, int k) 4872321936Shselasky{ 4873321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4874321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4875321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4876321936Shselasky 4877321936Shselasky if (install_tswitch(t, i, j, k, 4878321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 4879321936Shselasky t->sw[i][jp1][kp1], 4880321936Shselasky t->sw[i][j][kp1]))) { 4881321936Shselasky return true; 4882321936Shselasky } 4883321936Shselasky log_no_crnr(t, 0x723, i, j, k, i, j, k); 4884321936Shselasky 4885321936Shselasky if (install_tswitch(t, ip1, j, kp1, 4886321936Shselasky tfind_face_corner(t->sw[i][j][kp1], 4887321936Shselasky t->sw[i][jp1][kp1], 4888321936Shselasky t->sw[ip1][jp1][kp1]))) { 4889321936Shselasky return true; 4890321936Shselasky } 4891321936Shselasky log_no_crnr(t, 0x723, i, j, k, ip1, j, kp1); 4892321936Shselasky return false; 4893321936Shselasky} 4894321936Shselasky 4895321936Shselasky/* 4896321936Shselasky * 3D case 0x72a: O 4897321936Shselasky * . 4898321936Shselasky * b0: t->sw[i ][j ][k ] . 4899321936Shselasky * b1: . 4900321936Shselasky * b2: t->sw[i ][j+1][k ] . 4901321936Shselasky * b3: O O 4902321936Shselasky * b4: t->sw[i ][j ][k+1] . . O 4903321936Shselasky * b5: . . 4904321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 4905321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . 4906321936Shselasky * . O 4907321936Shselasky * O . O 4908321936Shselasky * . . 4909321936Shselasky * . . 4910321936Shselasky * . . 4911321936Shselasky * . . 4912321936Shselasky * @ 4913321936Shselasky */ 4914321936Shselaskystatic 4915321936Shselaskybool handle_case_0x72a(struct torus *t, int i, int j, int k) 4916321936Shselasky{ 4917321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4918321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4919321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4920321936Shselasky 4921321936Shselasky if (install_tswitch(t, ip1, jp1, k, 4922321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 4923321936Shselasky t->sw[i][jp1][kp1], 4924321936Shselasky t->sw[ip1][jp1][kp1]))) { 4925321936Shselasky return true; 4926321936Shselasky } 4927321936Shselasky log_no_crnr(t, 0x72a, i, j, k, ip1, jp1, k); 4928321936Shselasky 4929321936Shselasky if (install_tswitch(t, ip1, j, kp1, 4930321936Shselasky tfind_face_corner(t->sw[i][j][kp1], 4931321936Shselasky t->sw[i][jp1][kp1], 4932321936Shselasky t->sw[ip1][jp1][kp1]))) { 4933321936Shselasky return true; 4934321936Shselasky } 4935321936Shselasky log_no_crnr(t, 0x72a, i, j, k, ip1, j, kp1); 4936321936Shselasky return false; 4937321936Shselasky} 4938321936Shselasky 4939321936Shselasky/* 4940321936Shselasky * 3D case 0x731: O 4941321936Shselasky * . . 4942321936Shselasky * b0: . . 4943321936Shselasky * b1: t->sw[i+1][j ][k ] . . 4944321936Shselasky * b2: t->sw[i ][j+1][k ] . . 4945321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 4946321936Shselasky * b4: . O 4947321936Shselasky * b5: . . . 4948321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . 4949321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . 4950321936Shselasky * . . O . 4951321936Shselasky * O O 4952321936Shselasky * 4953321936Shselasky * 4954321936Shselasky * 4955321936Shselasky * 4956321936Shselasky * @ 4957321936Shselasky */ 4958321936Shselaskystatic 4959321936Shselaskybool handle_case_0x731(struct torus *t, int i, int j, int k) 4960321936Shselasky{ 4961321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 4962321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 4963321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 4964321936Shselasky 4965321936Shselasky if (install_tswitch(t, i, j, k, 4966321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 4967321936Shselasky t->sw[ip1][jp1][k], 4968321936Shselasky t->sw[i][jp1][k]))) { 4969321936Shselasky return true; 4970321936Shselasky } 4971321936Shselasky log_no_crnr(t, 0x731, i, j, k, i, j, k); 4972321936Shselasky 4973321936Shselasky if (install_tswitch(t, ip1, j, kp1, 4974321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 4975321936Shselasky t->sw[ip1][jp1][k], 4976321936Shselasky t->sw[ip1][jp1][kp1]))) { 4977321936Shselasky return true; 4978321936Shselasky } 4979321936Shselasky log_no_crnr(t, 0x731, i, j, k, ip1, j, kp1); 4980321936Shselasky return false; 4981321936Shselasky} 4982321936Shselasky 4983321936Shselasky/* 4984321936Shselasky * 3D case 0x732: O 4985321936Shselasky * . . 4986321936Shselasky * b0: t->sw[i ][j ][k ] . . 4987321936Shselasky * b1: . . 4988321936Shselasky * b2: t->sw[i ][j+1][k ] . . 4989321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 4990321936Shselasky * b4: . O 4991321936Shselasky * b5: . . 4992321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 4993321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . 4994321936Shselasky * . . O 4995321936Shselasky * O O 4996321936Shselasky * . 4997321936Shselasky * . 4998321936Shselasky * . 4999321936Shselasky * . 5000321936Shselasky * @ 5001321936Shselasky */ 5002321936Shselaskystatic 5003321936Shselaskybool handle_case_0x732(struct torus *t, int i, int j, int k) 5004321936Shselasky{ 5005321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5006321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5007321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5008321936Shselasky 5009321936Shselasky if (install_tswitch(t, ip1, j, k, 5010321936Shselasky tfind_face_corner(t->sw[i][j][k], 5011321936Shselasky t->sw[i][jp1][k], 5012321936Shselasky t->sw[ip1][jp1][k]))) { 5013321936Shselasky return true; 5014321936Shselasky } 5015321936Shselasky log_no_crnr(t, 0x732, i, j, k, ip1, j, k); 5016321936Shselasky 5017321936Shselasky if (install_tswitch(t, i, j, kp1, 5018321936Shselasky tfind_face_corner(t->sw[i][j][k], 5019321936Shselasky t->sw[i][jp1][k], 5020321936Shselasky t->sw[i][jp1][kp1]))) { 5021321936Shselasky return true; 5022321936Shselasky } 5023321936Shselasky log_no_crnr(t, 0x732, i, j, k, i, j, kp1); 5024321936Shselasky return false; 5025321936Shselasky} 5026321936Shselasky 5027321936Shselasky/* 5028321936Shselasky * 3D case 0x745: O 5029321936Shselasky * . . 5030321936Shselasky * b0: . . 5031321936Shselasky * b1: t->sw[i+1][j ][k ] . . 5032321936Shselasky * b2: . . 5033321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 5034321936Shselasky * b4: t->sw[i ][j ][k+1] O . . 5035321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . 5036321936Shselasky * b6: . . 5037321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . 5038321936Shselasky * O . . 5039321936Shselasky * O O 5040321936Shselasky * 5041321936Shselasky * 5042321936Shselasky * 5043321936Shselasky * 5044321936Shselasky * @ 5045321936Shselasky */ 5046321936Shselaskystatic 5047321936Shselaskybool handle_case_0x745(struct torus *t, int i, int j, int k) 5048321936Shselasky{ 5049321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5050321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5051321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5052321936Shselasky 5053321936Shselasky if (install_tswitch(t, i, j, k, 5054321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 5055321936Shselasky t->sw[ip1][j][kp1], 5056321936Shselasky t->sw[i][j][kp1]))) { 5057321936Shselasky return true; 5058321936Shselasky } 5059321936Shselasky log_no_crnr(t, 0x745, i, j, k, i, j, k); 5060321936Shselasky 5061321936Shselasky if (install_tswitch(t, i, jp1, kp1, 5062321936Shselasky tfind_face_corner(t->sw[i][j][kp1], 5063321936Shselasky t->sw[ip1][j][kp1], 5064321936Shselasky t->sw[ip1][jp1][kp1]))) { 5065321936Shselasky return true; 5066321936Shselasky } 5067321936Shselasky log_no_crnr(t, 0x745, i, j, k, i, jp1, kp1); 5068321936Shselasky return false; 5069321936Shselasky} 5070321936Shselasky 5071321936Shselasky/* 5072321936Shselasky * 3D case 0x74c: O 5073321936Shselasky * . 5074321936Shselasky * b0: t->sw[i ][j ][k ] . 5075321936Shselasky * b1: t->sw[i+1][j ][k ] . 5076321936Shselasky * b2: . 5077321936Shselasky * b3: O O 5078321936Shselasky * b4: t->sw[i ][j ][k+1] O . . 5079321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 5080321936Shselasky * b6: . . 5081321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . 5082321936Shselasky * O . 5083321936Shselasky * O . O 5084321936Shselasky * . . 5085321936Shselasky * . . 5086321936Shselasky * . . 5087321936Shselasky * . . 5088321936Shselasky * @ 5089321936Shselasky */ 5090321936Shselaskystatic 5091321936Shselaskybool handle_case_0x74c(struct torus *t, int i, int j, int k) 5092321936Shselasky{ 5093321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5094321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5095321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5096321936Shselasky 5097321936Shselasky if (install_tswitch(t, ip1, jp1, k, 5098321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 5099321936Shselasky t->sw[ip1][j][kp1], 5100321936Shselasky t->sw[ip1][jp1][kp1]))) { 5101321936Shselasky return true; 5102321936Shselasky } 5103321936Shselasky log_no_crnr(t, 0x74c, i, j, k, ip1, jp1, k); 5104321936Shselasky 5105321936Shselasky if (install_tswitch(t, i, jp1, kp1, 5106321936Shselasky tfind_face_corner(t->sw[i][j][kp1], 5107321936Shselasky t->sw[ip1][j][kp1], 5108321936Shselasky t->sw[ip1][jp1][kp1]))) { 5109321936Shselasky return true; 5110321936Shselasky } 5111321936Shselasky log_no_crnr(t, 0x74c, i, j, k, i, jp1, kp1); 5112321936Shselasky return false; 5113321936Shselasky} 5114321936Shselasky 5115321936Shselasky/* 5116321936Shselasky * 3D case 0x751: O 5117321936Shselasky * . . 5118321936Shselasky * b0: . . 5119321936Shselasky * b1: t->sw[i+1][j ][k ] . . 5120321936Shselasky * b2: t->sw[i ][j+1][k ] . . 5121321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 5122321936Shselasky * b4: O . 5123321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . 5124321936Shselasky * b6: . . . 5125321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . 5126321936Shselasky * . O . . 5127321936Shselasky * O O 5128321936Shselasky * 5129321936Shselasky * 5130321936Shselasky * 5131321936Shselasky * 5132321936Shselasky * @ 5133321936Shselasky */ 5134321936Shselaskystatic 5135321936Shselaskybool handle_case_0x751(struct torus *t, int i, int j, int k) 5136321936Shselasky{ 5137321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5138321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5139321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5140321936Shselasky 5141321936Shselasky if (install_tswitch(t, i, j, k, 5142321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 5143321936Shselasky t->sw[ip1][jp1][k], 5144321936Shselasky t->sw[i][jp1][k]))) { 5145321936Shselasky return true; 5146321936Shselasky } 5147321936Shselasky log_no_crnr(t, 0x751, i, j, k, i, j, k); 5148321936Shselasky 5149321936Shselasky if (install_tswitch(t, i, jp1, kp1, 5150321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 5151321936Shselasky t->sw[ip1][jp1][k], 5152321936Shselasky t->sw[ip1][jp1][kp1]))) { 5153321936Shselasky return true; 5154321936Shselasky } 5155321936Shselasky log_no_crnr(t, 0x751, i, j, k, i, jp1, kp1); 5156321936Shselasky return false; 5157321936Shselasky} 5158321936Shselasky 5159321936Shselasky/* 5160321936Shselasky * 3D case 0x754: O 5161321936Shselasky * . . 5162321936Shselasky * b0: t->sw[i ][j ][k ] . . 5163321936Shselasky * b1: t->sw[i+1][j ][k ] . . 5164321936Shselasky * b2: . . 5165321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 5166321936Shselasky * b4: O . 5167321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 5168321936Shselasky * b6: . . 5169321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . 5170321936Shselasky * O . . 5171321936Shselasky * O O 5172321936Shselasky * . 5173321936Shselasky * . 5174321936Shselasky * . 5175321936Shselasky * . 5176321936Shselasky * @ 5177321936Shselasky */ 5178321936Shselaskystatic 5179321936Shselaskybool handle_case_0x754(struct torus *t, int i, int j, int k) 5180321936Shselasky{ 5181321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5182321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5183321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5184321936Shselasky 5185321936Shselasky if (install_tswitch(t, i, jp1, k, 5186321936Shselasky tfind_face_corner(t->sw[i][j][k], 5187321936Shselasky t->sw[ip1][j][k], 5188321936Shselasky t->sw[ip1][jp1][k]))) { 5189321936Shselasky return true; 5190321936Shselasky } 5191321936Shselasky log_no_crnr(t, 0x754, i, j, k, i, jp1, k); 5192321936Shselasky 5193321936Shselasky if (install_tswitch(t, i, j, kp1, 5194321936Shselasky tfind_face_corner(t->sw[i][j][k], 5195321936Shselasky t->sw[ip1][j][k], 5196321936Shselasky t->sw[ip1][j][kp1]))) { 5197321936Shselasky return true; 5198321936Shselasky } 5199321936Shselasky log_no_crnr(t, 0x754, i, j, k, i, j, kp1); 5200321936Shselasky return false; 5201321936Shselasky} 5202321936Shselasky 5203321936Shselasky/* 5204321936Shselasky * 3D case 0x770: O 5205321936Shselasky * . 5206321936Shselasky * b0: t->sw[i ][j ][k ] . 5207321936Shselasky * b1: t->sw[i+1][j ][k ] . 5208321936Shselasky * b2: t->sw[i ][j+1][k ] . 5209321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 5210321936Shselasky * b4: O 5211321936Shselasky * b5: . . 5212321936Shselasky * b6: . . 5213321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . 5214321936Shselasky * . O . 5215321936Shselasky * O O 5216321936Shselasky * . . 5217321936Shselasky * . . 5218321936Shselasky * . . 5219321936Shselasky * . . 5220321936Shselasky * @ 5221321936Shselasky */ 5222321936Shselaskystatic 5223321936Shselaskybool handle_case_0x770(struct torus *t, int i, int j, int k) 5224321936Shselasky{ 5225321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5226321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5227321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5228321936Shselasky 5229321936Shselasky if (install_tswitch(t, ip1, j, kp1, 5230321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 5231321936Shselasky t->sw[ip1][jp1][k], 5232321936Shselasky t->sw[ip1][jp1][kp1]))) { 5233321936Shselasky return true; 5234321936Shselasky } 5235321936Shselasky log_no_crnr(t, 0x770, i, j, k, ip1, j, kp1); 5236321936Shselasky 5237321936Shselasky if (install_tswitch(t, i, jp1, kp1, 5238321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 5239321936Shselasky t->sw[ip1][jp1][k], 5240321936Shselasky t->sw[ip1][jp1][kp1]))) { 5241321936Shselasky return true; 5242321936Shselasky } 5243321936Shselasky log_no_crnr(t, 0x770, i, j, k, i, jp1, kp1); 5244321936Shselasky return false; 5245321936Shselasky} 5246321936Shselasky 5247321936Shselasky/* 5248321936Shselasky * 3D case 0x78a: O 5249321936Shselasky * 5250321936Shselasky * b0: t->sw[i ][j ][k ] 5251321936Shselasky * b1: 5252321936Shselasky * b2: t->sw[i ][j+1][k ] 5253321936Shselasky * b3: O O 5254321936Shselasky * b4: t->sw[i ][j ][k+1] . . O . 5255321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . 5256321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . 5257321936Shselasky * b7: . . . 5258321936Shselasky * . O 5259321936Shselasky * O . O 5260321936Shselasky * . . 5261321936Shselasky * . . 5262321936Shselasky * . . 5263321936Shselasky * . . 5264321936Shselasky * @ 5265321936Shselasky */ 5266321936Shselaskystatic 5267321936Shselaskybool handle_case_0x78a(struct torus *t, int i, int j, int k) 5268321936Shselasky{ 5269321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5270321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5271321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5272321936Shselasky 5273321936Shselasky if (install_tswitch(t, ip1, j, k, 5274321936Shselasky tfind_face_corner(t->sw[i][j][k], 5275321936Shselasky t->sw[i][j][kp1], 5276321936Shselasky t->sw[ip1][j][kp1]))) { 5277321936Shselasky return true; 5278321936Shselasky } 5279321936Shselasky log_no_crnr(t, 0x78a, i, j, k, ip1, j, k); 5280321936Shselasky 5281321936Shselasky if (install_tswitch(t, ip1, jp1, kp1, 5282321936Shselasky tfind_face_corner(t->sw[ip1][j][kp1], 5283321936Shselasky t->sw[i][j][kp1], 5284321936Shselasky t->sw[i][jp1][kp1]))) { 5285321936Shselasky return true; 5286321936Shselasky } 5287321936Shselasky log_no_crnr(t, 0x78a, i, j, k, ip1, jp1, kp1); 5288321936Shselasky return false; 5289321936Shselasky} 5290321936Shselasky 5291321936Shselasky/* 5292321936Shselasky * 3D case 0x78c: O 5293321936Shselasky * 5294321936Shselasky * b0: t->sw[i ][j ][k ] 5295321936Shselasky * b1: t->sw[i+1][j ][k ] 5296321936Shselasky * b2: 5297321936Shselasky * b3: O O 5298321936Shselasky * b4: t->sw[i ][j ][k+1] . O . . 5299321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . 5300321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . 5301321936Shselasky * b7: . . . 5302321936Shselasky * O . 5303321936Shselasky * O . O 5304321936Shselasky * . . 5305321936Shselasky * . . 5306321936Shselasky * . . 5307321936Shselasky * . . 5308321936Shselasky * @ 5309321936Shselasky */ 5310321936Shselaskystatic 5311321936Shselaskybool handle_case_0x78c(struct torus *t, int i, int j, int k) 5312321936Shselasky{ 5313321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5314321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5315321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5316321936Shselasky 5317321936Shselasky if (install_tswitch(t, i, jp1, k, 5318321936Shselasky tfind_face_corner(t->sw[i][j][k], 5319321936Shselasky t->sw[i][j][kp1], 5320321936Shselasky t->sw[i][jp1][kp1]))) { 5321321936Shselasky return true; 5322321936Shselasky } 5323321936Shselasky log_no_crnr(t, 0x78c, i, j, k, i, jp1, k); 5324321936Shselasky 5325321936Shselasky if (install_tswitch(t, ip1, jp1, kp1, 5326321936Shselasky tfind_face_corner(t->sw[ip1][j][kp1], 5327321936Shselasky t->sw[i][j][kp1], 5328321936Shselasky t->sw[i][jp1][kp1]))) { 5329321936Shselasky return true; 5330321936Shselasky } 5331321936Shselasky log_no_crnr(t, 0x78c, i, j, k, ip1, jp1, kp1); 5332321936Shselasky return false; 5333321936Shselasky} 5334321936Shselasky 5335321936Shselasky/* 5336321936Shselasky * 3D case 0x7a2: O 5337321936Shselasky * 5338321936Shselasky * b0: t->sw[i ][j ][k ] 5339321936Shselasky * b1: 5340321936Shselasky * b2: t->sw[i ][j+1][k ] 5341321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 5342321936Shselasky * b4: t->sw[i ][j ][k+1] . . O 5343321936Shselasky * b5: . . . 5344321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 5345321936Shselasky * b7: . . . 5346321936Shselasky * . . O 5347321936Shselasky * O . O 5348321936Shselasky * . . 5349321936Shselasky * . . 5350321936Shselasky * . . 5351321936Shselasky * . . 5352321936Shselasky * @ 5353321936Shselasky */ 5354321936Shselaskystatic 5355321936Shselaskybool handle_case_0x7a2(struct torus *t, int i, int j, int k) 5356321936Shselasky{ 5357321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5358321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5359321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5360321936Shselasky 5361321936Shselasky if (install_tswitch(t, ip1, j, k, 5362321936Shselasky tfind_face_corner(t->sw[i][j][k], 5363321936Shselasky t->sw[i][jp1][k], 5364321936Shselasky t->sw[ip1][jp1][k]))) { 5365321936Shselasky return true; 5366321936Shselasky } 5367321936Shselasky log_no_crnr(t, 0x7a2, i, j, k, ip1, j, k); 5368321936Shselasky 5369321936Shselasky if (install_tswitch(t, ip1, jp1, kp1, 5370321936Shselasky tfind_face_corner(t->sw[i][jp1][kp1], 5371321936Shselasky t->sw[i][jp1][k], 5372321936Shselasky t->sw[ip1][jp1][k]))) { 5373321936Shselasky return true; 5374321936Shselasky } 5375321936Shselasky log_no_crnr(t, 0x7a2, i, j, k, ip1, jp1, kp1); 5376321936Shselasky return false; 5377321936Shselasky} 5378321936Shselasky 5379321936Shselasky/* 5380321936Shselasky * 3D case 0x7a8: O 5381321936Shselasky * 5382321936Shselasky * b0: t->sw[i ][j ][k ] 5383321936Shselasky * b1: t->sw[ip1][j ][k ] 5384321936Shselasky * b2: t->sw[i ][j+1][k ] 5385321936Shselasky * b3: O O 5386321936Shselasky * b4: t->sw[i ][j ][k+1] . . O 5387321936Shselasky * b5: . . 5388321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 5389321936Shselasky * b7: . . 5390321936Shselasky * . O 5391321936Shselasky * O . O 5392321936Shselasky * . . . 5393321936Shselasky * . . . 5394321936Shselasky * . . . 5395321936Shselasky * . . . 5396321936Shselasky * @ 5397321936Shselasky */ 5398321936Shselaskystatic 5399321936Shselaskybool handle_case_0x7a8(struct torus *t, int i, int j, int k) 5400321936Shselasky{ 5401321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5402321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5403321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5404321936Shselasky 5405321936Shselasky if (install_tswitch(t, ip1, jp1, k, 5406321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 5407321936Shselasky t->sw[i][j][k], 5408321936Shselasky t->sw[i][jp1][k]))) { 5409321936Shselasky return true; 5410321936Shselasky } 5411321936Shselasky log_no_crnr(t, 0x7a8, i, j, k, ip1, jp1, k); 5412321936Shselasky 5413321936Shselasky if (install_tswitch(t, ip1, j, kp1, 5414321936Shselasky tfind_face_corner(t->sw[i][j][kp1], 5415321936Shselasky t->sw[i][j][k], 5416321936Shselasky t->sw[ip1][j][k]))) { 5417321936Shselasky return true; 5418321936Shselasky } 5419321936Shselasky log_no_crnr(t, 0x7a8, i, j, k, ip1, j, kp1); 5420321936Shselasky return false; 5421321936Shselasky} 5422321936Shselasky 5423321936Shselasky/* 5424321936Shselasky * 3D case 0x7b0: O 5425321936Shselasky * 5426321936Shselasky * b0: t->sw[i ][j ][k ] 5427321936Shselasky * b1: t->sw[i+1][j ][k ] 5428321936Shselasky * b2: t->sw[i ][j+1][k ] 5429321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 5430321936Shselasky * b4: . O 5431321936Shselasky * b5: . . . 5432321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . 5433321936Shselasky * b7: . . . 5434321936Shselasky * . . O . 5435321936Shselasky * O O 5436321936Shselasky * . . 5437321936Shselasky * . . 5438321936Shselasky * . . 5439321936Shselasky * . . 5440321936Shselasky * @ 5441321936Shselasky */ 5442321936Shselaskystatic 5443321936Shselaskybool handle_case_0x7b0(struct torus *t, int i, int j, int k) 5444321936Shselasky{ 5445321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5446321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5447321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5448321936Shselasky 5449321936Shselasky if (install_tswitch(t, i, j, kp1, 5450321936Shselasky tfind_face_corner(t->sw[i][j][k], 5451321936Shselasky t->sw[i][jp1][k], 5452321936Shselasky t->sw[i][jp1][kp1]))) { 5453321936Shselasky return true; 5454321936Shselasky } 5455321936Shselasky log_no_crnr(t, 0x7b0, i, j, k, i, j, kp1); 5456321936Shselasky 5457321936Shselasky if (install_tswitch(t, ip1, jp1, kp1, 5458321936Shselasky tfind_face_corner(t->sw[i][jp1][kp1], 5459321936Shselasky t->sw[i][jp1][k], 5460321936Shselasky t->sw[ip1][jp1][k]))) { 5461321936Shselasky return true; 5462321936Shselasky } 5463321936Shselasky log_no_crnr(t, 0x7b0, i, j, k, ip1, jp1, kp1); 5464321936Shselasky return false; 5465321936Shselasky} 5466321936Shselasky 5467321936Shselasky/* 5468321936Shselasky * 3D case 0x7c4: O 5469321936Shselasky * 5470321936Shselasky * b0: t->sw[i ][j ][k ] 5471321936Shselasky * b1: t->sw[i+1][j ][k ] 5472321936Shselasky * b2: 5473321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 5474321936Shselasky * b4: t->sw[i ][j ][k+1] O . . 5475321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . 5476321936Shselasky * b6: . . 5477321936Shselasky * b7: . . . 5478321936Shselasky * O . . 5479321936Shselasky * O . O 5480321936Shselasky * . . 5481321936Shselasky * . . 5482321936Shselasky * . . 5483321936Shselasky * . . 5484321936Shselasky * @ 5485321936Shselasky */ 5486321936Shselaskystatic 5487321936Shselaskybool handle_case_0x7c4(struct torus *t, int i, int j, int k) 5488321936Shselasky{ 5489321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5490321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5491321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5492321936Shselasky 5493321936Shselasky if (install_tswitch(t, i, jp1, k, 5494321936Shselasky tfind_face_corner(t->sw[i][j][k], 5495321936Shselasky t->sw[ip1][j][k], 5496321936Shselasky t->sw[ip1][jp1][k]))) { 5497321936Shselasky return true; 5498321936Shselasky } 5499321936Shselasky log_no_crnr(t, 0x7c4, i, j, k, i, jp1, k); 5500321936Shselasky 5501321936Shselasky if (install_tswitch(t, ip1, jp1, kp1, 5502321936Shselasky tfind_face_corner(t->sw[ip1][j][kp1], 5503321936Shselasky t->sw[ip1][j][k], 5504321936Shselasky t->sw[ip1][jp1][k]))) { 5505321936Shselasky return true; 5506321936Shselasky } 5507321936Shselasky log_no_crnr(t, 0x7c4, i, j, k, ip1, jp1, kp1); 5508321936Shselasky return false; 5509321936Shselasky} 5510321936Shselasky 5511321936Shselasky/* 5512321936Shselasky * 3D case 0x7c8: O 5513321936Shselasky * 5514321936Shselasky * b0: t->sw[i ][j ][k ] 5515321936Shselasky * b1: t->sw[i+1][j ][k ] 5516321936Shselasky * b2: t->sw[i ][j+1][k ] 5517321936Shselasky * b3: O O 5518321936Shselasky * b4: t->sw[i ][j ][k+1] O . . 5519321936Shselasky * b5: t->sw[i+1][j ][k+1] . . 5520321936Shselasky * b6: . . 5521321936Shselasky * b7: . . 5522321936Shselasky * O . 5523321936Shselasky * O . O 5524321936Shselasky * . . . 5525321936Shselasky * . . . 5526321936Shselasky * . . . 5527321936Shselasky * . . . 5528321936Shselasky * @ 5529321936Shselasky */ 5530321936Shselaskystatic 5531321936Shselaskybool handle_case_0x7c8(struct torus *t, int i, int j, int k) 5532321936Shselasky{ 5533321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5534321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5535321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5536321936Shselasky 5537321936Shselasky if (install_tswitch(t, ip1, jp1, k, 5538321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 5539321936Shselasky t->sw[i][j][k], 5540321936Shselasky t->sw[i][jp1][k]))) { 5541321936Shselasky return true; 5542321936Shselasky } 5543321936Shselasky log_no_crnr(t, 0x7c8, i, j, k, ip1, jp1, k); 5544321936Shselasky 5545321936Shselasky if (install_tswitch(t, i, jp1, kp1, 5546321936Shselasky tfind_face_corner(t->sw[i][j][kp1], 5547321936Shselasky t->sw[i][j][k], 5548321936Shselasky t->sw[i][jp1][k]))) { 5549321936Shselasky return true; 5550321936Shselasky } 5551321936Shselasky log_no_crnr(t, 0x7c8, i, j, k, i, jp1, kp1); 5552321936Shselasky return false; 5553321936Shselasky} 5554321936Shselasky 5555321936Shselasky/* 5556321936Shselasky * 3D case 0x7d0: O 5557321936Shselasky * 5558321936Shselasky * b0: t->sw[i ][j ][k ] 5559321936Shselasky * b1: t->sw[i+1][j ][k ] 5560321936Shselasky * b2: t->sw[i ][j+1][k ] 5561321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 5562321936Shselasky * b4: O . 5563321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . 5564321936Shselasky * b6: . . . 5565321936Shselasky * b7: . . . 5566321936Shselasky * . O . . 5567321936Shselasky * O O 5568321936Shselasky * . . 5569321936Shselasky * . . 5570321936Shselasky * . . 5571321936Shselasky * . . 5572321936Shselasky * @ 5573321936Shselasky */ 5574321936Shselaskystatic 5575321936Shselaskybool handle_case_0x7d0(struct torus *t, int i, int j, int k) 5576321936Shselasky{ 5577321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5578321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5579321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5580321936Shselasky 5581321936Shselasky if (install_tswitch(t, i, j, kp1, 5582321936Shselasky tfind_face_corner(t->sw[i][j][k], 5583321936Shselasky t->sw[ip1][j][k], 5584321936Shselasky t->sw[ip1][j][kp1]))) { 5585321936Shselasky return true; 5586321936Shselasky } 5587321936Shselasky log_no_crnr(t, 0x7d0, i, j, k, i, j, kp1); 5588321936Shselasky 5589321936Shselasky if (install_tswitch(t, ip1, jp1, kp1, 5590321936Shselasky tfind_face_corner(t->sw[ip1][j][kp1], 5591321936Shselasky t->sw[ip1][j][k], 5592321936Shselasky t->sw[ip1][jp1][k]))) { 5593321936Shselasky return true; 5594321936Shselasky } 5595321936Shselasky log_no_crnr(t, 0x7d0, i, j, k, ip1, jp1, kp1); 5596321936Shselasky return false; 5597321936Shselasky} 5598321936Shselasky 5599321936Shselasky/* 5600321936Shselasky * 3D case 0x7e0: O 5601321936Shselasky * 5602321936Shselasky * b0: t->sw[i ][j ][k ] 5603321936Shselasky * b1: t->sw[i+1][j ][k ] 5604321936Shselasky * b2: t->sw[i ][j+1][k ] 5605321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 5606321936Shselasky * b4: t->sw[i ][j ][k+1] O 5607321936Shselasky * b5: . . 5608321936Shselasky * b6: . . 5609321936Shselasky * b7: . . 5610321936Shselasky * . O . 5611321936Shselasky * O . O 5612321936Shselasky * . . . 5613321936Shselasky * . . . 5614321936Shselasky * . . . 5615321936Shselasky * . . . 5616321936Shselasky * @ 5617321936Shselasky */ 5618321936Shselaskystatic 5619321936Shselaskybool handle_case_0x7e0(struct torus *t, int i, int j, int k) 5620321936Shselasky{ 5621321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5622321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5623321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5624321936Shselasky 5625321936Shselasky if (install_tswitch(t, ip1, j, kp1, 5626321936Shselasky tfind_face_corner(t->sw[i][j][kp1], 5627321936Shselasky t->sw[i][j][k], 5628321936Shselasky t->sw[ip1][j][k]))) { 5629321936Shselasky return true; 5630321936Shselasky } 5631321936Shselasky log_no_crnr(t, 0x7e0, i, j, k, ip1, j, kp1); 5632321936Shselasky 5633321936Shselasky if (install_tswitch(t, i, jp1, kp1, 5634321936Shselasky tfind_face_corner(t->sw[i][j][kp1], 5635321936Shselasky t->sw[i][j][k], 5636321936Shselasky t->sw[i][jp1][k]))) { 5637321936Shselasky return true; 5638321936Shselasky } 5639321936Shselasky log_no_crnr(t, 0x7e0, i, j, k, i, jp1, kp1); 5640321936Shselasky return false; 5641321936Shselasky} 5642321936Shselasky 5643321936Shselasky/* 5644321936Shselasky * Handle the cases where two corners on a single edge are missing. 5645321936Shselasky */ 5646321936Shselasky 5647321936Shselasky/* 5648321936Shselasky * 3D case 0x703: O 5649321936Shselasky * . . . 5650321936Shselasky * b0: . . . 5651321936Shselasky * b1: . . . 5652321936Shselasky * b2: t->sw[i ][j+1][k ] . . . 5653321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 5654321936Shselasky * b4: t->sw[i ][j ][k+1] . . O . 5655321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . . 5656321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . 5657321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . . 5658321936Shselasky * . . O 5659321936Shselasky * O O 5660321936Shselasky * 5661321936Shselasky * 5662321936Shselasky * 5663321936Shselasky * 5664321936Shselasky * @ 5665321936Shselasky */ 5666321936Shselaskystatic 5667321936Shselaskybool handle_case_0x703(struct torus *t, int i, int j, int k) 5668321936Shselasky{ 5669321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5670321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5671321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5672321936Shselasky 5673321936Shselasky if (install_tswitch(t, i, j, k, 5674321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 5675321936Shselasky t->sw[i][jp1][kp1], 5676321936Shselasky t->sw[i][j][kp1]))) { 5677321936Shselasky return true; 5678321936Shselasky } 5679321936Shselasky log_no_crnr(t, 0x703, i, j, k, i, j, k); 5680321936Shselasky 5681321936Shselasky if (install_tswitch(t, ip1, j, k, 5682321936Shselasky tfind_face_corner(t->sw[ip1][jp1][k], 5683321936Shselasky t->sw[ip1][jp1][kp1], 5684321936Shselasky t->sw[ip1][j][kp1]))) { 5685321936Shselasky return true; 5686321936Shselasky } 5687321936Shselasky log_no_crnr(t, 0x703, i, j, k, ip1, j, k); 5688321936Shselasky return false; 5689321936Shselasky} 5690321936Shselasky 5691321936Shselasky/* 5692321936Shselasky * 3D case 0x705: O 5693321936Shselasky * . . . 5694321936Shselasky * b0: . . . 5695321936Shselasky * b1: t->sw[i+1][j ][k ] . . . 5696321936Shselasky * b2: . . . 5697321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 5698321936Shselasky * b4: t->sw[i ][j ][k+1] . O . . 5699321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . . 5700321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . 5701321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . . 5702321936Shselasky * O . . 5703321936Shselasky * O O 5704321936Shselasky * 5705321936Shselasky * 5706321936Shselasky * 5707321936Shselasky * 5708321936Shselasky * @ 5709321936Shselasky */ 5710321936Shselaskystatic 5711321936Shselaskybool handle_case_0x705(struct torus *t, int i, int j, int k) 5712321936Shselasky{ 5713321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5714321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5715321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5716321936Shselasky 5717321936Shselasky if (install_tswitch(t, i, j, k, 5718321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 5719321936Shselasky t->sw[ip1][j][kp1], 5720321936Shselasky t->sw[i][j][kp1]))) { 5721321936Shselasky return true; 5722321936Shselasky } 5723321936Shselasky log_no_crnr(t, 0x705, i, j, k, i, j, k); 5724321936Shselasky 5725321936Shselasky if (install_tswitch(t, i, jp1, k, 5726321936Shselasky tfind_face_corner(t->sw[ip1][jp1][k], 5727321936Shselasky t->sw[ip1][jp1][kp1], 5728321936Shselasky t->sw[i][jp1][kp1]))) { 5729321936Shselasky return true; 5730321936Shselasky } 5731321936Shselasky log_no_crnr(t, 0x705, i, j, k, i, jp1, k); 5732321936Shselasky return false; 5733321936Shselasky} 5734321936Shselasky 5735321936Shselasky/* 5736321936Shselasky * 3D case 0x70a: O 5737321936Shselasky * . . . 5738321936Shselasky * b0: t->sw[i ][j ][k ] . . 5739321936Shselasky * b1: . . 5740321936Shselasky * b2: t->sw[i ][j+1][k ] . . 5741321936Shselasky * b3: O O 5742321936Shselasky * b4: t->sw[i ][j ][k+1] . . O . 5743321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . 5744321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . 5745321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . 5746321936Shselasky * . O 5747321936Shselasky * O . O 5748321936Shselasky * . . 5749321936Shselasky * . . 5750321936Shselasky * . . 5751321936Shselasky * . . 5752321936Shselasky * @ 5753321936Shselasky */ 5754321936Shselaskystatic 5755321936Shselaskybool handle_case_0x70a(struct torus *t, int i, int j, int k) 5756321936Shselasky{ 5757321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5758321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5759321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5760321936Shselasky 5761321936Shselasky if (install_tswitch(t, ip1, j, k, 5762321936Shselasky tfind_face_corner(t->sw[i][j][k], 5763321936Shselasky t->sw[i][j][kp1], 5764321936Shselasky t->sw[ip1][j][kp1]))) { 5765321936Shselasky return true; 5766321936Shselasky } 5767321936Shselasky log_no_crnr(t, 0x70a, i, j, k, ip1, j, k); 5768321936Shselasky 5769321936Shselasky if (install_tswitch(t, ip1, jp1, k, 5770321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 5771321936Shselasky t->sw[i][jp1][kp1], 5772321936Shselasky t->sw[ip1][jp1][kp1]))) { 5773321936Shselasky return true; 5774321936Shselasky } 5775321936Shselasky log_no_crnr(t, 0x70a, i, j, k, ip1, jp1, k); 5776321936Shselasky return false; 5777321936Shselasky} 5778321936Shselasky 5779321936Shselasky/* 5780321936Shselasky * 3D case 0x70c: O 5781321936Shselasky * . . 5782321936Shselasky * b0: t->sw[i ][j ][k ] . . 5783321936Shselasky * b1: t->sw[i+1][j ][k ] . . 5784321936Shselasky * b2: . . 5785321936Shselasky * b3: O O 5786321936Shselasky * b4: t->sw[i ][j ][k+1] . O . . 5787321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . 5788321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . 5789321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . 5790321936Shselasky * O . 5791321936Shselasky * O . O 5792321936Shselasky * . . 5793321936Shselasky * . . 5794321936Shselasky * . . 5795321936Shselasky * . . 5796321936Shselasky * @ 5797321936Shselasky */ 5798321936Shselaskystatic 5799321936Shselaskybool handle_case_0x70c(struct torus *t, int i, int j, int k) 5800321936Shselasky{ 5801321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5802321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5803321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5804321936Shselasky 5805321936Shselasky if (install_tswitch(t, i, jp1, k, 5806321936Shselasky tfind_face_corner(t->sw[i][j][k], 5807321936Shselasky t->sw[i][j][kp1], 5808321936Shselasky t->sw[i][jp1][kp1]))) { 5809321936Shselasky return true; 5810321936Shselasky } 5811321936Shselasky log_no_crnr(t, 0x70c, i, j, k, i, jp1, k); 5812321936Shselasky 5813321936Shselasky if (install_tswitch(t, ip1, jp1, k, 5814321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 5815321936Shselasky t->sw[ip1][j][kp1], 5816321936Shselasky t->sw[ip1][jp1][kp1]))) { 5817321936Shselasky return true; 5818321936Shselasky } 5819321936Shselasky log_no_crnr(t, 0x70c, i, j, k, ip1, jp1, k); 5820321936Shselasky return false; 5821321936Shselasky} 5822321936Shselasky 5823321936Shselasky/* 5824321936Shselasky * 3D case 0x711: O 5825321936Shselasky * . . . 5826321936Shselasky * b0: . . . 5827321936Shselasky * b1: t->sw[i+1][j ][k ] . . . 5828321936Shselasky * b2: t->sw[i ][j+1][k ] . . . 5829321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 5830321936Shselasky * b4: . O . 5831321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . . 5832321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . . 5833321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . . 5834321936Shselasky * . . O . . 5835321936Shselasky * O O 5836321936Shselasky * 5837321936Shselasky * 5838321936Shselasky * 5839321936Shselasky * 5840321936Shselasky * @ 5841321936Shselasky */ 5842321936Shselaskystatic 5843321936Shselaskybool handle_case_0x711(struct torus *t, int i, int j, int k) 5844321936Shselasky{ 5845321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5846321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5847321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5848321936Shselasky 5849321936Shselasky if (install_tswitch(t, i, j, k, 5850321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 5851321936Shselasky t->sw[ip1][jp1][k], 5852321936Shselasky t->sw[i][jp1][k]))) { 5853321936Shselasky return true; 5854321936Shselasky } 5855321936Shselasky log_no_crnr(t, 0x711, i, j, k, i, j, k); 5856321936Shselasky 5857321936Shselasky if (install_tswitch(t, i, j, kp1, 5858321936Shselasky tfind_face_corner(t->sw[ip1][j][kp1], 5859321936Shselasky t->sw[ip1][jp1][kp1], 5860321936Shselasky t->sw[i][jp1][kp1]))) { 5861321936Shselasky return true; 5862321936Shselasky } 5863321936Shselasky log_no_crnr(t, 0x711, i, j, k, i, j, kp1); 5864321936Shselasky return false; 5865321936Shselasky} 5866321936Shselasky 5867321936Shselasky/* 5868321936Shselasky * 3D case 0x722: O 5869321936Shselasky * . . 5870321936Shselasky * b0: t->sw[i ][j ][k ] . . 5871321936Shselasky * b1: . . 5872321936Shselasky * b2: t->sw[i ][j+1][k ] . . 5873321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 5874321936Shselasky * b4: t->sw[i ][j ][k+1] . . O 5875321936Shselasky * b5: . . . 5876321936Shselasky * b6: t->sw[i ][j+1][k+1] . . 5877321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . 5878321936Shselasky * . . O 5879321936Shselasky * O . O 5880321936Shselasky * . . 5881321936Shselasky * . . 5882321936Shselasky * . . 5883321936Shselasky * . . 5884321936Shselasky * @ 5885321936Shselasky */ 5886321936Shselaskystatic 5887321936Shselaskybool handle_case_0x722(struct torus *t, int i, int j, int k) 5888321936Shselasky{ 5889321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5890321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5891321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5892321936Shselasky 5893321936Shselasky if (install_tswitch(t, ip1, j, k, 5894321936Shselasky tfind_face_corner(t->sw[i][j][k], 5895321936Shselasky t->sw[i][jp1][k], 5896321936Shselasky t->sw[ip1][jp1][k]))) { 5897321936Shselasky return true; 5898321936Shselasky } 5899321936Shselasky log_no_crnr(t, 0x722, i, j, k, ip1, j, k); 5900321936Shselasky 5901321936Shselasky if (install_tswitch(t, ip1, j, kp1, 5902321936Shselasky tfind_face_corner(t->sw[i][j][kp1], 5903321936Shselasky t->sw[i][jp1][kp1], 5904321936Shselasky t->sw[ip1][jp1][kp1]))) { 5905321936Shselasky return true; 5906321936Shselasky } 5907321936Shselasky log_no_crnr(t, 0x722, i, j, k, ip1, j, kp1); 5908321936Shselasky return false; 5909321936Shselasky} 5910321936Shselasky 5911321936Shselasky/* 5912321936Shselasky * 3D case 0x730: O 5913321936Shselasky * . . 5914321936Shselasky * b0: t->sw[i ][j ][k ] . . 5915321936Shselasky * b1: t->sw[i+1][j ][k ] . . 5916321936Shselasky * b2: t->sw[i ][j+1][k ] . . 5917321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 5918321936Shselasky * b4: . O 5919321936Shselasky * b5: . . . 5920321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . 5921321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . 5922321936Shselasky * . . O . 5923321936Shselasky * O O 5924321936Shselasky * . . 5925321936Shselasky * . . 5926321936Shselasky * . . 5927321936Shselasky * . . 5928321936Shselasky * @ 5929321936Shselasky */ 5930321936Shselaskystatic 5931321936Shselaskybool handle_case_0x730(struct torus *t, int i, int j, int k) 5932321936Shselasky{ 5933321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5934321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5935321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5936321936Shselasky 5937321936Shselasky if (install_tswitch(t, i, j, kp1, 5938321936Shselasky tfind_face_corner(t->sw[i][j][k], 5939321936Shselasky t->sw[i][jp1][k], 5940321936Shselasky t->sw[i][jp1][kp1]))) { 5941321936Shselasky return true; 5942321936Shselasky } 5943321936Shselasky log_no_crnr(t, 0x730, i, j, k, i, j, kp1); 5944321936Shselasky 5945321936Shselasky if (install_tswitch(t, ip1, j, kp1, 5946321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 5947321936Shselasky t->sw[ip1][jp1][k], 5948321936Shselasky t->sw[ip1][jp1][kp1]))) { 5949321936Shselasky return true; 5950321936Shselasky } 5951321936Shselasky log_no_crnr(t, 0x730, i, j, k, ip1, j, kp1); 5952321936Shselasky return false; 5953321936Shselasky} 5954321936Shselasky 5955321936Shselasky/* 5956321936Shselasky * 3D case 0x744: O 5957321936Shselasky * . . 5958321936Shselasky * b0: t->sw[i ][j ][k ] . . 5959321936Shselasky * b1: t->sw[i+1][j ][k ] . . 5960321936Shselasky * b2: . . 5961321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 5962321936Shselasky * b4: t->sw[i ][j ][k+1] O . . 5963321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . 5964321936Shselasky * b6: . . 5965321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . 5966321936Shselasky * O . . 5967321936Shselasky * O . O 5968321936Shselasky * . . 5969321936Shselasky * . . 5970321936Shselasky * . . 5971321936Shselasky * . . 5972321936Shselasky * @ 5973321936Shselasky */ 5974321936Shselaskystatic 5975321936Shselaskybool handle_case_0x744(struct torus *t, int i, int j, int k) 5976321936Shselasky{ 5977321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 5978321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 5979321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 5980321936Shselasky 5981321936Shselasky if (install_tswitch(t, i, jp1, k, 5982321936Shselasky tfind_face_corner(t->sw[i][j][k], 5983321936Shselasky t->sw[ip1][j][k], 5984321936Shselasky t->sw[ip1][jp1][k]))) { 5985321936Shselasky return true; 5986321936Shselasky } 5987321936Shselasky log_no_crnr(t, 0x744, i, j, k, i, jp1, k); 5988321936Shselasky 5989321936Shselasky if (install_tswitch(t, i, jp1, kp1, 5990321936Shselasky tfind_face_corner(t->sw[i][j][kp1], 5991321936Shselasky t->sw[ip1][j][kp1], 5992321936Shselasky t->sw[ip1][jp1][kp1]))) { 5993321936Shselasky return true; 5994321936Shselasky } 5995321936Shselasky log_no_crnr(t, 0x744, i, j, k, i, jp1, kp1); 5996321936Shselasky return false; 5997321936Shselasky} 5998321936Shselasky 5999321936Shselasky/* 6000321936Shselasky * 3D case 0x750: O 6001321936Shselasky * . . 6002321936Shselasky * b0: t->sw[i ][j ][k ] . . 6003321936Shselasky * b1: t->sw[i+1][j ][k ] . . 6004321936Shselasky * b2: t->sw[i ][j+1][k ] . . 6005321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 6006321936Shselasky * b4: O . 6007321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . 6008321936Shselasky * b6: . . . 6009321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . 6010321936Shselasky * . O . . 6011321936Shselasky * O O 6012321936Shselasky * . . 6013321936Shselasky * . . 6014321936Shselasky * . . 6015321936Shselasky * . . 6016321936Shselasky * @ 6017321936Shselasky */ 6018321936Shselaskystatic 6019321936Shselaskybool handle_case_0x750(struct torus *t, int i, int j, int k) 6020321936Shselasky{ 6021321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 6022321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 6023321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 6024321936Shselasky 6025321936Shselasky if (install_tswitch(t, i, j, kp1, 6026321936Shselasky tfind_face_corner(t->sw[i][j][k], 6027321936Shselasky t->sw[ip1][j][k], 6028321936Shselasky t->sw[ip1][j][kp1]))) { 6029321936Shselasky return true; 6030321936Shselasky } 6031321936Shselasky log_no_crnr(t, 0x750, i, j, k, i, j, kp1); 6032321936Shselasky 6033321936Shselasky if (install_tswitch(t, i, jp1, kp1, 6034321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 6035321936Shselasky t->sw[ip1][jp1][k], 6036321936Shselasky t->sw[ip1][jp1][kp1]))) { 6037321936Shselasky return true; 6038321936Shselasky } 6039321936Shselasky log_no_crnr(t, 0x750, i, j, k, i, jp1, kp1); 6040321936Shselasky return false; 6041321936Shselasky} 6042321936Shselasky 6043321936Shselasky/* 6044321936Shselasky * 3D case 0x788: O 6045321936Shselasky * 6046321936Shselasky * b0: t->sw[i ][j ][k ] 6047321936Shselasky * b1: t->sw[ip1][j ][k ] 6048321936Shselasky * b2: t->sw[i ][j+1][k ] 6049321936Shselasky * b3: O O 6050321936Shselasky * b4: t->sw[i ][j ][k+1] . . O . . 6051321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . . 6052321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . . 6053321936Shselasky * b7: . . . . 6054321936Shselasky * . O . 6055321936Shselasky * O . O 6056321936Shselasky * . . . 6057321936Shselasky * . . . 6058321936Shselasky * . . . 6059321936Shselasky * . . . 6060321936Shselasky * @ 6061321936Shselasky */ 6062321936Shselaskystatic 6063321936Shselaskybool handle_case_0x788(struct torus *t, int i, int j, int k) 6064321936Shselasky{ 6065321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 6066321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 6067321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 6068321936Shselasky 6069321936Shselasky if (install_tswitch(t, ip1, jp1, k, 6070321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 6071321936Shselasky t->sw[i][j][k], 6072321936Shselasky t->sw[i][jp1][k]))) { 6073321936Shselasky return true; 6074321936Shselasky } 6075321936Shselasky log_no_crnr(t, 0x788, i, j, k, ip1, jp1, k); 6076321936Shselasky 6077321936Shselasky if (install_tswitch(t, ip1, jp1, kp1, 6078321936Shselasky tfind_face_corner(t->sw[ip1][j][kp1], 6079321936Shselasky t->sw[i][j][kp1], 6080321936Shselasky t->sw[i][jp1][kp1]))) { 6081321936Shselasky return true; 6082321936Shselasky } 6083321936Shselasky log_no_crnr(t, 0x788, i, j, k, ip1, jp1, kp1); 6084321936Shselasky return false; 6085321936Shselasky} 6086321936Shselasky 6087321936Shselasky/* 6088321936Shselasky * 3D case 0x7a0: O 6089321936Shselasky * 6090321936Shselasky * b0: t->sw[i ][j ][k ] 6091321936Shselasky * b1: t->sw[i+1][j ][k ] 6092321936Shselasky * b2: t->sw[i ][j+1][k ] 6093321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 6094321936Shselasky * b4: t->sw[i ][j ][k+1] . . O 6095321936Shselasky * b5: . . . . 6096321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . 6097321936Shselasky * b7: . . . . 6098321936Shselasky * . . O . 6099321936Shselasky * O . O 6100321936Shselasky * . . . 6101321936Shselasky * . . . 6102321936Shselasky * . . . 6103321936Shselasky * . . . 6104321936Shselasky * @ 6105321936Shselasky */ 6106321936Shselaskystatic 6107321936Shselaskybool handle_case_0x7a0(struct torus *t, int i, int j, int k) 6108321936Shselasky{ 6109321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 6110321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 6111321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 6112321936Shselasky 6113321936Shselasky if (install_tswitch(t, ip1, j, kp1, 6114321936Shselasky tfind_face_corner(t->sw[i][j][kp1], 6115321936Shselasky t->sw[i][j][k], 6116321936Shselasky t->sw[ip1][j][k]))) { 6117321936Shselasky return true; 6118321936Shselasky } 6119321936Shselasky log_no_crnr(t, 0x7a0, i, j, k, ip1, j, kp1); 6120321936Shselasky 6121321936Shselasky if (install_tswitch(t, ip1, jp1, kp1, 6122321936Shselasky tfind_face_corner(t->sw[i][jp1][kp1], 6123321936Shselasky t->sw[i][jp1][k], 6124321936Shselasky t->sw[ip1][jp1][k]))) { 6125321936Shselasky return true; 6126321936Shselasky } 6127321936Shselasky log_no_crnr(t, 0x7a0, i, j, k, ip1, jp1, kp1); 6128321936Shselasky return false; 6129321936Shselasky} 6130321936Shselasky 6131321936Shselasky/* 6132321936Shselasky * 3D case 0x7c0: O 6133321936Shselasky * 6134321936Shselasky * b0: t->sw[i ][j ][k ] 6135321936Shselasky * b1: t->sw[i+1][j ][k ] 6136321936Shselasky * b2: t->sw[i ][j+1][k ] 6137321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 6138321936Shselasky * b4: t->sw[i ][j ][k+1] O . . 6139321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . . 6140321936Shselasky * b6: . . . 6141321936Shselasky * b7: . . . . 6142321936Shselasky * . O . . 6143321936Shselasky * O . O 6144321936Shselasky * . . . 6145321936Shselasky * . . . 6146321936Shselasky * . . . 6147321936Shselasky * . . . 6148321936Shselasky * @ 6149321936Shselasky */ 6150321936Shselaskystatic 6151321936Shselaskybool handle_case_0x7c0(struct torus *t, int i, int j, int k) 6152321936Shselasky{ 6153321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 6154321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 6155321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 6156321936Shselasky 6157321936Shselasky if (install_tswitch(t, i, jp1, kp1, 6158321936Shselasky tfind_face_corner(t->sw[i][j][kp1], 6159321936Shselasky t->sw[i][j][k], 6160321936Shselasky t->sw[i][jp1][k]))) { 6161321936Shselasky return true; 6162321936Shselasky } 6163321936Shselasky log_no_crnr(t, 0x7c0, i, j, k, i, jp1, kp1); 6164321936Shselasky 6165321936Shselasky if (install_tswitch(t, ip1, jp1, kp1, 6166321936Shselasky tfind_face_corner(t->sw[ip1][j][kp1], 6167321936Shselasky t->sw[ip1][j][k], 6168321936Shselasky t->sw[ip1][jp1][k]))) { 6169321936Shselasky return true; 6170321936Shselasky } 6171321936Shselasky log_no_crnr(t, 0x7c0, i, j, k, ip1, jp1, kp1); 6172321936Shselasky return false; 6173321936Shselasky} 6174321936Shselasky 6175321936Shselasky/* 6176321936Shselasky * Handle the cases where a single corner is missing. 6177321936Shselasky */ 6178321936Shselasky 6179321936Shselasky/* 6180321936Shselasky * 3D case 0x701: O 6181321936Shselasky * . . . 6182321936Shselasky * b0: . . . 6183321936Shselasky * b1: t->sw[i+1][j ][k ] . . . 6184321936Shselasky * b2: t->sw[i ][j+1][k ] . . . 6185321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 6186321936Shselasky * b4: t->sw[i ][j ][k+1] . . O . . 6187321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . . . . 6188321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . . 6189321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . . . . 6190321936Shselasky * . . O . . 6191321936Shselasky * O O 6192321936Shselasky * 6193321936Shselasky * 6194321936Shselasky * 6195321936Shselasky * 6196321936Shselasky * @ 6197321936Shselasky */ 6198321936Shselaskystatic 6199321936Shselaskybool handle_case_0x701(struct torus *t, int i, int j, int k) 6200321936Shselasky{ 6201321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 6202321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 6203321936Shselasky 6204321936Shselasky if (install_tswitch(t, i, j, k, 6205321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 6206321936Shselasky t->sw[ip1][jp1][k], 6207321936Shselasky t->sw[ip1][j][k]))) { 6208321936Shselasky return true; 6209321936Shselasky } 6210321936Shselasky log_no_crnr(t, 0x701, i, j, k, i, j, k); 6211321936Shselasky return false; 6212321936Shselasky} 6213321936Shselasky 6214321936Shselasky/* 6215321936Shselasky * 3D case 0x702: O 6216321936Shselasky * . . . 6217321936Shselasky * b0: t->sw[i ][j ][k ] . . . 6218321936Shselasky * b1: . . . 6219321936Shselasky * b2: t->sw[i ][j+1][k ] . . . 6220321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 6221321936Shselasky * b4: t->sw[i ][j ][k+1] . . O . 6222321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . . 6223321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . 6224321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . . 6225321936Shselasky * . . O 6226321936Shselasky * O . O 6227321936Shselasky * . . 6228321936Shselasky * . . 6229321936Shselasky * . . 6230321936Shselasky * . . 6231321936Shselasky * @ 6232321936Shselasky */ 6233321936Shselaskystatic 6234321936Shselaskybool handle_case_0x702(struct torus *t, int i, int j, int k) 6235321936Shselasky{ 6236321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 6237321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 6238321936Shselasky 6239321936Shselasky if (install_tswitch(t, ip1, j, k, 6240321936Shselasky tfind_face_corner(t->sw[i][j][k], 6241321936Shselasky t->sw[i][j][kp1], 6242321936Shselasky t->sw[ip1][j][kp1]))) { 6243321936Shselasky return true; 6244321936Shselasky } 6245321936Shselasky log_no_crnr(t, 0x702, i, j, k, ip1, j, k); 6246321936Shselasky return false; 6247321936Shselasky} 6248321936Shselasky 6249321936Shselasky/* 6250321936Shselasky * 3D case 0x704: O 6251321936Shselasky * . . . 6252321936Shselasky * b0: t->sw[i ][j ][k ] . . . 6253321936Shselasky * b1: t->sw[i+1][j ][k ] . . . 6254321936Shselasky * b2: . . . 6255321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 6256321936Shselasky * b4: t->sw[i ][j ][k+1] . O . . 6257321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . . 6258321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . 6259321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . . 6260321936Shselasky * O . . 6261321936Shselasky * O . O 6262321936Shselasky * . . 6263321936Shselasky * . . 6264321936Shselasky * . . 6265321936Shselasky * . . 6266321936Shselasky * @ 6267321936Shselasky */ 6268321936Shselaskystatic 6269321936Shselaskybool handle_case_0x704(struct torus *t, int i, int j, int k) 6270321936Shselasky{ 6271321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 6272321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 6273321936Shselasky 6274321936Shselasky if (install_tswitch(t, i, jp1, k, 6275321936Shselasky tfind_face_corner(t->sw[i][j][k], 6276321936Shselasky t->sw[i][j][kp1], 6277321936Shselasky t->sw[i][jp1][kp1]))) { 6278321936Shselasky return true; 6279321936Shselasky } 6280321936Shselasky log_no_crnr(t, 0x704, i, j, k, i, jp1, k); 6281321936Shselasky return false; 6282321936Shselasky} 6283321936Shselasky 6284321936Shselasky/* 6285321936Shselasky * 3D case 0x708: O 6286321936Shselasky * . . 6287321936Shselasky * b0: t->sw[i ][j ][k ] . . 6288321936Shselasky * b1: t->sw[i+1][j ][k ] . . 6289321936Shselasky * b2: t->sw[i ][j+1][k ] . . 6290321936Shselasky * b3: O O 6291321936Shselasky * b4: t->sw[i ][j ][k+1] . . O . . 6292321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . . 6293321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . . 6294321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . . 6295321936Shselasky * . O . 6296321936Shselasky * O . O 6297321936Shselasky * . . . 6298321936Shselasky * . . . 6299321936Shselasky * . . . 6300321936Shselasky * . . . 6301321936Shselasky * @ 6302321936Shselasky */ 6303321936Shselaskystatic 6304321936Shselaskybool handle_case_0x708(struct torus *t, int i, int j, int k) 6305321936Shselasky{ 6306321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 6307321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 6308321936Shselasky 6309321936Shselasky if (install_tswitch(t, ip1, jp1, k, 6310321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 6311321936Shselasky t->sw[i][j][k], 6312321936Shselasky t->sw[ip1][j][k]))) { 6313321936Shselasky return true; 6314321936Shselasky } 6315321936Shselasky log_no_crnr(t, 0x708, i, j, k, ip1, jp1, k); 6316321936Shselasky return false; 6317321936Shselasky} 6318321936Shselasky 6319321936Shselasky/* 6320321936Shselasky * 3D case 0x710: O 6321321936Shselasky * . . . 6322321936Shselasky * b0: t->sw[i ][j ][k ] . . . 6323321936Shselasky * b1: t->sw[i+1][j ][k ] . . . 6324321936Shselasky * b2: t->sw[i ][j+1][k ] . . . 6325321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 6326321936Shselasky * b4: . O . 6327321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . . 6328321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . . 6329321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . . 6330321936Shselasky * . . O . . 6331321936Shselasky * O O 6332321936Shselasky * . . 6333321936Shselasky * . . 6334321936Shselasky * . . 6335321936Shselasky * . . 6336321936Shselasky * @ 6337321936Shselasky */ 6338321936Shselaskystatic 6339321936Shselaskybool handle_case_0x710(struct torus *t, int i, int j, int k) 6340321936Shselasky{ 6341321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 6342321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 6343321936Shselasky 6344321936Shselasky if (install_tswitch(t, i, j, kp1, 6345321936Shselasky tfind_face_corner(t->sw[i][j][k], 6346321936Shselasky t->sw[ip1][j][k], 6347321936Shselasky t->sw[ip1][j][kp1]))) { 6348321936Shselasky return true; 6349321936Shselasky } 6350321936Shselasky log_no_crnr(t, 0x710, i, j, k, i, j, kp1); 6351321936Shselasky return false; 6352321936Shselasky} 6353321936Shselasky 6354321936Shselasky/* 6355321936Shselasky * 3D case 0x720: O 6356321936Shselasky * . . 6357321936Shselasky * b0: t->sw[i ][j ][k ] . . 6358321936Shselasky * b1: t->sw[i+1][j ][k ] . . 6359321936Shselasky * b2: t->sw[i ][j+1][k ] . . 6360321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 6361321936Shselasky * b4: t->sw[i ][j ][k+1] . . O 6362321936Shselasky * b5: . . . . 6363321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . 6364321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . . 6365321936Shselasky * . . O . 6366321936Shselasky * O . O 6367321936Shselasky * . . . 6368321936Shselasky * . . . 6369321936Shselasky * . . . 6370321936Shselasky * . . . 6371321936Shselasky * @ 6372321936Shselasky */ 6373321936Shselaskystatic 6374321936Shselaskybool handle_case_0x720(struct torus *t, int i, int j, int k) 6375321936Shselasky{ 6376321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 6377321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 6378321936Shselasky 6379321936Shselasky if (install_tswitch(t, ip1, j, kp1, 6380321936Shselasky tfind_face_corner(t->sw[ip1][j][k], 6381321936Shselasky t->sw[i][j][k], 6382321936Shselasky t->sw[i][j][kp1]))) { 6383321936Shselasky return true; 6384321936Shselasky } 6385321936Shselasky log_no_crnr(t, 0x720, i, j, k, ip1, j, kp1); 6386321936Shselasky return false; 6387321936Shselasky} 6388321936Shselasky 6389321936Shselasky/* 6390321936Shselasky * 3D case 0x740: O 6391321936Shselasky * . . 6392321936Shselasky * b0: t->sw[i ][j ][k ] . . 6393321936Shselasky * b1: t->sw[i+1][j ][k ] . . 6394321936Shselasky * b2: t->sw[i ][j+1][k ] . . 6395321936Shselasky * b3: t->sw[i+1][j+1][k ] O . O 6396321936Shselasky * b4: t->sw[i ][j ][k+1] O . . 6397321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . . 6398321936Shselasky * b6: . . . 6399321936Shselasky * b7: t->sw[i+1][j+1][k+1] . . . . 6400321936Shselasky * . O . . 6401321936Shselasky * O . O 6402321936Shselasky * . . . 6403321936Shselasky * . . . 6404321936Shselasky * . . . 6405321936Shselasky * . . . 6406321936Shselasky * @ 6407321936Shselasky */ 6408321936Shselaskystatic 6409321936Shselaskybool handle_case_0x740(struct torus *t, int i, int j, int k) 6410321936Shselasky{ 6411321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 6412321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 6413321936Shselasky 6414321936Shselasky if (install_tswitch(t, i, jp1, kp1, 6415321936Shselasky tfind_face_corner(t->sw[i][jp1][k], 6416321936Shselasky t->sw[i][j][k], 6417321936Shselasky t->sw[i][j][kp1]))) { 6418321936Shselasky return true; 6419321936Shselasky } 6420321936Shselasky log_no_crnr(t, 0x740, i, j, k, i, jp1, kp1); 6421321936Shselasky return false; 6422321936Shselasky} 6423321936Shselasky 6424321936Shselasky/* 6425321936Shselasky * 3D case 0x780: O 6426321936Shselasky * 6427321936Shselasky * b0: t->sw[i ][j ][k ] 6428321936Shselasky * b1: t->sw[i+1][j ][k ] 6429321936Shselasky * b2: t->sw[i ][j+1][k ] 6430321936Shselasky * b3: t->sw[i+1][j+1][k ] O O 6431321936Shselasky * b4: t->sw[i ][j ][k+1] . . O . . 6432321936Shselasky * b5: t->sw[i+1][j ][k+1] . . . . . . 6433321936Shselasky * b6: t->sw[i ][j+1][k+1] . . . . 6434321936Shselasky * b7: . . . . . . 6435321936Shselasky * . . O . . 6436321936Shselasky * O . O 6437321936Shselasky * . . . 6438321936Shselasky * . . . 6439321936Shselasky * . . . 6440321936Shselasky * . . . 6441321936Shselasky * @ 6442321936Shselasky */ 6443321936Shselaskystatic 6444321936Shselaskybool handle_case_0x780(struct torus *t, int i, int j, int k) 6445321936Shselasky{ 6446321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 6447321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 6448321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 6449321936Shselasky 6450321936Shselasky if (install_tswitch(t, ip1, jp1, kp1, 6451321936Shselasky tfind_face_corner(t->sw[i][jp1][kp1], 6452321936Shselasky t->sw[i][j][kp1], 6453321936Shselasky t->sw[ip1][j][kp1]))) { 6454321936Shselasky return true; 6455321936Shselasky } 6456321936Shselasky log_no_crnr(t, 0x780, i, j, k, ip1, jp1, kp1); 6457321936Shselasky return false; 6458321936Shselasky} 6459321936Shselasky 6460321936Shselasky/* 6461321936Shselasky * Make sure links between all known torus/mesh switches are installed. 6462321936Shselasky * 6463321936Shselasky * We don't have to worry about links that wrap on a mesh coordinate, as 6464321936Shselasky * there shouldn't be any; if there are it indicates an input error. 6465321936Shselasky */ 6466321936Shselaskystatic 6467321936Shselaskyvoid check_tlinks(struct torus *t, int i, int j, int k) 6468321936Shselasky{ 6469321936Shselasky struct t_switch ****sw = t->sw; 6470321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 6471321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 6472321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 6473321936Shselasky 6474321936Shselasky /* 6475321936Shselasky * Don't waste time/code checking return status of link_tswitches() 6476321936Shselasky * here. It is unlikely to fail, and the result of any failure here 6477321936Shselasky * will be caught elsewhere anyway. 6478321936Shselasky */ 6479321936Shselasky if (sw[i][j][k] && sw[ip1][j][k]) 6480321936Shselasky link_tswitches(t, 0, sw[i][j][k], sw[ip1][j][k]); 6481321936Shselasky 6482321936Shselasky if (sw[i][jp1][k] && sw[ip1][jp1][k]) 6483321936Shselasky link_tswitches(t, 0, sw[i][jp1][k], sw[ip1][jp1][k]); 6484321936Shselasky 6485321936Shselasky if (sw[i][j][kp1] && sw[ip1][j][kp1]) 6486321936Shselasky link_tswitches(t, 0, sw[i][j][kp1], sw[ip1][j][kp1]); 6487321936Shselasky 6488321936Shselasky if (sw[i][jp1][kp1] && sw[ip1][jp1][kp1]) 6489321936Shselasky link_tswitches(t, 0, sw[i][jp1][kp1], sw[ip1][jp1][kp1]); 6490321936Shselasky 6491321936Shselasky 6492321936Shselasky if (sw[i][j][k] && sw[i][jp1][k]) 6493321936Shselasky link_tswitches(t, 1, sw[i][j][k], sw[i][jp1][k]); 6494321936Shselasky 6495321936Shselasky if (sw[ip1][j][k] && sw[ip1][jp1][k]) 6496321936Shselasky link_tswitches(t, 1, sw[ip1][j][k], sw[ip1][jp1][k]); 6497321936Shselasky 6498321936Shselasky if (sw[i][j][kp1] && sw[i][jp1][kp1]) 6499321936Shselasky link_tswitches(t, 1, sw[i][j][kp1], sw[i][jp1][kp1]); 6500321936Shselasky 6501321936Shselasky if (sw[ip1][j][kp1] && sw[ip1][jp1][kp1]) 6502321936Shselasky link_tswitches(t, 1, sw[ip1][j][kp1], sw[ip1][jp1][kp1]); 6503321936Shselasky 6504321936Shselasky 6505321936Shselasky if (sw[i][j][k] && sw[i][j][kp1]) 6506321936Shselasky link_tswitches(t, 2, sw[i][j][k], sw[i][j][kp1]); 6507321936Shselasky 6508321936Shselasky if (sw[ip1][j][k] && sw[ip1][j][kp1]) 6509321936Shselasky link_tswitches(t, 2, sw[ip1][j][k], sw[ip1][j][kp1]); 6510321936Shselasky 6511321936Shselasky if (sw[i][jp1][k] && sw[i][jp1][kp1]) 6512321936Shselasky link_tswitches(t, 2, sw[i][jp1][k], sw[i][jp1][kp1]); 6513321936Shselasky 6514321936Shselasky if (sw[ip1][jp1][k] && sw[ip1][jp1][kp1]) 6515321936Shselasky link_tswitches(t, 2, sw[ip1][jp1][k], sw[ip1][jp1][kp1]); 6516321936Shselasky} 6517321936Shselasky 6518321936Shselaskystatic 6519321936Shselaskyvoid locate_sw(struct torus *t, int i, int j, int k) 6520321936Shselasky{ 6521321936Shselasky unsigned fp; 6522321936Shselasky bool success; 6523321936Shselasky 6524321936Shselasky i = canonicalize(i, t->x_sz); 6525321936Shselasky j = canonicalize(j, t->y_sz); 6526321936Shselasky k = canonicalize(k, t->z_sz); 6527321936Shselasky 6528321936Shselasky /* 6529321936Shselasky * By definition, if a coordinate direction is meshed, we don't 6530321936Shselasky * allow it to wrap to zero. 6531321936Shselasky */ 6532321936Shselasky if (t->flags & X_MESH) { 6533321936Shselasky int ip1 = canonicalize(i + 1, t->x_sz); 6534321936Shselasky if (ip1 < i) 6535321936Shselasky goto out; 6536321936Shselasky } 6537321936Shselasky if (t->flags & Y_MESH) { 6538321936Shselasky int jp1 = canonicalize(j + 1, t->y_sz); 6539321936Shselasky if (jp1 < j) 6540321936Shselasky goto out; 6541321936Shselasky } 6542321936Shselasky if (t->flags & Z_MESH) { 6543321936Shselasky int kp1 = canonicalize(k + 1, t->z_sz); 6544321936Shselasky if (kp1 < k) 6545321936Shselasky goto out; 6546321936Shselasky } 6547321936Shselasky /* 6548321936Shselasky * There are various reasons that the links are not installed between 6549321936Shselasky * known torus switches. These include cases where the search for 6550321936Shselasky * new switches only partially succeeds due to missing switches, and 6551321936Shselasky * cases where we haven't processed this position yet, but processing 6552321936Shselasky * of multiple independent neighbor positions has installed switches 6553321936Shselasky * into corners of our case. 6554321936Shselasky * 6555321936Shselasky * In any event, the topology assumptions made in handling the 6556321936Shselasky * fingerprint for this position require that all links be installed 6557321936Shselasky * between installed switches for this position. 6558321936Shselasky */ 6559321936Shselaskyagain: 6560321936Shselasky check_tlinks(t, i, j, k); 6561321936Shselasky fp = fingerprint(t, i, j, k); 6562321936Shselasky 6563321936Shselasky switch (fp) { 6564321936Shselasky /* 6565321936Shselasky * When all switches are present, we are done. Otherwise, one of 6566321936Shselasky * the cases below will be unsuccessful, and we'll be done also. 6567321936Shselasky * 6568321936Shselasky * Note that check_tlinks() above will ensure all links that are 6569321936Shselasky * present are connected, in the event that all our switches are 6570321936Shselasky * present due to successful case handling in the surrounding 6571321936Shselasky * torus/mesh. 6572321936Shselasky */ 6573321936Shselasky case 0x300: 6574321936Shselasky case 0x500: 6575321936Shselasky case 0x600: 6576321936Shselasky case 0x700: 6577321936Shselasky goto out; 6578321936Shselasky /* 6579321936Shselasky * Ignore the 2D cases where there isn't enough information to uniquely 6580321936Shselasky * locate/place a switch into the cube. 6581321936Shselasky */ 6582321936Shselasky case 0x30f: /* 0 corners available */ 6583321936Shselasky case 0x533: /* 0 corners available */ 6584321936Shselasky case 0x655: /* 0 corners available */ 6585321936Shselasky case 0x30e: /* 1 corner available */ 6586321936Shselasky case 0x532: /* 1 corner available */ 6587321936Shselasky case 0x654: /* 1 corner available */ 6588321936Shselasky case 0x30d: /* 1 corner available */ 6589321936Shselasky case 0x531: /* 1 corner available */ 6590321936Shselasky case 0x651: /* 1 corner available */ 6591321936Shselasky case 0x30b: /* 1 corner available */ 6592321936Shselasky case 0x523: /* 1 corner available */ 6593321936Shselasky case 0x645: /* 1 corner available */ 6594321936Shselasky case 0x307: /* 1 corner available */ 6595321936Shselasky case 0x513: /* 1 corner available */ 6596321936Shselasky case 0x615: /* 1 corner available */ 6597321936Shselasky goto out; 6598321936Shselasky /* 6599321936Shselasky * Handle the 2D cases with a single existing edge. 6600321936Shselasky * 6601321936Shselasky */ 6602321936Shselasky case 0x30c: 6603321936Shselasky success = handle_case_0x30c(t, i, j, k); 6604321936Shselasky break; 6605321936Shselasky case 0x303: 6606321936Shselasky success = handle_case_0x303(t, i, j, k); 6607321936Shselasky break; 6608321936Shselasky case 0x305: 6609321936Shselasky success = handle_case_0x305(t, i, j, k); 6610321936Shselasky break; 6611321936Shselasky case 0x30a: 6612321936Shselasky success = handle_case_0x30a(t, i, j, k); 6613321936Shselasky break; 6614321936Shselasky case 0x503: 6615321936Shselasky success = handle_case_0x503(t, i, j, k); 6616321936Shselasky break; 6617321936Shselasky case 0x511: 6618321936Shselasky success = handle_case_0x511(t, i, j, k); 6619321936Shselasky break; 6620321936Shselasky case 0x522: 6621321936Shselasky success = handle_case_0x522(t, i, j, k); 6622321936Shselasky break; 6623321936Shselasky case 0x530: 6624321936Shselasky success = handle_case_0x530(t, i, j, k); 6625321936Shselasky break; 6626321936Shselasky case 0x605: 6627321936Shselasky success = handle_case_0x605(t, i, j, k); 6628321936Shselasky break; 6629321936Shselasky case 0x611: 6630321936Shselasky success = handle_case_0x611(t, i, j, k); 6631321936Shselasky break; 6632321936Shselasky case 0x644: 6633321936Shselasky success = handle_case_0x644(t, i, j, k); 6634321936Shselasky break; 6635321936Shselasky case 0x650: 6636321936Shselasky success = handle_case_0x650(t, i, j, k); 6637321936Shselasky break; 6638321936Shselasky /* 6639321936Shselasky * Handle the 2D cases where two existing edges meet at a corner. 6640321936Shselasky */ 6641321936Shselasky case 0x301: 6642321936Shselasky success = handle_case_0x301(t, i, j, k); 6643321936Shselasky break; 6644321936Shselasky case 0x302: 6645321936Shselasky success = handle_case_0x302(t, i, j, k); 6646321936Shselasky break; 6647321936Shselasky case 0x304: 6648321936Shselasky success = handle_case_0x304(t, i, j, k); 6649321936Shselasky break; 6650321936Shselasky case 0x308: 6651321936Shselasky success = handle_case_0x308(t, i, j, k); 6652321936Shselasky break; 6653321936Shselasky case 0x501: 6654321936Shselasky success = handle_case_0x501(t, i, j, k); 6655321936Shselasky break; 6656321936Shselasky case 0x502: 6657321936Shselasky success = handle_case_0x502(t, i, j, k); 6658321936Shselasky break; 6659321936Shselasky case 0x520: 6660321936Shselasky success = handle_case_0x520(t, i, j, k); 6661321936Shselasky break; 6662321936Shselasky case 0x510: 6663321936Shselasky success = handle_case_0x510(t, i, j, k); 6664321936Shselasky break; 6665321936Shselasky case 0x601: 6666321936Shselasky success = handle_case_0x601(t, i, j, k); 6667321936Shselasky break; 6668321936Shselasky case 0x604: 6669321936Shselasky success = handle_case_0x604(t, i, j, k); 6670321936Shselasky break; 6671321936Shselasky case 0x610: 6672321936Shselasky success = handle_case_0x610(t, i, j, k); 6673321936Shselasky break; 6674321936Shselasky case 0x640: 6675321936Shselasky success = handle_case_0x640(t, i, j, k); 6676321936Shselasky break; 6677321936Shselasky /* 6678321936Shselasky * Ignore the 3D cases where there isn't enough information to uniquely 6679321936Shselasky * locate/place a switch into the cube. 6680321936Shselasky */ 6681321936Shselasky case 0x7ff: /* 0 corners available */ 6682321936Shselasky case 0x7fe: /* 1 corner available */ 6683321936Shselasky case 0x7fd: /* 1 corner available */ 6684321936Shselasky case 0x7fb: /* 1 corner available */ 6685321936Shselasky case 0x7f7: /* 1 corner available */ 6686321936Shselasky case 0x7ef: /* 1 corner available */ 6687321936Shselasky case 0x7df: /* 1 corner available */ 6688321936Shselasky case 0x7bf: /* 1 corner available */ 6689321936Shselasky case 0x77f: /* 1 corner available */ 6690321936Shselasky case 0x7fc: /* 2 adj corners available */ 6691321936Shselasky case 0x7fa: /* 2 adj corners available */ 6692321936Shselasky case 0x7f5: /* 2 adj corners available */ 6693321936Shselasky case 0x7f3: /* 2 adj corners available */ 6694321936Shselasky case 0x7cf: /* 2 adj corners available */ 6695321936Shselasky case 0x7af: /* 2 adj corners available */ 6696321936Shselasky case 0x75f: /* 2 adj corners available */ 6697321936Shselasky case 0x73f: /* 2 adj corners available */ 6698321936Shselasky case 0x7ee: /* 2 adj corners available */ 6699321936Shselasky case 0x7dd: /* 2 adj corners available */ 6700321936Shselasky case 0x7bb: /* 2 adj corners available */ 6701321936Shselasky case 0x777: /* 2 adj corners available */ 6702321936Shselasky goto out; 6703321936Shselasky /* 6704321936Shselasky * Handle the 3D cases where two existing edges meet at a corner. 6705321936Shselasky * 6706321936Shselasky */ 6707321936Shselasky case 0x71f: 6708321936Shselasky success = handle_case_0x71f(t, i, j, k); 6709321936Shselasky break; 6710321936Shselasky case 0x72f: 6711321936Shselasky success = handle_case_0x72f(t, i, j, k); 6712321936Shselasky break; 6713321936Shselasky case 0x737: 6714321936Shselasky success = handle_case_0x737(t, i, j, k); 6715321936Shselasky break; 6716321936Shselasky case 0x73b: 6717321936Shselasky success = handle_case_0x73b(t, i, j, k); 6718321936Shselasky break; 6719321936Shselasky case 0x74f: 6720321936Shselasky success = handle_case_0x74f(t, i, j, k); 6721321936Shselasky break; 6722321936Shselasky case 0x757: 6723321936Shselasky success = handle_case_0x757(t, i, j, k); 6724321936Shselasky break; 6725321936Shselasky case 0x75d: 6726321936Shselasky success = handle_case_0x75d(t, i, j, k); 6727321936Shselasky break; 6728321936Shselasky case 0x773: 6729321936Shselasky success = handle_case_0x773(t, i, j, k); 6730321936Shselasky break; 6731321936Shselasky case 0x775: 6732321936Shselasky success = handle_case_0x775(t, i, j, k); 6733321936Shselasky break; 6734321936Shselasky case 0x78f: 6735321936Shselasky success = handle_case_0x78f(t, i, j, k); 6736321936Shselasky break; 6737321936Shselasky case 0x7ab: 6738321936Shselasky success = handle_case_0x7ab(t, i, j, k); 6739321936Shselasky break; 6740321936Shselasky case 0x7ae: 6741321936Shselasky success = handle_case_0x7ae(t, i, j, k); 6742321936Shselasky break; 6743321936Shselasky case 0x7b3: 6744321936Shselasky success = handle_case_0x7b3(t, i, j, k); 6745321936Shselasky break; 6746321936Shselasky case 0x7ba: 6747321936Shselasky success = handle_case_0x7ba(t, i, j, k); 6748321936Shselasky break; 6749321936Shselasky case 0x7cd: 6750321936Shselasky success = handle_case_0x7cd(t, i, j, k); 6751321936Shselasky break; 6752321936Shselasky case 0x7ce: 6753321936Shselasky success = handle_case_0x7ce(t, i, j, k); 6754321936Shselasky break; 6755321936Shselasky case 0x7d5: 6756321936Shselasky success = handle_case_0x7d5(t, i, j, k); 6757321936Shselasky break; 6758321936Shselasky case 0x7dc: 6759321936Shselasky success = handle_case_0x7dc(t, i, j, k); 6760321936Shselasky break; 6761321936Shselasky case 0x7ea: 6762321936Shselasky success = handle_case_0x7ea(t, i, j, k); 6763321936Shselasky break; 6764321936Shselasky case 0x7ec: 6765321936Shselasky success = handle_case_0x7ec(t, i, j, k); 6766321936Shselasky break; 6767321936Shselasky case 0x7f1: 6768321936Shselasky success = handle_case_0x7f1(t, i, j, k); 6769321936Shselasky break; 6770321936Shselasky case 0x7f2: 6771321936Shselasky success = handle_case_0x7f2(t, i, j, k); 6772321936Shselasky break; 6773321936Shselasky case 0x7f4: 6774321936Shselasky success = handle_case_0x7f4(t, i, j, k); 6775321936Shselasky break; 6776321936Shselasky case 0x7f8: 6777321936Shselasky success = handle_case_0x7f8(t, i, j, k); 6778321936Shselasky break; 6779321936Shselasky /* 6780321936Shselasky * Handle the cases where three existing edges meet at a corner. 6781321936Shselasky * 6782321936Shselasky */ 6783321936Shselasky case 0x717: 6784321936Shselasky success = handle_case_0x717(t, i, j, k); 6785321936Shselasky break; 6786321936Shselasky case 0x72b: 6787321936Shselasky success = handle_case_0x72b(t, i, j, k); 6788321936Shselasky break; 6789321936Shselasky case 0x74d: 6790321936Shselasky success = handle_case_0x74d(t, i, j, k); 6791321936Shselasky break; 6792321936Shselasky case 0x771: 6793321936Shselasky success = handle_case_0x771(t, i, j, k); 6794321936Shselasky break; 6795321936Shselasky case 0x78e: 6796321936Shselasky success = handle_case_0x78e(t, i, j, k); 6797321936Shselasky break; 6798321936Shselasky case 0x7b2: 6799321936Shselasky success = handle_case_0x7b2(t, i, j, k); 6800321936Shselasky break; 6801321936Shselasky case 0x7d4: 6802321936Shselasky success = handle_case_0x7d4(t, i, j, k); 6803321936Shselasky break; 6804321936Shselasky case 0x7e8: 6805321936Shselasky success = handle_case_0x7e8(t, i, j, k); 6806321936Shselasky break; 6807321936Shselasky /* 6808321936Shselasky * Handle the cases where four corners on a single face are missing. 6809321936Shselasky */ 6810321936Shselasky case 0x70f: 6811321936Shselasky success = handle_case_0x70f(t, i, j, k); 6812321936Shselasky break; 6813321936Shselasky case 0x733: 6814321936Shselasky success = handle_case_0x733(t, i, j, k); 6815321936Shselasky break; 6816321936Shselasky case 0x755: 6817321936Shselasky success = handle_case_0x755(t, i, j, k); 6818321936Shselasky break; 6819321936Shselasky case 0x7aa: 6820321936Shselasky success = handle_case_0x7aa(t, i, j, k); 6821321936Shselasky break; 6822321936Shselasky case 0x7cc: 6823321936Shselasky success = handle_case_0x7cc(t, i, j, k); 6824321936Shselasky break; 6825321936Shselasky case 0x7f0: 6826321936Shselasky success = handle_case_0x7f0(t, i, j, k); 6827321936Shselasky break; 6828321936Shselasky /* 6829321936Shselasky * Handle the cases where three corners on a single face are missing. 6830321936Shselasky */ 6831321936Shselasky case 0x707: 6832321936Shselasky success = handle_case_0x707(t, i, j, k); 6833321936Shselasky break; 6834321936Shselasky case 0x70b: 6835321936Shselasky success = handle_case_0x70b(t, i, j, k); 6836321936Shselasky break; 6837321936Shselasky case 0x70d: 6838321936Shselasky success = handle_case_0x70d(t, i, j, k); 6839321936Shselasky break; 6840321936Shselasky case 0x70e: 6841321936Shselasky success = handle_case_0x70e(t, i, j, k); 6842321936Shselasky break; 6843321936Shselasky case 0x713: 6844321936Shselasky success = handle_case_0x713(t, i, j, k); 6845321936Shselasky break; 6846321936Shselasky case 0x715: 6847321936Shselasky success = handle_case_0x715(t, i, j, k); 6848321936Shselasky break; 6849321936Shselasky case 0x723: 6850321936Shselasky success = handle_case_0x723(t, i, j, k); 6851321936Shselasky break; 6852321936Shselasky case 0x72a: 6853321936Shselasky success = handle_case_0x72a(t, i, j, k); 6854321936Shselasky break; 6855321936Shselasky case 0x731: 6856321936Shselasky success = handle_case_0x731(t, i, j, k); 6857321936Shselasky break; 6858321936Shselasky case 0x732: 6859321936Shselasky success = handle_case_0x732(t, i, j, k); 6860321936Shselasky break; 6861321936Shselasky case 0x745: 6862321936Shselasky success = handle_case_0x745(t, i, j, k); 6863321936Shselasky break; 6864321936Shselasky case 0x74c: 6865321936Shselasky success = handle_case_0x74c(t, i, j, k); 6866321936Shselasky break; 6867321936Shselasky case 0x751: 6868321936Shselasky success = handle_case_0x751(t, i, j, k); 6869321936Shselasky break; 6870321936Shselasky case 0x754: 6871321936Shselasky success = handle_case_0x754(t, i, j, k); 6872321936Shselasky break; 6873321936Shselasky case 0x770: 6874321936Shselasky success = handle_case_0x770(t, i, j, k); 6875321936Shselasky break; 6876321936Shselasky case 0x78a: 6877321936Shselasky success = handle_case_0x78a(t, i, j, k); 6878321936Shselasky break; 6879321936Shselasky case 0x78c: 6880321936Shselasky success = handle_case_0x78c(t, i, j, k); 6881321936Shselasky break; 6882321936Shselasky case 0x7a2: 6883321936Shselasky success = handle_case_0x7a2(t, i, j, k); 6884321936Shselasky break; 6885321936Shselasky case 0x7a8: 6886321936Shselasky success = handle_case_0x7a8(t, i, j, k); 6887321936Shselasky break; 6888321936Shselasky case 0x7b0: 6889321936Shselasky success = handle_case_0x7b0(t, i, j, k); 6890321936Shselasky break; 6891321936Shselasky case 0x7c4: 6892321936Shselasky success = handle_case_0x7c4(t, i, j, k); 6893321936Shselasky break; 6894321936Shselasky case 0x7c8: 6895321936Shselasky success = handle_case_0x7c8(t, i, j, k); 6896321936Shselasky break; 6897321936Shselasky case 0x7d0: 6898321936Shselasky success = handle_case_0x7d0(t, i, j, k); 6899321936Shselasky break; 6900321936Shselasky case 0x7e0: 6901321936Shselasky success = handle_case_0x7e0(t, i, j, k); 6902321936Shselasky break; 6903321936Shselasky /* 6904321936Shselasky * Handle the cases where two corners on a single edge are missing. 6905321936Shselasky */ 6906321936Shselasky case 0x703: 6907321936Shselasky success = handle_case_0x703(t, i, j, k); 6908321936Shselasky break; 6909321936Shselasky case 0x705: 6910321936Shselasky success = handle_case_0x705(t, i, j, k); 6911321936Shselasky break; 6912321936Shselasky case 0x70a: 6913321936Shselasky success = handle_case_0x70a(t, i, j, k); 6914321936Shselasky break; 6915321936Shselasky case 0x70c: 6916321936Shselasky success = handle_case_0x70c(t, i, j, k); 6917321936Shselasky break; 6918321936Shselasky case 0x711: 6919321936Shselasky success = handle_case_0x711(t, i, j, k); 6920321936Shselasky break; 6921321936Shselasky case 0x722: 6922321936Shselasky success = handle_case_0x722(t, i, j, k); 6923321936Shselasky break; 6924321936Shselasky case 0x730: 6925321936Shselasky success = handle_case_0x730(t, i, j, k); 6926321936Shselasky break; 6927321936Shselasky case 0x744: 6928321936Shselasky success = handle_case_0x744(t, i, j, k); 6929321936Shselasky break; 6930321936Shselasky case 0x750: 6931321936Shselasky success = handle_case_0x750(t, i, j, k); 6932321936Shselasky break; 6933321936Shselasky case 0x788: 6934321936Shselasky success = handle_case_0x788(t, i, j, k); 6935321936Shselasky break; 6936321936Shselasky case 0x7a0: 6937321936Shselasky success = handle_case_0x7a0(t, i, j, k); 6938321936Shselasky break; 6939321936Shselasky case 0x7c0: 6940321936Shselasky success = handle_case_0x7c0(t, i, j, k); 6941321936Shselasky break; 6942321936Shselasky /* 6943321936Shselasky * Handle the cases where a single corner is missing. 6944321936Shselasky */ 6945321936Shselasky case 0x701: 6946321936Shselasky success = handle_case_0x701(t, i, j, k); 6947321936Shselasky break; 6948321936Shselasky case 0x702: 6949321936Shselasky success = handle_case_0x702(t, i, j, k); 6950321936Shselasky break; 6951321936Shselasky case 0x704: 6952321936Shselasky success = handle_case_0x704(t, i, j, k); 6953321936Shselasky break; 6954321936Shselasky case 0x708: 6955321936Shselasky success = handle_case_0x708(t, i, j, k); 6956321936Shselasky break; 6957321936Shselasky case 0x710: 6958321936Shselasky success = handle_case_0x710(t, i, j, k); 6959321936Shselasky break; 6960321936Shselasky case 0x720: 6961321936Shselasky success = handle_case_0x720(t, i, j, k); 6962321936Shselasky break; 6963321936Shselasky case 0x740: 6964321936Shselasky success = handle_case_0x740(t, i, j, k); 6965321936Shselasky break; 6966321936Shselasky case 0x780: 6967321936Shselasky success = handle_case_0x780(t, i, j, k); 6968321936Shselasky break; 6969321936Shselasky 6970321936Shselasky default: 6971321936Shselasky /* 6972321936Shselasky * There's lots of unhandled cases still, but it's not clear 6973321936Shselasky * we care. Let debugging show us what they are so we can 6974321936Shselasky * learn if we care. 6975321936Shselasky */ 6976321936Shselasky if (t->debug) 6977321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 6978321936Shselasky "Unhandled fingerprint 0x%03x @ %d %d %d\n", 6979321936Shselasky fp, i, j, k); 6980321936Shselasky goto out; 6981321936Shselasky } 6982321936Shselasky /* 6983321936Shselasky * If we successfully handled a case, we may be able to make more 6984321936Shselasky * progress at this position, so try again. Otherwise, even though 6985321936Shselasky * we didn't successfully handle a case, we may have installed a 6986321936Shselasky * switch into the torus/mesh, so try to install links as well. 6987321936Shselasky * Then we'll have another go at the next position. 6988321936Shselasky */ 6989321936Shselasky if (success) { 6990321936Shselasky if (t->debug) 6991321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 6992321936Shselasky "Success on fingerprint 0x%03x @ %d %d %d\n", 6993321936Shselasky fp, i, j, k); 6994321936Shselasky goto again; 6995321936Shselasky } else { 6996321936Shselasky check_tlinks(t, i, j, k); 6997321936Shselasky if (t->debug) 6998321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 6999321936Shselasky "Failed on fingerprint 0x%03x @ %d %d %d\n", 7000321936Shselasky fp, i, j, k); 7001321936Shselasky } 7002321936Shselaskyout: 7003321936Shselasky return; 7004321936Shselasky} 7005321936Shselasky 7006321936Shselasky#define LINK_ERR_STR " direction link required for topology seed configuration since radix == 4! See torus-2QoS.conf(5).\n" 7007321936Shselasky#define LINK_ERR2_STR " direction link required for topology seed configuration! See torus-2QoS.conf(5).\n" 7008321936Shselasky#define SEED_ERR_STR " direction links for topology seed do not share a common switch! See torus-2QoS.conf(5).\n" 7009321936Shselasky 7010321936Shselaskystatic 7011321936Shselaskybool verify_setup(struct torus *t, struct fabric *f) 7012321936Shselasky{ 7013321936Shselasky struct coord_dirs *o; 7014321936Shselasky struct f_switch *sw; 7015321936Shselasky unsigned p, s, n = 0; 7016321936Shselasky bool success = false; 7017321936Shselasky bool all_sw_present, need_seed = true; 7018321936Shselasky 7019321936Shselasky if (!(t->x_sz && t->y_sz && t->z_sz)) { 7020321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7021321936Shselasky "ERR 4E20: missing required torus size specification!\n"); 7022321936Shselasky goto out; 7023321936Shselasky } 7024321936Shselasky if (t->osm->subn.min_sw_data_vls < 2) { 7025321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7026321936Shselasky "ERR 4E48: Too few data VLs to support torus routing " 7027321936Shselasky "without credit loops (have switchport %d need 2)\n", 7028321936Shselasky (int)t->osm->subn.min_sw_data_vls); 7029321936Shselasky goto out; 7030321936Shselasky } 7031321936Shselasky if (t->osm->subn.min_sw_data_vls < 4) 7032321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, 7033321936Shselasky "Warning: Too few data VLs to support torus routing " 7034321936Shselasky "with a failed switch without credit loops " 7035321936Shselasky "(have switchport %d need 4)\n", 7036321936Shselasky (int)t->osm->subn.min_sw_data_vls); 7037321936Shselasky if (t->osm->subn.min_sw_data_vls < 8) 7038321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, 7039321936Shselasky "Warning: Too few data VLs to support torus routing " 7040321936Shselasky "with two QoS levels (have switchport %d need 8)\n", 7041321936Shselasky (int)t->osm->subn.min_sw_data_vls); 7042321936Shselasky if (t->osm->subn.min_data_vls < 2) 7043321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, 7044321936Shselasky "Warning: Too few data VLs to support torus routing " 7045321936Shselasky "with two QoS levels (have endport %d need 2)\n", 7046321936Shselasky (int)t->osm->subn.min_data_vls); 7047321936Shselasky /* 7048321936Shselasky * Be sure all the switches in the torus support the port 7049321936Shselasky * ordering that might have been configured. 7050321936Shselasky */ 7051321936Shselasky for (s = 0; s < f->switch_cnt; s++) { 7052321936Shselasky sw = f->sw[s]; 7053321936Shselasky for (p = 0; p < sw->port_cnt; p++) { 7054321936Shselasky if (t->port_order[p] >= sw->port_cnt) { 7055321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7056321936Shselasky "ERR 4E21: port_order configured using " 7057321936Shselasky "port %u, but only %u ports in " 7058321936Shselasky "switch w/ GUID 0x%04"PRIx64"\n", 7059321936Shselasky t->port_order[p], sw->port_cnt - 1, 7060321936Shselasky cl_ntoh64(sw->n_id)); 7061321936Shselasky goto out; 7062321936Shselasky } 7063321936Shselasky } 7064321936Shselasky } 7065321936Shselasky /* 7066321936Shselasky * Unfortunately, there is a problem with non-unique topology for any 7067321936Shselasky * torus dimension which has radix four. This problem requires extra 7068321936Shselasky * input, in the form of specifying both the positive and negative 7069321936Shselasky * coordinate directions from a common switch, for any torus dimension 7070321936Shselasky * with radix four (see also build_torus()). 7071321936Shselasky * 7072321936Shselasky * Do the checking required to ensure that the required information 7073321936Shselasky * is present, but more than the needed information is not required. 7074321936Shselasky * 7075321936Shselasky * So, verify that we learned the coordinate directions correctly for 7076321936Shselasky * the fabric. The coordinate direction links get an invalid port 7077321936Shselasky * set on their ends when parsed. 7078321936Shselasky */ 7079321936Shselaskyagain: 7080321936Shselasky all_sw_present = true; 7081321936Shselasky o = &t->seed[n]; 7082321936Shselasky 7083321936Shselasky if (t->x_sz == 4 && !(t->flags & X_MESH)) { 7084321936Shselasky if (o->xp_link.end[0].port >= 0) { 7085321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7086321936Shselasky "ERR 4E22: Positive x" LINK_ERR_STR); 7087321936Shselasky goto out; 7088321936Shselasky } 7089321936Shselasky if (o->xm_link.end[0].port >= 0) { 7090321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7091321936Shselasky "ERR 4E23: Negative x" LINK_ERR_STR); 7092321936Shselasky goto out; 7093321936Shselasky } 7094321936Shselasky if (o->xp_link.end[0].n_id != o->xm_link.end[0].n_id) { 7095321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7096321936Shselasky "ERR 4E24: Positive/negative x" SEED_ERR_STR); 7097321936Shselasky goto out; 7098321936Shselasky } 7099321936Shselasky } 7100321936Shselasky if (t->y_sz == 4 && !(t->flags & Y_MESH)) { 7101321936Shselasky if (o->yp_link.end[0].port >= 0) { 7102321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7103321936Shselasky "ERR 4E25: Positive y" LINK_ERR_STR); 7104321936Shselasky goto out; 7105321936Shselasky } 7106321936Shselasky if (o->ym_link.end[0].port >= 0) { 7107321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7108321936Shselasky "ERR 4E26: Negative y" LINK_ERR_STR); 7109321936Shselasky goto out; 7110321936Shselasky } 7111321936Shselasky if (o->yp_link.end[0].n_id != o->ym_link.end[0].n_id) { 7112321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7113321936Shselasky "ERR 4E27: Positive/negative y" SEED_ERR_STR); 7114321936Shselasky goto out; 7115321936Shselasky } 7116321936Shselasky } 7117321936Shselasky if (t->z_sz == 4 && !(t->flags & Z_MESH)) { 7118321936Shselasky if (o->zp_link.end[0].port >= 0) { 7119321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7120321936Shselasky "ERR 4E28: Positive z" LINK_ERR_STR); 7121321936Shselasky goto out; 7122321936Shselasky } 7123321936Shselasky if (o->zm_link.end[0].port >= 0) { 7124321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7125321936Shselasky "ERR 4E29: Negative z" LINK_ERR_STR); 7126321936Shselasky goto out; 7127321936Shselasky } 7128321936Shselasky if (o->zp_link.end[0].n_id != o->zm_link.end[0].n_id) { 7129321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7130321936Shselasky "ERR 4E2A: Positive/negative z" SEED_ERR_STR); 7131321936Shselasky goto out; 7132321936Shselasky } 7133321936Shselasky } 7134321936Shselasky if (t->x_sz > 1) { 7135321936Shselasky if (o->xp_link.end[0].port >= 0 && 7136321936Shselasky o->xm_link.end[0].port >= 0) { 7137321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7138321936Shselasky "ERR 4E2B: Positive or negative x" LINK_ERR2_STR); 7139321936Shselasky goto out; 7140321936Shselasky } 7141321936Shselasky if (o->xp_link.end[0].port < 0 && 7142321936Shselasky !find_f_sw(f, o->xp_link.end[0].n_id)) 7143321936Shselasky all_sw_present = false; 7144321936Shselasky 7145321936Shselasky if (o->xp_link.end[1].port < 0 && 7146321936Shselasky !find_f_sw(f, o->xp_link.end[1].n_id)) 7147321936Shselasky all_sw_present = false; 7148321936Shselasky 7149321936Shselasky if (o->xm_link.end[0].port < 0 && 7150321936Shselasky !find_f_sw(f, o->xm_link.end[0].n_id)) 7151321936Shselasky all_sw_present = false; 7152321936Shselasky 7153321936Shselasky if (o->xm_link.end[1].port < 0 && 7154321936Shselasky !find_f_sw(f, o->xm_link.end[1].n_id)) 7155321936Shselasky all_sw_present = false; 7156321936Shselasky } 7157321936Shselasky if (t->z_sz > 1) { 7158321936Shselasky if (o->zp_link.end[0].port >= 0 && 7159321936Shselasky o->zm_link.end[0].port >= 0) { 7160321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7161321936Shselasky "ERR 4E2C: Positive or negative z" LINK_ERR2_STR); 7162321936Shselasky goto out; 7163321936Shselasky } 7164321936Shselasky if ((o->xp_link.end[0].port < 0 && 7165321936Shselasky o->zp_link.end[0].port < 0 && 7166321936Shselasky o->zp_link.end[0].n_id != o->xp_link.end[0].n_id) || 7167321936Shselasky 7168321936Shselasky (o->xp_link.end[0].port < 0 && 7169321936Shselasky o->zm_link.end[0].port < 0 && 7170321936Shselasky o->zm_link.end[0].n_id != o->xp_link.end[0].n_id) || 7171321936Shselasky 7172321936Shselasky (o->xm_link.end[0].port < 0 && 7173321936Shselasky o->zp_link.end[0].port < 0 && 7174321936Shselasky o->zp_link.end[0].n_id != o->xm_link.end[0].n_id) || 7175321936Shselasky 7176321936Shselasky (o->xm_link.end[0].port < 0 && 7177321936Shselasky o->zm_link.end[0].port < 0 && 7178321936Shselasky o->zm_link.end[0].n_id != o->xm_link.end[0].n_id)) { 7179321936Shselasky 7180321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7181321936Shselasky "ERR 4E2D: x and z" SEED_ERR_STR); 7182321936Shselasky goto out; 7183321936Shselasky } 7184321936Shselasky if (o->zp_link.end[0].port < 0 && 7185321936Shselasky !find_f_sw(f, o->zp_link.end[0].n_id)) 7186321936Shselasky all_sw_present = false; 7187321936Shselasky 7188321936Shselasky if (o->zp_link.end[1].port < 0 && 7189321936Shselasky !find_f_sw(f, o->zp_link.end[1].n_id)) 7190321936Shselasky all_sw_present = false; 7191321936Shselasky 7192321936Shselasky if (o->zm_link.end[0].port < 0 && 7193321936Shselasky !find_f_sw(f, o->zm_link.end[0].n_id)) 7194321936Shselasky all_sw_present = false; 7195321936Shselasky 7196321936Shselasky if (o->zm_link.end[1].port < 0 && 7197321936Shselasky !find_f_sw(f, o->zm_link.end[1].n_id)) 7198321936Shselasky all_sw_present = false; 7199321936Shselasky } 7200321936Shselasky if (t->y_sz > 1) { 7201321936Shselasky if (o->yp_link.end[0].port >= 0 && 7202321936Shselasky o->ym_link.end[0].port >= 0) { 7203321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7204321936Shselasky "ERR 4E2E: Positive or negative y" LINK_ERR2_STR); 7205321936Shselasky goto out; 7206321936Shselasky } 7207321936Shselasky if ((o->xp_link.end[0].port < 0 && 7208321936Shselasky o->yp_link.end[0].port < 0 && 7209321936Shselasky o->yp_link.end[0].n_id != o->xp_link.end[0].n_id) || 7210321936Shselasky 7211321936Shselasky (o->xp_link.end[0].port < 0 && 7212321936Shselasky o->ym_link.end[0].port < 0 && 7213321936Shselasky o->ym_link.end[0].n_id != o->xp_link.end[0].n_id) || 7214321936Shselasky 7215321936Shselasky (o->xm_link.end[0].port < 0 && 7216321936Shselasky o->yp_link.end[0].port < 0 && 7217321936Shselasky o->yp_link.end[0].n_id != o->xm_link.end[0].n_id) || 7218321936Shselasky 7219321936Shselasky (o->xm_link.end[0].port < 0 && 7220321936Shselasky o->ym_link.end[0].port < 0 && 7221321936Shselasky o->ym_link.end[0].n_id != o->xm_link.end[0].n_id)) { 7222321936Shselasky 7223321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7224321936Shselasky "ERR 4E2F: x and y" SEED_ERR_STR); 7225321936Shselasky goto out; 7226321936Shselasky } 7227321936Shselasky if (o->yp_link.end[0].port < 0 && 7228321936Shselasky !find_f_sw(f, o->yp_link.end[0].n_id)) 7229321936Shselasky all_sw_present = false; 7230321936Shselasky 7231321936Shselasky if (o->yp_link.end[1].port < 0 && 7232321936Shselasky !find_f_sw(f, o->yp_link.end[1].n_id)) 7233321936Shselasky all_sw_present = false; 7234321936Shselasky 7235321936Shselasky if (o->ym_link.end[0].port < 0 && 7236321936Shselasky !find_f_sw(f, o->ym_link.end[0].n_id)) 7237321936Shselasky all_sw_present = false; 7238321936Shselasky 7239321936Shselasky if (o->ym_link.end[1].port < 0 && 7240321936Shselasky !find_f_sw(f, o->ym_link.end[1].n_id)) 7241321936Shselasky all_sw_present = false; 7242321936Shselasky } 7243321936Shselasky if (all_sw_present && need_seed) { 7244321936Shselasky t->seed_idx = n; 7245321936Shselasky need_seed = false; 7246321936Shselasky } 7247321936Shselasky if (++n < t->seed_cnt) 7248321936Shselasky goto again; 7249321936Shselasky 7250321936Shselasky if (need_seed) 7251321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7252321936Shselasky "ERR 4E30: Every configured torus seed has at " 7253321936Shselasky "least one switch missing in fabric! See " 7254321936Shselasky "torus-2QoS.conf(5) and TORUS TOPOLOGY DISCOVERY " 7255321936Shselasky "in torus-2QoS(8)\n"); 7256321936Shselasky else 7257321936Shselasky success = true; 7258321936Shselaskyout: 7259321936Shselasky return success; 7260321936Shselasky} 7261321936Shselasky 7262321936Shselaskystatic 7263321936Shselaskybool build_torus(struct fabric *f, struct torus *t) 7264321936Shselasky{ 7265321936Shselasky int i, j, k; 7266321936Shselasky int im1, jm1, km1; 7267321936Shselasky int ip1, jp1, kp1; 7268321936Shselasky unsigned nlink; 7269321936Shselasky struct coord_dirs *o; 7270321936Shselasky struct f_switch *fsw0, *fsw1; 7271321936Shselasky struct t_switch ****sw = t->sw; 7272321936Shselasky bool success = true; 7273321936Shselasky 7274321936Shselasky t->link_pool_sz = f->link_cnt; 7275321936Shselasky t->link_pool = calloc(1, t->link_pool_sz * sizeof(*t->link_pool)); 7276321936Shselasky if (!t->link_pool) { 7277321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7278321936Shselasky "ERR 4E31: Allocating torus link pool: %s\n", 7279321936Shselasky strerror(errno)); 7280321936Shselasky goto out; 7281321936Shselasky } 7282321936Shselasky t->fabric = f; 7283321936Shselasky 7284321936Shselasky /* 7285321936Shselasky * Get things started by locating the up to seven switches that 7286321936Shselasky * define the torus "seed", coordinate directions, and datelines. 7287321936Shselasky */ 7288321936Shselasky o = &t->seed[t->seed_idx]; 7289321936Shselasky 7290321936Shselasky i = canonicalize(-o->x_dateline, t->x_sz); 7291321936Shselasky j = canonicalize(-o->y_dateline, t->y_sz); 7292321936Shselasky k = canonicalize(-o->z_dateline, t->z_sz); 7293321936Shselasky 7294321936Shselasky if (o->xp_link.end[0].port < 0) { 7295321936Shselasky ip1 = canonicalize(1 - o->x_dateline, t->x_sz); 7296321936Shselasky fsw0 = find_f_sw(f, o->xp_link.end[0].n_id); 7297321936Shselasky fsw1 = find_f_sw(f, o->xp_link.end[1].n_id); 7298321936Shselasky success = 7299321936Shselasky install_tswitch(t, i, j, k, fsw0) && 7300321936Shselasky install_tswitch(t, ip1, j, k, fsw1) && success; 7301321936Shselasky } 7302321936Shselasky if (o->xm_link.end[0].port < 0) { 7303321936Shselasky im1 = canonicalize(-1 - o->x_dateline, t->x_sz); 7304321936Shselasky fsw0 = find_f_sw(f, o->xm_link.end[0].n_id); 7305321936Shselasky fsw1 = find_f_sw(f, o->xm_link.end[1].n_id); 7306321936Shselasky success = 7307321936Shselasky install_tswitch(t, i, j, k, fsw0) && 7308321936Shselasky install_tswitch(t, im1, j, k, fsw1) && success; 7309321936Shselasky } 7310321936Shselasky if (o->yp_link.end[0].port < 0) { 7311321936Shselasky jp1 = canonicalize(1 - o->y_dateline, t->y_sz); 7312321936Shselasky fsw0 = find_f_sw(f, o->yp_link.end[0].n_id); 7313321936Shselasky fsw1 = find_f_sw(f, o->yp_link.end[1].n_id); 7314321936Shselasky success = 7315321936Shselasky install_tswitch(t, i, j, k, fsw0) && 7316321936Shselasky install_tswitch(t, i, jp1, k, fsw1) && success; 7317321936Shselasky } 7318321936Shselasky if (o->ym_link.end[0].port < 0) { 7319321936Shselasky jm1 = canonicalize(-1 - o->y_dateline, t->y_sz); 7320321936Shselasky fsw0 = find_f_sw(f, o->ym_link.end[0].n_id); 7321321936Shselasky fsw1 = find_f_sw(f, o->ym_link.end[1].n_id); 7322321936Shselasky success = 7323321936Shselasky install_tswitch(t, i, j, k, fsw0) && 7324321936Shselasky install_tswitch(t, i, jm1, k, fsw1) && success; 7325321936Shselasky } 7326321936Shselasky if (o->zp_link.end[0].port < 0) { 7327321936Shselasky kp1 = canonicalize(1 - o->z_dateline, t->z_sz); 7328321936Shselasky fsw0 = find_f_sw(f, o->zp_link.end[0].n_id); 7329321936Shselasky fsw1 = find_f_sw(f, o->zp_link.end[1].n_id); 7330321936Shselasky success = 7331321936Shselasky install_tswitch(t, i, j, k, fsw0) && 7332321936Shselasky install_tswitch(t, i, j, kp1, fsw1) && success; 7333321936Shselasky } 7334321936Shselasky if (o->zm_link.end[0].port < 0) { 7335321936Shselasky km1 = canonicalize(-1 - o->z_dateline, t->z_sz); 7336321936Shselasky fsw0 = find_f_sw(f, o->zm_link.end[0].n_id); 7337321936Shselasky fsw1 = find_f_sw(f, o->zm_link.end[1].n_id); 7338321936Shselasky success = 7339321936Shselasky install_tswitch(t, i, j, k, fsw0) && 7340321936Shselasky install_tswitch(t, i, j, km1, fsw1) && success; 7341321936Shselasky } 7342321936Shselasky if (!success) 7343321936Shselasky goto out; 7344321936Shselasky 7345321936Shselasky if (!t->seed_idx) 7346321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, 7347321936Shselasky "Using torus seed configured as default " 7348321936Shselasky "(seed sw %d,%d,%d GUID 0x%04"PRIx64").\n", 7349321936Shselasky i, j, k, cl_ntoh64(sw[i][j][k]->n_id)); 7350321936Shselasky else 7351321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, 7352321936Shselasky "Using torus seed configured as backup #%u " 7353321936Shselasky "(seed sw %d,%d,%d GUID 0x%04"PRIx64").\n", 7354321936Shselasky t->seed_idx, i, j, k, cl_ntoh64(sw[i][j][k]->n_id)); 7355321936Shselasky 7356321936Shselasky /* 7357321936Shselasky * Search the fabric and construct the expected torus topology. 7358321936Shselasky * 7359321936Shselasky * The algorithm is to consider the "cube" formed by eight switch 7360321936Shselasky * locations bounded by the corners i, j, k and i+1, j+1, k+1. 7361321936Shselasky * For each such cube look at the topology of the switches already 7362321936Shselasky * placed in the torus, and deduce which new switches can be placed 7363321936Shselasky * into their proper locations in the torus. Examine each cube 7364321936Shselasky * multiple times, until the number of links moved into the torus 7365321936Shselasky * topology does not change. 7366321936Shselasky */ 7367321936Shselaskyagain: 7368321936Shselasky nlink = t->link_cnt; 7369321936Shselasky 7370321936Shselasky for (k = 0; k < (int)t->z_sz; k++) 7371321936Shselasky for (j = 0; j < (int)t->y_sz; j++) 7372321936Shselasky for (i = 0; i < (int)t->x_sz; i++) 7373321936Shselasky locate_sw(t, i, j, k); 7374321936Shselasky 7375321936Shselasky if (t->link_cnt != nlink) 7376321936Shselasky goto again; 7377321936Shselasky 7378321936Shselasky /* 7379321936Shselasky * Move all other endpoints into torus/mesh. 7380321936Shselasky */ 7381321936Shselasky for (k = 0; k < (int)t->z_sz; k++) 7382321936Shselasky for (j = 0; j < (int)t->y_sz; j++) 7383321936Shselasky for (i = 0; i < (int)t->x_sz; i++) 7384321936Shselasky if (!link_srcsink(t, i, j, k)) { 7385321936Shselasky success = false; 7386321936Shselasky goto out; 7387321936Shselasky } 7388321936Shselaskyout: 7389321936Shselasky return success; 7390321936Shselasky} 7391321936Shselasky 7392321936Shselasky/* 7393321936Shselasky * Returns a count of differences between old and new switches. 7394321936Shselasky */ 7395321936Shselaskystatic 7396321936Shselaskyunsigned tsw_changes(struct t_switch *nsw, struct t_switch *osw) 7397321936Shselasky{ 7398321936Shselasky unsigned p, cnt = 0, port_cnt; 7399321936Shselasky struct endpoint *npt, *opt; 7400321936Shselasky struct endpoint *rnpt, *ropt; 7401321936Shselasky 7402321936Shselasky if (nsw && !osw) { 7403321936Shselasky cnt++; 7404321936Shselasky OSM_LOG(&nsw->torus->osm->log, OSM_LOG_INFO, 7405321936Shselasky "New torus switch %d,%d,%d GUID 0x%04"PRIx64"\n", 7406321936Shselasky nsw->i, nsw->j, nsw->k, cl_ntoh64(nsw->n_id)); 7407321936Shselasky goto out; 7408321936Shselasky } 7409321936Shselasky if (osw && !nsw) { 7410321936Shselasky cnt++; 7411321936Shselasky OSM_LOG(&osw->torus->osm->log, OSM_LOG_INFO, 7412321936Shselasky "Lost torus switch %d,%d,%d GUID 0x%04"PRIx64"\n", 7413321936Shselasky osw->i, osw->j, osw->k, cl_ntoh64(osw->n_id)); 7414321936Shselasky goto out; 7415321936Shselasky } 7416321936Shselasky if (!(nsw && osw)) 7417321936Shselasky goto out; 7418321936Shselasky 7419321936Shselasky if (nsw->n_id != osw->n_id) { 7420321936Shselasky cnt++; 7421321936Shselasky OSM_LOG(&nsw->torus->osm->log, OSM_LOG_INFO, 7422321936Shselasky "Torus switch %d,%d,%d GUID " 7423321936Shselasky "was 0x%04"PRIx64", now 0x%04"PRIx64"\n", 7424321936Shselasky nsw->i, nsw->j, nsw->k, 7425321936Shselasky cl_ntoh64(osw->n_id), cl_ntoh64(nsw->n_id)); 7426321936Shselasky } 7427321936Shselasky 7428321936Shselasky if (nsw->port_cnt != osw->port_cnt) { 7429321936Shselasky cnt++; 7430321936Shselasky OSM_LOG(&nsw->torus->osm->log, OSM_LOG_INFO, 7431321936Shselasky "Torus switch %d,%d,%d GUID 0x%04"PRIx64" " 7432321936Shselasky "had %d ports, now has %d\n", 7433321936Shselasky nsw->i, nsw->j, nsw->k, cl_ntoh64(nsw->n_id), 7434321936Shselasky osw->port_cnt, nsw->port_cnt); 7435321936Shselasky } 7436321936Shselasky port_cnt = nsw->port_cnt; 7437321936Shselasky if (port_cnt > osw->port_cnt) 7438321936Shselasky port_cnt = osw->port_cnt; 7439321936Shselasky 7440321936Shselasky for (p = 0; p < port_cnt; p++) { 7441321936Shselasky npt = nsw->port[p]; 7442321936Shselasky opt = osw->port[p]; 7443321936Shselasky 7444321936Shselasky if (npt && npt->link) { 7445321936Shselasky if (&npt->link->end[0] == npt) 7446321936Shselasky rnpt = &npt->link->end[1]; 7447321936Shselasky else 7448321936Shselasky rnpt = &npt->link->end[0]; 7449321936Shselasky } else 7450321936Shselasky rnpt = NULL; 7451321936Shselasky 7452321936Shselasky if (opt && opt->link) { 7453321936Shselasky if (&opt->link->end[0] == opt) 7454321936Shselasky ropt = &opt->link->end[1]; 7455321936Shselasky else 7456321936Shselasky ropt = &opt->link->end[0]; 7457321936Shselasky } else 7458321936Shselasky ropt = NULL; 7459321936Shselasky 7460321936Shselasky if (rnpt && !ropt) { 7461321936Shselasky ++cnt; 7462321936Shselasky OSM_LOG(&nsw->torus->osm->log, OSM_LOG_INFO, 7463321936Shselasky "Torus switch %d,%d,%d GUID 0x%04"PRIx64"[%d] " 7464321936Shselasky "remote now %s GUID 0x%04"PRIx64"[%d], " 7465321936Shselasky "was missing\n", 7466321936Shselasky nsw->i, nsw->j, nsw->k, cl_ntoh64(nsw->n_id), 7467321936Shselasky p, rnpt->type == PASSTHRU ? "sw" : "node", 7468321936Shselasky cl_ntoh64(rnpt->n_id), rnpt->port); 7469321936Shselasky continue; 7470321936Shselasky } 7471321936Shselasky if (ropt && !rnpt) { 7472321936Shselasky ++cnt; 7473321936Shselasky OSM_LOG(&nsw->torus->osm->log, OSM_LOG_INFO, 7474321936Shselasky "Torus switch %d,%d,%d GUID 0x%04"PRIx64"[%d] " 7475321936Shselasky "remote now missing, " 7476321936Shselasky "was %s GUID 0x%04"PRIx64"[%d]\n", 7477321936Shselasky osw->i, osw->j, osw->k, cl_ntoh64(nsw->n_id), 7478321936Shselasky p, ropt->type == PASSTHRU ? "sw" : "node", 7479321936Shselasky cl_ntoh64(ropt->n_id), ropt->port); 7480321936Shselasky continue; 7481321936Shselasky } 7482321936Shselasky if (!(rnpt && ropt)) 7483321936Shselasky continue; 7484321936Shselasky 7485321936Shselasky if (rnpt->n_id != ropt->n_id) { 7486321936Shselasky ++cnt; 7487321936Shselasky OSM_LOG(&nsw->torus->osm->log, OSM_LOG_INFO, 7488321936Shselasky "Torus switch %d,%d,%d GUID 0x%04"PRIx64"[%d] " 7489321936Shselasky "remote now %s GUID 0x%04"PRIx64"[%d], " 7490321936Shselasky "was %s GUID 0x%04"PRIx64"[%d]\n", 7491321936Shselasky nsw->i, nsw->j, nsw->k, cl_ntoh64(nsw->n_id), 7492321936Shselasky p, rnpt->type == PASSTHRU ? "sw" : "node", 7493321936Shselasky cl_ntoh64(rnpt->n_id), rnpt->port, 7494321936Shselasky ropt->type == PASSTHRU ? "sw" : "node", 7495321936Shselasky cl_ntoh64(ropt->n_id), ropt->port); 7496321936Shselasky continue; 7497321936Shselasky } 7498321936Shselasky } 7499321936Shselaskyout: 7500321936Shselasky return cnt; 7501321936Shselasky} 7502321936Shselasky 7503321936Shselaskystatic 7504321936Shselaskyvoid dump_torus(struct torus *t) 7505321936Shselasky{ 7506321936Shselasky unsigned i, j, k; 7507321936Shselasky unsigned x_sz = t->x_sz; 7508321936Shselasky unsigned y_sz = t->y_sz; 7509321936Shselasky unsigned z_sz = t->z_sz; 7510321936Shselasky char path[1024]; 7511321936Shselasky FILE *file; 7512321936Shselasky 7513321936Shselasky snprintf(path, sizeof(path), "%s/%s", t->osm->subn.opt.dump_files_dir, 7514321936Shselasky "opensm-torus.dump"); 7515321936Shselasky file = fopen(path, "w"); 7516321936Shselasky if (!file) { 7517321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7518321936Shselasky "ERR 4E47: cannot create file \'%s\'\n", path); 7519321936Shselasky return; 7520321936Shselasky } 7521321936Shselasky 7522321936Shselasky for (k = 0; k < z_sz; k++) 7523321936Shselasky for (j = 0; j < y_sz; j++) 7524321936Shselasky for (i = 0; i < x_sz; i++) 7525321936Shselasky if (t->sw[i][j][k]) 7526321936Shselasky fprintf(file, "switch %u,%u,%u GUID 0x%04" 7527321936Shselasky PRIx64 " (%s)\n", 7528321936Shselasky i, j, k, 7529321936Shselasky cl_ntoh64(t->sw[i][j][k]->n_id), 7530321936Shselasky t->sw[i][j][k]->osm_switch->p_node->print_desc); 7531321936Shselasky fclose(file); 7532321936Shselasky} 7533321936Shselasky 7534321936Shselaskystatic 7535321936Shselaskyvoid report_torus_changes(struct torus *nt, struct torus *ot) 7536321936Shselasky{ 7537321936Shselasky unsigned cnt = 0; 7538321936Shselasky unsigned i, j, k; 7539321936Shselasky unsigned x_sz = nt->x_sz; 7540321936Shselasky unsigned y_sz = nt->y_sz; 7541321936Shselasky unsigned z_sz = nt->z_sz; 7542321936Shselasky unsigned max_changes = nt->max_changes; 7543321936Shselasky 7544321936Shselasky if (OSM_LOG_IS_ACTIVE_V2(&nt->osm->log, OSM_LOG_ROUTING)) 7545321936Shselasky dump_torus(nt); 7546321936Shselasky 7547321936Shselasky if (!ot) 7548321936Shselasky return; 7549321936Shselasky 7550321936Shselasky if (x_sz != ot->x_sz) { 7551321936Shselasky cnt++; 7552321936Shselasky OSM_LOG(&nt->osm->log, OSM_LOG_INFO, 7553321936Shselasky "Torus x radix was %d now %d\n", 7554321936Shselasky ot->x_sz, nt->x_sz); 7555321936Shselasky if (x_sz > ot->x_sz) 7556321936Shselasky x_sz = ot->x_sz; 7557321936Shselasky } 7558321936Shselasky if (y_sz != ot->y_sz) { 7559321936Shselasky cnt++; 7560321936Shselasky OSM_LOG(&nt->osm->log, OSM_LOG_INFO, 7561321936Shselasky "Torus y radix was %d now %d\n", 7562321936Shselasky ot->y_sz, nt->y_sz); 7563321936Shselasky if (y_sz > ot->y_sz) 7564321936Shselasky y_sz = ot->y_sz; 7565321936Shselasky } 7566321936Shselasky if (z_sz != ot->z_sz) { 7567321936Shselasky cnt++; 7568321936Shselasky OSM_LOG(&nt->osm->log, OSM_LOG_INFO, 7569321936Shselasky "Torus z radix was %d now %d\n", 7570321936Shselasky ot->z_sz, nt->z_sz); 7571321936Shselasky if (z_sz > ot->z_sz) 7572321936Shselasky z_sz = ot->z_sz; 7573321936Shselasky } 7574321936Shselasky 7575321936Shselasky for (k = 0; k < z_sz; k++) 7576321936Shselasky for (j = 0; j < y_sz; j++) 7577321936Shselasky for (i = 0; i < x_sz; i++) { 7578321936Shselasky cnt += tsw_changes(nt->sw[i][j][k], 7579321936Shselasky ot->sw[i][j][k]); 7580321936Shselasky /* 7581321936Shselasky * Booting a big fabric will cause lots of 7582321936Shselasky * changes as hosts come up, so don't spew. 7583321936Shselasky * We want to log changes to learn more about 7584321936Shselasky * bouncing links, etc, so they can be fixed. 7585321936Shselasky */ 7586321936Shselasky if (cnt > max_changes) { 7587321936Shselasky OSM_LOG(&nt->osm->log, OSM_LOG_INFO, 7588321936Shselasky "Too many torus changes; " 7589321936Shselasky "stopping reporting early\n"); 7590321936Shselasky return; 7591321936Shselasky } 7592321936Shselasky } 7593321936Shselasky} 7594321936Shselasky 7595321936Shselaskystatic 7596321936Shselaskyvoid rpt_torus_missing(struct torus *t, int i, int j, int k, 7597321936Shselasky struct t_switch *sw, int *missing_z) 7598321936Shselasky{ 7599321936Shselasky uint64_t guid_ho; 7600321936Shselasky 7601321936Shselasky if (!sw) { 7602321936Shselasky /* 7603321936Shselasky * We can have multiple missing switches without deadlock 7604321936Shselasky * if and only if they are adajacent in the Z direction. 7605321936Shselasky */ 7606321936Shselasky if ((t->switch_cnt + 1) < t->sw_pool_sz) { 7607321936Shselasky if (t->sw[i][j][canonicalize(k - 1, t->z_sz)] && 7608321936Shselasky t->sw[i][j][canonicalize(k + 1, t->z_sz)]) 7609321936Shselasky t->flags |= MSG_DEADLOCK; 7610321936Shselasky } 7611321936Shselasky /* 7612321936Shselasky * There can be only one such Z-column of missing switches. 7613321936Shselasky */ 7614321936Shselasky if (*missing_z < 0) 7615321936Shselasky *missing_z = i + j * t->x_sz; 7616321936Shselasky else if (*missing_z != i + j * t->x_sz) 7617321936Shselasky t->flags |= MSG_DEADLOCK; 7618321936Shselasky 7619321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, 7620321936Shselasky "Missing torus switch at %d,%d,%d\n", i, j, k); 7621321936Shselasky return; 7622321936Shselasky } 7623321936Shselasky guid_ho = cl_ntoh64(sw->n_id); 7624321936Shselasky 7625321936Shselasky if (!(sw->ptgrp[0].port_cnt || (t->x_sz == 1) || 7626321936Shselasky ((t->flags & X_MESH) && i == 0))) 7627321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, 7628321936Shselasky "Missing torus -x link on " 7629321936Shselasky "switch %d,%d,%d GUID 0x%04"PRIx64"\n", 7630321936Shselasky i, j, k, guid_ho); 7631321936Shselasky if (!(sw->ptgrp[1].port_cnt || (t->x_sz == 1) || 7632321936Shselasky ((t->flags & X_MESH) && (i + 1) == t->x_sz))) 7633321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, 7634321936Shselasky "Missing torus +x link on " 7635321936Shselasky "switch %d,%d,%d GUID 0x%04"PRIx64"\n", 7636321936Shselasky i, j, k, guid_ho); 7637321936Shselasky if (!(sw->ptgrp[2].port_cnt || (t->y_sz == 1) || 7638321936Shselasky ((t->flags & Y_MESH) && j == 0))) 7639321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, 7640321936Shselasky "Missing torus -y link on " 7641321936Shselasky "switch %d,%d,%d GUID 0x%04"PRIx64"\n", 7642321936Shselasky i, j, k, guid_ho); 7643321936Shselasky if (!(sw->ptgrp[3].port_cnt || (t->y_sz == 1) || 7644321936Shselasky ((t->flags & Y_MESH) && (j + 1) == t->y_sz))) 7645321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, 7646321936Shselasky "Missing torus +y link on " 7647321936Shselasky "switch %d,%d,%d GUID 0x%04"PRIx64"\n", 7648321936Shselasky i, j, k, guid_ho); 7649321936Shselasky if (!(sw->ptgrp[4].port_cnt || (t->z_sz == 1) || 7650321936Shselasky ((t->flags & Z_MESH) && k == 0))) 7651321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, 7652321936Shselasky "Missing torus -z link on " 7653321936Shselasky "switch %d,%d,%d GUID 0x%04"PRIx64"\n", 7654321936Shselasky i, j, k, guid_ho); 7655321936Shselasky if (!(sw->ptgrp[5].port_cnt || (t->z_sz == 1) || 7656321936Shselasky ((t->flags & Z_MESH) && (k + 1) == t->z_sz))) 7657321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, 7658321936Shselasky "Missing torus +z link on " 7659321936Shselasky "switch %d,%d,%d GUID 0x%04"PRIx64"\n", 7660321936Shselasky i, j, k, guid_ho); 7661321936Shselasky} 7662321936Shselasky 7663321936Shselasky/* 7664321936Shselasky * Returns true if the torus can be successfully routed, false otherwise. 7665321936Shselasky */ 7666321936Shselaskystatic 7667321936Shselaskybool routable_torus(struct torus *t, struct fabric *f) 7668321936Shselasky{ 7669321936Shselasky int i, j, k, tmp = -1; 7670321936Shselasky unsigned b2g_cnt, g2b_cnt; 7671321936Shselasky bool success = true; 7672321936Shselasky 7673321936Shselasky t->flags &= ~MSG_DEADLOCK; 7674321936Shselasky 7675321936Shselasky if (t->link_cnt != f->link_cnt || t->switch_cnt != f->switch_cnt) 7676321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_INFO, 7677321936Shselasky "Warning: Could not construct torus using all " 7678321936Shselasky "known fabric switches and/or links.\n"); 7679321936Shselasky 7680321936Shselasky for (k = 0; k < (int)t->z_sz; k++) 7681321936Shselasky for (j = 0; j < (int)t->y_sz; j++) 7682321936Shselasky for (i = 0; i < (int)t->x_sz; i++) 7683321936Shselasky rpt_torus_missing(t, i, j, k, 7684321936Shselasky t->sw[i][j][k], &tmp); 7685321936Shselasky /* 7686321936Shselasky * Check for multiple failures that create disjoint regions on a ring. 7687321936Shselasky */ 7688321936Shselasky for (k = 0; k < (int)t->z_sz; k++) 7689321936Shselasky for (j = 0; j < (int)t->y_sz; j++) { 7690321936Shselasky b2g_cnt = 0; 7691321936Shselasky g2b_cnt = 0; 7692321936Shselasky for (i = 0; i < (int)t->x_sz; i++) { 7693321936Shselasky 7694321936Shselasky if (!t->sw[i][j][k]) 7695321936Shselasky continue; 7696321936Shselasky 7697321936Shselasky if (!t->sw[i][j][k]->ptgrp[0].port_cnt) 7698321936Shselasky b2g_cnt++; 7699321936Shselasky if (!t->sw[i][j][k]->ptgrp[1].port_cnt) 7700321936Shselasky g2b_cnt++; 7701321936Shselasky } 7702321936Shselasky if (b2g_cnt != g2b_cnt) { 7703321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7704321936Shselasky "ERR 4E32: strange failures in " 7705321936Shselasky "x ring at y=%d z=%d" 7706321936Shselasky " b2g_cnt %u g2b_cnt %u\n", 7707321936Shselasky j, k, b2g_cnt, g2b_cnt); 7708321936Shselasky success = false; 7709321936Shselasky } 7710321936Shselasky if (b2g_cnt > 1) { 7711321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7712321936Shselasky "ERR 4E33: disjoint failures in " 7713321936Shselasky "x ring at y=%d z=%d\n", j, k); 7714321936Shselasky success = false; 7715321936Shselasky } 7716321936Shselasky } 7717321936Shselasky 7718321936Shselasky for (i = 0; i < (int)t->x_sz; i++) 7719321936Shselasky for (k = 0; k < (int)t->z_sz; k++) { 7720321936Shselasky b2g_cnt = 0; 7721321936Shselasky g2b_cnt = 0; 7722321936Shselasky for (j = 0; j < (int)t->y_sz; j++) { 7723321936Shselasky 7724321936Shselasky if (!t->sw[i][j][k]) 7725321936Shselasky continue; 7726321936Shselasky 7727321936Shselasky if (!t->sw[i][j][k]->ptgrp[2].port_cnt) 7728321936Shselasky b2g_cnt++; 7729321936Shselasky if (!t->sw[i][j][k]->ptgrp[3].port_cnt) 7730321936Shselasky g2b_cnt++; 7731321936Shselasky } 7732321936Shselasky if (b2g_cnt != g2b_cnt) { 7733321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7734321936Shselasky "ERR 4E34: strange failures in " 7735321936Shselasky "y ring at x=%d z=%d" 7736321936Shselasky " b2g_cnt %u g2b_cnt %u\n", 7737321936Shselasky i, k, b2g_cnt, g2b_cnt); 7738321936Shselasky success = false; 7739321936Shselasky } 7740321936Shselasky if (b2g_cnt > 1) { 7741321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7742321936Shselasky "ERR 4E35: disjoint failures in " 7743321936Shselasky "y ring at x=%d z=%d\n", i, k); 7744321936Shselasky success = false; 7745321936Shselasky } 7746321936Shselasky } 7747321936Shselasky 7748321936Shselasky for (j = 0; j < (int)t->y_sz; j++) 7749321936Shselasky for (i = 0; i < (int)t->x_sz; i++) { 7750321936Shselasky b2g_cnt = 0; 7751321936Shselasky g2b_cnt = 0; 7752321936Shselasky for (k = 0; k < (int)t->z_sz; k++) { 7753321936Shselasky 7754321936Shselasky if (!t->sw[i][j][k]) 7755321936Shselasky continue; 7756321936Shselasky 7757321936Shselasky if (!t->sw[i][j][k]->ptgrp[4].port_cnt) 7758321936Shselasky b2g_cnt++; 7759321936Shselasky if (!t->sw[i][j][k]->ptgrp[5].port_cnt) 7760321936Shselasky g2b_cnt++; 7761321936Shselasky } 7762321936Shselasky if (b2g_cnt != g2b_cnt) { 7763321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7764321936Shselasky "ERR 4E36: strange failures in " 7765321936Shselasky "z ring at x=%d y=%d" 7766321936Shselasky " b2g_cnt %u g2b_cnt %u\n", 7767321936Shselasky i, j, b2g_cnt, g2b_cnt); 7768321936Shselasky success = false; 7769321936Shselasky } 7770321936Shselasky if (b2g_cnt > 1) { 7771321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7772321936Shselasky "ERR 4E37: disjoint failures in " 7773321936Shselasky "z ring at x=%d y=%d\n", i, j); 7774321936Shselasky success = false; 7775321936Shselasky } 7776321936Shselasky } 7777321936Shselasky 7778321936Shselasky if (t->flags & MSG_DEADLOCK) { 7779321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 7780321936Shselasky "ERR 4E38: missing switch topology " 7781321936Shselasky "==> message deadlock!\n"); 7782321936Shselasky success = false; 7783321936Shselasky } 7784321936Shselasky return success; 7785321936Shselasky} 7786321936Shselasky 7787321936Shselasky/* 7788321936Shselasky * Use this function to re-establish the pointers between a torus endpoint 7789321936Shselasky * and an opensm osm_port_t. 7790321936Shselasky * 7791321936Shselasky * Typically this is only needed when "opensm --ucast-cache" is used, and 7792321936Shselasky * a CA link bounces. When the CA port goes away, the osm_port_t object 7793321936Shselasky * is destroyed, invalidating the endpoint osm_port_t pointer. When the 7794321936Shselasky * link comes back, a new osm_port_t object is created with a NULL priv 7795321936Shselasky * member. Thus, when osm_get_torus_sl() is called it is missing the data 7796321936Shselasky * needed to do its work. Use this function to fix things up. 7797321936Shselasky */ 7798321936Shselaskystatic 7799321936Shselaskystruct endpoint *osm_port_relink_endpoint(const osm_port_t *osm_port) 7800321936Shselasky{ 7801321936Shselasky guid_t node_guid; 7802321936Shselasky uint8_t port_num, r_port_num; 7803321936Shselasky struct t_switch *sw; 7804321936Shselasky struct endpoint *ep = NULL; 7805321936Shselasky osm_switch_t *osm_sw; 7806321936Shselasky osm_physp_t *osm_physp; 7807321936Shselasky osm_node_t *osm_node, *r_osm_node; 7808321936Shselasky 7809321936Shselasky /* 7810321936Shselasky * We need to find the torus endpoint that has the same GUID as 7811321936Shselasky * the osm_port. Rather than search the entire set of endpoints, 7812321936Shselasky * we'll try to follow pointers. 7813321936Shselasky */ 7814321936Shselasky osm_physp = osm_port->p_physp; 7815321936Shselasky osm_node = osm_port->p_node; 7816321936Shselasky port_num = osm_physp_get_port_num(osm_physp); 7817321936Shselasky node_guid = osm_node_get_node_guid(osm_node); 7818321936Shselasky /* 7819321936Shselasky * Switch management port? 7820321936Shselasky */ 7821321936Shselasky if (port_num == 0 && 7822321936Shselasky osm_node_get_type(osm_node) == IB_NODE_TYPE_SWITCH) { 7823321936Shselasky 7824321936Shselasky osm_sw = osm_node->sw; 7825321936Shselasky if (osm_sw && osm_sw->priv) { 7826321936Shselasky sw = osm_sw->priv; 7827321936Shselasky if (sw->osm_switch == osm_sw && 7828321936Shselasky sw->port[0]->n_id == node_guid) { 7829321936Shselasky 7830321936Shselasky ep = sw->port[0]; 7831321936Shselasky goto relink_priv; 7832321936Shselasky } 7833321936Shselasky } 7834321936Shselasky } 7835321936Shselasky /* 7836321936Shselasky * CA port? Try other end of link. This should also catch a 7837321936Shselasky * router port if it is connected to a switch. 7838321936Shselasky */ 7839321936Shselasky r_osm_node = osm_node_get_remote_node(osm_node, port_num, &r_port_num); 7840321936Shselasky if (!r_osm_node) 7841321936Shselasky goto out; 7842321936Shselasky 7843321936Shselasky osm_sw = r_osm_node->sw; 7844321936Shselasky if (!osm_sw) 7845321936Shselasky goto out; 7846321936Shselasky 7847321936Shselasky sw = osm_sw->priv; 7848321936Shselasky if (!(sw && sw->osm_switch == osm_sw)) 7849321936Shselasky goto out; 7850321936Shselasky 7851321936Shselasky ep = sw->port[r_port_num]; 7852321936Shselasky if (!(ep && ep->link)) 7853321936Shselasky goto out; 7854321936Shselasky 7855321936Shselasky if (ep->link->end[0].n_id == node_guid) { 7856321936Shselasky ep = &ep->link->end[0]; 7857321936Shselasky goto relink_priv; 7858321936Shselasky } 7859321936Shselasky if (ep->link->end[1].n_id == node_guid) { 7860321936Shselasky ep = &ep->link->end[1]; 7861321936Shselasky goto relink_priv; 7862321936Shselasky } 7863321936Shselasky ep = NULL; 7864321936Shselasky goto out; 7865321936Shselasky 7866321936Shselaskyrelink_priv: 7867321936Shselasky /* FIXME: 7868321936Shselasky * Unfortunately, we need to cast away const to rebuild the links 7869321936Shselasky * between the torus endpoint and the osm_port_t. 7870321936Shselasky * 7871321936Shselasky * What is really needed is to check whether pr_rcv_get_path_parms() 7872321936Shselasky * needs its port objects to be const. If so, why, and whether 7873321936Shselasky * anything can be done about it. 7874321936Shselasky */ 7875321936Shselasky ((osm_port_t *)osm_port)->priv = ep; 7876321936Shselasky ep->osm_port = (osm_port_t *)osm_port; 7877321936Shselaskyout: 7878321936Shselasky return ep; 7879321936Shselasky} 7880321936Shselasky 7881321936Shselasky/* 7882321936Shselasky * Computing LFT entries and path SL values: 7883321936Shselasky * 7884321936Shselasky * For a pristine torus, we compute LFT entries using XYZ DOR, and select 7885321936Shselasky * which direction to route on a ring (i.e., the 1-D torus for the coordinate 7886321936Shselasky * in question) based on shortest path. We compute the SL to use for the 7887321936Shselasky * path based on whether we crossed a dateline (where a ring coordinate 7888321936Shselasky * wraps to zero) for each coordinate. 7889321936Shselasky * 7890321936Shselasky * When there is a link/switch failure, we want to compute LFT entries 7891321936Shselasky * to route around the failure, without changing the path SL. I.e., we 7892321936Shselasky * want the SL to reach a given destination from a given source to be 7893321936Shselasky * independent of the presence or number of failed components in the fabric. 7894321936Shselasky * 7895321936Shselasky * In order to make this feasible, we will assume that no ring is broken 7896321936Shselasky * into disjoint pieces by multiple failures 7897321936Shselasky * 7898321936Shselasky * We handle failure by attempting to take the long way around any ring 7899321936Shselasky * with connectivity interrupted by failed components, unless the path 7900321936Shselasky * requires a turn on a failed switch. 7901321936Shselasky * 7902321936Shselasky * For paths that require a turn on a failed switch, we head towards the 7903321936Shselasky * failed switch, then turn when progress is blocked by a failure, using a 7904321936Shselasky * turn allowed under XYZ DOR. However, such a path will also require a turn 7905321936Shselasky * that is not a legal XYZ DOR turn, so we construct the SL2VL mapping tables 7906321936Shselasky * such that XYZ DOR turns use one set of VLs and ZYX DOR turns use a 7907321936Shselasky * separate set of VLs. 7908321936Shselasky * 7909321936Shselasky * Under these rules the algorithm guarantees credit-loop-free routing for a 7910321936Shselasky * single failed switch, without any change in path SL values. We can also 7911321936Shselasky * guarantee credit-loop-free routing for failures of multiple switches, if 7912321936Shselasky * they are adjacent in the last DOR direction. Since we use XYZ-DOR, 7913321936Shselasky * that means failed switches at i,j,k and i,j,k+1 will not cause credit 7914321936Shselasky * loops. 7915321936Shselasky * 7916321936Shselasky * These failure routing rules are intended to prevent paths that cross any 7917321936Shselasky * coordinate dateline twice (over and back), so we don't need to worry about 7918321936Shselasky * any ambiguity over which SL to use for such a case. Also, we cannot have 7919321936Shselasky * a ring deadlock when a ring is broken by failure and we route the long 7920321936Shselasky * way around, so we don't need to worry about the impact of such routing 7921321936Shselasky * on SL choice. 7922321936Shselasky */ 7923321936Shselasky 7924321936Shselasky/* 7925321936Shselasky * Functions to set our SL bit encoding for routing/QoS info. Combine the 7926321936Shselasky * resuts of these functions with bitwise or to get final SL. 7927321936Shselasky * 7928321936Shselasky * SL bits 0-2 encode whether we "looped" in a given direction 7929321936Shselasky * on the torus on the path from source to destination. 7930321936Shselasky * 7931321936Shselasky * SL bit 3 encodes the QoS level. We only support two QoS levels. 7932321936Shselasky * 7933321936Shselasky * Below we assume TORUS_MAX_DIM == 3 and 0 <= coord_dir < TORUS_MAX_DIM. 7934321936Shselasky */ 7935321936Shselaskystatic inline 7936321936Shselaskyunsigned sl_set_use_loop_vl(bool use_loop_vl, unsigned coord_dir) 7937321936Shselasky{ 7938321936Shselasky return (coord_dir < TORUS_MAX_DIM) 7939321936Shselasky ? ((unsigned)use_loop_vl << coord_dir) : 0; 7940321936Shselasky} 7941321936Shselasky 7942321936Shselaskystatic inline 7943321936Shselaskyunsigned sl_set_qos(unsigned qos) 7944321936Shselasky{ 7945321936Shselasky return (unsigned)(!!qos) << TORUS_MAX_DIM; 7946321936Shselasky} 7947321936Shselasky 7948321936Shselasky/* 7949321936Shselasky * Functions to crack our SL bit encoding for routing/QoS info. 7950321936Shselasky */ 7951321936Shselaskystatic inline 7952321936Shselaskybool sl_get_use_loop_vl(unsigned sl, unsigned coord_dir) 7953321936Shselasky{ 7954321936Shselasky return (coord_dir < TORUS_MAX_DIM) 7955321936Shselasky ? (sl >> coord_dir) & 0x1 : false; 7956321936Shselasky} 7957321936Shselasky 7958321936Shselaskystatic inline 7959321936Shselaskyunsigned sl_get_qos(unsigned sl) 7960321936Shselasky{ 7961321936Shselasky return (sl >> TORUS_MAX_DIM) & 0x1; 7962321936Shselasky} 7963321936Shselasky 7964321936Shselasky/* 7965321936Shselasky * Functions to encode routing/QoS info into VL bits. Combine the resuts of 7966321936Shselasky * these functions with bitwise or to get final VL. 7967321936Shselasky * 7968321936Shselasky * For interswitch links: 7969321936Shselasky * VL bit 0 encodes whether we need to leave on the "loop" VL. 7970321936Shselasky * 7971321936Shselasky * VL bit 1 encodes whether turn is XYZ DOR or ZYX DOR. A 3d mesh/torus 7972321936Shselasky * has 6 turn types: x-y, y-z, x-z, y-x, z-y, z-x. The first three are 7973321936Shselasky * legal XYZ DOR turns, and the second three are legal ZYX DOR turns. 7974321936Shselasky * Straight-through (x-x, y-y, z-z) paths are legal in both DOR variants, 7975321936Shselasky * so we'll assign them to XYZ DOR VLs. 7976321936Shselasky * 7977321936Shselasky * Note that delivery to switch-local ports (i.e. those that source/sink 7978321936Shselasky * traffic, rather than forwarding it) cannot cause a deadlock, so that 7979321936Shselasky * can also use either XYZ or ZYX DOR. 7980321936Shselasky * 7981321936Shselasky * VL bit 2 encodes QoS level. 7982321936Shselasky * 7983321936Shselasky * For end port links: 7984321936Shselasky * VL bit 0 encodes QoS level. 7985321936Shselasky * 7986321936Shselasky * Note that if VL bit encodings are changed here, the available fabric VL 7987321936Shselasky * verification in verify_setup() needs to be updated as well. 7988321936Shselasky */ 7989321936Shselaskystatic inline 7990321936Shselaskyunsigned vl_set_loop_vl(bool use_loop_vl) 7991321936Shselasky{ 7992321936Shselasky return use_loop_vl; 7993321936Shselasky} 7994321936Shselasky 7995321936Shselaskystatic inline 7996321936Shselaskyunsigned vl_set_qos_vl(unsigned qos) 7997321936Shselasky{ 7998321936Shselasky return (qos & 0x1) << 2; 7999321936Shselasky} 8000321936Shselasky 8001321936Shselaskystatic inline 8002321936Shselaskyunsigned vl_set_ca_qos_vl(unsigned qos) 8003321936Shselasky{ 8004321936Shselasky return qos & 0x1; 8005321936Shselasky} 8006321936Shselasky 8007321936Shselaskystatic inline 8008321936Shselaskyunsigned vl_set_turn_vl(unsigned in_coord_dir, unsigned out_coord_dir) 8009321936Shselasky{ 8010321936Shselasky unsigned vl = 0; 8011321936Shselasky 8012321936Shselasky if (in_coord_dir != TORUS_MAX_DIM && 8013321936Shselasky out_coord_dir != TORUS_MAX_DIM) 8014321936Shselasky vl = (in_coord_dir > out_coord_dir) 8015321936Shselasky ? 0x1 << 1 : 0; 8016321936Shselasky 8017321936Shselasky return vl; 8018321936Shselasky} 8019321936Shselasky 8020321936Shselaskystatic 8021321936Shselaskyunsigned sl2vl_entry(struct torus *t, struct t_switch *sw, 8022321936Shselasky int input_pt, int output_pt, unsigned sl) 8023321936Shselasky{ 8024321936Shselasky unsigned id, od, vl, data_vls; 8025321936Shselasky 8026321936Shselasky if (sw && sw->port[input_pt]) 8027321936Shselasky id = sw->port[input_pt]->pgrp->port_grp / 2; 8028321936Shselasky else 8029321936Shselasky id = TORUS_MAX_DIM; 8030321936Shselasky 8031321936Shselasky if (sw && sw->port[output_pt]) 8032321936Shselasky od = sw->port[output_pt]->pgrp->port_grp / 2; 8033321936Shselasky else 8034321936Shselasky od = TORUS_MAX_DIM; 8035321936Shselasky 8036321936Shselasky if (sw) 8037321936Shselasky data_vls = t->osm->subn.min_sw_data_vls; 8038321936Shselasky else 8039321936Shselasky data_vls = t->osm->subn.min_data_vls; 8040321936Shselasky 8041321936Shselasky vl = 0; 8042321936Shselasky if (sw && od != TORUS_MAX_DIM) { 8043321936Shselasky if (data_vls >= 2) 8044321936Shselasky vl |= vl_set_loop_vl(sl_get_use_loop_vl(sl, od)); 8045321936Shselasky if (data_vls >= 4) 8046321936Shselasky vl |= vl_set_turn_vl(id, od); 8047321936Shselasky if (data_vls >= 8) 8048321936Shselasky vl |= vl_set_qos_vl(sl_get_qos(sl)); 8049321936Shselasky } else { 8050321936Shselasky if (data_vls >= 2) 8051321936Shselasky vl |= vl_set_ca_qos_vl(sl_get_qos(sl)); 8052321936Shselasky } 8053321936Shselasky return vl; 8054321936Shselasky} 8055321936Shselasky 8056321936Shselaskystatic 8057321936Shselaskyvoid torus_update_osm_sl2vl(void *context, osm_physp_t *osm_phys_port, 8058321936Shselasky uint8_t iport_num, uint8_t oport_num, 8059321936Shselasky ib_slvl_table_t *osm_oport_sl2vl) 8060321936Shselasky{ 8061321936Shselasky osm_node_t *node = osm_physp_get_node_ptr(osm_phys_port); 8062321936Shselasky struct torus_context *ctx = context; 8063321936Shselasky struct t_switch *sw = NULL; 8064321936Shselasky int sl, vl; 8065321936Shselasky 8066321936Shselasky if (node->sw) { 8067321936Shselasky sw = node->sw->priv; 8068321936Shselasky if (sw && sw->osm_switch != node->sw) { 8069321936Shselasky osm_log_t *log = &ctx->osm->log; 8070321936Shselasky guid_t guid; 8071321936Shselasky 8072321936Shselasky guid = osm_node_get_node_guid(node); 8073321936Shselasky OSM_LOG(log, OSM_LOG_INFO, 8074321936Shselasky "Note: osm_switch (GUID 0x%04"PRIx64") " 8075321936Shselasky "not in torus fabric description\n", 8076321936Shselasky cl_ntoh64(guid)); 8077321936Shselasky return; 8078321936Shselasky } 8079321936Shselasky } 8080321936Shselasky for (sl = 0; sl < 16; sl++) { 8081321936Shselasky vl = sl2vl_entry(ctx->torus, sw, iport_num, oport_num, sl); 8082321936Shselasky ib_slvl_table_set(osm_oport_sl2vl, sl, vl); 8083321936Shselasky } 8084321936Shselasky} 8085321936Shselasky 8086321936Shselaskystatic 8087321936Shselaskyvoid torus_update_osm_vlarb(void *context, osm_physp_t *osm_phys_port, 8088321936Shselasky uint8_t port_num, ib_vl_arb_table_t *block, 8089321936Shselasky unsigned block_length, unsigned block_num) 8090321936Shselasky{ 8091321936Shselasky osm_node_t *node = osm_physp_get_node_ptr(osm_phys_port); 8092321936Shselasky struct torus_context *ctx = context; 8093321936Shselasky struct t_switch *sw = NULL; 8094321936Shselasky unsigned i, next; 8095321936Shselasky 8096321936Shselasky if (node->sw) { 8097321936Shselasky sw = node->sw->priv; 8098321936Shselasky if (sw && sw->osm_switch != node->sw) { 8099321936Shselasky osm_log_t *log = &ctx->osm->log; 8100321936Shselasky guid_t guid; 8101321936Shselasky 8102321936Shselasky guid = osm_node_get_node_guid(node); 8103321936Shselasky OSM_LOG(log, OSM_LOG_INFO, 8104321936Shselasky "Note: osm_switch (GUID 0x%04"PRIx64") " 8105321936Shselasky "not in torus fabric description\n", 8106321936Shselasky cl_ntoh64(guid)); 8107321936Shselasky return; 8108321936Shselasky } 8109321936Shselasky } 8110321936Shselasky 8111321936Shselasky /* 8112321936Shselasky * If osm_phys_port is a switch port that connects to a CA, then 8113321936Shselasky * we're using at most VL 0 (for QoS level 0) and VL 1 (for QoS 8114321936Shselasky * level 1). We've been passed the VLarb values for a switch 8115321936Shselasky * external port, so we need to fix them up to avoid unexpected 8116321936Shselasky * results depending on how the switch handles VLarb values for 8117321936Shselasky * unprogrammed VLs. 8118321936Shselasky * 8119321936Shselasky * For inter-switch links torus-2QoS uses VLs 0-3 to implement 8120321936Shselasky * QoS level 0, and VLs 4-7 to implement QoS level 1. 8121321936Shselasky * 8122321936Shselasky * So, leave VL 0 alone, remap VL 4 to VL 1, zero out the rest, 8123321936Shselasky * and compress out the zero entries to the end. 8124321936Shselasky */ 8125321936Shselasky if (!sw || !port_num || !sw->port[port_num] || 8126321936Shselasky sw->port[port_num]->pgrp->port_grp != 2 * TORUS_MAX_DIM) 8127321936Shselasky return; 8128321936Shselasky 8129321936Shselasky next = 0; 8130321936Shselasky for (i = 0; i < block_length; i++) { 8131321936Shselasky switch (block->vl_entry[i].vl) { 8132321936Shselasky case 4: 8133321936Shselasky block->vl_entry[i].vl = 1; 8134321936Shselasky /* fall through */ 8135321936Shselasky case 0: 8136321936Shselasky block->vl_entry[next].vl = block->vl_entry[i].vl; 8137321936Shselasky block->vl_entry[next].weight = block->vl_entry[i].weight; 8138321936Shselasky next++; 8139321936Shselasky /* 8140321936Shselasky * If we didn't update vl_entry[i] in place, 8141321936Shselasky * fall through to zero it out. 8142321936Shselasky */ 8143321936Shselasky if (next > i) 8144321936Shselasky break; 8145321936Shselasky default: 8146321936Shselasky block->vl_entry[i].vl = 0; 8147321936Shselasky block->vl_entry[i].weight = 0; 8148321936Shselasky break; 8149321936Shselasky } 8150321936Shselasky } 8151321936Shselasky} 8152321936Shselasky 8153321936Shselasky/* 8154321936Shselasky * Computes the path lengths *vl0_len and *vl1_len to get from src 8155321936Shselasky * to dst on a ring with count switches. 8156321936Shselasky * 8157321936Shselasky * *vl0_len is the path length for a direct path; it corresponds to a path 8158321936Shselasky * that should be assigned to use VL0 in a switch. *vl1_len is the path 8159321936Shselasky * length for a path that wraps aroung the ring, i.e. where the ring index 8160321936Shselasky * goes from count to zero or from zero to count. It corresponds to the path 8161321936Shselasky * that should be assigned to use VL1 in a switch. 8162321936Shselasky */ 8163321936Shselaskystatic 8164321936Shselaskyvoid get_pathlen(unsigned src, unsigned dst, unsigned count, 8165321936Shselasky unsigned *vl0_len, unsigned *vl1_len) 8166321936Shselasky{ 8167321936Shselasky unsigned s, l; /* assume s < l */ 8168321936Shselasky 8169321936Shselasky if (dst > src) { 8170321936Shselasky s = src; 8171321936Shselasky l = dst; 8172321936Shselasky } else { 8173321936Shselasky s = dst; 8174321936Shselasky l = src; 8175321936Shselasky } 8176321936Shselasky *vl0_len = l - s; 8177321936Shselasky *vl1_len = s + count - l; 8178321936Shselasky} 8179321936Shselasky 8180321936Shselasky/* 8181321936Shselasky * Returns a positive number if we should take the "positive" ring direction 8182321936Shselasky * to reach dst from src, a negative number if we should take the "negative" 8183321936Shselasky * ring direction, and 0 if src and dst are the same. The choice is strictly 8184321936Shselasky * based on which path is shorter. 8185321936Shselasky */ 8186321936Shselaskystatic 8187321936Shselaskyint ring_dir_idx(unsigned src, unsigned dst, unsigned count) 8188321936Shselasky{ 8189321936Shselasky int r; 8190321936Shselasky unsigned vl0_len, vl1_len; 8191321936Shselasky 8192321936Shselasky if (dst == src) 8193321936Shselasky return 0; 8194321936Shselasky 8195321936Shselasky get_pathlen(src, dst, count, &vl0_len, &vl1_len); 8196321936Shselasky 8197321936Shselasky if (dst > src) 8198321936Shselasky r = vl0_len <= vl1_len ? 1 : -1; 8199321936Shselasky else 8200321936Shselasky r = vl0_len <= vl1_len ? -1 : 1; 8201321936Shselasky 8202321936Shselasky return r; 8203321936Shselasky} 8204321936Shselasky 8205321936Shselasky/* 8206321936Shselasky * Returns true if the VL1 path should be used to reach src from dst on a 8207321936Shselasky * ring, based on which path is shorter. 8208321936Shselasky */ 8209321936Shselaskystatic 8210321936Shselaskybool use_vl1(unsigned src, unsigned dst, unsigned count) 8211321936Shselasky{ 8212321936Shselasky unsigned vl0_len, vl1_len; 8213321936Shselasky 8214321936Shselasky get_pathlen(src, dst, count, &vl0_len, &vl1_len); 8215321936Shselasky 8216321936Shselasky return vl0_len <= vl1_len ? false : true; 8217321936Shselasky} 8218321936Shselasky 8219321936Shselasky/* 8220321936Shselasky * Returns the next switch in the ring of switches along coordinate direction 8221321936Shselasky * cdir, in the positive ring direction if rdir is positive, and in the 8222321936Shselasky * negative ring direction if rdir is negative. 8223321936Shselasky * 8224321936Shselasky * Returns NULL if rdir is zero, or there is no next switch. 8225321936Shselasky */ 8226321936Shselaskystatic 8227321936Shselaskystruct t_switch *ring_next_sw(struct t_switch *sw, unsigned cdir, int rdir) 8228321936Shselasky{ 8229321936Shselasky unsigned pt_grp, far_end = 0; 8230321936Shselasky 8231321936Shselasky if (!rdir) 8232321936Shselasky return NULL; 8233321936Shselasky /* 8234321936Shselasky * Recall that links are installed into the torus so that their 1 end 8235321936Shselasky * is in the "positive" coordinate direction relative to their 0 end 8236321936Shselasky * (see link_tswitches() and connect_tlink()). Recall also that for 8237321936Shselasky * interswitch links, all links in a given switch port group have the 8238321936Shselasky * same endpoints, so we just need to look at the first link. 8239321936Shselasky */ 8240321936Shselasky pt_grp = 2 * cdir; 8241321936Shselasky if (rdir > 0) { 8242321936Shselasky pt_grp++; 8243321936Shselasky far_end = 1; 8244321936Shselasky } 8245321936Shselasky 8246321936Shselasky if (!sw->ptgrp[pt_grp].port_cnt) 8247321936Shselasky return NULL; 8248321936Shselasky 8249321936Shselasky return sw->ptgrp[pt_grp].port[0]->link->end[far_end].sw; 8250321936Shselasky} 8251321936Shselasky 8252321936Shselasky/* 8253321936Shselasky * Returns a positive number if we should take the "positive" ring direction 8254321936Shselasky * to reach dsw from ssw, a negative number if we should take the "negative" 8255321936Shselasky * ring direction, and 0 if src and dst are the same, or if dsw is not 8256321936Shselasky * reachable from ssw because the path is interrupted by failure. 8257321936Shselasky */ 8258321936Shselaskystatic 8259321936Shselaskyint ring_dir_path(struct torus *t, unsigned cdir, 8260321936Shselasky struct t_switch *ssw, struct t_switch *dsw) 8261321936Shselasky{ 8262321936Shselasky int d = 0; 8263321936Shselasky struct t_switch *sw; 8264321936Shselasky 8265321936Shselasky switch (cdir) { 8266321936Shselasky case 0: 8267321936Shselasky d = ring_dir_idx(ssw->i, dsw->i, t->x_sz); 8268321936Shselasky break; 8269321936Shselasky case 1: 8270321936Shselasky d = ring_dir_idx(ssw->j, dsw->j, t->y_sz); 8271321936Shselasky break; 8272321936Shselasky case 2: 8273321936Shselasky d = ring_dir_idx(ssw->k, dsw->k, t->z_sz); 8274321936Shselasky break; 8275321936Shselasky default: 8276321936Shselasky break; 8277321936Shselasky } 8278321936Shselasky if (!d) 8279321936Shselasky goto out; 8280321936Shselasky 8281321936Shselasky sw = ssw; 8282321936Shselasky while (sw) { 8283321936Shselasky sw = ring_next_sw(sw, cdir, d); 8284321936Shselasky if (sw == dsw) 8285321936Shselasky goto out; 8286321936Shselasky } 8287321936Shselasky d *= -1; 8288321936Shselasky sw = ssw; 8289321936Shselasky while (sw) { 8290321936Shselasky sw = ring_next_sw(sw, cdir, d); 8291321936Shselasky if (sw == dsw) 8292321936Shselasky goto out; 8293321936Shselasky } 8294321936Shselasky d = 0; 8295321936Shselaskyout: 8296321936Shselasky return d; 8297321936Shselasky} 8298321936Shselasky 8299321936Shselasky/* 8300321936Shselasky * Returns true, and sets *pt_grp to the port group index to use for the 8301321936Shselasky * next hop, if it is possible to make progress from ssw to dsw along the 8302321936Shselasky * coordinate direction cdir, taking into account whether there are 8303321936Shselasky * interruptions in the path. 8304321936Shselasky * 8305321936Shselasky * This next hop result can be used without worrying about ring deadlocks - 8306321936Shselasky * if we don't choose the shortest path it is because there is a failure in 8307321936Shselasky * the ring, which removes the possibilility of a ring deadlock on that ring. 8308321936Shselasky */ 8309321936Shselaskystatic 8310321936Shselaskybool next_hop_path(struct torus *t, unsigned cdir, 8311321936Shselasky struct t_switch *ssw, struct t_switch *dsw, 8312321936Shselasky unsigned *pt_grp) 8313321936Shselasky{ 8314321936Shselasky struct t_switch *tsw = NULL; 8315321936Shselasky bool success = false; 8316321936Shselasky int d; 8317321936Shselasky 8318321936Shselasky /* 8319321936Shselasky * If the path from ssw to dsw turns, this is the switch where the 8320321936Shselasky * turn happens. 8321321936Shselasky */ 8322321936Shselasky switch (cdir) { 8323321936Shselasky case 0: 8324321936Shselasky tsw = t->sw[dsw->i][ssw->j][ssw->k]; 8325321936Shselasky break; 8326321936Shselasky case 1: 8327321936Shselasky tsw = t->sw[ssw->i][dsw->j][ssw->k]; 8328321936Shselasky break; 8329321936Shselasky case 2: 8330321936Shselasky tsw = t->sw[ssw->i][ssw->j][dsw->k]; 8331321936Shselasky break; 8332321936Shselasky default: 8333321936Shselasky goto out; 8334321936Shselasky } 8335321936Shselasky if (tsw) { 8336321936Shselasky d = ring_dir_path(t, cdir, ssw, tsw); 8337321936Shselasky cdir *= 2; 8338321936Shselasky if (d > 0) 8339321936Shselasky *pt_grp = cdir + 1; 8340321936Shselasky else if (d < 0) 8341321936Shselasky *pt_grp = cdir; 8342321936Shselasky else 8343321936Shselasky goto out; 8344321936Shselasky success = true; 8345321936Shselasky } 8346321936Shselaskyout: 8347321936Shselasky return success; 8348321936Shselasky} 8349321936Shselasky 8350321936Shselasky/* 8351321936Shselasky * Returns true, and sets *pt_grp to the port group index to use for the 8352321936Shselasky * next hop, if it is possible to make progress from ssw to dsw along the 8353321936Shselasky * coordinate direction cdir. This decision is made strictly on a 8354321936Shselasky * shortest-path basis without regard for path availability. 8355321936Shselasky */ 8356321936Shselaskystatic 8357321936Shselaskybool next_hop_idx(struct torus *t, unsigned cdir, 8358321936Shselasky struct t_switch *ssw, struct t_switch *dsw, 8359321936Shselasky unsigned *pt_grp) 8360321936Shselasky{ 8361321936Shselasky int d; 8362321936Shselasky unsigned g; 8363321936Shselasky bool success = false; 8364321936Shselasky 8365321936Shselasky switch (cdir) { 8366321936Shselasky case 0: 8367321936Shselasky d = ring_dir_idx(ssw->i, dsw->i, t->x_sz); 8368321936Shselasky break; 8369321936Shselasky case 1: 8370321936Shselasky d = ring_dir_idx(ssw->j, dsw->j, t->y_sz); 8371321936Shselasky break; 8372321936Shselasky case 2: 8373321936Shselasky d = ring_dir_idx(ssw->k, dsw->k, t->z_sz); 8374321936Shselasky break; 8375321936Shselasky default: 8376321936Shselasky goto out; 8377321936Shselasky } 8378321936Shselasky 8379321936Shselasky cdir *= 2; 8380321936Shselasky if (d > 0) 8381321936Shselasky g = cdir + 1; 8382321936Shselasky else if (d < 0) 8383321936Shselasky g = cdir; 8384321936Shselasky else 8385321936Shselasky goto out; 8386321936Shselasky 8387321936Shselasky if (!ssw->ptgrp[g].port_cnt) 8388321936Shselasky goto out; 8389321936Shselasky 8390321936Shselasky *pt_grp = g; 8391321936Shselasky success = true; 8392321936Shselaskyout: 8393321936Shselasky return success; 8394321936Shselasky} 8395321936Shselasky 8396321936Shselaskystatic 8397321936Shselaskyvoid warn_on_routing(const char *msg, 8398321936Shselasky struct t_switch *sw, struct t_switch *dsw) 8399321936Shselasky{ 8400321936Shselasky OSM_LOG(&sw->torus->osm->log, OSM_LOG_ERROR, 8401321936Shselasky "%s from sw 0x%04"PRIx64" (%d,%d,%d) " 8402321936Shselasky "to sw 0x%04"PRIx64" (%d,%d,%d)\n", 8403321936Shselasky msg, cl_ntoh64(sw->n_id), sw->i, sw->j, sw->k, 8404321936Shselasky cl_ntoh64(dsw->n_id), dsw->i, dsw->j, dsw->k); 8405321936Shselasky} 8406321936Shselasky 8407321936Shselaskystatic 8408321936Shselaskybool next_hop_x(struct torus *t, 8409321936Shselasky struct t_switch *ssw, struct t_switch *dsw, unsigned *pt_grp) 8410321936Shselasky{ 8411321936Shselasky if (t->sw[dsw->i][ssw->j][ssw->k]) 8412321936Shselasky /* 8413321936Shselasky * The next turning switch on this path is available, 8414321936Shselasky * so head towards it by the shortest available path. 8415321936Shselasky */ 8416321936Shselasky return next_hop_path(t, 0, ssw, dsw, pt_grp); 8417321936Shselasky else 8418321936Shselasky /* 8419321936Shselasky * The next turning switch on this path is not 8420321936Shselasky * available, so head towards it in the shortest 8421321936Shselasky * path direction. 8422321936Shselasky */ 8423321936Shselasky return next_hop_idx(t, 0, ssw, dsw, pt_grp); 8424321936Shselasky} 8425321936Shselasky 8426321936Shselaskystatic 8427321936Shselaskybool next_hop_y(struct torus *t, 8428321936Shselasky struct t_switch *ssw, struct t_switch *dsw, unsigned *pt_grp) 8429321936Shselasky{ 8430321936Shselasky if (t->sw[ssw->i][dsw->j][ssw->k]) 8431321936Shselasky /* 8432321936Shselasky * The next turning switch on this path is available, 8433321936Shselasky * so head towards it by the shortest available path. 8434321936Shselasky */ 8435321936Shselasky return next_hop_path(t, 1, ssw, dsw, pt_grp); 8436321936Shselasky else 8437321936Shselasky /* 8438321936Shselasky * The next turning switch on this path is not 8439321936Shselasky * available, so head towards it in the shortest 8440321936Shselasky * path direction. 8441321936Shselasky */ 8442321936Shselasky return next_hop_idx(t, 1, ssw, dsw, pt_grp); 8443321936Shselasky} 8444321936Shselasky 8445321936Shselaskystatic 8446321936Shselaskybool next_hop_z(struct torus *t, 8447321936Shselasky struct t_switch *ssw, struct t_switch *dsw, unsigned *pt_grp) 8448321936Shselasky{ 8449321936Shselasky return next_hop_path(t, 2, ssw, dsw, pt_grp); 8450321936Shselasky} 8451321936Shselasky 8452321936Shselasky/* 8453321936Shselasky * Returns the port number on *sw to use to reach *dsw, or -1 if unable to 8454321936Shselasky * route. 8455321936Shselasky */ 8456321936Shselaskystatic 8457321936Shselaskyint lft_port(struct torus *t, 8458321936Shselasky struct t_switch *sw, struct t_switch *dsw, 8459321936Shselasky bool update_port_cnt, bool ca) 8460321936Shselasky{ 8461321936Shselasky unsigned g, p; 8462321936Shselasky struct port_grp *pg; 8463321936Shselasky 8464321936Shselasky /* 8465321936Shselasky * The IBA does not provide a way to preserve path history for 8466321936Shselasky * routing decisions and VL assignment, and the only mechanism to 8467321936Shselasky * provide global fabric knowledge to the routing engine is via 8468321936Shselasky * the four SL bits. This severely constrains the ability to deal 8469321936Shselasky * with missing/dead switches. 8470321936Shselasky * 8471321936Shselasky * Also, if routing a torus with XYZ-DOR, the only way to route 8472321936Shselasky * around a missing/dead switch is to introduce a turn that is 8473321936Shselasky * illegal under XYZ-DOR. 8474321936Shselasky * 8475321936Shselasky * But here's what we can do: 8476321936Shselasky * 8477321936Shselasky * We have a VL bit we use to flag illegal turns, thus putting the 8478321936Shselasky * hop directly after an illegal turn on a separate set of VLs. 8479321936Shselasky * Unfortunately, since there is no path history, the _second_ 8480321936Shselasky * and subsequent hops after an illegal turn use the standard 8481321936Shselasky * XYZ-DOR VL set. This is enough to introduce credit loops in 8482321936Shselasky * many cases. 8483321936Shselasky * 8484321936Shselasky * To minimize the number of cases such illegal turns can introduce 8485321936Shselasky * credit loops, we try to introduce the illegal turn as late in a 8486321936Shselasky * path as possible. 8487321936Shselasky * 8488321936Shselasky * Define a turning switch as a switch where a path turns from one 8489321936Shselasky * coordinate direction onto another. If a turning switch in a path 8490321936Shselasky * is missing, construct the LFT entries so that the path progresses 8491321936Shselasky * as far as possible on the shortest path to the turning switch. 8492321936Shselasky * When progress is not possible, turn onto the next coordinate 8493321936Shselasky * direction. 8494321936Shselasky * 8495321936Shselasky * The next turn after that will be an illegal turn, after which 8496321936Shselasky * point the path will continue to use a standard XYZ-DOR path. 8497321936Shselasky */ 8498321936Shselasky if (dsw->i != sw->i) { 8499321936Shselasky 8500321936Shselasky if (next_hop_x(t, sw, dsw, &g)) 8501321936Shselasky goto done; 8502321936Shselasky /* 8503321936Shselasky * This path has made as much progress in this direction as 8504321936Shselasky * is possible, so turn it now. 8505321936Shselasky */ 8506321936Shselasky if (dsw->j != sw->j && next_hop_y(t, sw, dsw, &g)) 8507321936Shselasky goto done; 8508321936Shselasky 8509321936Shselasky if (dsw->k != sw->k && next_hop_z(t, sw, dsw, &g)) 8510321936Shselasky goto done; 8511321936Shselasky 8512321936Shselasky warn_on_routing("Error: unable to route", sw, dsw); 8513321936Shselasky goto no_route; 8514321936Shselasky } else if (dsw->j != sw->j) { 8515321936Shselasky 8516321936Shselasky if (next_hop_y(t, sw, dsw, &g)) 8517321936Shselasky goto done; 8518321936Shselasky 8519321936Shselasky if (dsw->k != sw->k && next_hop_z(t, sw, dsw, &g)) 8520321936Shselasky goto done; 8521321936Shselasky 8522321936Shselasky warn_on_routing("Error: unable to route", sw, dsw); 8523321936Shselasky goto no_route; 8524321936Shselasky } else { 8525321936Shselasky if (dsw->k == sw->k) 8526321936Shselasky warn_on_routing("Warning: bad routing", sw, dsw); 8527321936Shselasky 8528321936Shselasky if (next_hop_z(t, sw, dsw, &g)) 8529321936Shselasky goto done; 8530321936Shselasky 8531321936Shselasky warn_on_routing("Error: unable to route", sw, dsw); 8532321936Shselasky goto no_route; 8533321936Shselasky } 8534321936Shselaskydone: 8535321936Shselasky pg = &sw->ptgrp[g]; 8536321936Shselasky if (!pg->port_cnt) 8537321936Shselasky goto no_route; 8538321936Shselasky 8539321936Shselasky if (update_port_cnt) { 8540321936Shselasky if (ca) 8541321936Shselasky p = pg->ca_dlid_cnt++ % pg->port_cnt; 8542321936Shselasky else 8543321936Shselasky p = pg->sw_dlid_cnt++ % pg->port_cnt; 8544321936Shselasky } else { 8545321936Shselasky /* 8546321936Shselasky * If we're not updating port counts, then we're just running 8547321936Shselasky * routes for SL path checking, and it doesn't matter which 8548321936Shselasky * of several parallel links we use. Use the first one. 8549321936Shselasky */ 8550321936Shselasky p = 0; 8551321936Shselasky } 8552321936Shselasky p = pg->port[p]->port; 8553321936Shselasky 8554321936Shselasky return p; 8555321936Shselasky 8556321936Shselaskyno_route: 8557321936Shselasky /* 8558321936Shselasky * We can't get there from here. 8559321936Shselasky */ 8560321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 8561321936Shselasky "ERR 4E39: routing on sw 0x%04"PRIx64": sending " 8562321936Shselasky "traffic for dest sw 0x%04"PRIx64" to port %u\n", 8563321936Shselasky cl_ntoh64(sw->n_id), cl_ntoh64(dsw->n_id), OSM_NO_PATH); 8564321936Shselasky return -1; 8565321936Shselasky} 8566321936Shselasky 8567321936Shselaskystatic 8568321936Shselaskybool get_lid(struct port_grp *pg, unsigned p, 8569321936Shselasky uint16_t *dlid_base, uint8_t *dlid_lmc, bool *ca) 8570321936Shselasky{ 8571321936Shselasky struct endpoint *ep; 8572321936Shselasky osm_port_t *osm_port; 8573321936Shselasky 8574321936Shselasky if (p >= pg->port_cnt) { 8575321936Shselasky OSM_LOG(&pg->sw->torus->osm->log, OSM_LOG_ERROR, 8576321936Shselasky "ERR 4E3A: Port group index %u too large: sw " 8577321936Shselasky "0x%04"PRIx64" pt_grp %u pt_grp_cnt %u\n", 8578321936Shselasky p, cl_ntoh64(pg->sw->n_id), 8579321936Shselasky (unsigned)pg->port_grp, (unsigned)pg->port_cnt); 8580321936Shselasky return false; 8581321936Shselasky } 8582321936Shselasky if (pg->port[p]->type == SRCSINK) { 8583321936Shselasky ep = pg->port[p]; 8584321936Shselasky if (ca) 8585321936Shselasky *ca = false; 8586321936Shselasky } else if (pg->port[p]->type == PASSTHRU && 8587321936Shselasky pg->port[p]->link->end[1].type == SRCSINK) { 8588321936Shselasky /* 8589321936Shselasky * If this port is connected via a link to a CA, then we 8590321936Shselasky * know link->end[0] is the switch end and link->end[1] is 8591321936Shselasky * the CA end; see build_ca_link() and link_srcsink(). 8592321936Shselasky */ 8593321936Shselasky ep = &pg->port[p]->link->end[1]; 8594321936Shselasky if (ca) 8595321936Shselasky *ca = true; 8596321936Shselasky } else { 8597321936Shselasky OSM_LOG(&pg->sw->torus->osm->log, OSM_LOG_ERROR, 8598321936Shselasky "ERR 4E3B: Switch 0x%04"PRIx64" port %d improperly connected\n", 8599321936Shselasky cl_ntoh64(pg->sw->n_id), pg->port[p]->port); 8600321936Shselasky return false; 8601321936Shselasky } 8602321936Shselasky osm_port = ep->osm_port; 8603321936Shselasky if (!(osm_port && osm_port->priv == ep)) { 8604321936Shselasky OSM_LOG(&pg->sw->torus->osm->log, OSM_LOG_ERROR, 8605321936Shselasky "ERR 4E3C: ep->osm_port->priv != ep " 8606321936Shselasky "for sw 0x%04"PRIx64" port %d\n", 8607321936Shselasky cl_ntoh64(((struct t_switch *)(ep->sw))->n_id), ep->port); 8608321936Shselasky return false; 8609321936Shselasky } 8610321936Shselasky *dlid_base = cl_ntoh16(osm_physp_get_base_lid(osm_port->p_physp)); 8611321936Shselasky *dlid_lmc = osm_physp_get_lmc(osm_port->p_physp); 8612321936Shselasky 8613321936Shselasky return true; 8614321936Shselasky} 8615321936Shselasky 8616321936Shselaskystatic 8617321936Shselaskybool torus_lft(struct torus *t, struct t_switch *sw) 8618321936Shselasky{ 8619321936Shselasky bool success = true; 8620321936Shselasky int dp; 8621321936Shselasky unsigned p, s; 8622321936Shselasky uint16_t l, dlid_base; 8623321936Shselasky uint8_t dlid_lmc; 8624321936Shselasky bool ca; 8625321936Shselasky struct port_grp *pgrp; 8626321936Shselasky struct t_switch *dsw; 8627321936Shselasky osm_switch_t *osm_sw; 8628321936Shselasky uint8_t order[IB_NODE_NUM_PORTS_MAX+1]; 8629321936Shselasky 8630321936Shselasky if (!(sw->osm_switch && sw->osm_switch->priv == sw)) { 8631321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 8632321936Shselasky "ERR 4E3D: sw->osm_switch->priv != sw " 8633321936Shselasky "for sw 0x%04"PRIx64"\n", cl_ntoh64(sw->n_id)); 8634321936Shselasky return false; 8635321936Shselasky } 8636321936Shselasky osm_sw = sw->osm_switch; 8637321936Shselasky memset(osm_sw->new_lft, OSM_NO_PATH, osm_sw->lft_size); 8638321936Shselasky 8639321936Shselasky for (s = 0; s < t->switch_cnt; s++) { 8640321936Shselasky 8641321936Shselasky dsw = t->sw_pool[s]; 8642321936Shselasky pgrp = &dsw->ptgrp[2 * TORUS_MAX_DIM]; 8643321936Shselasky 8644321936Shselasky memset(order, IB_INVALID_PORT_NUM, sizeof(order)); 8645321936Shselasky for (p = 0; p < pgrp->port_cnt; p++) 8646321936Shselasky order[pgrp->port[p]->port] = p; 8647321936Shselasky 8648321936Shselasky for (p = 0; p < ARRAY_SIZE(order); p++) { 8649321936Shselasky 8650321936Shselasky uint8_t px = order[t->port_order[p]]; 8651321936Shselasky 8652321936Shselasky if (px == IB_INVALID_PORT_NUM) 8653321936Shselasky continue; 8654321936Shselasky 8655321936Shselasky if (!get_lid(pgrp, px, &dlid_base, &dlid_lmc, &ca)) 8656321936Shselasky return false; 8657321936Shselasky 8658321936Shselasky if (sw->n_id == dsw->n_id) 8659321936Shselasky dp = pgrp->port[px]->port; 8660321936Shselasky else 8661321936Shselasky dp = lft_port(t, sw, dsw, true, ca); 8662321936Shselasky /* 8663321936Shselasky * LMC > 0 doesn't really make sense for torus-2QoS. 8664321936Shselasky * So, just make sure traffic gets delivered if 8665321936Shselasky * non-zero LMC is used. 8666321936Shselasky */ 8667321936Shselasky if (dp >= 0) 8668321936Shselasky for (l = 0; l < (1U << dlid_lmc); l++) 8669321936Shselasky osm_sw->new_lft[dlid_base + l] = dp; 8670321936Shselasky else 8671321936Shselasky success = false; 8672321936Shselasky } 8673321936Shselasky } 8674321936Shselasky return success; 8675321936Shselasky} 8676321936Shselasky 8677321936Shselaskystatic 8678321936Shselaskyosm_mtree_node_t *mcast_stree_branch(struct t_switch *sw, osm_switch_t *osm_sw, 8679321936Shselasky osm_mgrp_box_t *mgb, unsigned depth, 8680321936Shselasky unsigned *port_cnt, unsigned *max_depth) 8681321936Shselasky{ 8682321936Shselasky osm_mtree_node_t *mtn = NULL; 8683321936Shselasky osm_mcast_tbl_t *mcast_tbl, *ds_mcast_tbl; 8684321936Shselasky osm_node_t *ds_node; 8685321936Shselasky struct t_switch *ds_sw; 8686321936Shselasky struct port_grp *ptgrp; 8687321936Shselasky struct link *link; 8688321936Shselasky struct endpoint *port; 8689321936Shselasky unsigned g, p; 8690321936Shselasky unsigned mcast_fwd_ports = 0, mcast_end_ports = 0; 8691321936Shselasky 8692321936Shselasky depth++; 8693321936Shselasky 8694321936Shselasky if (osm_sw->priv != sw) { 8695321936Shselasky OSM_LOG(&sw->torus->osm->log, OSM_LOG_ERROR, 8696321936Shselasky "ERR 4E3E: osm_sw (GUID 0x%04"PRIx64") " 8697321936Shselasky "not in torus fabric description\n", 8698321936Shselasky cl_ntoh64(osm_node_get_node_guid(osm_sw->p_node))); 8699321936Shselasky goto out; 8700321936Shselasky } 8701321936Shselasky if (!osm_switch_supports_mcast(osm_sw)) { 8702321936Shselasky OSM_LOG(&sw->torus->osm->log, OSM_LOG_ERROR, 8703321936Shselasky "ERR 4E3F: osm_sw (GUID 0x%04"PRIx64") " 8704321936Shselasky "does not support multicast\n", 8705321936Shselasky cl_ntoh64(osm_node_get_node_guid(osm_sw->p_node))); 8706321936Shselasky goto out; 8707321936Shselasky } 8708321936Shselasky mtn = osm_mtree_node_new(osm_sw); 8709321936Shselasky if (!mtn) { 8710321936Shselasky OSM_LOG(&sw->torus->osm->log, OSM_LOG_ERROR, 8711321936Shselasky "ERR 4E46: Insufficient memory to build multicast tree\n"); 8712321936Shselasky goto out; 8713321936Shselasky } 8714321936Shselasky mcast_tbl = osm_switch_get_mcast_tbl_ptr(osm_sw); 8715321936Shselasky /* 8716321936Shselasky * Recurse to downstream switches, i.e. those closer to master 8717321936Shselasky * spanning tree branch tips. 8718321936Shselasky * 8719321936Shselasky * Note that if there are multiple ports in this port group, i.e., 8720321936Shselasky * multiple parallel links, we can pick any one of them to use for 8721321936Shselasky * any individual MLID without causing loops. Pick one based on MLID 8722321936Shselasky * for now, until someone turns up evidence we need to be smarter. 8723321936Shselasky * 8724321936Shselasky * Also, it might be we got called in a window between a switch getting 8725321936Shselasky * removed from the fabric, and torus-2QoS getting to rebuild its 8726321936Shselasky * fabric representation. If that were to happen, our next hop 8727321936Shselasky * osm_switch pointer might be stale. Look it up via opensm's fabric 8728321936Shselasky * description to be sure it's not. 8729321936Shselasky */ 8730321936Shselasky for (g = 0; g < 2 * TORUS_MAX_DIM; g++) { 8731321936Shselasky ptgrp = &sw->ptgrp[g]; 8732321936Shselasky if (!ptgrp->to_stree_tip) 8733321936Shselasky continue; 8734321936Shselasky 8735321936Shselasky p = mgb->mlid % ptgrp->port_cnt;/* port # in port group */ 8736321936Shselasky p = ptgrp->port[p]->port; /* now port # in switch */ 8737321936Shselasky 8738321936Shselasky ds_node = osm_node_get_remote_node(osm_sw->p_node, p, NULL); 8739321936Shselasky ds_sw = ptgrp->to_stree_tip->sw; 8740321936Shselasky 8741321936Shselasky if (!(ds_node && ds_node->sw && 8742321936Shselasky ds_sw->osm_switch == ds_node->sw)) { 8743321936Shselasky OSM_LOG(&sw->torus->osm->log, OSM_LOG_ERROR, 8744321936Shselasky "ERR 4E40: stale pointer to osm_sw " 8745321936Shselasky "(GUID 0x%04"PRIx64")\n", cl_ntoh64(ds_sw->n_id)); 8746321936Shselasky continue; 8747321936Shselasky } 8748321936Shselasky mtn->child_array[p] = 8749321936Shselasky mcast_stree_branch(ds_sw, ds_node->sw, mgb, 8750321936Shselasky depth, port_cnt, max_depth); 8751321936Shselasky if (!mtn->child_array[p]) 8752321936Shselasky continue; 8753321936Shselasky 8754321936Shselasky osm_mcast_tbl_set(mcast_tbl, mgb->mlid, p); 8755321936Shselasky mcast_fwd_ports++; 8756321936Shselasky /* 8757321936Shselasky * Since we forward traffic for this multicast group on this 8758321936Shselasky * port, cause the switch on the other end of the link 8759321936Shselasky * to forward traffic back to us. Do it now since have at 8760321936Shselasky * hand the link used; otherwise it'll be hard to figure out 8761321936Shselasky * later, and if we get it wrong we get a MC routing loop. 8762321936Shselasky */ 8763321936Shselasky link = sw->port[p]->link; 8764321936Shselasky ds_mcast_tbl = osm_switch_get_mcast_tbl_ptr(ds_node->sw); 8765321936Shselasky 8766321936Shselasky if (&link->end[0] == sw->port[p]) 8767321936Shselasky osm_mcast_tbl_set(ds_mcast_tbl, mgb->mlid, 8768321936Shselasky link->end[1].port); 8769321936Shselasky else 8770321936Shselasky osm_mcast_tbl_set(ds_mcast_tbl, mgb->mlid, 8771321936Shselasky link->end[0].port); 8772321936Shselasky } 8773321936Shselasky /* 8774321936Shselasky * Add any host ports marked as in mcast group into spanning tree. 8775321936Shselasky */ 8776321936Shselasky ptgrp = &sw->ptgrp[2 * TORUS_MAX_DIM]; 8777321936Shselasky for (p = 0; p < ptgrp->port_cnt; p++) { 8778321936Shselasky port = ptgrp->port[p]; 8779321936Shselasky if (port->tmp) { 8780321936Shselasky port->tmp = NULL; 8781321936Shselasky mtn->child_array[port->port] = OSM_MTREE_LEAF; 8782321936Shselasky osm_mcast_tbl_set(mcast_tbl, mgb->mlid, port->port); 8783321936Shselasky mcast_end_ports++; 8784321936Shselasky } 8785321936Shselasky } 8786321936Shselasky if (!(mcast_end_ports || mcast_fwd_ports)) { 8787321936Shselasky osm_mtree_destroy(mtn); 8788321936Shselasky mtn = NULL; 8789321936Shselasky } else if (depth > *max_depth) 8790321936Shselasky *max_depth = depth; 8791321936Shselasky 8792321936Shselasky *port_cnt += mcast_end_ports; 8793321936Shselaskyout: 8794321936Shselasky return mtn; 8795321936Shselasky} 8796321936Shselasky 8797321936Shselaskystatic 8798321936Shselaskyosm_port_t *next_mgrp_box_port(osm_mgrp_box_t *mgb, 8799321936Shselasky cl_list_item_t **list_iterator, 8800321936Shselasky cl_map_item_t **map_iterator) 8801321936Shselasky{ 8802321936Shselasky osm_mgrp_t *mgrp; 8803321936Shselasky osm_mcm_port_t *mcm_port; 8804321936Shselasky osm_port_t *osm_port = NULL; 8805321936Shselasky cl_map_item_t *m_item = *map_iterator; 8806321936Shselasky cl_list_item_t *l_item = *list_iterator; 8807321936Shselasky 8808321936Shselaskynext_mgrp: 8809321936Shselasky if (!l_item) 8810321936Shselasky l_item = cl_qlist_head(&mgb->mgrp_list); 8811321936Shselasky if (l_item == cl_qlist_end(&mgb->mgrp_list)) { 8812321936Shselasky l_item = NULL; 8813321936Shselasky goto out; 8814321936Shselasky } 8815321936Shselasky mgrp = cl_item_obj(l_item, mgrp, list_item); 8816321936Shselasky 8817321936Shselasky if (!m_item) 8818321936Shselasky m_item = cl_qmap_head(&mgrp->mcm_port_tbl); 8819321936Shselasky if (m_item == cl_qmap_end(&mgrp->mcm_port_tbl)) { 8820321936Shselasky m_item = NULL; 8821321936Shselasky l_item = cl_qlist_next(l_item); 8822321936Shselasky goto next_mgrp; 8823321936Shselasky } 8824321936Shselasky mcm_port = cl_item_obj(m_item, mcm_port, map_item); 8825321936Shselasky m_item = cl_qmap_next(m_item); 8826321936Shselasky osm_port = mcm_port->port; 8827321936Shselaskyout: 8828321936Shselasky *list_iterator = l_item; 8829321936Shselasky *map_iterator = m_item; 8830321936Shselasky return osm_port; 8831321936Shselasky} 8832321936Shselasky 8833321936Shselaskystatic 8834321936Shselaskyib_api_status_t torus_mcast_stree(void *context, osm_mgrp_box_t *mgb) 8835321936Shselasky{ 8836321936Shselasky struct torus_context *ctx = context; 8837321936Shselasky struct torus *t = ctx->torus; 8838321936Shselasky cl_map_item_t *m_item = NULL; 8839321936Shselasky cl_list_item_t *l_item = NULL; 8840321936Shselasky osm_port_t *osm_port; 8841321936Shselasky osm_switch_t *osm_sw; 8842321936Shselasky struct endpoint *port; 8843321936Shselasky unsigned port_cnt = 0, max_depth = 0; 8844321936Shselasky 8845321936Shselasky osm_purge_mtree(&ctx->osm->sm, mgb); 8846321936Shselasky 8847321936Shselasky /* 8848321936Shselasky * Build a spanning tree for a multicast group by first marking 8849321936Shselasky * the torus endpoints that are participating in the group. 8850321936Shselasky * Then do a depth-first search of the torus master spanning 8851321936Shselasky * tree to build up the spanning tree specific to this group. 8852321936Shselasky * 8853321936Shselasky * Since the torus master spanning tree is constructed specifically 8854321936Shselasky * to guarantee that multicast will not deadlock against unicast 8855321936Shselasky * when they share VLs, we can be sure that any multicast group 8856321936Shselasky * spanning tree constructed this way has the same property. 8857321936Shselasky */ 8858321936Shselasky while ((osm_port = next_mgrp_box_port(mgb, &l_item, &m_item))) { 8859321936Shselasky port = osm_port->priv; 8860321936Shselasky if (!(port && port->osm_port == osm_port)) { 8861321936Shselasky port = osm_port_relink_endpoint(osm_port); 8862321936Shselasky if (!port) { 8863321936Shselasky guid_t id; 8864321936Shselasky id = osm_node_get_node_guid(osm_port->p_node); 8865321936Shselasky OSM_LOG(&ctx->osm->log, OSM_LOG_ERROR, 8866321936Shselasky "ERR 4E41: osm_port (GUID 0x%04"PRIx64") " 8867321936Shselasky "not in torus fabric description\n", 8868321936Shselasky cl_ntoh64(id)); 8869321936Shselasky continue; 8870321936Shselasky } 8871321936Shselasky } 8872321936Shselasky /* 8873321936Shselasky * If this is a CA port, mark the switch port at the 8874321936Shselasky * other end of this port's link. 8875321936Shselasky * 8876321936Shselasky * By definition, a CA port is connected to end[1] of a link, 8877321936Shselasky * and the switch port is end[0]. See build_ca_link() and 8878321936Shselasky * link_srcsink(). 8879321936Shselasky */ 8880321936Shselasky if (port->link) 8881321936Shselasky port = &port->link->end[0]; 8882321936Shselasky port->tmp = osm_port; 8883321936Shselasky } 8884321936Shselasky /* 8885321936Shselasky * It might be we got called in a window between a switch getting 8886321936Shselasky * removed from the fabric, and torus-2QoS getting to rebuild its 8887321936Shselasky * fabric representation. If that were to happen, our 8888321936Shselasky * master_stree_root->osm_switch pointer might be stale. Look up 8889321936Shselasky * the osm_switch by GUID to be sure it's not. 8890321936Shselasky * 8891321936Shselasky * Also, call into mcast_stree_branch with depth = -1, because 8892321936Shselasky * depth at root switch needs to be 0. 8893321936Shselasky */ 8894321936Shselasky osm_sw = (osm_switch_t *)cl_qmap_get(&ctx->osm->subn.sw_guid_tbl, 8895321936Shselasky t->master_stree_root->n_id); 8896321936Shselasky if (!(osm_sw && t->master_stree_root->osm_switch == osm_sw)) { 8897321936Shselasky OSM_LOG(&ctx->osm->log, OSM_LOG_ERROR, 8898321936Shselasky "ERR 4E42: stale pointer to osm_sw (GUID 0x%04"PRIx64")\n", 8899321936Shselasky cl_ntoh64(t->master_stree_root->n_id)); 8900321936Shselasky return IB_ERROR; 8901321936Shselasky } 8902321936Shselasky mgb->root = mcast_stree_branch(t->master_stree_root, osm_sw, 8903321936Shselasky mgb, -1, &port_cnt, &max_depth); 8904321936Shselasky 8905321936Shselasky OSM_LOG(&ctx->osm->log, OSM_LOG_VERBOSE, 8906321936Shselasky "Configured MLID 0x%X for %u ports, max tree depth = %u\n", 8907321936Shselasky mgb->mlid, port_cnt, max_depth); 8908321936Shselasky 8909321936Shselasky return IB_SUCCESS; 8910321936Shselasky} 8911321936Shselasky 8912321936Shselaskystatic 8913321936Shselaskybool good_xy_ring(struct torus *t, const int x, const int y, const int z) 8914321936Shselasky{ 8915321936Shselasky struct t_switch ****sw = t->sw; 8916321936Shselasky bool good_ring = true; 8917321936Shselasky int x_tst, y_tst; 8918321936Shselasky 8919321936Shselasky for (x_tst = 0; x_tst < t->x_sz && good_ring; x_tst++) 8920321936Shselasky good_ring = sw[x_tst][y][z]; 8921321936Shselasky 8922321936Shselasky for (y_tst = 0; y_tst < t->y_sz && good_ring; y_tst++) 8923321936Shselasky good_ring = sw[x][y_tst][z]; 8924321936Shselasky 8925321936Shselasky return good_ring; 8926321936Shselasky} 8927321936Shselasky 8928321936Shselaskystatic 8929321936Shselaskystruct t_switch *find_plane_mid(struct torus *t, const int z) 8930321936Shselasky{ 8931321936Shselasky int x, dx, xm = t->x_sz / 2; 8932321936Shselasky int y, dy, ym = t->y_sz / 2; 8933321936Shselasky struct t_switch ****sw = t->sw; 8934321936Shselasky 8935321936Shselasky if (good_xy_ring(t, xm, ym, z)) 8936321936Shselasky return sw[xm][ym][z]; 8937321936Shselasky 8938321936Shselasky for (dx = 1, dy = 1; dx <= xm && dy <= ym; dx++, dy++) { 8939321936Shselasky 8940321936Shselasky x = canonicalize(xm - dx, t->x_sz); 8941321936Shselasky y = canonicalize(ym - dy, t->y_sz); 8942321936Shselasky if (good_xy_ring(t, x, y, z)) 8943321936Shselasky return sw[x][y][z]; 8944321936Shselasky 8945321936Shselasky x = canonicalize(xm + dx, t->x_sz); 8946321936Shselasky y = canonicalize(ym + dy, t->y_sz); 8947321936Shselasky if (good_xy_ring(t, x, y, z)) 8948321936Shselasky return sw[x][y][z]; 8949321936Shselasky } 8950321936Shselasky return NULL; 8951321936Shselasky} 8952321936Shselasky 8953321936Shselaskystatic 8954321936Shselaskystruct t_switch *find_stree_root(struct torus *t) 8955321936Shselasky{ 8956321936Shselasky int x, y, z, dz, zm = t->z_sz / 2; 8957321936Shselasky struct t_switch ****sw = t->sw; 8958321936Shselasky struct t_switch *root; 8959321936Shselasky bool good_plane; 8960321936Shselasky 8961321936Shselasky /* 8962321936Shselasky * Look for a switch near the "center" (wrt. the datelines) of the 8963321936Shselasky * torus, as that will be the most optimum spanning tree root. Use 8964321936Shselasky * a search that is not exhaustive, on the theory that this routing 8965321936Shselasky * engine isn't useful anyway if too many switches are missing. 8966321936Shselasky * 8967321936Shselasky * Also, want to pick an x-y plane with no missing switches, so that 8968321936Shselasky * the master spanning tree construction algorithm doesn't have to 8969321936Shselasky * deal with needing a turn on a missing switch. 8970321936Shselasky */ 8971321936Shselasky for (dz = 0; dz <= zm; dz++) { 8972321936Shselasky 8973321936Shselasky z = canonicalize(zm - dz, t->z_sz); 8974321936Shselasky good_plane = true; 8975321936Shselasky for (y = 0; y < t->y_sz && good_plane; y++) 8976321936Shselasky for (x = 0; x < t->x_sz && good_plane; x++) 8977321936Shselasky good_plane = sw[x][y][z]; 8978321936Shselasky 8979321936Shselasky if (good_plane) { 8980321936Shselasky root = find_plane_mid(t, z); 8981321936Shselasky if (root) 8982321936Shselasky goto out; 8983321936Shselasky } 8984321936Shselasky if (!dz) 8985321936Shselasky continue; 8986321936Shselasky 8987321936Shselasky z = canonicalize(zm + dz, t->z_sz); 8988321936Shselasky good_plane = true; 8989321936Shselasky for (y = 0; y < t->y_sz && good_plane; y++) 8990321936Shselasky for (x = 0; x < t->x_sz && good_plane; x++) 8991321936Shselasky good_plane = sw[x][y][z]; 8992321936Shselasky 8993321936Shselasky if (good_plane) { 8994321936Shselasky root = find_plane_mid(t, z); 8995321936Shselasky if (root) 8996321936Shselasky goto out; 8997321936Shselasky } 8998321936Shselasky } 8999321936Shselasky /* 9000321936Shselasky * Note that torus-2QoS can route a torus that is missing an entire 9001321936Shselasky * column (switches with x,y constant, for all z values) without 9002321936Shselasky * deadlocks. 9003321936Shselasky * 9004321936Shselasky * if we've reached this point, we must have a column of missing 9005321936Shselasky * switches, as routable_torus() would have returned false for 9006321936Shselasky * any other configuration of missing switches that made it through 9007321936Shselasky * the above. 9008321936Shselasky * 9009321936Shselasky * So any switch in the mid-z plane will do as the root. 9010321936Shselasky */ 9011321936Shselasky root = find_plane_mid(t, zm); 9012321936Shselaskyout: 9013321936Shselasky return root; 9014321936Shselasky} 9015321936Shselasky 9016321936Shselaskystatic 9017321936Shselaskybool sw_in_master_stree(struct t_switch *sw) 9018321936Shselasky{ 9019321936Shselasky int g; 9020321936Shselasky bool connected; 9021321936Shselasky 9022321936Shselasky connected = sw == sw->torus->master_stree_root; 9023321936Shselasky for (g = 0; g < 2 * TORUS_MAX_DIM; g++) 9024321936Shselasky connected = connected || sw->ptgrp[g].to_stree_root; 9025321936Shselasky 9026321936Shselasky return connected; 9027321936Shselasky} 9028321936Shselasky 9029321936Shselaskystatic 9030321936Shselaskyvoid grow_master_stree_branch(struct t_switch *root, struct t_switch *tip, 9031321936Shselasky unsigned to_root_pg, unsigned to_tip_pg) 9032321936Shselasky{ 9033321936Shselasky root->ptgrp[to_tip_pg].to_stree_tip = &tip->ptgrp[to_root_pg]; 9034321936Shselasky tip->ptgrp[to_root_pg].to_stree_root = &root->ptgrp[to_tip_pg]; 9035321936Shselasky} 9036321936Shselasky 9037321936Shselaskystatic 9038321936Shselaskyvoid build_master_stree_branch(struct t_switch *branch_root, int cdir) 9039321936Shselasky{ 9040321936Shselasky struct t_switch *sw, *n_sw, *p_sw; 9041321936Shselasky unsigned l, idx, cnt, pg, ng; 9042321936Shselasky 9043321936Shselasky switch (cdir) { 9044321936Shselasky case 0: 9045321936Shselasky idx = branch_root->i; 9046321936Shselasky cnt = branch_root->torus->x_sz; 9047321936Shselasky break; 9048321936Shselasky case 1: 9049321936Shselasky idx = branch_root->j; 9050321936Shselasky cnt = branch_root->torus->y_sz; 9051321936Shselasky break; 9052321936Shselasky case 2: 9053321936Shselasky idx = branch_root->k; 9054321936Shselasky cnt = branch_root->torus->z_sz; 9055321936Shselasky break; 9056321936Shselasky default: 9057321936Shselasky goto out; 9058321936Shselasky } 9059321936Shselasky /* 9060321936Shselasky * This algorithm intends that a spanning tree branch never crosses 9061321936Shselasky * a dateline unless the 1-D ring for which we're building the branch 9062321936Shselasky * is interrupted by failure. We need that guarantee to prevent 9063321936Shselasky * multicast/unicast credit loops. 9064321936Shselasky */ 9065321936Shselasky n_sw = branch_root; /* tip of negative cdir branch */ 9066321936Shselasky ng = 2 * cdir; /* negative cdir port group index */ 9067321936Shselasky p_sw = branch_root; /* tip of positive cdir branch */ 9068321936Shselasky pg = 2 * cdir + 1; /* positive cdir port group index */ 9069321936Shselasky 9070321936Shselasky for (l = idx; n_sw && l >= 1; l--) { 9071321936Shselasky sw = ring_next_sw(n_sw, cdir, -1); 9072321936Shselasky if (sw && !sw_in_master_stree(sw)) { 9073321936Shselasky grow_master_stree_branch(n_sw, sw, pg, ng); 9074321936Shselasky n_sw = sw; 9075321936Shselasky } else 9076321936Shselasky n_sw = NULL; 9077321936Shselasky } 9078321936Shselasky for (l = idx; p_sw && l < (cnt - 1); l++) { 9079321936Shselasky sw = ring_next_sw(p_sw, cdir, 1); 9080321936Shselasky if (sw && !sw_in_master_stree(sw)) { 9081321936Shselasky grow_master_stree_branch(p_sw, sw, ng, pg); 9082321936Shselasky p_sw = sw; 9083321936Shselasky } else 9084321936Shselasky p_sw = NULL; 9085321936Shselasky } 9086321936Shselasky if (n_sw && p_sw) 9087321936Shselasky goto out; 9088321936Shselasky /* 9089321936Shselasky * At least one branch couldn't grow to the dateline for this ring. 9090321936Shselasky * That means it is acceptable to grow the branch by crossing the 9091321936Shselasky * dateline. 9092321936Shselasky */ 9093321936Shselasky for (l = 0; l < cnt; l++) { 9094321936Shselasky if (n_sw) { 9095321936Shselasky sw = ring_next_sw(n_sw, cdir, -1); 9096321936Shselasky if (sw && !sw_in_master_stree(sw)) { 9097321936Shselasky grow_master_stree_branch(n_sw, sw, pg, ng); 9098321936Shselasky n_sw = sw; 9099321936Shselasky } else 9100321936Shselasky n_sw = NULL; 9101321936Shselasky } 9102321936Shselasky if (p_sw) { 9103321936Shselasky sw = ring_next_sw(p_sw, cdir, 1); 9104321936Shselasky if (sw && !sw_in_master_stree(sw)) { 9105321936Shselasky grow_master_stree_branch(p_sw, sw, ng, pg); 9106321936Shselasky p_sw = sw; 9107321936Shselasky } else 9108321936Shselasky p_sw = NULL; 9109321936Shselasky } 9110321936Shselasky if (!(n_sw || p_sw)) 9111321936Shselasky break; 9112321936Shselasky } 9113321936Shselaskyout: 9114321936Shselasky return; 9115321936Shselasky} 9116321936Shselasky 9117321936Shselaskystatic 9118321936Shselaskybool torus_master_stree(struct torus *t) 9119321936Shselasky{ 9120321936Shselasky int i, j, k; 9121321936Shselasky bool success = false; 9122321936Shselasky struct t_switch *stree_root = find_stree_root(t); 9123321936Shselasky 9124321936Shselasky if (stree_root) 9125321936Shselasky build_master_stree_branch(stree_root, 0); 9126321936Shselasky else 9127321936Shselasky goto out; 9128321936Shselasky 9129321936Shselasky k = stree_root->k; 9130321936Shselasky for (i = 0; i < t->x_sz; i++) { 9131321936Shselasky j = stree_root->j; 9132321936Shselasky if (t->sw[i][j][k]) 9133321936Shselasky build_master_stree_branch(t->sw[i][j][k], 1); 9134321936Shselasky 9135321936Shselasky for (j = 0; j < t->y_sz; j++) 9136321936Shselasky if (t->sw[i][j][k]) 9137321936Shselasky build_master_stree_branch(t->sw[i][j][k], 2); 9138321936Shselasky } 9139321936Shselasky t->master_stree_root = stree_root; 9140321936Shselasky /* 9141321936Shselasky * At this point we should have a master spanning tree that contains 9142321936Shselasky * every present switch, for all fabrics that torus-2QoS can route 9143321936Shselasky * without deadlocks. Make sure this is the case; otherwise warn 9144321936Shselasky * and return failure so we get bug reports. 9145321936Shselasky */ 9146321936Shselasky success = true; 9147321936Shselasky for (i = 0; i < t->x_sz; i++) 9148321936Shselasky for (j = 0; j < t->y_sz; j++) 9149321936Shselasky for (k = 0; k < t->z_sz; k++) { 9150321936Shselasky struct t_switch *sw = t->sw[i][j][k]; 9151321936Shselasky if (!sw || sw_in_master_stree(sw)) 9152321936Shselasky continue; 9153321936Shselasky 9154321936Shselasky success = false; 9155321936Shselasky OSM_LOG(&t->osm->log, OSM_LOG_ERROR, 9156321936Shselasky "ERR 4E43: sw 0x%04"PRIx64" (%d,%d,%d) not in " 9157321936Shselasky "torus multicast master spanning tree\n", 9158321936Shselasky cl_ntoh64(sw->n_id), i, j, k); 9159321936Shselasky } 9160321936Shselaskyout: 9161321936Shselasky return success; 9162321936Shselasky} 9163321936Shselasky 9164321936Shselaskyint route_torus(struct torus *t) 9165321936Shselasky{ 9166321936Shselasky int s; 9167321936Shselasky bool success = true; 9168321936Shselasky 9169321936Shselasky for (s = 0; s < (int)t->switch_cnt; s++) 9170321936Shselasky success = torus_lft(t, t->sw_pool[s]) && success; 9171321936Shselasky 9172321936Shselasky success = success && torus_master_stree(t); 9173321936Shselasky 9174321936Shselasky return success ? 0 : -1; 9175321936Shselasky} 9176321936Shselasky 9177321936Shselaskyuint8_t torus_path_sl(void *context, uint8_t path_sl_hint, 9178321936Shselasky const ib_net16_t slid, const ib_net16_t dlid) 9179321936Shselasky{ 9180321936Shselasky struct torus_context *ctx = context; 9181321936Shselasky osm_opensm_t *p_osm = ctx->osm; 9182321936Shselasky osm_log_t *log = &p_osm->log; 9183321936Shselasky osm_port_t *osm_sport, *osm_dport; 9184321936Shselasky struct endpoint *sport, *dport; 9185321936Shselasky struct t_switch *ssw, *dsw; 9186321936Shselasky struct torus *t; 9187321936Shselasky guid_t guid; 9188321936Shselasky unsigned sl = 0; 9189321936Shselasky 9190321936Shselasky osm_sport = osm_get_port_by_lid(&p_osm->subn, slid); 9191321936Shselasky if (!osm_sport) 9192321936Shselasky goto out; 9193321936Shselasky 9194321936Shselasky osm_dport = osm_get_port_by_lid(&p_osm->subn, dlid); 9195321936Shselasky if (!osm_dport) 9196321936Shselasky goto out; 9197321936Shselasky 9198321936Shselasky sport = osm_sport->priv; 9199321936Shselasky if (!(sport && sport->osm_port == osm_sport)) { 9200321936Shselasky sport = osm_port_relink_endpoint(osm_sport); 9201321936Shselasky if (!sport) { 9202321936Shselasky guid = osm_node_get_node_guid(osm_sport->p_node); 9203321936Shselasky OSM_LOG(log, OSM_LOG_INFO, 9204321936Shselasky "Note: osm_sport (GUID 0x%04"PRIx64") " 9205321936Shselasky "not in torus fabric description\n", 9206321936Shselasky cl_ntoh64(guid)); 9207321936Shselasky goto out; 9208321936Shselasky } 9209321936Shselasky } 9210321936Shselasky dport = osm_dport->priv; 9211321936Shselasky if (!(dport && dport->osm_port == osm_dport)) { 9212321936Shselasky dport = osm_port_relink_endpoint(osm_dport); 9213321936Shselasky if (!dport) { 9214321936Shselasky guid = osm_node_get_node_guid(osm_dport->p_node); 9215321936Shselasky OSM_LOG(log, OSM_LOG_INFO, 9216321936Shselasky "Note: osm_dport (GUID 0x%04"PRIx64") " 9217321936Shselasky "not in torus fabric description\n", 9218321936Shselasky cl_ntoh64(guid)); 9219321936Shselasky goto out; 9220321936Shselasky } 9221321936Shselasky } 9222321936Shselasky /* 9223321936Shselasky * We're only supposed to be called for CA ports, and maybe 9224321936Shselasky * switch management ports. 9225321936Shselasky */ 9226321936Shselasky if (sport->type != SRCSINK) { 9227321936Shselasky guid = osm_node_get_node_guid(osm_sport->p_node); 9228321936Shselasky OSM_LOG(log, OSM_LOG_INFO, 9229321936Shselasky "Error: osm_sport (GUID 0x%04"PRIx64") " 9230321936Shselasky "not a data src/sink port\n", cl_ntoh64(guid)); 9231321936Shselasky goto out; 9232321936Shselasky } 9233321936Shselasky if (dport->type != SRCSINK) { 9234321936Shselasky guid = osm_node_get_node_guid(osm_dport->p_node); 9235321936Shselasky OSM_LOG(log, OSM_LOG_INFO, 9236321936Shselasky "Error: osm_dport (GUID 0x%04"PRIx64") " 9237321936Shselasky "not a data src/sink port\n", cl_ntoh64(guid)); 9238321936Shselasky goto out; 9239321936Shselasky } 9240321936Shselasky /* 9241321936Shselasky * By definition, a CA port is connected to end[1] of a link, and 9242321936Shselasky * the switch port is end[0]. See build_ca_link() and link_srcsink(). 9243321936Shselasky */ 9244321936Shselasky if (sport->link) { 9245321936Shselasky ssw = sport->link->end[0].sw; 9246321936Shselasky } else { 9247321936Shselasky ssw = sport->sw; 9248321936Shselasky } 9249321936Shselasky if (dport->link) 9250321936Shselasky dsw = dport->link->end[0].sw; 9251321936Shselasky else 9252321936Shselasky dsw = dport->sw; 9253321936Shselasky 9254321936Shselasky t = ssw->torus; 9255321936Shselasky 9256321936Shselasky sl = sl_set_use_loop_vl(use_vl1(ssw->i, dsw->i, t->x_sz), 0); 9257321936Shselasky sl |= sl_set_use_loop_vl(use_vl1(ssw->j, dsw->j, t->y_sz), 1); 9258321936Shselasky sl |= sl_set_use_loop_vl(use_vl1(ssw->k, dsw->k, t->z_sz), 2); 9259321936Shselasky sl |= sl_set_qos(sl_get_qos(path_sl_hint)); 9260321936Shselaskyout: 9261321936Shselasky return sl; 9262321936Shselasky} 9263321936Shselasky 9264321936Shselaskystatic 9265321936Shselaskyvoid sum_vlarb_weights(const char *vlarb_str, 9266321936Shselasky unsigned total_weight[IB_MAX_NUM_VLS]) 9267321936Shselasky{ 9268321936Shselasky unsigned i = 0, v, vl = 0; 9269321936Shselasky char *end; 9270321936Shselasky 9271321936Shselasky while (*vlarb_str && i++ < 2 * IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK) { 9272321936Shselasky v = strtoul(vlarb_str, &end, 0); 9273321936Shselasky if (*end) 9274321936Shselasky end++; 9275321936Shselasky vlarb_str = end; 9276321936Shselasky if (i & 0x1) 9277321936Shselasky vl = v & 0xf; 9278321936Shselasky else 9279321936Shselasky total_weight[vl] += v & 0xff; 9280321936Shselasky } 9281321936Shselasky} 9282321936Shselasky 9283321936Shselaskystatic 9284321936Shselaskyint uniform_vlarb_weight_value(unsigned *weight, unsigned count) 9285321936Shselasky{ 9286321936Shselasky int i, v = weight[0]; 9287321936Shselasky 9288321936Shselasky for (i = 1; i < count; i++) { 9289321936Shselasky if (v != weight[i]) 9290321936Shselasky return -1; 9291321936Shselasky } 9292321936Shselasky return v; 9293321936Shselasky} 9294321936Shselasky 9295321936Shselaskystatic 9296321936Shselaskyvoid check_vlarb_config(const char *vlarb_str, bool is_default, 9297321936Shselasky const char *str, const char *pri, osm_log_t *log) 9298321936Shselasky{ 9299321936Shselasky unsigned total_weight[IB_MAX_NUM_VLS] = {0,}; 9300321936Shselasky 9301321936Shselasky sum_vlarb_weights(vlarb_str, total_weight); 9302321936Shselasky if (!(uniform_vlarb_weight_value(&total_weight[0], 4) >= 0 && 9303321936Shselasky uniform_vlarb_weight_value(&total_weight[4], 4) >= 0)) 9304321936Shselasky OSM_LOG(log, OSM_LOG_INFO, 9305321936Shselasky "Warning: torus-2QoS requires same VLarb weights for " 9306321936Shselasky "VLs 0-3; also for VLs 4-7: not true for %s " 9307321936Shselasky "%s_vlarb_%s\n", 9308321936Shselasky (is_default ? "default" : "configured"), str, pri); 9309321936Shselasky} 9310321936Shselasky 9311321936Shselasky/* 9312321936Shselasky * Use this to check the qos_config for switch external ports. 9313321936Shselasky */ 9314321936Shselaskystatic 9315321936Shselaskyvoid check_qos_swe_config(osm_qos_options_t *opt, 9316321936Shselasky osm_qos_options_t *def, osm_log_t *log) 9317321936Shselasky{ 9318321936Shselasky const char *vlarb_str, *tstr; 9319321936Shselasky bool is_default; 9320321936Shselasky unsigned max_vls; 9321321936Shselasky 9322321936Shselasky max_vls = def->max_vls; 9323321936Shselasky if (opt->max_vls > 0) 9324321936Shselasky max_vls = opt->max_vls; 9325321936Shselasky 9326321936Shselasky if (max_vls > 0 && max_vls < 8) 9327321936Shselasky OSM_LOG(log, OSM_LOG_INFO, 9328321936Shselasky "Warning: full torus-2QoS functionality not available " 9329321936Shselasky "for configured %s_max_vls = %d\n", 9330321936Shselasky (opt->max_vls > 0 ? "qos_swe" : "qos"), opt->max_vls); 9331321936Shselasky 9332321936Shselasky vlarb_str = opt->vlarb_high; 9333321936Shselasky is_default = false; 9334321936Shselasky tstr = "qos_swe"; 9335321936Shselasky if (!vlarb_str) { 9336321936Shselasky vlarb_str = def->vlarb_high; 9337321936Shselasky tstr = "qos"; 9338321936Shselasky } 9339321936Shselasky if (!vlarb_str) { 9340321936Shselasky vlarb_str = OSM_DEFAULT_QOS_VLARB_HIGH; 9341321936Shselasky is_default = true; 9342321936Shselasky } 9343321936Shselasky check_vlarb_config(vlarb_str, is_default, tstr, "high", log); 9344321936Shselasky 9345321936Shselasky vlarb_str = opt->vlarb_low; 9346321936Shselasky is_default = false; 9347321936Shselasky tstr = "qos_swe"; 9348321936Shselasky if (!vlarb_str) { 9349321936Shselasky vlarb_str = def->vlarb_low; 9350321936Shselasky tstr = "qos"; 9351321936Shselasky } 9352321936Shselasky if (!vlarb_str) { 9353321936Shselasky vlarb_str = OSM_DEFAULT_QOS_VLARB_LOW; 9354321936Shselasky is_default = true; 9355321936Shselasky } 9356321936Shselasky check_vlarb_config(vlarb_str, is_default, tstr, "low", log); 9357321936Shselasky 9358321936Shselasky if (opt->sl2vl) 9359321936Shselasky OSM_LOG(log, OSM_LOG_INFO, 9360321936Shselasky "Warning: torus-2QoS must override configured " 9361321936Shselasky "qos_swe_sl2vl to generate deadlock-free routes\n"); 9362321936Shselasky} 9363321936Shselasky 9364321936Shselaskystatic 9365321936Shselaskyvoid check_ep_vlarb_config(const char *vlarb_str, 9366321936Shselasky bool is_default, bool is_specific, 9367321936Shselasky const char *str, const char *pri, osm_log_t *log) 9368321936Shselasky{ 9369321936Shselasky unsigned i, total_weight[IB_MAX_NUM_VLS] = {0,}; 9370321936Shselasky int val = 0; 9371321936Shselasky 9372321936Shselasky sum_vlarb_weights(vlarb_str, total_weight); 9373321936Shselasky for (i = 2; i < 8; i++) { 9374321936Shselasky val += total_weight[i]; 9375321936Shselasky } 9376321936Shselasky if (!val) 9377321936Shselasky return; 9378321936Shselasky 9379321936Shselasky if (is_specific) 9380321936Shselasky OSM_LOG(log, OSM_LOG_INFO, 9381321936Shselasky "Warning: torus-2QoS recommends 0 VLarb weights" 9382321936Shselasky " for VLs 2-7 on endpoint links; not true for " 9383321936Shselasky " configured %s_vlarb_%s\n", str, pri); 9384321936Shselasky else 9385321936Shselasky OSM_LOG(log, OSM_LOG_INFO, 9386321936Shselasky "Warning: torus-2QoS recommends 0 VLarb weights " 9387321936Shselasky "for VLs 2-7 on endpoint links; not true for %s " 9388321936Shselasky "qos_vlarb_%s values used for %s_vlarb_%s\n", 9389321936Shselasky (is_default ? "default" : "configured"), pri, str, pri); 9390321936Shselasky} 9391321936Shselasky 9392321936Shselasky/* 9393321936Shselasky * Use this to check the qos_config for endports 9394321936Shselasky */ 9395321936Shselaskystatic 9396321936Shselaskyvoid check_qos_ep_config(osm_qos_options_t *opt, osm_qos_options_t *def, 9397321936Shselasky const char *str, osm_log_t *log) 9398321936Shselasky{ 9399321936Shselasky const char *vlarb_str; 9400321936Shselasky bool is_default, is_specific; 9401321936Shselasky unsigned max_vls; 9402321936Shselasky 9403321936Shselasky max_vls = def->max_vls; 9404321936Shselasky if (opt->max_vls > 0) 9405321936Shselasky max_vls = opt->max_vls; 9406321936Shselasky 9407321936Shselasky if (max_vls > 0 && max_vls < 2) 9408321936Shselasky OSM_LOG(log, OSM_LOG_INFO, 9409321936Shselasky "Warning: full torus-2QoS functionality not available " 9410321936Shselasky "for configured %s_max_vls = %d\n", 9411321936Shselasky (opt->max_vls > 0 ? str : "qos"), opt->max_vls); 9412321936Shselasky 9413321936Shselasky vlarb_str = opt->vlarb_high; 9414321936Shselasky is_default = false; 9415321936Shselasky is_specific = true; 9416321936Shselasky if (!vlarb_str) { 9417321936Shselasky vlarb_str = def->vlarb_high; 9418321936Shselasky is_specific = false; 9419321936Shselasky } 9420321936Shselasky if (!vlarb_str) { 9421321936Shselasky vlarb_str = OSM_DEFAULT_QOS_VLARB_HIGH; 9422321936Shselasky is_default = true; 9423321936Shselasky } 9424321936Shselasky check_ep_vlarb_config(vlarb_str, is_default, is_specific, 9425321936Shselasky str, "high", log); 9426321936Shselasky 9427321936Shselasky vlarb_str = opt->vlarb_low; 9428321936Shselasky is_default = false; 9429321936Shselasky is_specific = true; 9430321936Shselasky if (!vlarb_str) { 9431321936Shselasky vlarb_str = def->vlarb_low; 9432321936Shselasky is_specific = false; 9433321936Shselasky } 9434321936Shselasky if (!vlarb_str) { 9435321936Shselasky vlarb_str = OSM_DEFAULT_QOS_VLARB_LOW; 9436321936Shselasky is_default = true; 9437321936Shselasky } 9438321936Shselasky check_ep_vlarb_config(vlarb_str, is_default, is_specific, 9439321936Shselasky str, "low", log); 9440321936Shselasky 9441321936Shselasky if (opt->sl2vl) 9442321936Shselasky OSM_LOG(log, OSM_LOG_INFO, 9443321936Shselasky "Warning: torus-2QoS must override configured " 9444321936Shselasky "%s_sl2vl to generate deadlock-free routes\n", str); 9445321936Shselasky} 9446321936Shselasky 9447321936Shselaskystatic 9448321936Shselaskyint torus_build_lfts(void *context) 9449321936Shselasky{ 9450321936Shselasky int status = -1; 9451321936Shselasky struct torus_context *ctx = context; 9452321936Shselasky struct fabric *fabric; 9453321936Shselasky struct torus *torus; 9454321936Shselasky 9455321936Shselasky if (!ctx->osm->subn.opt.qos) { 9456321936Shselasky OSM_LOG(&ctx->osm->log, OSM_LOG_ERROR, 9457321936Shselasky "ERR 4E44: Routing engine list contains torus-2QoS. " 9458321936Shselasky "Enable QoS for correct operation " 9459321936Shselasky "(-Q or 'qos TRUE' in opensm.conf).\n"); 9460321936Shselasky return status; 9461321936Shselasky } 9462321936Shselasky 9463321936Shselasky fabric = &ctx->fabric; 9464321936Shselasky teardown_fabric(fabric); 9465321936Shselasky 9466321936Shselasky torus = calloc(1, sizeof(*torus)); 9467321936Shselasky if (!torus) { 9468321936Shselasky OSM_LOG(&ctx->osm->log, OSM_LOG_ERROR, 9469321936Shselasky "ERR 4E45: allocating torus: %s\n", strerror(errno)); 9470321936Shselasky goto out; 9471321936Shselasky } 9472321936Shselasky torus->osm = ctx->osm; 9473321936Shselasky fabric->osm = ctx->osm; 9474321936Shselasky 9475321936Shselasky if (!parse_config(ctx->osm->subn.opt.torus_conf_file, 9476321936Shselasky fabric, torus)) 9477321936Shselasky goto out; 9478321936Shselasky 9479321936Shselasky if (!capture_fabric(fabric)) 9480321936Shselasky goto out; 9481321936Shselasky 9482321936Shselasky OSM_LOG(&torus->osm->log, OSM_LOG_INFO, 9483321936Shselasky "Found fabric w/ %d links, %d switches, %d CA ports, " 9484321936Shselasky "minimum data VLs: endport %d, switchport %d\n", 9485321936Shselasky (int)fabric->link_cnt, (int)fabric->switch_cnt, 9486321936Shselasky (int)fabric->ca_cnt, (int)ctx->osm->subn.min_data_vls, 9487321936Shselasky (int)ctx->osm->subn.min_sw_data_vls); 9488321936Shselasky 9489321936Shselasky if (!verify_setup(torus, fabric)) 9490321936Shselasky goto out; 9491321936Shselasky 9492321936Shselasky OSM_LOG(&torus->osm->log, OSM_LOG_INFO, 9493321936Shselasky "Looking for %d x %d x %d %s\n", 9494321936Shselasky (int)torus->x_sz, (int)torus->y_sz, (int)torus->z_sz, 9495321936Shselasky (ALL_MESH(torus->flags) ? "mesh" : "torus")); 9496321936Shselasky 9497321936Shselasky if (!build_torus(fabric, torus)) { 9498321936Shselasky OSM_LOG(&torus->osm->log, OSM_LOG_ERROR, "ERR 4E57: " 9499321936Shselasky "build_torus finished with errors\n"); 9500321936Shselasky goto out; 9501321936Shselasky } 9502321936Shselasky 9503321936Shselasky OSM_LOG(&torus->osm->log, OSM_LOG_INFO, 9504321936Shselasky "Built %d x %d x %d %s w/ %d links, %d switches, %d CA ports\n", 9505321936Shselasky (int)torus->x_sz, (int)torus->y_sz, (int)torus->z_sz, 9506321936Shselasky (ALL_MESH(torus->flags) ? "mesh" : "torus"), 9507321936Shselasky (int)torus->link_cnt, (int)torus->switch_cnt, 9508321936Shselasky (int)torus->ca_cnt); 9509321936Shselasky 9510321936Shselasky diagnose_fabric(fabric); 9511321936Shselasky /* 9512321936Shselasky * Since we found some sort of torus fabric, report on any topology 9513321936Shselasky * changes vs. the last torus we found. 9514321936Shselasky */ 9515321936Shselasky if (torus->flags & NOTIFY_CHANGES) 9516321936Shselasky report_torus_changes(torus, ctx->torus); 9517321936Shselasky 9518321936Shselasky if (routable_torus(torus, fabric)) 9519321936Shselasky status = route_torus(torus); 9520321936Shselasky 9521321936Shselaskyout: 9522321936Shselasky if (status) { /* bad torus!! */ 9523321936Shselasky if (torus) 9524321936Shselasky teardown_torus(torus); 9525321936Shselasky } else { 9526321936Shselasky osm_subn_opt_t *opt = &torus->osm->subn.opt; 9527321936Shselasky osm_log_t *log = &torus->osm->log; 9528321936Shselasky 9529321936Shselasky if (ctx->torus) 9530321936Shselasky teardown_torus(ctx->torus); 9531321936Shselasky ctx->torus = torus; 9532321936Shselasky 9533321936Shselasky check_qos_swe_config(&opt->qos_swe_options, &opt->qos_options, 9534321936Shselasky log); 9535321936Shselasky 9536321936Shselasky check_qos_ep_config(&opt->qos_ca_options, 9537321936Shselasky &opt->qos_options, "qos_ca", log); 9538321936Shselasky check_qos_ep_config(&opt->qos_sw0_options, 9539321936Shselasky &opt->qos_options, "qos_sw0", log); 9540321936Shselasky check_qos_ep_config(&opt->qos_rtr_options, 9541321936Shselasky &opt->qos_options, "qos_rtr", log); 9542321936Shselasky } 9543321936Shselasky teardown_fabric(fabric); 9544321936Shselasky return status; 9545321936Shselasky} 9546321936Shselasky 9547321936Shselaskyint osm_ucast_torus2QoS_setup(struct osm_routing_engine *r, 9548321936Shselasky osm_opensm_t *osm) 9549321936Shselasky{ 9550321936Shselasky struct torus_context *ctx; 9551321936Shselasky 9552321936Shselasky ctx = torus_context_create(osm); 9553321936Shselasky if (!ctx) 9554321936Shselasky return -1; 9555321936Shselasky 9556321936Shselasky r->context = ctx; 9557321936Shselasky r->ucast_build_fwd_tables = torus_build_lfts; 9558321936Shselasky r->build_lid_matrices = ucast_dummy_build_lid_matrices; 9559321936Shselasky r->update_sl2vl = torus_update_osm_sl2vl; 9560321936Shselasky r->update_vlarb = torus_update_osm_vlarb; 9561321936Shselasky r->path_sl = torus_path_sl; 9562321936Shselasky r->mcast_build_stree = torus_mcast_stree; 9563321936Shselasky r->destroy = torus_context_delete; 9564321936Shselasky return 0; 9565321936Shselasky} 9566