xref: /illumos-gate/usr/src/uts/common/io/idm/idm_so.c (revision 61dfa509)
1a6d42e7dSPeter Dunlap /*
2a6d42e7dSPeter Dunlap  * CDDL HEADER START
3a6d42e7dSPeter Dunlap  *
4a6d42e7dSPeter Dunlap  * The contents of this file are subject to the terms of the
5a6d42e7dSPeter Dunlap  * Common Development and Distribution License (the "License").
6a6d42e7dSPeter Dunlap  * You may not use this file except in compliance with the License.
7a6d42e7dSPeter Dunlap  *
8a6d42e7dSPeter Dunlap  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a6d42e7dSPeter Dunlap  * or http://www.opensolaris.org/os/licensing.
10a6d42e7dSPeter Dunlap  * See the License for the specific language governing permissions
11a6d42e7dSPeter Dunlap  * and limitations under the License.
12a6d42e7dSPeter Dunlap  *
13a6d42e7dSPeter Dunlap  * When distributing Covered Code, include this CDDL HEADER in each
14a6d42e7dSPeter Dunlap  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a6d42e7dSPeter Dunlap  * If applicable, add the following below this CDDL HEADER, with the
16a6d42e7dSPeter Dunlap  * fields enclosed by brackets "[]" replaced with your own identifying
17a6d42e7dSPeter Dunlap  * information: Portions Copyright [yyyy] [name of copyright owner]
18a6d42e7dSPeter Dunlap  *
19a6d42e7dSPeter Dunlap  * CDDL HEADER END
20a6d42e7dSPeter Dunlap  */
21a6d42e7dSPeter Dunlap /*
22e97fb153SPeter Cudhea - Sun Microsystems - Burlington, MA United States  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23a6d42e7dSPeter Dunlap  * Use is subject to license terms.
24a6d42e7dSPeter Dunlap  */
250f94976eSJeff Biseda /*
260f94976eSJeff Biseda  * Copyright (c) 2013 by Delphix. All rights reserved.
27*61dfa509SRick McNeal  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
282727bb05STim Kordas  * Copyright (c) 2017, Joyent, Inc.  All rights reserved.
290f94976eSJeff Biseda  */
30a6d42e7dSPeter Dunlap 
31a6d42e7dSPeter Dunlap #include <sys/conf.h>
32a6d42e7dSPeter Dunlap #include <sys/stat.h>
33a6d42e7dSPeter Dunlap #include <sys/file.h>
34a6d42e7dSPeter Dunlap #include <sys/ddi.h>
35a6d42e7dSPeter Dunlap #include <sys/sunddi.h>
36a6d42e7dSPeter Dunlap #include <sys/modctl.h>
37a6d42e7dSPeter Dunlap #include <sys/priv.h>
38a6d42e7dSPeter Dunlap #include <sys/cpuvar.h>
39a6d42e7dSPeter Dunlap #include <sys/socket.h>
40a6d42e7dSPeter Dunlap #include <sys/strsubr.h>
41a6d42e7dSPeter Dunlap #include <sys/sysmacros.h>
42a6d42e7dSPeter Dunlap #include <sys/sdt.h>
43a6d42e7dSPeter Dunlap #include <netinet/tcp.h>
44a6d42e7dSPeter Dunlap #include <inet/tcp.h>
45a6d42e7dSPeter Dunlap #include <sys/socketvar.h>
46a6d42e7dSPeter Dunlap #include <sys/pathname.h>
47a6d42e7dSPeter Dunlap #include <sys/fs/snode.h>
48a6d42e7dSPeter Dunlap #include <sys/fs/dv_node.h>
49a6d42e7dSPeter Dunlap #include <sys/vnode.h>
50a6d42e7dSPeter Dunlap #include <netinet/in.h>
51a6d42e7dSPeter Dunlap #include <net/if.h>
52a6d42e7dSPeter Dunlap #include <sys/sockio.h>
530f1702c5SYu Xiangning #include <sys/ksocket.h>
54bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States #include <sys/filio.h>		/* FIONBIO */
5556261083SCharles Ting #include <sys/iscsi_protocol.h>
56a6d42e7dSPeter Dunlap #include <sys/idm/idm.h>
57a6d42e7dSPeter Dunlap #include <sys/idm/idm_so.h>
58a6d42e7dSPeter Dunlap #include <sys/idm/idm_text.h>
59a6d42e7dSPeter Dunlap 
60aff4bce5Syi zhang - Sun Microsystems - Beijing China #define	IN_PROGRESS_DELAY	1
61aff4bce5Syi zhang - Sun Microsystems - Beijing China 
62a6d42e7dSPeter Dunlap /*
63a6d42e7dSPeter Dunlap  * in6addr_any is currently all zeroes, but use the macro in case this
64a6d42e7dSPeter Dunlap  * ever changes.
65a6d42e7dSPeter Dunlap  */
66e42a0851Speter dunlap static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
67a6d42e7dSPeter Dunlap 
68a6d42e7dSPeter Dunlap static void idm_sorx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status);
69a6d42e7dSPeter Dunlap static void idm_sorx_addl_pdu_cb(idm_pdu_t *pdu, idm_status_t status);
70a6d42e7dSPeter Dunlap static void idm_sotx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status);
71a6d42e7dSPeter Dunlap 
720f1702c5SYu Xiangning static idm_status_t idm_so_conn_create_common(idm_conn_t *ic, ksocket_t new_so);
73a6d42e7dSPeter Dunlap static void idm_so_conn_destroy_common(idm_conn_t *ic);
74a6d42e7dSPeter Dunlap static void idm_so_conn_connect_common(idm_conn_t *ic);
75a6d42e7dSPeter Dunlap 
76dedec472SJack Meng static void idm_set_ini_preconnect_options(idm_so_conn_t *sc,
77dedec472SJack Meng     boolean_t boot_conn);
780f94976eSJeff Biseda static void idm_set_postconnect_options(ksocket_t so);
79a6d42e7dSPeter Dunlap static idm_status_t idm_i_so_tx(idm_pdu_t *pdu);
80a6d42e7dSPeter Dunlap 
81a6d42e7dSPeter Dunlap static idm_status_t idm_sorecvdata(idm_conn_t *ic, idm_pdu_t *pdu);
8230e7468fSPeter Dunlap static void idm_so_send_rtt_data(idm_conn_t *ic, idm_task_t *idt,
8330e7468fSPeter Dunlap     idm_buf_t *idb, uint32_t offset, uint32_t length);
8430e7468fSPeter Dunlap static void idm_so_send_rtt_data_done(idm_task_t *idt, idm_buf_t *idb);
8530e7468fSPeter Dunlap static idm_status_t idm_so_send_buf_region(idm_task_t *idt,
86a6d42e7dSPeter Dunlap     idm_buf_t *idb, uint32_t buf_region_offset, uint32_t buf_region_length);
87a6d42e7dSPeter Dunlap 
88a6d42e7dSPeter Dunlap static uint32_t idm_fill_iov(idm_pdu_t *pdu, idm_buf_t *idb,
89a6d42e7dSPeter Dunlap     uint32_t ro, uint32_t dlength);
90a6d42e7dSPeter Dunlap 
91a6d42e7dSPeter Dunlap static idm_status_t idm_so_handle_digest(idm_conn_t *it,
92a6d42e7dSPeter Dunlap     nvpair_t *digest_choice, const idm_kv_xlate_t *ikvx);
93a6d42e7dSPeter Dunlap 
94aff4bce5Syi zhang - Sun Microsystems - Beijing China static void idm_so_socket_set_nonblock(struct sonode *node);
95aff4bce5Syi zhang - Sun Microsystems - Beijing China static void idm_so_socket_set_block(struct sonode *node);
96aff4bce5Syi zhang - Sun Microsystems - Beijing China 
97a6d42e7dSPeter Dunlap /*
98a6d42e7dSPeter Dunlap  * Transport ops prototypes
99a6d42e7dSPeter Dunlap  */
100a6d42e7dSPeter Dunlap static void idm_so_tx(idm_conn_t *ic, idm_pdu_t *pdu);
101a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb);
102a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb);
103a6d42e7dSPeter Dunlap static void idm_so_rx_datain(idm_conn_t *ic, idm_pdu_t *pdu);
104a6d42e7dSPeter Dunlap static void idm_so_rx_rtt(idm_conn_t *ic, idm_pdu_t *pdu);
105a6d42e7dSPeter Dunlap static void idm_so_rx_dataout(idm_conn_t *ic, idm_pdu_t *pdu);
106a6d42e7dSPeter Dunlap static idm_status_t idm_so_free_task_rsrc(idm_task_t *idt);
107a6d42e7dSPeter Dunlap static kv_status_t idm_so_negotiate_key_values(idm_conn_t *it,
108a6d42e7dSPeter Dunlap     nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl);
10930e7468fSPeter Dunlap static void idm_so_notice_key_values(idm_conn_t *it,
110a6d42e7dSPeter Dunlap     nvlist_t *negotiated_nvl);
11156261083SCharles Ting static kv_status_t idm_so_declare_key_values(idm_conn_t *it,
11256261083SCharles Ting     nvlist_t *config_nvl, nvlist_t *outgoing_nvl);
113a6d42e7dSPeter Dunlap static boolean_t idm_so_conn_is_capable(idm_conn_req_t *ic,
114a6d42e7dSPeter Dunlap     idm_transport_caps_t *caps);
115a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_alloc(idm_buf_t *idb, uint64_t buflen);
116a6d42e7dSPeter Dunlap static void idm_so_buf_free(idm_buf_t *idb);
117a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_setup(idm_buf_t *idb);
118a6d42e7dSPeter Dunlap static void idm_so_buf_teardown(idm_buf_t *idb);
119a6d42e7dSPeter Dunlap static idm_status_t idm_so_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t *is);
120a6d42e7dSPeter Dunlap static void idm_so_tgt_svc_destroy(idm_svc_t *is);
121a6d42e7dSPeter Dunlap static idm_status_t idm_so_tgt_svc_online(idm_svc_t *is);
122a6d42e7dSPeter Dunlap static void idm_so_tgt_svc_offline(idm_svc_t *is);
123a6d42e7dSPeter Dunlap static void idm_so_tgt_conn_destroy(idm_conn_t *ic);
124a6d42e7dSPeter Dunlap static idm_status_t idm_so_tgt_conn_connect(idm_conn_t *ic);
125a6d42e7dSPeter Dunlap static void idm_so_conn_disconnect(idm_conn_t *ic);
126a6d42e7dSPeter Dunlap static idm_status_t idm_so_ini_conn_create(idm_conn_req_t *cr, idm_conn_t *ic);
127a6d42e7dSPeter Dunlap static void idm_so_ini_conn_destroy(idm_conn_t *ic);
128a6d42e7dSPeter Dunlap static idm_status_t idm_so_ini_conn_connect(idm_conn_t *ic);
129a6d42e7dSPeter Dunlap 
130a6d42e7dSPeter Dunlap /*
131a6d42e7dSPeter Dunlap  * IDM Native Sockets transport operations
132a6d42e7dSPeter Dunlap  */
133a6d42e7dSPeter Dunlap static
134a6d42e7dSPeter Dunlap idm_transport_ops_t idm_so_transport_ops = {
135a6d42e7dSPeter Dunlap 	idm_so_tx,			/* it_tx_pdu */
136a6d42e7dSPeter Dunlap 	idm_so_buf_tx_to_ini,		/* it_buf_tx_to_ini */
137a6d42e7dSPeter Dunlap 	idm_so_buf_rx_from_ini,		/* it_buf_rx_from_ini */
138a6d42e7dSPeter Dunlap 	idm_so_rx_datain,		/* it_rx_datain */
139a6d42e7dSPeter Dunlap 	idm_so_rx_rtt,			/* it_rx_rtt */
140a6d42e7dSPeter Dunlap 	idm_so_rx_dataout,		/* it_rx_dataout */
141a6d42e7dSPeter Dunlap 	NULL,				/* it_alloc_conn_rsrc */
142a6d42e7dSPeter Dunlap 	NULL,				/* it_free_conn_rsrc */
143a6d42e7dSPeter Dunlap 	NULL,				/* it_tgt_enable_datamover */
144a6d42e7dSPeter Dunlap 	NULL,				/* it_ini_enable_datamover */
145a6d42e7dSPeter Dunlap 	NULL,				/* it_conn_terminate */
146a6d42e7dSPeter Dunlap 	idm_so_free_task_rsrc,		/* it_free_task_rsrc */
147a6d42e7dSPeter Dunlap 	idm_so_negotiate_key_values,	/* it_negotiate_key_values */
148a6d42e7dSPeter Dunlap 	idm_so_notice_key_values,	/* it_notice_key_values */
149a6d42e7dSPeter Dunlap 	idm_so_conn_is_capable,		/* it_conn_is_capable */
150a6d42e7dSPeter Dunlap 	idm_so_buf_alloc,		/* it_buf_alloc */
151a6d42e7dSPeter Dunlap 	idm_so_buf_free,		/* it_buf_free */
152a6d42e7dSPeter Dunlap 	idm_so_buf_setup,		/* it_buf_setup */
153a6d42e7dSPeter Dunlap 	idm_so_buf_teardown,		/* it_buf_teardown */
154a6d42e7dSPeter Dunlap 	idm_so_tgt_svc_create,		/* it_tgt_svc_create */
155a6d42e7dSPeter Dunlap 	idm_so_tgt_svc_destroy,		/* it_tgt_svc_destroy */
156a6d42e7dSPeter Dunlap 	idm_so_tgt_svc_online,		/* it_tgt_svc_online */
157a6d42e7dSPeter Dunlap 	idm_so_tgt_svc_offline,		/* it_tgt_svc_offline */
158a6d42e7dSPeter Dunlap 	idm_so_tgt_conn_destroy,	/* it_tgt_conn_destroy */
159a6d42e7dSPeter Dunlap 	idm_so_tgt_conn_connect,	/* it_tgt_conn_connect */
160a6d42e7dSPeter Dunlap 	idm_so_conn_disconnect,		/* it_tgt_conn_disconnect */
161a6d42e7dSPeter Dunlap 	idm_so_ini_conn_create,		/* it_ini_conn_create */
162a6d42e7dSPeter Dunlap 	idm_so_ini_conn_destroy,	/* it_ini_conn_destroy */
163a6d42e7dSPeter Dunlap 	idm_so_ini_conn_connect,	/* it_ini_conn_connect */
16456261083SCharles Ting 	idm_so_conn_disconnect,		/* it_ini_conn_disconnect */
16556261083SCharles Ting 	idm_so_declare_key_values	/* it_declare_key_values */
166a6d42e7dSPeter Dunlap };
167a6d42e7dSPeter Dunlap 
168bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States kmutex_t	idm_so_timed_socket_mutex;
1690f94976eSJeff Biseda 
1700f94976eSJeff Biseda int32_t idm_so_sndbuf = IDM_SNDBUF_SIZE;
1710f94976eSJeff Biseda int32_t idm_so_rcvbuf = IDM_RCVBUF_SIZE;
1720f94976eSJeff Biseda 
173a6d42e7dSPeter Dunlap /*
174a6d42e7dSPeter Dunlap  * idm_so_init()
175a6d42e7dSPeter Dunlap  * Sockets transport initialization
176a6d42e7dSPeter Dunlap  */
177a6d42e7dSPeter Dunlap void
idm_so_init(idm_transport_t * it)178a6d42e7dSPeter Dunlap idm_so_init(idm_transport_t *it)
179a6d42e7dSPeter Dunlap {
180a6d42e7dSPeter Dunlap 	/* Cache for IDM Data and R2T Transmit PDU's */
181a6d42e7dSPeter Dunlap 	idm.idm_sotx_pdu_cache = kmem_cache_create("idm_tx_pdu_cache",
182a6d42e7dSPeter Dunlap 	    sizeof (idm_pdu_t) + sizeof (iscsi_hdr_t), 8,
183a6d42e7dSPeter Dunlap 	    &idm_sotx_pdu_constructor, NULL, NULL, NULL, NULL, KM_SLEEP);
184a6d42e7dSPeter Dunlap 
185a6d42e7dSPeter Dunlap 	/* Cache for IDM Receive PDU's */
186a6d42e7dSPeter Dunlap 	idm.idm_sorx_pdu_cache = kmem_cache_create("idm_rx_pdu_cache",
187a6d42e7dSPeter Dunlap 	    sizeof (idm_pdu_t) + IDM_SORX_CACHE_HDRLEN, 8,
188a6d42e7dSPeter Dunlap 	    &idm_sorx_pdu_constructor, NULL, NULL, NULL, NULL, KM_SLEEP);
189a6d42e7dSPeter Dunlap 
190cf8c0ebaSPeter Dunlap 	/* 128k buffer cache */
191cf8c0ebaSPeter Dunlap 	idm.idm_so_128k_buf_cache = kmem_cache_create("idm_128k_buf_cache",
192cf8c0ebaSPeter Dunlap 	    IDM_SO_BUF_CACHE_UB, 8, NULL, NULL, NULL, NULL, NULL, KM_SLEEP);
193cf8c0ebaSPeter Dunlap 
194a6d42e7dSPeter Dunlap 	/* Set the sockets transport ops */
195a6d42e7dSPeter Dunlap 	it->it_ops = &idm_so_transport_ops;
196bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
197bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	mutex_init(&idm_so_timed_socket_mutex, NULL, MUTEX_DEFAULT, NULL);
198bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
199a6d42e7dSPeter Dunlap }
200a6d42e7dSPeter Dunlap 
201a6d42e7dSPeter Dunlap /*
202a6d42e7dSPeter Dunlap  * idm_so_fini()
203a6d42e7dSPeter Dunlap  * Sockets transport teardown
204a6d42e7dSPeter Dunlap  */
205a6d42e7dSPeter Dunlap void
idm_so_fini(void)206a6d42e7dSPeter Dunlap idm_so_fini(void)
207a6d42e7dSPeter Dunlap {
208cf8c0ebaSPeter Dunlap 	kmem_cache_destroy(idm.idm_so_128k_buf_cache);
209a6d42e7dSPeter Dunlap 	kmem_cache_destroy(idm.idm_sotx_pdu_cache);
210a6d42e7dSPeter Dunlap 	kmem_cache_destroy(idm.idm_sorx_pdu_cache);
211bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	mutex_destroy(&idm_so_timed_socket_mutex);
212a6d42e7dSPeter Dunlap }
213a6d42e7dSPeter Dunlap 
2140f1702c5SYu Xiangning ksocket_t
idm_socreate(int domain,int type,int protocol)215a6d42e7dSPeter Dunlap idm_socreate(int domain, int type, int protocol)
216a6d42e7dSPeter Dunlap {
2170f1702c5SYu Xiangning 	ksocket_t ks;
218a6d42e7dSPeter Dunlap 
2190f1702c5SYu Xiangning 	if (!ksocket_socket(&ks, domain, type, protocol, KSOCKET_NOSLEEP,
2200f1702c5SYu Xiangning 	    CRED())) {
2210f1702c5SYu Xiangning 		return (ks);
2220f1702c5SYu Xiangning 	} else {
2230f1702c5SYu Xiangning 		return (NULL);
224a6d42e7dSPeter Dunlap 	}
225a6d42e7dSPeter Dunlap }
226a6d42e7dSPeter Dunlap 
227a6d42e7dSPeter Dunlap /*
228a6d42e7dSPeter Dunlap  * idm_soshutdown will disconnect the socket and prevent subsequent PDU
229a6d42e7dSPeter Dunlap  * reception and transmission.  The sonode still exists but its state
230a6d42e7dSPeter Dunlap  * gets modified to indicate it is no longer connected.  Calls to
231a6d42e7dSPeter Dunlap  * idm_sorecv/idm_iov_sorecv will return so idm_soshutdown can be used
232a6d42e7dSPeter Dunlap  * regain control of a thread stuck in idm_sorecv.
233a6d42e7dSPeter Dunlap  */
234a6d42e7dSPeter Dunlap void
idm_soshutdown(ksocket_t so)2350f1702c5SYu Xiangning idm_soshutdown(ksocket_t so)
236a6d42e7dSPeter Dunlap {
2370f1702c5SYu Xiangning 	(void) ksocket_shutdown(so, SHUT_RDWR, CRED());
238a6d42e7dSPeter Dunlap }
239a6d42e7dSPeter Dunlap 
240a6d42e7dSPeter Dunlap /*
241a6d42e7dSPeter Dunlap  * idm_sodestroy releases all resources associated with a socket previously
242a6d42e7dSPeter Dunlap  * created with idm_socreate.  The socket must be shutdown using
243a6d42e7dSPeter Dunlap  * idm_soshutdown before the socket is destroyed with idm_sodestroy,
244a6d42e7dSPeter Dunlap  * otherwise undefined behavior will result.
245a6d42e7dSPeter Dunlap  */
246a6d42e7dSPeter Dunlap void
idm_sodestroy(ksocket_t ks)2470f1702c5SYu Xiangning idm_sodestroy(ksocket_t ks)
248a6d42e7dSPeter Dunlap {
2490f1702c5SYu Xiangning 	(void) ksocket_close(ks, CRED());
250a6d42e7dSPeter Dunlap }
251a6d42e7dSPeter Dunlap 
252e42a0851Speter dunlap /*
253e42a0851Speter dunlap  * Function to compare two addresses in sockaddr_storage format
254e42a0851Speter dunlap  */
255e42a0851Speter dunlap 
256e42a0851Speter dunlap int
idm_ss_compare(const struct sockaddr_storage * cmp_ss1,const struct sockaddr_storage * cmp_ss2,boolean_t v4_mapped_as_v4,boolean_t compare_ports)257e42a0851Speter dunlap idm_ss_compare(const struct sockaddr_storage *cmp_ss1,
258e42a0851Speter dunlap     const struct sockaddr_storage *cmp_ss2,
259bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States     boolean_t v4_mapped_as_v4,
260bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States     boolean_t compare_ports)
261e42a0851Speter dunlap {
262e42a0851Speter dunlap 	struct sockaddr_storage			mapped_v4_ss1, mapped_v4_ss2;
263e42a0851Speter dunlap 	const struct sockaddr_storage		*ss1, *ss2;
264e42a0851Speter dunlap 	struct in_addr				*in1, *in2;
265e42a0851Speter dunlap 	struct in6_addr				*in61, *in62;
266e42a0851Speter dunlap 	int i;
267e42a0851Speter dunlap 
268e42a0851Speter dunlap 	/*
269e42a0851Speter dunlap 	 * Normalize V4-mapped IPv6 addresses into V4 format if
270e42a0851Speter dunlap 	 * v4_mapped_as_v4 is B_TRUE.
271e42a0851Speter dunlap 	 */
272e42a0851Speter dunlap 	ss1 = cmp_ss1;
273e42a0851Speter dunlap 	ss2 = cmp_ss2;
274e42a0851Speter dunlap 	if (v4_mapped_as_v4 && (ss1->ss_family == AF_INET6)) {
275e42a0851Speter dunlap 		in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr;
276e42a0851Speter dunlap 		if (IN6_IS_ADDR_V4MAPPED(in61)) {
277e42a0851Speter dunlap 			bzero(&mapped_v4_ss1, sizeof (mapped_v4_ss1));
278e42a0851Speter dunlap 			mapped_v4_ss1.ss_family = AF_INET;
279e42a0851Speter dunlap 			((struct sockaddr_in *)&mapped_v4_ss1)->sin_port =
280e42a0851Speter dunlap 			    ((struct sockaddr_in *)ss1)->sin_port;
281e42a0851Speter dunlap 			IN6_V4MAPPED_TO_INADDR(in61,
282e42a0851Speter dunlap 			    &((struct sockaddr_in *)&mapped_v4_ss1)->sin_addr);
283e42a0851Speter dunlap 			ss1 = &mapped_v4_ss1;
284e42a0851Speter dunlap 		}
285e42a0851Speter dunlap 	}
286e42a0851Speter dunlap 	ss2 = cmp_ss2;
287e42a0851Speter dunlap 	if (v4_mapped_as_v4 && (ss2->ss_family == AF_INET6)) {
288e42a0851Speter dunlap 		in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr;
289e42a0851Speter dunlap 		if (IN6_IS_ADDR_V4MAPPED(in62)) {
290e42a0851Speter dunlap 			bzero(&mapped_v4_ss2, sizeof (mapped_v4_ss2));
291e42a0851Speter dunlap 			mapped_v4_ss2.ss_family = AF_INET;
292e42a0851Speter dunlap 			((struct sockaddr_in *)&mapped_v4_ss2)->sin_port =
293e42a0851Speter dunlap 			    ((struct sockaddr_in *)ss2)->sin_port;
294e42a0851Speter dunlap 			IN6_V4MAPPED_TO_INADDR(in62,
295e42a0851Speter dunlap 			    &((struct sockaddr_in *)&mapped_v4_ss2)->sin_addr);
296e42a0851Speter dunlap 			ss2 = &mapped_v4_ss2;
297e42a0851Speter dunlap 		}
298e42a0851Speter dunlap 	}
299e42a0851Speter dunlap 
300e42a0851Speter dunlap 	/*
301e42a0851Speter dunlap 	 * Compare ports, then address family, then ip address
302e42a0851Speter dunlap 	 */
303bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	if (compare_ports &&
304bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	    (((struct sockaddr_in *)ss1)->sin_port !=
305bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	    ((struct sockaddr_in *)ss2)->sin_port)) {
306e42a0851Speter dunlap 		if (((struct sockaddr_in *)ss1)->sin_port >
307e42a0851Speter dunlap 		    ((struct sockaddr_in *)ss2)->sin_port)
308e42a0851Speter dunlap 			return (1);
309e42a0851Speter dunlap 		else
310e42a0851Speter dunlap 			return (-1);
311e42a0851Speter dunlap 	}
312e42a0851Speter dunlap 
313e42a0851Speter dunlap 	/*
314e42a0851Speter dunlap 	 * ports are the same
315e42a0851Speter dunlap 	 */
316e42a0851Speter dunlap 	if (ss1->ss_family != ss2->ss_family) {
317e42a0851Speter dunlap 		if (ss1->ss_family == AF_INET)
318e42a0851Speter dunlap 			return (1);
319e42a0851Speter dunlap 		else
320e42a0851Speter dunlap 			return (-1);
321e42a0851Speter dunlap 	}
322e42a0851Speter dunlap 
323e42a0851Speter dunlap 	/*
324e42a0851Speter dunlap 	 * address families are the same
325e42a0851Speter dunlap 	 */
326e42a0851Speter dunlap 	if (ss1->ss_family == AF_INET) {
327e42a0851Speter dunlap 		in1 = &((struct sockaddr_in *)ss1)->sin_addr;
328e42a0851Speter dunlap 		in2 = &((struct sockaddr_in *)ss2)->sin_addr;
329e42a0851Speter dunlap 
330e42a0851Speter dunlap 		if (in1->s_addr > in2->s_addr)
331e42a0851Speter dunlap 			return (1);
332e42a0851Speter dunlap 		else if (in1->s_addr < in2->s_addr)
333e42a0851Speter dunlap 			return (-1);
334e42a0851Speter dunlap 		else
335e42a0851Speter dunlap 			return (0);
336e42a0851Speter dunlap 	} else if (ss1->ss_family == AF_INET6) {
337e42a0851Speter dunlap 		in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr;
338e42a0851Speter dunlap 		in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr;
339e42a0851Speter dunlap 
340e42a0851Speter dunlap 		for (i = 0; i < 4; i++) {
341e42a0851Speter dunlap 			if (in61->s6_addr32[i] > in62->s6_addr32[i])
342e42a0851Speter dunlap 				return (1);
343e42a0851Speter dunlap 			else if (in61->s6_addr32[i] < in62->s6_addr32[i])
344e42a0851Speter dunlap 				return (-1);
345e42a0851Speter dunlap 		}
346e42a0851Speter dunlap 		return (0);
347e42a0851Speter dunlap 	}
348e42a0851Speter dunlap 
349e42a0851Speter dunlap 	return (1);
350e42a0851Speter dunlap }
351e42a0851Speter dunlap 
352a6d42e7dSPeter Dunlap /*
353a6d42e7dSPeter Dunlap  * IP address filter functions to flag addresses that should not
354a6d42e7dSPeter Dunlap  * go out to initiators through discovery.
355a6d42e7dSPeter Dunlap  */
356a6d42e7dSPeter Dunlap static boolean_t
idm_v4_addr_okay(struct in_addr * in_addr)357a6d42e7dSPeter Dunlap idm_v4_addr_okay(struct in_addr *in_addr)
358a6d42e7dSPeter Dunlap {
359a6d42e7dSPeter Dunlap 	in_addr_t addr = ntohl(in_addr->s_addr);
360a6d42e7dSPeter Dunlap 
361a6d42e7dSPeter Dunlap 	if ((INADDR_NONE == addr) ||
362a6d42e7dSPeter Dunlap 	    (IN_MULTICAST(addr)) ||
363a6d42e7dSPeter Dunlap 	    ((addr >> IN_CLASSA_NSHIFT) == 0) ||
364a6d42e7dSPeter Dunlap 	    ((addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)) {
365a6d42e7dSPeter Dunlap 		return (B_FALSE);
366a6d42e7dSPeter Dunlap 	}
367a6d42e7dSPeter Dunlap 	return (B_TRUE);
368a6d42e7dSPeter Dunlap }
369a6d42e7dSPeter Dunlap 
370a6d42e7dSPeter Dunlap static boolean_t
idm_v6_addr_okay(struct in6_addr * addr6)371a6d42e7dSPeter Dunlap idm_v6_addr_okay(struct in6_addr *addr6)
372a6d42e7dSPeter Dunlap {
373a6d42e7dSPeter Dunlap 
374a6d42e7dSPeter Dunlap 	if ((IN6_IS_ADDR_UNSPECIFIED(addr6)) ||
375a6d42e7dSPeter Dunlap 	    (IN6_IS_ADDR_LOOPBACK(addr6)) ||
376a6d42e7dSPeter Dunlap 	    (IN6_IS_ADDR_MULTICAST(addr6)) ||
377a6d42e7dSPeter Dunlap 	    (IN6_IS_ADDR_V4MAPPED(addr6)) ||
378a6d42e7dSPeter Dunlap 	    (IN6_IS_ADDR_V4COMPAT(addr6)) ||
379a6d42e7dSPeter Dunlap 	    (IN6_IS_ADDR_LINKLOCAL(addr6))) {
380a6d42e7dSPeter Dunlap 		return (B_FALSE);
381a6d42e7dSPeter Dunlap 	}
382a6d42e7dSPeter Dunlap 	return (B_TRUE);
383a6d42e7dSPeter Dunlap }
384a6d42e7dSPeter Dunlap 
385a6d42e7dSPeter Dunlap /*
386a6d42e7dSPeter Dunlap  * idm_get_ipaddr will retrieve a list of IP Addresses which the host is
387a6d42e7dSPeter Dunlap  * configured with by sending down a sequence of kernel ioctl to IP STREAMS.
388a6d42e7dSPeter Dunlap  */
389a6d42e7dSPeter Dunlap int
idm_get_ipaddr(idm_addr_list_t ** ipaddr_p)390a6d42e7dSPeter Dunlap idm_get_ipaddr(idm_addr_list_t **ipaddr_p)
391a6d42e7dSPeter Dunlap {
3928e718be9SToomas Soome 	ksocket_t		so4, so6;
393a6d42e7dSPeter Dunlap 	struct lifnum		lifn;
394a6d42e7dSPeter Dunlap 	struct lifconf		lifc;
395a6d42e7dSPeter Dunlap 	struct lifreq		*lp;
396a6d42e7dSPeter Dunlap 	int			rval;
397a6d42e7dSPeter Dunlap 	int			numifs;
398a6d42e7dSPeter Dunlap 	int			bufsize;
399a6d42e7dSPeter Dunlap 	void			*buf;
400a6d42e7dSPeter Dunlap 	int			i, j, n, rc;
401a6d42e7dSPeter Dunlap 	struct sockaddr_storage	ss;
402a6d42e7dSPeter Dunlap 	struct sockaddr_in	*sin;
403a6d42e7dSPeter Dunlap 	struct sockaddr_in6	*sin6;
404a6d42e7dSPeter Dunlap 	idm_addr_t		*ip;
405fcc214c3SCharles Ting 	idm_addr_list_t		*ipaddr = NULL;
406a6d42e7dSPeter Dunlap 	int			size_ipaddr;
407a6d42e7dSPeter Dunlap 
408a6d42e7dSPeter Dunlap 	*ipaddr_p = NULL;
409a6d42e7dSPeter Dunlap 	size_ipaddr = 0;
410a6d42e7dSPeter Dunlap 	buf = NULL;
411a6d42e7dSPeter Dunlap 
412a6d42e7dSPeter Dunlap 	/* create an ipv4 and ipv6 UDP socket */
413a6d42e7dSPeter Dunlap 	if ((so6 = idm_socreate(PF_INET6, SOCK_DGRAM, 0)) == NULL)
414a6d42e7dSPeter Dunlap 		return (0);
415a6d42e7dSPeter Dunlap 	if ((so4 = idm_socreate(PF_INET, SOCK_DGRAM, 0)) == NULL) {
416a6d42e7dSPeter Dunlap 		idm_sodestroy(so6);
417a6d42e7dSPeter Dunlap 		return (0);
418a6d42e7dSPeter Dunlap 	}
419a6d42e7dSPeter Dunlap 
420a6d42e7dSPeter Dunlap 
421a6d42e7dSPeter Dunlap retry_count:
422a6d42e7dSPeter Dunlap 	/* snapshot the current number of interfaces */
423a6d42e7dSPeter Dunlap 	lifn.lifn_family = PF_UNSPEC;
424a6d42e7dSPeter Dunlap 	lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
425a6d42e7dSPeter Dunlap 	lifn.lifn_count = 0;
4260f1702c5SYu Xiangning 	/* use vp6 for ioctls with unspecified families by default */
4270f1702c5SYu Xiangning 	if (ksocket_ioctl(so6, SIOCGLIFNUM, (intptr_t)&lifn, &rval, CRED())
4280f1702c5SYu Xiangning 	    != 0) {
429a6d42e7dSPeter Dunlap 		goto cleanup;
430a6d42e7dSPeter Dunlap 	}
431a6d42e7dSPeter Dunlap 
432a6d42e7dSPeter Dunlap 	numifs = lifn.lifn_count;
433a6d42e7dSPeter Dunlap 	if (numifs <= 0) {
434a6d42e7dSPeter Dunlap 		goto cleanup;
435a6d42e7dSPeter Dunlap 	}
436a6d42e7dSPeter Dunlap 
437a6d42e7dSPeter Dunlap 	/* allocate extra room in case more interfaces appear */
438a6d42e7dSPeter Dunlap 	numifs += 10;
439a6d42e7dSPeter Dunlap 
440a6d42e7dSPeter Dunlap 	/* get the interface names and ip addresses */
441a6d42e7dSPeter Dunlap 	bufsize = numifs * sizeof (struct lifreq);
442a6d42e7dSPeter Dunlap 	buf = kmem_alloc(bufsize, KM_SLEEP);
443a6d42e7dSPeter Dunlap 
444a6d42e7dSPeter Dunlap 	lifc.lifc_family = AF_UNSPEC;
445a6d42e7dSPeter Dunlap 	lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
446a6d42e7dSPeter Dunlap 	lifc.lifc_len = bufsize;
447a6d42e7dSPeter Dunlap 	lifc.lifc_buf = buf;
4480f1702c5SYu Xiangning 	rc = ksocket_ioctl(so6, SIOCGLIFCONF, (intptr_t)&lifc, &rval, CRED());
449a6d42e7dSPeter Dunlap 	if (rc != 0) {
450a6d42e7dSPeter Dunlap 		goto cleanup;
451a6d42e7dSPeter Dunlap 	}
452a6d42e7dSPeter Dunlap 	/* if our extra room is used up, try again */
453a6d42e7dSPeter Dunlap 	if (bufsize <= lifc.lifc_len) {
454a6d42e7dSPeter Dunlap 		kmem_free(buf, bufsize);
455a6d42e7dSPeter Dunlap 		buf = NULL;
456a6d42e7dSPeter Dunlap 		goto retry_count;
457a6d42e7dSPeter Dunlap 	}
458a6d42e7dSPeter Dunlap 	/* calc actual number of ifconfs */
459a6d42e7dSPeter Dunlap 	n = lifc.lifc_len / sizeof (struct lifreq);
460a6d42e7dSPeter Dunlap 
461a6d42e7dSPeter Dunlap 	/* get ip address */
462a6d42e7dSPeter Dunlap 	if (n > 0) {
463a6d42e7dSPeter Dunlap 		size_ipaddr = sizeof (idm_addr_list_t) +
464a6d42e7dSPeter Dunlap 		    (n - 1) * sizeof (idm_addr_t);
465a6d42e7dSPeter Dunlap 		ipaddr = kmem_zalloc(size_ipaddr, KM_SLEEP);
466a6d42e7dSPeter Dunlap 	} else {
467a6d42e7dSPeter Dunlap 		goto cleanup;
468a6d42e7dSPeter Dunlap 	}
469a6d42e7dSPeter Dunlap 
470a6d42e7dSPeter Dunlap 	/*
471a6d42e7dSPeter Dunlap 	 * Examine the array of interfaces and filter uninteresting ones
472a6d42e7dSPeter Dunlap 	 */
473a6d42e7dSPeter Dunlap 	for (i = 0, j = 0, lp = lifc.lifc_req; i < n; i++, lp++) {
474a6d42e7dSPeter Dunlap 
475a6d42e7dSPeter Dunlap 		/*
476a6d42e7dSPeter Dunlap 		 * Copy the address as the SIOCGLIFFLAGS ioctl is destructive
477a6d42e7dSPeter Dunlap 		 */
478a6d42e7dSPeter Dunlap 		ss = lp->lifr_addr;
479a6d42e7dSPeter Dunlap 		/*
480a6d42e7dSPeter Dunlap 		 * fetch the flags using the socket of the correct family
481a6d42e7dSPeter Dunlap 		 */
482a6d42e7dSPeter Dunlap 		switch (ss.ss_family) {
483a6d42e7dSPeter Dunlap 		case AF_INET:
4840f1702c5SYu Xiangning 			rc = ksocket_ioctl(so4, SIOCGLIFFLAGS, (intptr_t)lp,
4850f1702c5SYu Xiangning 			    &rval, CRED());
486a6d42e7dSPeter Dunlap 			break;
487a6d42e7dSPeter Dunlap 		case AF_INET6:
4880f1702c5SYu Xiangning 			rc = ksocket_ioctl(so6, SIOCGLIFFLAGS, (intptr_t)lp,
4890f1702c5SYu Xiangning 			    &rval, CRED());
490a6d42e7dSPeter Dunlap 			break;
491a6d42e7dSPeter Dunlap 		default:
492a6d42e7dSPeter Dunlap 			continue;
493a6d42e7dSPeter Dunlap 		}
494a6d42e7dSPeter Dunlap 		if (rc == 0) {
495a6d42e7dSPeter Dunlap 			/*
496a6d42e7dSPeter Dunlap 			 * If we got the flags, skip uninteresting
497a6d42e7dSPeter Dunlap 			 * interfaces based on flags
498a6d42e7dSPeter Dunlap 			 */
499a6d42e7dSPeter Dunlap 			if ((lp->lifr_flags & IFF_UP) != IFF_UP)
500a6d42e7dSPeter Dunlap 				continue;
501a6d42e7dSPeter Dunlap 			if (lp->lifr_flags &
502a6d42e7dSPeter Dunlap 			    (IFF_ANYCAST|IFF_NOLOCAL|IFF_DEPRECATED))
503a6d42e7dSPeter Dunlap 				continue;
504a6d42e7dSPeter Dunlap 		}
505a6d42e7dSPeter Dunlap 
506a6d42e7dSPeter Dunlap 		/* save ip address */
507a6d42e7dSPeter Dunlap 		ip = &ipaddr->al_addrs[j];
508a6d42e7dSPeter Dunlap 		switch (ss.ss_family) {
509a6d42e7dSPeter Dunlap 		case AF_INET:
510a6d42e7dSPeter Dunlap 			sin = (struct sockaddr_in *)&ss;
511a6d42e7dSPeter Dunlap 			if (!idm_v4_addr_okay(&sin->sin_addr))
512a6d42e7dSPeter Dunlap 				continue;
513a6d42e7dSPeter Dunlap 			ip->a_addr.i_addr.in4 = sin->sin_addr;
514a6d42e7dSPeter Dunlap 			ip->a_addr.i_insize = sizeof (struct in_addr);
515a6d42e7dSPeter Dunlap 			break;
516a6d42e7dSPeter Dunlap 		case AF_INET6:
517a6d42e7dSPeter Dunlap 			sin6 = (struct sockaddr_in6 *)&ss;
518a6d42e7dSPeter Dunlap 			if (!idm_v6_addr_okay(&sin6->sin6_addr))
519a6d42e7dSPeter Dunlap 				continue;
520a6d42e7dSPeter Dunlap 			ip->a_addr.i_addr.in6 = sin6->sin6_addr;
521a6d42e7dSPeter Dunlap 			ip->a_addr.i_insize = sizeof (struct in6_addr);
522a6d42e7dSPeter Dunlap 			break;
523a6d42e7dSPeter Dunlap 		default:
524a6d42e7dSPeter Dunlap 			continue;
525a6d42e7dSPeter Dunlap 		}
526a6d42e7dSPeter Dunlap 		j++;
527a6d42e7dSPeter Dunlap 	}
528a6d42e7dSPeter Dunlap 
529a6d42e7dSPeter Dunlap 	if (j == 0) {
530a6d42e7dSPeter Dunlap 		/* no valid ifaddr */
531a6d42e7dSPeter Dunlap 		kmem_free(ipaddr, size_ipaddr);
532a6d42e7dSPeter Dunlap 		size_ipaddr = 0;
533a6d42e7dSPeter Dunlap 		ipaddr = NULL;
534a6d42e7dSPeter Dunlap 	} else {
535a6d42e7dSPeter Dunlap 		ipaddr->al_out_cnt = j;
536a6d42e7dSPeter Dunlap 	}
537a6d42e7dSPeter Dunlap 
538a6d42e7dSPeter Dunlap 
539a6d42e7dSPeter Dunlap cleanup:
540a6d42e7dSPeter Dunlap 	idm_sodestroy(so6);
541a6d42e7dSPeter Dunlap 	idm_sodestroy(so4);
542a6d42e7dSPeter Dunlap 
543a6d42e7dSPeter Dunlap 	if (buf != NULL)
544a6d42e7dSPeter Dunlap 		kmem_free(buf, bufsize);
545a6d42e7dSPeter Dunlap 
546a6d42e7dSPeter Dunlap 	*ipaddr_p = ipaddr;
547a6d42e7dSPeter Dunlap 	return (size_ipaddr);
548a6d42e7dSPeter Dunlap }
549a6d42e7dSPeter Dunlap 
550a6d42e7dSPeter Dunlap int
idm_sorecv(ksocket_t so,void * msg,size_t len)5510f1702c5SYu Xiangning idm_sorecv(ksocket_t so, void *msg, size_t len)
552a6d42e7dSPeter Dunlap {
553a6d42e7dSPeter Dunlap 	iovec_t iov;
554a6d42e7dSPeter Dunlap 
555a6d42e7dSPeter Dunlap 	ASSERT(so != NULL);
556a6d42e7dSPeter Dunlap 	ASSERT(len != 0);
557a6d42e7dSPeter Dunlap 
558a6d42e7dSPeter Dunlap 	/*
559a6d42e7dSPeter Dunlap 	 * Fill in iovec and receive data
560a6d42e7dSPeter Dunlap 	 */
561a6d42e7dSPeter Dunlap 	iov.iov_base = msg;
562a6d42e7dSPeter Dunlap 	iov.iov_len = len;
563a6d42e7dSPeter Dunlap 
564a6d42e7dSPeter Dunlap 	return (idm_iov_sorecv(so, &iov, 1, len));
565a6d42e7dSPeter Dunlap }
566a6d42e7dSPeter Dunlap 
567a6d42e7dSPeter Dunlap /*
568a6d42e7dSPeter Dunlap  * idm_sosendto - Sends a buffered data on a non-connected socket.
569a6d42e7dSPeter Dunlap  *
570a6d42e7dSPeter Dunlap  * This function puts the data provided on the wire by calling sosendmsg.
571a6d42e7dSPeter Dunlap  * It will return only when all the data has been sent or if an error
572a6d42e7dSPeter Dunlap  * occurs.
573a6d42e7dSPeter Dunlap  *
574a6d42e7dSPeter Dunlap  * Returns 0 for success, the socket errno value if sosendmsg fails, and
575a6d42e7dSPeter Dunlap  * -1 if sosendmsg returns success but uio_resid != 0
576a6d42e7dSPeter Dunlap  */
577a6d42e7dSPeter Dunlap int
idm_sosendto(ksocket_t so,void * buff,size_t len,struct sockaddr * name,socklen_t namelen)5780f1702c5SYu Xiangning idm_sosendto(ksocket_t so, void *buff, size_t len,
579a6d42e7dSPeter Dunlap     struct sockaddr *name, socklen_t namelen)
580a6d42e7dSPeter Dunlap {
581a6d42e7dSPeter Dunlap 	struct msghdr		msg;
582a6d42e7dSPeter Dunlap 	struct iovec		iov[1];
583a6d42e7dSPeter Dunlap 	int			error;
5840f1702c5SYu Xiangning 	size_t			sent = 0;
585a6d42e7dSPeter Dunlap 
586a6d42e7dSPeter Dunlap 	iov[0].iov_base	= buff;
587a6d42e7dSPeter Dunlap 	iov[0].iov_len	= len;
588a6d42e7dSPeter Dunlap 
589a6d42e7dSPeter Dunlap 	/* Initialization of the message header. */
590a6d42e7dSPeter Dunlap 	bzero(&msg, sizeof (msg));
591a6d42e7dSPeter Dunlap 	msg.msg_iov	= iov;
592a6d42e7dSPeter Dunlap 	msg.msg_iovlen	= 1;
593a6d42e7dSPeter Dunlap 	msg.msg_name	= name;
594a6d42e7dSPeter Dunlap 	msg.msg_namelen	= namelen;
595a6d42e7dSPeter Dunlap 
5960f1702c5SYu Xiangning 	if ((error = ksocket_sendmsg(so, &msg, 0, &sent, CRED())) == 0) {
597a6d42e7dSPeter Dunlap 		/* Data sent */
5980f1702c5SYu Xiangning 		if (sent == len) {
599a6d42e7dSPeter Dunlap 			/* All data sent.  Success. */
600a6d42e7dSPeter Dunlap 			return (0);
601a6d42e7dSPeter Dunlap 		} else {
602a6d42e7dSPeter Dunlap 			/* Not all data was sent.  Failure */
603a6d42e7dSPeter Dunlap 			return (-1);
604a6d42e7dSPeter Dunlap 		}
605a6d42e7dSPeter Dunlap 	}
606a6d42e7dSPeter Dunlap 
607a6d42e7dSPeter Dunlap 	/* Send failed */
608a6d42e7dSPeter Dunlap 	return (error);
609a6d42e7dSPeter Dunlap }
610a6d42e7dSPeter Dunlap 
611a6d42e7dSPeter Dunlap /*
612a6d42e7dSPeter Dunlap  * idm_iov_sosend - Sends an iovec on a connection.
613a6d42e7dSPeter Dunlap  *
614a6d42e7dSPeter Dunlap  * This function puts the data provided on the wire by calling sosendmsg.
615a6d42e7dSPeter Dunlap  * It will return only when all the data has been sent or if an error
616a6d42e7dSPeter Dunlap  * occurs.
617a6d42e7dSPeter Dunlap  *
618a6d42e7dSPeter Dunlap  * Returns 0 for success, the socket errno value if sosendmsg fails, and
619a6d42e7dSPeter Dunlap  * -1 if sosendmsg returns success but uio_resid != 0
620a6d42e7dSPeter Dunlap  */
621a6d42e7dSPeter Dunlap int
idm_iov_sosend(ksocket_t so,iovec_t * iop,int iovlen,size_t total_len)6220f1702c5SYu Xiangning idm_iov_sosend(ksocket_t so, iovec_t *iop, int iovlen, size_t total_len)
623a6d42e7dSPeter Dunlap {
624a6d42e7dSPeter Dunlap 	struct msghdr		msg;
625a6d42e7dSPeter Dunlap 	int			error;
6268e718be9SToomas Soome 	size_t			sent = 0;
627a6d42e7dSPeter Dunlap 
628a6d42e7dSPeter Dunlap 	ASSERT(iop != NULL);
629a6d42e7dSPeter Dunlap 
630a6d42e7dSPeter Dunlap 	/* Initialization of the message header. */
631a6d42e7dSPeter Dunlap 	bzero(&msg, sizeof (msg));
632a6d42e7dSPeter Dunlap 	msg.msg_iov	= iop;
633a6d42e7dSPeter Dunlap 	msg.msg_iovlen	= iovlen;
634a6d42e7dSPeter Dunlap 
6350f1702c5SYu Xiangning 	if ((error = ksocket_sendmsg(so, &msg, 0, &sent, CRED()))
6360f1702c5SYu Xiangning 	    == 0) {
637a6d42e7dSPeter Dunlap 		/* Data sent */
6380f1702c5SYu Xiangning 		if (sent == total_len) {
639a6d42e7dSPeter Dunlap 			/* All data sent.  Success. */
640a6d42e7dSPeter Dunlap 			return (0);
641a6d42e7dSPeter Dunlap 		} else {
642a6d42e7dSPeter Dunlap 			/* Not all data was sent.  Failure */
643a6d42e7dSPeter Dunlap 			return (-1);
644a6d42e7dSPeter Dunlap 		}
645a6d42e7dSPeter Dunlap 	}
646a6d42e7dSPeter Dunlap 
647a6d42e7dSPeter Dunlap 	/* Send failed */
648a6d42e7dSPeter Dunlap 	return (error);
649a6d42e7dSPeter Dunlap }
650a6d42e7dSPeter Dunlap 
651a6d42e7dSPeter Dunlap /*
652a6d42e7dSPeter Dunlap  * idm_iov_sorecv - Receives an iovec from a connection
653a6d42e7dSPeter Dunlap  *
654a6d42e7dSPeter Dunlap  * This function gets the data asked for from the socket.  It will return
655a6d42e7dSPeter Dunlap  * only when all the requested data has been retrieved or if an error
656a6d42e7dSPeter Dunlap  * occurs.
657a6d42e7dSPeter Dunlap  *
658a6d42e7dSPeter Dunlap  * Returns 0 for success, the socket errno value if sorecvmsg fails, and
659a6d42e7dSPeter Dunlap  * -1 if sorecvmsg returns success but uio_resid != 0
660a6d42e7dSPeter Dunlap  */
661a6d42e7dSPeter Dunlap int
idm_iov_sorecv(ksocket_t so,iovec_t * iop,int iovlen,size_t total_len)6620f1702c5SYu Xiangning idm_iov_sorecv(ksocket_t so, iovec_t *iop, int iovlen, size_t total_len)
663a6d42e7dSPeter Dunlap {
664a6d42e7dSPeter Dunlap 	struct msghdr		msg;
665a6d42e7dSPeter Dunlap 	int			error;
6660f1702c5SYu Xiangning 	size_t			recv;
6678e718be9SToomas Soome 	int			flags;
668a6d42e7dSPeter Dunlap 
669a6d42e7dSPeter Dunlap 	ASSERT(iop != NULL);
670a6d42e7dSPeter Dunlap 
671a6d42e7dSPeter Dunlap 	/* Initialization of the message header. */
672a6d42e7dSPeter Dunlap 	bzero(&msg, sizeof (msg));
673a6d42e7dSPeter Dunlap 	msg.msg_iov	= iop;
674a6d42e7dSPeter Dunlap 	msg.msg_iovlen	= iovlen;
6750f1702c5SYu Xiangning 	flags		= MSG_WAITALL;
676a6d42e7dSPeter Dunlap 
6770f1702c5SYu Xiangning 	if ((error = ksocket_recvmsg(so, &msg, flags, &recv, CRED()))
6780f1702c5SYu Xiangning 	    == 0) {
679a6d42e7dSPeter Dunlap 		/* Received data */
6800f1702c5SYu Xiangning 		if (recv == total_len) {
681a6d42e7dSPeter Dunlap 			/* All requested data received.  Success */
682a6d42e7dSPeter Dunlap 			return (0);
683a6d42e7dSPeter Dunlap 		} else {
684a6d42e7dSPeter Dunlap 			/*
685a6d42e7dSPeter Dunlap 			 * Not all data was received.  The connection has
686a6d42e7dSPeter Dunlap 			 * probably failed.
687a6d42e7dSPeter Dunlap 			 */
688a6d42e7dSPeter Dunlap 			return (-1);
689a6d42e7dSPeter Dunlap 		}
690a6d42e7dSPeter Dunlap 	}
691a6d42e7dSPeter Dunlap 
692a6d42e7dSPeter Dunlap 	/* Receive failed */
693a6d42e7dSPeter Dunlap 	return (error);
694a6d42e7dSPeter Dunlap }
695a6d42e7dSPeter Dunlap 
696a6d42e7dSPeter Dunlap static void
idm_set_ini_preconnect_options(idm_so_conn_t * sc,boolean_t boot_conn)697dedec472SJack Meng idm_set_ini_preconnect_options(idm_so_conn_t *sc, boolean_t boot_conn)
698a6d42e7dSPeter Dunlap {
699a6d42e7dSPeter Dunlap 	int	conn_abort = 10000;
700a6d42e7dSPeter Dunlap 	int	conn_notify = 2000;
701a6d42e7dSPeter Dunlap 	int	abort = 30000;
702a6d42e7dSPeter Dunlap 
703a6d42e7dSPeter Dunlap 	/* Pre-connect socket options */
7040f1702c5SYu Xiangning 	(void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP,
7050f1702c5SYu Xiangning 	    TCP_CONN_NOTIFY_THRESHOLD, (char *)&conn_notify, sizeof (int),
7060f1702c5SYu Xiangning 	    CRED());
707dedec472SJack Meng 	if (boot_conn == B_FALSE) {
708dedec472SJack Meng 		(void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP,
709dedec472SJack Meng 		    TCP_CONN_ABORT_THRESHOLD, (char *)&conn_abort, sizeof (int),
710dedec472SJack Meng 		    CRED());
711dedec472SJack Meng 		(void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP,
712dedec472SJack Meng 		    TCP_ABORT_THRESHOLD,
713dedec472SJack Meng 		    (char *)&abort, sizeof (int), CRED());
714dedec472SJack Meng 	}
715a6d42e7dSPeter Dunlap }
716a6d42e7dSPeter Dunlap 
717a6d42e7dSPeter Dunlap static void
idm_set_postconnect_options(ksocket_t ks)7180f94976eSJeff Biseda idm_set_postconnect_options(ksocket_t ks)
719a6d42e7dSPeter Dunlap {
720a6d42e7dSPeter Dunlap 	const int	on = 1;
721a6d42e7dSPeter Dunlap 
722a6d42e7dSPeter Dunlap 	/* Set connect options */
7230f1702c5SYu Xiangning 	(void) ksocket_setsockopt(ks, SOL_SOCKET, SO_RCVBUF,
724f99db78fSChristopher Siden 	    (char *)&idm_so_rcvbuf, sizeof (idm_so_rcvbuf), CRED());
7250f1702c5SYu Xiangning 	(void) ksocket_setsockopt(ks, SOL_SOCKET, SO_SNDBUF,
726f99db78fSChristopher Siden 	    (char *)&idm_so_sndbuf, sizeof (idm_so_sndbuf), CRED());
7270f1702c5SYu Xiangning 	(void) ksocket_setsockopt(ks, IPPROTO_TCP, TCP_NODELAY,
7280f1702c5SYu Xiangning 	    (char *)&on, sizeof (on), CRED());
729a6d42e7dSPeter Dunlap }
730a6d42e7dSPeter Dunlap 
731a6d42e7dSPeter Dunlap static uint32_t
n2h24(const uchar_t * ptr)732a6d42e7dSPeter Dunlap n2h24(const uchar_t *ptr)
733a6d42e7dSPeter Dunlap {
734a6d42e7dSPeter Dunlap 	return ((ptr[0] << 16) | (ptr[1] << 8) | ptr[2]);
735a6d42e7dSPeter Dunlap }
736a6d42e7dSPeter Dunlap 
7372727bb05STim Kordas static boolean_t
idm_dataseglenokay(idm_conn_t * ic,idm_pdu_t * pdu)7382727bb05STim Kordas idm_dataseglenokay(idm_conn_t *ic, idm_pdu_t *pdu)
7392727bb05STim Kordas {
7402727bb05STim Kordas 	iscsi_hdr_t	*bhs;
7412727bb05STim Kordas 
7422727bb05STim Kordas 	if (ic->ic_conn_type == CONN_TYPE_TGT &&
7432727bb05STim Kordas 	    pdu->isp_datalen > ic->ic_conn_params.max_recv_dataseglen) {
7442727bb05STim Kordas 		IDM_CONN_LOG(CE_WARN,
7452727bb05STim Kordas 		    "idm_dataseglenokay: exceeded the max data segment length");
7462727bb05STim Kordas 		return (B_FALSE);
7472727bb05STim Kordas 	}
7482727bb05STim Kordas 
7492727bb05STim Kordas 	bhs = pdu->isp_hdr;
7502727bb05STim Kordas 	/*
7512727bb05STim Kordas 	 * Filter out any RFC3720 data-size violations.
7522727bb05STim Kordas 	 */
7532727bb05STim Kordas 	switch (IDM_PDU_OPCODE(pdu)) {
7542727bb05STim Kordas 	case ISCSI_OP_SCSI_TASK_MGT_MSG:
7552727bb05STim Kordas 	case ISCSI_OP_SCSI_TASK_MGT_RSP:
7562727bb05STim Kordas 	case ISCSI_OP_RTT_RSP:
7572727bb05STim Kordas 	case ISCSI_OP_LOGOUT_CMD:
7582727bb05STim Kordas 		/*
7592727bb05STim Kordas 		 * Data-segment not allowed and additional headers not allowed.
7602727bb05STim Kordas 		 * (both must be zero according to the RFC3720.)
7612727bb05STim Kordas 		 */
7622727bb05STim Kordas 		if (bhs->hlength != 0 || pdu->isp_datalen != 0)
7632727bb05STim Kordas 			return (B_FALSE);
7642727bb05STim Kordas 		break;
7652727bb05STim Kordas 	case ISCSI_OP_NOOP_OUT:
7662727bb05STim Kordas 	case ISCSI_OP_LOGIN_CMD:
7672727bb05STim Kordas 	case ISCSI_OP_TEXT_CMD:
7682727bb05STim Kordas 	case ISCSI_OP_SNACK_CMD:
7692727bb05STim Kordas 	case ISCSI_OP_NOOP_IN:
7702727bb05STim Kordas 	case ISCSI_OP_SCSI_RSP:
7712727bb05STim Kordas 	case ISCSI_OP_LOGIN_RSP:
7722727bb05STim Kordas 	case ISCSI_OP_TEXT_RSP:
7732727bb05STim Kordas 	case ISCSI_OP_SCSI_DATA_RSP:
7742727bb05STim Kordas 	case ISCSI_OP_LOGOUT_RSP:
7752727bb05STim Kordas 	case ISCSI_OP_ASYNC_EVENT:
7762727bb05STim Kordas 	case ISCSI_OP_REJECT_MSG:
7772727bb05STim Kordas 		/*
7782727bb05STim Kordas 		 * Additional headers not allowed.
7792727bb05STim Kordas 		 * (must be zero according to RFC3720.)
7802727bb05STim Kordas 		 */
7812727bb05STim Kordas 		if (bhs->hlength)
7822727bb05STim Kordas 			return (B_FALSE);
7832727bb05STim Kordas 		break;
7842727bb05STim Kordas 	case ISCSI_OP_SCSI_CMD:
7852727bb05STim Kordas 		/*
7862727bb05STim Kordas 		 * See RFC3720, section 10.3
7872727bb05STim Kordas 		 *
7882727bb05STim Kordas 		 * For pure read cmds, data-segment-length must be zero.
7892727bb05STim Kordas 		 * For non-final transfers, data-size must be even number of
7902727bb05STim Kordas 		 * 4-byte words.
7912727bb05STim Kordas 		 * For any transfer, an expected byte count must be provided.
7922727bb05STim Kordas 		 * For bidirectional transfers, an additional-header must be
7932727bb05STim Kordas 		 * provided (for the read byte-count.)
7942727bb05STim Kordas 		 */
7952727bb05STim Kordas 		if (pdu->isp_datalen) {
7962727bb05STim Kordas 			if ((bhs->flags & (ISCSI_FLAG_CMD_READ |
7972727bb05STim Kordas 			    ISCSI_FLAG_CMD_WRITE)) == ISCSI_FLAG_CMD_READ)
7982727bb05STim Kordas 				return (B_FALSE);
7992727bb05STim Kordas 			if ((bhs->flags & ISCSI_FLAG_FINAL) == 0 &&
8002727bb05STim Kordas 			    ((pdu->isp_datalen & 0x3) != 0))
8012727bb05STim Kordas 				return (B_FALSE);
8022727bb05STim Kordas 		}
8032727bb05STim Kordas 		if (bhs->flags & (ISCSI_FLAG_CMD_READ |
8042727bb05STim Kordas 		    ISCSI_FLAG_CMD_WRITE)) {
8052727bb05STim Kordas 			iscsi_scsi_cmd_hdr_t *cmdhdr =
8062727bb05STim Kordas 			    (iscsi_scsi_cmd_hdr_t *)bhs;
8072727bb05STim Kordas 			/*
8082727bb05STim Kordas 			 * we're transfering some data, we must have a
8092727bb05STim Kordas 			 * byte count
8102727bb05STim Kordas 			 */
8112727bb05STim Kordas 			if (cmdhdr->data_length == 0)
8122727bb05STim Kordas 				return (B_FALSE);
8132727bb05STim Kordas 		}
8142727bb05STim Kordas 		break;
8152727bb05STim Kordas 	case ISCSI_OP_SCSI_DATA:
8162727bb05STim Kordas 		/*
8172727bb05STim Kordas 		 * See RFC3720, section 10.7
8182727bb05STim Kordas 		 *
8192727bb05STim Kordas 		 * Additional headers aren't allowed, and the data-size must
8202727bb05STim Kordas 		 * be an even number of 4-byte words (unless the final bit
8212727bb05STim Kordas 		 * is set.)
8222727bb05STim Kordas 		 */
8232727bb05STim Kordas 		if (bhs->hlength)
8242727bb05STim Kordas 			return (B_FALSE);
8252727bb05STim Kordas 		if ((bhs->flags & ISCSI_FLAG_FINAL) == 0 &&
8262727bb05STim Kordas 		    ((pdu->isp_datalen & 0x3) != 0))
8272727bb05STim Kordas 			return (B_FALSE);
8282727bb05STim Kordas 		break;
8292727bb05STim Kordas 	default:
8302727bb05STim Kordas 		break;
8312727bb05STim Kordas 	}
8322727bb05STim Kordas 	return (B_TRUE);
8332727bb05STim Kordas }
834a6d42e7dSPeter Dunlap 
835a6d42e7dSPeter Dunlap static idm_status_t
idm_sorecvhdr(idm_conn_t * ic,idm_pdu_t * pdu)836a6d42e7dSPeter Dunlap idm_sorecvhdr(idm_conn_t *ic, idm_pdu_t *pdu)
837a6d42e7dSPeter Dunlap {
838a6d42e7dSPeter Dunlap 	iscsi_hdr_t	*bhs;
839a6d42e7dSPeter Dunlap 	uint32_t	hdr_digest_crc;
840a6d42e7dSPeter Dunlap 	uint32_t	crc_calculated;
841a6d42e7dSPeter Dunlap 	void		*new_hdr;
842a6d42e7dSPeter Dunlap 	int		ahslen = 0;
843a6d42e7dSPeter Dunlap 	int		total_len = 0;
844a6d42e7dSPeter Dunlap 	int		iovlen = 0;
845a6d42e7dSPeter Dunlap 	struct iovec	iov[2];
846a6d42e7dSPeter Dunlap 	idm_so_conn_t	*so_conn;
847a6d42e7dSPeter Dunlap 	int		rc;
848a6d42e7dSPeter Dunlap 
849a6d42e7dSPeter Dunlap 	so_conn = ic->ic_transport_private;
850a6d42e7dSPeter Dunlap 
851a6d42e7dSPeter Dunlap 	/*
852a6d42e7dSPeter Dunlap 	 * Read BHS
853a6d42e7dSPeter Dunlap 	 */
854a6d42e7dSPeter Dunlap 	bhs = pdu->isp_hdr;
855a6d42e7dSPeter Dunlap 	rc = idm_sorecv(so_conn->ic_so, pdu->isp_hdr, sizeof (iscsi_hdr_t));
856a6d42e7dSPeter Dunlap 	if (rc != IDM_STATUS_SUCCESS) {
857a6d42e7dSPeter Dunlap 		return (IDM_STATUS_FAIL);
858a6d42e7dSPeter Dunlap 	}
859a6d42e7dSPeter Dunlap 
860a6d42e7dSPeter Dunlap 	/*
861a6d42e7dSPeter Dunlap 	 * Check actual AHS length against the amount available in the buffer
862a6d42e7dSPeter Dunlap 	 */
863*61dfa509SRick McNeal 	if ((IDM_PDU_OPCODE(pdu) != ISCSI_OP_SCSI_CMD) &&
864*61dfa509SRick McNeal 	    (bhs->hlength != 0)) {
865*61dfa509SRick McNeal 		/* ---- hlength is only only valid for SCSI Request ---- */
866*61dfa509SRick McNeal 		return (IDM_STATUS_FAIL);
867*61dfa509SRick McNeal 	}
868a6d42e7dSPeter Dunlap 	pdu->isp_hdrlen = sizeof (iscsi_hdr_t) +
869a6d42e7dSPeter Dunlap 	    (bhs->hlength * sizeof (uint32_t));
870a6d42e7dSPeter Dunlap 	pdu->isp_datalen = n2h24(bhs->dlength);
8712727bb05STim Kordas 
8722727bb05STim Kordas 	if (!idm_dataseglenokay(ic, pdu)) {
87356261083SCharles Ting 		IDM_CONN_LOG(CE_WARN,
8742727bb05STim Kordas 		    "idm_sorecvhdr: invalid data segment length");
87556261083SCharles Ting 		return (IDM_STATUS_FAIL);
87656261083SCharles Ting 	}
877*61dfa509SRick McNeal 	if (bhs->hlength > IDM_SORX_WIRE_AHSLEN) {
878a6d42e7dSPeter Dunlap 		/* Allocate a new header segment and change the callback */
879a6d42e7dSPeter Dunlap 		new_hdr = kmem_alloc(pdu->isp_hdrlen, KM_SLEEP);
880a6d42e7dSPeter Dunlap 		bcopy(pdu->isp_hdr, new_hdr, sizeof (iscsi_hdr_t));
881a6d42e7dSPeter Dunlap 		pdu->isp_hdr = new_hdr;
882a6d42e7dSPeter Dunlap 		pdu->isp_flags |= IDM_PDU_ADDL_HDR;
883a6d42e7dSPeter Dunlap 
884a6d42e7dSPeter Dunlap 		/*
885a6d42e7dSPeter Dunlap 		 * This callback will restore the expected values after
886a6d42e7dSPeter Dunlap 		 * the RX PDU has been processed.
887a6d42e7dSPeter Dunlap 		 */
888a6d42e7dSPeter Dunlap 		pdu->isp_callback = idm_sorx_addl_pdu_cb;
889a6d42e7dSPeter Dunlap 	}
890a6d42e7dSPeter Dunlap 
891a6d42e7dSPeter Dunlap 	/*
892a6d42e7dSPeter Dunlap 	 * Setup receipt of additional header and header digest (if enabled).
893a6d42e7dSPeter Dunlap 	 */
894a6d42e7dSPeter Dunlap 	if (bhs->hlength > 0) {
895a6d42e7dSPeter Dunlap 		iov[iovlen].iov_base = (caddr_t)(pdu->isp_hdr + 1);
896a6d42e7dSPeter Dunlap 		ahslen = pdu->isp_hdrlen - sizeof (iscsi_hdr_t);
897a6d42e7dSPeter Dunlap 		iov[iovlen].iov_len = ahslen;
898a6d42e7dSPeter Dunlap 		total_len += iov[iovlen].iov_len;
899a6d42e7dSPeter Dunlap 		iovlen++;
900a6d42e7dSPeter Dunlap 	}
901a6d42e7dSPeter Dunlap 
902a6d42e7dSPeter Dunlap 	if (ic->ic_conn_flags & IDM_CONN_HEADER_DIGEST) {
903a6d42e7dSPeter Dunlap 		iov[iovlen].iov_base = (caddr_t)&hdr_digest_crc;
904a6d42e7dSPeter Dunlap 		iov[iovlen].iov_len = sizeof (hdr_digest_crc);
905a6d42e7dSPeter Dunlap 		total_len += iov[iovlen].iov_len;
906a6d42e7dSPeter Dunlap 		iovlen++;
907a6d42e7dSPeter Dunlap 	}
908a6d42e7dSPeter Dunlap 
909a6d42e7dSPeter Dunlap 	if ((iovlen != 0) &&
910a6d42e7dSPeter Dunlap 	    (idm_iov_sorecv(so_conn->ic_so, &iov[0], iovlen,
911a6d42e7dSPeter Dunlap 	    total_len) != 0)) {
912a6d42e7dSPeter Dunlap 		return (IDM_STATUS_FAIL);
913a6d42e7dSPeter Dunlap 	}
914a6d42e7dSPeter Dunlap 
915a6d42e7dSPeter Dunlap 	/*
916a6d42e7dSPeter Dunlap 	 * Validate header digest if enabled
917a6d42e7dSPeter Dunlap 	 */
918a6d42e7dSPeter Dunlap 	if (ic->ic_conn_flags & IDM_CONN_HEADER_DIGEST) {
919a6d42e7dSPeter Dunlap 		crc_calculated = idm_crc32c(pdu->isp_hdr,
920a6d42e7dSPeter Dunlap 		    sizeof (iscsi_hdr_t) + ahslen);
921a6d42e7dSPeter Dunlap 		if (crc_calculated != hdr_digest_crc) {
922a6d42e7dSPeter Dunlap 			/* Invalid Header Digest */
923a6d42e7dSPeter Dunlap 			return (IDM_STATUS_HEADER_DIGEST);
924a6d42e7dSPeter Dunlap 		}
925a6d42e7dSPeter Dunlap 	}
926a6d42e7dSPeter Dunlap 
927a6d42e7dSPeter Dunlap 	return (0);
928a6d42e7dSPeter Dunlap }
929a6d42e7dSPeter Dunlap 
930a6d42e7dSPeter Dunlap /*
931a6d42e7dSPeter Dunlap  * idm_so_ini_conn_create()
932a6d42e7dSPeter Dunlap  * Allocate the sockets transport connection resources.
933a6d42e7dSPeter Dunlap  */
934a6d42e7dSPeter Dunlap static idm_status_t
idm_so_ini_conn_create(idm_conn_req_t * cr,idm_conn_t * ic)935a6d42e7dSPeter Dunlap idm_so_ini_conn_create(idm_conn_req_t *cr, idm_conn_t *ic)
936a6d42e7dSPeter Dunlap {
9370f1702c5SYu Xiangning 	ksocket_t	so;
938a6d42e7dSPeter Dunlap 	idm_so_conn_t	*so_conn;
939a6d42e7dSPeter Dunlap 	idm_status_t	idmrc;
940a6d42e7dSPeter Dunlap 
941a6d42e7dSPeter Dunlap 	so = idm_socreate(cr->cr_domain, cr->cr_type,
942a6d42e7dSPeter Dunlap 	    cr->cr_protocol);
943a6d42e7dSPeter Dunlap 	if (so == NULL) {
944a6d42e7dSPeter Dunlap 		return (IDM_STATUS_FAIL);
945a6d42e7dSPeter Dunlap 	}
946a6d42e7dSPeter Dunlap 
947a6d42e7dSPeter Dunlap 	/* Bind the socket if configured to do so */
948a6d42e7dSPeter Dunlap 	if (cr->cr_bound) {
9490f1702c5SYu Xiangning 		if (ksocket_bind(so, &cr->cr_bound_addr.sin,
9500f1702c5SYu Xiangning 		    SIZEOF_SOCKADDR(&cr->cr_bound_addr.sin), CRED()) != 0) {
951a6d42e7dSPeter Dunlap 			idm_sodestroy(so);
952a6d42e7dSPeter Dunlap 			return (IDM_STATUS_FAIL);
953a6d42e7dSPeter Dunlap 		}
954a6d42e7dSPeter Dunlap 	}
955a6d42e7dSPeter Dunlap 
956a6d42e7dSPeter Dunlap 	idmrc = idm_so_conn_create_common(ic, so);
957a6d42e7dSPeter Dunlap 	if (idmrc != IDM_STATUS_SUCCESS) {
958a6d42e7dSPeter Dunlap 		idm_soshutdown(so);
959a6d42e7dSPeter Dunlap 		idm_sodestroy(so);
960a6d42e7dSPeter Dunlap 		return (IDM_STATUS_FAIL);
961a6d42e7dSPeter Dunlap 	}
962a6d42e7dSPeter Dunlap 
963a6d42e7dSPeter Dunlap 	so_conn = ic->ic_transport_private;
964a6d42e7dSPeter Dunlap 	/* Set up socket options */
965dedec472SJack Meng 	idm_set_ini_preconnect_options(so_conn, cr->cr_boot_conn);
966a6d42e7dSPeter Dunlap 
967a6d42e7dSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
968a6d42e7dSPeter Dunlap }
969a6d42e7dSPeter Dunlap 
970a6d42e7dSPeter Dunlap /*
971a6d42e7dSPeter Dunlap  * idm_so_ini_conn_destroy()
972a6d42e7dSPeter Dunlap  * Tear down the sockets transport connection resources.
973a6d42e7dSPeter Dunlap  */
974a6d42e7dSPeter Dunlap static void
idm_so_ini_conn_destroy(idm_conn_t * ic)975a6d42e7dSPeter Dunlap idm_so_ini_conn_destroy(idm_conn_t *ic)
976a6d42e7dSPeter Dunlap {
977a6d42e7dSPeter Dunlap 	idm_so_conn_destroy_common(ic);
978a6d42e7dSPeter Dunlap }
979a6d42e7dSPeter Dunlap 
980a6d42e7dSPeter Dunlap /*
981a6d42e7dSPeter Dunlap  * idm_so_ini_conn_connect()
982a6d42e7dSPeter Dunlap  * Establish the connection referred to by the handle previously allocated via
983a6d42e7dSPeter Dunlap  * idm_so_ini_conn_create().
984a6d42e7dSPeter Dunlap  */
985a6d42e7dSPeter Dunlap static idm_status_t
idm_so_ini_conn_connect(idm_conn_t * ic)986a6d42e7dSPeter Dunlap idm_so_ini_conn_connect(idm_conn_t *ic)
987a6d42e7dSPeter Dunlap {
988a6d42e7dSPeter Dunlap 	idm_so_conn_t	*so_conn;
989aff4bce5Syi zhang - Sun Microsystems - Beijing China 	struct sonode	*node = NULL;
9908e718be9SToomas Soome 	int		rc;
991aff4bce5Syi zhang - Sun Microsystems - Beijing China 	clock_t		lbolt, conn_login_max, conn_login_interval;
992aff4bce5Syi zhang - Sun Microsystems - Beijing China 	boolean_t	nonblock;
993a6d42e7dSPeter Dunlap 
994a6d42e7dSPeter Dunlap 	so_conn = ic->ic_transport_private;
995aff4bce5Syi zhang - Sun Microsystems - Beijing China 	nonblock = ic->ic_conn_params.nonblock_socket;
996aff4bce5Syi zhang - Sun Microsystems - Beijing China 	conn_login_max = ic->ic_conn_params.conn_login_max;
997aff4bce5Syi zhang - Sun Microsystems - Beijing China 	conn_login_interval = ddi_get_lbolt() +
998aff4bce5Syi zhang - Sun Microsystems - Beijing China 	    SEC_TO_TICK(ic->ic_conn_params.conn_login_interval);
999aff4bce5Syi zhang - Sun Microsystems - Beijing China 
1000aff4bce5Syi zhang - Sun Microsystems - Beijing China 	if (nonblock == B_TRUE) {
1001aff4bce5Syi zhang - Sun Microsystems - Beijing China 		node = ((struct sonode *)(so_conn->ic_so));
1002aff4bce5Syi zhang - Sun Microsystems - Beijing China 		/* Set to none block socket mode */
1003aff4bce5Syi zhang - Sun Microsystems - Beijing China 		idm_so_socket_set_nonblock(node);
1004aff4bce5Syi zhang - Sun Microsystems - Beijing China 		do {
1005aff4bce5Syi zhang - Sun Microsystems - Beijing China 			rc = ksocket_connect(so_conn->ic_so,
1006aff4bce5Syi zhang - Sun Microsystems - Beijing China 			    &ic->ic_ini_dst_addr.sin,
1007aff4bce5Syi zhang - Sun Microsystems - Beijing China 			    (SIZEOF_SOCKADDR(&ic->ic_ini_dst_addr.sin)),
1008aff4bce5Syi zhang - Sun Microsystems - Beijing China 			    CRED());
1009aff4bce5Syi zhang - Sun Microsystems - Beijing China 			if (rc == 0 || rc == EISCONN) {
1010aff4bce5Syi zhang - Sun Microsystems - Beijing China 				/* socket success or already success */
1011aff4bce5Syi zhang - Sun Microsystems - Beijing China 				rc = IDM_STATUS_SUCCESS;
1012aff4bce5Syi zhang - Sun Microsystems - Beijing China 				break;
1013aff4bce5Syi zhang - Sun Microsystems - Beijing China 			}
1014aff4bce5Syi zhang - Sun Microsystems - Beijing China 			if ((rc == ETIMEDOUT) || (rc == ECONNREFUSED) ||
1015aff4bce5Syi zhang - Sun Microsystems - Beijing China 			    (rc == ECONNRESET)) {
1016aff4bce5Syi zhang - Sun Microsystems - Beijing China 				/* socket connection timeout or refuse */
1017aff4bce5Syi zhang - Sun Microsystems - Beijing China 				break;
1018aff4bce5Syi zhang - Sun Microsystems - Beijing China 			}
1019aff4bce5Syi zhang - Sun Microsystems - Beijing China 			lbolt = ddi_get_lbolt();
1020aff4bce5Syi zhang - Sun Microsystems - Beijing China 			if (lbolt > conn_login_max) {
1021aff4bce5Syi zhang - Sun Microsystems - Beijing China 				/*
1022aff4bce5Syi zhang - Sun Microsystems - Beijing China 				 * Connection retry timeout,
1023aff4bce5Syi zhang - Sun Microsystems - Beijing China 				 * failed connect to target.
1024aff4bce5Syi zhang - Sun Microsystems - Beijing China 				 */
1025aff4bce5Syi zhang - Sun Microsystems - Beijing China 				break;
1026aff4bce5Syi zhang - Sun Microsystems - Beijing China 			}
1027aff4bce5Syi zhang - Sun Microsystems - Beijing China 			if (lbolt < conn_login_interval) {
1028aff4bce5Syi zhang - Sun Microsystems - Beijing China 				if ((rc == EINPROGRESS) || (rc == EALREADY)) {
1029aff4bce5Syi zhang - Sun Microsystems - Beijing China 					/* TCP connect still in progress */
1030aff4bce5Syi zhang - Sun Microsystems - Beijing China 					delay(SEC_TO_TICK(IN_PROGRESS_DELAY));
1031aff4bce5Syi zhang - Sun Microsystems - Beijing China 					continue;
1032aff4bce5Syi zhang - Sun Microsystems - Beijing China 				} else {
1033aff4bce5Syi zhang - Sun Microsystems - Beijing China 					delay(conn_login_interval - lbolt);
1034aff4bce5Syi zhang - Sun Microsystems - Beijing China 				}
1035aff4bce5Syi zhang - Sun Microsystems - Beijing China 			}
1036aff4bce5Syi zhang - Sun Microsystems - Beijing China 			conn_login_interval = ddi_get_lbolt() +
1037aff4bce5Syi zhang - Sun Microsystems - Beijing China 			    SEC_TO_TICK(ic->ic_conn_params.conn_login_interval);
1038aff4bce5Syi zhang - Sun Microsystems - Beijing China 		} while (rc != 0);
1039aff4bce5Syi zhang - Sun Microsystems - Beijing China 		/* resume to nonblock mode */
1040aff4bce5Syi zhang - Sun Microsystems - Beijing China 		if (rc == IDM_STATUS_SUCCESS) {
1041aff4bce5Syi zhang - Sun Microsystems - Beijing China 			idm_so_socket_set_block(node);
1042aff4bce5Syi zhang - Sun Microsystems - Beijing China 		}
1043aff4bce5Syi zhang - Sun Microsystems - Beijing China 	} else {
1044aff4bce5Syi zhang - Sun Microsystems - Beijing China 		rc = ksocket_connect(so_conn->ic_so, &ic->ic_ini_dst_addr.sin,
1045aff4bce5Syi zhang - Sun Microsystems - Beijing China 		    (SIZEOF_SOCKADDR(&ic->ic_ini_dst_addr.sin)), CRED());
1046aff4bce5Syi zhang - Sun Microsystems - Beijing China 	}
1047a6d42e7dSPeter Dunlap 
1048aff4bce5Syi zhang - Sun Microsystems - Beijing China 	if (rc != 0) {
1049a6d42e7dSPeter Dunlap 		idm_soshutdown(so_conn->ic_so);
1050a6d42e7dSPeter Dunlap 		return (IDM_STATUS_FAIL);
1051a6d42e7dSPeter Dunlap 	}
1052a6d42e7dSPeter Dunlap 
1053a6d42e7dSPeter Dunlap 	idm_so_conn_connect_common(ic);
1054a6d42e7dSPeter Dunlap 
10550f94976eSJeff Biseda 	idm_set_postconnect_options(so_conn->ic_so);
1056a6d42e7dSPeter Dunlap 
1057a6d42e7dSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
1058a6d42e7dSPeter Dunlap }
1059a6d42e7dSPeter Dunlap 
1060a6d42e7dSPeter Dunlap idm_status_t
idm_so_tgt_conn_create(idm_conn_t * ic,ksocket_t new_so)10610f1702c5SYu Xiangning idm_so_tgt_conn_create(idm_conn_t *ic, ksocket_t new_so)
1062a6d42e7dSPeter Dunlap {
1063a6d42e7dSPeter Dunlap 	idm_status_t	idmrc;
1064a6d42e7dSPeter Dunlap 
10650f94976eSJeff Biseda 	idm_set_postconnect_options(new_so);
1066a6d42e7dSPeter Dunlap 	idmrc = idm_so_conn_create_common(ic, new_so);
1067a6d42e7dSPeter Dunlap 
1068a6d42e7dSPeter Dunlap 	return (idmrc);
1069a6d42e7dSPeter Dunlap }
1070a6d42e7dSPeter Dunlap 
1071a6d42e7dSPeter Dunlap static void
idm_so_tgt_conn_destroy(idm_conn_t * ic)1072a6d42e7dSPeter Dunlap idm_so_tgt_conn_destroy(idm_conn_t *ic)
1073a6d42e7dSPeter Dunlap {
1074a6d42e7dSPeter Dunlap 	idm_so_conn_destroy_common(ic);
1075a6d42e7dSPeter Dunlap }
1076a6d42e7dSPeter Dunlap 
1077a6d42e7dSPeter Dunlap /*
1078a6d42e7dSPeter Dunlap  * idm_so_tgt_conn_connect()
1079a6d42e7dSPeter Dunlap  * Establish the connection in ic, passed from idm_tgt_conn_finish(), which
1080a6d42e7dSPeter Dunlap  * is invoked from the SM as a result of an inbound connection request.
1081a6d42e7dSPeter Dunlap  */
1082a6d42e7dSPeter Dunlap static idm_status_t
idm_so_tgt_conn_connect(idm_conn_t * ic)1083a6d42e7dSPeter Dunlap idm_so_tgt_conn_connect(idm_conn_t *ic)
1084a6d42e7dSPeter Dunlap {
1085a6d42e7dSPeter Dunlap 	idm_so_conn_connect_common(ic);
1086a6d42e7dSPeter Dunlap 
1087a6d42e7dSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
1088a6d42e7dSPeter Dunlap }
1089a6d42e7dSPeter Dunlap 
1090a6d42e7dSPeter Dunlap static idm_status_t
idm_so_conn_create_common(idm_conn_t * ic,ksocket_t new_so)10910f1702c5SYu Xiangning idm_so_conn_create_common(idm_conn_t *ic, ksocket_t new_so)
1092a6d42e7dSPeter Dunlap {
1093a6d42e7dSPeter Dunlap 	idm_so_conn_t	*so_conn;
1094a6d42e7dSPeter Dunlap 
1095a6d42e7dSPeter Dunlap 	so_conn = kmem_zalloc(sizeof (idm_so_conn_t), KM_SLEEP);
1096a6d42e7dSPeter Dunlap 	so_conn->ic_so = new_so;
1097a6d42e7dSPeter Dunlap 
1098a6d42e7dSPeter Dunlap 	ic->ic_transport_private = so_conn;
1099a6d42e7dSPeter Dunlap 	ic->ic_transport_hdrlen = 0;
1100a6d42e7dSPeter Dunlap 
1101a6d42e7dSPeter Dunlap 	/* Set the scoreboarding flag on this connection */
1102a6d42e7dSPeter Dunlap 	ic->ic_conn_flags |= IDM_CONN_USE_SCOREBOARD;
110356261083SCharles Ting 	ic->ic_conn_params.max_recv_dataseglen =
110456261083SCharles Ting 	    ISCSI_DEFAULT_MAX_RECV_SEG_LEN;
110556261083SCharles Ting 	ic->ic_conn_params.max_xmit_dataseglen =
110656261083SCharles Ting 	    ISCSI_DEFAULT_MAX_XMIT_SEG_LEN;
1107a6d42e7dSPeter Dunlap 
1108a6d42e7dSPeter Dunlap 	/*
1109a6d42e7dSPeter Dunlap 	 * Initialize tx thread mutex and list
1110a6d42e7dSPeter Dunlap 	 */
1111a6d42e7dSPeter Dunlap 	mutex_init(&so_conn->ic_tx_mutex, NULL, MUTEX_DEFAULT, NULL);
1112a6d42e7dSPeter Dunlap 	cv_init(&so_conn->ic_tx_cv, NULL, CV_DEFAULT, NULL);
1113a6d42e7dSPeter Dunlap 	list_create(&so_conn->ic_tx_list, sizeof (idm_pdu_t),
1114a6d42e7dSPeter Dunlap 	    offsetof(idm_pdu_t, idm_tx_link));
1115a6d42e7dSPeter Dunlap 
1116a6d42e7dSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
1117a6d42e7dSPeter Dunlap }
1118a6d42e7dSPeter Dunlap 
1119a6d42e7dSPeter Dunlap static void
idm_so_conn_destroy_common(idm_conn_t * ic)1120a6d42e7dSPeter Dunlap idm_so_conn_destroy_common(idm_conn_t *ic)
1121a6d42e7dSPeter Dunlap {
1122a6d42e7dSPeter Dunlap 	idm_so_conn_t	*so_conn = ic->ic_transport_private;
1123a6d42e7dSPeter Dunlap 
1124a6d42e7dSPeter Dunlap 	ic->ic_transport_private = NULL;
1125a6d42e7dSPeter Dunlap 	idm_sodestroy(so_conn->ic_so);
1126a6d42e7dSPeter Dunlap 	list_destroy(&so_conn->ic_tx_list);
1127a6d42e7dSPeter Dunlap 	mutex_destroy(&so_conn->ic_tx_mutex);
1128a6d42e7dSPeter Dunlap 	cv_destroy(&so_conn->ic_tx_cv);
1129a6d42e7dSPeter Dunlap 
1130a6d42e7dSPeter Dunlap 	kmem_free(so_conn, sizeof (idm_so_conn_t));
1131a6d42e7dSPeter Dunlap }
1132a6d42e7dSPeter Dunlap 
1133a6d42e7dSPeter Dunlap static void
idm_so_conn_connect_common(idm_conn_t * ic)1134a6d42e7dSPeter Dunlap idm_so_conn_connect_common(idm_conn_t *ic)
1135a6d42e7dSPeter Dunlap {
1136a6d42e7dSPeter Dunlap 	idm_so_conn_t	*so_conn;
11370f1702c5SYu Xiangning 	struct sockaddr_in6	t_addr;
11380f1702c5SYu Xiangning 	socklen_t	t_addrlen = 0;
1139a6d42e7dSPeter Dunlap 
1140a6d42e7dSPeter Dunlap 	so_conn = ic->ic_transport_private;
11410f1702c5SYu Xiangning 	bzero(&t_addr, sizeof (struct sockaddr_in6));
11420f1702c5SYu Xiangning 	t_addrlen = sizeof (struct sockaddr_in6);
1143a6d42e7dSPeter Dunlap 
1144a6d42e7dSPeter Dunlap 	/* Set the local and remote addresses in the idm conn handle */
1145aedf2b3bSsrivijitha dugganapalli 	(void) ksocket_getsockname(so_conn->ic_so, (struct sockaddr *)&t_addr,
11460f1702c5SYu Xiangning 	    &t_addrlen, CRED());
11470f1702c5SYu Xiangning 	bcopy(&t_addr, &ic->ic_laddr, t_addrlen);
1148aedf2b3bSsrivijitha dugganapalli 	(void) ksocket_getpeername(so_conn->ic_so, (struct sockaddr *)&t_addr,
11490f1702c5SYu Xiangning 	    &t_addrlen, CRED());
11500f1702c5SYu Xiangning 	bcopy(&t_addr, &ic->ic_raddr, t_addrlen);
1151a6d42e7dSPeter Dunlap 
1152a6d42e7dSPeter Dunlap 	mutex_enter(&ic->ic_mutex);
1153a6d42e7dSPeter Dunlap 	so_conn->ic_tx_thread = thread_create(NULL, 0, idm_sotx_thread, ic, 0,
1154a6d42e7dSPeter Dunlap 	    &p0, TS_RUN, minclsyspri);
1155a6d42e7dSPeter Dunlap 	so_conn->ic_rx_thread = thread_create(NULL, 0, idm_sorx_thread, ic, 0,
1156a6d42e7dSPeter Dunlap 	    &p0, TS_RUN, minclsyspri);
1157a6d42e7dSPeter Dunlap 
1158e97fb153SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	while (so_conn->ic_rx_thread_did == 0 ||
1159e97fb153SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	    so_conn->ic_tx_thread_did == 0)
1160a6d42e7dSPeter Dunlap 		cv_wait(&ic->ic_cv, &ic->ic_mutex);
1161a6d42e7dSPeter Dunlap 	mutex_exit(&ic->ic_mutex);
1162a6d42e7dSPeter Dunlap }
1163a6d42e7dSPeter Dunlap 
1164a6d42e7dSPeter Dunlap /*
1165a6d42e7dSPeter Dunlap  * idm_so_conn_disconnect()
1166a6d42e7dSPeter Dunlap  * Shutdown the socket connection and stop the thread
1167a6d42e7dSPeter Dunlap  */
1168a6d42e7dSPeter Dunlap static void
idm_so_conn_disconnect(idm_conn_t * ic)1169a6d42e7dSPeter Dunlap idm_so_conn_disconnect(idm_conn_t *ic)
1170a6d42e7dSPeter Dunlap {
1171a6d42e7dSPeter Dunlap 	idm_so_conn_t	*so_conn;
1172a6d42e7dSPeter Dunlap 
1173a6d42e7dSPeter Dunlap 	so_conn = ic->ic_transport_private;
1174a6d42e7dSPeter Dunlap 
1175a6d42e7dSPeter Dunlap 	mutex_enter(&ic->ic_mutex);
1176a6d42e7dSPeter Dunlap 	so_conn->ic_rx_thread_running = B_FALSE;
1177a6d42e7dSPeter Dunlap 	so_conn->ic_tx_thread_running = B_FALSE;
1178a6d42e7dSPeter Dunlap 	/* We need to wakeup the TX thread */
1179a6d42e7dSPeter Dunlap 	mutex_enter(&so_conn->ic_tx_mutex);
1180a6d42e7dSPeter Dunlap 	cv_signal(&so_conn->ic_tx_cv);
1181a6d42e7dSPeter Dunlap 	mutex_exit(&so_conn->ic_tx_mutex);
1182a6d42e7dSPeter Dunlap 	mutex_exit(&ic->ic_mutex);
1183a6d42e7dSPeter Dunlap 
1184a6d42e7dSPeter Dunlap 	/* This should wakeup the RX thread if it is sleeping */
1185a6d42e7dSPeter Dunlap 	idm_soshutdown(so_conn->ic_so);
1186a6d42e7dSPeter Dunlap 
1187a6d42e7dSPeter Dunlap 	thread_join(so_conn->ic_tx_thread_did);
1188a6d42e7dSPeter Dunlap 	thread_join(so_conn->ic_rx_thread_did);
1189a6d42e7dSPeter Dunlap }
1190a6d42e7dSPeter Dunlap 
1191a6d42e7dSPeter Dunlap /*
1192a6d42e7dSPeter Dunlap  * idm_so_tgt_svc_create()
1193a6d42e7dSPeter Dunlap  * Establish a service on an IP address and port.  idm_svc_req_t contains
1194a6d42e7dSPeter Dunlap  * the service parameters.
1195a6d42e7dSPeter Dunlap  */
1196a6d42e7dSPeter Dunlap /*ARGSUSED*/
1197a6d42e7dSPeter Dunlap static idm_status_t
idm_so_tgt_svc_create(idm_svc_req_t * sr,idm_svc_t * is)1198a6d42e7dSPeter Dunlap idm_so_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t *is)
1199a6d42e7dSPeter Dunlap {
1200a6d42e7dSPeter Dunlap 	idm_so_svc_t		*so_svc;
1201a6d42e7dSPeter Dunlap 
1202a6d42e7dSPeter Dunlap 	so_svc = kmem_zalloc(sizeof (idm_so_svc_t), KM_SLEEP);
1203a6d42e7dSPeter Dunlap 
1204a6d42e7dSPeter Dunlap 	/* Set the new sockets service in svc handle */
1205a6d42e7dSPeter Dunlap 	is->is_so_svc = (void *)so_svc;
1206a6d42e7dSPeter Dunlap 
1207a6d42e7dSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
1208a6d42e7dSPeter Dunlap }
1209a6d42e7dSPeter Dunlap 
1210a6d42e7dSPeter Dunlap /*
1211a6d42e7dSPeter Dunlap  * idm_so_tgt_svc_destroy()
1212a6d42e7dSPeter Dunlap  * Teardown sockets resources allocated in idm_so_tgt_svc_create()
1213a6d42e7dSPeter Dunlap  */
1214a6d42e7dSPeter Dunlap static void
idm_so_tgt_svc_destroy(idm_svc_t * is)1215a6d42e7dSPeter Dunlap idm_so_tgt_svc_destroy(idm_svc_t *is)
1216a6d42e7dSPeter Dunlap {
1217a6d42e7dSPeter Dunlap 	/* the socket will have been torn down; free the service */
1218a6d42e7dSPeter Dunlap 	kmem_free(is->is_so_svc, sizeof (idm_so_svc_t));
1219a6d42e7dSPeter Dunlap }
1220a6d42e7dSPeter Dunlap 
1221a6d42e7dSPeter Dunlap /*
1222a6d42e7dSPeter Dunlap  * idm_so_tgt_svc_online()
1223a6d42e7dSPeter Dunlap  * Launch a watch thread on the svc allocated in idm_so_tgt_svc_create()
1224a6d42e7dSPeter Dunlap  */
1225a6d42e7dSPeter Dunlap 
1226a6d42e7dSPeter Dunlap static idm_status_t
idm_so_tgt_svc_online(idm_svc_t * is)1227a6d42e7dSPeter Dunlap idm_so_tgt_svc_online(idm_svc_t *is)
1228a6d42e7dSPeter Dunlap {
1229a6d42e7dSPeter Dunlap 	idm_so_svc_t		*so_svc;
1230a6d42e7dSPeter Dunlap 	idm_svc_req_t		*sr = &is->is_svc_req;
1231a6d42e7dSPeter Dunlap 	struct sockaddr_in6	sin6_ip;
1232a6d42e7dSPeter Dunlap 	const uint32_t		on = 1;
1233a6d42e7dSPeter Dunlap 	const uint32_t		off = 0;
1234a6d42e7dSPeter Dunlap 
1235a6d42e7dSPeter Dunlap 	mutex_enter(&is->is_mutex);
1236a6d42e7dSPeter Dunlap 	so_svc = (idm_so_svc_t *)is->is_so_svc;
1237a6d42e7dSPeter Dunlap 
1238a6d42e7dSPeter Dunlap 	/*
1239a6d42e7dSPeter Dunlap 	 * Try creating an IPv6 socket first
1240a6d42e7dSPeter Dunlap 	 */
1241a6d42e7dSPeter Dunlap 	if ((so_svc->is_so = idm_socreate(PF_INET6, SOCK_STREAM, 0)) == NULL) {
1242a6d42e7dSPeter Dunlap 		mutex_exit(&is->is_mutex);
1243a6d42e7dSPeter Dunlap 		return (IDM_STATUS_FAIL);
1244a6d42e7dSPeter Dunlap 	} else {
1245a6d42e7dSPeter Dunlap 		bzero(&sin6_ip, sizeof (sin6_ip));
1246a6d42e7dSPeter Dunlap 		sin6_ip.sin6_family = AF_INET6;
1247a6d42e7dSPeter Dunlap 		sin6_ip.sin6_port = htons(sr->sr_port);
1248a6d42e7dSPeter Dunlap 		sin6_ip.sin6_addr = in6addr_any;
1249a6d42e7dSPeter Dunlap 
12500f1702c5SYu Xiangning 		(void) ksocket_setsockopt(so_svc->is_so, SOL_SOCKET,
12510f1702c5SYu Xiangning 		    SO_REUSEADDR, (char *)&on, sizeof (on), CRED());
1252a6d42e7dSPeter Dunlap 		/*
1253a6d42e7dSPeter Dunlap 		 * Turn off SO_MAC_EXEMPT so future sobinds succeed
1254a6d42e7dSPeter Dunlap 		 */
12550f1702c5SYu Xiangning 		(void) ksocket_setsockopt(so_svc->is_so, SOL_SOCKET,
12560f1702c5SYu Xiangning 		    SO_MAC_EXEMPT, (char *)&off, sizeof (off), CRED());
1257a6d42e7dSPeter Dunlap 
12580f1702c5SYu Xiangning 		if (ksocket_bind(so_svc->is_so, (struct sockaddr *)&sin6_ip,
12590f1702c5SYu Xiangning 		    sizeof (sin6_ip), CRED()) != 0) {
1260a6d42e7dSPeter Dunlap 			mutex_exit(&is->is_mutex);
1261a6d42e7dSPeter Dunlap 			idm_sodestroy(so_svc->is_so);
1262a6d42e7dSPeter Dunlap 			return (IDM_STATUS_FAIL);
1263a6d42e7dSPeter Dunlap 		}
1264a6d42e7dSPeter Dunlap 	}
1265a6d42e7dSPeter Dunlap 
12660f94976eSJeff Biseda 	idm_set_postconnect_options(so_svc->is_so);
1267a6d42e7dSPeter Dunlap 
12680f1702c5SYu Xiangning 	if (ksocket_listen(so_svc->is_so, 5, CRED()) != 0) {
1269a6d42e7dSPeter Dunlap 		mutex_exit(&is->is_mutex);
1270a6d42e7dSPeter Dunlap 		idm_soshutdown(so_svc->is_so);
1271a6d42e7dSPeter Dunlap 		idm_sodestroy(so_svc->is_so);
1272a6d42e7dSPeter Dunlap 		return (IDM_STATUS_FAIL);
1273a6d42e7dSPeter Dunlap 	}
1274a6d42e7dSPeter Dunlap 
1275a6d42e7dSPeter Dunlap 	/* Launch a watch thread */
1276a6d42e7dSPeter Dunlap 	so_svc->is_thread = thread_create(NULL, 0, idm_so_svc_port_watcher,
1277a6d42e7dSPeter Dunlap 	    is, 0, &p0, TS_RUN, minclsyspri);
1278a6d42e7dSPeter Dunlap 
1279a6d42e7dSPeter Dunlap 	if (so_svc->is_thread == NULL) {
1280a6d42e7dSPeter Dunlap 		/* Failure to launch; teardown the socket */
1281a6d42e7dSPeter Dunlap 		mutex_exit(&is->is_mutex);
1282a6d42e7dSPeter Dunlap 		idm_soshutdown(so_svc->is_so);
1283a6d42e7dSPeter Dunlap 		idm_sodestroy(so_svc->is_so);
1284a6d42e7dSPeter Dunlap 		return (IDM_STATUS_FAIL);
1285a6d42e7dSPeter Dunlap 	}
12860f1702c5SYu Xiangning 	ksocket_hold(so_svc->is_so);
1287a6d42e7dSPeter Dunlap 	/* Wait for the port watcher thread to start */
1288a6d42e7dSPeter Dunlap 	while (!so_svc->is_thread_running)
1289a6d42e7dSPeter Dunlap 		cv_wait(&is->is_cv, &is->is_mutex);
1290a6d42e7dSPeter Dunlap 	mutex_exit(&is->is_mutex);
1291a6d42e7dSPeter Dunlap 
1292a6d42e7dSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
1293a6d42e7dSPeter Dunlap }
1294a6d42e7dSPeter Dunlap 
1295a6d42e7dSPeter Dunlap /*
1296a6d42e7dSPeter Dunlap  * idm_so_tgt_svc_offline
1297a6d42e7dSPeter Dunlap  *
1298a6d42e7dSPeter Dunlap  * Stop listening on the IP address and port identified by idm_svc_t.
1299a6d42e7dSPeter Dunlap  */
1300a6d42e7dSPeter Dunlap static void
idm_so_tgt_svc_offline(idm_svc_t * is)1301a6d42e7dSPeter Dunlap idm_so_tgt_svc_offline(idm_svc_t *is)
1302a6d42e7dSPeter Dunlap {
1303a6d42e7dSPeter Dunlap 	idm_so_svc_t		*so_svc;
1304a6d42e7dSPeter Dunlap 	mutex_enter(&is->is_mutex);
1305a6d42e7dSPeter Dunlap 	so_svc = (idm_so_svc_t *)is->is_so_svc;
1306a6d42e7dSPeter Dunlap 	so_svc->is_thread_running = B_FALSE;
1307a6d42e7dSPeter Dunlap 	mutex_exit(&is->is_mutex);
1308a6d42e7dSPeter Dunlap 
1309a6d42e7dSPeter Dunlap 	/*
13100f1702c5SYu Xiangning 	 * Teardown socket
1311a6d42e7dSPeter Dunlap 	 */
13120f1702c5SYu Xiangning 	idm_sodestroy(so_svc->is_so);
1313a6d42e7dSPeter Dunlap 
1314a6d42e7dSPeter Dunlap 	/*
1315a6d42e7dSPeter Dunlap 	 * Now we expect the port watcher thread to terminate
1316a6d42e7dSPeter Dunlap 	 */
1317a6d42e7dSPeter Dunlap 	thread_join(so_svc->is_thread_did);
1318a6d42e7dSPeter Dunlap }
1319a6d42e7dSPeter Dunlap 
1320a6d42e7dSPeter Dunlap /*
1321a6d42e7dSPeter Dunlap  * Watch thread for target service connection establishment.
1322a6d42e7dSPeter Dunlap  */
1323a6d42e7dSPeter Dunlap void
idm_so_svc_port_watcher(void * arg)1324a6d42e7dSPeter Dunlap idm_so_svc_port_watcher(void *arg)
1325a6d42e7dSPeter Dunlap {
1326a6d42e7dSPeter Dunlap 	idm_svc_t		*svc = arg;
13270f1702c5SYu Xiangning 	ksocket_t		new_so;
1328a6d42e7dSPeter Dunlap 	idm_conn_t		*ic;
1329a6d42e7dSPeter Dunlap 	idm_status_t		idmrc;
1330a6d42e7dSPeter Dunlap 	idm_so_svc_t		*so_svc;
1331a6d42e7dSPeter Dunlap 	int			rc;
1332a6d42e7dSPeter Dunlap 	const uint32_t		off = 0;
13338e718be9SToomas Soome 	struct sockaddr_in6	t_addr;
13340f1702c5SYu Xiangning 	socklen_t		t_addrlen;
1335a6d42e7dSPeter Dunlap 
13360f1702c5SYu Xiangning 	bzero(&t_addr, sizeof (struct sockaddr_in6));
13370f1702c5SYu Xiangning 	t_addrlen = sizeof (struct sockaddr_in6);
1338a6d42e7dSPeter Dunlap 	mutex_enter(&svc->is_mutex);
1339a6d42e7dSPeter Dunlap 
1340a6d42e7dSPeter Dunlap 	so_svc = svc->is_so_svc;
1341a6d42e7dSPeter Dunlap 	so_svc->is_thread_running = B_TRUE;
1342a6d42e7dSPeter Dunlap 	so_svc->is_thread_did = so_svc->is_thread->t_did;
1343a6d42e7dSPeter Dunlap 
1344a6d42e7dSPeter Dunlap 	cv_signal(&svc->is_cv);
1345a6d42e7dSPeter Dunlap 
1346a6d42e7dSPeter Dunlap 	IDM_SVC_LOG(CE_NOTE, "iSCSI service (%p/%d) online", (void *)svc,
1347a6d42e7dSPeter Dunlap 	    svc->is_svc_req.sr_port);
1348a6d42e7dSPeter Dunlap 
1349a6d42e7dSPeter Dunlap 	while (so_svc->is_thread_running) {
1350a6d42e7dSPeter Dunlap 		mutex_exit(&svc->is_mutex);
1351a6d42e7dSPeter Dunlap 
13520f1702c5SYu Xiangning 		if ((rc = ksocket_accept(so_svc->is_so,
13530f1702c5SYu Xiangning 		    (struct sockaddr *)&t_addr, &t_addrlen,
13540f1702c5SYu Xiangning 		    &new_so, CRED())) != 0) {
1355a6d42e7dSPeter Dunlap 			mutex_enter(&svc->is_mutex);
135657ff5e7eSJeff Biseda 			if (rc != ECONNABORTED && rc != EINTR) {
135757ff5e7eSJeff Biseda 				IDM_SVC_LOG(CE_NOTE, "idm_so_svc_port_watcher:"
135857ff5e7eSJeff Biseda 				    " ksocket_accept failed %d", rc);
135957ff5e7eSJeff Biseda 			}
136057ff5e7eSJeff Biseda 			/*
136157ff5e7eSJeff Biseda 			 * Unclean shutdown of this thread is not handled
136257ff5e7eSJeff Biseda 			 * wait for !is_thread_running.
136357ff5e7eSJeff Biseda 			 */
136457ff5e7eSJeff Biseda 			continue;
1365a6d42e7dSPeter Dunlap 		}
1366a6d42e7dSPeter Dunlap 		/*
1367a6d42e7dSPeter Dunlap 		 * Turn off SO_MAC_EXEMPT so future sobinds succeed
1368a6d42e7dSPeter Dunlap 		 */
13690f1702c5SYu Xiangning 		(void) ksocket_setsockopt(new_so, SOL_SOCKET, SO_MAC_EXEMPT,
13700f1702c5SYu Xiangning 		    (char *)&off, sizeof (off), CRED());
1371a6d42e7dSPeter Dunlap 
1372a6d42e7dSPeter Dunlap 		idmrc = idm_svc_conn_create(svc, IDM_TRANSPORT_TYPE_SOCKETS,
1373a6d42e7dSPeter Dunlap 		    &ic);
1374a6d42e7dSPeter Dunlap 		if (idmrc != IDM_STATUS_SUCCESS) {
1375a6d42e7dSPeter Dunlap 			/* Drop connection */
1376a6d42e7dSPeter Dunlap 			idm_soshutdown(new_so);
1377a6d42e7dSPeter Dunlap 			idm_sodestroy(new_so);
1378a6d42e7dSPeter Dunlap 			mutex_enter(&svc->is_mutex);
1379a6d42e7dSPeter Dunlap 			continue;
1380a6d42e7dSPeter Dunlap 		}
1381a6d42e7dSPeter Dunlap 
1382a6d42e7dSPeter Dunlap 		idmrc = idm_so_tgt_conn_create(ic, new_so);
1383a6d42e7dSPeter Dunlap 		if (idmrc != IDM_STATUS_SUCCESS) {
1384a6d42e7dSPeter Dunlap 			idm_svc_conn_destroy(ic);
1385a6d42e7dSPeter Dunlap 			idm_soshutdown(new_so);
1386a6d42e7dSPeter Dunlap 			idm_sodestroy(new_so);
1387a6d42e7dSPeter Dunlap 			mutex_enter(&svc->is_mutex);
1388a6d42e7dSPeter Dunlap 			continue;
1389a6d42e7dSPeter Dunlap 		}
1390a6d42e7dSPeter Dunlap 
1391a6d42e7dSPeter Dunlap 		/*
1392a6d42e7dSPeter Dunlap 		 * Kick the state machine.  At CS_S3_XPT_UP the state machine
1393a6d42e7dSPeter Dunlap 		 * will notify the client (target) about the new connection.
1394a6d42e7dSPeter Dunlap 		 */
13958e718be9SToomas Soome 		idm_conn_event(ic, CE_CONNECT_ACCEPT, (uintptr_t)NULL);
1396a6d42e7dSPeter Dunlap 
1397a6d42e7dSPeter Dunlap 		mutex_enter(&svc->is_mutex);
1398a6d42e7dSPeter Dunlap 	}
13990f1702c5SYu Xiangning 	ksocket_rele(so_svc->is_so);
1400a6d42e7dSPeter Dunlap 	so_svc->is_thread_running = B_FALSE;
1401a6d42e7dSPeter Dunlap 	mutex_exit(&svc->is_mutex);
1402a6d42e7dSPeter Dunlap 
1403a6d42e7dSPeter Dunlap 	IDM_SVC_LOG(CE_NOTE, "iSCSI service (%p/%d) offline", (void *)svc,
1404a6d42e7dSPeter Dunlap 	    svc->is_svc_req.sr_port);
1405a6d42e7dSPeter Dunlap 
1406a6d42e7dSPeter Dunlap 	thread_exit();
1407a6d42e7dSPeter Dunlap }
1408a6d42e7dSPeter Dunlap 
1409a6d42e7dSPeter Dunlap /*
1410a6d42e7dSPeter Dunlap  * idm_so_free_task_rsrc() stops any ongoing processing of the task and
1411a6d42e7dSPeter Dunlap  * frees resources associated with the task.
1412a6d42e7dSPeter Dunlap  *
1413a6d42e7dSPeter Dunlap  * It's not clear that this should return idm_status_t.  What do we do
1414a6d42e7dSPeter Dunlap  * if it fails?
1415a6d42e7dSPeter Dunlap  */
1416a6d42e7dSPeter Dunlap static idm_status_t
idm_so_free_task_rsrc(idm_task_t * idt)1417a6d42e7dSPeter Dunlap idm_so_free_task_rsrc(idm_task_t *idt)
1418a6d42e7dSPeter Dunlap {
141992adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	idm_buf_t	*idb, *next_idb;
1420a6d42e7dSPeter Dunlap 
142130e7468fSPeter Dunlap 	/*
142230e7468fSPeter Dunlap 	 * There is nothing to cleanup on initiator connections
142330e7468fSPeter Dunlap 	 */
142430e7468fSPeter Dunlap 	if (IDM_CONN_ISINI(idt->idt_ic))
142530e7468fSPeter Dunlap 		return (IDM_STATUS_SUCCESS);
142630e7468fSPeter Dunlap 
1427a6d42e7dSPeter Dunlap 	/*
1428a6d42e7dSPeter Dunlap 	 * If this is a target connection, call idm_buf_rx_from_ini_done for
1429a6d42e7dSPeter Dunlap 	 * any buffer on the "outbufv" list with idb->idb_in_transport==B_TRUE.
1430a6d42e7dSPeter Dunlap 	 *
1431a6d42e7dSPeter Dunlap 	 * In addition, remove any buffers associated with this task from
1432a6d42e7dSPeter Dunlap 	 * the ic_tx_list.  We'll do this by walking the idt_inbufv list, but
1433a6d42e7dSPeter Dunlap 	 * items don't actually get removed from that list (and completion
1434a6d42e7dSPeter Dunlap 	 * routines called) until idm_task_cleanup.
1435a6d42e7dSPeter Dunlap 	 */
1436a6d42e7dSPeter Dunlap 	mutex_enter(&idt->idt_mutex);
1437a6d42e7dSPeter Dunlap 
143892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	for (idb = list_head(&idt->idt_outbufv); idb != NULL; idb = next_idb) {
143992adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		next_idb = list_next(&idt->idt_outbufv, idb);
1440a6d42e7dSPeter Dunlap 		if (idb->idb_in_transport) {
1441a6d42e7dSPeter Dunlap 			/*
1442a6d42e7dSPeter Dunlap 			 * idm_buf_rx_from_ini_done releases idt->idt_mutex
1443a6d42e7dSPeter Dunlap 			 */
1444a668b114SPriya Krishnan 			DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic,
1445a668b114SPriya Krishnan 			    uintptr_t, idb->idb_buf,
1446a668b114SPriya Krishnan 			    uint32_t, idb->idb_bufoffset,
1447a668b114SPriya Krishnan 			    uint64_t, 0, uint32_t, 0, uint32_t, 0,
1448a668b114SPriya Krishnan 			    uint32_t, idb->idb_xfer_len,
1449a668b114SPriya Krishnan 			    int, XFER_BUF_RX_FROM_INI);
1450a6d42e7dSPeter Dunlap 			idm_buf_rx_from_ini_done(idt, idb, IDM_STATUS_ABORTED);
1451a6d42e7dSPeter Dunlap 			mutex_enter(&idt->idt_mutex);
1452a6d42e7dSPeter Dunlap 		}
1453a6d42e7dSPeter Dunlap 	}
1454a6d42e7dSPeter Dunlap 
145592adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	for (idb = list_head(&idt->idt_inbufv); idb != NULL; idb = next_idb) {
145692adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		next_idb = list_next(&idt->idt_inbufv, idb);
1457a6d42e7dSPeter Dunlap 		/*
1458a6d42e7dSPeter Dunlap 		 * We want to remove these items from the tx_list as well,
1459a6d42e7dSPeter Dunlap 		 * but knowing it's in the idt_inbufv list is not a guarantee
1460a6d42e7dSPeter Dunlap 		 * that it's in the tx_list.  If it's on the tx list then
1461a6d42e7dSPeter Dunlap 		 * let idm_sotx_thread() clean it up.
1462a6d42e7dSPeter Dunlap 		 */
1463a6d42e7dSPeter Dunlap 		if (idb->idb_in_transport && !idb->idb_tx_thread) {
1464a6d42e7dSPeter Dunlap 			/*
1465a6d42e7dSPeter Dunlap 			 * idm_buf_tx_to_ini_done releases idt->idt_mutex
1466a6d42e7dSPeter Dunlap 			 */
1467a668b114SPriya Krishnan 			DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic,
1468a668b114SPriya Krishnan 			    uintptr_t, idb->idb_buf,
1469a668b114SPriya Krishnan 			    uint32_t, idb->idb_bufoffset,
1470a668b114SPriya Krishnan 			    uint64_t, 0, uint32_t, 0, uint32_t, 0,
1471a668b114SPriya Krishnan 			    uint32_t, idb->idb_xfer_len,
1472a668b114SPriya Krishnan 			    int, XFER_BUF_TX_TO_INI);
1473a6d42e7dSPeter Dunlap 			idm_buf_tx_to_ini_done(idt, idb, IDM_STATUS_ABORTED);
1474a6d42e7dSPeter Dunlap 			mutex_enter(&idt->idt_mutex);
1475a6d42e7dSPeter Dunlap 		}
1476a6d42e7dSPeter Dunlap 	}
1477a6d42e7dSPeter Dunlap 
1478a6d42e7dSPeter Dunlap 	mutex_exit(&idt->idt_mutex);
1479a6d42e7dSPeter Dunlap 
1480a6d42e7dSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
1481a6d42e7dSPeter Dunlap }
1482a6d42e7dSPeter Dunlap 
1483a6d42e7dSPeter Dunlap /*
1484a6d42e7dSPeter Dunlap  * idm_so_negotiate_key_values() validates the key values for this connection
1485a6d42e7dSPeter Dunlap  */
1486a6d42e7dSPeter Dunlap /* ARGSUSED */
1487a6d42e7dSPeter Dunlap static kv_status_t
idm_so_negotiate_key_values(idm_conn_t * it,nvlist_t * request_nvl,nvlist_t * response_nvl,nvlist_t * negotiated_nvl)1488a6d42e7dSPeter Dunlap idm_so_negotiate_key_values(idm_conn_t *it, nvlist_t *request_nvl,
1489a6d42e7dSPeter Dunlap     nvlist_t *response_nvl, nvlist_t *negotiated_nvl)
1490a6d42e7dSPeter Dunlap {
1491a6d42e7dSPeter Dunlap 	/* All parameters are negotiated at the iscsit level */
1492a6d42e7dSPeter Dunlap 	return (KV_HANDLED);
1493a6d42e7dSPeter Dunlap }
1494a6d42e7dSPeter Dunlap 
1495a6d42e7dSPeter Dunlap /*
1496a6d42e7dSPeter Dunlap  * idm_so_notice_key_values() activates the negotiated key values for
1497a6d42e7dSPeter Dunlap  * this connection.
1498a6d42e7dSPeter Dunlap  */
149930e7468fSPeter Dunlap static void
idm_so_notice_key_values(idm_conn_t * it,nvlist_t * negotiated_nvl)1500a6d42e7dSPeter Dunlap idm_so_notice_key_values(idm_conn_t *it, nvlist_t *negotiated_nvl)
1501a6d42e7dSPeter Dunlap {
1502a6d42e7dSPeter Dunlap 	char			*nvp_name;
1503a6d42e7dSPeter Dunlap 	nvpair_t		*nvp;
1504a6d42e7dSPeter Dunlap 	nvpair_t		*next_nvp;
1505a6d42e7dSPeter Dunlap 	int			nvrc;
1506a6d42e7dSPeter Dunlap 	idm_status_t		idm_status;
1507a6d42e7dSPeter Dunlap 	const idm_kv_xlate_t	*ikvx;
150856261083SCharles Ting 	uint64_t		num_val;
1509a6d42e7dSPeter Dunlap 
1510a6d42e7dSPeter Dunlap 	for (nvp = nvlist_next_nvpair(negotiated_nvl, NULL);
1511a6d42e7dSPeter Dunlap 	    nvp != NULL; nvp = next_nvp) {
1512a6d42e7dSPeter Dunlap 		next_nvp = nvlist_next_nvpair(negotiated_nvl, nvp);
1513a6d42e7dSPeter Dunlap 		nvp_name = nvpair_name(nvp);
1514a6d42e7dSPeter Dunlap 
1515a6d42e7dSPeter Dunlap 		ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name));
1516a6d42e7dSPeter Dunlap 		switch (ikvx->ik_key_id) {
1517a6d42e7dSPeter Dunlap 		case KI_HEADER_DIGEST:
1518a6d42e7dSPeter Dunlap 		case KI_DATA_DIGEST:
1519a6d42e7dSPeter Dunlap 			idm_status = idm_so_handle_digest(it, nvp, ikvx);
1520a6d42e7dSPeter Dunlap 			ASSERT(idm_status == 0);
1521a6d42e7dSPeter Dunlap 
1522a6d42e7dSPeter Dunlap 			/* Remove processed item from negotiated_nvl list */
1523a6d42e7dSPeter Dunlap 			nvrc = nvlist_remove_all(
1524a6d42e7dSPeter Dunlap 			    negotiated_nvl, ikvx->ik_key_name);
1525a6d42e7dSPeter Dunlap 			ASSERT(nvrc == 0);
1526a6d42e7dSPeter Dunlap 			break;
152756261083SCharles Ting 		case KI_MAX_RECV_DATA_SEGMENT_LENGTH:
152856261083SCharles Ting 			/*
152956261083SCharles Ting 			 * Just pass the value down to idm layer.
153056261083SCharles Ting 			 * No need to remove it from negotiated_nvl list here.
153156261083SCharles Ting 			 */
153256261083SCharles Ting 			nvrc = nvpair_value_uint64(nvp, &num_val);
153356261083SCharles Ting 			ASSERT(nvrc == 0);
153456261083SCharles Ting 			it->ic_conn_params.max_xmit_dataseglen =
153556261083SCharles Ting 			    (uint32_t)num_val;
153656261083SCharles Ting 			break;
1537a6d42e7dSPeter Dunlap 		default:
1538a6d42e7dSPeter Dunlap 			break;
1539a6d42e7dSPeter Dunlap 		}
1540a6d42e7dSPeter Dunlap 	}
1541a6d42e7dSPeter Dunlap }
1542a6d42e7dSPeter Dunlap 
154356261083SCharles Ting /*
154456261083SCharles Ting  * idm_so_declare_key_values() declares the key values for this connection
154556261083SCharles Ting  */
154656261083SCharles Ting /* ARGSUSED */
154756261083SCharles Ting static kv_status_t
idm_so_declare_key_values(idm_conn_t * it,nvlist_t * config_nvl,nvlist_t * outgoing_nvl)154856261083SCharles Ting idm_so_declare_key_values(idm_conn_t *it, nvlist_t *config_nvl,
154956261083SCharles Ting     nvlist_t *outgoing_nvl)
155056261083SCharles Ting {
155156261083SCharles Ting 	char			*nvp_name;
155256261083SCharles Ting 	nvpair_t		*nvp;
155356261083SCharles Ting 	nvpair_t		*next_nvp;
155456261083SCharles Ting 	kv_status_t		kvrc;
155556261083SCharles Ting 	int			nvrc = 0;
155656261083SCharles Ting 	const idm_kv_xlate_t	*ikvx;
155756261083SCharles Ting 	uint64_t		num_val;
155856261083SCharles Ting 
155956261083SCharles Ting 	for (nvp = nvlist_next_nvpair(config_nvl, NULL);
156056261083SCharles Ting 	    nvp != NULL && nvrc == 0; nvp = next_nvp) {
156156261083SCharles Ting 		next_nvp = nvlist_next_nvpair(config_nvl, nvp);
156256261083SCharles Ting 		nvp_name = nvpair_name(nvp);
156356261083SCharles Ting 
156456261083SCharles Ting 		ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name));
156556261083SCharles Ting 		switch (ikvx->ik_key_id) {
156656261083SCharles Ting 		case KI_MAX_RECV_DATA_SEGMENT_LENGTH:
156756261083SCharles Ting 			if ((nvrc = nvpair_value_uint64(nvp, &num_val)) != 0) {
156856261083SCharles Ting 				break;
156956261083SCharles Ting 			}
157056261083SCharles Ting 			if (outgoing_nvl &&
157156261083SCharles Ting 			    (nvrc = nvlist_add_uint64(outgoing_nvl,
157256261083SCharles Ting 			    nvp_name, num_val)) != 0) {
157356261083SCharles Ting 				break;
157456261083SCharles Ting 			}
157556261083SCharles Ting 			it->ic_conn_params.max_recv_dataseglen =
157656261083SCharles Ting 			    (uint32_t)num_val;
157756261083SCharles Ting 			break;
157856261083SCharles Ting 		default:
157956261083SCharles Ting 			break;
158056261083SCharles Ting 		}
158156261083SCharles Ting 	}
158256261083SCharles Ting 	kvrc = idm_nvstat_to_kvstat(nvrc);
158356261083SCharles Ting 	return (kvrc);
158456261083SCharles Ting }
1585a6d42e7dSPeter Dunlap 
1586a6d42e7dSPeter Dunlap static idm_status_t
idm_so_handle_digest(idm_conn_t * it,nvpair_t * digest_choice,const idm_kv_xlate_t * ikvx)1587a6d42e7dSPeter Dunlap idm_so_handle_digest(idm_conn_t *it, nvpair_t *digest_choice,
1588a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx)
1589a6d42e7dSPeter Dunlap {
1590a6d42e7dSPeter Dunlap 	int			nvrc;
1591a6d42e7dSPeter Dunlap 	char			*digest_choice_string;
1592a6d42e7dSPeter Dunlap 
1593a6d42e7dSPeter Dunlap 	nvrc = nvpair_value_string(digest_choice,
1594a6d42e7dSPeter Dunlap 	    &digest_choice_string);
1595a6d42e7dSPeter Dunlap 	ASSERT(nvrc == 0);
1596a6d42e7dSPeter Dunlap 	if (strcasecmp(digest_choice_string, "crc32c") == 0) {
1597a6d42e7dSPeter Dunlap 		switch (ikvx->ik_key_id) {
1598a6d42e7dSPeter Dunlap 		case KI_HEADER_DIGEST:
1599a6d42e7dSPeter Dunlap 			it->ic_conn_flags |= IDM_CONN_HEADER_DIGEST;
1600a6d42e7dSPeter Dunlap 			break;
1601a6d42e7dSPeter Dunlap 		case KI_DATA_DIGEST:
1602a6d42e7dSPeter Dunlap 			it->ic_conn_flags |= IDM_CONN_DATA_DIGEST;
1603a6d42e7dSPeter Dunlap 			break;
1604a6d42e7dSPeter Dunlap 		default:
1605a6d42e7dSPeter Dunlap 			ASSERT(0);
1606a6d42e7dSPeter Dunlap 			break;
1607a6d42e7dSPeter Dunlap 		}
1608a6d42e7dSPeter Dunlap 	} else if (strcasecmp(digest_choice_string, "none") == 0) {
1609a6d42e7dSPeter Dunlap 		switch (ikvx->ik_key_id) {
1610a6d42e7dSPeter Dunlap 		case KI_HEADER_DIGEST:
1611a6d42e7dSPeter Dunlap 			it->ic_conn_flags &= ~IDM_CONN_HEADER_DIGEST;
1612a6d42e7dSPeter Dunlap 			break;
1613a6d42e7dSPeter Dunlap 		case KI_DATA_DIGEST:
1614a6d42e7dSPeter Dunlap 			it->ic_conn_flags &= ~IDM_CONN_DATA_DIGEST;
1615a6d42e7dSPeter Dunlap 			break;
1616a6d42e7dSPeter Dunlap 		default:
1617a6d42e7dSPeter Dunlap 			ASSERT(0);
1618a6d42e7dSPeter Dunlap 			break;
1619a6d42e7dSPeter Dunlap 		}
1620a6d42e7dSPeter Dunlap 	} else {
1621a6d42e7dSPeter Dunlap 		ASSERT(0);
1622a6d42e7dSPeter Dunlap 	}
1623a6d42e7dSPeter Dunlap 
1624a6d42e7dSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
1625a6d42e7dSPeter Dunlap }
1626a6d42e7dSPeter Dunlap 
1627a6d42e7dSPeter Dunlap 
1628a6d42e7dSPeter Dunlap /*
1629a6d42e7dSPeter Dunlap  * idm_so_conn_is_capable() verifies that the passed connection is provided
1630a6d42e7dSPeter Dunlap  * for by the sockets interface.
1631a6d42e7dSPeter Dunlap  */
1632a6d42e7dSPeter Dunlap /* ARGSUSED */
1633a6d42e7dSPeter Dunlap static boolean_t
idm_so_conn_is_capable(idm_conn_req_t * ic,idm_transport_caps_t * caps)1634a6d42e7dSPeter Dunlap idm_so_conn_is_capable(idm_conn_req_t *ic, idm_transport_caps_t *caps)
1635a6d42e7dSPeter Dunlap {
1636a6d42e7dSPeter Dunlap 	return (B_TRUE);
1637a6d42e7dSPeter Dunlap }
1638a6d42e7dSPeter Dunlap 
1639a6d42e7dSPeter Dunlap /*
1640a6d42e7dSPeter Dunlap  * idm_so_rx_datain() validates the Data Sequence number of the PDU. The
1641a6d42e7dSPeter Dunlap  * idm_sorecv_scsidata() function invoked earlier actually reads the data
1642a6d42e7dSPeter Dunlap  * off the socket into the appropriate buffers.
1643a6d42e7dSPeter Dunlap  */
1644a6d42e7dSPeter Dunlap static void
idm_so_rx_datain(idm_conn_t * ic,idm_pdu_t * pdu)1645a6d42e7dSPeter Dunlap idm_so_rx_datain(idm_conn_t *ic, idm_pdu_t *pdu)
1646a6d42e7dSPeter Dunlap {
1647a6d42e7dSPeter Dunlap 	iscsi_data_hdr_t	*bhs;
1648a6d42e7dSPeter Dunlap 	idm_task_t		*idt;
1649a6d42e7dSPeter Dunlap 	idm_buf_t		*idb;
1650a6d42e7dSPeter Dunlap 	uint32_t		datasn;
1651a6d42e7dSPeter Dunlap 	size_t			offset;
1652a6d42e7dSPeter Dunlap 	iscsi_hdr_t		*ihp = (iscsi_hdr_t *)pdu->isp_hdr;
1653a6d42e7dSPeter Dunlap 	iscsi_data_rsp_hdr_t    *idrhp = (iscsi_data_rsp_hdr_t *)ihp;
1654a6d42e7dSPeter Dunlap 
1655a6d42e7dSPeter Dunlap 	ASSERT(ic != NULL);
1656a6d42e7dSPeter Dunlap 	ASSERT(pdu != NULL);
16572727bb05STim Kordas 	ASSERT(IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA_RSP);
1658a6d42e7dSPeter Dunlap 
1659a6d42e7dSPeter Dunlap 	bhs	= (iscsi_data_hdr_t *)pdu->isp_hdr;
1660a6d42e7dSPeter Dunlap 	datasn	= ntohl(bhs->datasn);
1661a6d42e7dSPeter Dunlap 	offset	= ntohl(bhs->offset);
1662a6d42e7dSPeter Dunlap 
1663a6d42e7dSPeter Dunlap 	/*
1664a6d42e7dSPeter Dunlap 	 * Look up the task corresponding to the initiator task tag
1665a6d42e7dSPeter Dunlap 	 * to get the buffers affiliated with the task.
1666a6d42e7dSPeter Dunlap 	 */
1667a6d42e7dSPeter Dunlap 	idt = idm_task_find(ic, bhs->itt, bhs->ttt);
1668a6d42e7dSPeter Dunlap 	if (idt == NULL) {
1669a6d42e7dSPeter Dunlap 		IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: failed to find task");
1670a6d42e7dSPeter Dunlap 		idm_pdu_rx_protocol_error(ic, pdu);
1671a6d42e7dSPeter Dunlap 		return;
1672a6d42e7dSPeter Dunlap 	}
1673a6d42e7dSPeter Dunlap 
1674a6d42e7dSPeter Dunlap 	idb = pdu->isp_sorx_buf;
1675a6d42e7dSPeter Dunlap 	if (idb == NULL) {
1676a6d42e7dSPeter Dunlap 		IDM_CONN_LOG(CE_WARN,
1677a6d42e7dSPeter Dunlap 		    "idm_so_rx_datain: failed to find buffer");
1678a6d42e7dSPeter Dunlap 		idm_task_rele(idt);
1679a6d42e7dSPeter Dunlap 		idm_pdu_rx_protocol_error(ic, pdu);
1680a6d42e7dSPeter Dunlap 		return;
1681a6d42e7dSPeter Dunlap 	}
1682a6d42e7dSPeter Dunlap 
1683a6d42e7dSPeter Dunlap 	/*
1684a6d42e7dSPeter Dunlap 	 * DataSN values should be sequential and should not have any gaps or
1685a6d42e7dSPeter Dunlap 	 * repetitions. Check the DataSN with the one stored in the task.
1686a6d42e7dSPeter Dunlap 	 */
1687a6d42e7dSPeter Dunlap 	if (datasn == idt->idt_exp_datasn) {
1688a6d42e7dSPeter Dunlap 		idt->idt_exp_datasn++; /* keep track of DataSN received */
1689a6d42e7dSPeter Dunlap 	} else {
1690a6d42e7dSPeter Dunlap 		IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: datasn out of order");
1691a6d42e7dSPeter Dunlap 		idm_task_rele(idt);
1692a6d42e7dSPeter Dunlap 		idm_pdu_rx_protocol_error(ic, pdu);
1693a6d42e7dSPeter Dunlap 		return;
1694a6d42e7dSPeter Dunlap 	}
1695a6d42e7dSPeter Dunlap 
1696a6d42e7dSPeter Dunlap 	/*
1697a6d42e7dSPeter Dunlap 	 * PDUs in a sequence should be in continuously increasing
1698a6d42e7dSPeter Dunlap 	 * address offset
1699a6d42e7dSPeter Dunlap 	 */
1700a6d42e7dSPeter Dunlap 	if (offset != idb->idb_exp_offset) {
1701a6d42e7dSPeter Dunlap 		IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: unexpected offset");
170230e7468fSPeter Dunlap 		idm_task_rele(idt);
1703a6d42e7dSPeter Dunlap 		idm_pdu_rx_protocol_error(ic, pdu);
1704a6d42e7dSPeter Dunlap 		return;
1705a6d42e7dSPeter Dunlap 	}
1706a6d42e7dSPeter Dunlap 	/* Expected next relative buffer offset */
1707a6d42e7dSPeter Dunlap 	idb->idb_exp_offset += n2h24(bhs->dlength);
170830e7468fSPeter Dunlap 	idt->idt_rx_bytes += n2h24(bhs->dlength);
170930e7468fSPeter Dunlap 
171030e7468fSPeter Dunlap 	idm_task_rele(idt);
1711a6d42e7dSPeter Dunlap 
1712a6d42e7dSPeter Dunlap 	/*
1713a6d42e7dSPeter Dunlap 	 * For now call scsi_rsp which will process the data rsp
1714a6d42e7dSPeter Dunlap 	 * Revisit, need to provide an explicit client entry point for
1715a6d42e7dSPeter Dunlap 	 * phase collapse completions.
1716a6d42e7dSPeter Dunlap 	 */
17172727bb05STim Kordas 	if ((IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA_RSP) &&
1718a6d42e7dSPeter Dunlap 	    (idrhp->flags & ISCSI_FLAG_DATA_STATUS)) {
1719a6d42e7dSPeter Dunlap 		(*ic->ic_conn_ops.icb_rx_scsi_rsp)(ic, pdu);
1720a6d42e7dSPeter Dunlap 	}
1721a6d42e7dSPeter Dunlap 
1722a6d42e7dSPeter Dunlap 	idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
1723a6d42e7dSPeter Dunlap }
1724a6d42e7dSPeter Dunlap 
1725a6d42e7dSPeter Dunlap /*
1726a6d42e7dSPeter Dunlap  * The idm_so_rx_dataout() function is used by the iSCSI target to read
1727a6d42e7dSPeter Dunlap  * data from the Data-Out PDU sent by the iSCSI initiator.
1728a6d42e7dSPeter Dunlap  *
1729a6d42e7dSPeter Dunlap  * This function gets the Initiator Task Tag from the PDU BHS and looks up the
1730a6d42e7dSPeter Dunlap  * task to get the buffers associated with the PDU. A PDU might span buffers.
1731a6d42e7dSPeter Dunlap  * The data is then read into the respective buffer.
1732a6d42e7dSPeter Dunlap  */
1733a6d42e7dSPeter Dunlap static void
idm_so_rx_dataout(idm_conn_t * ic,idm_pdu_t * pdu)1734a6d42e7dSPeter Dunlap idm_so_rx_dataout(idm_conn_t *ic, idm_pdu_t *pdu)
1735a6d42e7dSPeter Dunlap {
1736a6d42e7dSPeter Dunlap 
1737a6d42e7dSPeter Dunlap 	iscsi_data_hdr_t	*bhs;
1738a6d42e7dSPeter Dunlap 	idm_task_t		*idt;
1739a6d42e7dSPeter Dunlap 	idm_buf_t		*idb;
1740a6d42e7dSPeter Dunlap 	size_t			offset;
1741a6d42e7dSPeter Dunlap 
1742a6d42e7dSPeter Dunlap 	ASSERT(ic != NULL);
1743a6d42e7dSPeter Dunlap 	ASSERT(pdu != NULL);
17442727bb05STim Kordas 	ASSERT(IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA);
1745a6d42e7dSPeter Dunlap 
1746a6d42e7dSPeter Dunlap 	bhs = (iscsi_data_hdr_t *)pdu->isp_hdr;
1747a6d42e7dSPeter Dunlap 	offset = ntohl(bhs->offset);
1748a6d42e7dSPeter Dunlap 
1749a6d42e7dSPeter Dunlap 	/*
1750a6d42e7dSPeter Dunlap 	 * Look up the task corresponding to the initiator task tag
1751a6d42e7dSPeter Dunlap 	 * to get the buffers affiliated with the task.
1752a6d42e7dSPeter Dunlap 	 */
1753a6d42e7dSPeter Dunlap 	idt = idm_task_find(ic, bhs->itt, bhs->ttt);
1754a6d42e7dSPeter Dunlap 	if (idt == NULL) {
1755a6d42e7dSPeter Dunlap 		IDM_CONN_LOG(CE_WARN,
1756a6d42e7dSPeter Dunlap 		    "idm_so_rx_dataout: failed to find task");
1757a6d42e7dSPeter Dunlap 		idm_pdu_rx_protocol_error(ic, pdu);
1758a6d42e7dSPeter Dunlap 		return;
1759a6d42e7dSPeter Dunlap 	}
1760a6d42e7dSPeter Dunlap 
1761a6d42e7dSPeter Dunlap 	idb = pdu->isp_sorx_buf;
1762a6d42e7dSPeter Dunlap 	if (idb == NULL) {
1763a6d42e7dSPeter Dunlap 		IDM_CONN_LOG(CE_WARN,
1764a6d42e7dSPeter Dunlap 		    "idm_so_rx_dataout: failed to find buffer");
1765a6d42e7dSPeter Dunlap 		idm_task_rele(idt);
1766a6d42e7dSPeter Dunlap 		idm_pdu_rx_protocol_error(ic, pdu);
1767a6d42e7dSPeter Dunlap 		return;
1768a6d42e7dSPeter Dunlap 	}
1769a6d42e7dSPeter Dunlap 
1770a6d42e7dSPeter Dunlap 	/* Keep track of data transferred - check data offsets */
1771a6d42e7dSPeter Dunlap 	if (offset != idb->idb_exp_offset) {
1772a6d42e7dSPeter Dunlap 		IDM_CONN_LOG(CE_NOTE, "idm_so_rx_dataout: offset out of seq: "
1773a6d42e7dSPeter Dunlap 		    "%ld, %d", offset, idb->idb_exp_offset);
1774a6d42e7dSPeter Dunlap 		idm_task_rele(idt);
1775a6d42e7dSPeter Dunlap 		idm_pdu_rx_protocol_error(ic, pdu);
1776a6d42e7dSPeter Dunlap 		return;
1777a6d42e7dSPeter Dunlap 	}
1778a6d42e7dSPeter Dunlap 	/* Expected next relative offset */
1779a6d42e7dSPeter Dunlap 	idb->idb_exp_offset += ntoh24(bhs->dlength);
178030e7468fSPeter Dunlap 	idt->idt_rx_bytes += n2h24(bhs->dlength);
1781a6d42e7dSPeter Dunlap 
1782a6d42e7dSPeter Dunlap 	/*
1783a6d42e7dSPeter Dunlap 	 * Call the buffer callback when the transfer is complete
1784a6d42e7dSPeter Dunlap 	 *
1785a6d42e7dSPeter Dunlap 	 * The connection state machine should only abort tasks after
1786a6d42e7dSPeter Dunlap 	 * shutting down the connection so we are assured that there
1787a6d42e7dSPeter Dunlap 	 * won't be a simultaneous attempt to abort this task at the
1788a6d42e7dSPeter Dunlap 	 * same time as we are processing this PDU (due to a connection
1789a6d42e7dSPeter Dunlap 	 * state change).
1790a6d42e7dSPeter Dunlap 	 */
1791a6d42e7dSPeter Dunlap 	if (bhs->flags & ISCSI_FLAG_FINAL) {
17922727bb05STim Kordas 		/*
17932727bb05STim Kordas 		 * We have gotten the last data-message for the current
17942727bb05STim Kordas 		 * transfer.  idb_xfer_len represents the data that the
17952727bb05STim Kordas 		 * command intended to transfer, it does not represent the
17962727bb05STim Kordas 		 * actual number of bytes transferred. If we have not
17972727bb05STim Kordas 		 * transferred the expected number of bytes something is
17982727bb05STim Kordas 		 * wrong.
17992727bb05STim Kordas 		 *
18002727bb05STim Kordas 		 * We have two options, when there is a mismatch, we can
18012727bb05STim Kordas 		 * regard the transfer as invalid -- or we can modify our
18022727bb05STim Kordas 		 * notion of "xfer_len." In order to be as stringent as
18032727bb05STim Kordas 		 * possible, here we regard this transfer as in error; and
18042727bb05STim Kordas 		 * bail out.
18052727bb05STim Kordas 		 */
18062727bb05STim Kordas 		if (idb->idb_buflen == idb->idb_xfer_len &&
18072727bb05STim Kordas 		    idb->idb_buflen !=
18082727bb05STim Kordas 		    (idb->idb_exp_offset - idb->idb_bufoffset)) {
18092727bb05STim Kordas 			printf("idm_so_rx_dataout: incomplete transfer, "
18102727bb05STim Kordas 			    "protocol err");
18112727bb05STim Kordas 			IDM_CONN_LOG(CE_NOTE,
18122727bb05STim Kordas 			    "idm_so_rx_dataout: incomplete transfer: %ld, %d",
18132727bb05STim Kordas 			    offset, (int)(idb->idb_exp_offset - offset));
18142727bb05STim Kordas 			idm_task_rele(idt);
18152727bb05STim Kordas 			idm_pdu_rx_protocol_error(ic, pdu);
18162727bb05STim Kordas 			return;
18172727bb05STim Kordas 		}
1818a6d42e7dSPeter Dunlap 		/*
1819a6d42e7dSPeter Dunlap 		 * We only want to call idm_buf_rx_from_ini_done once
1820a6d42e7dSPeter Dunlap 		 * per transfer.  It's possible that this task has
1821a6d42e7dSPeter Dunlap 		 * already been aborted in which case
1822a6d42e7dSPeter Dunlap 		 * idm_so_free_task_rsrc will call idm_buf_rx_from_ini_done
1823a6d42e7dSPeter Dunlap 		 * for each buffer with idb_in_transport==B_TRUE.  To
1824a6d42e7dSPeter Dunlap 		 * close this window and ensure that this doesn't happen,
1825a6d42e7dSPeter Dunlap 		 * we'll clear idb->idb_in_transport now while holding
1826a6d42e7dSPeter Dunlap 		 * the task mutex.   This is only really an issue for
1827a6d42e7dSPeter Dunlap 		 * SCSI task abort -- if tasks were being aborted because
1828a6d42e7dSPeter Dunlap 		 * of a connection state change the state machine would
1829a6d42e7dSPeter Dunlap 		 * have already stopped the receive thread.
1830a6d42e7dSPeter Dunlap 		 */
1831a6d42e7dSPeter Dunlap 		mutex_enter(&idt->idt_mutex);
1832a6d42e7dSPeter Dunlap 
1833a6d42e7dSPeter Dunlap 		/*
1834a6d42e7dSPeter Dunlap 		 * Release the task hold here (obtained in idm_task_find)
1835a6d42e7dSPeter Dunlap 		 * because the task may complete synchronously during
1836a6d42e7dSPeter Dunlap 		 * idm_buf_rx_from_ini_done.  Since we still have an active
1837a6d42e7dSPeter Dunlap 		 * buffer we know there is at least one additional hold on idt.
1838a6d42e7dSPeter Dunlap 		 */
1839a6d42e7dSPeter Dunlap 		idm_task_rele(idt);
1840a6d42e7dSPeter Dunlap 
1841a6d42e7dSPeter Dunlap 		/*
1842a6d42e7dSPeter Dunlap 		 * idm_buf_rx_from_ini_done releases idt->idt_mutex
1843a6d42e7dSPeter Dunlap 		 */
1844a668b114SPriya Krishnan 		DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic,
1845a668b114SPriya Krishnan 		    uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset,
1846a668b114SPriya Krishnan 		    uint64_t, 0, uint32_t, 0, uint32_t, 0,
1847a668b114SPriya Krishnan 		    uint32_t, idb->idb_xfer_len,
1848a668b114SPriya Krishnan 		    int, XFER_BUF_RX_FROM_INI);
1849a6d42e7dSPeter Dunlap 		idm_buf_rx_from_ini_done(idt, idb, IDM_STATUS_SUCCESS);
1850a6d42e7dSPeter Dunlap 		idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
1851a6d42e7dSPeter Dunlap 		return;
1852a6d42e7dSPeter Dunlap 	}
1853a6d42e7dSPeter Dunlap 
1854a6d42e7dSPeter Dunlap 	idm_task_rele(idt);
1855a6d42e7dSPeter Dunlap 	idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
1856a6d42e7dSPeter Dunlap }
1857a6d42e7dSPeter Dunlap 
1858a6d42e7dSPeter Dunlap /*
1859a6d42e7dSPeter Dunlap  * The idm_so_rx_rtt() function is used by the iSCSI initiator to handle
1860a6d42e7dSPeter Dunlap  * the R2T PDU sent by the iSCSI target indicating that it is ready to
1861a6d42e7dSPeter Dunlap  * accept data. This gets the Initiator Task Tag (itt) from the PDU BHS
1862a6d42e7dSPeter Dunlap  * and looks up the task in the task tree using the itt to get the output
1863a6d42e7dSPeter Dunlap  * buffers associated the task. The R2T PDU contains the offset of the
1864a6d42e7dSPeter Dunlap  * requested data and the data length. This function then constructs a
1865a6d42e7dSPeter Dunlap  * sequence of iSCSI PDUs and outputs the requested data. Each Data-Out
1866a6d42e7dSPeter Dunlap  * PDU is associated with the R2T by the Target Transfer Tag  (ttt).
1867a6d42e7dSPeter Dunlap  */
186830e7468fSPeter Dunlap 
1869a6d42e7dSPeter Dunlap static void
idm_so_rx_rtt(idm_conn_t * ic,idm_pdu_t * pdu)1870a6d42e7dSPeter Dunlap idm_so_rx_rtt(idm_conn_t *ic, idm_pdu_t *pdu)
1871a6d42e7dSPeter Dunlap {
1872a6d42e7dSPeter Dunlap 	idm_task_t		*idt;
1873a6d42e7dSPeter Dunlap 	idm_buf_t		*idb;
1874a6d42e7dSPeter Dunlap 	iscsi_rtt_hdr_t		*rtt_hdr;
1875a6d42e7dSPeter Dunlap 	uint32_t		data_offset;
187630e7468fSPeter Dunlap 	uint32_t		data_length;
1877a6d42e7dSPeter Dunlap 
1878a6d42e7dSPeter Dunlap 	ASSERT(ic != NULL);
1879a6d42e7dSPeter Dunlap 	ASSERT(pdu != NULL);
1880a6d42e7dSPeter Dunlap 
1881a6d42e7dSPeter Dunlap 	rtt_hdr	= (iscsi_rtt_hdr_t *)pdu->isp_hdr;
1882a6d42e7dSPeter Dunlap 	data_offset = ntohl(rtt_hdr->data_offset);
188330e7468fSPeter Dunlap 	data_length = ntohl(rtt_hdr->data_length);
1884a6d42e7dSPeter Dunlap 	idt	= idm_task_find(ic, rtt_hdr->itt, rtt_hdr->ttt);
1885a6d42e7dSPeter Dunlap 
1886a6d42e7dSPeter Dunlap 	if (idt == NULL) {
1887a6d42e7dSPeter Dunlap 		IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: could not find task");
1888a6d42e7dSPeter Dunlap 		idm_pdu_rx_protocol_error(ic, pdu);
1889a6d42e7dSPeter Dunlap 		return;
1890a6d42e7dSPeter Dunlap 	}
1891a6d42e7dSPeter Dunlap 
1892a6d42e7dSPeter Dunlap 	/* Find the buffer bound to the task by the iSCSI initiator */
1893a6d42e7dSPeter Dunlap 	mutex_enter(&idt->idt_mutex);
1894a6d42e7dSPeter Dunlap 	idb = idm_buf_find(&idt->idt_outbufv, data_offset);
1895a6d42e7dSPeter Dunlap 	if (idb == NULL) {
1896a6d42e7dSPeter Dunlap 		mutex_exit(&idt->idt_mutex);
1897a6d42e7dSPeter Dunlap 		idm_task_rele(idt);
1898a6d42e7dSPeter Dunlap 		IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: could not find buffer");
1899a6d42e7dSPeter Dunlap 		idm_pdu_rx_protocol_error(ic, pdu);
1900a6d42e7dSPeter Dunlap 		return;
1901a6d42e7dSPeter Dunlap 	}
1902a6d42e7dSPeter Dunlap 
190330e7468fSPeter Dunlap 	/* return buffer contains this data */
190430e7468fSPeter Dunlap 	if (data_offset + data_length > idb->idb_buflen) {
190530e7468fSPeter Dunlap 		/* Overflow */
190630e7468fSPeter Dunlap 		mutex_exit(&idt->idt_mutex);
190730e7468fSPeter Dunlap 		idm_task_rele(idt);
190830e7468fSPeter Dunlap 		IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: read from outside "
190930e7468fSPeter Dunlap 		    "buffer");
191030e7468fSPeter Dunlap 		idm_pdu_rx_protocol_error(ic, pdu);
191130e7468fSPeter Dunlap 		return;
191230e7468fSPeter Dunlap 	}
191330e7468fSPeter Dunlap 
191430e7468fSPeter Dunlap 	idt->idt_r2t_ttt = rtt_hdr->ttt;
191530e7468fSPeter Dunlap 	idt->idt_exp_datasn = 0;
191630e7468fSPeter Dunlap 
191730e7468fSPeter Dunlap 	idm_so_send_rtt_data(ic, idt, idb, data_offset,
191830e7468fSPeter Dunlap 	    ntohl(rtt_hdr->data_length));
1919c158b55cSJack Meng 	/*
1920c158b55cSJack Meng 	 * the idt_mutex is released in idm_so_send_rtt_data
1921c158b55cSJack Meng 	 */
1922a6d42e7dSPeter Dunlap 
1923a6d42e7dSPeter Dunlap 	idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
1924a6d42e7dSPeter Dunlap 	idm_task_rele(idt);
1925a6d42e7dSPeter Dunlap 
1926a6d42e7dSPeter Dunlap }
1927a6d42e7dSPeter Dunlap 
1928a6d42e7dSPeter Dunlap idm_status_t
idm_sorecvdata(idm_conn_t * ic,idm_pdu_t * pdu)1929a6d42e7dSPeter Dunlap idm_sorecvdata(idm_conn_t *ic, idm_pdu_t *pdu)
1930a6d42e7dSPeter Dunlap {
1931a6d42e7dSPeter Dunlap 	uint8_t		pad[ISCSI_PAD_WORD_LEN];
1932a6d42e7dSPeter Dunlap 	int		pad_len;
1933a6d42e7dSPeter Dunlap 	uint32_t	data_digest_crc;
1934a6d42e7dSPeter Dunlap 	uint32_t	crc_calculated;
1935a6d42e7dSPeter Dunlap 	int		total_len;
1936a6d42e7dSPeter Dunlap 	idm_so_conn_t	*so_conn;
1937a6d42e7dSPeter Dunlap 
1938a6d42e7dSPeter Dunlap 	so_conn = ic->ic_transport_private;
1939a6d42e7dSPeter Dunlap 
1940a6d42e7dSPeter Dunlap 	pad_len = ((ISCSI_PAD_WORD_LEN -
1941a6d42e7dSPeter Dunlap 	    (pdu->isp_datalen & (ISCSI_PAD_WORD_LEN - 1))) &
1942a6d42e7dSPeter Dunlap 	    (ISCSI_PAD_WORD_LEN - 1));
1943a6d42e7dSPeter Dunlap 
1944a6d42e7dSPeter Dunlap 	ASSERT(pdu->isp_iovlen < (PDU_MAX_IOVLEN - 2)); /* pad + data digest */
1945a6d42e7dSPeter Dunlap 
1946a6d42e7dSPeter Dunlap 	total_len = pdu->isp_datalen;
1947a6d42e7dSPeter Dunlap 
1948a6d42e7dSPeter Dunlap 	if (pad_len) {
1949a6d42e7dSPeter Dunlap 		pdu->isp_iov[pdu->isp_iovlen].iov_base	= (char *)&pad;
1950a6d42e7dSPeter Dunlap 		pdu->isp_iov[pdu->isp_iovlen].iov_len	= pad_len;
1951a6d42e7dSPeter Dunlap 		total_len		+= pad_len;
1952a6d42e7dSPeter Dunlap 		pdu->isp_iovlen++;
1953a6d42e7dSPeter Dunlap 	}
1954a6d42e7dSPeter Dunlap 
1955a6d42e7dSPeter Dunlap 	/* setup data digest */
1956a6d42e7dSPeter Dunlap 	if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) != 0) {
1957a6d42e7dSPeter Dunlap 		pdu->isp_iov[pdu->isp_iovlen].iov_base =
1958a6d42e7dSPeter Dunlap 		    (char *)&data_digest_crc;
1959a6d42e7dSPeter Dunlap 		pdu->isp_iov[pdu->isp_iovlen].iov_len =
1960a6d42e7dSPeter Dunlap 		    sizeof (data_digest_crc);
1961a6d42e7dSPeter Dunlap 		total_len		+= sizeof (data_digest_crc);
1962a6d42e7dSPeter Dunlap 		pdu->isp_iovlen++;
1963a6d42e7dSPeter Dunlap 	}
1964a6d42e7dSPeter Dunlap 
196530e7468fSPeter Dunlap 	pdu->isp_data = (uint8_t *)(uintptr_t)pdu->isp_iov[0].iov_base;
196630e7468fSPeter Dunlap 
1967a6d42e7dSPeter Dunlap 	if (idm_iov_sorecv(so_conn->ic_so, &pdu->isp_iov[0],
1968a6d42e7dSPeter Dunlap 	    pdu->isp_iovlen, total_len) != 0) {
1969a6d42e7dSPeter Dunlap 		return (IDM_STATUS_IO);
1970a6d42e7dSPeter Dunlap 	}
1971a6d42e7dSPeter Dunlap 
1972a6d42e7dSPeter Dunlap 	if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) != 0) {
1973a6d42e7dSPeter Dunlap 		crc_calculated = idm_crc32c(pdu->isp_data,
1974a6d42e7dSPeter Dunlap 		    pdu->isp_datalen);
1975a6d42e7dSPeter Dunlap 		if (pad_len) {
1976a6d42e7dSPeter Dunlap 			crc_calculated = idm_crc32c_continued((char *)&pad,
1977a6d42e7dSPeter Dunlap 			    pad_len, crc_calculated);
1978a6d42e7dSPeter Dunlap 		}
1979a6d42e7dSPeter Dunlap 		if (crc_calculated != data_digest_crc) {
1980a6d42e7dSPeter Dunlap 			IDM_CONN_LOG(CE_WARN,
1981a6d42e7dSPeter Dunlap 			    "idm_sorecvdata: "
1982a6d42e7dSPeter Dunlap 			    "CRC error: actual 0x%x, calc 0x%x",
1983a6d42e7dSPeter Dunlap 			    data_digest_crc, crc_calculated);
1984a6d42e7dSPeter Dunlap 
1985a6d42e7dSPeter Dunlap 			/* Invalid Data Digest */
1986a6d42e7dSPeter Dunlap 			return (IDM_STATUS_DATA_DIGEST);
1987a6d42e7dSPeter Dunlap 		}
1988a6d42e7dSPeter Dunlap 	}
1989a6d42e7dSPeter Dunlap 
1990a6d42e7dSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
1991a6d42e7dSPeter Dunlap }
1992a6d42e7dSPeter Dunlap 
1993a6d42e7dSPeter Dunlap /*
1994a6d42e7dSPeter Dunlap  * idm_sorecv_scsidata() is used to receive scsi data from the socket. The
1995a6d42e7dSPeter Dunlap  * Data-type PDU header must be read into the idm_pdu_t structure prior to
1996a6d42e7dSPeter Dunlap  * calling this function.
1997a6d42e7dSPeter Dunlap  */
1998a6d42e7dSPeter Dunlap idm_status_t
idm_sorecv_scsidata(idm_conn_t * ic,idm_pdu_t * pdu)1999a6d42e7dSPeter Dunlap idm_sorecv_scsidata(idm_conn_t *ic, idm_pdu_t *pdu)
2000a6d42e7dSPeter Dunlap {
2001a6d42e7dSPeter Dunlap 	iscsi_data_hdr_t	*bhs;
2002a6d42e7dSPeter Dunlap 	idm_task_t		*task;
2003a6d42e7dSPeter Dunlap 	uint32_t		offset;
2004a6d42e7dSPeter Dunlap 	uint8_t			opcode;
2005a6d42e7dSPeter Dunlap 	uint32_t		dlength;
2006a6d42e7dSPeter Dunlap 	list_t			*buflst;
2007a6d42e7dSPeter Dunlap 	uint32_t		xfer_bytes;
2008a6d42e7dSPeter Dunlap 	idm_status_t		status;
2009a6d42e7dSPeter Dunlap 
2010a6d42e7dSPeter Dunlap 	ASSERT(ic != NULL);
2011a6d42e7dSPeter Dunlap 	ASSERT(pdu != NULL);
2012a6d42e7dSPeter Dunlap 
2013a6d42e7dSPeter Dunlap 	bhs	= (iscsi_data_hdr_t *)pdu->isp_hdr;
2014a6d42e7dSPeter Dunlap 
2015a6d42e7dSPeter Dunlap 	offset	= ntohl(bhs->offset);
20162727bb05STim Kordas 	opcode	= IDM_PDU_OPCODE(pdu);
2017a6d42e7dSPeter Dunlap 	dlength = n2h24(bhs->dlength);
2018a6d42e7dSPeter Dunlap 
2019a6d42e7dSPeter Dunlap 	ASSERT((opcode == ISCSI_OP_SCSI_DATA_RSP) ||
2020a6d42e7dSPeter Dunlap 	    (opcode == ISCSI_OP_SCSI_DATA));
2021a6d42e7dSPeter Dunlap 
2022a6d42e7dSPeter Dunlap 	/*
2023a6d42e7dSPeter Dunlap 	 * Successful lookup implicitly gets a "hold" on the task.  This
2024a6d42e7dSPeter Dunlap 	 * hold must be released before leaving this function.  At one
2025a6d42e7dSPeter Dunlap 	 * point we were caching this task context and retaining the hold
2026a6d42e7dSPeter Dunlap 	 * but it turned out to be very difficult to release the hold properly.
2027a6d42e7dSPeter Dunlap 	 * The task can be aborted and the connection shutdown between this
2028a6d42e7dSPeter Dunlap 	 * call and the subsequent expected call to idm_so_rx_datain/
2029a6d42e7dSPeter Dunlap 	 * idm_so_rx_dataout (in which case those functions are not called).
2030a6d42e7dSPeter Dunlap 	 * Releasing the hold in the PDU callback doesn't work well either
2031a6d42e7dSPeter Dunlap 	 * because the whole task may be completed by then at which point
2032a6d42e7dSPeter Dunlap 	 * it is too late to release the hold -- for better or worse this
2033a6d42e7dSPeter Dunlap 	 * code doesn't wait on the refcnts during normal operation.
2034a6d42e7dSPeter Dunlap 	 * idm_task_find() is very fast and it is not a huge burden if we
2035a6d42e7dSPeter Dunlap 	 * have to do it twice.
2036a6d42e7dSPeter Dunlap 	 */
2037a6d42e7dSPeter Dunlap 	task = idm_task_find(ic, bhs->itt, bhs->ttt);
2038a6d42e7dSPeter Dunlap 	if (task == NULL) {
2039a6d42e7dSPeter Dunlap 		IDM_CONN_LOG(CE_WARN,
2040a6d42e7dSPeter Dunlap 		    "idm_sorecv_scsidata: could not find task");
2041a6d42e7dSPeter Dunlap 		return (IDM_STATUS_FAIL);
2042a6d42e7dSPeter Dunlap 	}
2043a6d42e7dSPeter Dunlap 
2044a6d42e7dSPeter Dunlap 	mutex_enter(&task->idt_mutex);
2045a6d42e7dSPeter Dunlap 	buflst	= (opcode == ISCSI_OP_SCSI_DATA_RSP) ?
2046a6d42e7dSPeter Dunlap 	    &task->idt_inbufv : &task->idt_outbufv;
2047a6d42e7dSPeter Dunlap 	pdu->isp_sorx_buf = idm_buf_find(buflst, offset);
2048a6d42e7dSPeter Dunlap 	mutex_exit(&task->idt_mutex);
2049a6d42e7dSPeter Dunlap 
2050a6d42e7dSPeter Dunlap 	if (pdu->isp_sorx_buf == NULL) {
2051a6d42e7dSPeter Dunlap 		idm_task_rele(task);
2052a6d42e7dSPeter Dunlap 		IDM_CONN_LOG(CE_WARN, "idm_sorecv_scsidata: could not find "
2053a6d42e7dSPeter Dunlap 		    "buffer for offset %x opcode=%x",
2054a6d42e7dSPeter Dunlap 		    offset, opcode);
2055a6d42e7dSPeter Dunlap 		return (IDM_STATUS_FAIL);
2056a6d42e7dSPeter Dunlap 	}
2057a6d42e7dSPeter Dunlap 
2058a6d42e7dSPeter Dunlap 	xfer_bytes = idm_fill_iov(pdu, pdu->isp_sorx_buf, offset, dlength);
2059a6d42e7dSPeter Dunlap 	ASSERT(xfer_bytes != 0);
2060a6d42e7dSPeter Dunlap 	if (xfer_bytes != dlength) {
2061a6d42e7dSPeter Dunlap 		idm_task_rele(task);
2062a6d42e7dSPeter Dunlap 		/*
2063a6d42e7dSPeter Dunlap 		 * Buffer overflow, connection error.  The PDU data is still
2064a6d42e7dSPeter Dunlap 		 * sitting in the socket so we can't use the connection
2065a6d42e7dSPeter Dunlap 		 * again until that data is drained.
2066a6d42e7dSPeter Dunlap 		 */
2067a6d42e7dSPeter Dunlap 		return (IDM_STATUS_FAIL);
2068a6d42e7dSPeter Dunlap 	}
2069a6d42e7dSPeter Dunlap 
2070a6d42e7dSPeter Dunlap 	status = idm_sorecvdata(ic, pdu);
2071a6d42e7dSPeter Dunlap 
2072a6d42e7dSPeter Dunlap 	idm_task_rele(task);
2073a6d42e7dSPeter Dunlap 
2074a6d42e7dSPeter Dunlap 	return (status);
2075a6d42e7dSPeter Dunlap }
2076a6d42e7dSPeter Dunlap 
2077a6d42e7dSPeter Dunlap static uint32_t
idm_fill_iov(idm_pdu_t * pdu,idm_buf_t * idb,uint32_t ro,uint32_t dlength)2078a6d42e7dSPeter Dunlap idm_fill_iov(idm_pdu_t *pdu, idm_buf_t *idb, uint32_t ro, uint32_t dlength)
2079a6d42e7dSPeter Dunlap {
2080a6d42e7dSPeter Dunlap 	uint32_t	buf_ro = ro - idb->idb_bufoffset;
2081a6d42e7dSPeter Dunlap 	uint32_t	xfer_len = min(dlength, idb->idb_buflen - buf_ro);
2082a6d42e7dSPeter Dunlap 
2083a6d42e7dSPeter Dunlap 	ASSERT(ro >= idb->idb_bufoffset);
2084a6d42e7dSPeter Dunlap 
2085a6d42e7dSPeter Dunlap 	pdu->isp_iov[pdu->isp_iovlen].iov_base	=
2086a6d42e7dSPeter Dunlap 	    (caddr_t)idb->idb_buf + buf_ro;
2087a6d42e7dSPeter Dunlap 	pdu->isp_iov[pdu->isp_iovlen].iov_len	= xfer_len;
2088a6d42e7dSPeter Dunlap 	pdu->isp_iovlen++;
2089a6d42e7dSPeter Dunlap 
2090a6d42e7dSPeter Dunlap 	return (xfer_len);
2091a6d42e7dSPeter Dunlap }
2092a6d42e7dSPeter Dunlap 
2093a6d42e7dSPeter Dunlap int
idm_sorecv_nonscsidata(idm_conn_t * ic,idm_pdu_t * pdu)2094a6d42e7dSPeter Dunlap idm_sorecv_nonscsidata(idm_conn_t *ic, idm_pdu_t *pdu)
2095a6d42e7dSPeter Dunlap {
2096a6d42e7dSPeter Dunlap 	pdu->isp_data = kmem_alloc(pdu->isp_datalen, KM_SLEEP);
2097a6d42e7dSPeter Dunlap 	ASSERT(pdu->isp_data != NULL);
2098a6d42e7dSPeter Dunlap 
2099a6d42e7dSPeter Dunlap 	pdu->isp_databuflen = pdu->isp_datalen;
2100a6d42e7dSPeter Dunlap 	pdu->isp_iov[0].iov_base = (caddr_t)pdu->isp_data;
2101a6d42e7dSPeter Dunlap 	pdu->isp_iov[0].iov_len = pdu->isp_datalen;
2102a6d42e7dSPeter Dunlap 	pdu->isp_iovlen = 1;
2103a6d42e7dSPeter Dunlap 	/*
2104a6d42e7dSPeter Dunlap 	 * Since we are associating a new data buffer with this received
2105a6d42e7dSPeter Dunlap 	 * PDU we need to set a specific callback to free the data
2106a6d42e7dSPeter Dunlap 	 * after the PDU is processed.
2107a6d42e7dSPeter Dunlap 	 */
2108a6d42e7dSPeter Dunlap 	pdu->isp_flags |= IDM_PDU_ADDL_DATA;
2109a6d42e7dSPeter Dunlap 	pdu->isp_callback = idm_sorx_addl_pdu_cb;
2110a6d42e7dSPeter Dunlap 
2111a6d42e7dSPeter Dunlap 	return (idm_sorecvdata(ic, pdu));
2112a6d42e7dSPeter Dunlap }
2113a6d42e7dSPeter Dunlap 
2114a6d42e7dSPeter Dunlap void
idm_sorx_thread(void * arg)2115a6d42e7dSPeter Dunlap idm_sorx_thread(void *arg)
2116a6d42e7dSPeter Dunlap {
2117a6d42e7dSPeter Dunlap 	boolean_t	conn_failure = B_FALSE;
2118a6d42e7dSPeter Dunlap 	idm_conn_t	*ic = (idm_conn_t *)arg;
2119a6d42e7dSPeter Dunlap 	idm_so_conn_t	*so_conn;
2120a6d42e7dSPeter Dunlap 	idm_pdu_t	*pdu;
2121a6d42e7dSPeter Dunlap 	idm_status_t	rc;
2122a6d42e7dSPeter Dunlap 
2123a6d42e7dSPeter Dunlap 	idm_conn_hold(ic);
2124a6d42e7dSPeter Dunlap 
2125a6d42e7dSPeter Dunlap 	mutex_enter(&ic->ic_mutex);
2126a6d42e7dSPeter Dunlap 
2127a6d42e7dSPeter Dunlap 	so_conn = ic->ic_transport_private;
2128a6d42e7dSPeter Dunlap 	so_conn->ic_rx_thread_running = B_TRUE;
2129a6d42e7dSPeter Dunlap 	so_conn->ic_rx_thread_did = so_conn->ic_rx_thread->t_did;
2130a6d42e7dSPeter Dunlap 	cv_signal(&ic->ic_cv);
2131a6d42e7dSPeter Dunlap 
2132a6d42e7dSPeter Dunlap 	while (so_conn->ic_rx_thread_running) {
2133a6d42e7dSPeter Dunlap 		mutex_exit(&ic->ic_mutex);
2134a6d42e7dSPeter Dunlap 
2135a6d42e7dSPeter Dunlap 		/*
2136a6d42e7dSPeter Dunlap 		 * Get PDU with default header size (large enough for
2137a6d42e7dSPeter Dunlap 		 * BHS plus any anticipated AHS).  PDU from
2138a6d42e7dSPeter Dunlap 		 * the cache will have all values set correctly
2139a6d42e7dSPeter Dunlap 		 * for sockets RX including callback.
2140a6d42e7dSPeter Dunlap 		 */
2141a6d42e7dSPeter Dunlap 		pdu = kmem_cache_alloc(idm.idm_sorx_pdu_cache, KM_SLEEP);
2142a6d42e7dSPeter Dunlap 		pdu->isp_ic = ic;
2143a6d42e7dSPeter Dunlap 		pdu->isp_flags = 0;
2144a6d42e7dSPeter Dunlap 		pdu->isp_transport_hdrlen = 0;
2145a6d42e7dSPeter Dunlap 
2146a6d42e7dSPeter Dunlap 		if ((rc = idm_sorecvhdr(ic, pdu)) != 0) {
2147a6d42e7dSPeter Dunlap 			/*
2148a6d42e7dSPeter Dunlap 			 * Call idm_pdu_complete so that we call the callback
2149a6d42e7dSPeter Dunlap 			 * and ensure any memory allocated in idm_sorecvhdr
2150a6d42e7dSPeter Dunlap 			 * gets freed up.
2151a6d42e7dSPeter Dunlap 			 */
2152a6d42e7dSPeter Dunlap 			idm_pdu_complete(pdu, IDM_STATUS_FAIL);
2153a6d42e7dSPeter Dunlap 
2154a6d42e7dSPeter Dunlap 			/*
2155a6d42e7dSPeter Dunlap 			 * If ic_rx_thread_running is still set then
2156a6d42e7dSPeter Dunlap 			 * this is some kind of connection problem
2157a6d42e7dSPeter Dunlap 			 * on the socket.  In this case we want to
2158a6d42e7dSPeter Dunlap 			 * generate an event.  Otherwise some other
2159a6d42e7dSPeter Dunlap 			 * thread closed the socket due to another
2160a6d42e7dSPeter Dunlap 			 * issue in which case we don't need to
2161a6d42e7dSPeter Dunlap 			 * generate an event.
2162a6d42e7dSPeter Dunlap 			 */
2163a6d42e7dSPeter Dunlap 			mutex_enter(&ic->ic_mutex);
2164a6d42e7dSPeter Dunlap 			if (so_conn->ic_rx_thread_running) {
2165a6d42e7dSPeter Dunlap 				conn_failure = B_TRUE;
2166a6d42e7dSPeter Dunlap 				so_conn->ic_rx_thread_running = B_FALSE;
2167a6d42e7dSPeter Dunlap 			}
2168a6d42e7dSPeter Dunlap 
2169a6d42e7dSPeter Dunlap 			continue;
2170a6d42e7dSPeter Dunlap 		}
2171a6d42e7dSPeter Dunlap 
2172a6d42e7dSPeter Dunlap 		/*
2173a6d42e7dSPeter Dunlap 		 * Header has been read and validated.  Now we need
2174a6d42e7dSPeter Dunlap 		 * to read the PDU data payload (if present).  SCSI data
2175a6d42e7dSPeter Dunlap 		 * need to be transferred from the socket directly into
2176a6d42e7dSPeter Dunlap 		 * the associated transfer buffer for the SCSI task.
2177a6d42e7dSPeter Dunlap 		 */
2178a6d42e7dSPeter Dunlap 		if (pdu->isp_datalen != 0) {
2179a6d42e7dSPeter Dunlap 			if ((IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA) ||
2180a6d42e7dSPeter Dunlap 			    (IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA_RSP)) {
2181a6d42e7dSPeter Dunlap 				rc = idm_sorecv_scsidata(ic, pdu);
2182a6d42e7dSPeter Dunlap 				/*
2183a6d42e7dSPeter Dunlap 				 * All SCSI errors are fatal to the
2184a6d42e7dSPeter Dunlap 				 * connection right now since we have no
2185a6d42e7dSPeter Dunlap 				 * place to put the data.  What we need
2186a6d42e7dSPeter Dunlap 				 * is some kind of sink to dispose of unwanted
2187a6d42e7dSPeter Dunlap 				 * SCSI data.  For example an invalid task tag
2188a6d42e7dSPeter Dunlap 				 * should not kill the connection (although
2189a6d42e7dSPeter Dunlap 				 * we may want to drop the connection).
2190a6d42e7dSPeter Dunlap 				 */
2191a6d42e7dSPeter Dunlap 			} else {
2192a6d42e7dSPeter Dunlap 				/*
2193a6d42e7dSPeter Dunlap 				 * Not data PDUs so allocate a buffer for the
2194a6d42e7dSPeter Dunlap 				 * data segment and read the remaining data.
2195a6d42e7dSPeter Dunlap 				 */
2196a6d42e7dSPeter Dunlap 				rc = idm_sorecv_nonscsidata(ic, pdu);
2197a6d42e7dSPeter Dunlap 			}
2198a6d42e7dSPeter Dunlap 			if (rc != 0) {
2199a6d42e7dSPeter Dunlap 				/*
2200a6d42e7dSPeter Dunlap 				 * Call idm_pdu_complete so that we call the
2201a6d42e7dSPeter Dunlap 				 * callback and ensure any memory allocated
2202a6d42e7dSPeter Dunlap 				 * in idm_sorecvhdr gets freed up.
2203a6d42e7dSPeter Dunlap 				 */
2204a6d42e7dSPeter Dunlap 				idm_pdu_complete(pdu, IDM_STATUS_FAIL);
2205a6d42e7dSPeter Dunlap 
2206a6d42e7dSPeter Dunlap 				/*
2207a6d42e7dSPeter Dunlap 				 * If ic_rx_thread_running is still set then
2208a6d42e7dSPeter Dunlap 				 * this is some kind of connection problem
2209a6d42e7dSPeter Dunlap 				 * on the socket.  In this case we want to
2210a6d42e7dSPeter Dunlap 				 * generate an event.  Otherwise some other
2211a6d42e7dSPeter Dunlap 				 * thread closed the socket due to another
2212a6d42e7dSPeter Dunlap 				 * issue in which case we don't need to
2213a6d42e7dSPeter Dunlap 				 * generate an event.
2214a6d42e7dSPeter Dunlap 				 */
2215a6d42e7dSPeter Dunlap 				mutex_enter(&ic->ic_mutex);
2216a6d42e7dSPeter Dunlap 				if (so_conn->ic_rx_thread_running) {
2217a6d42e7dSPeter Dunlap 					conn_failure = B_TRUE;
2218a6d42e7dSPeter Dunlap 					so_conn->ic_rx_thread_running = B_FALSE;
2219a6d42e7dSPeter Dunlap 				}
2220a6d42e7dSPeter Dunlap 				continue;
2221a6d42e7dSPeter Dunlap 			}
2222a6d42e7dSPeter Dunlap 		}
2223a6d42e7dSPeter Dunlap 
2224a6d42e7dSPeter Dunlap 		/*
2225a6d42e7dSPeter Dunlap 		 * Process RX PDU
2226a6d42e7dSPeter Dunlap 		 */
2227a6d42e7dSPeter Dunlap 		idm_pdu_rx(ic, pdu);
2228a6d42e7dSPeter Dunlap 
2229a6d42e7dSPeter Dunlap 		mutex_enter(&ic->ic_mutex);
2230a6d42e7dSPeter Dunlap 	}
2231a6d42e7dSPeter Dunlap 
2232a6d42e7dSPeter Dunlap 	mutex_exit(&ic->ic_mutex);
2233a6d42e7dSPeter Dunlap 
2234a6d42e7dSPeter Dunlap 	/*
2235a6d42e7dSPeter Dunlap 	 * If we dropped out of the RX processing loop because of
2236a6d42e7dSPeter Dunlap 	 * a socket problem or other connection failure (including
2237a6d42e7dSPeter Dunlap 	 * digest errors) then we need to generate a state machine
2238a6d42e7dSPeter Dunlap 	 * event to shut the connection down.
2239a6d42e7dSPeter Dunlap 	 * If the state machine is already in, for example, INIT_ERROR, this
2240a6d42e7dSPeter Dunlap 	 * event will get dropped, and the TX thread will never be notified
2241a6d42e7dSPeter Dunlap 	 * to shut down.  To be safe, we'll just notify it here.
2242a6d42e7dSPeter Dunlap 	 */
2243a6d42e7dSPeter Dunlap 	if (conn_failure) {
2244a6d42e7dSPeter Dunlap 		if (so_conn->ic_tx_thread_running) {
2245a6d42e7dSPeter Dunlap 			so_conn->ic_tx_thread_running = B_FALSE;
2246a6d42e7dSPeter Dunlap 			mutex_enter(&so_conn->ic_tx_mutex);
2247a6d42e7dSPeter Dunlap 			cv_signal(&so_conn->ic_tx_cv);
2248a6d42e7dSPeter Dunlap 			mutex_exit(&so_conn->ic_tx_mutex);
2249a6d42e7dSPeter Dunlap 		}
2250a6d42e7dSPeter Dunlap 
2251a6d42e7dSPeter Dunlap 		idm_conn_event(ic, CE_TRANSPORT_FAIL, rc);
2252a6d42e7dSPeter Dunlap 	}
2253a6d42e7dSPeter Dunlap 
2254a6d42e7dSPeter Dunlap 	idm_conn_rele(ic);
2255a6d42e7dSPeter Dunlap 
2256a6d42e7dSPeter Dunlap 	thread_exit();
2257a6d42e7dSPeter Dunlap }
2258a6d42e7dSPeter Dunlap 
2259a6d42e7dSPeter Dunlap /*
2260a6d42e7dSPeter Dunlap  * idm_so_tx
2261a6d42e7dSPeter Dunlap  *
2262a6d42e7dSPeter Dunlap  * This is the implementation of idm_transport_ops_t's it_tx_pdu entry
2263a6d42e7dSPeter Dunlap  * point.  By definition, it is supposed to be fast.  So, simply queue
2264a6d42e7dSPeter Dunlap  * the entry and return.  The real work is done by idm_i_so_tx() via
2265a6d42e7dSPeter Dunlap  * idm_sotx_thread().
2266a6d42e7dSPeter Dunlap  */
2267a6d42e7dSPeter Dunlap 
2268a6d42e7dSPeter Dunlap static void
idm_so_tx(idm_conn_t * ic,idm_pdu_t * pdu)2269a6d42e7dSPeter Dunlap idm_so_tx(idm_conn_t *ic, idm_pdu_t *pdu)
2270a6d42e7dSPeter Dunlap {
2271a6d42e7dSPeter Dunlap 	idm_so_conn_t *so_conn = ic->ic_transport_private;
2272a6d42e7dSPeter Dunlap 
2273a6d42e7dSPeter Dunlap 	ASSERT(pdu->isp_ic == ic);
2274a6d42e7dSPeter Dunlap 	mutex_enter(&so_conn->ic_tx_mutex);
2275a6d42e7dSPeter Dunlap 
2276a6d42e7dSPeter Dunlap 	if (!so_conn->ic_tx_thread_running) {
2277a6d42e7dSPeter Dunlap 		mutex_exit(&so_conn->ic_tx_mutex);
2278a6d42e7dSPeter Dunlap 		idm_pdu_complete(pdu, IDM_STATUS_ABORTED);
2279a6d42e7dSPeter Dunlap 		return;
2280a6d42e7dSPeter Dunlap 	}
2281a6d42e7dSPeter Dunlap 
2282a6d42e7dSPeter Dunlap 	list_insert_tail(&so_conn->ic_tx_list, (void *)pdu);
2283a6d42e7dSPeter Dunlap 	cv_signal(&so_conn->ic_tx_cv);
2284a6d42e7dSPeter Dunlap 	mutex_exit(&so_conn->ic_tx_mutex);
2285a6d42e7dSPeter Dunlap }
2286a6d42e7dSPeter Dunlap 
2287a6d42e7dSPeter Dunlap static idm_status_t
idm_i_so_tx(idm_pdu_t * pdu)2288a6d42e7dSPeter Dunlap idm_i_so_tx(idm_pdu_t *pdu)
2289a6d42e7dSPeter Dunlap {
2290a6d42e7dSPeter Dunlap 	idm_conn_t	*ic = pdu->isp_ic;
2291a6d42e7dSPeter Dunlap 	idm_status_t	status = IDM_STATUS_SUCCESS;
2292a6d42e7dSPeter Dunlap 	uint8_t		pad[ISCSI_PAD_WORD_LEN];
2293a6d42e7dSPeter Dunlap 	int		pad_len;
2294a6d42e7dSPeter Dunlap 	uint32_t	hdr_digest_crc;
2295a6d42e7dSPeter Dunlap 	uint32_t	data_digest_crc = 0;
2296a6d42e7dSPeter Dunlap 	int		total_len = 0;
2297a6d42e7dSPeter Dunlap 	int		iovlen = 0;
2298a6d42e7dSPeter Dunlap 	struct iovec	iov[6];
2299a6d42e7dSPeter Dunlap 	idm_so_conn_t	*so_conn;
2300a6d42e7dSPeter Dunlap 
2301a6d42e7dSPeter Dunlap 	so_conn = ic->ic_transport_private;
2302a6d42e7dSPeter Dunlap 
2303a6d42e7dSPeter Dunlap 	/* Setup BHS */
2304a6d42e7dSPeter Dunlap 	iov[iovlen].iov_base	= (caddr_t)pdu->isp_hdr;
2305a6d42e7dSPeter Dunlap 	iov[iovlen].iov_len	= pdu->isp_hdrlen;
2306a6d42e7dSPeter Dunlap 	total_len		+= iov[iovlen].iov_len;
2307a6d42e7dSPeter Dunlap 	iovlen++;
2308a6d42e7dSPeter Dunlap 
2309a6d42e7dSPeter Dunlap 	/* Setup header digest */
2310a6d42e7dSPeter Dunlap 	if (((pdu->isp_flags & IDM_PDU_LOGIN_TX) == 0) &&
2311a6d42e7dSPeter Dunlap 	    (ic->ic_conn_flags & IDM_CONN_HEADER_DIGEST)) {
2312a6d42e7dSPeter Dunlap 		hdr_digest_crc = idm_crc32c(pdu->isp_hdr, pdu->isp_hdrlen);
2313a6d42e7dSPeter Dunlap 
2314a6d42e7dSPeter Dunlap 		iov[iovlen].iov_base	= (caddr_t)&hdr_digest_crc;
2315a6d42e7dSPeter Dunlap 		iov[iovlen].iov_len	= sizeof (hdr_digest_crc);
2316a6d42e7dSPeter Dunlap 		total_len		+= iov[iovlen].iov_len;
2317a6d42e7dSPeter Dunlap 		iovlen++;
2318a6d42e7dSPeter Dunlap 	}
2319a6d42e7dSPeter Dunlap 
2320a6d42e7dSPeter Dunlap 	/* Setup the data */
2321a6d42e7dSPeter Dunlap 	if (pdu->isp_datalen) {
2322a6d42e7dSPeter Dunlap 		idm_task_t		*idt;
2323a6d42e7dSPeter Dunlap 		idm_buf_t		*idb;
2324a6d42e7dSPeter Dunlap 		iscsi_data_hdr_t	*ihp;
2325a6d42e7dSPeter Dunlap 		ihp = (iscsi_data_hdr_t *)pdu->isp_hdr;
2326a6d42e7dSPeter Dunlap 		/* Write of immediate data */
2327a6d42e7dSPeter Dunlap 		if (ic->ic_ffp &&
23282727bb05STim Kordas 		    (IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_CMD ||
23292727bb05STim Kordas 		    IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA)) {
2330a6d42e7dSPeter Dunlap 			idt = idm_task_find(ic, ihp->itt, ihp->ttt);
2331a6d42e7dSPeter Dunlap 			if (idt) {
2332a6d42e7dSPeter Dunlap 				mutex_enter(&idt->idt_mutex);
2333a6d42e7dSPeter Dunlap 				idb = idm_buf_find(&idt->idt_outbufv, 0);
2334a6d42e7dSPeter Dunlap 				mutex_exit(&idt->idt_mutex);
233530e7468fSPeter Dunlap 				/*
233630e7468fSPeter Dunlap 				 * If the initiator call to idm_buf_alloc
233730e7468fSPeter Dunlap 				 * failed then we can get to this point
233830e7468fSPeter Dunlap 				 * without a bound buffer.  The associated
233930e7468fSPeter Dunlap 				 * connection failure will clean things up
234030e7468fSPeter Dunlap 				 * later.  It would be nice to come up with
234130e7468fSPeter Dunlap 				 * a cleaner way to handle this.  In
234230e7468fSPeter Dunlap 				 * particular it seems absurd to look up
234330e7468fSPeter Dunlap 				 * the task and the buffer just to update
234430e7468fSPeter Dunlap 				 * this counter.
234530e7468fSPeter Dunlap 				 */
234630e7468fSPeter Dunlap 				if (idb)
234730e7468fSPeter Dunlap 					idb->idb_xfer_len += pdu->isp_datalen;
234830e7468fSPeter Dunlap 				idm_task_rele(idt);
2349a6d42e7dSPeter Dunlap 			}
2350a6d42e7dSPeter Dunlap 		}
2351a6d42e7dSPeter Dunlap 
2352a6d42e7dSPeter Dunlap 		iov[iovlen].iov_base = (caddr_t)pdu->isp_data;
2353a6d42e7dSPeter Dunlap 		iov[iovlen].iov_len  = pdu->isp_datalen;
2354a6d42e7dSPeter Dunlap 		total_len += iov[iovlen].iov_len;
2355a6d42e7dSPeter Dunlap 		iovlen++;
2356a6d42e7dSPeter Dunlap 	}
2357a6d42e7dSPeter Dunlap 
2358a6d42e7dSPeter Dunlap 	/* Setup the data pad if necessary */
2359a6d42e7dSPeter Dunlap 	pad_len = ((ISCSI_PAD_WORD_LEN -
2360a6d42e7dSPeter Dunlap 	    (pdu->isp_datalen & (ISCSI_PAD_WORD_LEN - 1))) &
2361a6d42e7dSPeter Dunlap 	    (ISCSI_PAD_WORD_LEN - 1));
2362a6d42e7dSPeter Dunlap 
2363a6d42e7dSPeter Dunlap 	if (pad_len) {
2364a6d42e7dSPeter Dunlap 		bzero(pad, sizeof (pad));
2365a6d42e7dSPeter Dunlap 		iov[iovlen].iov_base = (void *)&pad;
2366a6d42e7dSPeter Dunlap 		iov[iovlen].iov_len  = pad_len;
2367a6d42e7dSPeter Dunlap 		total_len		+= iov[iovlen].iov_len;
2368a6d42e7dSPeter Dunlap 		iovlen++;
2369a6d42e7dSPeter Dunlap 	}
2370a6d42e7dSPeter Dunlap 
2371a6d42e7dSPeter Dunlap 	/*
2372a6d42e7dSPeter Dunlap 	 * Setup the data digest if enabled.  Data-digest is not sent
2373a6d42e7dSPeter Dunlap 	 * for login-phase PDUs.
2374a6d42e7dSPeter Dunlap 	 */
2375a6d42e7dSPeter Dunlap 	if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) &&
2376a6d42e7dSPeter Dunlap 	    ((pdu->isp_flags & IDM_PDU_LOGIN_TX) == 0) &&
2377a6d42e7dSPeter Dunlap 	    (pdu->isp_datalen || pad_len)) {
2378a6d42e7dSPeter Dunlap 		/*
2379a6d42e7dSPeter Dunlap 		 * RFC3720/10.2.3: A zero-length Data Segment also
2380a6d42e7dSPeter Dunlap 		 * implies a zero-length data digest.
2381a6d42e7dSPeter Dunlap 		 */
2382a6d42e7dSPeter Dunlap 		if (pdu->isp_datalen) {
2383a6d42e7dSPeter Dunlap 			data_digest_crc = idm_crc32c(pdu->isp_data,
2384a6d42e7dSPeter Dunlap 			    pdu->isp_datalen);
2385a6d42e7dSPeter Dunlap 		}
2386a6d42e7dSPeter Dunlap 		if (pad_len) {
2387a6d42e7dSPeter Dunlap 			data_digest_crc = idm_crc32c_continued(&pad,
2388a6d42e7dSPeter Dunlap 			    pad_len, data_digest_crc);
2389a6d42e7dSPeter Dunlap 		}
2390a6d42e7dSPeter Dunlap 
2391a6d42e7dSPeter Dunlap 		iov[iovlen].iov_base	= (caddr_t)&data_digest_crc;
2392a6d42e7dSPeter Dunlap 		iov[iovlen].iov_len	= sizeof (data_digest_crc);
2393a6d42e7dSPeter Dunlap 		total_len		+= iov[iovlen].iov_len;
2394a6d42e7dSPeter Dunlap 		iovlen++;
2395a6d42e7dSPeter Dunlap 	}
2396a6d42e7dSPeter Dunlap 
2397a6d42e7dSPeter Dunlap 	/* Transmit the PDU */
2398a6d42e7dSPeter Dunlap 	if (idm_iov_sosend(so_conn->ic_so, &iov[0], iovlen,
2399a6d42e7dSPeter Dunlap 	    total_len) != 0) {
2400a6d42e7dSPeter Dunlap 		/* Set error status */
2401a6d42e7dSPeter Dunlap 		IDM_CONN_LOG(CE_WARN,
2402a6d42e7dSPeter Dunlap 		    "idm_so_tx: failed to transmit the PDU, so: %p ic: %p "
2403a6d42e7dSPeter Dunlap 		    "data: %p", (void *) so_conn->ic_so, (void *) ic,
2404a6d42e7dSPeter Dunlap 		    (void *) pdu->isp_data);
2405a6d42e7dSPeter Dunlap 		status = IDM_STATUS_IO;
2406a6d42e7dSPeter Dunlap 	}
2407a6d42e7dSPeter Dunlap 
2408a6d42e7dSPeter Dunlap 	/*
2409a6d42e7dSPeter Dunlap 	 * Success does not mean that the PDU actually reached the
2410a6d42e7dSPeter Dunlap 	 * remote node since it could get dropped along the way.
2411a6d42e7dSPeter Dunlap 	 */
2412a6d42e7dSPeter Dunlap 	idm_pdu_complete(pdu, status);
2413a6d42e7dSPeter Dunlap 
2414a6d42e7dSPeter Dunlap 	return (status);
2415a6d42e7dSPeter Dunlap }
2416a6d42e7dSPeter Dunlap 
2417a6d42e7dSPeter Dunlap /*
2418a6d42e7dSPeter Dunlap  * The idm_so_buf_tx_to_ini() is used by the target iSCSI layer to transmit the
2419a6d42e7dSPeter Dunlap  * Data-In PDUs using sockets. Based on the negotiated MaxRecvDataSegmentLength,
2420a6d42e7dSPeter Dunlap  * the buffer is segmented into a sequence of Data-In PDUs, ordered by DataSN.
2421a6d42e7dSPeter Dunlap  * A target can invoke this function multiple times for a single read command
2422a6d42e7dSPeter Dunlap  * (identified by the same ITT) to split the input into several sequences.
2423a6d42e7dSPeter Dunlap  *
2424a6d42e7dSPeter Dunlap  * DataSN starts with 0 for the first data PDU of an input command and advances
2425a6d42e7dSPeter Dunlap  * by 1 for each subsequent data PDU. Each sequence will have its own F bit,
2426a6d42e7dSPeter Dunlap  * which is set to 1 for the last data PDU of a sequence.
242760220f10SPriya Krishnan  * If the initiator supports phase collapse, the status bit must be set along
242860220f10SPriya Krishnan  * with the F bit to indicate that the status is shipped together with the last
242960220f10SPriya Krishnan  * Data-In PDU.
2430a6d42e7dSPeter Dunlap  *
2431a6d42e7dSPeter Dunlap  * The data PDUs within a sequence will be sent in order with the buffer offset
2432a6d42e7dSPeter Dunlap  * in increasing order. i.e. initiator and target must have negotiated the
2433a6d42e7dSPeter Dunlap  * "DataPDUInOrder" to "Yes". The order between sequences is not enforced.
2434a6d42e7dSPeter Dunlap  *
2435a6d42e7dSPeter Dunlap  * Caller holds idt->idt_mutex
2436a6d42e7dSPeter Dunlap  */
2437a6d42e7dSPeter Dunlap static idm_status_t
idm_so_buf_tx_to_ini(idm_task_t * idt,idm_buf_t * idb)2438a6d42e7dSPeter Dunlap idm_so_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb)
2439a6d42e7dSPeter Dunlap {
2440a6d42e7dSPeter Dunlap 	idm_so_conn_t	*so_conn = idb->idb_ic->ic_transport_private;
2441a6d42e7dSPeter Dunlap 	idm_pdu_t	tmppdu;
2442a6d42e7dSPeter Dunlap 
2443a6d42e7dSPeter Dunlap 	ASSERT(mutex_owned(&idt->idt_mutex));
2444a6d42e7dSPeter Dunlap 
2445a6d42e7dSPeter Dunlap 	/*
2446a6d42e7dSPeter Dunlap 	 * Put the idm_buf_t on the tx queue.  It will be transmitted by
2447a6d42e7dSPeter Dunlap 	 * idm_sotx_thread.
2448a6d42e7dSPeter Dunlap 	 */
2449a6d42e7dSPeter Dunlap 	mutex_enter(&so_conn->ic_tx_mutex);
2450a6d42e7dSPeter Dunlap 
2451a668b114SPriya Krishnan 	DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic,
2452a668b114SPriya Krishnan 	    uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset,
2453a668b114SPriya Krishnan 	    uint64_t, 0, uint32_t, 0, uint32_t, 0,
2454a668b114SPriya Krishnan 	    uint32_t, idb->idb_xfer_len, int, XFER_BUF_TX_TO_INI);
2455a668b114SPriya Krishnan 
2456a6d42e7dSPeter Dunlap 	if (!so_conn->ic_tx_thread_running) {
2457a6d42e7dSPeter Dunlap 		mutex_exit(&so_conn->ic_tx_mutex);
2458a6d42e7dSPeter Dunlap 		/*
2459a6d42e7dSPeter Dunlap 		 * Don't release idt->idt_mutex since we're supposed to hold
2460a6d42e7dSPeter Dunlap 		 * in when calling idm_buf_tx_to_ini_done
2461a6d42e7dSPeter Dunlap 		 */
2462a668b114SPriya Krishnan 		DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic,
2463a668b114SPriya Krishnan 		    uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset,
2464a668b114SPriya Krishnan 		    uint64_t, 0, uint32_t, 0, uint32_t, 0,
2465a668b114SPriya Krishnan 		    uint32_t, idb->idb_xfer_len,
2466a668b114SPriya Krishnan 		    int, XFER_BUF_TX_TO_INI);
2467a6d42e7dSPeter Dunlap 		idm_buf_tx_to_ini_done(idt, idb, IDM_STATUS_ABORTED);
2468a6d42e7dSPeter Dunlap 		return (IDM_STATUS_FAIL);
2469a6d42e7dSPeter Dunlap 	}
2470a6d42e7dSPeter Dunlap 
2471a6d42e7dSPeter Dunlap 	/*
2472a6d42e7dSPeter Dunlap 	 * Build a template for the data PDU headers we will use so that
2473a6d42e7dSPeter Dunlap 	 * the SN values will stay consistent with other PDU's we are
2474a6d42e7dSPeter Dunlap 	 * transmitting like R2T and SCSI status.
2475a6d42e7dSPeter Dunlap 	 */
2476a6d42e7dSPeter Dunlap 	bzero(&idb->idb_data_hdr_tmpl, sizeof (iscsi_hdr_t));
2477a6d42e7dSPeter Dunlap 	tmppdu.isp_hdr = &idb->idb_data_hdr_tmpl;
2478a6d42e7dSPeter Dunlap 	(*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, &tmppdu,
2479a6d42e7dSPeter Dunlap 	    ISCSI_OP_SCSI_DATA_RSP);
2480a6d42e7dSPeter Dunlap 	idb->idb_tx_thread = B_TRUE;
2481a6d42e7dSPeter Dunlap 	list_insert_tail(&so_conn->ic_tx_list, (void *)idb);
2482a6d42e7dSPeter Dunlap 	cv_signal(&so_conn->ic_tx_cv);
2483a6d42e7dSPeter Dunlap 	mutex_exit(&so_conn->ic_tx_mutex);
2484a6d42e7dSPeter Dunlap 	mutex_exit(&idt->idt_mutex);
2485a6d42e7dSPeter Dunlap 
2486a6d42e7dSPeter Dunlap 	/*
2487a6d42e7dSPeter Dunlap 	 * Returning success here indicates the transfer was successfully
2488a6d42e7dSPeter Dunlap 	 * dispatched -- it does not mean that the transfer completed
2489a6d42e7dSPeter Dunlap 	 * successfully.
2490a6d42e7dSPeter Dunlap 	 */
2491a6d42e7dSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
2492a6d42e7dSPeter Dunlap }
2493a6d42e7dSPeter Dunlap 
2494a6d42e7dSPeter Dunlap /*
2495a6d42e7dSPeter Dunlap  * The idm_so_buf_rx_from_ini() is used by the target iSCSI layer to specify the
2496a6d42e7dSPeter Dunlap  * data blocks it is ready to receive from the initiator in response to a WRITE
2497a6d42e7dSPeter Dunlap  * SCSI command. The target iSCSI layer passes the information about the desired
2498a6d42e7dSPeter Dunlap  * data blocks to the initiator in one R2T PDU. The receiving buffer, the buffer
2499a6d42e7dSPeter Dunlap  * offset and datalen are passed via the 'idb' argument.
2500a6d42e7dSPeter Dunlap  *
2501a6d42e7dSPeter Dunlap  * Scope for Prototype build:
2502a6d42e7dSPeter Dunlap  * R2Ts are required for any Data-Out PDU, i.e. initiator and target must have
2503a6d42e7dSPeter Dunlap  * negotiated the "InitialR2T" to "Yes".
2504a6d42e7dSPeter Dunlap  *
2505a6d42e7dSPeter Dunlap  * Caller holds idt->idt_mutex
2506a6d42e7dSPeter Dunlap  */
2507a6d42e7dSPeter Dunlap static idm_status_t
idm_so_buf_rx_from_ini(idm_task_t * idt,idm_buf_t * idb)2508a6d42e7dSPeter Dunlap idm_so_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb)
2509a6d42e7dSPeter Dunlap {
2510a6d42e7dSPeter Dunlap 	idm_pdu_t		*pdu;
2511a6d42e7dSPeter Dunlap 	iscsi_rtt_hdr_t		*rtt;
2512a6d42e7dSPeter Dunlap 
2513a6d42e7dSPeter Dunlap 	ASSERT(mutex_owned(&idt->idt_mutex));
2514a6d42e7dSPeter Dunlap 
2515a668b114SPriya Krishnan 	DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic,
2516a668b114SPriya Krishnan 	    uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset,
2517a668b114SPriya Krishnan 	    uint64_t, 0, uint32_t, 0, uint32_t, 0,
2518a668b114SPriya Krishnan 	    uint32_t, idb->idb_xfer_len, int, XFER_BUF_RX_FROM_INI);
2519a668b114SPriya Krishnan 
2520a6d42e7dSPeter Dunlap 	pdu = kmem_cache_alloc(idm.idm_sotx_pdu_cache, KM_SLEEP);
2521a6d42e7dSPeter Dunlap 	pdu->isp_ic = idt->idt_ic;
2522a2383ac5SPriya Krishnan 	pdu->isp_flags = IDM_PDU_SET_STATSN;
2523a6d42e7dSPeter Dunlap 	bzero(pdu->isp_hdr, sizeof (iscsi_rtt_hdr_t));
2524a6d42e7dSPeter Dunlap 
2525a2383ac5SPriya Krishnan 	/* iSCSI layer fills the TTT, ITT, ExpCmdSN, MaxCmdSN */
2526a6d42e7dSPeter Dunlap 	(*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, pdu, ISCSI_OP_RTT_RSP);
2527a6d42e7dSPeter Dunlap 
2528a6d42e7dSPeter Dunlap 	/* set the rttsn, rtt.flags, rtt.data_offset and rtt.data_length */
2529a6d42e7dSPeter Dunlap 	rtt = (iscsi_rtt_hdr_t *)(pdu->isp_hdr);
2530a6d42e7dSPeter Dunlap 
2531a6d42e7dSPeter Dunlap 	rtt->opcode		= ISCSI_OP_RTT_RSP;
2532a6d42e7dSPeter Dunlap 	rtt->flags		= ISCSI_FLAG_FINAL;
2533a6d42e7dSPeter Dunlap 	rtt->data_offset	= htonl(idb->idb_bufoffset);
2534a6d42e7dSPeter Dunlap 	rtt->data_length	= htonl(idb->idb_xfer_len);
2535a6d42e7dSPeter Dunlap 	rtt->rttsn		= htonl(idt->idt_exp_rttsn++);
2536a6d42e7dSPeter Dunlap 
2537a6d42e7dSPeter Dunlap 	/* Keep track of buffer offsets */
2538a6d42e7dSPeter Dunlap 	idb->idb_exp_offset	= idb->idb_bufoffset;
2539a6d42e7dSPeter Dunlap 	mutex_exit(&idt->idt_mutex);
2540a6d42e7dSPeter Dunlap 
2541a6d42e7dSPeter Dunlap 	/*
254263528ae4SJames Moore 	 * Transmit the PDU.
2543a6d42e7dSPeter Dunlap 	 */
254463528ae4SJames Moore 	idm_pdu_tx(pdu);
2545a6d42e7dSPeter Dunlap 
2546a6d42e7dSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
2547a6d42e7dSPeter Dunlap }
2548a6d42e7dSPeter Dunlap 
2549a6d42e7dSPeter Dunlap static idm_status_t
idm_so_buf_alloc(idm_buf_t * idb,uint64_t buflen)2550a6d42e7dSPeter Dunlap idm_so_buf_alloc(idm_buf_t *idb, uint64_t buflen)
2551a6d42e7dSPeter Dunlap {
2552cf8c0ebaSPeter Dunlap 	if ((buflen > IDM_SO_BUF_CACHE_LB) && (buflen <= IDM_SO_BUF_CACHE_UB)) {
2553cf8c0ebaSPeter Dunlap 		idb->idb_buf = kmem_cache_alloc(idm.idm_so_128k_buf_cache,
2554cf8c0ebaSPeter Dunlap 		    KM_NOSLEEP);
2555cf8c0ebaSPeter Dunlap 		idb->idb_buf_private = idm.idm_so_128k_buf_cache;
2556cf8c0ebaSPeter Dunlap 	} else {
2557cf8c0ebaSPeter Dunlap 		idb->idb_buf = kmem_alloc(buflen, KM_NOSLEEP);
2558cf8c0ebaSPeter Dunlap 		idb->idb_buf_private = NULL;
2559cf8c0ebaSPeter Dunlap 	}
2560cf8c0ebaSPeter Dunlap 
2561a6d42e7dSPeter Dunlap 	if (idb->idb_buf == NULL) {
2562a6d42e7dSPeter Dunlap 		IDM_CONN_LOG(CE_NOTE,
2563a6d42e7dSPeter Dunlap 		    "idm_so_buf_alloc: failed buffer allocation");
2564a6d42e7dSPeter Dunlap 		return (IDM_STATUS_FAIL);
2565a6d42e7dSPeter Dunlap 	}
2566cf8c0ebaSPeter Dunlap 
2567a6d42e7dSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
2568a6d42e7dSPeter Dunlap }
2569a6d42e7dSPeter Dunlap 
2570a6d42e7dSPeter Dunlap /* ARGSUSED */
2571a6d42e7dSPeter Dunlap static idm_status_t
idm_so_buf_setup(idm_buf_t * idb)2572a6d42e7dSPeter Dunlap idm_so_buf_setup(idm_buf_t *idb)
2573a6d42e7dSPeter Dunlap {
257430e7468fSPeter Dunlap 	/* Ensure bufalloc'd flag is unset */
257530e7468fSPeter Dunlap 	idb->idb_bufalloc = B_FALSE;
257630e7468fSPeter Dunlap 
2577a6d42e7dSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
2578a6d42e7dSPeter Dunlap }
2579a6d42e7dSPeter Dunlap 
2580a6d42e7dSPeter Dunlap /* ARGSUSED */
2581a6d42e7dSPeter Dunlap static void
idm_so_buf_teardown(idm_buf_t * idb)2582a6d42e7dSPeter Dunlap idm_so_buf_teardown(idm_buf_t *idb)
2583a6d42e7dSPeter Dunlap {
2584a6d42e7dSPeter Dunlap 	/* nothing to do here */
2585a6d42e7dSPeter Dunlap }
2586a6d42e7dSPeter Dunlap 
2587a6d42e7dSPeter Dunlap static void
idm_so_buf_free(idm_buf_t * idb)2588a6d42e7dSPeter Dunlap idm_so_buf_free(idm_buf_t *idb)
2589a6d42e7dSPeter Dunlap {
2590cf8c0ebaSPeter Dunlap 	if (idb->idb_buf_private == NULL) {
2591cf8c0ebaSPeter Dunlap 		kmem_free(idb->idb_buf, idb->idb_buflen);
2592cf8c0ebaSPeter Dunlap 	} else {
2593cf8c0ebaSPeter Dunlap 		kmem_cache_free(idb->idb_buf_private, idb->idb_buf);
2594cf8c0ebaSPeter Dunlap 	}
2595a6d42e7dSPeter Dunlap }
2596a6d42e7dSPeter Dunlap 
259730e7468fSPeter Dunlap static void
idm_so_send_rtt_data(idm_conn_t * ic,idm_task_t * idt,idm_buf_t * idb,uint32_t offset,uint32_t length)259830e7468fSPeter Dunlap idm_so_send_rtt_data(idm_conn_t *ic, idm_task_t *idt, idm_buf_t *idb,
259930e7468fSPeter Dunlap     uint32_t offset, uint32_t length)
260030e7468fSPeter Dunlap {
260130e7468fSPeter Dunlap 	idm_so_conn_t	*so_conn = ic->ic_transport_private;
260230e7468fSPeter Dunlap 	idm_pdu_t	tmppdu;
260330e7468fSPeter Dunlap 	idm_buf_t	*rtt_buf;
260430e7468fSPeter Dunlap 
260530e7468fSPeter Dunlap 	ASSERT(mutex_owned(&idt->idt_mutex));
260630e7468fSPeter Dunlap 
260730e7468fSPeter Dunlap 	/*
260830e7468fSPeter Dunlap 	 * Allocate a buffer to represent the RTT transfer.  We could further
260930e7468fSPeter Dunlap 	 * optimize this by allocating the buffers internally from an rtt
261030e7468fSPeter Dunlap 	 * specific buffer cache since this is socket-specific code but for
261130e7468fSPeter Dunlap 	 * now we will keep it simple.
261230e7468fSPeter Dunlap 	 */
261330e7468fSPeter Dunlap 	rtt_buf = idm_buf_alloc(ic, (uint8_t *)idb->idb_buf + offset, length);
261430e7468fSPeter Dunlap 	if (rtt_buf == NULL) {
261530e7468fSPeter Dunlap 		/*
261630e7468fSPeter Dunlap 		 * If we're in FFP then the failure was likely a resource
261730e7468fSPeter Dunlap 		 * allocation issue and we should close the connection by
261830e7468fSPeter Dunlap 		 * sending a CE_TRANSPORT_FAIL event.
261930e7468fSPeter Dunlap 		 *
262030e7468fSPeter Dunlap 		 * If we're not in FFP then idm_buf_alloc will always
262130e7468fSPeter Dunlap 		 * fail and the state is transitioning to "complete" anyway
262230e7468fSPeter Dunlap 		 * so we won't bother to send an event.
262330e7468fSPeter Dunlap 		 */
262430e7468fSPeter Dunlap 		mutex_enter(&ic->ic_state_mutex);
262530e7468fSPeter Dunlap 		if (ic->ic_ffp)
262630e7468fSPeter Dunlap 			idm_conn_event_locked(ic, CE_TRANSPORT_FAIL,
26278e718be9SToomas Soome 			    (uintptr_t)NULL, CT_NONE);
262830e7468fSPeter Dunlap 		mutex_exit(&ic->ic_state_mutex);
2629c158b55cSJack Meng 		mutex_exit(&idt->idt_mutex);
263030e7468fSPeter Dunlap 		return;
263130e7468fSPeter Dunlap 	}
263230e7468fSPeter Dunlap 
263330e7468fSPeter Dunlap 	rtt_buf->idb_buf_cb = NULL;
263430e7468fSPeter Dunlap 	rtt_buf->idb_cb_arg = NULL;
263530e7468fSPeter Dunlap 	rtt_buf->idb_bufoffset = offset;
263630e7468fSPeter Dunlap 	rtt_buf->idb_xfer_len = length;
263730e7468fSPeter Dunlap 	rtt_buf->idb_ic = idt->idt_ic;
263830e7468fSPeter Dunlap 	rtt_buf->idb_task_binding = idt;
263930e7468fSPeter Dunlap 
2640c158b55cSJack Meng 	/*
2641c158b55cSJack Meng 	 * The new buffer (if any) represents an additional
2642c158b55cSJack Meng 	 * reference on the task
2643c158b55cSJack Meng 	 */
2644c158b55cSJack Meng 	idm_task_hold(idt);
2645c158b55cSJack Meng 	mutex_exit(&idt->idt_mutex);
2646c158b55cSJack Meng 
264730e7468fSPeter Dunlap 	/*
264830e7468fSPeter Dunlap 	 * Put the idm_buf_t on the tx queue.  It will be transmitted by
264930e7468fSPeter Dunlap 	 * idm_sotx_thread.
265030e7468fSPeter Dunlap 	 */
265130e7468fSPeter Dunlap 	mutex_enter(&so_conn->ic_tx_mutex);
265230e7468fSPeter Dunlap 
265330e7468fSPeter Dunlap 	if (!so_conn->ic_tx_thread_running) {
265430e7468fSPeter Dunlap 		idm_buf_free(rtt_buf);
265530e7468fSPeter Dunlap 		mutex_exit(&so_conn->ic_tx_mutex);
2656c158b55cSJack Meng 		idm_task_rele(idt);
265730e7468fSPeter Dunlap 		return;
265830e7468fSPeter Dunlap 	}
265930e7468fSPeter Dunlap 
266030e7468fSPeter Dunlap 	/*
266130e7468fSPeter Dunlap 	 * Build a template for the data PDU headers we will use so that
266230e7468fSPeter Dunlap 	 * the SN values will stay consistent with other PDU's we are
266330e7468fSPeter Dunlap 	 * transmitting like R2T and SCSI status.
266430e7468fSPeter Dunlap 	 */
266530e7468fSPeter Dunlap 	bzero(&rtt_buf->idb_data_hdr_tmpl, sizeof (iscsi_hdr_t));
266630e7468fSPeter Dunlap 	tmppdu.isp_hdr = &rtt_buf->idb_data_hdr_tmpl;
266730e7468fSPeter Dunlap 	(*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, &tmppdu,
266830e7468fSPeter Dunlap 	    ISCSI_OP_SCSI_DATA);
266930e7468fSPeter Dunlap 	rtt_buf->idb_tx_thread = B_TRUE;
267030e7468fSPeter Dunlap 	rtt_buf->idb_in_transport = B_TRUE;
267130e7468fSPeter Dunlap 	list_insert_tail(&so_conn->ic_tx_list, (void *)rtt_buf);
267230e7468fSPeter Dunlap 	cv_signal(&so_conn->ic_tx_cv);
267330e7468fSPeter Dunlap 	mutex_exit(&so_conn->ic_tx_mutex);
267430e7468fSPeter Dunlap }
267530e7468fSPeter Dunlap 
267630e7468fSPeter Dunlap static void
idm_so_send_rtt_data_done(idm_task_t * idt,idm_buf_t * idb)267730e7468fSPeter Dunlap idm_so_send_rtt_data_done(idm_task_t *idt, idm_buf_t *idb)
267830e7468fSPeter Dunlap {
267930e7468fSPeter Dunlap 	/*
268030e7468fSPeter Dunlap 	 * Don't worry about status -- we assume any error handling
268130e7468fSPeter Dunlap 	 * is performed by the caller (idm_sotx_thread).
268230e7468fSPeter Dunlap 	 */
268330e7468fSPeter Dunlap 	idb->idb_in_transport = B_FALSE;
268430e7468fSPeter Dunlap 	idm_task_rele(idt);
268530e7468fSPeter Dunlap 	idm_buf_free(idb);
268630e7468fSPeter Dunlap }
268730e7468fSPeter Dunlap 
268830e7468fSPeter Dunlap static idm_status_t
idm_so_send_buf_region(idm_task_t * idt,idm_buf_t * idb,uint32_t buf_region_offset,uint32_t buf_region_length)268930e7468fSPeter Dunlap idm_so_send_buf_region(idm_task_t *idt, idm_buf_t *idb,
2690a6d42e7dSPeter Dunlap     uint32_t buf_region_offset, uint32_t buf_region_length)
2691a6d42e7dSPeter Dunlap {
2692a6d42e7dSPeter Dunlap 	idm_conn_t		*ic;
2693a6d42e7dSPeter Dunlap 	uint32_t		max_dataseglen;
2694a6d42e7dSPeter Dunlap 	size_t			remainder, chunk;
2695a6d42e7dSPeter Dunlap 	uint32_t		data_offset = buf_region_offset;
2696a6d42e7dSPeter Dunlap 	iscsi_data_hdr_t	*bhs;
2697a6d42e7dSPeter Dunlap 	idm_pdu_t		*pdu;
269830e7468fSPeter Dunlap 	idm_status_t		tx_status;
2699a6d42e7dSPeter Dunlap 
2700a6d42e7dSPeter Dunlap 	ASSERT(mutex_owned(&idt->idt_mutex));
2701a6d42e7dSPeter Dunlap 
2702a6d42e7dSPeter Dunlap 	ic = idt->idt_ic;
2703a6d42e7dSPeter Dunlap 
270456261083SCharles Ting 	max_dataseglen = ic->ic_conn_params.max_xmit_dataseglen;
2705a6d42e7dSPeter Dunlap 	remainder = buf_region_length;
2706a6d42e7dSPeter Dunlap 
2707a6d42e7dSPeter Dunlap 	while (remainder) {
2708a6d42e7dSPeter Dunlap 		if (idt->idt_state != TASK_ACTIVE) {
2709a6d42e7dSPeter Dunlap 			ASSERT((idt->idt_state != TASK_IDLE) &&
2710a6d42e7dSPeter Dunlap 			    (idt->idt_state != TASK_COMPLETE));
2711a6d42e7dSPeter Dunlap 			return (IDM_STATUS_ABORTED);
2712a6d42e7dSPeter Dunlap 		}
2713a6d42e7dSPeter Dunlap 
2714a6d42e7dSPeter Dunlap 		/* check to see if we need to chunk the data */
2715a6d42e7dSPeter Dunlap 		if (remainder > max_dataseglen) {
2716a6d42e7dSPeter Dunlap 			chunk = max_dataseglen;
2717a6d42e7dSPeter Dunlap 		} else {
2718a6d42e7dSPeter Dunlap 			chunk = remainder;
2719a6d42e7dSPeter Dunlap 		}
2720a6d42e7dSPeter Dunlap 
2721a6d42e7dSPeter Dunlap 		/* Data PDU headers will always be sizeof (iscsi_hdr_t) */
2722a6d42e7dSPeter Dunlap 		pdu = kmem_cache_alloc(idm.idm_sotx_pdu_cache, KM_SLEEP);
2723a6d42e7dSPeter Dunlap 		pdu->isp_ic = ic;
272460220f10SPriya Krishnan 		pdu->isp_flags = 0;	/* initialize isp_flags */
2725a6d42e7dSPeter Dunlap 
2726a6d42e7dSPeter Dunlap 		/*
272730e7468fSPeter Dunlap 		 * We've already built a build a header template
2728a6d42e7dSPeter Dunlap 		 * to use during the transfer.  Use this template so that
2729a6d42e7dSPeter Dunlap 		 * the SN values stay consistent with any unrelated PDU's
2730a6d42e7dSPeter Dunlap 		 * being transmitted.
2731a6d42e7dSPeter Dunlap 		 */
273230e7468fSPeter Dunlap 		bcopy(&idb->idb_data_hdr_tmpl, pdu->isp_hdr,
273330e7468fSPeter Dunlap 		    sizeof (iscsi_hdr_t));
2734a6d42e7dSPeter Dunlap 
2735a6d42e7dSPeter Dunlap 		/*
2736a6d42e7dSPeter Dunlap 		 * Set DataSN, data offset, and flags in BHS
2737a6d42e7dSPeter Dunlap 		 * For the prototype build, A = 0, S = 0, U = 0
2738a6d42e7dSPeter Dunlap 		 */
2739a6d42e7dSPeter Dunlap 		bhs = (iscsi_data_hdr_t *)(pdu->isp_hdr);
2740a6d42e7dSPeter Dunlap 
2741a6d42e7dSPeter Dunlap 		bhs->datasn		= htonl(idt->idt_exp_datasn++);
2742a6d42e7dSPeter Dunlap 
2743a6d42e7dSPeter Dunlap 		hton24(bhs->dlength, chunk);
2744a6d42e7dSPeter Dunlap 		bhs->offset = htonl(idb->idb_bufoffset + data_offset);
2745a6d42e7dSPeter Dunlap 
274660220f10SPriya Krishnan 		/* setup data */
274760220f10SPriya Krishnan 		pdu->isp_data	=  (uint8_t *)idb->idb_buf + data_offset;
274860220f10SPriya Krishnan 		pdu->isp_datalen = (uint_t)chunk;
274960220f10SPriya Krishnan 
2750a6d42e7dSPeter Dunlap 		if (chunk == remainder) {
2751a6d42e7dSPeter Dunlap 			bhs->flags = ISCSI_FLAG_FINAL; /* F bit set to 1 */
275260220f10SPriya Krishnan 			/* Piggyback the status with the last data PDU */
275360220f10SPriya Krishnan 			if (idt->idt_flags & IDM_TASK_PHASECOLLAPSE_REQ) {
275460220f10SPriya Krishnan 				pdu->isp_flags |= IDM_PDU_SET_STATSN |
275560220f10SPriya Krishnan 				    IDM_PDU_ADVANCE_STATSN;
275660220f10SPriya Krishnan 				(*idt->idt_ic->ic_conn_ops.icb_update_statsn)
275760220f10SPriya Krishnan 				    (idt, pdu);
275860220f10SPriya Krishnan 				idt->idt_flags |=
275960220f10SPriya Krishnan 				    IDM_TASK_PHASECOLLAPSE_SUCCESS;
276060220f10SPriya Krishnan 
276160220f10SPriya Krishnan 			}
2762a6d42e7dSPeter Dunlap 		}
2763a6d42e7dSPeter Dunlap 
276460220f10SPriya Krishnan 		remainder	-= chunk;
276560220f10SPriya Krishnan 		data_offset	+= chunk;
276660220f10SPriya Krishnan 
2767a668b114SPriya Krishnan 		/* Instrument the data-send DTrace probe. */
2768a668b114SPriya Krishnan 		if (IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA_RSP) {
2769a668b114SPriya Krishnan 			DTRACE_ISCSI_2(data__send,
2770a668b114SPriya Krishnan 			    idm_conn_t *, idt->idt_ic,
2771a668b114SPriya Krishnan 			    iscsi_data_rsp_hdr_t *,
2772a668b114SPriya Krishnan 			    (iscsi_data_rsp_hdr_t *)pdu->isp_hdr);
2773a668b114SPriya Krishnan 		}
2774a6d42e7dSPeter Dunlap 
2775a6d42e7dSPeter Dunlap 		/*
2776a6d42e7dSPeter Dunlap 		 * Now that we're done working with idt_exp_datasn,
2777a6d42e7dSPeter Dunlap 		 * idt->idt_state and idb->idb_bufoffset we can release
2778a6d42e7dSPeter Dunlap 		 * the task lock -- don't want to hold it across the
2779a6d42e7dSPeter Dunlap 		 * call to idm_i_so_tx since we could block.
2780a6d42e7dSPeter Dunlap 		 */
2781a6d42e7dSPeter Dunlap 		mutex_exit(&idt->idt_mutex);
2782a6d42e7dSPeter Dunlap 
2783a6d42e7dSPeter Dunlap 		/*
2784a6d42e7dSPeter Dunlap 		 * Transmit the PDU.  Call the internal routine directly
2785a6d42e7dSPeter Dunlap 		 * as there is already implicit ordering.
2786a6d42e7dSPeter Dunlap 		 */
278730e7468fSPeter Dunlap 		if ((tx_status = idm_i_so_tx(pdu)) != IDM_STATUS_SUCCESS) {
278830e7468fSPeter Dunlap 			mutex_enter(&idt->idt_mutex);
278930e7468fSPeter Dunlap 			return (tx_status);
279030e7468fSPeter Dunlap 		}
2791a6d42e7dSPeter Dunlap 
2792a6d42e7dSPeter Dunlap 		mutex_enter(&idt->idt_mutex);
279330e7468fSPeter Dunlap 		idt->idt_tx_bytes += chunk;
2794a6d42e7dSPeter Dunlap 	}
2795a6d42e7dSPeter Dunlap 
2796a6d42e7dSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
2797a6d42e7dSPeter Dunlap }
2798a6d42e7dSPeter Dunlap 
2799a6d42e7dSPeter Dunlap /*
2800a6d42e7dSPeter Dunlap  * TX PDU cache
2801a6d42e7dSPeter Dunlap  */
2802a6d42e7dSPeter Dunlap /* ARGSUSED */
2803a6d42e7dSPeter Dunlap int
idm_sotx_pdu_constructor(void * hdl,void * arg,int flags)2804a6d42e7dSPeter Dunlap idm_sotx_pdu_constructor(void *hdl, void *arg, int flags)
2805a6d42e7dSPeter Dunlap {
2806a6d42e7dSPeter Dunlap 	idm_pdu_t	*pdu = hdl;
2807a6d42e7dSPeter Dunlap 
2808a6d42e7dSPeter Dunlap 	bzero(pdu, sizeof (idm_pdu_t));
2809a6d42e7dSPeter Dunlap 	pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); /* Ptr arithmetic */
2810a6d42e7dSPeter Dunlap 	pdu->isp_hdrlen = sizeof (iscsi_hdr_t);
2811a6d42e7dSPeter Dunlap 	pdu->isp_callback = idm_sotx_cache_pdu_cb;
2812a6d42e7dSPeter Dunlap 	pdu->isp_magic = IDM_PDU_MAGIC;
2813a6d42e7dSPeter Dunlap 	bzero(pdu->isp_hdr, sizeof (iscsi_hdr_t));
2814a6d42e7dSPeter Dunlap 
2815a6d42e7dSPeter Dunlap 	return (0);
2816a6d42e7dSPeter Dunlap }
2817a6d42e7dSPeter Dunlap 
2818a6d42e7dSPeter Dunlap /* ARGSUSED */
2819a6d42e7dSPeter Dunlap void
idm_sotx_cache_pdu_cb(idm_pdu_t * pdu,idm_status_t status)2820a6d42e7dSPeter Dunlap idm_sotx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status)
2821a6d42e7dSPeter Dunlap {
2822a6d42e7dSPeter Dunlap 	/* reset values between use */
2823a6d42e7dSPeter Dunlap 	pdu->isp_datalen = 0;
2824a6d42e7dSPeter Dunlap 
2825a6d42e7dSPeter Dunlap 	kmem_cache_free(idm.idm_sotx_pdu_cache, pdu);
2826a6d42e7dSPeter Dunlap }
2827a6d42e7dSPeter Dunlap 
2828a6d42e7dSPeter Dunlap /*
2829a6d42e7dSPeter Dunlap  * RX PDU cache
2830a6d42e7dSPeter Dunlap  */
2831a6d42e7dSPeter Dunlap /* ARGSUSED */
2832a6d42e7dSPeter Dunlap int
idm_sorx_pdu_constructor(void * hdl,void * arg,int flags)2833a6d42e7dSPeter Dunlap idm_sorx_pdu_constructor(void *hdl, void *arg, int flags)
2834a6d42e7dSPeter Dunlap {
2835a6d42e7dSPeter Dunlap 	idm_pdu_t	*pdu = hdl;
2836a6d42e7dSPeter Dunlap 
2837a6d42e7dSPeter Dunlap 	bzero(pdu, sizeof (idm_pdu_t));
2838a6d42e7dSPeter Dunlap 	pdu->isp_magic = IDM_PDU_MAGIC;
2839a6d42e7dSPeter Dunlap 	pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); /* Ptr arithmetic */
2840a6d42e7dSPeter Dunlap 	pdu->isp_callback = idm_sorx_cache_pdu_cb;
2841a6d42e7dSPeter Dunlap 
2842a6d42e7dSPeter Dunlap 	return (0);
2843a6d42e7dSPeter Dunlap }
2844a6d42e7dSPeter Dunlap 
2845a6d42e7dSPeter Dunlap /* ARGSUSED */
2846a6d42e7dSPeter Dunlap static void
idm_sorx_cache_pdu_cb(idm_pdu_t * pdu,idm_status_t status)2847a6d42e7dSPeter Dunlap idm_sorx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status)
2848a6d42e7dSPeter Dunlap {
2849a6d42e7dSPeter Dunlap 	pdu->isp_iovlen = 0;
2850a6d42e7dSPeter Dunlap 	pdu->isp_sorx_buf = 0;
2851a6d42e7dSPeter Dunlap 	kmem_cache_free(idm.idm_sorx_pdu_cache, pdu);
2852a6d42e7dSPeter Dunlap }
2853a6d42e7dSPeter Dunlap 
2854a6d42e7dSPeter Dunlap static void
idm_sorx_addl_pdu_cb(idm_pdu_t * pdu,idm_status_t status)2855a6d42e7dSPeter Dunlap idm_sorx_addl_pdu_cb(idm_pdu_t *pdu, idm_status_t status)
2856a6d42e7dSPeter Dunlap {
2857a6d42e7dSPeter Dunlap 	/*
2858a6d42e7dSPeter Dunlap 	 * We had to modify our cached RX PDU with a longer header buffer
2859a6d42e7dSPeter Dunlap 	 * and/or a longer data buffer.  Release the new buffers and fix
2860a6d42e7dSPeter Dunlap 	 * the fields back to what we would expect for a cached RX PDU.
2861a6d42e7dSPeter Dunlap 	 */
2862a6d42e7dSPeter Dunlap 	if (pdu->isp_flags & IDM_PDU_ADDL_HDR) {
2863a6d42e7dSPeter Dunlap 		kmem_free(pdu->isp_hdr, pdu->isp_hdrlen);
2864a6d42e7dSPeter Dunlap 	}
2865a6d42e7dSPeter Dunlap 	if (pdu->isp_flags & IDM_PDU_ADDL_DATA) {
2866a6d42e7dSPeter Dunlap 		kmem_free(pdu->isp_data, pdu->isp_datalen);
2867a6d42e7dSPeter Dunlap 	}
2868a6d42e7dSPeter Dunlap 	pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1);
2869a6d42e7dSPeter Dunlap 	pdu->isp_hdrlen = sizeof (iscsi_hdr_t);
2870a6d42e7dSPeter Dunlap 	pdu->isp_data = NULL;
2871a6d42e7dSPeter Dunlap 	pdu->isp_datalen = 0;
2872a6d42e7dSPeter Dunlap 	pdu->isp_sorx_buf = 0;
2873a6d42e7dSPeter Dunlap 	pdu->isp_callback = idm_sorx_cache_pdu_cb;
2874a6d42e7dSPeter Dunlap 	idm_sorx_cache_pdu_cb(pdu, status);
2875a6d42e7dSPeter Dunlap }
2876a6d42e7dSPeter Dunlap 
2877a6d42e7dSPeter Dunlap /*
2878a6d42e7dSPeter Dunlap  * This thread is only active when I/O is queued for transmit
2879a6d42e7dSPeter Dunlap  * because the socket is busy.
2880a6d42e7dSPeter Dunlap  */
2881a6d42e7dSPeter Dunlap void
idm_sotx_thread(void * arg)2882a6d42e7dSPeter Dunlap idm_sotx_thread(void *arg)
2883a6d42e7dSPeter Dunlap {
2884a6d42e7dSPeter Dunlap 	idm_conn_t	*ic = arg;
2885a6d42e7dSPeter Dunlap 	idm_tx_obj_t	*object, *next;
2886a6d42e7dSPeter Dunlap 	idm_so_conn_t	*so_conn;
2887a6d42e7dSPeter Dunlap 	idm_status_t	status = IDM_STATUS_SUCCESS;
2888a6d42e7dSPeter Dunlap 
2889a6d42e7dSPeter Dunlap 	idm_conn_hold(ic);
2890a6d42e7dSPeter Dunlap 
2891a6d42e7dSPeter Dunlap 	mutex_enter(&ic->ic_mutex);
2892a6d42e7dSPeter Dunlap 	so_conn = ic->ic_transport_private;
2893a6d42e7dSPeter Dunlap 	so_conn->ic_tx_thread_running = B_TRUE;
2894a6d42e7dSPeter Dunlap 	so_conn->ic_tx_thread_did = so_conn->ic_tx_thread->t_did;
2895a6d42e7dSPeter Dunlap 	cv_signal(&ic->ic_cv);
2896a6d42e7dSPeter Dunlap 	mutex_exit(&ic->ic_mutex);
2897a6d42e7dSPeter Dunlap 
2898a6d42e7dSPeter Dunlap 	mutex_enter(&so_conn->ic_tx_mutex);
2899a6d42e7dSPeter Dunlap 
2900a6d42e7dSPeter Dunlap 	while (so_conn->ic_tx_thread_running) {
2901a6d42e7dSPeter Dunlap 		while (list_is_empty(&so_conn->ic_tx_list)) {
2902a6d42e7dSPeter Dunlap 			DTRACE_PROBE1(soconn__tx__sleep, idm_conn_t *, ic);
2903a6d42e7dSPeter Dunlap 			cv_wait(&so_conn->ic_tx_cv, &so_conn->ic_tx_mutex);
2904a6d42e7dSPeter Dunlap 			DTRACE_PROBE1(soconn__tx__wakeup, idm_conn_t *, ic);
2905a6d42e7dSPeter Dunlap 
2906a6d42e7dSPeter Dunlap 			if (!so_conn->ic_tx_thread_running) {
2907a6d42e7dSPeter Dunlap 				goto tx_bail;
2908a6d42e7dSPeter Dunlap 			}
2909a6d42e7dSPeter Dunlap 		}
2910a6d42e7dSPeter Dunlap 
2911a6d42e7dSPeter Dunlap 		object = (idm_tx_obj_t *)list_head(&so_conn->ic_tx_list);
2912a6d42e7dSPeter Dunlap 		list_remove(&so_conn->ic_tx_list, object);
2913a6d42e7dSPeter Dunlap 		mutex_exit(&so_conn->ic_tx_mutex);
2914a6d42e7dSPeter Dunlap 
2915a6d42e7dSPeter Dunlap 		switch (object->idm_tx_obj_magic) {
291660220f10SPriya Krishnan 		case IDM_PDU_MAGIC: {
291760220f10SPriya Krishnan 			idm_pdu_t *pdu = (idm_pdu_t *)object;
2918a6d42e7dSPeter Dunlap 			DTRACE_PROBE2(soconn__tx__pdu, idm_conn_t *, ic,
2919a6d42e7dSPeter Dunlap 			    idm_pdu_t *, (idm_pdu_t *)object);
2920a6d42e7dSPeter Dunlap 
292160220f10SPriya Krishnan 			if (pdu->isp_flags & IDM_PDU_SET_STATSN) {
292260220f10SPriya Krishnan 				/* No IDM task */
292360220f10SPriya Krishnan 				(ic->ic_conn_ops.icb_update_statsn)(NULL, pdu);
292460220f10SPriya Krishnan 			}
2925a6d42e7dSPeter Dunlap 			status = idm_i_so_tx((idm_pdu_t *)object);
2926a6d42e7dSPeter Dunlap 			break;
292760220f10SPriya Krishnan 		}
2928a6d42e7dSPeter Dunlap 		case IDM_BUF_MAGIC: {
2929a6d42e7dSPeter Dunlap 			idm_buf_t *idb = (idm_buf_t *)object;
2930a6d42e7dSPeter Dunlap 			idm_task_t *idt = idb->idb_task_binding;
2931a6d42e7dSPeter Dunlap 
2932a6d42e7dSPeter Dunlap 			DTRACE_PROBE2(soconn__tx__buf, idm_conn_t *, ic,
2933a6d42e7dSPeter Dunlap 			    idm_buf_t *, idb);
2934a6d42e7dSPeter Dunlap 
2935a6d42e7dSPeter Dunlap 			mutex_enter(&idt->idt_mutex);
2936a6d42e7dSPeter Dunlap 			status = idm_so_send_buf_region(idt,
293730e7468fSPeter Dunlap 			    idb, 0, idb->idb_xfer_len);
2938a6d42e7dSPeter Dunlap 
2939a6d42e7dSPeter Dunlap 			/*
2940a6d42e7dSPeter Dunlap 			 * TX thread owns the buffer so we expect it to
2941a6d42e7dSPeter Dunlap 			 * be "in transport"
2942a6d42e7dSPeter Dunlap 			 */
2943a6d42e7dSPeter Dunlap 			ASSERT(idb->idb_in_transport);
294430e7468fSPeter Dunlap 			if (IDM_CONN_ISTGT(ic)) {
294530e7468fSPeter Dunlap 				/*
294630e7468fSPeter Dunlap 				 * idm_buf_tx_to_ini_done releases
294730e7468fSPeter Dunlap 				 * idt->idt_mutex
294830e7468fSPeter Dunlap 				 */
2949a668b114SPriya Krishnan 				DTRACE_ISCSI_8(xfer__done,
2950a668b114SPriya Krishnan 				    idm_conn_t *, idt->idt_ic,
2951a668b114SPriya Krishnan 				    uintptr_t, idb->idb_buf,
2952a668b114SPriya Krishnan 				    uint32_t, idb->idb_bufoffset,
2953a668b114SPriya Krishnan 				    uint64_t, 0, uint32_t, 0, uint32_t, 0,
2954a668b114SPriya Krishnan 				    uint32_t, idb->idb_xfer_len,
2955a668b114SPriya Krishnan 				    int, XFER_BUF_TX_TO_INI);
295630e7468fSPeter Dunlap 				idm_buf_tx_to_ini_done(idt, idb, status);
295730e7468fSPeter Dunlap 			} else {
295830e7468fSPeter Dunlap 				idm_so_send_rtt_data_done(idt, idb);
295930e7468fSPeter Dunlap 				mutex_exit(&idt->idt_mutex);
296030e7468fSPeter Dunlap 			}
2961a6d42e7dSPeter Dunlap 			break;
2962a6d42e7dSPeter Dunlap 		}
2963a6d42e7dSPeter Dunlap 
2964a6d42e7dSPeter Dunlap 		default:
2965a6d42e7dSPeter Dunlap 			IDM_CONN_LOG(CE_WARN, "idm_sotx_thread: Unknown magic "
2966a6d42e7dSPeter Dunlap 			    "(0x%08x)", object->idm_tx_obj_magic);
2967a6d42e7dSPeter Dunlap 			status = IDM_STATUS_FAIL;
2968a6d42e7dSPeter Dunlap 		}
2969a6d42e7dSPeter Dunlap 
2970a6d42e7dSPeter Dunlap 		mutex_enter(&so_conn->ic_tx_mutex);
2971a6d42e7dSPeter Dunlap 
2972a6d42e7dSPeter Dunlap 		if (status != IDM_STATUS_SUCCESS) {
2973a6d42e7dSPeter Dunlap 			so_conn->ic_tx_thread_running = B_FALSE;
2974a6d42e7dSPeter Dunlap 			idm_conn_event(ic, CE_TRANSPORT_FAIL, status);
2975a6d42e7dSPeter Dunlap 		}
2976a6d42e7dSPeter Dunlap 	}
2977a6d42e7dSPeter Dunlap 
2978a6d42e7dSPeter Dunlap 	/*
2979a6d42e7dSPeter Dunlap 	 * Before we leave, we need to abort every item remaining in the
2980a6d42e7dSPeter Dunlap 	 * TX list.
2981a6d42e7dSPeter Dunlap 	 */
2982a6d42e7dSPeter Dunlap 
2983a6d42e7dSPeter Dunlap tx_bail:
2984a6d42e7dSPeter Dunlap 	object = (idm_tx_obj_t *)list_head(&so_conn->ic_tx_list);
2985a6d42e7dSPeter Dunlap 
2986a6d42e7dSPeter Dunlap 	while (object != NULL) {
2987a6d42e7dSPeter Dunlap 		next = list_next(&so_conn->ic_tx_list, object);
2988a6d42e7dSPeter Dunlap 
2989a6d42e7dSPeter Dunlap 		list_remove(&so_conn->ic_tx_list, object);
2990a6d42e7dSPeter Dunlap 		switch (object->idm_tx_obj_magic) {
2991a6d42e7dSPeter Dunlap 		case IDM_PDU_MAGIC:
2992a6d42e7dSPeter Dunlap 			idm_pdu_complete((idm_pdu_t *)object,
2993a6d42e7dSPeter Dunlap 			    IDM_STATUS_ABORTED);
2994a6d42e7dSPeter Dunlap 			break;
2995a6d42e7dSPeter Dunlap 
2996a6d42e7dSPeter Dunlap 		case IDM_BUF_MAGIC: {
2997a6d42e7dSPeter Dunlap 			idm_buf_t *idb = (idm_buf_t *)object;
2998a6d42e7dSPeter Dunlap 			idm_task_t *idt = idb->idb_task_binding;
2999a6d42e7dSPeter Dunlap 			mutex_exit(&so_conn->ic_tx_mutex);
3000a6d42e7dSPeter Dunlap 			mutex_enter(&idt->idt_mutex);
3001a6d42e7dSPeter Dunlap 			/*
3002a6d42e7dSPeter Dunlap 			 * TX thread owns the buffer so we expect it to
3003a6d42e7dSPeter Dunlap 			 * be "in transport"
3004a6d42e7dSPeter Dunlap 			 */
3005a6d42e7dSPeter Dunlap 			ASSERT(idb->idb_in_transport);
300630e7468fSPeter Dunlap 			if (IDM_CONN_ISTGT(ic)) {
300730e7468fSPeter Dunlap 				/*
300830e7468fSPeter Dunlap 				 * idm_buf_tx_to_ini_done releases
300930e7468fSPeter Dunlap 				 * idt->idt_mutex
301030e7468fSPeter Dunlap 				 */
3011a668b114SPriya Krishnan 				DTRACE_ISCSI_8(xfer__done,
3012a668b114SPriya Krishnan 				    idm_conn_t *, idt->idt_ic,
3013a668b114SPriya Krishnan 				    uintptr_t, idb->idb_buf,
3014a668b114SPriya Krishnan 				    uint32_t, idb->idb_bufoffset,
3015a668b114SPriya Krishnan 				    uint64_t, 0, uint32_t, 0, uint32_t, 0,
3016a668b114SPriya Krishnan 				    uint32_t, idb->idb_xfer_len,
3017a668b114SPriya Krishnan 				    int, XFER_BUF_TX_TO_INI);
301830e7468fSPeter Dunlap 				idm_buf_tx_to_ini_done(idt, idb,
301930e7468fSPeter Dunlap 				    IDM_STATUS_ABORTED);
302030e7468fSPeter Dunlap 			} else {
302130e7468fSPeter Dunlap 				idm_so_send_rtt_data_done(idt, idb);
302230e7468fSPeter Dunlap 				mutex_exit(&idt->idt_mutex);
302330e7468fSPeter Dunlap 			}
3024a6d42e7dSPeter Dunlap 			mutex_enter(&so_conn->ic_tx_mutex);
3025a6d42e7dSPeter Dunlap 			break;
3026a6d42e7dSPeter Dunlap 		}
3027a6d42e7dSPeter Dunlap 		default:
3028a6d42e7dSPeter Dunlap 			IDM_CONN_LOG(CE_WARN,
3029a6d42e7dSPeter Dunlap 			    "idm_sotx_thread: Unexpected magic "
3030a6d42e7dSPeter Dunlap 			    "(0x%08x)", object->idm_tx_obj_magic);
3031a6d42e7dSPeter Dunlap 		}
3032a6d42e7dSPeter Dunlap 
3033a6d42e7dSPeter Dunlap 		object = next;
3034a6d42e7dSPeter Dunlap 	}
3035a6d42e7dSPeter Dunlap 
3036a6d42e7dSPeter Dunlap 	mutex_exit(&so_conn->ic_tx_mutex);
3037a6d42e7dSPeter Dunlap 	idm_conn_rele(ic);
3038a6d42e7dSPeter Dunlap 	thread_exit();
3039a6d42e7dSPeter Dunlap 	/*NOTREACHED*/
3040a6d42e7dSPeter Dunlap }
3041aff4bce5Syi zhang - Sun Microsystems - Beijing China 
3042aff4bce5Syi zhang - Sun Microsystems - Beijing China static void
idm_so_socket_set_nonblock(struct sonode * node)3043aff4bce5Syi zhang - Sun Microsystems - Beijing China idm_so_socket_set_nonblock(struct sonode *node)
3044aff4bce5Syi zhang - Sun Microsystems - Beijing China {
3045aff4bce5Syi zhang - Sun Microsystems - Beijing China 	(void) VOP_SETFL(node->so_vnode, node->so_flag,
3046aff4bce5Syi zhang - Sun Microsystems - Beijing China 	    (node->so_state | FNONBLOCK), CRED(), NULL);
3047aff4bce5Syi zhang - Sun Microsystems - Beijing China }
3048aff4bce5Syi zhang - Sun Microsystems - Beijing China 
3049aff4bce5Syi zhang - Sun Microsystems - Beijing China static void
idm_so_socket_set_block(struct sonode * node)3050aff4bce5Syi zhang - Sun Microsystems - Beijing China idm_so_socket_set_block(struct sonode *node)
3051aff4bce5Syi zhang - Sun Microsystems - Beijing China {
3052aff4bce5Syi zhang - Sun Microsystems - Beijing China 	(void) VOP_SETFL(node->so_vnode, node->so_flag,
3053aff4bce5Syi zhang - Sun Microsystems - Beijing China 	    (node->so_state & (~FNONBLOCK)), CRED(), NULL);
3054aff4bce5Syi zhang - Sun Microsystems - Beijing China }
3055bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3056bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3057bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /*
3058bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States  * Called by kernel sockets when the connection has been accepted or
3059bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States  * rejected. In early volo, a "disconnect" callback was sent instead of
3060bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States  * "connectfailed", so we check for both.
3061bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States  */
3062bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /* ARGSUSED */
3063bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States void
idm_so_timed_socket_connect_cb(ksocket_t ks,ksocket_callback_event_t ev,void * arg,uintptr_t info)3064bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_so_timed_socket_connect_cb(ksocket_t ks,
3065bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States     ksocket_callback_event_t ev, void *arg, uintptr_t info)
3066bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States {
3067bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	idm_so_timed_socket_t	*itp = arg;
3068bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	ASSERT(itp != NULL);
3069bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	ASSERT(ev == KSOCKET_EV_CONNECTED ||
3070bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	    ev == KSOCKET_EV_CONNECTFAILED ||
3071bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	    ev == KSOCKET_EV_DISCONNECTED);
3072bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3073bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	mutex_enter(&idm_so_timed_socket_mutex);
3074bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	itp->it_callback_called = B_TRUE;
3075bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	if (ev == KSOCKET_EV_CONNECTED) {
3076bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		itp->it_socket_error_code = 0;
3077bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	} else {
3078bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		/* Make sure the error code is non-zero on error */
3079bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		if (info == 0)
3080bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			info = ECONNRESET;
3081bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		itp->it_socket_error_code = (int)info;
3082bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	}
3083bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	cv_signal(&itp->it_cv);
3084bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	mutex_exit(&idm_so_timed_socket_mutex);
3085bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States }
3086bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3087bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States int
idm_so_timed_socket_connect(ksocket_t ks,struct sockaddr_storage * sa,int sa_sz,int login_max_usec)3088bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_so_timed_socket_connect(ksocket_t ks,
3089bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States     struct sockaddr_storage *sa, int sa_sz, int login_max_usec)
3090bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States {
3091bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	clock_t			conn_login_max;
3092bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	int			rc, nonblocking, rval;
3093bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	idm_so_timed_socket_t	it;
3094bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	ksocket_callbacks_t	ks_cb;
3095bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3096bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	conn_login_max = ddi_get_lbolt() + drv_usectohz(login_max_usec);
3097bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3098bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	/*
3099bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	 * Set to non-block socket mode, with callback on connect
3100bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	 * Early volo used "disconnected" instead of "connectfailed",
3101bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	 * so set callback to look for both.
3102bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	 */
3103bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	bzero(&it, sizeof (it));
3104bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	ks_cb.ksock_cb_flags = KSOCKET_CB_CONNECTED |
3105bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	    KSOCKET_CB_CONNECTFAILED | KSOCKET_CB_DISCONNECTED;
3106bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	ks_cb.ksock_cb_connected = idm_so_timed_socket_connect_cb;
3107bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	ks_cb.ksock_cb_connectfailed = idm_so_timed_socket_connect_cb;
3108bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	ks_cb.ksock_cb_disconnected = idm_so_timed_socket_connect_cb;
3109bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	cv_init(&it.it_cv, NULL, CV_DEFAULT, NULL);
3110bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	rc = ksocket_setcallbacks(ks, &ks_cb, &it, CRED());
3111bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	if (rc != 0)
3112bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		return (rc);
3113bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3114bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	/* Set to non-blocking mode */
3115bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	nonblocking = 1;
3116bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	rc = ksocket_ioctl(ks, FIONBIO, (intptr_t)&nonblocking, &rval,
3117bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	    CRED());
3118bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	if (rc != 0)
3119bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		goto cleanup;
3120bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3121bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	bzero(&it, sizeof (it));
3122bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	for (;;) {
3123bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		/*
3124bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		 * Warning -- in a loopback scenario, the call to
3125bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		 * the connect_cb can occur inside the call to
3126bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		 * ksocket_connect. Do not hold the mutex around the
3127bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		 * call to ksocket_connect.
3128bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		 */
3129bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		rc = ksocket_connect(ks, (struct sockaddr *)sa, sa_sz, CRED());
3130bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		if (rc == 0 || rc == EISCONN) {
3131bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			/* socket success or already success */
3132bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			rc = 0;
3133bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			break;
3134bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		}
3135bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		if ((rc != EINPROGRESS) && (rc != EALREADY)) {
3136bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			break;
3137bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		}
3138bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3139bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		/* TCP connect still in progress. See if out of time. */
3140bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		if (ddi_get_lbolt() > conn_login_max) {
3141bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			/*
3142bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			 * Connection retry timeout,
3143bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			 * failed connect to target.
3144bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			 */
3145bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			rc = ETIMEDOUT;
3146bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			break;
3147bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		}
3148bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3149bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		/*
3150bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		 * TCP connect still in progress.  Sleep until callback.
3151bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		 * Do NOT go to sleep if the callback already occurred!
3152bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		 */
3153bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		mutex_enter(&idm_so_timed_socket_mutex);
3154bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		if (!it.it_callback_called) {
3155bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			(void) cv_timedwait(&it.it_cv,
3156bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			    &idm_so_timed_socket_mutex, conn_login_max);
3157bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		}
3158bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		if (it.it_callback_called) {
3159bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			rc = it.it_socket_error_code;
3160bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			mutex_exit(&idm_so_timed_socket_mutex);
3161bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 			break;
3162bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		}
3163bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		/* If timer expires, go call ksocket_connect one last time. */
3164bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		mutex_exit(&idm_so_timed_socket_mutex);
3165bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	}
3166bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3167bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	/* resume blocking mode */
3168bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	nonblocking = 0;
3169aedf2b3bSsrivijitha dugganapalli 	(void) ksocket_ioctl(ks, FIONBIO, (intptr_t)&nonblocking, &rval,
3170bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	    CRED());
3171bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States cleanup:
3172aedf2b3bSsrivijitha dugganapalli 	(void) ksocket_setcallbacks(ks, NULL, NULL, CRED());
3173bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	cv_destroy(&it.it_cv);
3174bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	if (rc != 0) {
3175bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		idm_soshutdown(ks);
3176bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	}
3177bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	return (rc);
3178bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States }
3179bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3180bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3181bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States void
idm_addr_to_sa(idm_addr_t * dportal,struct sockaddr_storage * sa)3182bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_addr_to_sa(idm_addr_t *dportal, struct sockaddr_storage *sa)
3183bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States {
3184bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	int			dp_addr_size;
3185bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	struct sockaddr_in	*sin;
3186bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	struct sockaddr_in6	*sin6;
3187bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3188bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	/* Build sockaddr_storage for this portal (idm_addr_t) */
3189bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	bzero(sa, sizeof (*sa));
3190bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	dp_addr_size = dportal->a_addr.i_insize;
3191bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	if (dp_addr_size == sizeof (struct in_addr)) {
3192bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		/* IPv4 */
3193bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		sa->ss_family = AF_INET;
3194bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		sin = (struct sockaddr_in *)sa;
3195bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		sin->sin_port = htons(dportal->a_port);
3196bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		bcopy(&dportal->a_addr.i_addr.in4,
3197bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		    &sin->sin_addr, sizeof (struct in_addr));
3198bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	} else if (dp_addr_size == sizeof (struct in6_addr)) {
3199bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		/* IPv6 */
3200bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		sa->ss_family = AF_INET6;
3201bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		sin6 = (struct sockaddr_in6 *)sa;
3202bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		sin6->sin6_port = htons(dportal->a_port);
3203bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		bcopy(&dportal->a_addr.i_addr.in6,
3204bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		    &sin6->sin6_addr, sizeof (struct in6_addr));
3205bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	} else {
3206bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		ASSERT(0);
3207bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	}
3208bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States }
3209bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3210bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3211bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /*
3212bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States  * return a human-readable form of a sockaddr_storage, in the form
3213bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States  * [ip-address]:port.  This is used in calls to logging functions.
3214bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States  * If several calls to idm_sa_ntop are made within the same invocation
3215bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States  * of a logging function, then each one needs its own buf.
3216bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States  */
3217bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States const char *
idm_sa_ntop(const struct sockaddr_storage * sa,char * buf,size_t size)3218bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_sa_ntop(const struct sockaddr_storage *sa,
3219bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States     char *buf, size_t size)
3220bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States {
3221bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	static const char bogus_ip[] = "[0].-1";
3222bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	char tmp[INET6_ADDRSTRLEN];
3223bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 
3224bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	switch (sa->ss_family) {
32250b905b49SYuri Pankov 	case AF_INET6: {
32260b905b49SYuri Pankov 		const struct sockaddr_in6 *in6 =
32270b905b49SYuri Pankov 		    (const struct sockaddr_in6 *) sa;
32280b905b49SYuri Pankov 
32290b905b49SYuri Pankov 		(void) inet_ntop(in6->sin6_family, &in6->sin6_addr, tmp,
32300b905b49SYuri Pankov 		    sizeof (tmp));
32310b905b49SYuri Pankov 		if (strlen(tmp) + sizeof ("[].65535") > size)
32320b905b49SYuri Pankov 			goto err;
32330b905b49SYuri Pankov 		/* struct sockaddr_storage gets port info from v4 loc */
32340b905b49SYuri Pankov 		(void) snprintf(buf, size, "[%s].%u", tmp,
32350b905b49SYuri Pankov 		    ntohs(in6->sin6_port));
32360b905b49SYuri Pankov 		return (buf);
32370b905b49SYuri Pankov 	}
32380b905b49SYuri Pankov 	case AF_INET: {
32390b905b49SYuri Pankov 		const struct sockaddr_in *in = (const struct sockaddr_in *) sa;
32400b905b49SYuri Pankov 
32410b905b49SYuri Pankov 		(void) inet_ntop(in->sin_family, &in->sin_addr, tmp,
32420b905b49SYuri Pankov 		    sizeof (tmp));
32430b905b49SYuri Pankov 		if (strlen(tmp) + sizeof ("[].65535") > size)
3244bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 				goto err;
32450b905b49SYuri Pankov 		(void) snprintf(buf, size,  "[%s].%u", tmp,
32460b905b49SYuri Pankov 		    ntohs(in->sin_port));
32470b905b49SYuri Pankov 		return (buf);
32480b905b49SYuri Pankov 	}
3249bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	default:
3250bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 		break;
3251bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	}
3252bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States err:
3253bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	(void) snprintf(buf, size, "%s", bogus_ip);
3254bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States 	return (buf);
3255bdbe8dc6SPeter Cudhea - Sun Microsystems - Burlington, MA United States }
3256