1321936Shselasky/* 2321936Shselasky * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. 3321936Shselasky * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. 4321936Shselasky * Copyright (c) 2008 Lawrence Livermore National Laboratory 5321936Shselasky * 6321936Shselasky * This software is available to you under a choice of one of two 7321936Shselasky * licenses. You may choose to be licensed under the terms of the GNU 8321936Shselasky * General Public License (GPL) Version 2, available from the file 9321936Shselasky * COPYING in the main directory of this source tree, or the 10321936Shselasky * OpenIB.org BSD license below: 11321936Shselasky * 12321936Shselasky * Redistribution and use in source and binary forms, with or 13321936Shselasky * without modification, are permitted provided that the following 14321936Shselasky * conditions are met: 15321936Shselasky * 16321936Shselasky * - Redistributions of source code must retain the above 17321936Shselasky * copyright notice, this list of conditions and the following 18321936Shselasky * disclaimer. 19321936Shselasky * 20321936Shselasky * - Redistributions in binary form must reproduce the above 21321936Shselasky * copyright notice, this list of conditions and the following 22321936Shselasky * disclaimer in the documentation and/or other materials 23321936Shselasky * provided with the distribution. 24321936Shselasky * 25321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32321936Shselasky * SOFTWARE. 33321936Shselasky * 34321936Shselasky */ 35321936Shselasky 36321936Shselasky#if HAVE_CONFIG_H 37321936Shselasky#include <config.h> 38321936Shselasky#endif /* HAVE_CONFIG_H */ 39321936Shselasky 40321936Shselasky#define _GNU_SOURCE 41321936Shselasky#include <stdio.h> 42321936Shselasky#include <stdlib.h> 43321936Shselasky#include <sys/types.h> 44321936Shselasky#include <sys/stat.h> 45321936Shselasky#include <unistd.h> 46321936Shselasky#include <fcntl.h> 47321936Shselasky#include <string.h> 48321936Shselasky#include <errno.h> 49321936Shselasky#include <inttypes.h> 50321936Shselasky 51321936Shselasky#include <infiniband/ibnetdisc.h> 52321936Shselasky 53321936Shselasky#include "internal.h" 54321936Shselasky#include "chassis.h" 55321936Shselasky 56321936Shselasky/* For this caching lib, we always cache little endian */ 57321936Shselasky 58321936Shselasky/* Cache format 59321936Shselasky * 60321936Shselasky * Bytes 1-4 - magic number 61321936Shselasky * Bytes 5-8 - version number 62321936Shselasky * Bytes 9-12 - node count 63321936Shselasky * Bytes 13-16 - port count 64321936Shselasky * Bytes 17-24 - "from node" guid 65321936Shselasky * Bytes 25-28 - maxhops discovered 66321936Shselasky * Bytes X-Y - nodes (variable length) 67321936Shselasky * Bytes X-Y - ports (variable length) 68321936Shselasky * 69321936Shselasky * Nodes are cached as 70321936Shselasky * 71321936Shselasky * 2 bytes - smalid 72321936Shselasky * 1 byte - smalmc 73321936Shselasky * 1 byte - smaenhsp0 flag 74321936Shselasky * IB_SMP_DATA_SIZE bytes - switchinfo 75321936Shselasky * 8 bytes - guid 76321936Shselasky * 1 byte - type 77321936Shselasky * 1 byte - numports 78321936Shselasky * IB_SMP_DATA_SIZE bytes - info 79321936Shselasky * IB_SMP_DATA_SIZE bytes - nodedesc 80321936Shselasky * 1 byte - number of ports stored 81321936Shselasky * 8 bytes - portguid A 82321936Shselasky * 1 byte - port num A 83321936Shselasky * 8 bytes - portguid B 84321936Shselasky * 1 byte - port num B 85321936Shselasky * ... etc., depending on number of ports stored 86321936Shselasky * 87321936Shselasky * Ports are cached as 88321936Shselasky * 89321936Shselasky * 8 bytes - guid 90321936Shselasky * 1 byte - portnum 91321936Shselasky * 1 byte - external portnum 92321936Shselasky * 2 bytes - base lid 93321936Shselasky * 1 byte - lmc 94321936Shselasky * IB_SMP_DATA_SIZE bytes - info 95321936Shselasky * 8 bytes - node guid port "owned" by 96321936Shselasky * 1 byte - flag indicating if remote port exists 97321936Shselasky * 8 bytes - port guid remotely connected to 98321936Shselasky * 1 byte - port num remotely connected to 99321936Shselasky */ 100321936Shselasky 101321936Shselasky/* Structs that hold cache info temporarily before 102321936Shselasky * the real structs can be reconstructed. 103321936Shselasky */ 104321936Shselasky 105321936Shselaskytypedef struct ibnd_port_cache_key { 106321936Shselasky uint64_t guid; 107321936Shselasky uint8_t portnum; 108321936Shselasky} ibnd_port_cache_key_t; 109321936Shselasky 110321936Shselaskytypedef struct ibnd_node_cache { 111321936Shselasky ibnd_node_t *node; 112321936Shselasky uint8_t ports_stored_count; 113321936Shselasky ibnd_port_cache_key_t *port_cache_keys; 114321936Shselasky struct ibnd_node_cache *next; 115321936Shselasky struct ibnd_node_cache *htnext; 116321936Shselasky int node_stored_to_fabric; 117321936Shselasky} ibnd_node_cache_t; 118321936Shselasky 119321936Shselaskytypedef struct ibnd_port_cache { 120321936Shselasky ibnd_port_t *port; 121321936Shselasky uint64_t node_guid; 122321936Shselasky uint8_t remoteport_flag; 123321936Shselasky ibnd_port_cache_key_t remoteport_cache_key; 124321936Shselasky struct ibnd_port_cache *next; 125321936Shselasky struct ibnd_port_cache *htnext; 126321936Shselasky int port_stored_to_fabric; 127321936Shselasky} ibnd_port_cache_t; 128321936Shselasky 129321936Shselaskytypedef struct ibnd_fabric_cache { 130321936Shselasky f_internal_t *f_int; 131321936Shselasky uint64_t from_node_guid; 132321936Shselasky ibnd_node_cache_t *nodes_cache; 133321936Shselasky ibnd_port_cache_t *ports_cache; 134321936Shselasky ibnd_node_cache_t *nodescachetbl[HTSZ]; 135321936Shselasky ibnd_port_cache_t *portscachetbl[HTSZ]; 136321936Shselasky} ibnd_fabric_cache_t; 137321936Shselasky 138321936Shselasky#define IBND_FABRIC_CACHE_BUFLEN 4096 139321936Shselasky#define IBND_FABRIC_CACHE_MAGIC 0x8FE7832B 140321936Shselasky#define IBND_FABRIC_CACHE_VERSION 0x00000001 141321936Shselasky 142321936Shselasky#define IBND_FABRIC_CACHE_COUNT_OFFSET 8 143321936Shselasky 144321936Shselasky#define IBND_FABRIC_CACHE_HEADER_LEN (28) 145321936Shselasky#define IBND_NODE_CACHE_HEADER_LEN (15 + IB_SMP_DATA_SIZE*3) 146321936Shselasky#define IBND_PORT_CACHE_KEY_LEN (8 + 1) 147321936Shselasky#define IBND_PORT_CACHE_LEN (31 + IB_SMP_DATA_SIZE) 148321936Shselasky 149321936Shselaskystatic ssize_t ibnd_read(int fd, void *buf, size_t count) 150321936Shselasky{ 151321936Shselasky size_t count_done = 0; 152321936Shselasky ssize_t ret; 153321936Shselasky 154321936Shselasky while ((count - count_done) > 0) { 155321936Shselasky ret = read(fd, ((char *) buf) + count_done, count - count_done); 156321936Shselasky if (ret < 0) { 157321936Shselasky if (errno == EINTR) 158321936Shselasky continue; 159321936Shselasky else { 160321936Shselasky IBND_DEBUG("read: %s\n", strerror(errno)); 161321936Shselasky return -1; 162321936Shselasky } 163321936Shselasky } 164321936Shselasky if (!ret) 165321936Shselasky break; 166321936Shselasky count_done += ret; 167321936Shselasky } 168321936Shselasky 169321936Shselasky if (count_done != count) { 170321936Shselasky IBND_DEBUG("read: read short\n"); 171321936Shselasky return -1; 172321936Shselasky } 173321936Shselasky 174321936Shselasky return count_done; 175321936Shselasky} 176321936Shselasky 177321936Shselaskystatic size_t _unmarshall8(uint8_t * inbuf, uint8_t * num) 178321936Shselasky{ 179321936Shselasky (*num) = inbuf[0]; 180321936Shselasky 181321936Shselasky return (sizeof(*num)); 182321936Shselasky} 183321936Shselasky 184321936Shselaskystatic size_t _unmarshall16(uint8_t * inbuf, uint16_t * num) 185321936Shselasky{ 186321936Shselasky (*num) = ((uint16_t) inbuf[1] << 8) | inbuf[0]; 187321936Shselasky 188321936Shselasky return (sizeof(*num)); 189321936Shselasky} 190321936Shselasky 191321936Shselaskystatic size_t _unmarshall32(uint8_t * inbuf, uint32_t * num) 192321936Shselasky{ 193321936Shselasky (*num) = (uint32_t) inbuf[0]; 194321936Shselasky (*num) |= ((uint32_t) inbuf[1] << 8); 195321936Shselasky (*num) |= ((uint32_t) inbuf[2] << 16); 196321936Shselasky (*num) |= ((uint32_t) inbuf[3] << 24); 197321936Shselasky 198321936Shselasky return (sizeof(*num)); 199321936Shselasky} 200321936Shselasky 201321936Shselaskystatic size_t _unmarshall64(uint8_t * inbuf, uint64_t * num) 202321936Shselasky{ 203321936Shselasky (*num) = (uint64_t) inbuf[0]; 204321936Shselasky (*num) |= ((uint64_t) inbuf[1] << 8); 205321936Shselasky (*num) |= ((uint64_t) inbuf[2] << 16); 206321936Shselasky (*num) |= ((uint64_t) inbuf[3] << 24); 207321936Shselasky (*num) |= ((uint64_t) inbuf[4] << 32); 208321936Shselasky (*num) |= ((uint64_t) inbuf[5] << 40); 209321936Shselasky (*num) |= ((uint64_t) inbuf[6] << 48); 210321936Shselasky (*num) |= ((uint64_t) inbuf[7] << 56); 211321936Shselasky 212321936Shselasky return (sizeof(*num)); 213321936Shselasky} 214321936Shselasky 215321936Shselaskystatic size_t _unmarshall_buf(const void *inbuf, void *outbuf, unsigned int len) 216321936Shselasky{ 217321936Shselasky memcpy(outbuf, inbuf, len); 218321936Shselasky 219321936Shselasky return len; 220321936Shselasky} 221321936Shselasky 222321936Shselaskystatic int _load_header_info(int fd, ibnd_fabric_cache_t * fabric_cache, 223321936Shselasky unsigned int *node_count, unsigned int *port_count) 224321936Shselasky{ 225321936Shselasky uint8_t buf[IBND_FABRIC_CACHE_BUFLEN]; 226321936Shselasky uint32_t magic = 0; 227321936Shselasky uint32_t version = 0; 228321936Shselasky size_t offset = 0; 229321936Shselasky uint32_t tmp32; 230321936Shselasky 231321936Shselasky if (ibnd_read(fd, buf, IBND_FABRIC_CACHE_HEADER_LEN) < 0) 232321936Shselasky return -1; 233321936Shselasky 234321936Shselasky offset += _unmarshall32(buf + offset, &magic); 235321936Shselasky 236321936Shselasky if (magic != IBND_FABRIC_CACHE_MAGIC) { 237321936Shselasky IBND_DEBUG("invalid fabric cache file\n"); 238321936Shselasky return -1; 239321936Shselasky } 240321936Shselasky 241321936Shselasky offset += _unmarshall32(buf + offset, &version); 242321936Shselasky 243321936Shselasky if (version != IBND_FABRIC_CACHE_VERSION) { 244321936Shselasky IBND_DEBUG("invalid fabric cache version\n"); 245321936Shselasky return -1; 246321936Shselasky } 247321936Shselasky 248321936Shselasky offset += _unmarshall32(buf + offset, node_count); 249321936Shselasky offset += _unmarshall32(buf + offset, port_count); 250321936Shselasky 251321936Shselasky offset += _unmarshall64(buf + offset, &fabric_cache->from_node_guid); 252321936Shselasky offset += _unmarshall32(buf + offset, &tmp32); 253321936Shselasky fabric_cache->f_int->fabric.maxhops_discovered = tmp32; 254321936Shselasky 255321936Shselasky return 0; 256321936Shselasky} 257321936Shselasky 258321936Shselaskystatic void _destroy_ibnd_node_cache(ibnd_node_cache_t * node_cache) 259321936Shselasky{ 260321936Shselasky free(node_cache->port_cache_keys); 261321936Shselasky if (!node_cache->node_stored_to_fabric && node_cache->node) 262321936Shselasky destroy_node(node_cache->node); 263321936Shselasky free(node_cache); 264321936Shselasky} 265321936Shselasky 266321936Shselaskystatic void _destroy_ibnd_fabric_cache(ibnd_fabric_cache_t * fabric_cache) 267321936Shselasky{ 268321936Shselasky ibnd_node_cache_t *node_cache; 269321936Shselasky ibnd_node_cache_t *node_cache_next; 270321936Shselasky ibnd_port_cache_t *port_cache; 271321936Shselasky ibnd_port_cache_t *port_cache_next; 272321936Shselasky 273321936Shselasky if (!fabric_cache) 274321936Shselasky return; 275321936Shselasky 276321936Shselasky node_cache = fabric_cache->nodes_cache; 277321936Shselasky while (node_cache) { 278321936Shselasky node_cache_next = node_cache->next; 279321936Shselasky 280321936Shselasky _destroy_ibnd_node_cache(node_cache); 281321936Shselasky 282321936Shselasky node_cache = node_cache_next; 283321936Shselasky } 284321936Shselasky 285321936Shselasky port_cache = fabric_cache->ports_cache; 286321936Shselasky while (port_cache) { 287321936Shselasky port_cache_next = port_cache->next; 288321936Shselasky 289321936Shselasky if (!port_cache->port_stored_to_fabric && port_cache->port) 290321936Shselasky free(port_cache->port); 291321936Shselasky free(port_cache); 292321936Shselasky 293321936Shselasky port_cache = port_cache_next; 294321936Shselasky } 295321936Shselasky 296321936Shselasky free(fabric_cache); 297321936Shselasky} 298321936Shselasky 299321936Shselaskystatic void store_node_cache(ibnd_node_cache_t * node_cache, 300321936Shselasky ibnd_fabric_cache_t * fabric_cache) 301321936Shselasky{ 302321936Shselasky int hash_indx = HASHGUID(node_cache->node->guid) % HTSZ; 303321936Shselasky 304321936Shselasky node_cache->next = fabric_cache->nodes_cache; 305321936Shselasky fabric_cache->nodes_cache = node_cache; 306321936Shselasky 307321936Shselasky node_cache->htnext = fabric_cache->nodescachetbl[hash_indx]; 308321936Shselasky fabric_cache->nodescachetbl[hash_indx] = node_cache; 309321936Shselasky} 310321936Shselasky 311321936Shselaskystatic int _load_node(int fd, ibnd_fabric_cache_t * fabric_cache) 312321936Shselasky{ 313321936Shselasky uint8_t buf[IBND_FABRIC_CACHE_BUFLEN]; 314321936Shselasky ibnd_node_cache_t *node_cache = NULL; 315321936Shselasky ibnd_node_t *node = NULL; 316321936Shselasky size_t offset = 0; 317321936Shselasky uint8_t tmp8; 318321936Shselasky 319321936Shselasky node_cache = (ibnd_node_cache_t *) malloc(sizeof(ibnd_node_cache_t)); 320321936Shselasky if (!node_cache) { 321321936Shselasky IBND_DEBUG("OOM: node_cache\n"); 322321936Shselasky return -1; 323321936Shselasky } 324321936Shselasky memset(node_cache, '\0', sizeof(ibnd_node_cache_t)); 325321936Shselasky 326321936Shselasky node = (ibnd_node_t *) malloc(sizeof(ibnd_node_t)); 327321936Shselasky if (!node) { 328321936Shselasky IBND_DEBUG("OOM: node\n"); 329321936Shselasky free(node_cache); 330321936Shselasky return -1; 331321936Shselasky } 332321936Shselasky memset(node, '\0', sizeof(ibnd_node_t)); 333321936Shselasky 334321936Shselasky node_cache->node = node; 335321936Shselasky 336321936Shselasky if (ibnd_read(fd, buf, IBND_NODE_CACHE_HEADER_LEN) < 0) 337321936Shselasky goto cleanup; 338321936Shselasky 339321936Shselasky offset += _unmarshall16(buf + offset, &node->smalid); 340321936Shselasky offset += _unmarshall8(buf + offset, &node->smalmc); 341321936Shselasky offset += _unmarshall8(buf + offset, &tmp8); 342321936Shselasky node->smaenhsp0 = tmp8; 343321936Shselasky offset += _unmarshall_buf(buf + offset, node->switchinfo, 344321936Shselasky IB_SMP_DATA_SIZE); 345321936Shselasky offset += _unmarshall64(buf + offset, &node->guid); 346321936Shselasky offset += _unmarshall8(buf + offset, &tmp8); 347321936Shselasky node->type = tmp8; 348321936Shselasky offset += _unmarshall8(buf + offset, &tmp8); 349321936Shselasky node->numports = tmp8; 350321936Shselasky offset += _unmarshall_buf(buf + offset, node->info, IB_SMP_DATA_SIZE); 351321936Shselasky offset += _unmarshall_buf(buf + offset, node->nodedesc, 352321936Shselasky IB_SMP_DATA_SIZE); 353321936Shselasky 354321936Shselasky offset += _unmarshall8(buf + offset, &node_cache->ports_stored_count); 355321936Shselasky 356321936Shselasky if (node_cache->ports_stored_count) { 357321936Shselasky unsigned int tomalloc = 0; 358321936Shselasky unsigned int toread = 0; 359321936Shselasky unsigned int i; 360321936Shselasky 361321936Shselasky tomalloc = 362321936Shselasky sizeof(ibnd_port_cache_key_t) * 363321936Shselasky node_cache->ports_stored_count; 364321936Shselasky 365321936Shselasky toread = 366321936Shselasky IBND_PORT_CACHE_KEY_LEN * node_cache->ports_stored_count; 367321936Shselasky 368321936Shselasky node_cache->port_cache_keys = 369321936Shselasky (ibnd_port_cache_key_t *) malloc(tomalloc); 370321936Shselasky if (!node_cache->port_cache_keys) { 371321936Shselasky IBND_DEBUG("OOM: node_cache port_cache_keys\n"); 372321936Shselasky goto cleanup; 373321936Shselasky } 374321936Shselasky 375321936Shselasky if (ibnd_read(fd, buf, toread) < 0) 376321936Shselasky goto cleanup; 377321936Shselasky 378321936Shselasky offset = 0; 379321936Shselasky 380321936Shselasky for (i = 0; i < node_cache->ports_stored_count; i++) { 381321936Shselasky offset += 382321936Shselasky _unmarshall64(buf + offset, 383321936Shselasky &node_cache->port_cache_keys[i].guid); 384321936Shselasky offset += 385321936Shselasky _unmarshall8(buf + offset, 386321936Shselasky &node_cache-> 387321936Shselasky port_cache_keys[i].portnum); 388321936Shselasky } 389321936Shselasky } 390321936Shselasky 391321936Shselasky store_node_cache(node_cache, fabric_cache); 392321936Shselasky 393321936Shselasky return 0; 394321936Shselasky 395321936Shselaskycleanup: 396321936Shselasky _destroy_ibnd_node_cache(node_cache); 397321936Shselasky return -1; 398321936Shselasky} 399321936Shselasky 400321936Shselaskystatic void store_port_cache(ibnd_port_cache_t * port_cache, 401321936Shselasky ibnd_fabric_cache_t * fabric_cache) 402321936Shselasky{ 403321936Shselasky int hash_indx = HASHGUID(port_cache->port->guid) % HTSZ; 404321936Shselasky 405321936Shselasky port_cache->next = fabric_cache->ports_cache; 406321936Shselasky fabric_cache->ports_cache = port_cache; 407321936Shselasky 408321936Shselasky port_cache->htnext = fabric_cache->portscachetbl[hash_indx]; 409321936Shselasky fabric_cache->portscachetbl[hash_indx] = port_cache; 410321936Shselasky} 411321936Shselasky 412321936Shselaskystatic int _load_port(int fd, ibnd_fabric_cache_t * fabric_cache) 413321936Shselasky{ 414321936Shselasky uint8_t buf[IBND_FABRIC_CACHE_BUFLEN]; 415321936Shselasky ibnd_port_cache_t *port_cache = NULL; 416321936Shselasky ibnd_port_t *port = NULL; 417321936Shselasky size_t offset = 0; 418321936Shselasky uint8_t tmp8; 419321936Shselasky 420321936Shselasky port_cache = (ibnd_port_cache_t *) malloc(sizeof(ibnd_port_cache_t)); 421321936Shselasky if (!port_cache) { 422321936Shselasky IBND_DEBUG("OOM: port_cache\n"); 423321936Shselasky return -1; 424321936Shselasky } 425321936Shselasky memset(port_cache, '\0', sizeof(ibnd_port_cache_t)); 426321936Shselasky 427321936Shselasky port = (ibnd_port_t *) malloc(sizeof(ibnd_port_t)); 428321936Shselasky if (!port) { 429321936Shselasky IBND_DEBUG("OOM: port\n"); 430321936Shselasky free(port_cache); 431321936Shselasky return -1; 432321936Shselasky } 433321936Shselasky memset(port, '\0', sizeof(ibnd_port_t)); 434321936Shselasky 435321936Shselasky port_cache->port = port; 436321936Shselasky 437321936Shselasky if (ibnd_read(fd, buf, IBND_PORT_CACHE_LEN) < 0) 438321936Shselasky goto cleanup; 439321936Shselasky 440321936Shselasky offset += _unmarshall64(buf + offset, &port->guid); 441321936Shselasky offset += _unmarshall8(buf + offset, &tmp8); 442321936Shselasky port->portnum = tmp8; 443321936Shselasky offset += _unmarshall8(buf + offset, &tmp8); 444321936Shselasky port->ext_portnum = tmp8; 445321936Shselasky offset += _unmarshall16(buf + offset, &port->base_lid); 446321936Shselasky offset += _unmarshall8(buf + offset, &port->lmc); 447321936Shselasky offset += _unmarshall_buf(buf + offset, port->info, IB_SMP_DATA_SIZE); 448321936Shselasky offset += _unmarshall64(buf + offset, &port_cache->node_guid); 449321936Shselasky offset += _unmarshall8(buf + offset, &port_cache->remoteport_flag); 450321936Shselasky offset += 451321936Shselasky _unmarshall64(buf + offset, &port_cache->remoteport_cache_key.guid); 452321936Shselasky offset += 453321936Shselasky _unmarshall8(buf + offset, 454321936Shselasky &port_cache->remoteport_cache_key.portnum); 455321936Shselasky 456321936Shselasky store_port_cache(port_cache, fabric_cache); 457321936Shselasky 458321936Shselasky return 0; 459321936Shselasky 460321936Shselaskycleanup: 461321936Shselasky free(port); 462321936Shselasky free(port_cache); 463321936Shselasky return -1; 464321936Shselasky} 465321936Shselasky 466321936Shselaskystatic ibnd_port_cache_t *_find_port(ibnd_fabric_cache_t * fabric_cache, 467321936Shselasky ibnd_port_cache_key_t * port_cache_key) 468321936Shselasky{ 469321936Shselasky int hash_indx = HASHGUID(port_cache_key->guid) % HTSZ; 470321936Shselasky ibnd_port_cache_t *port_cache; 471321936Shselasky 472321936Shselasky for (port_cache = fabric_cache->portscachetbl[hash_indx]; 473321936Shselasky port_cache; port_cache = port_cache->htnext) { 474321936Shselasky if (port_cache->port->guid == port_cache_key->guid 475321936Shselasky && port_cache->port->portnum == port_cache_key->portnum) 476321936Shselasky return port_cache; 477321936Shselasky } 478321936Shselasky 479321936Shselasky return NULL; 480321936Shselasky} 481321936Shselasky 482321936Shselaskystatic ibnd_node_cache_t *_find_node(ibnd_fabric_cache_t * fabric_cache, 483321936Shselasky uint64_t guid) 484321936Shselasky{ 485321936Shselasky int hash_indx = HASHGUID(guid) % HTSZ; 486321936Shselasky ibnd_node_cache_t *node_cache; 487321936Shselasky 488321936Shselasky for (node_cache = fabric_cache->nodescachetbl[hash_indx]; 489321936Shselasky node_cache; node_cache = node_cache->htnext) { 490321936Shselasky if (node_cache->node->guid == guid) 491321936Shselasky return node_cache; 492321936Shselasky } 493321936Shselasky 494321936Shselasky return NULL; 495321936Shselasky} 496321936Shselasky 497321936Shselaskystatic int _fill_port(ibnd_fabric_cache_t * fabric_cache, ibnd_node_t * node, 498321936Shselasky ibnd_port_cache_key_t * port_cache_key) 499321936Shselasky{ 500321936Shselasky ibnd_port_cache_t *port_cache; 501321936Shselasky 502321936Shselasky if (!(port_cache = _find_port(fabric_cache, port_cache_key))) { 503321936Shselasky IBND_DEBUG("Cache invalid: cannot find port\n"); 504321936Shselasky return -1; 505321936Shselasky } 506321936Shselasky 507321936Shselasky if (port_cache->port_stored_to_fabric) { 508321936Shselasky IBND_DEBUG("Cache invalid: duplicate port discovered\n"); 509321936Shselasky return -1; 510321936Shselasky } 511321936Shselasky 512321936Shselasky node->ports[port_cache->port->portnum] = port_cache->port; 513321936Shselasky port_cache->port_stored_to_fabric++; 514321936Shselasky 515321936Shselasky /* achu: needed if user wishes to re-cache a loaded fabric. 516321936Shselasky * Otherwise, mostly unnecessary to do this. 517321936Shselasky */ 518321936Shselasky int rc = add_to_portguid_hash(port_cache->port, 519321936Shselasky fabric_cache->f_int->fabric.portstbl); 520321936Shselasky if (rc) { 521321936Shselasky IBND_DEBUG("Error Occurred when trying" 522321936Shselasky " to insert new port guid 0x%016" PRIx64 " to DB\n", 523321936Shselasky port_cache->port->guid); 524321936Shselasky } 525321936Shselasky return 0; 526321936Shselasky} 527321936Shselasky 528321936Shselaskystatic int _rebuild_nodes(ibnd_fabric_cache_t * fabric_cache) 529321936Shselasky{ 530321936Shselasky ibnd_node_cache_t *node_cache; 531321936Shselasky ibnd_node_cache_t *node_cache_next; 532321936Shselasky 533321936Shselasky node_cache = fabric_cache->nodes_cache; 534321936Shselasky while (node_cache) { 535321936Shselasky ibnd_node_t *node; 536321936Shselasky int i; 537321936Shselasky 538321936Shselasky node_cache_next = node_cache->next; 539321936Shselasky 540321936Shselasky node = node_cache->node; 541321936Shselasky 542321936Shselasky /* Insert node into appropriate data structures */ 543321936Shselasky 544321936Shselasky node->next = fabric_cache->f_int->fabric.nodes; 545321936Shselasky fabric_cache->f_int->fabric.nodes = node; 546321936Shselasky 547321936Shselasky int rc = add_to_nodeguid_hash(node_cache->node, 548321936Shselasky fabric_cache-> 549321936Shselasky f_int-> 550321936Shselasky fabric.nodestbl); 551321936Shselasky if (rc) { 552321936Shselasky IBND_DEBUG("Error Occurred when trying" 553321936Shselasky " to insert new node guid 0x%016" PRIx64 " to DB\n", 554321936Shselasky node_cache->node->guid); 555321936Shselasky } 556321936Shselasky 557321936Shselasky add_to_type_list(node_cache->node, fabric_cache->f_int); 558321936Shselasky 559321936Shselasky node_cache->node_stored_to_fabric++; 560321936Shselasky 561321936Shselasky /* Rebuild node ports array */ 562321936Shselasky 563321936Shselasky if (!(node->ports = 564321936Shselasky calloc(sizeof(*node->ports), node->numports + 1))) { 565321936Shselasky IBND_DEBUG("OOM: node->ports\n"); 566321936Shselasky return -1; 567321936Shselasky } 568321936Shselasky 569321936Shselasky for (i = 0; i < node_cache->ports_stored_count; i++) { 570321936Shselasky if (_fill_port(fabric_cache, node, 571321936Shselasky &node_cache->port_cache_keys[i]) < 0) 572321936Shselasky return -1; 573321936Shselasky } 574321936Shselasky 575321936Shselasky node_cache = node_cache_next; 576321936Shselasky } 577321936Shselasky 578321936Shselasky return 0; 579321936Shselasky} 580321936Shselasky 581321936Shselaskystatic int _rebuild_ports(ibnd_fabric_cache_t * fabric_cache) 582321936Shselasky{ 583321936Shselasky ibnd_port_cache_t *port_cache; 584321936Shselasky ibnd_port_cache_t *port_cache_next; 585321936Shselasky 586321936Shselasky port_cache = fabric_cache->ports_cache; 587321936Shselasky while (port_cache) { 588321936Shselasky ibnd_node_cache_t *node_cache; 589321936Shselasky ibnd_port_cache_t *remoteport_cache; 590321936Shselasky ibnd_port_t *port; 591321936Shselasky 592321936Shselasky port_cache_next = port_cache->next; 593321936Shselasky 594321936Shselasky port = port_cache->port; 595321936Shselasky 596321936Shselasky if (!(node_cache = 597321936Shselasky _find_node(fabric_cache, port_cache->node_guid))) { 598321936Shselasky IBND_DEBUG("Cache invalid: cannot find node\n"); 599321936Shselasky return -1; 600321936Shselasky } 601321936Shselasky 602321936Shselasky port->node = node_cache->node; 603321936Shselasky 604321936Shselasky if (port_cache->remoteport_flag) { 605321936Shselasky if (!(remoteport_cache = _find_port(fabric_cache, 606321936Shselasky &port_cache->remoteport_cache_key))) 607321936Shselasky { 608321936Shselasky IBND_DEBUG 609321936Shselasky ("Cache invalid: cannot find remote port\n"); 610321936Shselasky return -1; 611321936Shselasky } 612321936Shselasky 613321936Shselasky port->remoteport = remoteport_cache->port; 614321936Shselasky } else 615321936Shselasky port->remoteport = NULL; 616321936Shselasky 617321936Shselasky add_to_portlid_hash(port, fabric_cache->f_int->lid2guid); 618321936Shselasky port_cache = port_cache_next; 619321936Shselasky } 620321936Shselasky 621321936Shselasky return 0; 622321936Shselasky} 623321936Shselasky 624321936Shselaskyibnd_fabric_t *ibnd_load_fabric(const char *file, unsigned int flags) 625321936Shselasky{ 626321936Shselasky unsigned int node_count = 0; 627321936Shselasky unsigned int port_count = 0; 628321936Shselasky ibnd_fabric_cache_t *fabric_cache = NULL; 629321936Shselasky f_internal_t *f_int = NULL; 630321936Shselasky ibnd_node_cache_t *node_cache = NULL; 631321936Shselasky int fd = -1; 632321936Shselasky unsigned int i; 633321936Shselasky 634321936Shselasky if (!file) { 635321936Shselasky IBND_DEBUG("file parameter NULL\n"); 636321936Shselasky return NULL; 637321936Shselasky } 638321936Shselasky 639321936Shselasky if ((fd = open(file, O_RDONLY)) < 0) { 640321936Shselasky IBND_DEBUG("open: %s\n", strerror(errno)); 641321936Shselasky return NULL; 642321936Shselasky } 643321936Shselasky 644321936Shselasky fabric_cache = 645321936Shselasky (ibnd_fabric_cache_t *) malloc(sizeof(ibnd_fabric_cache_t)); 646321936Shselasky if (!fabric_cache) { 647321936Shselasky IBND_DEBUG("OOM: fabric_cache\n"); 648321936Shselasky goto cleanup; 649321936Shselasky } 650321936Shselasky memset(fabric_cache, '\0', sizeof(ibnd_fabric_cache_t)); 651321936Shselasky 652321936Shselasky f_int = allocate_fabric_internal(); 653321936Shselasky if (!f_int) { 654321936Shselasky IBND_DEBUG("OOM: fabric\n"); 655321936Shselasky goto cleanup; 656321936Shselasky } 657321936Shselasky 658321936Shselasky fabric_cache->f_int = f_int; 659321936Shselasky 660321936Shselasky if (_load_header_info(fd, fabric_cache, &node_count, &port_count) < 0) 661321936Shselasky goto cleanup; 662321936Shselasky 663321936Shselasky for (i = 0; i < node_count; i++) { 664321936Shselasky if (_load_node(fd, fabric_cache) < 0) 665321936Shselasky goto cleanup; 666321936Shselasky } 667321936Shselasky 668321936Shselasky for (i = 0; i < port_count; i++) { 669321936Shselasky if (_load_port(fd, fabric_cache) < 0) 670321936Shselasky goto cleanup; 671321936Shselasky } 672321936Shselasky 673321936Shselasky /* Special case - find from node */ 674321936Shselasky if (!(node_cache = 675321936Shselasky _find_node(fabric_cache, fabric_cache->from_node_guid))) { 676321936Shselasky IBND_DEBUG("Cache invalid: cannot find from node\n"); 677321936Shselasky goto cleanup; 678321936Shselasky } 679321936Shselasky f_int->fabric.from_node = node_cache->node; 680321936Shselasky 681321936Shselasky if (_rebuild_nodes(fabric_cache) < 0) 682321936Shselasky goto cleanup; 683321936Shselasky 684321936Shselasky if (_rebuild_ports(fabric_cache) < 0) 685321936Shselasky goto cleanup; 686321936Shselasky 687321936Shselasky if (group_nodes(&f_int->fabric)) 688321936Shselasky goto cleanup; 689321936Shselasky 690321936Shselasky _destroy_ibnd_fabric_cache(fabric_cache); 691321936Shselasky close(fd); 692321936Shselasky return (ibnd_fabric_t *)&f_int->fabric; 693321936Shselasky 694321936Shselaskycleanup: 695321936Shselasky ibnd_destroy_fabric((ibnd_fabric_t *)f_int); 696321936Shselasky _destroy_ibnd_fabric_cache(fabric_cache); 697321936Shselasky close(fd); 698321936Shselasky return NULL; 699321936Shselasky} 700321936Shselasky 701321936Shselaskystatic ssize_t ibnd_write(int fd, const void *buf, size_t count) 702321936Shselasky{ 703321936Shselasky size_t count_done = 0; 704321936Shselasky ssize_t ret; 705321936Shselasky 706321936Shselasky while ((count - count_done) > 0) { 707321936Shselasky ret = write(fd, ((char *) buf) + count_done, count - count_done); 708321936Shselasky if (ret < 0) { 709321936Shselasky if (errno == EINTR) 710321936Shselasky continue; 711321936Shselasky else { 712321936Shselasky IBND_DEBUG("write: %s\n", strerror(errno)); 713321936Shselasky return -1; 714321936Shselasky } 715321936Shselasky } 716321936Shselasky count_done += ret; 717321936Shselasky } 718321936Shselasky return count_done; 719321936Shselasky} 720321936Shselasky 721321936Shselaskystatic size_t _marshall8(uint8_t * outbuf, uint8_t num) 722321936Shselasky{ 723321936Shselasky outbuf[0] = num; 724321936Shselasky 725321936Shselasky return (sizeof(num)); 726321936Shselasky} 727321936Shselasky 728321936Shselaskystatic size_t _marshall16(uint8_t * outbuf, uint16_t num) 729321936Shselasky{ 730321936Shselasky outbuf[0] = num & 0x00FF; 731321936Shselasky outbuf[1] = (num & 0xFF00) >> 8; 732321936Shselasky 733321936Shselasky return (sizeof(num)); 734321936Shselasky} 735321936Shselasky 736321936Shselaskystatic size_t _marshall32(uint8_t * outbuf, uint32_t num) 737321936Shselasky{ 738321936Shselasky outbuf[0] = num & 0x000000FF; 739321936Shselasky outbuf[1] = (num & 0x0000FF00) >> 8; 740321936Shselasky outbuf[2] = (num & 0x00FF0000) >> 16; 741321936Shselasky outbuf[3] = (num & 0xFF000000) >> 24; 742321936Shselasky 743321936Shselasky return (sizeof(num)); 744321936Shselasky} 745321936Shselasky 746321936Shselaskystatic size_t _marshall64(uint8_t * outbuf, uint64_t num) 747321936Shselasky{ 748321936Shselasky outbuf[0] = (uint8_t) num; 749321936Shselasky outbuf[1] = (uint8_t) (num >> 8); 750321936Shselasky outbuf[2] = (uint8_t) (num >> 16); 751321936Shselasky outbuf[3] = (uint8_t) (num >> 24); 752321936Shselasky outbuf[4] = (uint8_t) (num >> 32); 753321936Shselasky outbuf[5] = (uint8_t) (num >> 40); 754321936Shselasky outbuf[6] = (uint8_t) (num >> 48); 755321936Shselasky outbuf[7] = (uint8_t) (num >> 56); 756321936Shselasky 757321936Shselasky return (sizeof(num)); 758321936Shselasky} 759321936Shselasky 760321936Shselaskystatic size_t _marshall_buf(void *outbuf, const void *inbuf, unsigned int len) 761321936Shselasky{ 762321936Shselasky memcpy(outbuf, inbuf, len); 763321936Shselasky 764321936Shselasky return len; 765321936Shselasky} 766321936Shselasky 767321936Shselaskystatic int _cache_header_info(int fd, ibnd_fabric_t * fabric) 768321936Shselasky{ 769321936Shselasky uint8_t buf[IBND_FABRIC_CACHE_BUFLEN]; 770321936Shselasky size_t offset = 0; 771321936Shselasky 772321936Shselasky /* Store magic number, version, and other important info */ 773321936Shselasky /* For this caching lib, we always assume cached as little endian */ 774321936Shselasky 775321936Shselasky offset += _marshall32(buf + offset, IBND_FABRIC_CACHE_MAGIC); 776321936Shselasky offset += _marshall32(buf + offset, IBND_FABRIC_CACHE_VERSION); 777321936Shselasky /* save space for node count */ 778321936Shselasky offset += _marshall32(buf + offset, 0); 779321936Shselasky /* save space for port count */ 780321936Shselasky offset += _marshall32(buf + offset, 0); 781321936Shselasky offset += _marshall64(buf + offset, fabric->from_node->guid); 782321936Shselasky offset += _marshall32(buf + offset, fabric->maxhops_discovered); 783321936Shselasky 784321936Shselasky if (ibnd_write(fd, buf, offset) < 0) 785321936Shselasky return -1; 786321936Shselasky 787321936Shselasky return 0; 788321936Shselasky} 789321936Shselasky 790321936Shselaskystatic int _cache_header_counts(int fd, unsigned int node_count, 791321936Shselasky unsigned int port_count) 792321936Shselasky{ 793321936Shselasky uint8_t buf[IBND_FABRIC_CACHE_BUFLEN]; 794321936Shselasky size_t offset = 0; 795321936Shselasky 796321936Shselasky offset += _marshall32(buf + offset, node_count); 797321936Shselasky offset += _marshall32(buf + offset, port_count); 798321936Shselasky 799321936Shselasky if (lseek(fd, IBND_FABRIC_CACHE_COUNT_OFFSET, SEEK_SET) < 0) { 800321936Shselasky IBND_DEBUG("lseek: %s\n", strerror(errno)); 801321936Shselasky return -1; 802321936Shselasky } 803321936Shselasky 804321936Shselasky if (ibnd_write(fd, buf, offset) < 0) 805321936Shselasky return -1; 806321936Shselasky 807321936Shselasky return 0; 808321936Shselasky} 809321936Shselasky 810321936Shselaskystatic int _cache_node(int fd, ibnd_node_t * node) 811321936Shselasky{ 812321936Shselasky uint8_t buf[IBND_FABRIC_CACHE_BUFLEN]; 813321936Shselasky size_t offset = 0; 814321936Shselasky size_t ports_stored_offset = 0; 815321936Shselasky uint8_t ports_stored_count = 0; 816321936Shselasky int i; 817321936Shselasky 818321936Shselasky offset += _marshall16(buf + offset, node->smalid); 819321936Shselasky offset += _marshall8(buf + offset, node->smalmc); 820321936Shselasky offset += _marshall8(buf + offset, (uint8_t) node->smaenhsp0); 821321936Shselasky offset += _marshall_buf(buf + offset, node->switchinfo, 822321936Shselasky IB_SMP_DATA_SIZE); 823321936Shselasky offset += _marshall64(buf + offset, node->guid); 824321936Shselasky offset += _marshall8(buf + offset, (uint8_t) node->type); 825321936Shselasky offset += _marshall8(buf + offset, (uint8_t) node->numports); 826321936Shselasky offset += _marshall_buf(buf + offset, node->info, IB_SMP_DATA_SIZE); 827321936Shselasky offset += _marshall_buf(buf + offset, node->nodedesc, IB_SMP_DATA_SIZE); 828321936Shselasky /* need to come back later and store number of stored ports 829321936Shselasky * because port entries can be NULL or (in the case of switches) 830321936Shselasky * there is an additional port 0 not accounted for in numports. 831321936Shselasky */ 832321936Shselasky ports_stored_offset = offset; 833321936Shselasky offset += sizeof(uint8_t); 834321936Shselasky 835321936Shselasky for (i = 0; i <= node->numports; i++) { 836321936Shselasky if (node->ports[i]) { 837321936Shselasky offset += _marshall64(buf + offset, 838321936Shselasky node->ports[i]->guid); 839321936Shselasky offset += _marshall8(buf + offset, 840321936Shselasky (uint8_t) node->ports[i]->portnum); 841321936Shselasky ports_stored_count++; 842321936Shselasky } 843321936Shselasky } 844321936Shselasky 845321936Shselasky /* go back and store number of port keys stored */ 846321936Shselasky _marshall8(buf + ports_stored_offset, ports_stored_count); 847321936Shselasky 848321936Shselasky if (ibnd_write(fd, buf, offset) < 0) 849321936Shselasky return -1; 850321936Shselasky 851321936Shselasky return 0; 852321936Shselasky} 853321936Shselasky 854321936Shselaskystatic int _cache_port(int fd, ibnd_port_t * port) 855321936Shselasky{ 856321936Shselasky uint8_t buf[IBND_FABRIC_CACHE_BUFLEN]; 857321936Shselasky size_t offset = 0; 858321936Shselasky 859321936Shselasky offset += _marshall64(buf + offset, port->guid); 860321936Shselasky offset += _marshall8(buf + offset, (uint8_t) port->portnum); 861321936Shselasky offset += _marshall8(buf + offset, (uint8_t) port->ext_portnum); 862321936Shselasky offset += _marshall16(buf + offset, port->base_lid); 863321936Shselasky offset += _marshall8(buf + offset, port->lmc); 864321936Shselasky offset += _marshall_buf(buf + offset, port->info, IB_SMP_DATA_SIZE); 865321936Shselasky offset += _marshall64(buf + offset, port->node->guid); 866321936Shselasky if (port->remoteport) { 867321936Shselasky offset += _marshall8(buf + offset, 1); 868321936Shselasky offset += _marshall64(buf + offset, port->remoteport->guid); 869321936Shselasky offset += _marshall8(buf + offset, (uint8_t) port->remoteport->portnum); 870321936Shselasky } else { 871321936Shselasky offset += _marshall8(buf + offset, 0); 872321936Shselasky offset += _marshall64(buf + offset, 0); 873321936Shselasky offset += _marshall8(buf + offset, 0); 874321936Shselasky } 875321936Shselasky 876321936Shselasky if (ibnd_write(fd, buf, offset) < 0) 877321936Shselasky return -1; 878321936Shselasky 879321936Shselasky return 0; 880321936Shselasky} 881321936Shselasky 882321936Shselaskyint ibnd_cache_fabric(ibnd_fabric_t * fabric, const char *file, 883321936Shselasky unsigned int flags) 884321936Shselasky{ 885321936Shselasky struct stat statbuf; 886321936Shselasky ibnd_node_t *node = NULL; 887321936Shselasky ibnd_node_t *node_next = NULL; 888321936Shselasky unsigned int node_count = 0; 889321936Shselasky ibnd_port_t *port = NULL; 890321936Shselasky ibnd_port_t *port_next = NULL; 891321936Shselasky unsigned int port_count = 0; 892321936Shselasky int fd; 893321936Shselasky int i; 894321936Shselasky 895321936Shselasky if (!fabric) { 896321936Shselasky IBND_DEBUG("fabric parameter NULL\n"); 897321936Shselasky return -1; 898321936Shselasky } 899321936Shselasky 900321936Shselasky if (!file) { 901321936Shselasky IBND_DEBUG("file parameter NULL\n"); 902321936Shselasky return -1; 903321936Shselasky } 904321936Shselasky 905321936Shselasky if (!(flags & IBND_CACHE_FABRIC_FLAG_NO_OVERWRITE)) { 906321936Shselasky if (!stat(file, &statbuf)) { 907321936Shselasky if (unlink(file) < 0) { 908321936Shselasky IBND_DEBUG("error removing '%s': %s\n", 909321936Shselasky file, strerror(errno)); 910321936Shselasky return -1; 911321936Shselasky } 912321936Shselasky } 913321936Shselasky } 914321936Shselasky else { 915321936Shselasky if (!stat(file, &statbuf)) { 916321936Shselasky IBND_DEBUG("file '%s' already exists\n", file); 917321936Shselasky return -1; 918321936Shselasky } 919321936Shselasky } 920321936Shselasky 921321936Shselasky if ((fd = open(file, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) { 922321936Shselasky IBND_DEBUG("open: %s\n", strerror(errno)); 923321936Shselasky return -1; 924321936Shselasky } 925321936Shselasky 926321936Shselasky if (_cache_header_info(fd, fabric) < 0) 927321936Shselasky goto cleanup; 928321936Shselasky 929321936Shselasky node = fabric->nodes; 930321936Shselasky while (node) { 931321936Shselasky node_next = node->next; 932321936Shselasky 933321936Shselasky if (_cache_node(fd, node) < 0) 934321936Shselasky goto cleanup; 935321936Shselasky 936321936Shselasky node_count++; 937321936Shselasky node = node_next; 938321936Shselasky } 939321936Shselasky 940321936Shselasky for (i = 0; i < HTSZ; i++) { 941321936Shselasky port = fabric->portstbl[i]; 942321936Shselasky while (port) { 943321936Shselasky port_next = port->htnext; 944321936Shselasky 945321936Shselasky if (_cache_port(fd, port) < 0) 946321936Shselasky goto cleanup; 947321936Shselasky 948321936Shselasky port_count++; 949321936Shselasky port = port_next; 950321936Shselasky } 951321936Shselasky } 952321936Shselasky 953321936Shselasky if (_cache_header_counts(fd, node_count, port_count) < 0) 954321936Shselasky goto cleanup; 955321936Shselasky 956321936Shselasky if (close(fd) < 0) { 957321936Shselasky IBND_DEBUG("close: %s\n", strerror(errno)); 958321936Shselasky goto cleanup; 959321936Shselasky } 960321936Shselasky 961321936Shselasky return 0; 962321936Shselasky 963321936Shselaskycleanup: 964321936Shselasky unlink(file); 965321936Shselasky close(fd); 966321936Shselasky return -1; 967321936Shselasky} 968