4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright (c) 2013 by Delphix. All rights reserved.
33 #include <sys/sunddi.h>
34 #include <sys/modctl.h>
36 #include <sys/cpuvar.h>
37 #include <sys/socket.h>
38 #include <sys/strsubr.h>
39 #include <sys/sysmacros.h>
41 #include <netinet/tcp.h>
43 #include <sys/socketvar.h>
44 #include <sys/pathname.h>
45 #include <sys/fs/snode.h>
46 #include <sys/fs/dv_node.h>
47 #include <sys/vnode.h>
48 #include <netinet/in.h>
50 #include <sys/sockio.h>
51 #include <sys/ksocket.h>
52 #include <sys/filio.h> /* FIONBIO */
53 #include <sys/iscsi_protocol.h>
54 #include <sys/idm/idm.h>
55 #include <sys/idm/idm_so.h>
56 #include <sys/idm/idm_text.h>
58 #define IN_PROGRESS_DELAY 1
61 * in6addr_any is currently all zeroes, but use the macro in case this
64 static const struct in6_addr in6addr_any
= IN6ADDR_ANY_INIT
;
66 static void idm_sorx_cache_pdu_cb(idm_pdu_t
*pdu
, idm_status_t status
);
67 static void idm_sorx_addl_pdu_cb(idm_pdu_t
*pdu
, idm_status_t status
);
68 static void idm_sotx_cache_pdu_cb(idm_pdu_t
*pdu
, idm_status_t status
);
70 static idm_status_t
idm_so_conn_create_common(idm_conn_t
*ic
, ksocket_t new_so
);
71 static void idm_so_conn_destroy_common(idm_conn_t
*ic
);
72 static void idm_so_conn_connect_common(idm_conn_t
*ic
);
74 static void idm_set_ini_preconnect_options(idm_so_conn_t
*sc
,
76 static void idm_set_postconnect_options(ksocket_t so
);
77 static idm_status_t
idm_i_so_tx(idm_pdu_t
*pdu
);
79 static idm_status_t
idm_sorecvdata(idm_conn_t
*ic
, idm_pdu_t
*pdu
);
80 static void idm_so_send_rtt_data(idm_conn_t
*ic
, idm_task_t
*idt
,
81 idm_buf_t
*idb
, uint32_t offset
, uint32_t length
);
82 static void idm_so_send_rtt_data_done(idm_task_t
*idt
, idm_buf_t
*idb
);
83 static idm_status_t
idm_so_send_buf_region(idm_task_t
*idt
,
84 idm_buf_t
*idb
, uint32_t buf_region_offset
, uint32_t buf_region_length
);
86 static uint32_t idm_fill_iov(idm_pdu_t
*pdu
, idm_buf_t
*idb
,
87 uint32_t ro
, uint32_t dlength
);
89 static idm_status_t
idm_so_handle_digest(idm_conn_t
*it
,
90 nvpair_t
*digest_choice
, const idm_kv_xlate_t
*ikvx
);
92 static void idm_so_socket_set_nonblock(struct sonode
*node
);
93 static void idm_so_socket_set_block(struct sonode
*node
);
96 * Transport ops prototypes
98 static void idm_so_tx(idm_conn_t
*ic
, idm_pdu_t
*pdu
);
99 static idm_status_t
idm_so_buf_tx_to_ini(idm_task_t
*idt
, idm_buf_t
*idb
);
100 static idm_status_t
idm_so_buf_rx_from_ini(idm_task_t
*idt
, idm_buf_t
*idb
);
101 static void idm_so_rx_datain(idm_conn_t
*ic
, idm_pdu_t
*pdu
);
102 static void idm_so_rx_rtt(idm_conn_t
*ic
, idm_pdu_t
*pdu
);
103 static void idm_so_rx_dataout(idm_conn_t
*ic
, idm_pdu_t
*pdu
);
104 static idm_status_t
idm_so_free_task_rsrc(idm_task_t
*idt
);
105 static kv_status_t
idm_so_negotiate_key_values(idm_conn_t
*it
,
106 nvlist_t
*request_nvl
, nvlist_t
*response_nvl
, nvlist_t
*negotiated_nvl
);
107 static void idm_so_notice_key_values(idm_conn_t
*it
,
108 nvlist_t
*negotiated_nvl
);
109 static kv_status_t
idm_so_declare_key_values(idm_conn_t
*it
,
110 nvlist_t
*config_nvl
, nvlist_t
*outgoing_nvl
);
111 static boolean_t
idm_so_conn_is_capable(idm_conn_req_t
*ic
,
112 idm_transport_caps_t
*caps
);
113 static idm_status_t
idm_so_buf_alloc(idm_buf_t
*idb
, uint64_t buflen
);
114 static void idm_so_buf_free(idm_buf_t
*idb
);
115 static idm_status_t
idm_so_buf_setup(idm_buf_t
*idb
);
116 static void idm_so_buf_teardown(idm_buf_t
*idb
);
117 static idm_status_t
idm_so_tgt_svc_create(idm_svc_req_t
*sr
, idm_svc_t
*is
);
118 static void idm_so_tgt_svc_destroy(idm_svc_t
*is
);
119 static idm_status_t
idm_so_tgt_svc_online(idm_svc_t
*is
);
120 static void idm_so_tgt_svc_offline(idm_svc_t
*is
);
121 static void idm_so_tgt_conn_destroy(idm_conn_t
*ic
);
122 static idm_status_t
idm_so_tgt_conn_connect(idm_conn_t
*ic
);
123 static void idm_so_conn_disconnect(idm_conn_t
*ic
);
124 static idm_status_t
idm_so_ini_conn_create(idm_conn_req_t
*cr
, idm_conn_t
*ic
);
125 static void idm_so_ini_conn_destroy(idm_conn_t
*ic
);
126 static idm_status_t
idm_so_ini_conn_connect(idm_conn_t
*ic
);
129 * IDM Native Sockets transport operations
132 idm_transport_ops_t idm_so_transport_ops
= {
133 idm_so_tx
, /* it_tx_pdu */
134 idm_so_buf_tx_to_ini
, /* it_buf_tx_to_ini */
135 idm_so_buf_rx_from_ini
, /* it_buf_rx_from_ini */
136 idm_so_rx_datain
, /* it_rx_datain */
137 idm_so_rx_rtt
, /* it_rx_rtt */
138 idm_so_rx_dataout
, /* it_rx_dataout */
139 NULL
, /* it_alloc_conn_rsrc */
140 NULL
, /* it_free_conn_rsrc */
141 NULL
, /* it_tgt_enable_datamover */
142 NULL
, /* it_ini_enable_datamover */
143 NULL
, /* it_conn_terminate */
144 idm_so_free_task_rsrc
, /* it_free_task_rsrc */
145 idm_so_negotiate_key_values
, /* it_negotiate_key_values */
146 idm_so_notice_key_values
, /* it_notice_key_values */
147 idm_so_conn_is_capable
, /* it_conn_is_capable */
148 idm_so_buf_alloc
, /* it_buf_alloc */
149 idm_so_buf_free
, /* it_buf_free */
150 idm_so_buf_setup
, /* it_buf_setup */
151 idm_so_buf_teardown
, /* it_buf_teardown */
152 idm_so_tgt_svc_create
, /* it_tgt_svc_create */
153 idm_so_tgt_svc_destroy
, /* it_tgt_svc_destroy */
154 idm_so_tgt_svc_online
, /* it_tgt_svc_online */
155 idm_so_tgt_svc_offline
, /* it_tgt_svc_offline */
156 idm_so_tgt_conn_destroy
, /* it_tgt_conn_destroy */
157 idm_so_tgt_conn_connect
, /* it_tgt_conn_connect */
158 idm_so_conn_disconnect
, /* it_tgt_conn_disconnect */
159 idm_so_ini_conn_create
, /* it_ini_conn_create */
160 idm_so_ini_conn_destroy
, /* it_ini_conn_destroy */
161 idm_so_ini_conn_connect
, /* it_ini_conn_connect */
162 idm_so_conn_disconnect
, /* it_ini_conn_disconnect */
163 idm_so_declare_key_values
/* it_declare_key_values */
166 kmutex_t idm_so_timed_socket_mutex
;
168 int32_t idm_so_sndbuf
= IDM_SNDBUF_SIZE
;
169 int32_t idm_so_rcvbuf
= IDM_RCVBUF_SIZE
;
173 * Sockets transport initialization
176 idm_so_init(idm_transport_t
*it
)
178 /* Cache for IDM Data and R2T Transmit PDU's */
179 idm
.idm_sotx_pdu_cache
= kmem_cache_create("idm_tx_pdu_cache",
180 sizeof (idm_pdu_t
) + sizeof (iscsi_hdr_t
), 8,
181 &idm_sotx_pdu_constructor
, NULL
, NULL
, NULL
, NULL
, KM_SLEEP
);
183 /* Cache for IDM Receive PDU's */
184 idm
.idm_sorx_pdu_cache
= kmem_cache_create("idm_rx_pdu_cache",
185 sizeof (idm_pdu_t
) + IDM_SORX_CACHE_HDRLEN
, 8,
186 &idm_sorx_pdu_constructor
, NULL
, NULL
, NULL
, NULL
, KM_SLEEP
);
188 /* 128k buffer cache */
189 idm
.idm_so_128k_buf_cache
= kmem_cache_create("idm_128k_buf_cache",
190 IDM_SO_BUF_CACHE_UB
, 8, NULL
, NULL
, NULL
, NULL
, NULL
, KM_SLEEP
);
192 /* Set the sockets transport ops */
193 it
->it_ops
= &idm_so_transport_ops
;
195 mutex_init(&idm_so_timed_socket_mutex
, NULL
, MUTEX_DEFAULT
, NULL
);
201 * Sockets transport teardown
206 kmem_cache_destroy(idm
.idm_so_128k_buf_cache
);
207 kmem_cache_destroy(idm
.idm_sotx_pdu_cache
);
208 kmem_cache_destroy(idm
.idm_sorx_pdu_cache
);
209 mutex_destroy(&idm_so_timed_socket_mutex
);
213 idm_socreate(int domain
, int type
, int protocol
)
217 if (!ksocket_socket(&ks
, domain
, type
, protocol
, KSOCKET_NOSLEEP
,
226 * idm_soshutdown will disconnect the socket and prevent subsequent PDU
227 * reception and transmission. The sonode still exists but its state
228 * gets modified to indicate it is no longer connected. Calls to
229 * idm_sorecv/idm_iov_sorecv will return so idm_soshutdown can be used
230 * regain control of a thread stuck in idm_sorecv.
233 idm_soshutdown(ksocket_t so
)
235 (void) ksocket_shutdown(so
, SHUT_RDWR
, CRED());
239 * idm_sodestroy releases all resources associated with a socket previously
240 * created with idm_socreate. The socket must be shutdown using
241 * idm_soshutdown before the socket is destroyed with idm_sodestroy,
242 * otherwise undefined behavior will result.
245 idm_sodestroy(ksocket_t ks
)
247 (void) ksocket_close(ks
, CRED());
251 * Function to compare two addresses in sockaddr_storage format
255 idm_ss_compare(const struct sockaddr_storage
*cmp_ss1
,
256 const struct sockaddr_storage
*cmp_ss2
,
257 boolean_t v4_mapped_as_v4
,
258 boolean_t compare_ports
)
260 struct sockaddr_storage mapped_v4_ss1
, mapped_v4_ss2
;
261 const struct sockaddr_storage
*ss1
, *ss2
;
262 struct in_addr
*in1
, *in2
;
263 struct in6_addr
*in61
, *in62
;
267 * Normalize V4-mapped IPv6 addresses into V4 format if
268 * v4_mapped_as_v4 is B_TRUE.
272 if (v4_mapped_as_v4
&& (ss1
->ss_family
== AF_INET6
)) {
273 in61
= &((struct sockaddr_in6
*)ss1
)->sin6_addr
;
274 if (IN6_IS_ADDR_V4MAPPED(in61
)) {
275 bzero(&mapped_v4_ss1
, sizeof (mapped_v4_ss1
));
276 mapped_v4_ss1
.ss_family
= AF_INET
;
277 ((struct sockaddr_in
*)&mapped_v4_ss1
)->sin_port
=
278 ((struct sockaddr_in
*)ss1
)->sin_port
;
279 IN6_V4MAPPED_TO_INADDR(in61
,
280 &((struct sockaddr_in
*)&mapped_v4_ss1
)->sin_addr
);
281 ss1
= &mapped_v4_ss1
;
285 if (v4_mapped_as_v4
&& (ss2
->ss_family
== AF_INET6
)) {
286 in62
= &((struct sockaddr_in6
*)ss2
)->sin6_addr
;
287 if (IN6_IS_ADDR_V4MAPPED(in62
)) {
288 bzero(&mapped_v4_ss2
, sizeof (mapped_v4_ss2
));
289 mapped_v4_ss2
.ss_family
= AF_INET
;
290 ((struct sockaddr_in
*)&mapped_v4_ss2
)->sin_port
=
291 ((struct sockaddr_in
*)ss2
)->sin_port
;
292 IN6_V4MAPPED_TO_INADDR(in62
,
293 &((struct sockaddr_in
*)&mapped_v4_ss2
)->sin_addr
);
294 ss2
= &mapped_v4_ss2
;
299 * Compare ports, then address family, then ip address
302 (((struct sockaddr_in
*)ss1
)->sin_port
!=
303 ((struct sockaddr_in
*)ss2
)->sin_port
)) {
304 if (((struct sockaddr_in
*)ss1
)->sin_port
>
305 ((struct sockaddr_in
*)ss2
)->sin_port
)
314 if (ss1
->ss_family
!= ss2
->ss_family
) {
315 if (ss1
->ss_family
== AF_INET
)
322 * address families are the same
324 if (ss1
->ss_family
== AF_INET
) {
325 in1
= &((struct sockaddr_in
*)ss1
)->sin_addr
;
326 in2
= &((struct sockaddr_in
*)ss2
)->sin_addr
;
328 if (in1
->s_addr
> in2
->s_addr
)
330 else if (in1
->s_addr
< in2
->s_addr
)
334 } else if (ss1
->ss_family
== AF_INET6
) {
335 in61
= &((struct sockaddr_in6
*)ss1
)->sin6_addr
;
336 in62
= &((struct sockaddr_in6
*)ss2
)->sin6_addr
;
338 for (i
= 0; i
< 4; i
++) {
339 if (in61
->s6_addr32
[i
] > in62
->s6_addr32
[i
])
341 else if (in61
->s6_addr32
[i
] < in62
->s6_addr32
[i
])
351 * IP address filter functions to flag addresses that should not
352 * go out to initiators through discovery.
355 idm_v4_addr_okay(struct in_addr
*in_addr
)
357 in_addr_t addr
= ntohl(in_addr
->s_addr
);
359 if ((INADDR_NONE
== addr
) ||
360 (IN_MULTICAST(addr
)) ||
361 ((addr
>> IN_CLASSA_NSHIFT
) == 0) ||
362 ((addr
>> IN_CLASSA_NSHIFT
) == IN_LOOPBACKNET
)) {
369 idm_v6_addr_okay(struct in6_addr
*addr6
)
372 if ((IN6_IS_ADDR_UNSPECIFIED(addr6
)) ||
373 (IN6_IS_ADDR_LOOPBACK(addr6
)) ||
374 (IN6_IS_ADDR_MULTICAST(addr6
)) ||
375 (IN6_IS_ADDR_V4MAPPED(addr6
)) ||
376 (IN6_IS_ADDR_V4COMPAT(addr6
)) ||
377 (IN6_IS_ADDR_LINKLOCAL(addr6
))) {
384 * idm_get_ipaddr will retrieve a list of IP Addresses which the host is
385 * configured with by sending down a sequence of kernel ioctl to IP STREAMS.
388 idm_get_ipaddr(idm_addr_list_t
**ipaddr_p
)
399 struct sockaddr_storage ss
;
400 struct sockaddr_in
*sin
;
401 struct sockaddr_in6
*sin6
;
403 idm_addr_list_t
*ipaddr
= NULL
;
410 /* create an ipv4 and ipv6 UDP socket */
411 if ((so6
= idm_socreate(PF_INET6
, SOCK_DGRAM
, 0)) == NULL
)
413 if ((so4
= idm_socreate(PF_INET
, SOCK_DGRAM
, 0)) == NULL
) {
420 /* snapshot the current number of interfaces */
421 lifn
.lifn_family
= PF_UNSPEC
;
422 lifn
.lifn_flags
= LIFC_NOXMIT
| LIFC_TEMPORARY
| LIFC_ALLZONES
;
424 /* use vp6 for ioctls with unspecified families by default */
425 if (ksocket_ioctl(so6
, SIOCGLIFNUM
, (intptr_t)&lifn
, &rval
, CRED())
430 numifs
= lifn
.lifn_count
;
435 /* allocate extra room in case more interfaces appear */
438 /* get the interface names and ip addresses */
439 bufsize
= numifs
* sizeof (struct lifreq
);
440 buf
= kmem_alloc(bufsize
, KM_SLEEP
);
442 lifc
.lifc_family
= AF_UNSPEC
;
443 lifc
.lifc_flags
= LIFC_NOXMIT
| LIFC_TEMPORARY
| LIFC_ALLZONES
;
444 lifc
.lifc_len
= bufsize
;
446 rc
= ksocket_ioctl(so6
, SIOCGLIFCONF
, (intptr_t)&lifc
, &rval
, CRED());
450 /* if our extra room is used up, try again */
451 if (bufsize
<= lifc
.lifc_len
) {
452 kmem_free(buf
, bufsize
);
456 /* calc actual number of ifconfs */
457 n
= lifc
.lifc_len
/ sizeof (struct lifreq
);
461 size_ipaddr
= sizeof (idm_addr_list_t
) +
462 (n
- 1) * sizeof (idm_addr_t
);
463 ipaddr
= kmem_zalloc(size_ipaddr
, KM_SLEEP
);
469 * Examine the array of interfaces and filter uninteresting ones
471 for (i
= 0, j
= 0, lp
= lifc
.lifc_req
; i
< n
; i
++, lp
++) {
474 * Copy the address as the SIOCGLIFFLAGS ioctl is destructive
478 * fetch the flags using the socket of the correct family
480 switch (ss
.ss_family
) {
482 rc
= ksocket_ioctl(so4
, SIOCGLIFFLAGS
, (intptr_t)lp
,
486 rc
= ksocket_ioctl(so6
, SIOCGLIFFLAGS
, (intptr_t)lp
,
494 * If we got the flags, skip uninteresting
495 * interfaces based on flags
497 if ((lp
->lifr_flags
& IFF_UP
) != IFF_UP
)
500 (IFF_ANYCAST
|IFF_NOLOCAL
|IFF_DEPRECATED
))
504 /* save ip address */
505 ip
= &ipaddr
->al_addrs
[j
];
506 switch (ss
.ss_family
) {
508 sin
= (struct sockaddr_in
*)&ss
;
509 if (!idm_v4_addr_okay(&sin
->sin_addr
))
511 ip
->a_addr
.i_addr
.in4
= sin
->sin_addr
;
512 ip
->a_addr
.i_insize
= sizeof (struct in_addr
);
515 sin6
= (struct sockaddr_in6
*)&ss
;
516 if (!idm_v6_addr_okay(&sin6
->sin6_addr
))
518 ip
->a_addr
.i_addr
.in6
= sin6
->sin6_addr
;
519 ip
->a_addr
.i_insize
= sizeof (struct in6_addr
);
528 /* no valid ifaddr */
529 kmem_free(ipaddr
, size_ipaddr
);
533 ipaddr
->al_out_cnt
= j
;
542 kmem_free(buf
, bufsize
);
545 return (size_ipaddr
);
549 idm_sorecv(ksocket_t so
, void *msg
, size_t len
)
557 * Fill in iovec and receive data
562 return (idm_iov_sorecv(so
, &iov
, 1, len
));
566 * idm_sosendto - Sends a buffered data on a non-connected socket.
568 * This function puts the data provided on the wire by calling sosendmsg.
569 * It will return only when all the data has been sent or if an error
572 * Returns 0 for success, the socket errno value if sosendmsg fails, and
573 * -1 if sosendmsg returns success but uio_resid != 0
576 idm_sosendto(ksocket_t so
, void *buff
, size_t len
,
577 struct sockaddr
*name
, socklen_t namelen
)
584 iov
[0].iov_base
= buff
;
585 iov
[0].iov_len
= len
;
587 /* Initialization of the message header. */
588 bzero(&msg
, sizeof (msg
));
592 msg
.msg_namelen
= namelen
;
594 if ((error
= ksocket_sendmsg(so
, &msg
, 0, &sent
, CRED())) == 0) {
597 /* All data sent. Success. */
600 /* Not all data was sent. Failure */
610 * idm_iov_sosend - Sends an iovec on a connection.
612 * This function puts the data provided on the wire by calling sosendmsg.
613 * It will return only when all the data has been sent or if an error
616 * Returns 0 for success, the socket errno value if sosendmsg fails, and
617 * -1 if sosendmsg returns success but uio_resid != 0
620 idm_iov_sosend(ksocket_t so
, iovec_t
*iop
, int iovlen
, size_t total_len
)
628 /* Initialization of the message header. */
629 bzero(&msg
, sizeof (msg
));
631 msg
.msg_iovlen
= iovlen
;
633 if ((error
= ksocket_sendmsg(so
, &msg
, 0, &sent
, CRED()))
636 if (sent
== total_len
) {
637 /* All data sent. Success. */
640 /* Not all data was sent. Failure */
650 * idm_iov_sorecv - Receives an iovec from a connection
652 * This function gets the data asked for from the socket. It will return
653 * only when all the requested data has been retrieved or if an error
656 * Returns 0 for success, the socket errno value if sorecvmsg fails, and
657 * -1 if sorecvmsg returns success but uio_resid != 0
660 idm_iov_sorecv(ksocket_t so
, iovec_t
*iop
, int iovlen
, size_t total_len
)
669 /* Initialization of the message header. */
670 bzero(&msg
, sizeof (msg
));
672 msg
.msg_iovlen
= iovlen
;
675 if ((error
= ksocket_recvmsg(so
, &msg
, flags
, &recv
, CRED()))
678 if (recv
== total_len
) {
679 /* All requested data received. Success */
683 * Not all data was received. The connection has
695 idm_set_ini_preconnect_options(idm_so_conn_t
*sc
, boolean_t boot_conn
)
697 int conn_abort
= 10000;
698 int conn_notify
= 2000;
701 /* Pre-connect socket options */
702 (void) ksocket_setsockopt(sc
->ic_so
, IPPROTO_TCP
,
703 TCP_CONN_NOTIFY_THRESHOLD
, (char *)&conn_notify
, sizeof (int),
705 if (boot_conn
== B_FALSE
) {
706 (void) ksocket_setsockopt(sc
->ic_so
, IPPROTO_TCP
,
707 TCP_CONN_ABORT_THRESHOLD
, (char *)&conn_abort
, sizeof (int),
709 (void) ksocket_setsockopt(sc
->ic_so
, IPPROTO_TCP
,
711 (char *)&abort
, sizeof (int), CRED());
716 idm_set_postconnect_options(ksocket_t ks
)
720 /* Set connect options */
721 (void) ksocket_setsockopt(ks
, SOL_SOCKET
, SO_RCVBUF
,
722 (char *)&idm_so_rcvbuf
, sizeof (idm_so_rcvbuf
), CRED());
723 (void) ksocket_setsockopt(ks
, SOL_SOCKET
, SO_SNDBUF
,
724 (char *)&idm_so_sndbuf
, sizeof (idm_so_sndbuf
), CRED());
725 (void) ksocket_setsockopt(ks
, IPPROTO_TCP
, TCP_NODELAY
,
726 (char *)&on
, sizeof (on
), CRED());
730 n2h24(const uchar_t
*ptr
)
732 return ((ptr
[0] << 16) | (ptr
[1] << 8) | ptr
[2]);
737 idm_sorecvhdr(idm_conn_t
*ic
, idm_pdu_t
*pdu
)
740 uint32_t hdr_digest_crc
;
741 uint32_t crc_calculated
;
747 idm_so_conn_t
*so_conn
;
750 so_conn
= ic
->ic_transport_private
;
756 rc
= idm_sorecv(so_conn
->ic_so
, pdu
->isp_hdr
, sizeof (iscsi_hdr_t
));
757 if (rc
!= IDM_STATUS_SUCCESS
) {
758 return (IDM_STATUS_FAIL
);
762 * Check actual AHS length against the amount available in the buffer
764 pdu
->isp_hdrlen
= sizeof (iscsi_hdr_t
) +
765 (bhs
->hlength
* sizeof (uint32_t));
766 pdu
->isp_datalen
= n2h24(bhs
->dlength
);
767 if (ic
->ic_conn_type
== CONN_TYPE_TGT
&&
768 pdu
->isp_datalen
> ic
->ic_conn_params
.max_recv_dataseglen
) {
769 IDM_CONN_LOG(CE_WARN
,
770 "idm_sorecvhdr: exceeded the max data segment length");
771 return (IDM_STATUS_FAIL
);
773 if (bhs
->hlength
> IDM_SORX_CACHE_AHSLEN
) {
774 /* Allocate a new header segment and change the callback */
775 new_hdr
= kmem_alloc(pdu
->isp_hdrlen
, KM_SLEEP
);
776 bcopy(pdu
->isp_hdr
, new_hdr
, sizeof (iscsi_hdr_t
));
777 pdu
->isp_hdr
= new_hdr
;
778 pdu
->isp_flags
|= IDM_PDU_ADDL_HDR
;
781 * This callback will restore the expected values after
782 * the RX PDU has been processed.
784 pdu
->isp_callback
= idm_sorx_addl_pdu_cb
;
788 * Setup receipt of additional header and header digest (if enabled).
790 if (bhs
->hlength
> 0) {
791 iov
[iovlen
].iov_base
= (caddr_t
)(pdu
->isp_hdr
+ 1);
792 ahslen
= pdu
->isp_hdrlen
- sizeof (iscsi_hdr_t
);
793 iov
[iovlen
].iov_len
= ahslen
;
794 total_len
+= iov
[iovlen
].iov_len
;
798 if (ic
->ic_conn_flags
& IDM_CONN_HEADER_DIGEST
) {
799 iov
[iovlen
].iov_base
= (caddr_t
)&hdr_digest_crc
;
800 iov
[iovlen
].iov_len
= sizeof (hdr_digest_crc
);
801 total_len
+= iov
[iovlen
].iov_len
;
806 (idm_iov_sorecv(so_conn
->ic_so
, &iov
[0], iovlen
,
808 return (IDM_STATUS_FAIL
);
812 * Validate header digest if enabled
814 if (ic
->ic_conn_flags
& IDM_CONN_HEADER_DIGEST
) {
815 crc_calculated
= idm_crc32c(pdu
->isp_hdr
,
816 sizeof (iscsi_hdr_t
) + ahslen
);
817 if (crc_calculated
!= hdr_digest_crc
) {
818 /* Invalid Header Digest */
819 return (IDM_STATUS_HEADER_DIGEST
);
827 * idm_so_ini_conn_create()
828 * Allocate the sockets transport connection resources.
831 idm_so_ini_conn_create(idm_conn_req_t
*cr
, idm_conn_t
*ic
)
834 idm_so_conn_t
*so_conn
;
837 so
= idm_socreate(cr
->cr_domain
, cr
->cr_type
,
840 return (IDM_STATUS_FAIL
);
843 /* Bind the socket if configured to do so */
845 if (ksocket_bind(so
, &cr
->cr_bound_addr
.sin
,
846 SIZEOF_SOCKADDR(&cr
->cr_bound_addr
.sin
), CRED()) != 0) {
848 return (IDM_STATUS_FAIL
);
852 idmrc
= idm_so_conn_create_common(ic
, so
);
853 if (idmrc
!= IDM_STATUS_SUCCESS
) {
856 return (IDM_STATUS_FAIL
);
859 so_conn
= ic
->ic_transport_private
;
860 /* Set up socket options */
861 idm_set_ini_preconnect_options(so_conn
, cr
->cr_boot_conn
);
863 return (IDM_STATUS_SUCCESS
);
867 * idm_so_ini_conn_destroy()
868 * Tear down the sockets transport connection resources.
871 idm_so_ini_conn_destroy(idm_conn_t
*ic
)
873 idm_so_conn_destroy_common(ic
);
877 * idm_so_ini_conn_connect()
878 * Establish the connection referred to by the handle previously allocated via
879 * idm_so_ini_conn_create().
882 idm_so_ini_conn_connect(idm_conn_t
*ic
)
884 idm_so_conn_t
*so_conn
;
885 struct sonode
*node
= NULL
;
887 clock_t lbolt
, conn_login_max
, conn_login_interval
;
890 so_conn
= ic
->ic_transport_private
;
891 nonblock
= ic
->ic_conn_params
.nonblock_socket
;
892 conn_login_max
= ic
->ic_conn_params
.conn_login_max
;
893 conn_login_interval
= ddi_get_lbolt() +
894 SEC_TO_TICK(ic
->ic_conn_params
.conn_login_interval
);
896 if (nonblock
== B_TRUE
) {
897 node
= ((struct sonode
*)(so_conn
->ic_so
));
898 /* Set to none block socket mode */
899 idm_so_socket_set_nonblock(node
);
901 rc
= ksocket_connect(so_conn
->ic_so
,
902 &ic
->ic_ini_dst_addr
.sin
,
903 (SIZEOF_SOCKADDR(&ic
->ic_ini_dst_addr
.sin
)),
905 if (rc
== 0 || rc
== EISCONN
) {
906 /* socket success or already success */
907 rc
= IDM_STATUS_SUCCESS
;
910 if ((rc
== ETIMEDOUT
) || (rc
== ECONNREFUSED
) ||
911 (rc
== ECONNRESET
)) {
912 /* socket connection timeout or refuse */
915 lbolt
= ddi_get_lbolt();
916 if (lbolt
> conn_login_max
) {
918 * Connection retry timeout,
919 * failed connect to target.
923 if (lbolt
< conn_login_interval
) {
924 if ((rc
== EINPROGRESS
) || (rc
== EALREADY
)) {
925 /* TCP connect still in progress */
926 ddi_sleep(IN_PROGRESS_DELAY
);
929 delay(conn_login_interval
- lbolt
);
932 conn_login_interval
= ddi_get_lbolt() +
933 SEC_TO_TICK(ic
->ic_conn_params
.conn_login_interval
);
935 /* resume to nonblock mode */
936 if (rc
== IDM_STATUS_SUCCESS
) {
937 idm_so_socket_set_block(node
);
940 rc
= ksocket_connect(so_conn
->ic_so
, &ic
->ic_ini_dst_addr
.sin
,
941 (SIZEOF_SOCKADDR(&ic
->ic_ini_dst_addr
.sin
)), CRED());
945 idm_soshutdown(so_conn
->ic_so
);
946 return (IDM_STATUS_FAIL
);
949 idm_so_conn_connect_common(ic
);
951 idm_set_postconnect_options(so_conn
->ic_so
);
953 return (IDM_STATUS_SUCCESS
);
957 idm_so_tgt_conn_create(idm_conn_t
*ic
, ksocket_t new_so
)
961 idm_set_postconnect_options(new_so
);
962 idmrc
= idm_so_conn_create_common(ic
, new_so
);
968 idm_so_tgt_conn_destroy(idm_conn_t
*ic
)
970 idm_so_conn_destroy_common(ic
);
974 * idm_so_tgt_conn_connect()
975 * Establish the connection in ic, passed from idm_tgt_conn_finish(), which
976 * is invoked from the SM as a result of an inbound connection request.
979 idm_so_tgt_conn_connect(idm_conn_t
*ic
)
981 idm_so_conn_connect_common(ic
);
983 return (IDM_STATUS_SUCCESS
);
987 idm_so_conn_create_common(idm_conn_t
*ic
, ksocket_t new_so
)
989 idm_so_conn_t
*so_conn
;
991 so_conn
= kmem_zalloc(sizeof (idm_so_conn_t
), KM_SLEEP
);
992 so_conn
->ic_so
= new_so
;
994 ic
->ic_transport_private
= so_conn
;
995 ic
->ic_transport_hdrlen
= 0;
997 /* Set the scoreboarding flag on this connection */
998 ic
->ic_conn_flags
|= IDM_CONN_USE_SCOREBOARD
;
999 ic
->ic_conn_params
.max_recv_dataseglen
=
1000 ISCSI_DEFAULT_MAX_RECV_SEG_LEN
;
1001 ic
->ic_conn_params
.max_xmit_dataseglen
=
1002 ISCSI_DEFAULT_MAX_XMIT_SEG_LEN
;
1005 * Initialize tx thread mutex and list
1007 mutex_init(&so_conn
->ic_tx_mutex
, NULL
, MUTEX_DEFAULT
, NULL
);
1008 cv_init(&so_conn
->ic_tx_cv
, NULL
, CV_DEFAULT
, NULL
);
1009 list_create(&so_conn
->ic_tx_list
, sizeof (idm_pdu_t
),
1010 offsetof(idm_pdu_t
, idm_tx_link
));
1012 return (IDM_STATUS_SUCCESS
);
1016 idm_so_conn_destroy_common(idm_conn_t
*ic
)
1018 idm_so_conn_t
*so_conn
= ic
->ic_transport_private
;
1020 ic
->ic_transport_private
= NULL
;
1021 idm_sodestroy(so_conn
->ic_so
);
1022 list_destroy(&so_conn
->ic_tx_list
);
1023 mutex_destroy(&so_conn
->ic_tx_mutex
);
1024 cv_destroy(&so_conn
->ic_tx_cv
);
1026 kmem_free(so_conn
, sizeof (idm_so_conn_t
));
1030 idm_so_conn_connect_common(idm_conn_t
*ic
)
1032 idm_so_conn_t
*so_conn
;
1033 struct sockaddr_in6 t_addr
;
1034 socklen_t t_addrlen
= 0;
1036 so_conn
= ic
->ic_transport_private
;
1037 bzero(&t_addr
, sizeof (struct sockaddr_in6
));
1038 t_addrlen
= sizeof (struct sockaddr_in6
);
1040 /* Set the local and remote addresses in the idm conn handle */
1041 (void) ksocket_getsockname(so_conn
->ic_so
, (struct sockaddr
*)&t_addr
,
1042 &t_addrlen
, CRED());
1043 bcopy(&t_addr
, &ic
->ic_laddr
, t_addrlen
);
1044 (void) ksocket_getpeername(so_conn
->ic_so
, (struct sockaddr
*)&t_addr
,
1045 &t_addrlen
, CRED());
1046 bcopy(&t_addr
, &ic
->ic_raddr
, t_addrlen
);
1048 mutex_enter(&ic
->ic_mutex
);
1049 so_conn
->ic_tx_thread
= thread_create(NULL
, 0, idm_sotx_thread
, ic
, 0,
1050 &p0
, TS_RUN
, minclsyspri
);
1051 so_conn
->ic_rx_thread
= thread_create(NULL
, 0, idm_sorx_thread
, ic
, 0,
1052 &p0
, TS_RUN
, minclsyspri
);
1054 while (so_conn
->ic_rx_thread_did
== 0 ||
1055 so_conn
->ic_tx_thread_did
== 0)
1056 cv_wait(&ic
->ic_cv
, &ic
->ic_mutex
);
1057 mutex_exit(&ic
->ic_mutex
);
1061 * idm_so_conn_disconnect()
1062 * Shutdown the socket connection and stop the thread
1065 idm_so_conn_disconnect(idm_conn_t
*ic
)
1067 idm_so_conn_t
*so_conn
;
1069 so_conn
= ic
->ic_transport_private
;
1071 mutex_enter(&ic
->ic_mutex
);
1072 so_conn
->ic_rx_thread_running
= B_FALSE
;
1073 so_conn
->ic_tx_thread_running
= B_FALSE
;
1074 /* We need to wakeup the TX thread */
1075 mutex_enter(&so_conn
->ic_tx_mutex
);
1076 cv_signal(&so_conn
->ic_tx_cv
);
1077 mutex_exit(&so_conn
->ic_tx_mutex
);
1078 mutex_exit(&ic
->ic_mutex
);
1080 /* This should wakeup the RX thread if it is sleeping */
1081 idm_soshutdown(so_conn
->ic_so
);
1083 thread_join(so_conn
->ic_tx_thread_did
);
1084 thread_join(so_conn
->ic_rx_thread_did
);
1088 * idm_so_tgt_svc_create()
1089 * Establish a service on an IP address and port. idm_svc_req_t contains
1090 * the service parameters.
1094 idm_so_tgt_svc_create(idm_svc_req_t
*sr
, idm_svc_t
*is
)
1096 idm_so_svc_t
*so_svc
;
1098 so_svc
= kmem_zalloc(sizeof (idm_so_svc_t
), KM_SLEEP
);
1100 /* Set the new sockets service in svc handle */
1101 is
->is_so_svc
= (void *)so_svc
;
1103 return (IDM_STATUS_SUCCESS
);
1107 * idm_so_tgt_svc_destroy()
1108 * Teardown sockets resources allocated in idm_so_tgt_svc_create()
1111 idm_so_tgt_svc_destroy(idm_svc_t
*is
)
1113 /* the socket will have been torn down; free the service */
1114 kmem_free(is
->is_so_svc
, sizeof (idm_so_svc_t
));
1118 * idm_so_tgt_svc_online()
1119 * Launch a watch thread on the svc allocated in idm_so_tgt_svc_create()
1123 idm_so_tgt_svc_online(idm_svc_t
*is
)
1125 idm_so_svc_t
*so_svc
;
1126 idm_svc_req_t
*sr
= &is
->is_svc_req
;
1127 struct sockaddr_in6 sin6_ip
;
1128 const uint32_t on
= 1;
1130 mutex_enter(&is
->is_mutex
);
1131 so_svc
= (idm_so_svc_t
*)is
->is_so_svc
;
1134 * Try creating an IPv6 socket first
1136 if ((so_svc
->is_so
= idm_socreate(PF_INET6
, SOCK_STREAM
, 0)) == NULL
) {
1137 mutex_exit(&is
->is_mutex
);
1138 return (IDM_STATUS_FAIL
);
1140 bzero(&sin6_ip
, sizeof (sin6_ip
));
1141 sin6_ip
.sin6_family
= AF_INET6
;
1142 sin6_ip
.sin6_port
= htons(sr
->sr_port
);
1143 sin6_ip
.sin6_addr
= in6addr_any
;
1145 (void) ksocket_setsockopt(so_svc
->is_so
, SOL_SOCKET
,
1146 SO_REUSEADDR
, (char *)&on
, sizeof (on
), CRED());
1148 if (ksocket_bind(so_svc
->is_so
, (struct sockaddr
*)&sin6_ip
,
1149 sizeof (sin6_ip
), CRED()) != 0) {
1150 mutex_exit(&is
->is_mutex
);
1151 idm_sodestroy(so_svc
->is_so
);
1152 return (IDM_STATUS_FAIL
);
1156 idm_set_postconnect_options(so_svc
->is_so
);
1158 if (ksocket_listen(so_svc
->is_so
, 5, CRED()) != 0) {
1159 mutex_exit(&is
->is_mutex
);
1160 idm_soshutdown(so_svc
->is_so
);
1161 idm_sodestroy(so_svc
->is_so
);
1162 return (IDM_STATUS_FAIL
);
1165 /* Launch a watch thread */
1166 so_svc
->is_thread
= thread_create(NULL
, 0, idm_so_svc_port_watcher
,
1167 is
, 0, &p0
, TS_RUN
, minclsyspri
);
1169 if (so_svc
->is_thread
== NULL
) {
1170 /* Failure to launch; teardown the socket */
1171 mutex_exit(&is
->is_mutex
);
1172 idm_soshutdown(so_svc
->is_so
);
1173 idm_sodestroy(so_svc
->is_so
);
1174 return (IDM_STATUS_FAIL
);
1176 ksocket_hold(so_svc
->is_so
);
1177 /* Wait for the port watcher thread to start */
1178 while (!so_svc
->is_thread_running
)
1179 cv_wait(&is
->is_cv
, &is
->is_mutex
);
1180 mutex_exit(&is
->is_mutex
);
1182 return (IDM_STATUS_SUCCESS
);
1186 * idm_so_tgt_svc_offline
1188 * Stop listening on the IP address and port identified by idm_svc_t.
1191 idm_so_tgt_svc_offline(idm_svc_t
*is
)
1193 idm_so_svc_t
*so_svc
;
1194 mutex_enter(&is
->is_mutex
);
1195 so_svc
= (idm_so_svc_t
*)is
->is_so_svc
;
1196 so_svc
->is_thread_running
= B_FALSE
;
1197 mutex_exit(&is
->is_mutex
);
1202 idm_sodestroy(so_svc
->is_so
);
1205 * Now we expect the port watcher thread to terminate
1207 thread_join(so_svc
->is_thread_did
);
1211 * Watch thread for target service connection establishment.
1214 idm_so_svc_port_watcher(void *arg
)
1216 idm_svc_t
*svc
= arg
;
1220 idm_so_svc_t
*so_svc
;
1222 struct sockaddr_in6 t_addr
;
1223 socklen_t t_addrlen
;
1225 bzero(&t_addr
, sizeof (struct sockaddr_in6
));
1226 t_addrlen
= sizeof (struct sockaddr_in6
);
1227 mutex_enter(&svc
->is_mutex
);
1229 so_svc
= svc
->is_so_svc
;
1230 so_svc
->is_thread_running
= B_TRUE
;
1231 so_svc
->is_thread_did
= so_svc
->is_thread
->t_did
;
1233 cv_signal(&svc
->is_cv
);
1235 IDM_SVC_LOG(CE_NOTE
, "iSCSI service (%p/%d) online", (void *)svc
,
1236 svc
->is_svc_req
.sr_port
);
1238 while (so_svc
->is_thread_running
) {
1239 mutex_exit(&svc
->is_mutex
);
1241 if ((rc
= ksocket_accept(so_svc
->is_so
,
1242 (struct sockaddr
*)&t_addr
, &t_addrlen
,
1243 &new_so
, CRED())) != 0) {
1244 mutex_enter(&svc
->is_mutex
);
1245 if (rc
!= ECONNABORTED
&& rc
!= EINTR
) {
1246 IDM_SVC_LOG(CE_NOTE
, "idm_so_svc_port_watcher:"
1247 " ksocket_accept failed %d", rc
);
1250 * Unclean shutdown of this thread is not handled
1251 * wait for !is_thread_running.
1255 idmrc
= idm_svc_conn_create(svc
, IDM_TRANSPORT_TYPE_SOCKETS
,
1257 if (idmrc
!= IDM_STATUS_SUCCESS
) {
1258 /* Drop connection */
1259 idm_soshutdown(new_so
);
1260 idm_sodestroy(new_so
);
1261 mutex_enter(&svc
->is_mutex
);
1265 idmrc
= idm_so_tgt_conn_create(ic
, new_so
);
1266 if (idmrc
!= IDM_STATUS_SUCCESS
) {
1267 idm_svc_conn_destroy(ic
);
1268 idm_soshutdown(new_so
);
1269 idm_sodestroy(new_so
);
1270 mutex_enter(&svc
->is_mutex
);
1275 * Kick the state machine. At CS_S3_XPT_UP the state machine
1276 * will notify the client (target) about the new connection.
1278 idm_conn_event(ic
, CE_CONNECT_ACCEPT
, (uintptr_t)NULL
);
1280 mutex_enter(&svc
->is_mutex
);
1282 ksocket_rele(so_svc
->is_so
);
1283 so_svc
->is_thread_running
= B_FALSE
;
1284 mutex_exit(&svc
->is_mutex
);
1286 IDM_SVC_LOG(CE_NOTE
, "iSCSI service (%p/%d) offline", (void *)svc
,
1287 svc
->is_svc_req
.sr_port
);
1293 * idm_so_free_task_rsrc() stops any ongoing processing of the task and
1294 * frees resources associated with the task.
1296 * It's not clear that this should return idm_status_t. What do we do
1300 idm_so_free_task_rsrc(idm_task_t
*idt
)
1302 idm_buf_t
*idb
, *next_idb
;
1305 * There is nothing to cleanup on initiator connections
1307 if (IDM_CONN_ISINI(idt
->idt_ic
))
1308 return (IDM_STATUS_SUCCESS
);
1311 * If this is a target connection, call idm_buf_rx_from_ini_done for
1312 * any buffer on the "outbufv" list with idb->idb_in_transport==B_TRUE.
1314 * In addition, remove any buffers associated with this task from
1315 * the ic_tx_list. We'll do this by walking the idt_inbufv list, but
1316 * items don't actually get removed from that list (and completion
1317 * routines called) until idm_task_cleanup.
1319 mutex_enter(&idt
->idt_mutex
);
1321 for (idb
= list_head(&idt
->idt_outbufv
); idb
!= NULL
; idb
= next_idb
) {
1322 next_idb
= list_next(&idt
->idt_outbufv
, idb
);
1323 if (idb
->idb_in_transport
) {
1325 * idm_buf_rx_from_ini_done releases idt->idt_mutex
1327 DTRACE_ISCSI_8(xfer__done
, idm_conn_t
*, idt
->idt_ic
,
1328 uintptr_t, idb
->idb_buf
,
1329 uint32_t, idb
->idb_bufoffset
,
1330 uint64_t, 0, uint32_t, 0, uint32_t, 0,
1331 uint32_t, idb
->idb_xfer_len
,
1332 int, XFER_BUF_RX_FROM_INI
);
1333 idm_buf_rx_from_ini_done(idt
, idb
, IDM_STATUS_ABORTED
);
1334 mutex_enter(&idt
->idt_mutex
);
1338 for (idb
= list_head(&idt
->idt_inbufv
); idb
!= NULL
; idb
= next_idb
) {
1339 next_idb
= list_next(&idt
->idt_inbufv
, idb
);
1341 * We want to remove these items from the tx_list as well,
1342 * but knowing it's in the idt_inbufv list is not a guarantee
1343 * that it's in the tx_list. If it's on the tx list then
1344 * let idm_sotx_thread() clean it up.
1346 if (idb
->idb_in_transport
&& !idb
->idb_tx_thread
) {
1348 * idm_buf_tx_to_ini_done releases idt->idt_mutex
1350 DTRACE_ISCSI_8(xfer__done
, idm_conn_t
*, idt
->idt_ic
,
1351 uintptr_t, idb
->idb_buf
,
1352 uint32_t, idb
->idb_bufoffset
,
1353 uint64_t, 0, uint32_t, 0, uint32_t, 0,
1354 uint32_t, idb
->idb_xfer_len
,
1355 int, XFER_BUF_TX_TO_INI
);
1356 idm_buf_tx_to_ini_done(idt
, idb
, IDM_STATUS_ABORTED
);
1357 mutex_enter(&idt
->idt_mutex
);
1361 mutex_exit(&idt
->idt_mutex
);
1363 return (IDM_STATUS_SUCCESS
);
1367 * idm_so_negotiate_key_values() validates the key values for this connection
1371 idm_so_negotiate_key_values(idm_conn_t
*it
, nvlist_t
*request_nvl
,
1372 nvlist_t
*response_nvl
, nvlist_t
*negotiated_nvl
)
1374 /* All parameters are negotiated at the iscsit level */
1375 return (KV_HANDLED
);
1379 * idm_so_notice_key_values() activates the negotiated key values for
1383 idm_so_notice_key_values(idm_conn_t
*it
, nvlist_t
*negotiated_nvl
)
1389 idm_status_t idm_status
;
1390 const idm_kv_xlate_t
*ikvx
;
1393 for (nvp
= nvlist_next_nvpair(negotiated_nvl
, NULL
);
1394 nvp
!= NULL
; nvp
= next_nvp
) {
1395 next_nvp
= nvlist_next_nvpair(negotiated_nvl
, nvp
);
1396 nvp_name
= nvpair_name(nvp
);
1398 ikvx
= idm_lookup_kv_xlate(nvp_name
, strlen(nvp_name
));
1399 switch (ikvx
->ik_key_id
) {
1400 case KI_HEADER_DIGEST
:
1401 case KI_DATA_DIGEST
:
1402 idm_status
= idm_so_handle_digest(it
, nvp
, ikvx
);
1403 ASSERT(idm_status
== 0);
1405 /* Remove processed item from negotiated_nvl list */
1406 nvrc
= nvlist_remove_all(
1407 negotiated_nvl
, ikvx
->ik_key_name
);
1410 case KI_MAX_RECV_DATA_SEGMENT_LENGTH
:
1412 * Just pass the value down to idm layer.
1413 * No need to remove it from negotiated_nvl list here.
1415 nvrc
= nvpair_value_uint64(nvp
, &num_val
);
1417 it
->ic_conn_params
.max_xmit_dataseglen
=
1427 * idm_so_declare_key_values() declares the key values for this connection
1431 idm_so_declare_key_values(idm_conn_t
*it
, nvlist_t
*config_nvl
,
1432 nvlist_t
*outgoing_nvl
)
1439 const idm_kv_xlate_t
*ikvx
;
1442 for (nvp
= nvlist_next_nvpair(config_nvl
, NULL
);
1443 nvp
!= NULL
&& nvrc
== 0; nvp
= next_nvp
) {
1444 next_nvp
= nvlist_next_nvpair(config_nvl
, nvp
);
1445 nvp_name
= nvpair_name(nvp
);
1447 ikvx
= idm_lookup_kv_xlate(nvp_name
, strlen(nvp_name
));
1448 switch (ikvx
->ik_key_id
) {
1449 case KI_MAX_RECV_DATA_SEGMENT_LENGTH
:
1450 if ((nvrc
= nvpair_value_uint64(nvp
, &num_val
)) != 0) {
1454 (nvrc
= nvlist_add_uint64(outgoing_nvl
,
1455 nvp_name
, num_val
)) != 0) {
1458 it
->ic_conn_params
.max_recv_dataseglen
=
1465 kvrc
= idm_nvstat_to_kvstat(nvrc
);
1470 idm_so_handle_digest(idm_conn_t
*it
, nvpair_t
*digest_choice
,
1471 const idm_kv_xlate_t
*ikvx
)
1474 char *digest_choice_string
;
1476 nvrc
= nvpair_value_string(digest_choice
,
1477 &digest_choice_string
);
1479 if (strcasecmp(digest_choice_string
, "crc32c") == 0) {
1480 switch (ikvx
->ik_key_id
) {
1481 case KI_HEADER_DIGEST
:
1482 it
->ic_conn_flags
|= IDM_CONN_HEADER_DIGEST
;
1484 case KI_DATA_DIGEST
:
1485 it
->ic_conn_flags
|= IDM_CONN_DATA_DIGEST
;
1491 } else if (strcasecmp(digest_choice_string
, "none") == 0) {
1492 switch (ikvx
->ik_key_id
) {
1493 case KI_HEADER_DIGEST
:
1494 it
->ic_conn_flags
&= ~IDM_CONN_HEADER_DIGEST
;
1496 case KI_DATA_DIGEST
:
1497 it
->ic_conn_flags
&= ~IDM_CONN_DATA_DIGEST
;
1507 return (IDM_STATUS_SUCCESS
);
1512 * idm_so_conn_is_capable() verifies that the passed connection is provided
1513 * for by the sockets interface.
1517 idm_so_conn_is_capable(idm_conn_req_t
*ic
, idm_transport_caps_t
*caps
)
1523 * idm_so_rx_datain() validates the Data Sequence number of the PDU. The
1524 * idm_sorecv_scsidata() function invoked earlier actually reads the data
1525 * off the socket into the appropriate buffers.
1528 idm_so_rx_datain(idm_conn_t
*ic
, idm_pdu_t
*pdu
)
1530 iscsi_data_hdr_t
*bhs
;
1535 iscsi_hdr_t
*ihp
= (iscsi_hdr_t
*)pdu
->isp_hdr
;
1536 iscsi_data_rsp_hdr_t
*idrhp
= (iscsi_data_rsp_hdr_t
*)ihp
;
1539 ASSERT(pdu
!= NULL
);
1541 bhs
= (iscsi_data_hdr_t
*)pdu
->isp_hdr
;
1542 datasn
= ntohl(bhs
->datasn
);
1543 offset
= ntohl(bhs
->offset
);
1545 ASSERT(bhs
->opcode
== ISCSI_OP_SCSI_DATA_RSP
);
1548 * Look up the task corresponding to the initiator task tag
1549 * to get the buffers affiliated with the task.
1551 idt
= idm_task_find(ic
, bhs
->itt
, bhs
->ttt
);
1553 IDM_CONN_LOG(CE_WARN
, "idm_so_rx_datain: failed to find task");
1554 idm_pdu_rx_protocol_error(ic
, pdu
);
1558 idb
= pdu
->isp_sorx_buf
;
1560 IDM_CONN_LOG(CE_WARN
,
1561 "idm_so_rx_datain: failed to find buffer");
1563 idm_pdu_rx_protocol_error(ic
, pdu
);
1568 * DataSN values should be sequential and should not have any gaps or
1569 * repetitions. Check the DataSN with the one stored in the task.
1571 if (datasn
== idt
->idt_exp_datasn
) {
1572 idt
->idt_exp_datasn
++; /* keep track of DataSN received */
1574 IDM_CONN_LOG(CE_WARN
, "idm_so_rx_datain: datasn out of order");
1576 idm_pdu_rx_protocol_error(ic
, pdu
);
1581 * PDUs in a sequence should be in continuously increasing
1584 if (offset
!= idb
->idb_exp_offset
) {
1585 IDM_CONN_LOG(CE_WARN
, "idm_so_rx_datain: unexpected offset");
1587 idm_pdu_rx_protocol_error(ic
, pdu
);
1590 /* Expected next relative buffer offset */
1591 idb
->idb_exp_offset
+= n2h24(bhs
->dlength
);
1592 idt
->idt_rx_bytes
+= n2h24(bhs
->dlength
);
1597 * For now call scsi_rsp which will process the data rsp
1598 * Revisit, need to provide an explicit client entry point for
1599 * phase collapse completions.
1601 if (((ihp
->opcode
& ISCSI_OPCODE_MASK
) == ISCSI_OP_SCSI_DATA_RSP
) &&
1602 (idrhp
->flags
& ISCSI_FLAG_DATA_STATUS
)) {
1603 (*ic
->ic_conn_ops
.icb_rx_scsi_rsp
)(ic
, pdu
);
1606 idm_pdu_complete(pdu
, IDM_STATUS_SUCCESS
);
1610 * The idm_so_rx_dataout() function is used by the iSCSI target to read
1611 * data from the Data-Out PDU sent by the iSCSI initiator.
1613 * This function gets the Initiator Task Tag from the PDU BHS and looks up the
1614 * task to get the buffers associated with the PDU. A PDU might span buffers.
1615 * The data is then read into the respective buffer.
1618 idm_so_rx_dataout(idm_conn_t
*ic
, idm_pdu_t
*pdu
)
1621 iscsi_data_hdr_t
*bhs
;
1627 ASSERT(pdu
!= NULL
);
1629 bhs
= (iscsi_data_hdr_t
*)pdu
->isp_hdr
;
1630 offset
= ntohl(bhs
->offset
);
1631 ASSERT(bhs
->opcode
== ISCSI_OP_SCSI_DATA
);
1634 * Look up the task corresponding to the initiator task tag
1635 * to get the buffers affiliated with the task.
1637 idt
= idm_task_find(ic
, bhs
->itt
, bhs
->ttt
);
1639 IDM_CONN_LOG(CE_WARN
,
1640 "idm_so_rx_dataout: failed to find task");
1641 idm_pdu_rx_protocol_error(ic
, pdu
);
1645 idb
= pdu
->isp_sorx_buf
;
1647 IDM_CONN_LOG(CE_WARN
,
1648 "idm_so_rx_dataout: failed to find buffer");
1650 idm_pdu_rx_protocol_error(ic
, pdu
);
1654 /* Keep track of data transferred - check data offsets */
1655 if (offset
!= idb
->idb_exp_offset
) {
1656 IDM_CONN_LOG(CE_NOTE
, "idm_so_rx_dataout: offset out of seq: "
1657 "%ld, %d", offset
, idb
->idb_exp_offset
);
1659 idm_pdu_rx_protocol_error(ic
, pdu
);
1662 /* Expected next relative offset */
1663 idb
->idb_exp_offset
+= ntoh24(bhs
->dlength
);
1664 idt
->idt_rx_bytes
+= n2h24(bhs
->dlength
);
1667 * Call the buffer callback when the transfer is complete
1669 * The connection state machine should only abort tasks after
1670 * shutting down the connection so we are assured that there
1671 * won't be a simultaneous attempt to abort this task at the
1672 * same time as we are processing this PDU (due to a connection
1675 if (bhs
->flags
& ISCSI_FLAG_FINAL
) {
1677 * We only want to call idm_buf_rx_from_ini_done once
1678 * per transfer. It's possible that this task has
1679 * already been aborted in which case
1680 * idm_so_free_task_rsrc will call idm_buf_rx_from_ini_done
1681 * for each buffer with idb_in_transport==B_TRUE. To
1682 * close this window and ensure that this doesn't happen,
1683 * we'll clear idb->idb_in_transport now while holding
1684 * the task mutex. This is only really an issue for
1685 * SCSI task abort -- if tasks were being aborted because
1686 * of a connection state change the state machine would
1687 * have already stopped the receive thread.
1689 mutex_enter(&idt
->idt_mutex
);
1692 * Release the task hold here (obtained in idm_task_find)
1693 * because the task may complete synchronously during
1694 * idm_buf_rx_from_ini_done. Since we still have an active
1695 * buffer we know there is at least one additional hold on idt.
1700 * idm_buf_rx_from_ini_done releases idt->idt_mutex
1702 DTRACE_ISCSI_8(xfer__done
, idm_conn_t
*, idt
->idt_ic
,
1703 uintptr_t, idb
->idb_buf
, uint32_t, idb
->idb_bufoffset
,
1704 uint64_t, 0, uint32_t, 0, uint32_t, 0,
1705 uint32_t, idb
->idb_xfer_len
,
1706 int, XFER_BUF_RX_FROM_INI
);
1707 idm_buf_rx_from_ini_done(idt
, idb
, IDM_STATUS_SUCCESS
);
1708 idm_pdu_complete(pdu
, IDM_STATUS_SUCCESS
);
1713 idm_pdu_complete(pdu
, IDM_STATUS_SUCCESS
);
1717 * The idm_so_rx_rtt() function is used by the iSCSI initiator to handle
1718 * the R2T PDU sent by the iSCSI target indicating that it is ready to
1719 * accept data. This gets the Initiator Task Tag (itt) from the PDU BHS
1720 * and looks up the task in the task tree using the itt to get the output
1721 * buffers associated the task. The R2T PDU contains the offset of the
1722 * requested data and the data length. This function then constructs a
1723 * sequence of iSCSI PDUs and outputs the requested data. Each Data-Out
1724 * PDU is associated with the R2T by the Target Transfer Tag (ttt).
1728 idm_so_rx_rtt(idm_conn_t
*ic
, idm_pdu_t
*pdu
)
1732 iscsi_rtt_hdr_t
*rtt_hdr
;
1733 uint32_t data_offset
;
1734 uint32_t data_length
;
1737 ASSERT(pdu
!= NULL
);
1739 rtt_hdr
= (iscsi_rtt_hdr_t
*)pdu
->isp_hdr
;
1740 data_offset
= ntohl(rtt_hdr
->data_offset
);
1741 data_length
= ntohl(rtt_hdr
->data_length
);
1742 idt
= idm_task_find(ic
, rtt_hdr
->itt
, rtt_hdr
->ttt
);
1745 IDM_CONN_LOG(CE_WARN
, "idm_so_rx_rtt: could not find task");
1746 idm_pdu_rx_protocol_error(ic
, pdu
);
1750 /* Find the buffer bound to the task by the iSCSI initiator */
1751 mutex_enter(&idt
->idt_mutex
);
1752 idb
= idm_buf_find(&idt
->idt_outbufv
, data_offset
);
1754 mutex_exit(&idt
->idt_mutex
);
1756 IDM_CONN_LOG(CE_WARN
, "idm_so_rx_rtt: could not find buffer");
1757 idm_pdu_rx_protocol_error(ic
, pdu
);
1761 /* return buffer contains this data */
1762 if (data_offset
+ data_length
> idb
->idb_buflen
) {
1764 mutex_exit(&idt
->idt_mutex
);
1766 IDM_CONN_LOG(CE_WARN
, "idm_so_rx_rtt: read from outside "
1768 idm_pdu_rx_protocol_error(ic
, pdu
);
1772 idt
->idt_r2t_ttt
= rtt_hdr
->ttt
;
1773 idt
->idt_exp_datasn
= 0;
1775 idm_so_send_rtt_data(ic
, idt
, idb
, data_offset
,
1776 ntohl(rtt_hdr
->data_length
));
1778 * the idt_mutex is released in idm_so_send_rtt_data
1781 idm_pdu_complete(pdu
, IDM_STATUS_SUCCESS
);
1787 idm_sorecvdata(idm_conn_t
*ic
, idm_pdu_t
*pdu
)
1789 uint8_t pad
[ISCSI_PAD_WORD_LEN
];
1791 uint32_t data_digest_crc
;
1792 uint32_t crc_calculated
;
1794 idm_so_conn_t
*so_conn
;
1796 so_conn
= ic
->ic_transport_private
;
1798 pad_len
= ((ISCSI_PAD_WORD_LEN
-
1799 (pdu
->isp_datalen
& (ISCSI_PAD_WORD_LEN
- 1))) &
1800 (ISCSI_PAD_WORD_LEN
- 1));
1802 ASSERT(pdu
->isp_iovlen
< (PDU_MAX_IOVLEN
- 2)); /* pad + data digest */
1804 total_len
= pdu
->isp_datalen
;
1807 pdu
->isp_iov
[pdu
->isp_iovlen
].iov_base
= (char *)&pad
;
1808 pdu
->isp_iov
[pdu
->isp_iovlen
].iov_len
= pad_len
;
1809 total_len
+= pad_len
;
1813 /* setup data digest */
1814 if ((ic
->ic_conn_flags
& IDM_CONN_DATA_DIGEST
) != 0) {
1815 pdu
->isp_iov
[pdu
->isp_iovlen
].iov_base
=
1816 (char *)&data_digest_crc
;
1817 pdu
->isp_iov
[pdu
->isp_iovlen
].iov_len
=
1818 sizeof (data_digest_crc
);
1819 total_len
+= sizeof (data_digest_crc
);
1823 pdu
->isp_data
= (uint8_t *)(uintptr_t)pdu
->isp_iov
[0].iov_base
;
1825 if (idm_iov_sorecv(so_conn
->ic_so
, &pdu
->isp_iov
[0],
1826 pdu
->isp_iovlen
, total_len
) != 0) {
1827 return (IDM_STATUS_IO
);
1830 if ((ic
->ic_conn_flags
& IDM_CONN_DATA_DIGEST
) != 0) {
1831 crc_calculated
= idm_crc32c(pdu
->isp_data
,
1834 crc_calculated
= idm_crc32c_continued((char *)&pad
,
1835 pad_len
, crc_calculated
);
1837 if (crc_calculated
!= data_digest_crc
) {
1838 IDM_CONN_LOG(CE_WARN
,
1840 "CRC error: actual 0x%x, calc 0x%x",
1841 data_digest_crc
, crc_calculated
);
1843 /* Invalid Data Digest */
1844 return (IDM_STATUS_DATA_DIGEST
);
1848 return (IDM_STATUS_SUCCESS
);
1852 * idm_sorecv_scsidata() is used to receive scsi data from the socket. The
1853 * Data-type PDU header must be read into the idm_pdu_t structure prior to
1854 * calling this function.
1857 idm_sorecv_scsidata(idm_conn_t
*ic
, idm_pdu_t
*pdu
)
1859 iscsi_data_hdr_t
*bhs
;
1865 uint32_t xfer_bytes
;
1866 idm_status_t status
;
1869 ASSERT(pdu
!= NULL
);
1871 bhs
= (iscsi_data_hdr_t
*)pdu
->isp_hdr
;
1873 offset
= ntohl(bhs
->offset
);
1874 opcode
= bhs
->opcode
;
1875 dlength
= n2h24(bhs
->dlength
);
1877 ASSERT((opcode
== ISCSI_OP_SCSI_DATA_RSP
) ||
1878 (opcode
== ISCSI_OP_SCSI_DATA
));
1881 * Successful lookup implicitly gets a "hold" on the task. This
1882 * hold must be released before leaving this function. At one
1883 * point we were caching this task context and retaining the hold
1884 * but it turned out to be very difficult to release the hold properly.
1885 * The task can be aborted and the connection shutdown between this
1886 * call and the subsequent expected call to idm_so_rx_datain/
1887 * idm_so_rx_dataout (in which case those functions are not called).
1888 * Releasing the hold in the PDU callback doesn't work well either
1889 * because the whole task may be completed by then at which point
1890 * it is too late to release the hold -- for better or worse this
1891 * code doesn't wait on the refcnts during normal operation.
1892 * idm_task_find() is very fast and it is not a huge burden if we
1893 * have to do it twice.
1895 task
= idm_task_find(ic
, bhs
->itt
, bhs
->ttt
);
1897 IDM_CONN_LOG(CE_WARN
,
1898 "idm_sorecv_scsidata: could not find task");
1899 return (IDM_STATUS_FAIL
);
1902 mutex_enter(&task
->idt_mutex
);
1903 buflst
= (opcode
== ISCSI_OP_SCSI_DATA_RSP
) ?
1904 &task
->idt_inbufv
: &task
->idt_outbufv
;
1905 pdu
->isp_sorx_buf
= idm_buf_find(buflst
, offset
);
1906 mutex_exit(&task
->idt_mutex
);
1908 if (pdu
->isp_sorx_buf
== NULL
) {
1909 idm_task_rele(task
);
1910 IDM_CONN_LOG(CE_WARN
, "idm_sorecv_scsidata: could not find "
1911 "buffer for offset %x opcode=%x",
1913 return (IDM_STATUS_FAIL
);
1916 xfer_bytes
= idm_fill_iov(pdu
, pdu
->isp_sorx_buf
, offset
, dlength
);
1917 ASSERT(xfer_bytes
!= 0);
1918 if (xfer_bytes
!= dlength
) {
1919 idm_task_rele(task
);
1921 * Buffer overflow, connection error. The PDU data is still
1922 * sitting in the socket so we can't use the connection
1923 * again until that data is drained.
1925 return (IDM_STATUS_FAIL
);
1928 status
= idm_sorecvdata(ic
, pdu
);
1930 idm_task_rele(task
);
1936 idm_fill_iov(idm_pdu_t
*pdu
, idm_buf_t
*idb
, uint32_t ro
, uint32_t dlength
)
1938 uint32_t buf_ro
= ro
- idb
->idb_bufoffset
;
1939 uint32_t xfer_len
= min(dlength
, idb
->idb_buflen
- buf_ro
);
1941 ASSERT(ro
>= idb
->idb_bufoffset
);
1943 pdu
->isp_iov
[pdu
->isp_iovlen
].iov_base
=
1944 (caddr_t
)idb
->idb_buf
+ buf_ro
;
1945 pdu
->isp_iov
[pdu
->isp_iovlen
].iov_len
= xfer_len
;
1952 idm_sorecv_nonscsidata(idm_conn_t
*ic
, idm_pdu_t
*pdu
)
1954 pdu
->isp_data
= kmem_alloc(pdu
->isp_datalen
, KM_SLEEP
);
1955 ASSERT(pdu
->isp_data
!= NULL
);
1957 pdu
->isp_databuflen
= pdu
->isp_datalen
;
1958 pdu
->isp_iov
[0].iov_base
= (caddr_t
)pdu
->isp_data
;
1959 pdu
->isp_iov
[0].iov_len
= pdu
->isp_datalen
;
1960 pdu
->isp_iovlen
= 1;
1962 * Since we are associating a new data buffer with this received
1963 * PDU we need to set a specific callback to free the data
1964 * after the PDU is processed.
1966 pdu
->isp_flags
|= IDM_PDU_ADDL_DATA
;
1967 pdu
->isp_callback
= idm_sorx_addl_pdu_cb
;
1969 return (idm_sorecvdata(ic
, pdu
));
1973 idm_sorx_thread(void *arg
)
1975 boolean_t conn_failure
= B_FALSE
;
1976 idm_conn_t
*ic
= (idm_conn_t
*)arg
;
1977 idm_so_conn_t
*so_conn
;
1983 mutex_enter(&ic
->ic_mutex
);
1985 so_conn
= ic
->ic_transport_private
;
1986 so_conn
->ic_rx_thread_running
= B_TRUE
;
1987 so_conn
->ic_rx_thread_did
= so_conn
->ic_rx_thread
->t_did
;
1988 cv_signal(&ic
->ic_cv
);
1990 while (so_conn
->ic_rx_thread_running
) {
1991 mutex_exit(&ic
->ic_mutex
);
1994 * Get PDU with default header size (large enough for
1995 * BHS plus any anticipated AHS). PDU from
1996 * the cache will have all values set correctly
1997 * for sockets RX including callback.
1999 pdu
= kmem_cache_alloc(idm
.idm_sorx_pdu_cache
, KM_SLEEP
);
2002 pdu
->isp_transport_hdrlen
= 0;
2004 if ((rc
= idm_sorecvhdr(ic
, pdu
)) != 0) {
2006 * Call idm_pdu_complete so that we call the callback
2007 * and ensure any memory allocated in idm_sorecvhdr
2010 idm_pdu_complete(pdu
, IDM_STATUS_FAIL
);
2013 * If ic_rx_thread_running is still set then
2014 * this is some kind of connection problem
2015 * on the socket. In this case we want to
2016 * generate an event. Otherwise some other
2017 * thread closed the socket due to another
2018 * issue in which case we don't need to
2019 * generate an event.
2021 mutex_enter(&ic
->ic_mutex
);
2022 if (so_conn
->ic_rx_thread_running
) {
2023 conn_failure
= B_TRUE
;
2024 so_conn
->ic_rx_thread_running
= B_FALSE
;
2031 * Header has been read and validated. Now we need
2032 * to read the PDU data payload (if present). SCSI data
2033 * need to be transferred from the socket directly into
2034 * the associated transfer buffer for the SCSI task.
2036 if (pdu
->isp_datalen
!= 0) {
2037 if ((IDM_PDU_OPCODE(pdu
) == ISCSI_OP_SCSI_DATA
) ||
2038 (IDM_PDU_OPCODE(pdu
) == ISCSI_OP_SCSI_DATA_RSP
)) {
2039 rc
= idm_sorecv_scsidata(ic
, pdu
);
2041 * All SCSI errors are fatal to the
2042 * connection right now since we have no
2043 * place to put the data. What we need
2044 * is some kind of sink to dispose of unwanted
2045 * SCSI data. For example an invalid task tag
2046 * should not kill the connection (although
2047 * we may want to drop the connection).
2051 * Not data PDUs so allocate a buffer for the
2052 * data segment and read the remaining data.
2054 rc
= idm_sorecv_nonscsidata(ic
, pdu
);
2058 * Call idm_pdu_complete so that we call the
2059 * callback and ensure any memory allocated
2060 * in idm_sorecvhdr gets freed up.
2062 idm_pdu_complete(pdu
, IDM_STATUS_FAIL
);
2065 * If ic_rx_thread_running is still set then
2066 * this is some kind of connection problem
2067 * on the socket. In this case we want to
2068 * generate an event. Otherwise some other
2069 * thread closed the socket due to another
2070 * issue in which case we don't need to
2071 * generate an event.
2073 mutex_enter(&ic
->ic_mutex
);
2074 if (so_conn
->ic_rx_thread_running
) {
2075 conn_failure
= B_TRUE
;
2076 so_conn
->ic_rx_thread_running
= B_FALSE
;
2085 idm_pdu_rx(ic
, pdu
);
2087 mutex_enter(&ic
->ic_mutex
);
2090 mutex_exit(&ic
->ic_mutex
);
2093 * If we dropped out of the RX processing loop because of
2094 * a socket problem or other connection failure (including
2095 * digest errors) then we need to generate a state machine
2096 * event to shut the connection down.
2097 * If the state machine is already in, for example, INIT_ERROR, this
2098 * event will get dropped, and the TX thread will never be notified
2099 * to shut down. To be safe, we'll just notify it here.
2102 if (so_conn
->ic_tx_thread_running
) {
2103 so_conn
->ic_tx_thread_running
= B_FALSE
;
2104 mutex_enter(&so_conn
->ic_tx_mutex
);
2105 cv_signal(&so_conn
->ic_tx_cv
);
2106 mutex_exit(&so_conn
->ic_tx_mutex
);
2109 idm_conn_event(ic
, CE_TRANSPORT_FAIL
, rc
);
2120 * This is the implementation of idm_transport_ops_t's it_tx_pdu entry
2121 * point. By definition, it is supposed to be fast. So, simply queue
2122 * the entry and return. The real work is done by idm_i_so_tx() via
2123 * idm_sotx_thread().
2127 idm_so_tx(idm_conn_t
*ic
, idm_pdu_t
*pdu
)
2129 idm_so_conn_t
*so_conn
= ic
->ic_transport_private
;
2131 ASSERT(pdu
->isp_ic
== ic
);
2132 mutex_enter(&so_conn
->ic_tx_mutex
);
2134 if (!so_conn
->ic_tx_thread_running
) {
2135 mutex_exit(&so_conn
->ic_tx_mutex
);
2136 idm_pdu_complete(pdu
, IDM_STATUS_ABORTED
);
2140 list_insert_tail(&so_conn
->ic_tx_list
, (void *)pdu
);
2141 cv_signal(&so_conn
->ic_tx_cv
);
2142 mutex_exit(&so_conn
->ic_tx_mutex
);
2146 idm_i_so_tx(idm_pdu_t
*pdu
)
2148 idm_conn_t
*ic
= pdu
->isp_ic
;
2149 idm_status_t status
= IDM_STATUS_SUCCESS
;
2150 uint8_t pad
[ISCSI_PAD_WORD_LEN
];
2152 uint32_t hdr_digest_crc
;
2153 uint32_t data_digest_crc
= 0;
2156 struct iovec iov
[6];
2157 idm_so_conn_t
*so_conn
;
2159 so_conn
= ic
->ic_transport_private
;
2162 iov
[iovlen
].iov_base
= (caddr_t
)pdu
->isp_hdr
;
2163 iov
[iovlen
].iov_len
= pdu
->isp_hdrlen
;
2164 total_len
+= iov
[iovlen
].iov_len
;
2167 /* Setup header digest */
2168 if (((pdu
->isp_flags
& IDM_PDU_LOGIN_TX
) == 0) &&
2169 (ic
->ic_conn_flags
& IDM_CONN_HEADER_DIGEST
)) {
2170 hdr_digest_crc
= idm_crc32c(pdu
->isp_hdr
, pdu
->isp_hdrlen
);
2172 iov
[iovlen
].iov_base
= (caddr_t
)&hdr_digest_crc
;
2173 iov
[iovlen
].iov_len
= sizeof (hdr_digest_crc
);
2174 total_len
+= iov
[iovlen
].iov_len
;
2178 /* Setup the data */
2179 if (pdu
->isp_datalen
) {
2182 iscsi_data_hdr_t
*ihp
;
2183 ihp
= (iscsi_data_hdr_t
*)pdu
->isp_hdr
;
2184 /* Write of immediate data */
2186 (ihp
->opcode
== ISCSI_OP_SCSI_CMD
||
2187 ihp
->opcode
== ISCSI_OP_SCSI_DATA
)) {
2188 idt
= idm_task_find(ic
, ihp
->itt
, ihp
->ttt
);
2190 mutex_enter(&idt
->idt_mutex
);
2191 idb
= idm_buf_find(&idt
->idt_outbufv
, 0);
2192 mutex_exit(&idt
->idt_mutex
);
2194 * If the initiator call to idm_buf_alloc
2195 * failed then we can get to this point
2196 * without a bound buffer. The associated
2197 * connection failure will clean things up
2198 * later. It would be nice to come up with
2199 * a cleaner way to handle this. In
2200 * particular it seems absurd to look up
2201 * the task and the buffer just to update
2205 idb
->idb_xfer_len
+= pdu
->isp_datalen
;
2210 iov
[iovlen
].iov_base
= (caddr_t
)pdu
->isp_data
;
2211 iov
[iovlen
].iov_len
= pdu
->isp_datalen
;
2212 total_len
+= iov
[iovlen
].iov_len
;
2216 /* Setup the data pad if necessary */
2217 pad_len
= ((ISCSI_PAD_WORD_LEN
-
2218 (pdu
->isp_datalen
& (ISCSI_PAD_WORD_LEN
- 1))) &
2219 (ISCSI_PAD_WORD_LEN
- 1));
2222 bzero(pad
, sizeof (pad
));
2223 iov
[iovlen
].iov_base
= (void *)&pad
;
2224 iov
[iovlen
].iov_len
= pad_len
;
2225 total_len
+= iov
[iovlen
].iov_len
;
2230 * Setup the data digest if enabled. Data-digest is not sent
2231 * for login-phase PDUs.
2233 if ((ic
->ic_conn_flags
& IDM_CONN_DATA_DIGEST
) &&
2234 ((pdu
->isp_flags
& IDM_PDU_LOGIN_TX
) == 0) &&
2235 (pdu
->isp_datalen
|| pad_len
)) {
2237 * RFC3720/10.2.3: A zero-length Data Segment also
2238 * implies a zero-length data digest.
2240 if (pdu
->isp_datalen
) {
2241 data_digest_crc
= idm_crc32c(pdu
->isp_data
,
2245 data_digest_crc
= idm_crc32c_continued(&pad
,
2246 pad_len
, data_digest_crc
);
2249 iov
[iovlen
].iov_base
= (caddr_t
)&data_digest_crc
;
2250 iov
[iovlen
].iov_len
= sizeof (data_digest_crc
);
2251 total_len
+= iov
[iovlen
].iov_len
;
2255 /* Transmit the PDU */
2256 if (idm_iov_sosend(so_conn
->ic_so
, &iov
[0], iovlen
,
2258 /* Set error status */
2259 IDM_CONN_LOG(CE_WARN
,
2260 "idm_so_tx: failed to transmit the PDU, so: %p ic: %p "
2261 "data: %p", (void *) so_conn
->ic_so
, (void *) ic
,
2262 (void *) pdu
->isp_data
);
2263 status
= IDM_STATUS_IO
;
2267 * Success does not mean that the PDU actually reached the
2268 * remote node since it could get dropped along the way.
2270 idm_pdu_complete(pdu
, status
);
2276 * The idm_so_buf_tx_to_ini() is used by the target iSCSI layer to transmit the
2277 * Data-In PDUs using sockets. Based on the negotiated MaxRecvDataSegmentLength,
2278 * the buffer is segmented into a sequence of Data-In PDUs, ordered by DataSN.
2279 * A target can invoke this function multiple times for a single read command
2280 * (identified by the same ITT) to split the input into several sequences.
2282 * DataSN starts with 0 for the first data PDU of an input command and advances
2283 * by 1 for each subsequent data PDU. Each sequence will have its own F bit,
2284 * which is set to 1 for the last data PDU of a sequence.
2285 * If the initiator supports phase collapse, the status bit must be set along
2286 * with the F bit to indicate that the status is shipped together with the last
2289 * The data PDUs within a sequence will be sent in order with the buffer offset
2290 * in increasing order. i.e. initiator and target must have negotiated the
2291 * "DataPDUInOrder" to "Yes". The order between sequences is not enforced.
2293 * Caller holds idt->idt_mutex
2296 idm_so_buf_tx_to_ini(idm_task_t
*idt
, idm_buf_t
*idb
)
2298 idm_so_conn_t
*so_conn
= idb
->idb_ic
->ic_transport_private
;
2301 ASSERT(mutex_owned(&idt
->idt_mutex
));
2304 * Put the idm_buf_t on the tx queue. It will be transmitted by
2307 mutex_enter(&so_conn
->ic_tx_mutex
);
2309 DTRACE_ISCSI_8(xfer__start
, idm_conn_t
*, idt
->idt_ic
,
2310 uintptr_t, idb
->idb_buf
, uint32_t, idb
->idb_bufoffset
,
2311 uint64_t, 0, uint32_t, 0, uint32_t, 0,
2312 uint32_t, idb
->idb_xfer_len
, int, XFER_BUF_TX_TO_INI
);
2314 if (!so_conn
->ic_tx_thread_running
) {
2315 mutex_exit(&so_conn
->ic_tx_mutex
);
2317 * Don't release idt->idt_mutex since we're supposed to hold
2318 * in when calling idm_buf_tx_to_ini_done
2320 DTRACE_ISCSI_8(xfer__done
, idm_conn_t
*, idt
->idt_ic
,
2321 uintptr_t, idb
->idb_buf
, uint32_t, idb
->idb_bufoffset
,
2322 uint64_t, 0, uint32_t, 0, uint32_t, 0,
2323 uint32_t, idb
->idb_xfer_len
,
2324 int, XFER_BUF_TX_TO_INI
);
2325 idm_buf_tx_to_ini_done(idt
, idb
, IDM_STATUS_ABORTED
);
2326 return (IDM_STATUS_FAIL
);
2330 * Build a template for the data PDU headers we will use so that
2331 * the SN values will stay consistent with other PDU's we are
2332 * transmitting like R2T and SCSI status.
2334 bzero(&idb
->idb_data_hdr_tmpl
, sizeof (iscsi_hdr_t
));
2335 tmppdu
.isp_hdr
= &idb
->idb_data_hdr_tmpl
;
2336 (*idt
->idt_ic
->ic_conn_ops
.icb_build_hdr
)(idt
, &tmppdu
,
2337 ISCSI_OP_SCSI_DATA_RSP
);
2338 idb
->idb_tx_thread
= B_TRUE
;
2339 list_insert_tail(&so_conn
->ic_tx_list
, (void *)idb
);
2340 cv_signal(&so_conn
->ic_tx_cv
);
2341 mutex_exit(&so_conn
->ic_tx_mutex
);
2342 mutex_exit(&idt
->idt_mutex
);
2345 * Returning success here indicates the transfer was successfully
2346 * dispatched -- it does not mean that the transfer completed
2349 return (IDM_STATUS_SUCCESS
);
2353 * The idm_so_buf_rx_from_ini() is used by the target iSCSI layer to specify the
2354 * data blocks it is ready to receive from the initiator in response to a WRITE
2355 * SCSI command. The target iSCSI layer passes the information about the desired
2356 * data blocks to the initiator in one R2T PDU. The receiving buffer, the buffer
2357 * offset and datalen are passed via the 'idb' argument.
2359 * Scope for Prototype build:
2360 * R2Ts are required for any Data-Out PDU, i.e. initiator and target must have
2361 * negotiated the "InitialR2T" to "Yes".
2363 * Caller holds idt->idt_mutex
2366 idm_so_buf_rx_from_ini(idm_task_t
*idt
, idm_buf_t
*idb
)
2369 iscsi_rtt_hdr_t
*rtt
;
2371 ASSERT(mutex_owned(&idt
->idt_mutex
));
2373 DTRACE_ISCSI_8(xfer__start
, idm_conn_t
*, idt
->idt_ic
,
2374 uintptr_t, idb
->idb_buf
, uint32_t, idb
->idb_bufoffset
,
2375 uint64_t, 0, uint32_t, 0, uint32_t, 0,
2376 uint32_t, idb
->idb_xfer_len
, int, XFER_BUF_RX_FROM_INI
);
2378 pdu
= kmem_cache_alloc(idm
.idm_sotx_pdu_cache
, KM_SLEEP
);
2379 pdu
->isp_ic
= idt
->idt_ic
;
2380 pdu
->isp_flags
= IDM_PDU_SET_STATSN
;
2381 bzero(pdu
->isp_hdr
, sizeof (iscsi_rtt_hdr_t
));
2383 /* iSCSI layer fills the TTT, ITT, ExpCmdSN, MaxCmdSN */
2384 (*idt
->idt_ic
->ic_conn_ops
.icb_build_hdr
)(idt
, pdu
, ISCSI_OP_RTT_RSP
);
2386 /* set the rttsn, rtt.flags, rtt.data_offset and rtt.data_length */
2387 rtt
= (iscsi_rtt_hdr_t
*)(pdu
->isp_hdr
);
2389 rtt
->opcode
= ISCSI_OP_RTT_RSP
;
2390 rtt
->flags
= ISCSI_FLAG_FINAL
;
2391 rtt
->data_offset
= htonl(idb
->idb_bufoffset
);
2392 rtt
->data_length
= htonl(idb
->idb_xfer_len
);
2393 rtt
->rttsn
= htonl(idt
->idt_exp_rttsn
++);
2395 /* Keep track of buffer offsets */
2396 idb
->idb_exp_offset
= idb
->idb_bufoffset
;
2397 mutex_exit(&idt
->idt_mutex
);
2404 return (IDM_STATUS_SUCCESS
);
2408 idm_so_buf_alloc(idm_buf_t
*idb
, uint64_t buflen
)
2410 if ((buflen
> IDM_SO_BUF_CACHE_LB
) && (buflen
<= IDM_SO_BUF_CACHE_UB
)) {
2411 idb
->idb_buf
= kmem_cache_alloc(idm
.idm_so_128k_buf_cache
,
2413 idb
->idb_buf_private
= idm
.idm_so_128k_buf_cache
;
2415 idb
->idb_buf
= kmem_alloc(buflen
, KM_NOSLEEP
);
2416 idb
->idb_buf_private
= NULL
;
2419 if (idb
->idb_buf
== NULL
) {
2420 IDM_CONN_LOG(CE_NOTE
,
2421 "idm_so_buf_alloc: failed buffer allocation");
2422 return (IDM_STATUS_FAIL
);
2425 return (IDM_STATUS_SUCCESS
);
2430 idm_so_buf_setup(idm_buf_t
*idb
)
2432 /* Ensure bufalloc'd flag is unset */
2433 idb
->idb_bufalloc
= B_FALSE
;
2435 return (IDM_STATUS_SUCCESS
);
2440 idm_so_buf_teardown(idm_buf_t
*idb
)
2442 /* nothing to do here */
2446 idm_so_buf_free(idm_buf_t
*idb
)
2448 if (idb
->idb_buf_private
== NULL
) {
2449 kmem_free(idb
->idb_buf
, idb
->idb_buflen
);
2451 kmem_cache_free(idb
->idb_buf_private
, idb
->idb_buf
);
2456 idm_so_send_rtt_data(idm_conn_t
*ic
, idm_task_t
*idt
, idm_buf_t
*idb
,
2457 uint32_t offset
, uint32_t length
)
2459 idm_so_conn_t
*so_conn
= ic
->ic_transport_private
;
2463 ASSERT(mutex_owned(&idt
->idt_mutex
));
2466 * Allocate a buffer to represent the RTT transfer. We could further
2467 * optimize this by allocating the buffers internally from an rtt
2468 * specific buffer cache since this is socket-specific code but for
2469 * now we will keep it simple.
2471 rtt_buf
= idm_buf_alloc(ic
, (uint8_t *)idb
->idb_buf
+ offset
, length
);
2472 if (rtt_buf
== NULL
) {
2474 * If we're in FFP then the failure was likely a resource
2475 * allocation issue and we should close the connection by
2476 * sending a CE_TRANSPORT_FAIL event.
2478 * If we're not in FFP then idm_buf_alloc will always
2479 * fail and the state is transitioning to "complete" anyway
2480 * so we won't bother to send an event.
2482 mutex_enter(&ic
->ic_state_mutex
);
2484 idm_conn_event_locked(ic
, CE_TRANSPORT_FAIL
,
2485 (uintptr_t)NULL
, CT_NONE
);
2486 mutex_exit(&ic
->ic_state_mutex
);
2487 mutex_exit(&idt
->idt_mutex
);
2491 rtt_buf
->idb_buf_cb
= NULL
;
2492 rtt_buf
->idb_cb_arg
= NULL
;
2493 rtt_buf
->idb_bufoffset
= offset
;
2494 rtt_buf
->idb_xfer_len
= length
;
2495 rtt_buf
->idb_ic
= idt
->idt_ic
;
2496 rtt_buf
->idb_task_binding
= idt
;
2499 * The new buffer (if any) represents an additional
2500 * reference on the task
2503 mutex_exit(&idt
->idt_mutex
);
2506 * Put the idm_buf_t on the tx queue. It will be transmitted by
2509 mutex_enter(&so_conn
->ic_tx_mutex
);
2511 if (!so_conn
->ic_tx_thread_running
) {
2512 idm_buf_free(rtt_buf
);
2513 mutex_exit(&so_conn
->ic_tx_mutex
);
2519 * Build a template for the data PDU headers we will use so that
2520 * the SN values will stay consistent with other PDU's we are
2521 * transmitting like R2T and SCSI status.
2523 bzero(&rtt_buf
->idb_data_hdr_tmpl
, sizeof (iscsi_hdr_t
));
2524 tmppdu
.isp_hdr
= &rtt_buf
->idb_data_hdr_tmpl
;
2525 (*idt
->idt_ic
->ic_conn_ops
.icb_build_hdr
)(idt
, &tmppdu
,
2526 ISCSI_OP_SCSI_DATA
);
2527 rtt_buf
->idb_tx_thread
= B_TRUE
;
2528 rtt_buf
->idb_in_transport
= B_TRUE
;
2529 list_insert_tail(&so_conn
->ic_tx_list
, (void *)rtt_buf
);
2530 cv_signal(&so_conn
->ic_tx_cv
);
2531 mutex_exit(&so_conn
->ic_tx_mutex
);
2535 idm_so_send_rtt_data_done(idm_task_t
*idt
, idm_buf_t
*idb
)
2538 * Don't worry about status -- we assume any error handling
2539 * is performed by the caller (idm_sotx_thread).
2541 idb
->idb_in_transport
= B_FALSE
;
2547 idm_so_send_buf_region(idm_task_t
*idt
, idm_buf_t
*idb
,
2548 uint32_t buf_region_offset
, uint32_t buf_region_length
)
2551 uint32_t max_dataseglen
;
2552 size_t remainder
, chunk
;
2553 uint32_t data_offset
= buf_region_offset
;
2554 iscsi_data_hdr_t
*bhs
;
2556 idm_status_t tx_status
;
2558 ASSERT(mutex_owned(&idt
->idt_mutex
));
2562 max_dataseglen
= ic
->ic_conn_params
.max_xmit_dataseglen
;
2563 remainder
= buf_region_length
;
2566 if (idt
->idt_state
!= TASK_ACTIVE
) {
2567 ASSERT((idt
->idt_state
!= TASK_IDLE
) &&
2568 (idt
->idt_state
!= TASK_COMPLETE
));
2569 return (IDM_STATUS_ABORTED
);
2572 /* check to see if we need to chunk the data */
2573 if (remainder
> max_dataseglen
) {
2574 chunk
= max_dataseglen
;
2579 /* Data PDU headers will always be sizeof (iscsi_hdr_t) */
2580 pdu
= kmem_cache_alloc(idm
.idm_sotx_pdu_cache
, KM_SLEEP
);
2582 pdu
->isp_flags
= 0; /* initialize isp_flags */
2585 * We've already built a build a header template
2586 * to use during the transfer. Use this template so that
2587 * the SN values stay consistent with any unrelated PDU's
2588 * being transmitted.
2590 bcopy(&idb
->idb_data_hdr_tmpl
, pdu
->isp_hdr
,
2591 sizeof (iscsi_hdr_t
));
2594 * Set DataSN, data offset, and flags in BHS
2595 * For the prototype build, A = 0, S = 0, U = 0
2597 bhs
= (iscsi_data_hdr_t
*)(pdu
->isp_hdr
);
2599 bhs
->datasn
= htonl(idt
->idt_exp_datasn
++);
2601 hton24(bhs
->dlength
, chunk
);
2602 bhs
->offset
= htonl(idb
->idb_bufoffset
+ data_offset
);
2605 pdu
->isp_data
= (uint8_t *)idb
->idb_buf
+ data_offset
;
2606 pdu
->isp_datalen
= (uint_t
)chunk
;
2608 if (chunk
== remainder
) {
2609 bhs
->flags
= ISCSI_FLAG_FINAL
; /* F bit set to 1 */
2610 /* Piggyback the status with the last data PDU */
2611 if (idt
->idt_flags
& IDM_TASK_PHASECOLLAPSE_REQ
) {
2612 pdu
->isp_flags
|= IDM_PDU_SET_STATSN
|
2613 IDM_PDU_ADVANCE_STATSN
;
2614 (*idt
->idt_ic
->ic_conn_ops
.icb_update_statsn
)
2617 IDM_TASK_PHASECOLLAPSE_SUCCESS
;
2623 data_offset
+= chunk
;
2625 /* Instrument the data-send DTrace probe. */
2626 if (IDM_PDU_OPCODE(pdu
) == ISCSI_OP_SCSI_DATA_RSP
) {
2627 DTRACE_ISCSI_2(data__send
,
2628 idm_conn_t
*, idt
->idt_ic
,
2629 iscsi_data_rsp_hdr_t
*,
2630 (iscsi_data_rsp_hdr_t
*)pdu
->isp_hdr
);
2634 * Now that we're done working with idt_exp_datasn,
2635 * idt->idt_state and idb->idb_bufoffset we can release
2636 * the task lock -- don't want to hold it across the
2637 * call to idm_i_so_tx since we could block.
2639 mutex_exit(&idt
->idt_mutex
);
2642 * Transmit the PDU. Call the internal routine directly
2643 * as there is already implicit ordering.
2645 if ((tx_status
= idm_i_so_tx(pdu
)) != IDM_STATUS_SUCCESS
) {
2646 mutex_enter(&idt
->idt_mutex
);
2650 mutex_enter(&idt
->idt_mutex
);
2651 idt
->idt_tx_bytes
+= chunk
;
2654 return (IDM_STATUS_SUCCESS
);
2662 idm_sotx_pdu_constructor(void *hdl
, void *arg
, int flags
)
2664 idm_pdu_t
*pdu
= hdl
;
2666 bzero(pdu
, sizeof (idm_pdu_t
));
2667 pdu
->isp_hdr
= (iscsi_hdr_t
*)(pdu
+ 1); /* Ptr arithmetic */
2668 pdu
->isp_hdrlen
= sizeof (iscsi_hdr_t
);
2669 pdu
->isp_callback
= idm_sotx_cache_pdu_cb
;
2670 pdu
->isp_magic
= IDM_PDU_MAGIC
;
2671 bzero(pdu
->isp_hdr
, sizeof (iscsi_hdr_t
));
2678 idm_sotx_cache_pdu_cb(idm_pdu_t
*pdu
, idm_status_t status
)
2680 /* reset values between use */
2681 pdu
->isp_datalen
= 0;
2683 kmem_cache_free(idm
.idm_sotx_pdu_cache
, pdu
);
2691 idm_sorx_pdu_constructor(void *hdl
, void *arg
, int flags
)
2693 idm_pdu_t
*pdu
= hdl
;
2695 bzero(pdu
, sizeof (idm_pdu_t
));
2696 pdu
->isp_magic
= IDM_PDU_MAGIC
;
2697 pdu
->isp_hdr
= (iscsi_hdr_t
*)(pdu
+ 1); /* Ptr arithmetic */
2698 pdu
->isp_callback
= idm_sorx_cache_pdu_cb
;
2705 idm_sorx_cache_pdu_cb(idm_pdu_t
*pdu
, idm_status_t status
)
2707 pdu
->isp_iovlen
= 0;
2708 pdu
->isp_sorx_buf
= 0;
2709 kmem_cache_free(idm
.idm_sorx_pdu_cache
, pdu
);
2713 idm_sorx_addl_pdu_cb(idm_pdu_t
*pdu
, idm_status_t status
)
2716 * We had to modify our cached RX PDU with a longer header buffer
2717 * and/or a longer data buffer. Release the new buffers and fix
2718 * the fields back to what we would expect for a cached RX PDU.
2720 if (pdu
->isp_flags
& IDM_PDU_ADDL_HDR
) {
2721 kmem_free(pdu
->isp_hdr
, pdu
->isp_hdrlen
);
2723 if (pdu
->isp_flags
& IDM_PDU_ADDL_DATA
) {
2724 kmem_free(pdu
->isp_data
, pdu
->isp_datalen
);
2726 pdu
->isp_hdr
= (iscsi_hdr_t
*)(pdu
+ 1);
2727 pdu
->isp_hdrlen
= sizeof (iscsi_hdr_t
);
2728 pdu
->isp_data
= NULL
;
2729 pdu
->isp_datalen
= 0;
2730 pdu
->isp_sorx_buf
= 0;
2731 pdu
->isp_callback
= idm_sorx_cache_pdu_cb
;
2732 idm_sorx_cache_pdu_cb(pdu
, status
);
2736 * This thread is only active when I/O is queued for transmit
2737 * because the socket is busy.
2740 idm_sotx_thread(void *arg
)
2742 idm_conn_t
*ic
= arg
;
2743 idm_tx_obj_t
*object
, *next
;
2744 idm_so_conn_t
*so_conn
;
2745 idm_status_t status
= IDM_STATUS_SUCCESS
;
2749 mutex_enter(&ic
->ic_mutex
);
2750 so_conn
= ic
->ic_transport_private
;
2751 so_conn
->ic_tx_thread_running
= B_TRUE
;
2752 so_conn
->ic_tx_thread_did
= so_conn
->ic_tx_thread
->t_did
;
2753 cv_signal(&ic
->ic_cv
);
2754 mutex_exit(&ic
->ic_mutex
);
2756 mutex_enter(&so_conn
->ic_tx_mutex
);
2758 while (so_conn
->ic_tx_thread_running
) {
2759 while (list_is_empty(&so_conn
->ic_tx_list
)) {
2760 DTRACE_PROBE1(soconn__tx__sleep
, idm_conn_t
*, ic
);
2761 cv_wait(&so_conn
->ic_tx_cv
, &so_conn
->ic_tx_mutex
);
2762 DTRACE_PROBE1(soconn__tx__wakeup
, idm_conn_t
*, ic
);
2764 if (!so_conn
->ic_tx_thread_running
) {
2769 object
= (idm_tx_obj_t
*)list_head(&so_conn
->ic_tx_list
);
2770 list_remove(&so_conn
->ic_tx_list
, object
);
2771 mutex_exit(&so_conn
->ic_tx_mutex
);
2773 switch (object
->idm_tx_obj_magic
) {
2774 case IDM_PDU_MAGIC
: {
2775 idm_pdu_t
*pdu
= (idm_pdu_t
*)object
;
2776 DTRACE_PROBE2(soconn__tx__pdu
, idm_conn_t
*, ic
,
2777 idm_pdu_t
*, (idm_pdu_t
*)object
);
2779 if (pdu
->isp_flags
& IDM_PDU_SET_STATSN
) {
2781 (ic
->ic_conn_ops
.icb_update_statsn
)(NULL
, pdu
);
2783 status
= idm_i_so_tx((idm_pdu_t
*)object
);
2786 case IDM_BUF_MAGIC
: {
2787 idm_buf_t
*idb
= (idm_buf_t
*)object
;
2788 idm_task_t
*idt
= idb
->idb_task_binding
;
2790 DTRACE_PROBE2(soconn__tx__buf
, idm_conn_t
*, ic
,
2793 mutex_enter(&idt
->idt_mutex
);
2794 status
= idm_so_send_buf_region(idt
,
2795 idb
, 0, idb
->idb_xfer_len
);
2798 * TX thread owns the buffer so we expect it to
2801 ASSERT(idb
->idb_in_transport
);
2802 if (IDM_CONN_ISTGT(ic
)) {
2804 * idm_buf_tx_to_ini_done releases
2807 DTRACE_ISCSI_8(xfer__done
,
2808 idm_conn_t
*, idt
->idt_ic
,
2809 uintptr_t, idb
->idb_buf
,
2810 uint32_t, idb
->idb_bufoffset
,
2811 uint64_t, 0, uint32_t, 0, uint32_t, 0,
2812 uint32_t, idb
->idb_xfer_len
,
2813 int, XFER_BUF_TX_TO_INI
);
2814 idm_buf_tx_to_ini_done(idt
, idb
, status
);
2816 idm_so_send_rtt_data_done(idt
, idb
);
2817 mutex_exit(&idt
->idt_mutex
);
2823 IDM_CONN_LOG(CE_WARN
, "idm_sotx_thread: Unknown magic "
2824 "(0x%08x)", object
->idm_tx_obj_magic
);
2825 status
= IDM_STATUS_FAIL
;
2828 mutex_enter(&so_conn
->ic_tx_mutex
);
2830 if (status
!= IDM_STATUS_SUCCESS
) {
2831 so_conn
->ic_tx_thread_running
= B_FALSE
;
2832 idm_conn_event(ic
, CE_TRANSPORT_FAIL
, status
);
2837 * Before we leave, we need to abort every item remaining in the
2842 object
= (idm_tx_obj_t
*)list_head(&so_conn
->ic_tx_list
);
2844 while (object
!= NULL
) {
2845 next
= list_next(&so_conn
->ic_tx_list
, object
);
2847 list_remove(&so_conn
->ic_tx_list
, object
);
2848 switch (object
->idm_tx_obj_magic
) {
2850 idm_pdu_complete((idm_pdu_t
*)object
,
2851 IDM_STATUS_ABORTED
);
2854 case IDM_BUF_MAGIC
: {
2855 idm_buf_t
*idb
= (idm_buf_t
*)object
;
2856 idm_task_t
*idt
= idb
->idb_task_binding
;
2857 mutex_exit(&so_conn
->ic_tx_mutex
);
2858 mutex_enter(&idt
->idt_mutex
);
2860 * TX thread owns the buffer so we expect it to
2863 ASSERT(idb
->idb_in_transport
);
2864 if (IDM_CONN_ISTGT(ic
)) {
2866 * idm_buf_tx_to_ini_done releases
2869 DTRACE_ISCSI_8(xfer__done
,
2870 idm_conn_t
*, idt
->idt_ic
,
2871 uintptr_t, idb
->idb_buf
,
2872 uint32_t, idb
->idb_bufoffset
,
2873 uint64_t, 0, uint32_t, 0, uint32_t, 0,
2874 uint32_t, idb
->idb_xfer_len
,
2875 int, XFER_BUF_TX_TO_INI
);
2876 idm_buf_tx_to_ini_done(idt
, idb
,
2877 IDM_STATUS_ABORTED
);
2879 idm_so_send_rtt_data_done(idt
, idb
);
2880 mutex_exit(&idt
->idt_mutex
);
2882 mutex_enter(&so_conn
->ic_tx_mutex
);
2886 IDM_CONN_LOG(CE_WARN
,
2887 "idm_sotx_thread: Unexpected magic "
2888 "(0x%08x)", object
->idm_tx_obj_magic
);
2894 mutex_exit(&so_conn
->ic_tx_mutex
);
2901 idm_so_socket_set_nonblock(struct sonode
*node
)
2903 (void) fop_setfl(node
->so_vnode
, node
->so_flag
,
2904 (node
->so_state
| FNONBLOCK
), CRED(), NULL
);
2908 idm_so_socket_set_block(struct sonode
*node
)
2910 (void) fop_setfl(node
->so_vnode
, node
->so_flag
,
2911 (node
->so_state
& (~FNONBLOCK
)), CRED(), NULL
);
2916 * Called by kernel sockets when the connection has been accepted or
2917 * rejected. In early volo, a "disconnect" callback was sent instead of
2918 * "connectfailed", so we check for both.
2922 idm_so_timed_socket_connect_cb(ksocket_t ks
,
2923 ksocket_callback_event_t ev
, void *arg
, uintptr_t info
)
2925 idm_so_timed_socket_t
*itp
= arg
;
2926 ASSERT(itp
!= NULL
);
2927 ASSERT(ev
== KSOCKET_EV_CONNECTED
||
2928 ev
== KSOCKET_EV_CONNECTFAILED
||
2929 ev
== KSOCKET_EV_DISCONNECTED
);
2931 mutex_enter(&idm_so_timed_socket_mutex
);
2932 itp
->it_callback_called
= B_TRUE
;
2933 if (ev
== KSOCKET_EV_CONNECTED
) {
2934 itp
->it_socket_error_code
= 0;
2936 /* Make sure the error code is non-zero on error */
2939 itp
->it_socket_error_code
= (int)info
;
2941 cv_signal(&itp
->it_cv
);
2942 mutex_exit(&idm_so_timed_socket_mutex
);
2946 idm_so_timed_socket_connect(ksocket_t ks
,
2947 struct sockaddr_storage
*sa
, int sa_sz
, int login_max_usec
)
2949 clock_t conn_login_max
;
2950 int rc
, nonblocking
, rval
;
2951 idm_so_timed_socket_t it
;
2952 ksocket_callbacks_t ks_cb
;
2954 conn_login_max
= ddi_get_lbolt() + drv_usectohz(login_max_usec
);
2957 * Set to non-block socket mode, with callback on connect
2958 * Early volo used "disconnected" instead of "connectfailed",
2959 * so set callback to look for both.
2961 bzero(&it
, sizeof (it
));
2962 ks_cb
.ksock_cb_flags
= KSOCKET_CB_CONNECTED
|
2963 KSOCKET_CB_CONNECTFAILED
| KSOCKET_CB_DISCONNECTED
;
2964 ks_cb
.ksock_cb_connected
= idm_so_timed_socket_connect_cb
;
2965 ks_cb
.ksock_cb_connectfailed
= idm_so_timed_socket_connect_cb
;
2966 ks_cb
.ksock_cb_disconnected
= idm_so_timed_socket_connect_cb
;
2967 cv_init(&it
.it_cv
, NULL
, CV_DEFAULT
, NULL
);
2968 rc
= ksocket_setcallbacks(ks
, &ks_cb
, &it
, CRED());
2972 /* Set to non-blocking mode */
2974 rc
= ksocket_ioctl(ks
, FIONBIO
, (intptr_t)&nonblocking
, &rval
,
2979 bzero(&it
, sizeof (it
));
2982 * Warning -- in a loopback scenario, the call to
2983 * the connect_cb can occur inside the call to
2984 * ksocket_connect. Do not hold the mutex around the
2985 * call to ksocket_connect.
2987 rc
= ksocket_connect(ks
, (struct sockaddr
*)sa
, sa_sz
, CRED());
2988 if (rc
== 0 || rc
== EISCONN
) {
2989 /* socket success or already success */
2993 if ((rc
!= EINPROGRESS
) && (rc
!= EALREADY
)) {
2997 /* TCP connect still in progress. See if out of time. */
2998 if (ddi_get_lbolt() > conn_login_max
) {
3000 * Connection retry timeout,
3001 * failed connect to target.
3008 * TCP connect still in progress. Sleep until callback.
3009 * Do NOT go to sleep if the callback already occurred!
3011 mutex_enter(&idm_so_timed_socket_mutex
);
3012 if (!it
.it_callback_called
) {
3013 (void) cv_timedwait(&it
.it_cv
,
3014 &idm_so_timed_socket_mutex
, conn_login_max
);
3016 if (it
.it_callback_called
) {
3017 rc
= it
.it_socket_error_code
;
3018 mutex_exit(&idm_so_timed_socket_mutex
);
3021 /* If timer expires, go call ksocket_connect one last time. */
3022 mutex_exit(&idm_so_timed_socket_mutex
);
3025 /* resume blocking mode */
3027 (void) ksocket_ioctl(ks
, FIONBIO
, (intptr_t)&nonblocking
, &rval
,
3030 (void) ksocket_setcallbacks(ks
, NULL
, NULL
, CRED());
3031 cv_destroy(&it
.it_cv
);
3040 idm_addr_to_sa(idm_addr_t
*dportal
, struct sockaddr_storage
*sa
)
3043 struct sockaddr_in
*sin
;
3044 struct sockaddr_in6
*sin6
;
3046 /* Build sockaddr_storage for this portal (idm_addr_t) */
3047 bzero(sa
, sizeof (*sa
));
3048 dp_addr_size
= dportal
->a_addr
.i_insize
;
3049 if (dp_addr_size
== sizeof (struct in_addr
)) {
3051 sa
->ss_family
= AF_INET
;
3052 sin
= (struct sockaddr_in
*)sa
;
3053 sin
->sin_port
= htons(dportal
->a_port
);
3054 bcopy(&dportal
->a_addr
.i_addr
.in4
,
3055 &sin
->sin_addr
, sizeof (struct in_addr
));
3056 } else if (dp_addr_size
== sizeof (struct in6_addr
)) {
3058 sa
->ss_family
= AF_INET6
;
3059 sin6
= (struct sockaddr_in6
*)sa
;
3060 sin6
->sin6_port
= htons(dportal
->a_port
);
3061 bcopy(&dportal
->a_addr
.i_addr
.in6
,
3062 &sin6
->sin6_addr
, sizeof (struct in6_addr
));
3070 * return a human-readable form of a sockaddr_storage, in the form
3071 * [ip-address]:port. This is used in calls to logging functions.
3072 * If several calls to idm_sa_ntop are made within the same invocation
3073 * of a logging function, then each one needs its own buf.
3076 idm_sa_ntop(const struct sockaddr_storage
*sa
,
3077 char *buf
, size_t size
)
3079 static const char bogus_ip
[] = "[0].-1";
3080 char tmp
[INET6_ADDRSTRLEN
];
3082 switch (sa
->ss_family
) {
3084 const struct sockaddr_in6
*in6
=
3085 (const struct sockaddr_in6
*) sa
;
3087 (void) inet_ntop(in6
->sin6_family
, &in6
->sin6_addr
, tmp
,
3089 if (strlen(tmp
) + sizeof ("[].65535") > size
)
3091 /* struct sockaddr_storage gets port info from v4 loc */
3092 (void) snprintf(buf
, size
, "[%s].%u", tmp
,
3093 ntohs(in6
->sin6_port
));
3097 const struct sockaddr_in
*in
= (const struct sockaddr_in
*) sa
;
3099 (void) inet_ntop(in
->sin_family
, &in
->sin_addr
, tmp
,
3101 if (strlen(tmp
) + sizeof ("[].65535") > size
)
3103 (void) snprintf(buf
, size
, "[%s].%u", tmp
,
3104 ntohs(in
->sin_port
));
3111 (void) snprintf(buf
, size
, "%s", bogus_ip
);