xref: /freebsd/contrib/ofed/libibnetdisc/ibnetdisc_cache.c (revision 87181516ef48be852d5e5fee53c6e0dbfc62f21e)
1*d6b92ffaSHans Petter Selasky /*
2*d6b92ffaSHans Petter Selasky  * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
3*d6b92ffaSHans Petter Selasky  * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
4*d6b92ffaSHans Petter Selasky  * Copyright (c) 2008 Lawrence Livermore National Laboratory
5*d6b92ffaSHans Petter Selasky  *
6*d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
7*d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
8*d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
9*d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
10*d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
11*d6b92ffaSHans Petter Selasky  *
12*d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
13*d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
14*d6b92ffaSHans Petter Selasky  *     conditions are met:
15*d6b92ffaSHans Petter Selasky  *
16*d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
17*d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
18*d6b92ffaSHans Petter Selasky  *        disclaimer.
19*d6b92ffaSHans Petter Selasky  *
20*d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
21*d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
22*d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
23*d6b92ffaSHans Petter Selasky  *        provided with the distribution.
24*d6b92ffaSHans Petter Selasky  *
25*d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26*d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27*d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28*d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29*d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30*d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31*d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32*d6b92ffaSHans Petter Selasky  * SOFTWARE.
33*d6b92ffaSHans Petter Selasky  *
34*d6b92ffaSHans Petter Selasky  */
35*d6b92ffaSHans Petter Selasky 
36*d6b92ffaSHans Petter Selasky #if HAVE_CONFIG_H
37*d6b92ffaSHans Petter Selasky #include <config.h>
38*d6b92ffaSHans Petter Selasky #endif				/* HAVE_CONFIG_H */
39*d6b92ffaSHans Petter Selasky 
40*d6b92ffaSHans Petter Selasky #define _GNU_SOURCE
41*d6b92ffaSHans Petter Selasky #include <stdio.h>
42*d6b92ffaSHans Petter Selasky #include <stdlib.h>
43*d6b92ffaSHans Petter Selasky #include <sys/types.h>
44*d6b92ffaSHans Petter Selasky #include <sys/stat.h>
45*d6b92ffaSHans Petter Selasky #include <unistd.h>
46*d6b92ffaSHans Petter Selasky #include <fcntl.h>
47*d6b92ffaSHans Petter Selasky #include <string.h>
48*d6b92ffaSHans Petter Selasky #include <errno.h>
49*d6b92ffaSHans Petter Selasky #include <inttypes.h>
50*d6b92ffaSHans Petter Selasky 
51*d6b92ffaSHans Petter Selasky #include <infiniband/ibnetdisc.h>
52*d6b92ffaSHans Petter Selasky 
53*d6b92ffaSHans Petter Selasky #include "internal.h"
54*d6b92ffaSHans Petter Selasky #include "chassis.h"
55*d6b92ffaSHans Petter Selasky 
56*d6b92ffaSHans Petter Selasky /* For this caching lib, we always cache little endian */
57*d6b92ffaSHans Petter Selasky 
58*d6b92ffaSHans Petter Selasky /* Cache format
59*d6b92ffaSHans Petter Selasky  *
60*d6b92ffaSHans Petter Selasky  * Bytes 1-4 - magic number
61*d6b92ffaSHans Petter Selasky  * Bytes 5-8 - version number
62*d6b92ffaSHans Petter Selasky  * Bytes 9-12 - node count
63*d6b92ffaSHans Petter Selasky  * Bytes 13-16 - port count
64*d6b92ffaSHans Petter Selasky  * Bytes 17-24 - "from node" guid
65*d6b92ffaSHans Petter Selasky  * Bytes 25-28 - maxhops discovered
66*d6b92ffaSHans Petter Selasky  * Bytes X-Y - nodes (variable length)
67*d6b92ffaSHans Petter Selasky  * Bytes X-Y - ports (variable length)
68*d6b92ffaSHans Petter Selasky  *
69*d6b92ffaSHans Petter Selasky  * Nodes are cached as
70*d6b92ffaSHans Petter Selasky  *
71*d6b92ffaSHans Petter Selasky  * 2 bytes - smalid
72*d6b92ffaSHans Petter Selasky  * 1 byte - smalmc
73*d6b92ffaSHans Petter Selasky  * 1 byte - smaenhsp0 flag
74*d6b92ffaSHans Petter Selasky  * IB_SMP_DATA_SIZE bytes - switchinfo
75*d6b92ffaSHans Petter Selasky  * 8 bytes - guid
76*d6b92ffaSHans Petter Selasky  * 1 byte - type
77*d6b92ffaSHans Petter Selasky  * 1 byte - numports
78*d6b92ffaSHans Petter Selasky  * IB_SMP_DATA_SIZE bytes - info
79*d6b92ffaSHans Petter Selasky  * IB_SMP_DATA_SIZE bytes - nodedesc
80*d6b92ffaSHans Petter Selasky  * 1 byte - number of ports stored
81*d6b92ffaSHans Petter Selasky  * 8 bytes - portguid A
82*d6b92ffaSHans Petter Selasky  * 1 byte - port num A
83*d6b92ffaSHans Petter Selasky  * 8 bytes - portguid B
84*d6b92ffaSHans Petter Selasky  * 1 byte - port num B
85*d6b92ffaSHans Petter Selasky  * ... etc., depending on number of ports stored
86*d6b92ffaSHans Petter Selasky  *
87*d6b92ffaSHans Petter Selasky  * Ports are cached as
88*d6b92ffaSHans Petter Selasky  *
89*d6b92ffaSHans Petter Selasky  * 8 bytes - guid
90*d6b92ffaSHans Petter Selasky  * 1 byte - portnum
91*d6b92ffaSHans Petter Selasky  * 1 byte - external portnum
92*d6b92ffaSHans Petter Selasky  * 2 bytes - base lid
93*d6b92ffaSHans Petter Selasky  * 1 byte - lmc
94*d6b92ffaSHans Petter Selasky  * IB_SMP_DATA_SIZE bytes - info
95*d6b92ffaSHans Petter Selasky  * 8 bytes - node guid port "owned" by
96*d6b92ffaSHans Petter Selasky  * 1 byte - flag indicating if remote port exists
97*d6b92ffaSHans Petter Selasky  * 8 bytes - port guid remotely connected to
98*d6b92ffaSHans Petter Selasky  * 1 byte - port num remotely connected to
99*d6b92ffaSHans Petter Selasky  */
100*d6b92ffaSHans Petter Selasky 
101*d6b92ffaSHans Petter Selasky /* Structs that hold cache info temporarily before
102*d6b92ffaSHans Petter Selasky  * the real structs can be reconstructed.
103*d6b92ffaSHans Petter Selasky  */
104*d6b92ffaSHans Petter Selasky 
105*d6b92ffaSHans Petter Selasky typedef struct ibnd_port_cache_key {
106*d6b92ffaSHans Petter Selasky 	uint64_t guid;
107*d6b92ffaSHans Petter Selasky 	uint8_t portnum;
108*d6b92ffaSHans Petter Selasky } ibnd_port_cache_key_t;
109*d6b92ffaSHans Petter Selasky 
110*d6b92ffaSHans Petter Selasky typedef struct ibnd_node_cache {
111*d6b92ffaSHans Petter Selasky 	ibnd_node_t *node;
112*d6b92ffaSHans Petter Selasky 	uint8_t ports_stored_count;
113*d6b92ffaSHans Petter Selasky 	ibnd_port_cache_key_t *port_cache_keys;
114*d6b92ffaSHans Petter Selasky 	struct ibnd_node_cache *next;
115*d6b92ffaSHans Petter Selasky 	struct ibnd_node_cache *htnext;
116*d6b92ffaSHans Petter Selasky 	int node_stored_to_fabric;
117*d6b92ffaSHans Petter Selasky } ibnd_node_cache_t;
118*d6b92ffaSHans Petter Selasky 
119*d6b92ffaSHans Petter Selasky typedef struct ibnd_port_cache {
120*d6b92ffaSHans Petter Selasky 	ibnd_port_t *port;
121*d6b92ffaSHans Petter Selasky 	uint64_t node_guid;
122*d6b92ffaSHans Petter Selasky 	uint8_t remoteport_flag;
123*d6b92ffaSHans Petter Selasky 	ibnd_port_cache_key_t remoteport_cache_key;
124*d6b92ffaSHans Petter Selasky 	struct ibnd_port_cache *next;
125*d6b92ffaSHans Petter Selasky 	struct ibnd_port_cache *htnext;
126*d6b92ffaSHans Petter Selasky 	int port_stored_to_fabric;
127*d6b92ffaSHans Petter Selasky } ibnd_port_cache_t;
128*d6b92ffaSHans Petter Selasky 
129*d6b92ffaSHans Petter Selasky typedef struct ibnd_fabric_cache {
130*d6b92ffaSHans Petter Selasky 	f_internal_t *f_int;
131*d6b92ffaSHans Petter Selasky 	uint64_t from_node_guid;
132*d6b92ffaSHans Petter Selasky 	ibnd_node_cache_t *nodes_cache;
133*d6b92ffaSHans Petter Selasky 	ibnd_port_cache_t *ports_cache;
134*d6b92ffaSHans Petter Selasky 	ibnd_node_cache_t *nodescachetbl[HTSZ];
135*d6b92ffaSHans Petter Selasky 	ibnd_port_cache_t *portscachetbl[HTSZ];
136*d6b92ffaSHans Petter Selasky } ibnd_fabric_cache_t;
137*d6b92ffaSHans Petter Selasky 
138*d6b92ffaSHans Petter Selasky #define IBND_FABRIC_CACHE_BUFLEN  4096
139*d6b92ffaSHans Petter Selasky #define IBND_FABRIC_CACHE_MAGIC   0x8FE7832B
140*d6b92ffaSHans Petter Selasky #define IBND_FABRIC_CACHE_VERSION 0x00000001
141*d6b92ffaSHans Petter Selasky 
142*d6b92ffaSHans Petter Selasky #define IBND_FABRIC_CACHE_COUNT_OFFSET 8
143*d6b92ffaSHans Petter Selasky 
144*d6b92ffaSHans Petter Selasky #define IBND_FABRIC_CACHE_HEADER_LEN   (28)
145*d6b92ffaSHans Petter Selasky #define IBND_NODE_CACHE_HEADER_LEN     (15 + IB_SMP_DATA_SIZE*3)
146*d6b92ffaSHans Petter Selasky #define IBND_PORT_CACHE_KEY_LEN        (8 + 1)
147*d6b92ffaSHans Petter Selasky #define IBND_PORT_CACHE_LEN            (31 + IB_SMP_DATA_SIZE)
148*d6b92ffaSHans Petter Selasky 
ibnd_read(int fd,void * buf,size_t count)149*d6b92ffaSHans Petter Selasky static ssize_t ibnd_read(int fd, void *buf, size_t count)
150*d6b92ffaSHans Petter Selasky {
151*d6b92ffaSHans Petter Selasky 	size_t count_done = 0;
152*d6b92ffaSHans Petter Selasky 	ssize_t ret;
153*d6b92ffaSHans Petter Selasky 
154*d6b92ffaSHans Petter Selasky 	while ((count - count_done) > 0) {
155*d6b92ffaSHans Petter Selasky 		ret = read(fd, ((char *) buf) + count_done, count - count_done);
156*d6b92ffaSHans Petter Selasky 		if (ret < 0) {
157*d6b92ffaSHans Petter Selasky 			if (errno == EINTR)
158*d6b92ffaSHans Petter Selasky 				continue;
159*d6b92ffaSHans Petter Selasky 			else {
160*d6b92ffaSHans Petter Selasky 				IBND_DEBUG("read: %s\n", strerror(errno));
161*d6b92ffaSHans Petter Selasky 				return -1;
162*d6b92ffaSHans Petter Selasky 			}
163*d6b92ffaSHans Petter Selasky 		}
164*d6b92ffaSHans Petter Selasky 		if (!ret)
165*d6b92ffaSHans Petter Selasky 			break;
166*d6b92ffaSHans Petter Selasky 		count_done += ret;
167*d6b92ffaSHans Petter Selasky 	}
168*d6b92ffaSHans Petter Selasky 
169*d6b92ffaSHans Petter Selasky 	if (count_done != count) {
170*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("read: read short\n");
171*d6b92ffaSHans Petter Selasky 		return -1;
172*d6b92ffaSHans Petter Selasky 	}
173*d6b92ffaSHans Petter Selasky 
174*d6b92ffaSHans Petter Selasky 	return count_done;
175*d6b92ffaSHans Petter Selasky }
176*d6b92ffaSHans Petter Selasky 
_unmarshall8(uint8_t * inbuf,uint8_t * num)177*d6b92ffaSHans Petter Selasky static size_t _unmarshall8(uint8_t * inbuf, uint8_t * num)
178*d6b92ffaSHans Petter Selasky {
179*d6b92ffaSHans Petter Selasky 	(*num) = inbuf[0];
180*d6b92ffaSHans Petter Selasky 
181*d6b92ffaSHans Petter Selasky 	return (sizeof(*num));
182*d6b92ffaSHans Petter Selasky }
183*d6b92ffaSHans Petter Selasky 
_unmarshall16(uint8_t * inbuf,uint16_t * num)184*d6b92ffaSHans Petter Selasky static size_t _unmarshall16(uint8_t * inbuf, uint16_t * num)
185*d6b92ffaSHans Petter Selasky {
186*d6b92ffaSHans Petter Selasky 	(*num) = ((uint16_t) inbuf[1] << 8) | inbuf[0];
187*d6b92ffaSHans Petter Selasky 
188*d6b92ffaSHans Petter Selasky 	return (sizeof(*num));
189*d6b92ffaSHans Petter Selasky }
190*d6b92ffaSHans Petter Selasky 
_unmarshall32(uint8_t * inbuf,uint32_t * num)191*d6b92ffaSHans Petter Selasky static size_t _unmarshall32(uint8_t * inbuf, uint32_t * num)
192*d6b92ffaSHans Petter Selasky {
193*d6b92ffaSHans Petter Selasky 	(*num) = (uint32_t) inbuf[0];
194*d6b92ffaSHans Petter Selasky 	(*num) |= ((uint32_t) inbuf[1] << 8);
195*d6b92ffaSHans Petter Selasky 	(*num) |= ((uint32_t) inbuf[2] << 16);
196*d6b92ffaSHans Petter Selasky 	(*num) |= ((uint32_t) inbuf[3] << 24);
197*d6b92ffaSHans Petter Selasky 
198*d6b92ffaSHans Petter Selasky 	return (sizeof(*num));
199*d6b92ffaSHans Petter Selasky }
200*d6b92ffaSHans Petter Selasky 
_unmarshall64(uint8_t * inbuf,uint64_t * num)201*d6b92ffaSHans Petter Selasky static size_t _unmarshall64(uint8_t * inbuf, uint64_t * num)
202*d6b92ffaSHans Petter Selasky {
203*d6b92ffaSHans Petter Selasky 	(*num) = (uint64_t) inbuf[0];
204*d6b92ffaSHans Petter Selasky 	(*num) |= ((uint64_t) inbuf[1] << 8);
205*d6b92ffaSHans Petter Selasky 	(*num) |= ((uint64_t) inbuf[2] << 16);
206*d6b92ffaSHans Petter Selasky 	(*num) |= ((uint64_t) inbuf[3] << 24);
207*d6b92ffaSHans Petter Selasky 	(*num) |= ((uint64_t) inbuf[4] << 32);
208*d6b92ffaSHans Petter Selasky 	(*num) |= ((uint64_t) inbuf[5] << 40);
209*d6b92ffaSHans Petter Selasky 	(*num) |= ((uint64_t) inbuf[6] << 48);
210*d6b92ffaSHans Petter Selasky 	(*num) |= ((uint64_t) inbuf[7] << 56);
211*d6b92ffaSHans Petter Selasky 
212*d6b92ffaSHans Petter Selasky 	return (sizeof(*num));
213*d6b92ffaSHans Petter Selasky }
214*d6b92ffaSHans Petter Selasky 
_unmarshall_buf(const void * inbuf,void * outbuf,unsigned int len)215*d6b92ffaSHans Petter Selasky static size_t _unmarshall_buf(const void *inbuf, void *outbuf, unsigned int len)
216*d6b92ffaSHans Petter Selasky {
217*d6b92ffaSHans Petter Selasky 	memcpy(outbuf, inbuf, len);
218*d6b92ffaSHans Petter Selasky 
219*d6b92ffaSHans Petter Selasky 	return len;
220*d6b92ffaSHans Petter Selasky }
221*d6b92ffaSHans Petter Selasky 
_load_header_info(int fd,ibnd_fabric_cache_t * fabric_cache,unsigned int * node_count,unsigned int * port_count)222*d6b92ffaSHans Petter Selasky static int _load_header_info(int fd, ibnd_fabric_cache_t * fabric_cache,
223*d6b92ffaSHans Petter Selasky 			     unsigned int *node_count, unsigned int *port_count)
224*d6b92ffaSHans Petter Selasky {
225*d6b92ffaSHans Petter Selasky 	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
226*d6b92ffaSHans Petter Selasky 	uint32_t magic = 0;
227*d6b92ffaSHans Petter Selasky 	uint32_t version = 0;
228*d6b92ffaSHans Petter Selasky 	size_t offset = 0;
229*d6b92ffaSHans Petter Selasky 	uint32_t tmp32;
230*d6b92ffaSHans Petter Selasky 
231*d6b92ffaSHans Petter Selasky 	if (ibnd_read(fd, buf, IBND_FABRIC_CACHE_HEADER_LEN) < 0)
232*d6b92ffaSHans Petter Selasky 		return -1;
233*d6b92ffaSHans Petter Selasky 
234*d6b92ffaSHans Petter Selasky 	offset += _unmarshall32(buf + offset, &magic);
235*d6b92ffaSHans Petter Selasky 
236*d6b92ffaSHans Petter Selasky 	if (magic != IBND_FABRIC_CACHE_MAGIC) {
237*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("invalid fabric cache file\n");
238*d6b92ffaSHans Petter Selasky 		return -1;
239*d6b92ffaSHans Petter Selasky 	}
240*d6b92ffaSHans Petter Selasky 
241*d6b92ffaSHans Petter Selasky 	offset += _unmarshall32(buf + offset, &version);
242*d6b92ffaSHans Petter Selasky 
243*d6b92ffaSHans Petter Selasky 	if (version != IBND_FABRIC_CACHE_VERSION) {
244*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("invalid fabric cache version\n");
245*d6b92ffaSHans Petter Selasky 		return -1;
246*d6b92ffaSHans Petter Selasky 	}
247*d6b92ffaSHans Petter Selasky 
248*d6b92ffaSHans Petter Selasky 	offset += _unmarshall32(buf + offset, node_count);
249*d6b92ffaSHans Petter Selasky 	offset += _unmarshall32(buf + offset, port_count);
250*d6b92ffaSHans Petter Selasky 
251*d6b92ffaSHans Petter Selasky 	offset += _unmarshall64(buf + offset, &fabric_cache->from_node_guid);
252*d6b92ffaSHans Petter Selasky 	offset += _unmarshall32(buf + offset, &tmp32);
253*d6b92ffaSHans Petter Selasky 	fabric_cache->f_int->fabric.maxhops_discovered = tmp32;
254*d6b92ffaSHans Petter Selasky 
255*d6b92ffaSHans Petter Selasky 	return 0;
256*d6b92ffaSHans Petter Selasky }
257*d6b92ffaSHans Petter Selasky 
_destroy_ibnd_node_cache(ibnd_node_cache_t * node_cache)258*d6b92ffaSHans Petter Selasky static void _destroy_ibnd_node_cache(ibnd_node_cache_t * node_cache)
259*d6b92ffaSHans Petter Selasky {
260*d6b92ffaSHans Petter Selasky 	free(node_cache->port_cache_keys);
261*d6b92ffaSHans Petter Selasky 	if (!node_cache->node_stored_to_fabric && node_cache->node)
262*d6b92ffaSHans Petter Selasky 		destroy_node(node_cache->node);
263*d6b92ffaSHans Petter Selasky 	free(node_cache);
264*d6b92ffaSHans Petter Selasky }
265*d6b92ffaSHans Petter Selasky 
_destroy_ibnd_fabric_cache(ibnd_fabric_cache_t * fabric_cache)266*d6b92ffaSHans Petter Selasky static void _destroy_ibnd_fabric_cache(ibnd_fabric_cache_t * fabric_cache)
267*d6b92ffaSHans Petter Selasky {
268*d6b92ffaSHans Petter Selasky 	ibnd_node_cache_t *node_cache;
269*d6b92ffaSHans Petter Selasky 	ibnd_node_cache_t *node_cache_next;
270*d6b92ffaSHans Petter Selasky 	ibnd_port_cache_t *port_cache;
271*d6b92ffaSHans Petter Selasky 	ibnd_port_cache_t *port_cache_next;
272*d6b92ffaSHans Petter Selasky 
273*d6b92ffaSHans Petter Selasky 	if (!fabric_cache)
274*d6b92ffaSHans Petter Selasky 		return;
275*d6b92ffaSHans Petter Selasky 
276*d6b92ffaSHans Petter Selasky 	node_cache = fabric_cache->nodes_cache;
277*d6b92ffaSHans Petter Selasky 	while (node_cache) {
278*d6b92ffaSHans Petter Selasky 		node_cache_next = node_cache->next;
279*d6b92ffaSHans Petter Selasky 
280*d6b92ffaSHans Petter Selasky 		_destroy_ibnd_node_cache(node_cache);
281*d6b92ffaSHans Petter Selasky 
282*d6b92ffaSHans Petter Selasky 		node_cache = node_cache_next;
283*d6b92ffaSHans Petter Selasky 	}
284*d6b92ffaSHans Petter Selasky 
285*d6b92ffaSHans Petter Selasky 	port_cache = fabric_cache->ports_cache;
286*d6b92ffaSHans Petter Selasky 	while (port_cache) {
287*d6b92ffaSHans Petter Selasky 		port_cache_next = port_cache->next;
288*d6b92ffaSHans Petter Selasky 
289*d6b92ffaSHans Petter Selasky 		if (!port_cache->port_stored_to_fabric && port_cache->port)
290*d6b92ffaSHans Petter Selasky 			free(port_cache->port);
291*d6b92ffaSHans Petter Selasky 		free(port_cache);
292*d6b92ffaSHans Petter Selasky 
293*d6b92ffaSHans Petter Selasky 		port_cache = port_cache_next;
294*d6b92ffaSHans Petter Selasky 	}
295*d6b92ffaSHans Petter Selasky 
296*d6b92ffaSHans Petter Selasky 	free(fabric_cache);
297*d6b92ffaSHans Petter Selasky }
298*d6b92ffaSHans Petter Selasky 
store_node_cache(ibnd_node_cache_t * node_cache,ibnd_fabric_cache_t * fabric_cache)299*d6b92ffaSHans Petter Selasky static void store_node_cache(ibnd_node_cache_t * node_cache,
300*d6b92ffaSHans Petter Selasky 			     ibnd_fabric_cache_t * fabric_cache)
301*d6b92ffaSHans Petter Selasky {
302*d6b92ffaSHans Petter Selasky 	int hash_indx = HASHGUID(node_cache->node->guid) % HTSZ;
303*d6b92ffaSHans Petter Selasky 
304*d6b92ffaSHans Petter Selasky 	node_cache->next = fabric_cache->nodes_cache;
305*d6b92ffaSHans Petter Selasky 	fabric_cache->nodes_cache = node_cache;
306*d6b92ffaSHans Petter Selasky 
307*d6b92ffaSHans Petter Selasky 	node_cache->htnext = fabric_cache->nodescachetbl[hash_indx];
308*d6b92ffaSHans Petter Selasky 	fabric_cache->nodescachetbl[hash_indx] = node_cache;
309*d6b92ffaSHans Petter Selasky }
310*d6b92ffaSHans Petter Selasky 
_load_node(int fd,ibnd_fabric_cache_t * fabric_cache)311*d6b92ffaSHans Petter Selasky static int _load_node(int fd, ibnd_fabric_cache_t * fabric_cache)
312*d6b92ffaSHans Petter Selasky {
313*d6b92ffaSHans Petter Selasky 	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
314*d6b92ffaSHans Petter Selasky 	ibnd_node_cache_t *node_cache = NULL;
315*d6b92ffaSHans Petter Selasky 	ibnd_node_t *node = NULL;
316*d6b92ffaSHans Petter Selasky 	size_t offset = 0;
317*d6b92ffaSHans Petter Selasky 	uint8_t tmp8;
318*d6b92ffaSHans Petter Selasky 
319*d6b92ffaSHans Petter Selasky 	node_cache = (ibnd_node_cache_t *) malloc(sizeof(ibnd_node_cache_t));
320*d6b92ffaSHans Petter Selasky 	if (!node_cache) {
321*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("OOM: node_cache\n");
322*d6b92ffaSHans Petter Selasky 		return -1;
323*d6b92ffaSHans Petter Selasky 	}
324*d6b92ffaSHans Petter Selasky 	memset(node_cache, '\0', sizeof(ibnd_node_cache_t));
325*d6b92ffaSHans Petter Selasky 
326*d6b92ffaSHans Petter Selasky 	node = (ibnd_node_t *) malloc(sizeof(ibnd_node_t));
327*d6b92ffaSHans Petter Selasky 	if (!node) {
328*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("OOM: node\n");
329*d6b92ffaSHans Petter Selasky 		free(node_cache);
330*d6b92ffaSHans Petter Selasky 		return -1;
331*d6b92ffaSHans Petter Selasky 	}
332*d6b92ffaSHans Petter Selasky 	memset(node, '\0', sizeof(ibnd_node_t));
333*d6b92ffaSHans Petter Selasky 
334*d6b92ffaSHans Petter Selasky 	node_cache->node = node;
335*d6b92ffaSHans Petter Selasky 
336*d6b92ffaSHans Petter Selasky 	if (ibnd_read(fd, buf, IBND_NODE_CACHE_HEADER_LEN) < 0)
337*d6b92ffaSHans Petter Selasky 		goto cleanup;
338*d6b92ffaSHans Petter Selasky 
339*d6b92ffaSHans Petter Selasky 	offset += _unmarshall16(buf + offset, &node->smalid);
340*d6b92ffaSHans Petter Selasky 	offset += _unmarshall8(buf + offset, &node->smalmc);
341*d6b92ffaSHans Petter Selasky 	offset += _unmarshall8(buf + offset, &tmp8);
342*d6b92ffaSHans Petter Selasky 	node->smaenhsp0 = tmp8;
343*d6b92ffaSHans Petter Selasky 	offset += _unmarshall_buf(buf + offset, node->switchinfo,
344*d6b92ffaSHans Petter Selasky 				  IB_SMP_DATA_SIZE);
345*d6b92ffaSHans Petter Selasky 	offset += _unmarshall64(buf + offset, &node->guid);
346*d6b92ffaSHans Petter Selasky 	offset += _unmarshall8(buf + offset, &tmp8);
347*d6b92ffaSHans Petter Selasky 	node->type = tmp8;
348*d6b92ffaSHans Petter Selasky 	offset += _unmarshall8(buf + offset, &tmp8);
349*d6b92ffaSHans Petter Selasky 	node->numports = tmp8;
350*d6b92ffaSHans Petter Selasky 	offset += _unmarshall_buf(buf + offset, node->info, IB_SMP_DATA_SIZE);
351*d6b92ffaSHans Petter Selasky 	offset += _unmarshall_buf(buf + offset, node->nodedesc,
352*d6b92ffaSHans Petter Selasky 				  IB_SMP_DATA_SIZE);
353*d6b92ffaSHans Petter Selasky 
354*d6b92ffaSHans Petter Selasky 	offset += _unmarshall8(buf + offset, &node_cache->ports_stored_count);
355*d6b92ffaSHans Petter Selasky 
356*d6b92ffaSHans Petter Selasky 	if (node_cache->ports_stored_count) {
357*d6b92ffaSHans Petter Selasky 		unsigned int tomalloc = 0;
358*d6b92ffaSHans Petter Selasky 		unsigned int toread = 0;
359*d6b92ffaSHans Petter Selasky 		unsigned int i;
360*d6b92ffaSHans Petter Selasky 
361*d6b92ffaSHans Petter Selasky 		tomalloc =
362*d6b92ffaSHans Petter Selasky 		    sizeof(ibnd_port_cache_key_t) *
363*d6b92ffaSHans Petter Selasky 		    node_cache->ports_stored_count;
364*d6b92ffaSHans Petter Selasky 
365*d6b92ffaSHans Petter Selasky 		toread =
366*d6b92ffaSHans Petter Selasky 		    IBND_PORT_CACHE_KEY_LEN * node_cache->ports_stored_count;
367*d6b92ffaSHans Petter Selasky 
368*d6b92ffaSHans Petter Selasky 		node_cache->port_cache_keys =
369*d6b92ffaSHans Petter Selasky 		    (ibnd_port_cache_key_t *) malloc(tomalloc);
370*d6b92ffaSHans Petter Selasky 		if (!node_cache->port_cache_keys) {
371*d6b92ffaSHans Petter Selasky 			IBND_DEBUG("OOM: node_cache port_cache_keys\n");
372*d6b92ffaSHans Petter Selasky 			goto cleanup;
373*d6b92ffaSHans Petter Selasky 		}
374*d6b92ffaSHans Petter Selasky 
375*d6b92ffaSHans Petter Selasky 		if (ibnd_read(fd, buf, toread) < 0)
376*d6b92ffaSHans Petter Selasky 			goto cleanup;
377*d6b92ffaSHans Petter Selasky 
378*d6b92ffaSHans Petter Selasky 		offset = 0;
379*d6b92ffaSHans Petter Selasky 
380*d6b92ffaSHans Petter Selasky 		for (i = 0; i < node_cache->ports_stored_count; i++) {
381*d6b92ffaSHans Petter Selasky 			offset +=
382*d6b92ffaSHans Petter Selasky 			    _unmarshall64(buf + offset,
383*d6b92ffaSHans Petter Selasky 					  &node_cache->port_cache_keys[i].guid);
384*d6b92ffaSHans Petter Selasky 			offset +=
385*d6b92ffaSHans Petter Selasky 			    _unmarshall8(buf + offset,
386*d6b92ffaSHans Petter Selasky 					 &node_cache->
387*d6b92ffaSHans Petter Selasky 					 port_cache_keys[i].portnum);
388*d6b92ffaSHans Petter Selasky 		}
389*d6b92ffaSHans Petter Selasky 	}
390*d6b92ffaSHans Petter Selasky 
391*d6b92ffaSHans Petter Selasky 	store_node_cache(node_cache, fabric_cache);
392*d6b92ffaSHans Petter Selasky 
393*d6b92ffaSHans Petter Selasky 	return 0;
394*d6b92ffaSHans Petter Selasky 
395*d6b92ffaSHans Petter Selasky cleanup:
396*d6b92ffaSHans Petter Selasky 	_destroy_ibnd_node_cache(node_cache);
397*d6b92ffaSHans Petter Selasky 	return -1;
398*d6b92ffaSHans Petter Selasky }
399*d6b92ffaSHans Petter Selasky 
store_port_cache(ibnd_port_cache_t * port_cache,ibnd_fabric_cache_t * fabric_cache)400*d6b92ffaSHans Petter Selasky static void store_port_cache(ibnd_port_cache_t * port_cache,
401*d6b92ffaSHans Petter Selasky 			     ibnd_fabric_cache_t * fabric_cache)
402*d6b92ffaSHans Petter Selasky {
403*d6b92ffaSHans Petter Selasky 	int hash_indx = HASHGUID(port_cache->port->guid) % HTSZ;
404*d6b92ffaSHans Petter Selasky 
405*d6b92ffaSHans Petter Selasky 	port_cache->next = fabric_cache->ports_cache;
406*d6b92ffaSHans Petter Selasky 	fabric_cache->ports_cache = port_cache;
407*d6b92ffaSHans Petter Selasky 
408*d6b92ffaSHans Petter Selasky 	port_cache->htnext = fabric_cache->portscachetbl[hash_indx];
409*d6b92ffaSHans Petter Selasky 	fabric_cache->portscachetbl[hash_indx] = port_cache;
410*d6b92ffaSHans Petter Selasky }
411*d6b92ffaSHans Petter Selasky 
_load_port(int fd,ibnd_fabric_cache_t * fabric_cache)412*d6b92ffaSHans Petter Selasky static int _load_port(int fd, ibnd_fabric_cache_t * fabric_cache)
413*d6b92ffaSHans Petter Selasky {
414*d6b92ffaSHans Petter Selasky 	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
415*d6b92ffaSHans Petter Selasky 	ibnd_port_cache_t *port_cache = NULL;
416*d6b92ffaSHans Petter Selasky 	ibnd_port_t *port = NULL;
417*d6b92ffaSHans Petter Selasky 	size_t offset = 0;
418*d6b92ffaSHans Petter Selasky 	uint8_t tmp8;
419*d6b92ffaSHans Petter Selasky 
420*d6b92ffaSHans Petter Selasky 	port_cache = (ibnd_port_cache_t *) malloc(sizeof(ibnd_port_cache_t));
421*d6b92ffaSHans Petter Selasky 	if (!port_cache) {
422*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("OOM: port_cache\n");
423*d6b92ffaSHans Petter Selasky 		return -1;
424*d6b92ffaSHans Petter Selasky 	}
425*d6b92ffaSHans Petter Selasky 	memset(port_cache, '\0', sizeof(ibnd_port_cache_t));
426*d6b92ffaSHans Petter Selasky 
427*d6b92ffaSHans Petter Selasky 	port = (ibnd_port_t *) malloc(sizeof(ibnd_port_t));
428*d6b92ffaSHans Petter Selasky 	if (!port) {
429*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("OOM: port\n");
430*d6b92ffaSHans Petter Selasky 		free(port_cache);
431*d6b92ffaSHans Petter Selasky 		return -1;
432*d6b92ffaSHans Petter Selasky 	}
433*d6b92ffaSHans Petter Selasky 	memset(port, '\0', sizeof(ibnd_port_t));
434*d6b92ffaSHans Petter Selasky 
435*d6b92ffaSHans Petter Selasky 	port_cache->port = port;
436*d6b92ffaSHans Petter Selasky 
437*d6b92ffaSHans Petter Selasky 	if (ibnd_read(fd, buf, IBND_PORT_CACHE_LEN) < 0)
438*d6b92ffaSHans Petter Selasky 		goto cleanup;
439*d6b92ffaSHans Petter Selasky 
440*d6b92ffaSHans Petter Selasky 	offset += _unmarshall64(buf + offset, &port->guid);
441*d6b92ffaSHans Petter Selasky 	offset += _unmarshall8(buf + offset, &tmp8);
442*d6b92ffaSHans Petter Selasky 	port->portnum = tmp8;
443*d6b92ffaSHans Petter Selasky 	offset += _unmarshall8(buf + offset, &tmp8);
444*d6b92ffaSHans Petter Selasky 	port->ext_portnum = tmp8;
445*d6b92ffaSHans Petter Selasky 	offset += _unmarshall16(buf + offset, &port->base_lid);
446*d6b92ffaSHans Petter Selasky 	offset += _unmarshall8(buf + offset, &port->lmc);
447*d6b92ffaSHans Petter Selasky 	offset += _unmarshall_buf(buf + offset, port->info, IB_SMP_DATA_SIZE);
448*d6b92ffaSHans Petter Selasky 	offset += _unmarshall64(buf + offset, &port_cache->node_guid);
449*d6b92ffaSHans Petter Selasky 	offset += _unmarshall8(buf + offset, &port_cache->remoteport_flag);
450*d6b92ffaSHans Petter Selasky 	offset +=
451*d6b92ffaSHans Petter Selasky 	    _unmarshall64(buf + offset, &port_cache->remoteport_cache_key.guid);
452*d6b92ffaSHans Petter Selasky 	offset +=
453*d6b92ffaSHans Petter Selasky 	    _unmarshall8(buf + offset,
454*d6b92ffaSHans Petter Selasky 			 &port_cache->remoteport_cache_key.portnum);
455*d6b92ffaSHans Petter Selasky 
456*d6b92ffaSHans Petter Selasky 	store_port_cache(port_cache, fabric_cache);
457*d6b92ffaSHans Petter Selasky 
458*d6b92ffaSHans Petter Selasky 	return 0;
459*d6b92ffaSHans Petter Selasky 
460*d6b92ffaSHans Petter Selasky cleanup:
461*d6b92ffaSHans Petter Selasky 	free(port);
462*d6b92ffaSHans Petter Selasky 	free(port_cache);
463*d6b92ffaSHans Petter Selasky 	return -1;
464*d6b92ffaSHans Petter Selasky }
465*d6b92ffaSHans Petter Selasky 
_find_port(ibnd_fabric_cache_t * fabric_cache,ibnd_port_cache_key_t * port_cache_key)466*d6b92ffaSHans Petter Selasky static ibnd_port_cache_t *_find_port(ibnd_fabric_cache_t * fabric_cache,
467*d6b92ffaSHans Petter Selasky 				     ibnd_port_cache_key_t * port_cache_key)
468*d6b92ffaSHans Petter Selasky {
469*d6b92ffaSHans Petter Selasky 	int hash_indx = HASHGUID(port_cache_key->guid) % HTSZ;
470*d6b92ffaSHans Petter Selasky 	ibnd_port_cache_t *port_cache;
471*d6b92ffaSHans Petter Selasky 
472*d6b92ffaSHans Petter Selasky 	for (port_cache = fabric_cache->portscachetbl[hash_indx];
473*d6b92ffaSHans Petter Selasky 	     port_cache; port_cache = port_cache->htnext) {
474*d6b92ffaSHans Petter Selasky 		if (port_cache->port->guid == port_cache_key->guid
475*d6b92ffaSHans Petter Selasky 		    && port_cache->port->portnum == port_cache_key->portnum)
476*d6b92ffaSHans Petter Selasky 			return port_cache;
477*d6b92ffaSHans Petter Selasky 	}
478*d6b92ffaSHans Petter Selasky 
479*d6b92ffaSHans Petter Selasky 	return NULL;
480*d6b92ffaSHans Petter Selasky }
481*d6b92ffaSHans Petter Selasky 
_find_node(ibnd_fabric_cache_t * fabric_cache,uint64_t guid)482*d6b92ffaSHans Petter Selasky static ibnd_node_cache_t *_find_node(ibnd_fabric_cache_t * fabric_cache,
483*d6b92ffaSHans Petter Selasky 				     uint64_t guid)
484*d6b92ffaSHans Petter Selasky {
485*d6b92ffaSHans Petter Selasky 	int hash_indx = HASHGUID(guid) % HTSZ;
486*d6b92ffaSHans Petter Selasky 	ibnd_node_cache_t *node_cache;
487*d6b92ffaSHans Petter Selasky 
488*d6b92ffaSHans Petter Selasky 	for (node_cache = fabric_cache->nodescachetbl[hash_indx];
489*d6b92ffaSHans Petter Selasky 	     node_cache; node_cache = node_cache->htnext) {
490*d6b92ffaSHans Petter Selasky 		if (node_cache->node->guid == guid)
491*d6b92ffaSHans Petter Selasky 			return node_cache;
492*d6b92ffaSHans Petter Selasky 	}
493*d6b92ffaSHans Petter Selasky 
494*d6b92ffaSHans Petter Selasky 	return NULL;
495*d6b92ffaSHans Petter Selasky }
496*d6b92ffaSHans Petter Selasky 
_fill_port(ibnd_fabric_cache_t * fabric_cache,ibnd_node_t * node,ibnd_port_cache_key_t * port_cache_key)497*d6b92ffaSHans Petter Selasky static int _fill_port(ibnd_fabric_cache_t * fabric_cache, ibnd_node_t * node,
498*d6b92ffaSHans Petter Selasky 		      ibnd_port_cache_key_t * port_cache_key)
499*d6b92ffaSHans Petter Selasky {
500*d6b92ffaSHans Petter Selasky 	ibnd_port_cache_t *port_cache;
501*d6b92ffaSHans Petter Selasky 
502*d6b92ffaSHans Petter Selasky 	if (!(port_cache = _find_port(fabric_cache, port_cache_key))) {
503*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("Cache invalid: cannot find port\n");
504*d6b92ffaSHans Petter Selasky 		return -1;
505*d6b92ffaSHans Petter Selasky 	}
506*d6b92ffaSHans Petter Selasky 
507*d6b92ffaSHans Petter Selasky 	if (port_cache->port_stored_to_fabric) {
508*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("Cache invalid: duplicate port discovered\n");
509*d6b92ffaSHans Petter Selasky 		return -1;
510*d6b92ffaSHans Petter Selasky 	}
511*d6b92ffaSHans Petter Selasky 
512*d6b92ffaSHans Petter Selasky 	node->ports[port_cache->port->portnum] = port_cache->port;
513*d6b92ffaSHans Petter Selasky 	port_cache->port_stored_to_fabric++;
514*d6b92ffaSHans Petter Selasky 
515*d6b92ffaSHans Petter Selasky 	/* achu: needed if user wishes to re-cache a loaded fabric.
516*d6b92ffaSHans Petter Selasky 	 * Otherwise, mostly unnecessary to do this.
517*d6b92ffaSHans Petter Selasky 	 */
518*d6b92ffaSHans Petter Selasky 	int rc = add_to_portguid_hash(port_cache->port,
519*d6b92ffaSHans Petter Selasky 				      fabric_cache->f_int->fabric.portstbl);
520*d6b92ffaSHans Petter Selasky 	if (rc) {
521*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("Error Occurred when trying"
522*d6b92ffaSHans Petter Selasky 			   " to insert new port guid 0x%016" PRIx64 " to DB\n",
523*d6b92ffaSHans Petter Selasky 			   port_cache->port->guid);
524*d6b92ffaSHans Petter Selasky 	}
525*d6b92ffaSHans Petter Selasky 	return 0;
526*d6b92ffaSHans Petter Selasky }
527*d6b92ffaSHans Petter Selasky 
_rebuild_nodes(ibnd_fabric_cache_t * fabric_cache)528*d6b92ffaSHans Petter Selasky static int _rebuild_nodes(ibnd_fabric_cache_t * fabric_cache)
529*d6b92ffaSHans Petter Selasky {
530*d6b92ffaSHans Petter Selasky 	ibnd_node_cache_t *node_cache;
531*d6b92ffaSHans Petter Selasky 	ibnd_node_cache_t *node_cache_next;
532*d6b92ffaSHans Petter Selasky 
533*d6b92ffaSHans Petter Selasky 	node_cache = fabric_cache->nodes_cache;
534*d6b92ffaSHans Petter Selasky 	while (node_cache) {
535*d6b92ffaSHans Petter Selasky 		ibnd_node_t *node;
536*d6b92ffaSHans Petter Selasky 		int i;
537*d6b92ffaSHans Petter Selasky 
538*d6b92ffaSHans Petter Selasky 		node_cache_next = node_cache->next;
539*d6b92ffaSHans Petter Selasky 
540*d6b92ffaSHans Petter Selasky 		node = node_cache->node;
541*d6b92ffaSHans Petter Selasky 
542*d6b92ffaSHans Petter Selasky 		/* Insert node into appropriate data structures */
543*d6b92ffaSHans Petter Selasky 
544*d6b92ffaSHans Petter Selasky 		node->next = fabric_cache->f_int->fabric.nodes;
545*d6b92ffaSHans Petter Selasky 		fabric_cache->f_int->fabric.nodes = node;
546*d6b92ffaSHans Petter Selasky 
547*d6b92ffaSHans Petter Selasky 		int rc = add_to_nodeguid_hash(node_cache->node,
548*d6b92ffaSHans Petter Selasky 					      fabric_cache->
549*d6b92ffaSHans Petter Selasky 					      f_int->
550*d6b92ffaSHans Petter Selasky 					      fabric.nodestbl);
551*d6b92ffaSHans Petter Selasky 		if (rc) {
552*d6b92ffaSHans Petter Selasky 			IBND_DEBUG("Error Occurred when trying"
553*d6b92ffaSHans Petter Selasky 				   " to insert new node guid 0x%016" PRIx64 " to DB\n",
554*d6b92ffaSHans Petter Selasky 				   node_cache->node->guid);
555*d6b92ffaSHans Petter Selasky 		}
556*d6b92ffaSHans Petter Selasky 
557*d6b92ffaSHans Petter Selasky 		add_to_type_list(node_cache->node, fabric_cache->f_int);
558*d6b92ffaSHans Petter Selasky 
559*d6b92ffaSHans Petter Selasky 		node_cache->node_stored_to_fabric++;
560*d6b92ffaSHans Petter Selasky 
561*d6b92ffaSHans Petter Selasky 		/* Rebuild node ports array */
562*d6b92ffaSHans Petter Selasky 
563*d6b92ffaSHans Petter Selasky 		if (!(node->ports =
564*d6b92ffaSHans Petter Selasky 		      calloc(sizeof(*node->ports), node->numports + 1))) {
565*d6b92ffaSHans Petter Selasky 			IBND_DEBUG("OOM: node->ports\n");
566*d6b92ffaSHans Petter Selasky 			return -1;
567*d6b92ffaSHans Petter Selasky 		}
568*d6b92ffaSHans Petter Selasky 
569*d6b92ffaSHans Petter Selasky 		for (i = 0; i < node_cache->ports_stored_count; i++) {
570*d6b92ffaSHans Petter Selasky 			if (_fill_port(fabric_cache, node,
571*d6b92ffaSHans Petter Selasky 				       &node_cache->port_cache_keys[i]) < 0)
572*d6b92ffaSHans Petter Selasky 				return -1;
573*d6b92ffaSHans Petter Selasky 		}
574*d6b92ffaSHans Petter Selasky 
575*d6b92ffaSHans Petter Selasky 		node_cache = node_cache_next;
576*d6b92ffaSHans Petter Selasky 	}
577*d6b92ffaSHans Petter Selasky 
578*d6b92ffaSHans Petter Selasky 	return 0;
579*d6b92ffaSHans Petter Selasky }
580*d6b92ffaSHans Petter Selasky 
_rebuild_ports(ibnd_fabric_cache_t * fabric_cache)581*d6b92ffaSHans Petter Selasky static int _rebuild_ports(ibnd_fabric_cache_t * fabric_cache)
582*d6b92ffaSHans Petter Selasky {
583*d6b92ffaSHans Petter Selasky 	ibnd_port_cache_t *port_cache;
584*d6b92ffaSHans Petter Selasky 	ibnd_port_cache_t *port_cache_next;
585*d6b92ffaSHans Petter Selasky 
586*d6b92ffaSHans Petter Selasky 	port_cache = fabric_cache->ports_cache;
587*d6b92ffaSHans Petter Selasky 	while (port_cache) {
588*d6b92ffaSHans Petter Selasky 		ibnd_node_cache_t *node_cache;
589*d6b92ffaSHans Petter Selasky 		ibnd_port_cache_t *remoteport_cache;
590*d6b92ffaSHans Petter Selasky 		ibnd_port_t *port;
591*d6b92ffaSHans Petter Selasky 
592*d6b92ffaSHans Petter Selasky 		port_cache_next = port_cache->next;
593*d6b92ffaSHans Petter Selasky 
594*d6b92ffaSHans Petter Selasky 		port = port_cache->port;
595*d6b92ffaSHans Petter Selasky 
596*d6b92ffaSHans Petter Selasky 		if (!(node_cache =
597*d6b92ffaSHans Petter Selasky 		      _find_node(fabric_cache, port_cache->node_guid))) {
598*d6b92ffaSHans Petter Selasky 			IBND_DEBUG("Cache invalid: cannot find node\n");
599*d6b92ffaSHans Petter Selasky 			return -1;
600*d6b92ffaSHans Petter Selasky 		}
601*d6b92ffaSHans Petter Selasky 
602*d6b92ffaSHans Petter Selasky 		port->node = node_cache->node;
603*d6b92ffaSHans Petter Selasky 
604*d6b92ffaSHans Petter Selasky 		if (port_cache->remoteport_flag) {
605*d6b92ffaSHans Petter Selasky 			if (!(remoteport_cache = _find_port(fabric_cache,
606*d6b92ffaSHans Petter Selasky 							    &port_cache->remoteport_cache_key)))
607*d6b92ffaSHans Petter Selasky 			{
608*d6b92ffaSHans Petter Selasky 				IBND_DEBUG
609*d6b92ffaSHans Petter Selasky 				    ("Cache invalid: cannot find remote port\n");
610*d6b92ffaSHans Petter Selasky 				return -1;
611*d6b92ffaSHans Petter Selasky 			}
612*d6b92ffaSHans Petter Selasky 
613*d6b92ffaSHans Petter Selasky 			port->remoteport = remoteport_cache->port;
614*d6b92ffaSHans Petter Selasky 		} else
615*d6b92ffaSHans Petter Selasky 			port->remoteport = NULL;
616*d6b92ffaSHans Petter Selasky 
617*d6b92ffaSHans Petter Selasky 		add_to_portlid_hash(port, fabric_cache->f_int->lid2guid);
618*d6b92ffaSHans Petter Selasky 		port_cache = port_cache_next;
619*d6b92ffaSHans Petter Selasky 	}
620*d6b92ffaSHans Petter Selasky 
621*d6b92ffaSHans Petter Selasky 	return 0;
622*d6b92ffaSHans Petter Selasky }
623*d6b92ffaSHans Petter Selasky 
ibnd_load_fabric(const char * file,unsigned int flags)624*d6b92ffaSHans Petter Selasky ibnd_fabric_t *ibnd_load_fabric(const char *file, unsigned int flags)
625*d6b92ffaSHans Petter Selasky {
626*d6b92ffaSHans Petter Selasky 	unsigned int node_count = 0;
627*d6b92ffaSHans Petter Selasky 	unsigned int port_count = 0;
628*d6b92ffaSHans Petter Selasky 	ibnd_fabric_cache_t *fabric_cache = NULL;
629*d6b92ffaSHans Petter Selasky 	f_internal_t *f_int = NULL;
630*d6b92ffaSHans Petter Selasky 	ibnd_node_cache_t *node_cache = NULL;
631*d6b92ffaSHans Petter Selasky 	int fd = -1;
632*d6b92ffaSHans Petter Selasky 	unsigned int i;
633*d6b92ffaSHans Petter Selasky 
634*d6b92ffaSHans Petter Selasky 	if (!file) {
635*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("file parameter NULL\n");
636*d6b92ffaSHans Petter Selasky 		return NULL;
637*d6b92ffaSHans Petter Selasky 	}
638*d6b92ffaSHans Petter Selasky 
639*d6b92ffaSHans Petter Selasky 	if ((fd = open(file, O_RDONLY)) < 0) {
640*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("open: %s\n", strerror(errno));
641*d6b92ffaSHans Petter Selasky 		return NULL;
642*d6b92ffaSHans Petter Selasky 	}
643*d6b92ffaSHans Petter Selasky 
644*d6b92ffaSHans Petter Selasky 	fabric_cache =
645*d6b92ffaSHans Petter Selasky 	    (ibnd_fabric_cache_t *) malloc(sizeof(ibnd_fabric_cache_t));
646*d6b92ffaSHans Petter Selasky 	if (!fabric_cache) {
647*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("OOM: fabric_cache\n");
648*d6b92ffaSHans Petter Selasky 		goto cleanup;
649*d6b92ffaSHans Petter Selasky 	}
650*d6b92ffaSHans Petter Selasky 	memset(fabric_cache, '\0', sizeof(ibnd_fabric_cache_t));
651*d6b92ffaSHans Petter Selasky 
652*d6b92ffaSHans Petter Selasky 	f_int = allocate_fabric_internal();
653*d6b92ffaSHans Petter Selasky 	if (!f_int) {
654*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("OOM: fabric\n");
655*d6b92ffaSHans Petter Selasky 		goto cleanup;
656*d6b92ffaSHans Petter Selasky 	}
657*d6b92ffaSHans Petter Selasky 
658*d6b92ffaSHans Petter Selasky 	fabric_cache->f_int = f_int;
659*d6b92ffaSHans Petter Selasky 
660*d6b92ffaSHans Petter Selasky 	if (_load_header_info(fd, fabric_cache, &node_count, &port_count) < 0)
661*d6b92ffaSHans Petter Selasky 		goto cleanup;
662*d6b92ffaSHans Petter Selasky 
663*d6b92ffaSHans Petter Selasky 	for (i = 0; i < node_count; i++) {
664*d6b92ffaSHans Petter Selasky 		if (_load_node(fd, fabric_cache) < 0)
665*d6b92ffaSHans Petter Selasky 			goto cleanup;
666*d6b92ffaSHans Petter Selasky 	}
667*d6b92ffaSHans Petter Selasky 
668*d6b92ffaSHans Petter Selasky 	for (i = 0; i < port_count; i++) {
669*d6b92ffaSHans Petter Selasky 		if (_load_port(fd, fabric_cache) < 0)
670*d6b92ffaSHans Petter Selasky 			goto cleanup;
671*d6b92ffaSHans Petter Selasky 	}
672*d6b92ffaSHans Petter Selasky 
673*d6b92ffaSHans Petter Selasky 	/* Special case - find from node */
674*d6b92ffaSHans Petter Selasky 	if (!(node_cache =
675*d6b92ffaSHans Petter Selasky 	      _find_node(fabric_cache, fabric_cache->from_node_guid))) {
676*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("Cache invalid: cannot find from node\n");
677*d6b92ffaSHans Petter Selasky 		goto cleanup;
678*d6b92ffaSHans Petter Selasky 	}
679*d6b92ffaSHans Petter Selasky 	f_int->fabric.from_node = node_cache->node;
680*d6b92ffaSHans Petter Selasky 
681*d6b92ffaSHans Petter Selasky 	if (_rebuild_nodes(fabric_cache) < 0)
682*d6b92ffaSHans Petter Selasky 		goto cleanup;
683*d6b92ffaSHans Petter Selasky 
684*d6b92ffaSHans Petter Selasky 	if (_rebuild_ports(fabric_cache) < 0)
685*d6b92ffaSHans Petter Selasky 		goto cleanup;
686*d6b92ffaSHans Petter Selasky 
687*d6b92ffaSHans Petter Selasky 	if (group_nodes(&f_int->fabric))
688*d6b92ffaSHans Petter Selasky 		goto cleanup;
689*d6b92ffaSHans Petter Selasky 
690*d6b92ffaSHans Petter Selasky 	_destroy_ibnd_fabric_cache(fabric_cache);
691*d6b92ffaSHans Petter Selasky 	close(fd);
692*d6b92ffaSHans Petter Selasky 	return (ibnd_fabric_t *)&f_int->fabric;
693*d6b92ffaSHans Petter Selasky 
694*d6b92ffaSHans Petter Selasky cleanup:
695*d6b92ffaSHans Petter Selasky 	ibnd_destroy_fabric((ibnd_fabric_t *)f_int);
696*d6b92ffaSHans Petter Selasky 	_destroy_ibnd_fabric_cache(fabric_cache);
697*d6b92ffaSHans Petter Selasky 	close(fd);
698*d6b92ffaSHans Petter Selasky 	return NULL;
699*d6b92ffaSHans Petter Selasky }
700*d6b92ffaSHans Petter Selasky 
ibnd_write(int fd,const void * buf,size_t count)701*d6b92ffaSHans Petter Selasky static ssize_t ibnd_write(int fd, const void *buf, size_t count)
702*d6b92ffaSHans Petter Selasky {
703*d6b92ffaSHans Petter Selasky 	size_t count_done = 0;
704*d6b92ffaSHans Petter Selasky 	ssize_t ret;
705*d6b92ffaSHans Petter Selasky 
706*d6b92ffaSHans Petter Selasky 	while ((count - count_done) > 0) {
707*d6b92ffaSHans Petter Selasky 		ret = write(fd, ((char *) buf) + count_done, count - count_done);
708*d6b92ffaSHans Petter Selasky 		if (ret < 0) {
709*d6b92ffaSHans Petter Selasky 			if (errno == EINTR)
710*d6b92ffaSHans Petter Selasky 				continue;
711*d6b92ffaSHans Petter Selasky 			else {
712*d6b92ffaSHans Petter Selasky 				IBND_DEBUG("write: %s\n", strerror(errno));
713*d6b92ffaSHans Petter Selasky 				return -1;
714*d6b92ffaSHans Petter Selasky 			}
715*d6b92ffaSHans Petter Selasky 		}
716*d6b92ffaSHans Petter Selasky 		count_done += ret;
717*d6b92ffaSHans Petter Selasky 	}
718*d6b92ffaSHans Petter Selasky 	return count_done;
719*d6b92ffaSHans Petter Selasky }
720*d6b92ffaSHans Petter Selasky 
_marshall8(uint8_t * outbuf,uint8_t num)721*d6b92ffaSHans Petter Selasky static size_t _marshall8(uint8_t * outbuf, uint8_t num)
722*d6b92ffaSHans Petter Selasky {
723*d6b92ffaSHans Petter Selasky 	outbuf[0] = num;
724*d6b92ffaSHans Petter Selasky 
725*d6b92ffaSHans Petter Selasky 	return (sizeof(num));
726*d6b92ffaSHans Petter Selasky }
727*d6b92ffaSHans Petter Selasky 
_marshall16(uint8_t * outbuf,uint16_t num)728*d6b92ffaSHans Petter Selasky static size_t _marshall16(uint8_t * outbuf, uint16_t num)
729*d6b92ffaSHans Petter Selasky {
730*d6b92ffaSHans Petter Selasky 	outbuf[0] = num & 0x00FF;
731*d6b92ffaSHans Petter Selasky 	outbuf[1] = (num & 0xFF00) >> 8;
732*d6b92ffaSHans Petter Selasky 
733*d6b92ffaSHans Petter Selasky 	return (sizeof(num));
734*d6b92ffaSHans Petter Selasky }
735*d6b92ffaSHans Petter Selasky 
_marshall32(uint8_t * outbuf,uint32_t num)736*d6b92ffaSHans Petter Selasky static size_t _marshall32(uint8_t * outbuf, uint32_t num)
737*d6b92ffaSHans Petter Selasky {
738*d6b92ffaSHans Petter Selasky 	outbuf[0] = num & 0x000000FF;
739*d6b92ffaSHans Petter Selasky 	outbuf[1] = (num & 0x0000FF00) >> 8;
740*d6b92ffaSHans Petter Selasky 	outbuf[2] = (num & 0x00FF0000) >> 16;
741*d6b92ffaSHans Petter Selasky 	outbuf[3] = (num & 0xFF000000) >> 24;
742*d6b92ffaSHans Petter Selasky 
743*d6b92ffaSHans Petter Selasky 	return (sizeof(num));
744*d6b92ffaSHans Petter Selasky }
745*d6b92ffaSHans Petter Selasky 
_marshall64(uint8_t * outbuf,uint64_t num)746*d6b92ffaSHans Petter Selasky static size_t _marshall64(uint8_t * outbuf, uint64_t num)
747*d6b92ffaSHans Petter Selasky {
748*d6b92ffaSHans Petter Selasky 	outbuf[0] = (uint8_t) num;
749*d6b92ffaSHans Petter Selasky 	outbuf[1] = (uint8_t) (num >> 8);
750*d6b92ffaSHans Petter Selasky 	outbuf[2] = (uint8_t) (num >> 16);
751*d6b92ffaSHans Petter Selasky 	outbuf[3] = (uint8_t) (num >> 24);
752*d6b92ffaSHans Petter Selasky 	outbuf[4] = (uint8_t) (num >> 32);
753*d6b92ffaSHans Petter Selasky 	outbuf[5] = (uint8_t) (num >> 40);
754*d6b92ffaSHans Petter Selasky 	outbuf[6] = (uint8_t) (num >> 48);
755*d6b92ffaSHans Petter Selasky 	outbuf[7] = (uint8_t) (num >> 56);
756*d6b92ffaSHans Petter Selasky 
757*d6b92ffaSHans Petter Selasky 	return (sizeof(num));
758*d6b92ffaSHans Petter Selasky }
759*d6b92ffaSHans Petter Selasky 
_marshall_buf(void * outbuf,const void * inbuf,unsigned int len)760*d6b92ffaSHans Petter Selasky static size_t _marshall_buf(void *outbuf, const void *inbuf, unsigned int len)
761*d6b92ffaSHans Petter Selasky {
762*d6b92ffaSHans Petter Selasky 	memcpy(outbuf, inbuf, len);
763*d6b92ffaSHans Petter Selasky 
764*d6b92ffaSHans Petter Selasky 	return len;
765*d6b92ffaSHans Petter Selasky }
766*d6b92ffaSHans Petter Selasky 
_cache_header_info(int fd,ibnd_fabric_t * fabric)767*d6b92ffaSHans Petter Selasky static int _cache_header_info(int fd, ibnd_fabric_t * fabric)
768*d6b92ffaSHans Petter Selasky {
769*d6b92ffaSHans Petter Selasky 	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
770*d6b92ffaSHans Petter Selasky 	size_t offset = 0;
771*d6b92ffaSHans Petter Selasky 
772*d6b92ffaSHans Petter Selasky 	/* Store magic number, version, and other important info */
773*d6b92ffaSHans Petter Selasky 	/* For this caching lib, we always assume cached as little endian */
774*d6b92ffaSHans Petter Selasky 
775*d6b92ffaSHans Petter Selasky 	offset += _marshall32(buf + offset, IBND_FABRIC_CACHE_MAGIC);
776*d6b92ffaSHans Petter Selasky 	offset += _marshall32(buf + offset, IBND_FABRIC_CACHE_VERSION);
777*d6b92ffaSHans Petter Selasky 	/* save space for node count */
778*d6b92ffaSHans Petter Selasky 	offset += _marshall32(buf + offset, 0);
779*d6b92ffaSHans Petter Selasky 	/* save space for port count */
780*d6b92ffaSHans Petter Selasky 	offset += _marshall32(buf + offset, 0);
781*d6b92ffaSHans Petter Selasky 	offset += _marshall64(buf + offset, fabric->from_node->guid);
782*d6b92ffaSHans Petter Selasky 	offset += _marshall32(buf + offset, fabric->maxhops_discovered);
783*d6b92ffaSHans Petter Selasky 
784*d6b92ffaSHans Petter Selasky 	if (ibnd_write(fd, buf, offset) < 0)
785*d6b92ffaSHans Petter Selasky 		return -1;
786*d6b92ffaSHans Petter Selasky 
787*d6b92ffaSHans Petter Selasky 	return 0;
788*d6b92ffaSHans Petter Selasky }
789*d6b92ffaSHans Petter Selasky 
_cache_header_counts(int fd,unsigned int node_count,unsigned int port_count)790*d6b92ffaSHans Petter Selasky static int _cache_header_counts(int fd, unsigned int node_count,
791*d6b92ffaSHans Petter Selasky 				unsigned int port_count)
792*d6b92ffaSHans Petter Selasky {
793*d6b92ffaSHans Petter Selasky 	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
794*d6b92ffaSHans Petter Selasky 	size_t offset = 0;
795*d6b92ffaSHans Petter Selasky 
796*d6b92ffaSHans Petter Selasky 	offset += _marshall32(buf + offset, node_count);
797*d6b92ffaSHans Petter Selasky 	offset += _marshall32(buf + offset, port_count);
798*d6b92ffaSHans Petter Selasky 
799*d6b92ffaSHans Petter Selasky 	if (lseek(fd, IBND_FABRIC_CACHE_COUNT_OFFSET, SEEK_SET) < 0) {
800*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("lseek: %s\n", strerror(errno));
801*d6b92ffaSHans Petter Selasky 		return -1;
802*d6b92ffaSHans Petter Selasky 	}
803*d6b92ffaSHans Petter Selasky 
804*d6b92ffaSHans Petter Selasky 	if (ibnd_write(fd, buf, offset) < 0)
805*d6b92ffaSHans Petter Selasky 		return -1;
806*d6b92ffaSHans Petter Selasky 
807*d6b92ffaSHans Petter Selasky 	return 0;
808*d6b92ffaSHans Petter Selasky }
809*d6b92ffaSHans Petter Selasky 
_cache_node(int fd,ibnd_node_t * node)810*d6b92ffaSHans Petter Selasky static int _cache_node(int fd, ibnd_node_t * node)
811*d6b92ffaSHans Petter Selasky {
812*d6b92ffaSHans Petter Selasky 	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
813*d6b92ffaSHans Petter Selasky 	size_t offset = 0;
814*d6b92ffaSHans Petter Selasky 	size_t ports_stored_offset = 0;
815*d6b92ffaSHans Petter Selasky 	uint8_t ports_stored_count = 0;
816*d6b92ffaSHans Petter Selasky 	int i;
817*d6b92ffaSHans Petter Selasky 
818*d6b92ffaSHans Petter Selasky 	offset += _marshall16(buf + offset, node->smalid);
819*d6b92ffaSHans Petter Selasky 	offset += _marshall8(buf + offset, node->smalmc);
820*d6b92ffaSHans Petter Selasky 	offset += _marshall8(buf + offset, (uint8_t) node->smaenhsp0);
821*d6b92ffaSHans Petter Selasky 	offset += _marshall_buf(buf + offset, node->switchinfo,
822*d6b92ffaSHans Petter Selasky 				IB_SMP_DATA_SIZE);
823*d6b92ffaSHans Petter Selasky 	offset += _marshall64(buf + offset, node->guid);
824*d6b92ffaSHans Petter Selasky 	offset += _marshall8(buf + offset, (uint8_t) node->type);
825*d6b92ffaSHans Petter Selasky 	offset += _marshall8(buf + offset, (uint8_t) node->numports);
826*d6b92ffaSHans Petter Selasky 	offset += _marshall_buf(buf + offset, node->info, IB_SMP_DATA_SIZE);
827*d6b92ffaSHans Petter Selasky 	offset += _marshall_buf(buf + offset, node->nodedesc, IB_SMP_DATA_SIZE);
828*d6b92ffaSHans Petter Selasky 	/* need to come back later and store number of stored ports
829*d6b92ffaSHans Petter Selasky 	 * because port entries can be NULL or (in the case of switches)
830*d6b92ffaSHans Petter Selasky 	 * there is an additional port 0 not accounted for in numports.
831*d6b92ffaSHans Petter Selasky 	 */
832*d6b92ffaSHans Petter Selasky 	ports_stored_offset = offset;
833*d6b92ffaSHans Petter Selasky 	offset += sizeof(uint8_t);
834*d6b92ffaSHans Petter Selasky 
835*d6b92ffaSHans Petter Selasky 	for (i = 0; i <= node->numports; i++) {
836*d6b92ffaSHans Petter Selasky 		if (node->ports[i]) {
837*d6b92ffaSHans Petter Selasky 			offset += _marshall64(buf + offset,
838*d6b92ffaSHans Petter Selasky 					      node->ports[i]->guid);
839*d6b92ffaSHans Petter Selasky 			offset += _marshall8(buf + offset,
840*d6b92ffaSHans Petter Selasky 					     (uint8_t) node->ports[i]->portnum);
841*d6b92ffaSHans Petter Selasky 			ports_stored_count++;
842*d6b92ffaSHans Petter Selasky 		}
843*d6b92ffaSHans Petter Selasky 	}
844*d6b92ffaSHans Petter Selasky 
845*d6b92ffaSHans Petter Selasky 	/* go back and store number of port keys stored */
846*d6b92ffaSHans Petter Selasky 	_marshall8(buf + ports_stored_offset, ports_stored_count);
847*d6b92ffaSHans Petter Selasky 
848*d6b92ffaSHans Petter Selasky 	if (ibnd_write(fd, buf, offset) < 0)
849*d6b92ffaSHans Petter Selasky 		return -1;
850*d6b92ffaSHans Petter Selasky 
851*d6b92ffaSHans Petter Selasky 	return 0;
852*d6b92ffaSHans Petter Selasky }
853*d6b92ffaSHans Petter Selasky 
_cache_port(int fd,ibnd_port_t * port)854*d6b92ffaSHans Petter Selasky static int _cache_port(int fd, ibnd_port_t * port)
855*d6b92ffaSHans Petter Selasky {
856*d6b92ffaSHans Petter Selasky 	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
857*d6b92ffaSHans Petter Selasky 	size_t offset = 0;
858*d6b92ffaSHans Petter Selasky 
859*d6b92ffaSHans Petter Selasky 	offset += _marshall64(buf + offset, port->guid);
860*d6b92ffaSHans Petter Selasky 	offset += _marshall8(buf + offset, (uint8_t) port->portnum);
861*d6b92ffaSHans Petter Selasky 	offset += _marshall8(buf + offset, (uint8_t) port->ext_portnum);
862*d6b92ffaSHans Petter Selasky 	offset += _marshall16(buf + offset, port->base_lid);
863*d6b92ffaSHans Petter Selasky 	offset += _marshall8(buf + offset, port->lmc);
864*d6b92ffaSHans Petter Selasky 	offset += _marshall_buf(buf + offset, port->info, IB_SMP_DATA_SIZE);
865*d6b92ffaSHans Petter Selasky 	offset += _marshall64(buf + offset, port->node->guid);
866*d6b92ffaSHans Petter Selasky 	if (port->remoteport) {
867*d6b92ffaSHans Petter Selasky 		offset += _marshall8(buf + offset, 1);
868*d6b92ffaSHans Petter Selasky 		offset += _marshall64(buf + offset, port->remoteport->guid);
869*d6b92ffaSHans Petter Selasky 		offset += _marshall8(buf + offset, (uint8_t) port->remoteport->portnum);
870*d6b92ffaSHans Petter Selasky 	} else {
871*d6b92ffaSHans Petter Selasky 		offset += _marshall8(buf + offset, 0);
872*d6b92ffaSHans Petter Selasky 		offset += _marshall64(buf + offset, 0);
873*d6b92ffaSHans Petter Selasky 		offset += _marshall8(buf + offset, 0);
874*d6b92ffaSHans Petter Selasky 	}
875*d6b92ffaSHans Petter Selasky 
876*d6b92ffaSHans Petter Selasky 	if (ibnd_write(fd, buf, offset) < 0)
877*d6b92ffaSHans Petter Selasky 		return -1;
878*d6b92ffaSHans Petter Selasky 
879*d6b92ffaSHans Petter Selasky 	return 0;
880*d6b92ffaSHans Petter Selasky }
881*d6b92ffaSHans Petter Selasky 
ibnd_cache_fabric(ibnd_fabric_t * fabric,const char * file,unsigned int flags)882*d6b92ffaSHans Petter Selasky int ibnd_cache_fabric(ibnd_fabric_t * fabric, const char *file,
883*d6b92ffaSHans Petter Selasky 		      unsigned int flags)
884*d6b92ffaSHans Petter Selasky {
885*d6b92ffaSHans Petter Selasky 	struct stat statbuf;
886*d6b92ffaSHans Petter Selasky 	ibnd_node_t *node = NULL;
887*d6b92ffaSHans Petter Selasky 	ibnd_node_t *node_next = NULL;
888*d6b92ffaSHans Petter Selasky 	unsigned int node_count = 0;
889*d6b92ffaSHans Petter Selasky 	ibnd_port_t *port = NULL;
890*d6b92ffaSHans Petter Selasky 	ibnd_port_t *port_next = NULL;
891*d6b92ffaSHans Petter Selasky 	unsigned int port_count = 0;
892*d6b92ffaSHans Petter Selasky 	int fd;
893*d6b92ffaSHans Petter Selasky 	int i;
894*d6b92ffaSHans Petter Selasky 
895*d6b92ffaSHans Petter Selasky 	if (!fabric) {
896*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("fabric parameter NULL\n");
897*d6b92ffaSHans Petter Selasky 		return -1;
898*d6b92ffaSHans Petter Selasky 	}
899*d6b92ffaSHans Petter Selasky 
900*d6b92ffaSHans Petter Selasky 	if (!file) {
901*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("file parameter NULL\n");
902*d6b92ffaSHans Petter Selasky 		return -1;
903*d6b92ffaSHans Petter Selasky 	}
904*d6b92ffaSHans Petter Selasky 
905*d6b92ffaSHans Petter Selasky 	if (!(flags & IBND_CACHE_FABRIC_FLAG_NO_OVERWRITE)) {
906*d6b92ffaSHans Petter Selasky 		if (!stat(file, &statbuf)) {
907*d6b92ffaSHans Petter Selasky 			if (unlink(file) < 0) {
908*d6b92ffaSHans Petter Selasky 				IBND_DEBUG("error removing '%s': %s\n",
909*d6b92ffaSHans Petter Selasky 					   file, strerror(errno));
910*d6b92ffaSHans Petter Selasky 				return -1;
911*d6b92ffaSHans Petter Selasky 			}
912*d6b92ffaSHans Petter Selasky 		}
913*d6b92ffaSHans Petter Selasky 	}
914*d6b92ffaSHans Petter Selasky 	else {
915*d6b92ffaSHans Petter Selasky 		if (!stat(file, &statbuf)) {
916*d6b92ffaSHans Petter Selasky 			IBND_DEBUG("file '%s' already exists\n", file);
917*d6b92ffaSHans Petter Selasky 			return -1;
918*d6b92ffaSHans Petter Selasky 		}
919*d6b92ffaSHans Petter Selasky 	}
920*d6b92ffaSHans Petter Selasky 
921*d6b92ffaSHans Petter Selasky 	if ((fd = open(file, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) {
922*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("open: %s\n", strerror(errno));
923*d6b92ffaSHans Petter Selasky 		return -1;
924*d6b92ffaSHans Petter Selasky 	}
925*d6b92ffaSHans Petter Selasky 
926*d6b92ffaSHans Petter Selasky 	if (_cache_header_info(fd, fabric) < 0)
927*d6b92ffaSHans Petter Selasky 		goto cleanup;
928*d6b92ffaSHans Petter Selasky 
929*d6b92ffaSHans Petter Selasky 	node = fabric->nodes;
930*d6b92ffaSHans Petter Selasky 	while (node) {
931*d6b92ffaSHans Petter Selasky 		node_next = node->next;
932*d6b92ffaSHans Petter Selasky 
933*d6b92ffaSHans Petter Selasky 		if (_cache_node(fd, node) < 0)
934*d6b92ffaSHans Petter Selasky 			goto cleanup;
935*d6b92ffaSHans Petter Selasky 
936*d6b92ffaSHans Petter Selasky 		node_count++;
937*d6b92ffaSHans Petter Selasky 		node = node_next;
938*d6b92ffaSHans Petter Selasky 	}
939*d6b92ffaSHans Petter Selasky 
940*d6b92ffaSHans Petter Selasky 	for (i = 0; i < HTSZ; i++) {
941*d6b92ffaSHans Petter Selasky 		port = fabric->portstbl[i];
942*d6b92ffaSHans Petter Selasky 		while (port) {
943*d6b92ffaSHans Petter Selasky 			port_next = port->htnext;
944*d6b92ffaSHans Petter Selasky 
945*d6b92ffaSHans Petter Selasky 			if (_cache_port(fd, port) < 0)
946*d6b92ffaSHans Petter Selasky 				goto cleanup;
947*d6b92ffaSHans Petter Selasky 
948*d6b92ffaSHans Petter Selasky 			port_count++;
949*d6b92ffaSHans Petter Selasky 			port = port_next;
950*d6b92ffaSHans Petter Selasky 		}
951*d6b92ffaSHans Petter Selasky 	}
952*d6b92ffaSHans Petter Selasky 
953*d6b92ffaSHans Petter Selasky 	if (_cache_header_counts(fd, node_count, port_count) < 0)
954*d6b92ffaSHans Petter Selasky 		goto cleanup;
955*d6b92ffaSHans Petter Selasky 
956*d6b92ffaSHans Petter Selasky 	if (close(fd) < 0) {
957*d6b92ffaSHans Petter Selasky 		IBND_DEBUG("close: %s\n", strerror(errno));
958*d6b92ffaSHans Petter Selasky 		goto cleanup;
959*d6b92ffaSHans Petter Selasky 	}
960*d6b92ffaSHans Petter Selasky 
961*d6b92ffaSHans Petter Selasky 	return 0;
962*d6b92ffaSHans Petter Selasky 
963*d6b92ffaSHans Petter Selasky cleanup:
964*d6b92ffaSHans Petter Selasky 	unlink(file);
965*d6b92ffaSHans Petter Selasky 	close(fd);
966*d6b92ffaSHans Petter Selasky 	return -1;
967*d6b92ffaSHans Petter Selasky }
968