490 lines
14 KiB
C
490 lines
14 KiB
C
/*
|
|
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or
|
|
* using the software you agree to this license. If you do not agree to this license, do not download, install,
|
|
* copy or use the software.
|
|
*
|
|
* Intel License Agreement
|
|
*
|
|
* Copyright (c) 2000, Intel Corporation
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
|
|
* the following conditions are met:
|
|
*
|
|
* -Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
|
* following disclaimer.
|
|
*
|
|
* -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
|
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
*
|
|
* -The name of Intel Corporation may not be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef _UTIL_H_
|
|
#define _UTIL_H_
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#ifdef HAVE_STDINT_H
|
|
#include <stdint.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_STRING_H
|
|
#include <string.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_PTHREAD_H
|
|
#include <pthread.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_UIO_H
|
|
#include <sys/uio.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_SOCKET_H
|
|
#include <sys/socket.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_FCNTL_H
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SYSLOG_H
|
|
#include <syslog.h>
|
|
#endif
|
|
|
|
/*
|
|
*
|
|
*/
|
|
|
|
#define ISCSI_HTONLL6(x) (uint64_t) \
|
|
( ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x0000ff0000000000uLL) >> 40)) \
|
|
| ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x000000ff00000000uLL) >> 24)) \
|
|
| ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x00000000ff000000uLL) >> 8)) \
|
|
| ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x0000000000ff0000uLL) << 8)) \
|
|
| ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x000000000000ff00uLL) << 24)) \
|
|
| ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x00000000000000ffuLL) << 40)))
|
|
|
|
#define ISCSI_NTOHLL6(x) (uint64_t) \
|
|
( ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x0000ff0000000000uLL) >> 40)) \
|
|
| ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x000000ff00000000uLL) >> 24)) \
|
|
| ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x00000000ff000000uLL) >> 8)) \
|
|
| ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x0000000000ff0000uLL) << 8)) \
|
|
| ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x000000000000ff00uLL) << 24)) \
|
|
| ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x00000000000000ffuLL) << 40)))
|
|
|
|
/*
|
|
* Debugging Levels
|
|
*/
|
|
|
|
#define TRACE_NET_DEBUG 0x00000001
|
|
#define TRACE_NET_BUFF 0x00000002
|
|
#define TRACE_NET_IOV 0x00000004
|
|
#define TRACE_NET_ALL (TRACE_NET_DEBUG|TRACE_NET_BUFF|TRACE_NET_IOV)
|
|
|
|
#define TRACE_ISCSI_DEBUG 0x00000010
|
|
#define TRACE_ISCSI_CMD 0x00000020
|
|
#define TRACE_ISCSI_ARGS 0x00000040
|
|
#define TRACE_ISCSI_PARAM 0x00000080
|
|
#define TRACE_ISCSI_ALL (TRACE_ISCSI_DEBUG|TRACE_ISCSI_ARGS|TRACE_ISCSI_PARAM|TRACE_ISCSI_CMD)
|
|
|
|
#define TRACE_SCSI_DEBUG 0x00000100
|
|
#define TRACE_SCSI_CMD 0x00000200
|
|
#define TRACE_SCSI_DATA 0x00000400
|
|
#define TRACE_SCSI_ARGS 0x00000800
|
|
#define TRACE_SCSI_ALL (TRACE_SCSI_DEBUG|TRACE_SCSI_CMD|TRACE_SCSI_DATA|TRACE_SCSI_ARGS)
|
|
|
|
#define TRACE_DEBUG 0x00001000
|
|
#define TRACE_HASH 0x00002000
|
|
#define TRACE_SYNC 0x00004000
|
|
#define TRACE_QUEUE 0x00008000
|
|
#define TRACE_WARN 0x00010000
|
|
#define TRACE_MEM 0x00020000
|
|
|
|
#define TRACE_OSD 0x00040000
|
|
#define TRACE_OSDFS 0x00080000
|
|
#define TRACE_OSDSO 0x00100000
|
|
#define TRACE_ALL 0xffffffff
|
|
|
|
/*
|
|
* Set debugging level here. Turn on debugging in Makefile.
|
|
*/
|
|
#ifndef EXTERN
|
|
#define EXTERN extern
|
|
#endif
|
|
|
|
EXTERN uint32_t iscsi_debug_level;
|
|
|
|
/*
|
|
* Debugging Functions
|
|
*/
|
|
void set_debug(const char *);
|
|
void iscsi_trace(const int, const char *, const int, const char *, ...);
|
|
void iscsi_trace_warning(const char *, const int, const char *, ...);
|
|
void iscsi_trace_error(const char *, const int, const char *, ...);
|
|
void iscsi_print_buffer(const char *, const size_t);
|
|
|
|
|
|
/*
|
|
* Byte Order
|
|
*/
|
|
|
|
#ifdef HAVE_ASM_BYTEORDER_H
|
|
#include <asm/byteorder.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_BYTEORDER_H
|
|
#include <sys/byteorder.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_BYTESWAP_H
|
|
#include <byteswap.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_MACHINE_ENDIAN_H
|
|
#include <machine/endian.h>
|
|
#endif
|
|
|
|
#define __BYTE_ORDER _BYTE_ORDER
|
|
#define __BIG_ENDIAN _BIG_ENDIAN
|
|
#define __LITTLE_ENDIAN _LITTLE_ENDIAN
|
|
|
|
#define ISCSI_NTOHLL(a) ISCSI_BE64TOH(a)
|
|
#define ISCSI_HTONLL(a) ISCSI_HTOBE64(a)
|
|
#define ISCSI_NTOHL(a) ntohl(a)
|
|
#define ISCSI_HTONL(a) htonl(a)
|
|
#define ISCSI_NTOHS(a) ntohs(a)
|
|
#define ISCSI_HTONS(a) htons(a)
|
|
|
|
#define ISCSI_GETPID getpid()
|
|
|
|
#ifndef HAVE_SOCKLEN_T
|
|
typedef int socklen_t;
|
|
#endif
|
|
|
|
/*
|
|
* Sleeping
|
|
*/
|
|
|
|
#define ISCSI_SLEEP(N) sleep(N)
|
|
|
|
/*
|
|
* Memory
|
|
*/
|
|
|
|
void *iscsi_malloc(unsigned);
|
|
void iscsi_free(void *);
|
|
void *iscsi_malloc_atomic(unsigned);
|
|
void iscsi_free_atomic(void *);
|
|
|
|
/*
|
|
* Comparison
|
|
*/
|
|
|
|
#ifndef MIN
|
|
#define MIN(A,B) (((A)<(B))?(A):(B))
|
|
#endif
|
|
|
|
#define MIN_3(A,B,C) (((A)<(B))?(((A)<(C))?(A):(C)):(((B)<(C))?(B):(C)))
|
|
|
|
/* Spin locks */
|
|
|
|
typedef pthread_mutex_t iscsi_spin_t;
|
|
|
|
int iscsi_spin_init(iscsi_spin_t * );
|
|
int iscsi_spin_lock(iscsi_spin_t * );
|
|
int iscsi_spin_unlock(iscsi_spin_t * );
|
|
int iscsi_spin_lock_irqsave(iscsi_spin_t * , uint32_t *);
|
|
int iscsi_spin_unlock_irqrestore(iscsi_spin_t * , uint32_t *);
|
|
int iscsi_spin_destroy(iscsi_spin_t * );
|
|
|
|
/*
|
|
* End of ISCSI spin routines
|
|
*/
|
|
|
|
/*
|
|
* Tags
|
|
*/
|
|
|
|
#define ISCSI_SET_TAG(tag) do { \
|
|
iscsi_spin_lock(&g_tag_spin); \
|
|
*tag = g_tag++; \
|
|
iscsi_spin_unlock(&g_tag_spin); \
|
|
} while (/* CONSTCOND */ 0)
|
|
|
|
#define ISCSI_SET_TAG_IN_INTR(tag) do { \
|
|
uint32_t flags; \
|
|
iscsi_spin_lock_irqsave(&g_tag_spin, &flags); \
|
|
*tag = g_tag++; \
|
|
iscsi_spin_unlock_irqrestore(&g_tag_spin, &flags); \
|
|
} while (/* CONSTCOND */ 0)
|
|
|
|
|
|
|
|
/*
|
|
* Hashing
|
|
*/
|
|
|
|
|
|
typedef struct hash_t {
|
|
struct initiator_cmd_t **bucket;
|
|
int collisions;
|
|
int insertions;
|
|
int n;
|
|
iscsi_spin_t lock;
|
|
} hash_t;
|
|
|
|
int hash_init(hash_t * , int );
|
|
int hash_insert(hash_t * , struct initiator_cmd_t * , uint32_t );
|
|
struct initiator_cmd_t *hash_remove(hash_t * , uint32_t );
|
|
int hash_destroy(hash_t * );
|
|
|
|
/*
|
|
* Queuing
|
|
*/
|
|
|
|
typedef struct iscsi_queue_t {
|
|
int head;
|
|
int tail;
|
|
int count;
|
|
void **elem;
|
|
int depth;
|
|
iscsi_spin_t lock;
|
|
} iscsi_queue_t;
|
|
|
|
int iscsi_queue_init(iscsi_queue_t * , int );
|
|
void iscsi_queue_destroy(iscsi_queue_t * );
|
|
int iscsi_queue_insert(iscsi_queue_t * , void *);
|
|
void *iscsi_queue_remove(iscsi_queue_t * );
|
|
int iscsi_queue_depth(iscsi_queue_t * );
|
|
int iscsi_queue_full(iscsi_queue_t * );
|
|
|
|
/*
|
|
* Socket Abstraction
|
|
*/
|
|
|
|
typedef int iscsi_socket_t;
|
|
|
|
/* Turning off Nagle's Algorithm doesn't always seem to work, */
|
|
/* so we combine two messages into one when the second's size */
|
|
/* is less than or equal to ISCSI_SOCK_HACK_CROSSOVER. */
|
|
|
|
#define ISCSI_SOCK_HACK_CROSSOVER 1024
|
|
#define ISCSI_SOCK_CONNECT_NONBLOCK 0
|
|
#define ISCSI_SOCK_CONNECT_TIMEOUT 1
|
|
#define ISCSI_SOCK_MSG_BYTE_ALIGN 4
|
|
|
|
int iscsi_sock_create(iscsi_socket_t * );
|
|
int iscsi_socks_establish(iscsi_socket_t *, int *, int *, int);
|
|
int iscsi_waitfor_connection(iscsi_socket_t *, int, const char *cf, iscsi_socket_t *);
|
|
const char *iscsi_address_family(int);
|
|
int iscsi_sock_setsockopt(iscsi_socket_t * , int , int , void *, unsigned );
|
|
int iscsi_sock_getsockopt(iscsi_socket_t * , int , int , void *, unsigned *);
|
|
int iscsi_sock_bind(iscsi_socket_t , int );
|
|
int iscsi_sock_listen(iscsi_socket_t );
|
|
int iscsi_sock_connect(iscsi_socket_t , char *, int );
|
|
int iscsi_sock_accept(iscsi_socket_t , iscsi_socket_t * );
|
|
int iscsi_sock_shutdown(iscsi_socket_t , int );
|
|
int iscsi_sock_close(iscsi_socket_t );
|
|
int iscsi_sock_msg(iscsi_socket_t , int , unsigned , void *, int );
|
|
int iscsi_sock_send_header_and_data(iscsi_socket_t ,
|
|
void *, unsigned ,
|
|
const void *, unsigned , int );
|
|
int iscsi_sock_getsockname(iscsi_socket_t , struct sockaddr * , unsigned *);
|
|
int iscsi_sock_getpeername(iscsi_socket_t , struct sockaddr * , unsigned *);
|
|
int modify_iov(struct iovec ** , int *, uint32_t , uint32_t );
|
|
|
|
|
|
void cdb2lba(uint32_t *, uint16_t *, uint8_t *);
|
|
void lba2cdb(uint8_t *, uint32_t *, uint16_t *);
|
|
|
|
/*
|
|
* Mutexes
|
|
*/
|
|
|
|
typedef pthread_mutex_t iscsi_mutex_t;
|
|
|
|
int iscsi_mutex_init(iscsi_mutex_t * );
|
|
int iscsi_mutex_lock(iscsi_mutex_t * );
|
|
int iscsi_mutex_unlock(iscsi_mutex_t * );
|
|
int iscsi_mutex_destroy(iscsi_mutex_t * );
|
|
|
|
#define ISCSI_LOCK(M, ELSE) do { \
|
|
if (iscsi_mutex_lock(M) != 0) { \
|
|
iscsi_trace_error(__FILE__, __LINE__, "iscsi_mutex_lock() failed\n"); \
|
|
ELSE; \
|
|
} \
|
|
} while (/* CONSTCOND */ 0)
|
|
|
|
#define ISCSI_UNLOCK(M, ELSE) do { \
|
|
if (iscsi_mutex_unlock(M) != 0) { \
|
|
iscsi_trace_error(__FILE__, __LINE__, "iscsi_mutex_unlock() failed\n"); \
|
|
ELSE; \
|
|
} \
|
|
} while (/* CONSTCOND */ 0)
|
|
|
|
#define ISCSI_MUTEX_INIT(M, ELSE) do { \
|
|
if (iscsi_mutex_init(M) != 0) { \
|
|
iscsi_trace_error(__FILE__, __LINE__, "iscsi_mutex_init() failed\n"); \
|
|
ELSE; \
|
|
} \
|
|
} while (/* CONSTCOND */ 0)
|
|
|
|
#define ISCSI_MUTEX_DESTROY(M, ELSE) do { \
|
|
if (iscsi_mutex_destroy(M) != 0) { \
|
|
iscsi_trace_error(__FILE__, __LINE__, "iscsi_mutex_destroy() failed\n"); \
|
|
ELSE; \
|
|
} \
|
|
} while (/* CONSTCOND */ 0)
|
|
|
|
/*
|
|
* Condition Variable
|
|
*/
|
|
|
|
typedef pthread_cond_t iscsi_cond_t;
|
|
|
|
int iscsi_cond_init(iscsi_cond_t * );
|
|
int iscsi_cond_wait(iscsi_cond_t * , iscsi_mutex_t * );
|
|
int iscsi_cond_signal(iscsi_cond_t * );
|
|
int iscsi_cond_destroy(iscsi_cond_t * );
|
|
|
|
#define ISCSI_COND_INIT(C, ELSE) do { \
|
|
if (iscsi_cond_init(C) != 0) { \
|
|
ELSE; \
|
|
} \
|
|
} while (/* CONSTCOND */ 0)
|
|
|
|
#define ISCSI_WAIT(C, M, ELSE) do { \
|
|
if (iscsi_cond_wait(C, M) != 0) { \
|
|
ELSE; \
|
|
} \
|
|
} while (/* CONSTCOND */ 0)
|
|
|
|
#define ISCSI_SIGNAL(C, ELSE) do { \
|
|
if (iscsi_cond_signal(C) != 0) { \
|
|
ELSE; \
|
|
} \
|
|
} while (/* CONSTCOND */ 0)
|
|
|
|
#define ISCSI_COND_DESTROY(C, ELSE) do { \
|
|
if (iscsi_cond_destroy(C) != 0) { \
|
|
ELSE; \
|
|
} \
|
|
} while (/* CONSTCOND */ 0)
|
|
|
|
/*
|
|
* Threading Routines
|
|
*/
|
|
|
|
typedef struct iscsi_thread_t {
|
|
pthread_t pthread;
|
|
} iscsi_thread_t;
|
|
|
|
int iscsi_thread_create(iscsi_thread_t * , void *(*proc) (void *), void *);
|
|
|
|
#define ISCSI_SET_THREAD(ME) /* for user pthread id set by pthread_create
|
|
* in iscsi_thread_create */
|
|
#define ISCSI_THREAD_START(NAME)
|
|
|
|
/*
|
|
* Worker Thread
|
|
*/
|
|
|
|
#define ISCSI_WORKER_STATE_STARTED 1
|
|
#define ISCSI_WORKER_STATE_ERROR 2
|
|
#define ISCSI_WORKER_STATE_EXITING 4
|
|
|
|
typedef struct {
|
|
iscsi_thread_t thread;
|
|
iscsi_mutex_t work_mutex;
|
|
iscsi_cond_t work_cond;
|
|
iscsi_mutex_t exit_mutex;
|
|
iscsi_cond_t exit_cond;
|
|
int id;
|
|
int pid;
|
|
volatile uint32_t state;
|
|
} iscsi_worker_t;
|
|
|
|
#define ISCSI_WORKER_EXIT(ME) do { \
|
|
iscsi_trace(TRACE_ISCSI_DEBUG ,__FILE__, __LINE__, "exiting\n"); \
|
|
(ME)->state |= ISCSI_WORKER_STATE_EXITING; \
|
|
return 0; \
|
|
} while (/* CONSTCOND */ 0)
|
|
|
|
/*
|
|
* Spin Lock
|
|
*/
|
|
#define ISCSI_SPIN
|
|
|
|
/*
|
|
* Pre/Post condition checking
|
|
*/
|
|
|
|
#define NO_CLEANUP {}
|
|
#define RETURN_GREATER(NAME, V1, V2, CU, RC) \
|
|
if ((V1)>(V2)) { \
|
|
iscsi_trace_error(__FILE__, __LINE__, "Bad \"%s\": %u > %u.\n", NAME, (unsigned)V1, (unsigned)V2); \
|
|
CU; \
|
|
return RC; \
|
|
}
|
|
|
|
#define RETURN_NOT_EQUAL(NAME, V1, V2, CU, RC) \
|
|
if ((V1)!=(V2)) { \
|
|
iscsi_trace_error(__FILE__, __LINE__, "Bad \"%s\": Got %u expected %u.\n", NAME, V1, V2); \
|
|
CU; \
|
|
return RC; \
|
|
}
|
|
|
|
#define WARN_NOT_EQUAL(NAME, V1, V2) \
|
|
if ((V1)!=(V2)) { \
|
|
iscsi_trace_warning(__FILE__, __LINE__, "Bad \"%s\": Got %u expected %u.\n", NAME, V1, V2); \
|
|
}
|
|
|
|
#define RETURN_EQUAL(NAME, V1, V2, CU, RC) \
|
|
if ((V1)==(V2)) { \
|
|
iscsi_trace_error(__FILE__, __LINE__, "Bad \"%s\": %u == %u.\n", NAME, V1, V2); \
|
|
CU; \
|
|
return RC; \
|
|
}
|
|
|
|
/*
|
|
* Misc. Functions
|
|
*/
|
|
|
|
uint32_t iscsi_atoi(char *);
|
|
int HexTextToData(const char *, uint32_t , uint8_t *, uint32_t );
|
|
int HexDataToText(uint8_t *, uint32_t , char *, uint32_t );
|
|
void GenRandomData(uint8_t *, uint32_t );
|
|
|
|
/* this is the maximum number of iovecs which we can use in iscsi_sock_send_header_and_data */
|
|
#ifndef ISCSI_MAX_IOVECS
|
|
#define ISCSI_MAX_IOVECS 32
|
|
#endif
|
|
|
|
enum {
|
|
/* used in iscsi_sock_msg() */
|
|
Receive = 0,
|
|
Transmit = 1
|
|
};
|
|
|
|
int allow_netmask(const char *, const char *);
|
|
|
|
#endif /* _UTIL_H_ */
|