1 /*
2  * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #ifndef ISTGT_H
29 #define ISTGT_H
30 
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 
35 #ifdef USE_ATOMIC
36 #ifdef HAVE_SYS_TYPES_H
37 #include <sys/types.h>
38 #endif
39 #ifdef HAVE_MACHINE_ATOMIC_H
40 #include <machine/atomic.h>
41 #endif
42 #ifdef HAVE_SYS_ATOMIC_H
43 #include <sys/atomic.h>
44 #endif
45 #endif /* USE_ATOMIC */
46 
47 #include "build.h"
48 
49 #include <pthread.h>
50 #include <signal.h>
51 #include "istgt_log.h"
52 #include "istgt_conf.h"
53 
54 #if !defined(__GNUC__)
55 #undef __attribute__
56 #define __attribute__(x)
57 #endif
58 #if defined(__GNUC__) && defined(__GNUC_MINOR__)
59 #define ISTGT_GNUC_PREREQ(ma,mi) \
60 	(__GNUC__ > (ma) || (__GNUC__ == (ma) && __GNUC_MINOR__ >= (mi)))
61 #else
62 #define ISTGT_GNUC_PREREQ(ma,mi) 0
63 #endif
64 
65 #define MAX_TMPBUF 1024
66 #define MAX_ADDRBUF 64
67 #define MAX_INITIATOR_ADDR (MAX_ADDRBUF)
68 #define MAX_INITIATOR_NAME 256
69 #define MAX_TARGET_ADDR (MAX_ADDRBUF)
70 #define MAX_TARGET_NAME 256
71 #define MAX_ISCSI_NAME 256
72 
73 #define MAX_UCPORTAL 16
74 #define MAX_PORTAL 1024
75 #define MAX_INITIATOR 256
76 #define MAX_NETMASK 256
77 #define MAX_PORTAL_GROUP 4096
78 #define MAX_INITIATOR_GROUP 4096
79 #define MAX_LOGICAL_UNIT 4096
80 #define MAX_R2T 256
81 
82 #define DEFAULT_CONFIG BUILD_ETC_ISTGT "/istgt.conf"
83 #define DEFAULT_PIDFILE "/var/run/istgt.pid"
84 #define DEFAULT_AUTHFILE BUILD_ETC_ISTGT "/auth.conf"
85 #if 0
86 #define DEFAULT_MEDIAFILE BUILD_ETC_ISTGT "/media.conf"
87 #define DEFAULT_LIVEFILE BUILD_ETC_ISTGT "/istgt.live"
88 #endif
89 #define DEFAULT_MEDIADIRECTORY BUILD_VAR_ISTGT
90 #define DEFAULT_NODEBASE "iqn.2007-09.jp.ne.peach.istgt"
91 #define DEFAULT_PORT 3260
92 #define DEFAULT_MAX_SESSIONS 32
93 #define DEFAULT_MAX_CONNECTIONS 4
94 #define DEFAULT_MAXOUTSTANDINGR2T 16
95 #define DEFAULT_DEFAULTTIME2WAIT 2
96 #define DEFAULT_DEFAULTTIME2RETAIN 20
97 #define DEFAULT_FIRSTBURSTLENGTH 65536
98 #define DEFAULT_MAXBURSTLENGTH 262144
99 #define DEFAULT_MAXRECVDATASEGMENTLENGTH 8192
100 #define DEFAULT_INITIALR2T 1
101 #define DEFAULT_IMMEDIATEDATA 1
102 #define DEFAULT_DATAPDUINORDER 1
103 #define DEFAULT_DATASEQUENCEINORDER 1
104 #define DEFAULT_ERRORRECOVERYLEVEL 0
105 #define DEFAULT_TIMEOUT 60
106 #define DEFAULT_NOPININTERVAL 20
107 #define DEFAULT_MAXR2T 16
108 
109 #define ISTGT_PG_TAG_MAX 0x0000ffff
110 #define ISTGT_LU_TAG_MAX 0x0000ffff
111 #define ISTGT_UC_TAG     0x00010000
112 #define ISTGT_IOBUFSIZE (2 * 1024 * 1024)
113 #define ISTGT_SNSBUFSIZE 4096
114 #define ISTGT_SHORTDATASIZE 8192
115 #define ISTGT_SHORTPDUSIZE (48+4+ISTGT_SHORTDATASIZE+4)
116 #define ISTGT_CONDWAIT (50 * 1000) /* ms */
117 #define ISTGT_CONDWAIT_MIN (5 * 1000) /* ms */
118 #define ISTGT_STACKSIZE (2 * 1024 * 1024)
119 
120 #if defined (SIGRTMIN)
121 #define ISTGT_SIGWAKEUP (SIGRTMIN + 1)
122 #define ISTGT_USE_SIGRT
123 #elif defined (SIGIO)
124 #define ISTGT_SIGWAKEUP (SIGIO)
125 #else
126 #error "no signal for internal"
127 #endif
128 #if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__)
129 #define ISTGT_USE_KQUEUE
130 #if defined (__FreeBSD__)
131 #define ISTGT_EV_SET(kevp,a,b,c,d,e,f) EV_SET((kevp),(a),(b),(c),(d),(e),(void *)(f))
132 #elif defined (__NetBSD__)
133 #define ISTGT_EV_SET(kevp,a,b,c,d,e,f) EV_SET((kevp),(a),(b),(c),(d),(e),(intptr_t)(f))
134 #else
135 #define ISTGT_EV_SET(kevp,a,b,c,d,e,f) EV_SET((kevp),(a),(b),(c),(d),(e),(f))
136 #endif
137 #endif
138 
139 #define MTX_LOCK(MTX) \
140 	do {								\
141 		if (pthread_mutex_lock((MTX)) != 0) {			\
142 			ISTGT_ERRLOG("lock error\n");			\
143 			pthread_exit(NULL);				\
144 		}							\
145 	} while (0)
146 #define MTX_UNLOCK(MTX) \
147 	do {								\
148 		if (pthread_mutex_unlock((MTX)) != 0) {			\
149 			ISTGT_ERRLOG("unlock error\n");			\
150 			pthread_exit(NULL);				\
151 		}							\
152 	} while (0)
153 #define SPIN_LOCK(SPIN) \
154 	do {								\
155 		if (pthread_spin_lock((SPIN)) != 0) {			\
156 			ISTGT_ERRLOG("lock error\n");			\
157 			pthread_exit(NULL);				\
158 		}							\
159 	} while (0)
160 #define SPIN_UNLOCK(SPIN) \
161 	do {								\
162 		if (pthread_spin_unlock((SPIN)) != 0) {			\
163 			ISTGT_ERRLOG("unlock error\n");			\
164 			pthread_exit(NULL);				\
165 		}							\
166 	} while (0)
167 
168 typedef struct istgt_portal_t {
169 	char *label;
170 	char *host;
171 	char *port;
172 	int ref;
173 	int idx;
174 	int tag;
175 	int sock;
176 } PORTAL;
177 typedef PORTAL *PORTAL_Ptr;
178 
179 typedef struct istgt_portal_group_t {
180 	int nportals;
181 	PORTAL **portals;
182 	int ref;
183 	int idx;
184 	int tag;
185 } PORTAL_GROUP;
186 typedef PORTAL_GROUP *PORTAL_GROUP_Ptr;
187 
188 typedef struct istgt_initiator_group_t {
189 	int ninitiators;
190 	char **initiators;
191 	int nnetmasks;
192 	char **netmasks;
193 	int ref;
194 	int idx;
195 	int tag;
196 } INITIATOR_GROUP;
197 typedef INITIATOR_GROUP *INITIATOR_GROUP_Ptr;
198 
199 typedef enum {
200 	ISTGT_STATE_INVALID = 0,
201 	ISTGT_STATE_INITIALIZED = 1,
202 	ISTGT_STATE_RUNNING = 2,
203 	ISTGT_STATE_EXITING = 3,
204 	ISTGT_STATE_SHUTDOWN = 4,
205 } ISTGT_STATE;
206 
207 #define DEFAULT_ISTGT_SWMODE ISTGT_SWMODE_NORMAL
208 typedef enum {
209 	ISTGT_SWMODE_TRADITIONAL = 0,
210 	ISTGT_SWMODE_NORMAL = 1,
211 	ISTGT_SWMODE_EXPERIMENTAL = 2,
212 } ISTGT_SWMODE;
213 
214 typedef struct istgt_t {
215 	CONFIG *config;
216 	CONFIG *config_old;
217 	char *pidfile;
218 	char *authfile;
219 #if 0
220 	char *mediafile;
221 	char *livefile;
222 #endif
223 	char *mediadirectory;
224 	char *nodebase;
225 
226 	pthread_attr_t attr;
227 	pthread_mutexattr_t mutex_attr;
228 	pthread_mutex_t mutex;
229 	pthread_mutex_t state_mutex;
230 	pthread_mutex_t reload_mutex;
231 	pthread_cond_t reload_cond;
232 
233 	ISTGT_STATE state;
234 	ISTGT_SWMODE swmode;
235 	uint32_t generation;
236 	int sig_pipe[2];
237 	int daemon;
238 	int pg_reload;
239 
240 	int nuctl_portal;
241 	PORTAL uctl_portal[MAX_UCPORTAL];
242 	int nuctl_netmasks;
243 	char **uctl_netmasks;
244 
245 	int nportal_group;
246 	PORTAL_GROUP portal_group[MAX_PORTAL_GROUP];
247 	int ninitiator_group;
248 	INITIATOR_GROUP initiator_group[MAX_INITIATOR_GROUP];
249 	int nlogical_unit;
250 	struct istgt_lu_t *logical_unit[MAX_LOGICAL_UNIT];
251 
252 	int timeout;
253 	int nopininterval;
254 	int maxr2t;
255 	int no_discovery_auth;
256 	int req_discovery_auth;
257 	int req_discovery_auth_mutual;
258 	int discovery_auth_group;
259 	int no_uctl_auth;
260 	int req_uctl_auth;
261 	int req_uctl_auth_mutual;
262 	int uctl_auth_group;
263 
264 	int MaxSessions;
265 	int MaxConnections;
266 	int MaxOutstandingR2T;
267 	int DefaultTime2Wait;
268 	int DefaultTime2Retain;
269 	int FirstBurstLength;
270 	int MaxBurstLength;
271 	int MaxRecvDataSegmentLength;
272 	int InitialR2T;
273 	int ImmediateData;
274 	int DataPDUInOrder;
275 	int DataSequenceInOrder;
276 	int ErrorRecoveryLevel;
277 } ISTGT;
278 typedef ISTGT *ISTGT_Ptr;
279 
280 char *istgt_get_nmval(CF_SECTION *sp, const char *key, int idx1, int idx2);
281 char *istgt_get_nval(CF_SECTION *sp, const char *key, int idx);
282 char *istgt_get_val(CF_SECTION *sp, const char *key);
283 int istgt_get_nintval(CF_SECTION *sp, const char *key, int idx);
284 int istgt_get_intval(CF_SECTION *sp, const char *key);
285 
286 #ifdef USE_ATOMIC
287 static inline __attribute__((__always_inline__)) int
istgt_get_state(ISTGT_Ptr istgt)288 istgt_get_state(ISTGT_Ptr istgt)
289 {
290 	ISTGT_STATE state;
291 #if defined HAVE_ATOMIC_LOAD_ACQ_INT
292 	state = atomic_load_acq_int((unsigned int *)&istgt->state);
293 #elif defined HAVE_ATOMIC_OR_UINT_NV
294 	state = (int)atomic_or_uint_nv((unsigned int *)&istgt->state, 0);
295 #else
296 #error "no atomic operation"
297 #endif
298 	return state;
299 }
300 static inline __attribute__((__always_inline__)) void
istgt_set_state(ISTGT_Ptr istgt,ISTGT_STATE state)301 istgt_set_state(ISTGT_Ptr istgt, ISTGT_STATE state)
302 {
303 #if defined HAVE_ATOMIC_STORE_REL_INT
304 	atomic_store_rel_int((unsigned int *)&istgt->state, state);
305 #elif defined HAVE_ATOMIC_SWAP_UINT
306 	(void)atomic_swap_uint((unsigned int *)&istgt->state, state);
307 #if defined HAVE_MEMBAR_PRODUCER
308 	membar_producer();
309 #endif
310 #else
311 #error "no atomic operation"
312 #endif
313 }
314 #elif defined (USE_GCC_ATOMIC)
315 /* gcc >= 4.1 builtin functions */
316 static inline __attribute__((__always_inline__)) int
istgt_get_state(ISTGT_Ptr istgt)317 istgt_get_state(ISTGT_Ptr istgt)
318 {
319 	ISTGT_STATE state;
320 	state = __sync_fetch_and_add((unsigned int *)&istgt->state, 0);
321 	return state;
322 }
323 static inline __attribute__((__always_inline__)) void
istgt_set_state(ISTGT_Ptr istgt,ISTGT_STATE state)324 istgt_set_state(ISTGT_Ptr istgt, ISTGT_STATE state)
325 {
326 	ISTGT_STATE state_old;
327 	do {
328 		state_old = __sync_fetch_and_add((unsigned int *)&istgt->state, 0);
329 	} while (__sync_val_compare_and_swap((unsigned int *)&istgt->state,
330 		state_old, state) != state_old);
331 #if defined (HAVE_GCC_ATOMIC_SYNCHRONIZE)
332 	__sync_synchronize();
333 #endif
334 }
335 #else /* !USE_ATOMIC && !USE_GCC_ATOMIC */
336 static inline __attribute__((__always_inline__)) int
istgt_get_state(ISTGT_Ptr istgt)337 istgt_get_state(ISTGT_Ptr istgt)
338 {
339 	ISTGT_STATE state;
340 	MTX_LOCK(&istgt->state_mutex);
341 	state = istgt->state;
342 	MTX_UNLOCK(&istgt->state_mutex);
343 	return state;
344 }
345 
346 static inline __attribute__((__always_inline__)) void
istgt_set_state(ISTGT_Ptr istgt,ISTGT_STATE state)347 istgt_set_state(ISTGT_Ptr istgt, ISTGT_STATE state)
348 {
349 	MTX_LOCK(&istgt->state_mutex);
350 	istgt->state = state;
351 	MTX_UNLOCK(&istgt->state_mutex);
352 }
353 #endif /* USE_ATOMIC */
354 
355 #endif /* ISTGT_H */
356