2 * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
3 * By downloading, copying, installing or using the software you agree
4 * to this license. If you do not agree to this license, do not
5 * download, install, copy or use the software.
7 * Intel License Agreement
9 * Copyright (c) 2000, Intel Corporation
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
16 * -Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
19 * -Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the
24 * -The name of Intel Corporation may not be used to endorse or
25 * promote products derived from this software without specific prior
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
35 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
36 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 #include <sys/types.h>
46 #ifdef HAVE_SYS_SOCKET_H
47 #include <sys/socket.h>
54 #ifdef HAVE_ARPA_INET_H
55 #include <arpa/inet.h>
58 #ifdef HAVE_NETINET_IN_H
59 #include <netinet/in.h>
62 #ifdef HAVE_NETINET_TCP_H
63 #include <netinet/tcp.h>
86 #ifdef HAVE_SYS_SELECT_H
87 #include <sys/select.h>
106 #include "iscsiutil.h"
115 iscsi_malloc_atomic(unsigned n
)
120 iscsi_trace(TRACE_MEM
, "iscsi_malloc_atomic(%u) = %p\n", n
, ptr
);
125 iscsi_malloc(unsigned n
)
130 iscsi_trace(TRACE_MEM
, "iscsi_malloc(%u) = %p\n", n
, ptr
);
135 iscsi_free_atomic(void *ptr
)
138 iscsi_trace(TRACE_MEM
, "iscsi_free_atomic(%p)\n", ptr
);
142 iscsi_free(void *ptr
)
145 iscsi_trace(TRACE_MEM
, "iscsi_free(%p)\n", ptr
);
148 /* debugging levels */
150 set_debug(const char *level
)
152 if (strcmp(level
, "net") == 0) {
153 iscsi_debug_level
|= TRACE_NET_ALL
;
154 } else if (strcmp(level
, "iscsi") == 0) {
155 iscsi_debug_level
|= TRACE_ISCSI_ALL
;
156 } else if (strcmp(level
, "scsi") == 0) {
157 iscsi_debug_level
|= TRACE_SCSI_ALL
;
158 } else if (strcmp(level
, "osd") == 0) {
159 iscsi_debug_level
|= TRACE_OSD
;
160 } else if (strcmp(level
, "all") == 0) {
161 iscsi_debug_level
|= TRACE_ALL
;
169 iscsi_thread_create(iscsi_thread_t
* thread
, void *(*proc
) (void *), void *arg
)
171 if (pthread_create(&thread
->pthread
, NULL
, proc
, arg
) != 0) {
172 iscsi_err(__FILE__
, __LINE__
, "pthread_create() failed\n");
175 if (pthread_detach(thread
->pthread
) != 0) {
176 iscsi_err(__FILE__
, __LINE__
, "pthread_detach() failed\n");
186 iscsi_queue_init(iscsi_queue_t
* q
, int depth
)
188 q
->head
= q
->tail
= q
->count
= 0;
190 q
->elem
= iscsi_malloc_atomic((unsigned)(depth
* sizeof(void *)));
191 if (q
->elem
== NULL
) {
192 iscsi_err(__FILE__
, __LINE__
, "iscsi_malloc_atomic() failed\n");
195 iscsi_spin_init(&q
->lock
);
200 iscsi_queue_destroy(iscsi_queue_t
* q
)
202 iscsi_free_atomic(q
->elem
);
206 iscsi_queue_full(iscsi_queue_t
* q
)
208 return (q
->count
== q
->depth
);
212 iscsi_queue_depth(iscsi_queue_t
* q
)
218 iscsi_queue_insert(iscsi_queue_t
* q
, void *ptr
)
222 iscsi_spin_lock_irqsave(&q
->lock
, &flags
);
223 if (iscsi_queue_full(q
)) {
224 iscsi_err(__FILE__
, __LINE__
, "QUEUE FULL\n");
225 iscsi_spin_unlock_irqrestore(&q
->lock
, &flags
);
228 q
->elem
[q
->tail
] = ptr
;
230 if (q
->tail
== q
->depth
) {
234 iscsi_spin_unlock_irqrestore(&q
->lock
, &flags
);
239 iscsi_queue_remove(iscsi_queue_t
*q
)
244 iscsi_spin_lock_irqsave(&q
->lock
, &flags
);
245 if (!iscsi_queue_depth(q
)) {
246 iscsi_trace(TRACE_QUEUE
, "QUEUE EMPTY\n");
247 iscsi_spin_unlock_irqrestore(&q
->lock
, &flags
);
251 ptr
= q
->elem
[q
->head
];
253 if (q
->head
== q
->depth
) {
256 iscsi_spin_unlock_irqrestore(&q
->lock
, &flags
);
261 iscsi_trace(const int trace
, const char *fmt
, ...)
263 #ifdef CONFIG_ISCSI_DEBUG
267 if (iscsi_debug_level
& trace
) {
269 (void) vsnprintf(buf
, sizeof(buf
), fmt
, vp
);
270 printf("pid %d: %s", (int) getpid(), buf
);
277 iscsi_warn(const char *f
, const int line
, const char *fmt
, ...)
279 #ifdef CONFIG_ISCSI_DEBUG
283 if (iscsi_debug_level
& TRACE_WARN
) {
285 (void) vsnprintf(buf
, sizeof(buf
), fmt
, vp
);
286 printf("pid %d:%s:%d: ***WARNING*** %s",
287 (int) getpid(), f
, line
,
295 iscsi_err(const char *f
, const int line
, const char *fmt
, ...)
297 #ifdef CONFIG_ISCSI_DEBUG
302 (void) vsnprintf(buf
, sizeof(buf
), fmt
, vp
);
304 printf("pid %d:%s:%d: ***ERROR*** %s", (int) getpid(), f
, line
, buf
);
306 syslog(LOG_ERR
, "pid %d:%s:%d: ***ERROR*** %s", getpid(), f
, line
, buf
);
307 # endif /* HAVE_SYSLOG */
312 iscsi_print_buffer(const char *buf
, const size_t len
)
314 #ifdef CONFIG_ISCSI_DEBUG
317 if (iscsi_debug_level
& TRACE_NET_BUFF
) {
318 for (i
=0 ; i
< len
; i
++) {
325 printf("%2x ", (uint8_t) (buf
)[i
]);
327 if ((len
+ 1) % 32) {
337 #include "initiator.h"
340 hash_init(hash_t
* h
, int n
)
344 iscsi_spin_init(&h
->lock
);
348 h
->bucket
= iscsi_malloc_atomic(n
* sizeof(initiator_cmd_t
*));
349 if (h
->bucket
== NULL
) {
350 iscsi_err(__FILE__
, __LINE__
, "iscsi_malloc_atomic() failed\n");
353 for (i
= 0; i
< n
; i
++)
359 hash_insert(hash_t
* h
, initiator_cmd_t
* cmd
, unsigned key
)
363 iscsi_spin_lock(&h
->lock
);
364 cmd
->hash_next
= NULL
;
368 if (h
->bucket
[i
] == NULL
) {
369 iscsi_trace(TRACE_HASH
,
370 "inserting key %u (val 0x%p) into bucket[%d]\n",
374 cmd
->hash_next
= h
->bucket
[i
];
377 iscsi_trace(TRACE_HASH
,
378 "inserting key %u (val 0x%p) into bucket[%d] "
379 "(collision)\n", key
, cmd
, i
);
382 iscsi_spin_unlock(&h
->lock
);
386 struct initiator_cmd_t
*
387 hash_remove(hash_t
* h
, unsigned key
)
389 initiator_cmd_t
*prev
;
390 initiator_cmd_t
*curr
;
393 iscsi_spin_lock(&h
->lock
);
395 if (h
->bucket
[i
] == NULL
) {
396 iscsi_err(__FILE__
, __LINE__
, "bucket emtpy\n");
401 while ((curr
->key
!= key
) && (curr
->hash_next
!= NULL
)) {
403 curr
= curr
->hash_next
;
405 if (curr
->key
!= key
) {
406 iscsi_err(__FILE__
, __LINE__
,
407 "key %u (%#x) not found in bucket[%d]\n",
412 h
->bucket
[i
] = h
->bucket
[i
]->hash_next
;
413 iscsi_trace(TRACE_HASH
,
414 "removed key %u (val 0x%p) from head "
415 "of bucket\n", key
, curr
);
417 prev
->hash_next
= curr
->hash_next
;
418 if (prev
->hash_next
== NULL
) {
419 iscsi_trace(TRACE_HASH
,
420 "removed key %u (val 0x%p) "
421 "from end of bucket\n", key
,
424 iscsi_trace(TRACE_HASH
,
425 "removed key %u (val 0x%p) "
426 "from middle of bucket\n",
432 iscsi_spin_unlock(&h
->lock
);
437 hash_destroy(hash_t
* h
)
439 iscsi_free_atomic(h
->bucket
);
448 modify_iov(struct iovec
** iov_ptr
, int *iovc
, uint32_t offset
, uint32_t length
)
453 struct iovec
*iov
= *iov_ptr
;
456 /* Given <offset>, find beginning iovec and modify its base
459 for (i
= 0; i
< *iovc
; i
++) {
460 len
+= iov
[i
].iov_len
;
462 iscsi_trace(TRACE_NET_IOV
,
463 "found offset %u in iov[%d]\n", offset
, i
);
466 disp
-= iov
[i
].iov_len
;
469 iscsi_err(__FILE__
, __LINE__
,
470 "sum of iov lens (%u) < offset (%u)\n", len
, offset
);
473 iov
[i
].iov_len
-= disp
;
474 basep
= iov
[i
].iov_base
;
476 iov
[i
].iov_base
= basep
;
478 *iov_ptr
= &(iov
[i
]);
482 * Given <length>, find ending iovec and modify its length (base does
485 len
= 0; /* we should re-use len and i here... */
486 for (i
= 0; i
< *iovc
; i
++) {
487 len
+= iov
[i
].iov_len
;
489 iscsi_trace(TRACE_NET_IOV
,
490 "length %u ends in iovec[%d]\n", length
, i
);
495 iscsi_err(__FILE__
, __LINE__
,
496 "sum of iovec lens (%u) < length (%u)\n", len
, length
);
497 for (i
= 0; i
< *iovc
; i
++) {
498 iscsi_err(__FILE__
, __LINE__
,
499 "iov[%d].iov_base = %p (len %u)\n",
500 i
, iov
[i
].iov_base
, (unsigned)iov
[i
].iov_len
);
504 iov
[i
].iov_len
-= (len
- length
);
507 #ifdef CONFIG_ISCSI_DEBUG
508 iscsi_trace(TRACE_NET_IOV
, "new iov:\n");
510 for (i
= 0; i
< *iovc
; i
++) {
511 iscsi_trace(TRACE_NET_IOV
, "iov[%d].iov_base = %p (len %u)\n",
512 i
, iov
[i
].iov_base
, (unsigned)iov
[i
].iov_len
);
513 len
+= iov
[i
].iov_len
;
515 iscsi_trace(TRACE_NET_IOV
, "new iov length: %u bytes\n", len
);
522 iscsi_sock_setsockopt(int * sock
, int level
, int optname
, void *optval
,
527 if ((rc
= setsockopt(*sock
, level
, optname
, optval
, optlen
)) != 0) {
528 iscsi_err(__FILE__
, __LINE__
,
529 "sock->ops->setsockopt() failed: rc %d errno %d\n",
537 iscsi_sock_getsockopt(int * sock
, int level
, int optname
, void *optval
, unsigned *optlen
)
541 if ((rc
= getsockopt(*sock
, level
, optname
, optval
, optlen
)) != 0) {
542 iscsi_err(__FILE__
, __LINE__
,
543 "sock->ops->getsockopt() failed: rc %d errno %d\n",
551 iscsi_sock_create(int * sock
)
555 if ((*sock
= rc
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
556 iscsi_err(__FILE__
, __LINE__
,
557 "socket() failed: rc %d errno %d\n", rc
, errno
);
564 iscsi_sock_bind(int sock
, int port
)
566 struct sockaddr_in laddr
;
569 (void) memset(&laddr
, 0x0, sizeof(laddr
));
570 laddr
.sin_family
= AF_INET
;
571 laddr
.sin_addr
.s_addr
= INADDR_ANY
;
572 laddr
.sin_port
= ISCSI_HTONS(port
);
573 rc
= bind(sock
, (struct sockaddr
*) (void *) &laddr
, sizeof(laddr
));
575 iscsi_err(__FILE__
, __LINE__
,
576 "bind() failed: rc %d errno %d\n", rc
, errno
);
583 iscsi_sock_listen(int sock
)
587 if ((rc
= listen(sock
, 32)) < 0) {
588 iscsi_err(__FILE__
, __LINE__
,
589 "listen() failed: rc %d errno %d\n", rc
, errno
);
595 #ifndef ISCSI_MAXSOCK
596 #define ISCSI_MAXSOCK 8
600 iscsi_socks_establish(int *sockv
, int *famv
, int *sockc
, char *family
, int port
)
602 struct addrinfo hints
;
603 struct addrinfo
*res
;
604 struct addrinfo
*res0
;
605 const char *cause
= NULL
;
610 (void) memset(&hints
, 0x0, sizeof(hints
));
611 hints
.ai_family
= (strcmp(family
, "unspec") == 0) ? PF_UNSPEC
:
612 (strcmp(family
, "4") == 0) ? AF_INET
: AF_INET6
;
613 hints
.ai_socktype
= SOCK_STREAM
;
614 hints
.ai_flags
= AI_PASSIVE
;
615 #ifdef AI_NUMERICSERV
616 hints
.ai_flags
|= AI_NUMERICSERV
;
618 (void) snprintf(portnum
, sizeof(portnum
), "%d", port
);
619 if ((error
= getaddrinfo(NULL
, portnum
, &hints
, &res0
)) != 0) {
620 hints
.ai_flags
= AI_PASSIVE
;
621 if ((error
= getaddrinfo(NULL
, "iscsi-target", &hints
,
623 (error
= getaddrinfo(NULL
, "iscsi", &hints
, &res0
)) != 0) {
624 iscsi_err(__FILE__
, __LINE__
, "getaddrinfo: %s",
625 gai_strerror(error
));
630 for (res
= res0
; res
&& *sockc
< ISCSI_MAXSOCK
; res
= res
->ai_next
) {
631 sockv
[*sockc
] = socket(res
->ai_family
, res
->ai_socktype
,
633 if (sockv
[*sockc
] < 0) {
637 famv
[*sockc
] = res
->ai_family
;
638 if (!iscsi_sock_setsockopt(&sockv
[*sockc
], SOL_SOCKET
,
639 SO_REUSEADDR
, &one
, sizeof(one
))) {
640 iscsi_err(__FILE__
, __LINE__
,
641 "iscsi_sock_setsockopt() failed\n");
644 if (!iscsi_sock_setsockopt(&sockv
[*sockc
], SOL_TCP
,
645 TCP_NODELAY
, &one
, sizeof(one
))) {
646 iscsi_err(__FILE__
, __LINE__
,
647 "iscsi_sock_setsockopt() failed\n");
651 if (bind(sockv
[*sockc
], res
->ai_addr
, res
->ai_addrlen
) < 0) {
653 close(sockv
[*sockc
]);
656 (void) listen(sockv
[*sockc
], 32);
660 iscsi_err(__FILE__
, __LINE__
,
661 "iscsi_sock_establish: no sockets found: %s", cause
);
669 /* return the address family for the socket */
671 iscsi_address_family(int fam
)
679 return "[unknown type]";
683 /* wait for a connection to come in on a socket */
686 iscsi_waitfor_connection(int *sockv
, int sockc
, const char *cf
, int *sock
)
689 struct pollfd socks
[ISCSI_MAXSOCK
];
693 for (i
= 0 ; i
< sockc
; i
++) {
694 socks
[i
].fd
= sockv
[i
];
695 socks
[i
].events
= POLLIN
;
696 socks
[i
].revents
= 0;
698 switch(poll(socks
, (unsigned)sockc
, INFTIM
)) {
700 /* interrupted system call */
706 for (i
= 0 ; i
< sockc
; i
++) {
707 if (socks
[i
].revents
& POLLIN
) {
708 iscsi_trace(TRACE_NET_DEBUG
,
709 "connection %d selected\n",
723 for (i
= 0 ; i
< sockc
; i
++) {
724 FD_SET(sockv
[i
], &infds
);
726 iscsi_trace(TRACE_NET_DEBUG
, "waiting for connection\n");
727 switch (select(32, &infds
, NULL
, NULL
, NULL
)) {
729 /* interrupted system call */
735 for (i
= 0 ; i
< sockc
; i
++) {
736 if (FD_ISSET(sockv
[i
], &infds
)) {
737 iscsi_trace(TRACE_NET_DEBUG
,
738 "connection %d selected\n",
750 iscsi_sock_accept(int sock
, int *conn
)
752 struct sockaddr_in peer
;
755 peerlen
= sizeof(peer
);
756 (void) memset(&peer
, 0, sizeof(peer
));
757 *conn
= accept(sock
, (struct sockaddr
*)(void *)&peer
, &peerlen
);
759 iscsi_trace(TRACE_NET_DEBUG
,
760 "accept() failed: rc %d errno %d\n", *conn
, errno
);
768 iscsi_sock_getsockname(int sock
, struct sockaddr
* name
, unsigned *namelen
)
770 if (getsockname(sock
, name
, namelen
) != 0) {
771 iscsi_err(__FILE__
, __LINE__
,
772 "getsockame() failed (errno %d)\n", errno
);
779 iscsi_sock_getpeername(int sock
, struct sockaddr
* name
, unsigned *namelen
)
781 if (getpeername(sock
, name
, namelen
) != 0) {
782 iscsi_err(__FILE__
, __LINE__
,
783 "getpeername() failed (errno %d)\n", errno
);
790 iscsi_sock_shutdown(int sock
, int how
)
794 if ((rc
= shutdown(sock
, how
)) != 0) {
795 iscsi_trace(TRACE_NET_DEBUG
,
796 "shutdown() failed: rc %d, errno %d\n", rc
, errno
);
802 iscsi_sock_close(int sock
)
806 if ((rc
= close(sock
)) != 0) {
807 iscsi_err(__FILE__
, __LINE__
,
808 "close() failed: rc %d errno %d\n", rc
, errno
);
815 iscsi_sock_connect(int sock
, char *hostname
, int port
)
817 struct addrinfo hints
;
818 struct addrinfo
*res
;
823 (void) memset(&hints
, 0, sizeof(hints
));
824 hints
.ai_family
= AF_INET
;
825 hints
.ai_socktype
= SOCK_STREAM
;
826 (void) snprintf(portstr
, sizeof(portstr
), "%d", port
);
828 for (i
= 0; i
< ISCSI_SOCK_CONNECT_TIMEOUT
; i
++) {
829 /* Attempt connection */
830 #ifdef AI_NUMERICSERV
831 hints
.ai_flags
= AI_NUMERICSERV
;
833 if ((rc
= getaddrinfo(hostname
, portstr
, &hints
, &res
)) != 0) {
835 if ((rc
= getaddrinfo(hostname
, "iscsi-target", &hints
,
837 (rc
= getaddrinfo(hostname
, "iscsi", &hints
,
839 iscsi_err(__FILE__
, __LINE__
,
840 "getaddrinfo: %s", gai_strerror(rc
));
845 #if ISCSI_SOCK_CONNECT_NONBLOCK == 1
846 if (fcntl(sock
, F_SETFL
, O_NONBLOCK
) != 0) {
847 iscsi_err(__FILE__
, __LINE__
,
848 "fcntl O_NONBLOCK failed");
853 rc
= connect(sock
, res
->ai_addr
, res
->ai_addrlen
);
854 #if ISCSI_SOCK_CONNECT_NONBLOCK == 1
855 if (fcntl(sock
, F_SETFL
, O_SYNC
) != 0) {
856 iscsi_err(__FILE__
, __LINE__
, "fcntl O_SYNC failed\n");
863 if (errno
== EISCONN
) {
867 if (errno
== EAGAIN
||
868 errno
== EINPROGRESS
||
870 if (i
!= ISCSI_SOCK_CONNECT_TIMEOUT
- 1) {
871 printf("***SLEEPING***\n");
880 iscsi_err(__FILE__
, __LINE__
,
881 "connect() to %s:%d failed (errno %d)\n", hostname
,
888 * NOTE: iscsi_sock_msg() alters *sg when socket sends and recvs
889 * return having only transfered a portion of the iovec. When this
890 * happens, the iovec is modified and resent with the appropriate
895 iscsi_sock_msg(int sock
, int xmit
, unsigned len
, void *data
, int iovc
)
897 struct iovec singleton
;
899 struct iovec
*iov_padding
= NULL
;
902 uint32_t padding_len
= 0;
903 uint8_t padding
[ISCSI_SOCK_MSG_BYTE_ALIGN
];
904 size_t total_len
= 0;
908 iscsi_trace(TRACE_NET_DEBUG
, "%s %d bytes on sock\n",
909 xmit
? "sending" : "receiving", len
);
911 iscsi_trace(TRACE_NET_DEBUG
,
912 "building singleton iovec (data %p, len %u)\n",
914 singleton
.iov_base
= data
;
915 singleton
.iov_len
= len
;
919 iov
= (struct iovec
*) data
;
924 if ((remainder
= len
% ISCSI_SOCK_MSG_BYTE_ALIGN
) != 0) {
925 iov_padding
= iscsi_malloc_atomic((iovc
+ 1) *
926 sizeof(struct iovec
));
927 if (iov_padding
== NULL
) {
928 iscsi_err(__FILE__
, __LINE__
,
929 "iscsi_malloc_atomic() failed\n");
932 memcpy(iov_padding
, iov
, iovc
* sizeof(struct iovec
));
933 iov_padding
[iovc
].iov_base
= padding
;
934 padding_len
= ISCSI_SOCK_MSG_BYTE_ALIGN
- remainder
;
935 iov_padding
[iovc
].iov_len
= padding_len
;
938 memset(padding
, 0, padding_len
);
940 iscsi_trace(TRACE_NET_DEBUG
,
941 "Added iovec for padding (len %u)\n", padding_len
);
945 * We make copy of iovec if we're in debugging mode, as we'll
946 * print out the iovec and the buffer contents at the end of
947 * this subroutine and
953 iscsi_trace(TRACE_NET_DEBUG
, "%s %d buffers\n",
954 xmit
? "gathering from" : "scattering into", iovc
);
955 for (i
= 0; i
< iovc
; i
++) {
956 iscsi_trace(TRACE_NET_IOV
,
957 "iov[%d].iov_base = %p, len %u\n",
958 i
, iov
[i
].iov_base
, (unsigned)iov
[i
].iov_len
);
959 total_len
+= iov
[i
].iov_len
;
961 if (total_len
!= len
- n
) {
962 iscsi_err(__FILE__
, __LINE__
,
963 "iovcs sum to %u != total len of %u\n",
965 iscsi_err(__FILE__
, __LINE__
, "iov = %p\n", iov
);
966 for (i
= 0; i
< iovc
; i
++) {
967 iscsi_err(__FILE__
, __LINE__
,
968 "iov[%d].iov_base = %p, len %u\n",
970 (unsigned)iov
[i
].iov_len
);
974 if ((rc
= (xmit
) ? writev(sock
, iov
, iovc
) :
975 readv(sock
, iov
, iovc
)) == 0) {
976 iscsi_trace(TRACE_NET_DEBUG
,
977 "%s() failed: rc %d errno %d\n",
978 (xmit
) ? "writev" : "readv", rc
, errno
);
982 iscsi_err(__FILE__
, __LINE__
,
983 "%s() failed: rc %d errno %d\n",
984 (xmit
) ? "writev" : "readv", rc
, errno
);
989 iscsi_trace(TRACE_NET_DEBUG
,
990 "Got partial %s: %d bytes of %u\n",
991 (xmit
) ? "send" : "recv", rc
, len
- n
+ rc
);
993 for (i
= 0; i
< iovc
; i
++) {
994 total_len
+= iov
[i
].iov_len
;
996 iscsi_trace(TRACE_NET_IOV
,
997 "before modify_iov: %s %d buffers, "
998 "total_len = %u, n = %u, rc = %u\n",
999 xmit
? "gathering from" : "scattering into",
1000 iovc
, total_len
, n
, rc
);
1001 if (modify_iov(&iov
, &iovc
, (unsigned) rc
, len
- n
)
1003 iscsi_err(__FILE__
, __LINE__
,
1004 "modify_iov() failed\n");
1008 for (i
= 0; i
< iovc
; i
++) {
1009 total_len
+= iov
[i
].iov_len
;
1011 iscsi_trace(TRACE_NET_IOV
,
1012 "after modify_iov: %s %d buffers, "
1013 "total_len = %u, n = %u, rc = %u\n\n",
1014 xmit
? "gathering from" : "scattering into",
1015 iovc
, total_len
, n
, rc
);
1020 iscsi_free_atomic(iov_padding
);
1022 iscsi_trace(TRACE_NET_DEBUG
,
1023 "successfully %s %u bytes on sock (%u bytes padding)\n",
1024 xmit
? "sent" : "received", n
, padding_len
);
1025 return n
- padding_len
;
1031 * TCP's Nagle algorithm and delayed-ack lead to poor performance when we send
1032 * two small messages back to back (i.e., header+data). The TCP_NODELAY option
1033 * is supposed to turn off Nagle, but it doesn't seem to work on Linux 2.4.
1034 * Because of this, if our data payload is small, we'll combine the header and
1035 * data, else send as two separate messages.
1039 iscsi_sock_send_header_and_data(int sock
,
1040 void *header
, unsigned header_len
,
1041 const void *data
, unsigned data_len
, int iovc
)
1043 struct iovec iov
[ISCSI_MAX_IOVECS
];
1045 if (data_len
&& data_len
<= ISCSI_SOCK_HACK_CROSSOVER
) {
1046 /* combine header and data into one iovec */
1047 if (iovc
>= ISCSI_MAX_IOVECS
) {
1048 iscsi_err(__FILE__
, __LINE__
,
1049 "iscsi_sock_msg() failed\n");
1053 iov
[0].iov_base
= header
;
1054 iov
[0].iov_len
= header_len
;
1055 iov
[1].iov_base
= __UNCONST((const char *)data
);
1056 iov
[1].iov_len
= data_len
;
1059 iov
[0].iov_base
= header
;
1060 iov
[0].iov_len
= header_len
;
1061 (void) memcpy(&iov
[1], data
, sizeof(struct iovec
) *
1065 if ((unsigned)iscsi_sock_msg(sock
, Transmit
,
1066 header_len
+ data_len
, iov
, iovc
) !=
1067 header_len
+ data_len
) {
1068 iscsi_err(__FILE__
, __LINE__
,
1069 "iscsi_sock_msg() failed\n");
1073 if ((unsigned)iscsi_sock_msg(sock
, Transmit
, header_len
,
1074 header
, 0) != header_len
) {
1075 iscsi_err(__FILE__
, __LINE__
,
1076 "iscsi_sock_msg() failed\n");
1079 if (data_len
!= 0 &&
1080 (unsigned)iscsi_sock_msg(sock
, Transmit
, data_len
,
1081 __UNCONST((const char *) data
), iovc
) != data_len
) {
1082 iscsi_err(__FILE__
, __LINE__
,
1083 "iscsi_sock_msg() failed\n");
1087 return header_len
+ data_len
;
1091 /* spin lock functions */
1093 iscsi_spin_init(iscsi_spin_t
* lock
)
1095 pthread_mutexattr_t mattr
;
1097 pthread_mutexattr_init(&mattr
);
1098 #ifdef PTHREAD_MUTEX_ADAPTIVE_NP
1099 pthread_mutexattr_settype(&mattr
, PTHREAD_MUTEX_ADAPTIVE_NP
);
1101 if (pthread_mutex_init(lock
, &mattr
) != 0)
1107 iscsi_spin_lock(iscsi_spin_t
* lock
)
1109 return pthread_mutex_lock(lock
);
1113 iscsi_spin_unlock(iscsi_spin_t
* lock
)
1115 return pthread_mutex_unlock(lock
);
1120 iscsi_spin_lock_irqsave(iscsi_spin_t
* lock
, uint32_t *flags
)
1122 return pthread_mutex_lock(lock
);
1127 iscsi_spin_unlock_irqrestore(iscsi_spin_t
* lock
, uint32_t *flags
)
1129 return pthread_mutex_unlock(lock
);
1133 iscsi_spin_destroy(iscsi_spin_t
* lock
)
1135 return pthread_mutex_destroy(lock
);
1140 * Mutex Functions, kernel module doesn't require mutex for locking.
1141 * For thread sync, 'down' & 'up' have been wrapped into condition
1142 * varibles, which is kernel semaphores in kernel module.
1146 iscsi_mutex_init(iscsi_mutex_t
* m
)
1148 return (pthread_mutex_init(m
, NULL
) != 0) ? -1 : 0;
1152 iscsi_mutex_lock(iscsi_mutex_t
* m
)
1154 return pthread_mutex_lock(m
);
1158 iscsi_mutex_unlock(iscsi_mutex_t
* m
)
1160 return pthread_mutex_unlock(m
);
1164 iscsi_mutex_destroy(iscsi_mutex_t
* m
)
1166 return pthread_mutex_destroy(m
);
1170 * Condition Functions
1174 iscsi_cond_init(iscsi_cond_t
* c
)
1176 return pthread_cond_init(c
, NULL
);
1180 iscsi_cond_wait(iscsi_cond_t
* c
, iscsi_mutex_t
* m
)
1182 return pthread_cond_wait(c
, m
);
1186 iscsi_cond_signal(iscsi_cond_t
* c
)
1188 return pthread_cond_signal(c
);
1192 iscsi_cond_destroy(iscsi_cond_t
* c
)
1194 return pthread_cond_destroy(c
);
1202 iscsi_atoi(char *value
)
1204 if (value
== NULL
) {
1205 iscsi_err(__FILE__
, __LINE__
,
1206 "iscsi_atoi() called with NULL value\n");
1212 static const char HexString
[] = "0123456789abcdef";
1214 /* get the hex value (subscript) of the character */
1216 HexStringIndex(const char *s
, int c
)
1220 return (c
== '0') ? 0 :
1221 ((cp
= strchr(s
, tolower(c
))) == NULL
) ? -1 : (int)(cp
- s
);
1225 HexDataToText(uint8_t *data
, uint32_t dataLength
,
1226 char *text
, uint32_t textLength
)
1230 if (!text
|| textLength
== 0) {
1233 if (!data
|| dataLength
== 0) {
1237 if (textLength
< 3) {
1246 while (dataLength
> 0) {
1248 if (textLength
< 3) {
1255 *text
++ = HexString
[(n
>> 4) & 0xf];
1256 *text
++ = HexString
[n
& 0xf];
1268 HexTextToData(const char *text
, uint32_t textLength
,
1269 uint8_t *data
, uint32_t dataLength
)
1276 if ((text
[0] == '0') && (text
[1] != 'x' || text
[1] != 'X')) {
1281 if ((textLength
% 2) == 1) {
1283 i
= HexStringIndex(HexString
, *text
++);
1285 return -1; /* error, bad character */
1289 if (dataLength
< 1) {
1290 return -1; /* error, too much data */
1295 while (*text
!= 0x0) {
1297 if ((i
= HexStringIndex(HexString
, *text
++)) < 0) {
1298 /* error, bad character */
1305 /* error, odd string length */
1309 if ((i
= HexStringIndex(HexString
, *text
++)) < 0) {
1310 /* error, bad character */
1316 if (len
>= dataLength
) {
1317 /* error, too much data */
1320 *data
++ = (n1
<< 4) | n2
;
1324 return (len
== 0) ? -1 : 0;
1328 GenRandomData(uint8_t *data
, uint32_t length
)
1333 for (i
= 0 ; i
< length
; i
+= sizeof(n
)) {
1335 (void) memcpy(&data
[i
], &n
, MIN(length
- i
, sizeof(n
)));