xref: /titanic_50/usr/src/uts/common/io/idm/idm_so.c (revision 60471b7bbfab236de7d8776aed871d919c5f81c3)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/conf.h>
27 #include <sys/stat.h>
28 #include <sys/file.h>
29 #include <sys/ddi.h>
30 #include <sys/sunddi.h>
31 #include <sys/modctl.h>
32 #include <sys/priv.h>
33 #include <sys/cpuvar.h>
34 #include <sys/socket.h>
35 #include <sys/strsubr.h>
36 #include <sys/sysmacros.h>
37 #include <sys/sdt.h>
38 #include <netinet/tcp.h>
39 #include <inet/tcp.h>
40 #include <sys/socketvar.h>
41 #include <sys/pathname.h>
42 #include <sys/fs/snode.h>
43 #include <sys/fs/dv_node.h>
44 #include <sys/vnode.h>
45 #include <netinet/in.h>
46 #include <net/if.h>
47 #include <sys/sockio.h>
48 #include <sys/ksocket.h>
49 #include <sys/filio.h>		/* FIONBIO */
50 #include <sys/iscsi_protocol.h>
51 #include <sys/idm/idm.h>
52 #include <sys/idm/idm_so.h>
53 #include <sys/idm/idm_text.h>
54 
55 #define	IN_PROGRESS_DELAY	1
56 
57 /*
58  * in6addr_any is currently all zeroes, but use the macro in case this
59  * ever changes.
60  */
61 static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
62 
63 static void idm_sorx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status);
64 static void idm_sorx_addl_pdu_cb(idm_pdu_t *pdu, idm_status_t status);
65 static void idm_sotx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status);
66 
67 static idm_status_t idm_so_conn_create_common(idm_conn_t *ic, ksocket_t new_so);
68 static void idm_so_conn_destroy_common(idm_conn_t *ic);
69 static void idm_so_conn_connect_common(idm_conn_t *ic);
70 
71 static void idm_set_ini_preconnect_options(idm_so_conn_t *sc);
72 static void idm_set_ini_postconnect_options(idm_so_conn_t *sc);
73 static void idm_set_tgt_connect_options(ksocket_t so);
74 static idm_status_t idm_i_so_tx(idm_pdu_t *pdu);
75 
76 static idm_status_t idm_sorecvdata(idm_conn_t *ic, idm_pdu_t *pdu);
77 static void idm_so_send_rtt_data(idm_conn_t *ic, idm_task_t *idt,
78     idm_buf_t *idb, uint32_t offset, uint32_t length);
79 static void idm_so_send_rtt_data_done(idm_task_t *idt, idm_buf_t *idb);
80 static idm_status_t idm_so_send_buf_region(idm_task_t *idt,
81     idm_buf_t *idb, uint32_t buf_region_offset, uint32_t buf_region_length);
82 
83 static uint32_t idm_fill_iov(idm_pdu_t *pdu, idm_buf_t *idb,
84     uint32_t ro, uint32_t dlength);
85 
86 static idm_status_t idm_so_handle_digest(idm_conn_t *it,
87     nvpair_t *digest_choice, const idm_kv_xlate_t *ikvx);
88 
89 static void idm_so_socket_set_nonblock(struct sonode *node);
90 static void idm_so_socket_set_block(struct sonode *node);
91 
92 /*
93  * Transport ops prototypes
94  */
95 static void idm_so_tx(idm_conn_t *ic, idm_pdu_t *pdu);
96 static idm_status_t idm_so_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb);
97 static idm_status_t idm_so_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb);
98 static void idm_so_rx_datain(idm_conn_t *ic, idm_pdu_t *pdu);
99 static void idm_so_rx_rtt(idm_conn_t *ic, idm_pdu_t *pdu);
100 static void idm_so_rx_dataout(idm_conn_t *ic, idm_pdu_t *pdu);
101 static idm_status_t idm_so_free_task_rsrc(idm_task_t *idt);
102 static kv_status_t idm_so_negotiate_key_values(idm_conn_t *it,
103     nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl);
104 static void idm_so_notice_key_values(idm_conn_t *it,
105     nvlist_t *negotiated_nvl);
106 static kv_status_t idm_so_declare_key_values(idm_conn_t *it,
107     nvlist_t *config_nvl, nvlist_t *outgoing_nvl);
108 static boolean_t idm_so_conn_is_capable(idm_conn_req_t *ic,
109     idm_transport_caps_t *caps);
110 static idm_status_t idm_so_buf_alloc(idm_buf_t *idb, uint64_t buflen);
111 static void idm_so_buf_free(idm_buf_t *idb);
112 static idm_status_t idm_so_buf_setup(idm_buf_t *idb);
113 static void idm_so_buf_teardown(idm_buf_t *idb);
114 static idm_status_t idm_so_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t *is);
115 static void idm_so_tgt_svc_destroy(idm_svc_t *is);
116 static idm_status_t idm_so_tgt_svc_online(idm_svc_t *is);
117 static void idm_so_tgt_svc_offline(idm_svc_t *is);
118 static void idm_so_tgt_conn_destroy(idm_conn_t *ic);
119 static idm_status_t idm_so_tgt_conn_connect(idm_conn_t *ic);
120 static void idm_so_conn_disconnect(idm_conn_t *ic);
121 static idm_status_t idm_so_ini_conn_create(idm_conn_req_t *cr, idm_conn_t *ic);
122 static void idm_so_ini_conn_destroy(idm_conn_t *ic);
123 static idm_status_t idm_so_ini_conn_connect(idm_conn_t *ic);
124 
125 /*
126  * IDM Native Sockets transport operations
127  */
128 static
129 idm_transport_ops_t idm_so_transport_ops = {
130 	idm_so_tx,			/* it_tx_pdu */
131 	idm_so_buf_tx_to_ini,		/* it_buf_tx_to_ini */
132 	idm_so_buf_rx_from_ini,		/* it_buf_rx_from_ini */
133 	idm_so_rx_datain,		/* it_rx_datain */
134 	idm_so_rx_rtt,			/* it_rx_rtt */
135 	idm_so_rx_dataout,		/* it_rx_dataout */
136 	NULL,				/* it_alloc_conn_rsrc */
137 	NULL,				/* it_free_conn_rsrc */
138 	NULL,				/* it_tgt_enable_datamover */
139 	NULL,				/* it_ini_enable_datamover */
140 	NULL,				/* it_conn_terminate */
141 	idm_so_free_task_rsrc,		/* it_free_task_rsrc */
142 	idm_so_negotiate_key_values,	/* it_negotiate_key_values */
143 	idm_so_notice_key_values,	/* it_notice_key_values */
144 	idm_so_conn_is_capable,		/* it_conn_is_capable */
145 	idm_so_buf_alloc,		/* it_buf_alloc */
146 	idm_so_buf_free,		/* it_buf_free */
147 	idm_so_buf_setup,		/* it_buf_setup */
148 	idm_so_buf_teardown,		/* it_buf_teardown */
149 	idm_so_tgt_svc_create,		/* it_tgt_svc_create */
150 	idm_so_tgt_svc_destroy,		/* it_tgt_svc_destroy */
151 	idm_so_tgt_svc_online,		/* it_tgt_svc_online */
152 	idm_so_tgt_svc_offline,		/* it_tgt_svc_offline */
153 	idm_so_tgt_conn_destroy,	/* it_tgt_conn_destroy */
154 	idm_so_tgt_conn_connect,	/* it_tgt_conn_connect */
155 	idm_so_conn_disconnect,		/* it_tgt_conn_disconnect */
156 	idm_so_ini_conn_create,		/* it_ini_conn_create */
157 	idm_so_ini_conn_destroy,	/* it_ini_conn_destroy */
158 	idm_so_ini_conn_connect,	/* it_ini_conn_connect */
159 	idm_so_conn_disconnect,		/* it_ini_conn_disconnect */
160 	idm_so_declare_key_values	/* it_declare_key_values */
161 };
162 
163 kmutex_t	idm_so_timed_socket_mutex;
164 /*
165  * idm_so_init()
166  * Sockets transport initialization
167  */
168 void
169 idm_so_init(idm_transport_t *it)
170 {
171 	/* Cache for IDM Data and R2T Transmit PDU's */
172 	idm.idm_sotx_pdu_cache = kmem_cache_create("idm_tx_pdu_cache",
173 	    sizeof (idm_pdu_t) + sizeof (iscsi_hdr_t), 8,
174 	    &idm_sotx_pdu_constructor, NULL, NULL, NULL, NULL, KM_SLEEP);
175 
176 	/* Cache for IDM Receive PDU's */
177 	idm.idm_sorx_pdu_cache = kmem_cache_create("idm_rx_pdu_cache",
178 	    sizeof (idm_pdu_t) + IDM_SORX_CACHE_HDRLEN, 8,
179 	    &idm_sorx_pdu_constructor, NULL, NULL, NULL, NULL, KM_SLEEP);
180 
181 	/* 128k buffer cache */
182 	idm.idm_so_128k_buf_cache = kmem_cache_create("idm_128k_buf_cache",
183 	    IDM_SO_BUF_CACHE_UB, 8, NULL, NULL, NULL, NULL, NULL, KM_SLEEP);
184 
185 	/* Set the sockets transport ops */
186 	it->it_ops = &idm_so_transport_ops;
187 
188 	mutex_init(&idm_so_timed_socket_mutex, NULL, MUTEX_DEFAULT, NULL);
189 
190 }
191 
192 /*
193  * idm_so_fini()
194  * Sockets transport teardown
195  */
196 void
197 idm_so_fini(void)
198 {
199 	kmem_cache_destroy(idm.idm_so_128k_buf_cache);
200 	kmem_cache_destroy(idm.idm_sotx_pdu_cache);
201 	kmem_cache_destroy(idm.idm_sorx_pdu_cache);
202 	mutex_destroy(&idm_so_timed_socket_mutex);
203 }
204 
205 ksocket_t
206 idm_socreate(int domain, int type, int protocol)
207 {
208 	ksocket_t ks;
209 
210 	if (!ksocket_socket(&ks, domain, type, protocol, KSOCKET_NOSLEEP,
211 	    CRED())) {
212 		return (ks);
213 	} else {
214 		return (NULL);
215 	}
216 }
217 
218 /*
219  * idm_soshutdown will disconnect the socket and prevent subsequent PDU
220  * reception and transmission.  The sonode still exists but its state
221  * gets modified to indicate it is no longer connected.  Calls to
222  * idm_sorecv/idm_iov_sorecv will return so idm_soshutdown can be used
223  * regain control of a thread stuck in idm_sorecv.
224  */
225 void
226 idm_soshutdown(ksocket_t so)
227 {
228 	(void) ksocket_shutdown(so, SHUT_RDWR, CRED());
229 }
230 
231 /*
232  * idm_sodestroy releases all resources associated with a socket previously
233  * created with idm_socreate.  The socket must be shutdown using
234  * idm_soshutdown before the socket is destroyed with idm_sodestroy,
235  * otherwise undefined behavior will result.
236  */
237 void
238 idm_sodestroy(ksocket_t ks)
239 {
240 	(void) ksocket_close(ks, CRED());
241 }
242 
243 /*
244  * Function to compare two addresses in sockaddr_storage format
245  */
246 
247 int
248 idm_ss_compare(const struct sockaddr_storage *cmp_ss1,
249     const struct sockaddr_storage *cmp_ss2,
250     boolean_t v4_mapped_as_v4,
251     boolean_t compare_ports)
252 {
253 	struct sockaddr_storage			mapped_v4_ss1, mapped_v4_ss2;
254 	const struct sockaddr_storage		*ss1, *ss2;
255 	struct in_addr				*in1, *in2;
256 	struct in6_addr				*in61, *in62;
257 	int i;
258 
259 	/*
260 	 * Normalize V4-mapped IPv6 addresses into V4 format if
261 	 * v4_mapped_as_v4 is B_TRUE.
262 	 */
263 	ss1 = cmp_ss1;
264 	ss2 = cmp_ss2;
265 	if (v4_mapped_as_v4 && (ss1->ss_family == AF_INET6)) {
266 		in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr;
267 		if (IN6_IS_ADDR_V4MAPPED(in61)) {
268 			bzero(&mapped_v4_ss1, sizeof (mapped_v4_ss1));
269 			mapped_v4_ss1.ss_family = AF_INET;
270 			((struct sockaddr_in *)&mapped_v4_ss1)->sin_port =
271 			    ((struct sockaddr_in *)ss1)->sin_port;
272 			IN6_V4MAPPED_TO_INADDR(in61,
273 			    &((struct sockaddr_in *)&mapped_v4_ss1)->sin_addr);
274 			ss1 = &mapped_v4_ss1;
275 		}
276 	}
277 	ss2 = cmp_ss2;
278 	if (v4_mapped_as_v4 && (ss2->ss_family == AF_INET6)) {
279 		in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr;
280 		if (IN6_IS_ADDR_V4MAPPED(in62)) {
281 			bzero(&mapped_v4_ss2, sizeof (mapped_v4_ss2));
282 			mapped_v4_ss2.ss_family = AF_INET;
283 			((struct sockaddr_in *)&mapped_v4_ss2)->sin_port =
284 			    ((struct sockaddr_in *)ss2)->sin_port;
285 			IN6_V4MAPPED_TO_INADDR(in62,
286 			    &((struct sockaddr_in *)&mapped_v4_ss2)->sin_addr);
287 			ss2 = &mapped_v4_ss2;
288 		}
289 	}
290 
291 	/*
292 	 * Compare ports, then address family, then ip address
293 	 */
294 	if (compare_ports &&
295 	    (((struct sockaddr_in *)ss1)->sin_port !=
296 	    ((struct sockaddr_in *)ss2)->sin_port)) {
297 		if (((struct sockaddr_in *)ss1)->sin_port >
298 		    ((struct sockaddr_in *)ss2)->sin_port)
299 			return (1);
300 		else
301 			return (-1);
302 	}
303 
304 	/*
305 	 * ports are the same
306 	 */
307 	if (ss1->ss_family != ss2->ss_family) {
308 		if (ss1->ss_family == AF_INET)
309 			return (1);
310 		else
311 			return (-1);
312 	}
313 
314 	/*
315 	 * address families are the same
316 	 */
317 	if (ss1->ss_family == AF_INET) {
318 		in1 = &((struct sockaddr_in *)ss1)->sin_addr;
319 		in2 = &((struct sockaddr_in *)ss2)->sin_addr;
320 
321 		if (in1->s_addr > in2->s_addr)
322 			return (1);
323 		else if (in1->s_addr < in2->s_addr)
324 			return (-1);
325 		else
326 			return (0);
327 	} else if (ss1->ss_family == AF_INET6) {
328 		in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr;
329 		in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr;
330 
331 		for (i = 0; i < 4; i++) {
332 			if (in61->s6_addr32[i] > in62->s6_addr32[i])
333 				return (1);
334 			else if (in61->s6_addr32[i] < in62->s6_addr32[i])
335 				return (-1);
336 		}
337 		return (0);
338 	}
339 
340 	return (1);
341 }
342 
343 /*
344  * IP address filter functions to flag addresses that should not
345  * go out to initiators through discovery.
346  */
347 static boolean_t
348 idm_v4_addr_okay(struct in_addr *in_addr)
349 {
350 	in_addr_t addr = ntohl(in_addr->s_addr);
351 
352 	if ((INADDR_NONE == addr) ||
353 	    (IN_MULTICAST(addr)) ||
354 	    ((addr >> IN_CLASSA_NSHIFT) == 0) ||
355 	    ((addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)) {
356 		return (B_FALSE);
357 	}
358 	return (B_TRUE);
359 }
360 
361 static boolean_t
362 idm_v6_addr_okay(struct in6_addr *addr6)
363 {
364 
365 	if ((IN6_IS_ADDR_UNSPECIFIED(addr6)) ||
366 	    (IN6_IS_ADDR_LOOPBACK(addr6)) ||
367 	    (IN6_IS_ADDR_MULTICAST(addr6)) ||
368 	    (IN6_IS_ADDR_V4MAPPED(addr6)) ||
369 	    (IN6_IS_ADDR_V4COMPAT(addr6)) ||
370 	    (IN6_IS_ADDR_LINKLOCAL(addr6))) {
371 		return (B_FALSE);
372 	}
373 	return (B_TRUE);
374 }
375 
376 /*
377  * idm_get_ipaddr will retrieve a list of IP Addresses which the host is
378  * configured with by sending down a sequence of kernel ioctl to IP STREAMS.
379  */
380 int
381 idm_get_ipaddr(idm_addr_list_t **ipaddr_p)
382 {
383 	ksocket_t 		so4, so6;
384 	struct lifnum		lifn;
385 	struct lifconf		lifc;
386 	struct lifreq		*lp;
387 	int			rval;
388 	int			numifs;
389 	int			bufsize;
390 	void			*buf;
391 	int			i, j, n, rc;
392 	struct sockaddr_storage	ss;
393 	struct sockaddr_in	*sin;
394 	struct sockaddr_in6	*sin6;
395 	idm_addr_t		*ip;
396 	idm_addr_list_t		*ipaddr;
397 	int			size_ipaddr;
398 
399 	*ipaddr_p = NULL;
400 	size_ipaddr = 0;
401 	buf = NULL;
402 
403 	/* create an ipv4 and ipv6 UDP socket */
404 	if ((so6 = idm_socreate(PF_INET6, SOCK_DGRAM, 0)) == NULL)
405 		return (0);
406 	if ((so4 = idm_socreate(PF_INET, SOCK_DGRAM, 0)) == NULL) {
407 		idm_sodestroy(so6);
408 		return (0);
409 	}
410 
411 
412 retry_count:
413 	/* snapshot the current number of interfaces */
414 	lifn.lifn_family = PF_UNSPEC;
415 	lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
416 	lifn.lifn_count = 0;
417 	/* use vp6 for ioctls with unspecified families by default */
418 	if (ksocket_ioctl(so6, SIOCGLIFNUM, (intptr_t)&lifn, &rval, CRED())
419 	    != 0) {
420 		goto cleanup;
421 	}
422 
423 	numifs = lifn.lifn_count;
424 	if (numifs <= 0) {
425 		goto cleanup;
426 	}
427 
428 	/* allocate extra room in case more interfaces appear */
429 	numifs += 10;
430 
431 	/* get the interface names and ip addresses */
432 	bufsize = numifs * sizeof (struct lifreq);
433 	buf = kmem_alloc(bufsize, KM_SLEEP);
434 
435 	lifc.lifc_family = AF_UNSPEC;
436 	lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
437 	lifc.lifc_len = bufsize;
438 	lifc.lifc_buf = buf;
439 	rc = ksocket_ioctl(so6, SIOCGLIFCONF, (intptr_t)&lifc, &rval, CRED());
440 	if (rc != 0) {
441 		goto cleanup;
442 	}
443 	/* if our extra room is used up, try again */
444 	if (bufsize <= lifc.lifc_len) {
445 		kmem_free(buf, bufsize);
446 		buf = NULL;
447 		goto retry_count;
448 	}
449 	/* calc actual number of ifconfs */
450 	n = lifc.lifc_len / sizeof (struct lifreq);
451 
452 	/* get ip address */
453 	if (n > 0) {
454 		size_ipaddr = sizeof (idm_addr_list_t) +
455 		    (n - 1) * sizeof (idm_addr_t);
456 		ipaddr = kmem_zalloc(size_ipaddr, KM_SLEEP);
457 	} else {
458 		goto cleanup;
459 	}
460 
461 	/*
462 	 * Examine the array of interfaces and filter uninteresting ones
463 	 */
464 	for (i = 0, j = 0, lp = lifc.lifc_req; i < n; i++, lp++) {
465 
466 		/*
467 		 * Copy the address as the SIOCGLIFFLAGS ioctl is destructive
468 		 */
469 		ss = lp->lifr_addr;
470 		/*
471 		 * fetch the flags using the socket of the correct family
472 		 */
473 		switch (ss.ss_family) {
474 		case AF_INET:
475 			rc = ksocket_ioctl(so4, SIOCGLIFFLAGS, (intptr_t)lp,
476 			    &rval, CRED());
477 			break;
478 		case AF_INET6:
479 			rc = ksocket_ioctl(so6, SIOCGLIFFLAGS, (intptr_t)lp,
480 			    &rval, CRED());
481 			break;
482 		default:
483 			continue;
484 		}
485 		if (rc == 0) {
486 			/*
487 			 * If we got the flags, skip uninteresting
488 			 * interfaces based on flags
489 			 */
490 			if ((lp->lifr_flags & IFF_UP) != IFF_UP)
491 				continue;
492 			if (lp->lifr_flags &
493 			    (IFF_ANYCAST|IFF_NOLOCAL|IFF_DEPRECATED))
494 				continue;
495 		}
496 
497 		/* save ip address */
498 		ip = &ipaddr->al_addrs[j];
499 		switch (ss.ss_family) {
500 		case AF_INET:
501 			sin = (struct sockaddr_in *)&ss;
502 			if (!idm_v4_addr_okay(&sin->sin_addr))
503 				continue;
504 			ip->a_addr.i_addr.in4 = sin->sin_addr;
505 			ip->a_addr.i_insize = sizeof (struct in_addr);
506 			break;
507 		case AF_INET6:
508 			sin6 = (struct sockaddr_in6 *)&ss;
509 			if (!idm_v6_addr_okay(&sin6->sin6_addr))
510 				continue;
511 			ip->a_addr.i_addr.in6 = sin6->sin6_addr;
512 			ip->a_addr.i_insize = sizeof (struct in6_addr);
513 			break;
514 		default:
515 			continue;
516 		}
517 		j++;
518 	}
519 
520 	if (j == 0) {
521 		/* no valid ifaddr */
522 		kmem_free(ipaddr, size_ipaddr);
523 		size_ipaddr = 0;
524 		ipaddr = NULL;
525 	} else {
526 		ipaddr->al_out_cnt = j;
527 	}
528 
529 
530 cleanup:
531 	idm_sodestroy(so6);
532 	idm_sodestroy(so4);
533 
534 	if (buf != NULL)
535 		kmem_free(buf, bufsize);
536 
537 	*ipaddr_p = ipaddr;
538 	return (size_ipaddr);
539 }
540 
541 int
542 idm_sorecv(ksocket_t so, void *msg, size_t len)
543 {
544 	iovec_t iov;
545 
546 	ASSERT(so != NULL);
547 	ASSERT(len != 0);
548 
549 	/*
550 	 * Fill in iovec and receive data
551 	 */
552 	iov.iov_base = msg;
553 	iov.iov_len = len;
554 
555 	return (idm_iov_sorecv(so, &iov, 1, len));
556 }
557 
558 /*
559  * idm_sosendto - Sends a buffered data on a non-connected socket.
560  *
561  * This function puts the data provided on the wire by calling sosendmsg.
562  * It will return only when all the data has been sent or if an error
563  * occurs.
564  *
565  * Returns 0 for success, the socket errno value if sosendmsg fails, and
566  * -1 if sosendmsg returns success but uio_resid != 0
567  */
568 int
569 idm_sosendto(ksocket_t so, void *buff, size_t len,
570     struct sockaddr *name, socklen_t namelen)
571 {
572 	struct msghdr		msg;
573 	struct iovec		iov[1];
574 	int			error;
575 	size_t			sent = 0;
576 
577 	iov[0].iov_base	= buff;
578 	iov[0].iov_len	= len;
579 
580 	/* Initialization of the message header. */
581 	bzero(&msg, sizeof (msg));
582 	msg.msg_iov	= iov;
583 	msg.msg_iovlen	= 1;
584 	msg.msg_name	= name;
585 	msg.msg_namelen	= namelen;
586 
587 	if ((error = ksocket_sendmsg(so, &msg, 0, &sent, CRED())) == 0) {
588 		/* Data sent */
589 		if (sent == len) {
590 			/* All data sent.  Success. */
591 			return (0);
592 		} else {
593 			/* Not all data was sent.  Failure */
594 			return (-1);
595 		}
596 	}
597 
598 	/* Send failed */
599 	return (error);
600 }
601 
602 /*
603  * idm_iov_sosend - Sends an iovec on a connection.
604  *
605  * This function puts the data provided on the wire by calling sosendmsg.
606  * It will return only when all the data has been sent or if an error
607  * occurs.
608  *
609  * Returns 0 for success, the socket errno value if sosendmsg fails, and
610  * -1 if sosendmsg returns success but uio_resid != 0
611  */
612 int
613 idm_iov_sosend(ksocket_t so, iovec_t *iop, int iovlen, size_t total_len)
614 {
615 	struct msghdr		msg;
616 	int			error;
617 	size_t 			sent = 0;
618 
619 	ASSERT(iop != NULL);
620 
621 	/* Initialization of the message header. */
622 	bzero(&msg, sizeof (msg));
623 	msg.msg_iov	= iop;
624 	msg.msg_iovlen	= iovlen;
625 
626 	if ((error = ksocket_sendmsg(so, &msg, 0, &sent, CRED()))
627 	    == 0) {
628 		/* Data sent */
629 		if (sent == total_len) {
630 			/* All data sent.  Success. */
631 			return (0);
632 		} else {
633 			/* Not all data was sent.  Failure */
634 			return (-1);
635 		}
636 	}
637 
638 	/* Send failed */
639 	return (error);
640 }
641 
642 /*
643  * idm_iov_sorecv - Receives an iovec from a connection
644  *
645  * This function gets the data asked for from the socket.  It will return
646  * only when all the requested data has been retrieved or if an error
647  * occurs.
648  *
649  * Returns 0 for success, the socket errno value if sorecvmsg fails, and
650  * -1 if sorecvmsg returns success but uio_resid != 0
651  */
652 int
653 idm_iov_sorecv(ksocket_t so, iovec_t *iop, int iovlen, size_t total_len)
654 {
655 	struct msghdr		msg;
656 	int			error;
657 	size_t			recv;
658 	int 			flags;
659 
660 	ASSERT(iop != NULL);
661 
662 	/* Initialization of the message header. */
663 	bzero(&msg, sizeof (msg));
664 	msg.msg_iov	= iop;
665 	msg.msg_iovlen	= iovlen;
666 	flags		= MSG_WAITALL;
667 
668 	if ((error = ksocket_recvmsg(so, &msg, flags, &recv, CRED()))
669 	    == 0) {
670 		/* Received data */
671 		if (recv == total_len) {
672 			/* All requested data received.  Success */
673 			return (0);
674 		} else {
675 			/*
676 			 * Not all data was received.  The connection has
677 			 * probably failed.
678 			 */
679 			return (-1);
680 		}
681 	}
682 
683 	/* Receive failed */
684 	return (error);
685 }
686 
687 static void
688 idm_set_ini_preconnect_options(idm_so_conn_t *sc)
689 {
690 	int	conn_abort = 10000;
691 	int	conn_notify = 2000;
692 	int	abort = 30000;
693 
694 	/* Pre-connect socket options */
695 	(void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP,
696 	    TCP_CONN_NOTIFY_THRESHOLD, (char *)&conn_notify, sizeof (int),
697 	    CRED());
698 	(void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP,
699 	    TCP_CONN_ABORT_THRESHOLD, (char *)&conn_abort, sizeof (int),
700 	    CRED());
701 	(void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP, TCP_ABORT_THRESHOLD,
702 	    (char *)&abort, sizeof (int), CRED());
703 }
704 
705 static void
706 idm_set_ini_postconnect_options(idm_so_conn_t *sc)
707 {
708 	int32_t		rcvbuf = IDM_RCVBUF_SIZE;
709 	int32_t		sndbuf = IDM_SNDBUF_SIZE;
710 	const int	on = 1;
711 
712 	/* Set postconnect options */
713 	(void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP, TCP_NODELAY,
714 	    (char *)&on, sizeof (int), CRED());
715 	(void) ksocket_setsockopt(sc->ic_so, SOL_SOCKET, SO_RCVBUF,
716 	    (char *)&rcvbuf, sizeof (int), CRED());
717 	(void) ksocket_setsockopt(sc->ic_so, SOL_SOCKET, SO_SNDBUF,
718 	    (char *)&sndbuf, sizeof (int), CRED());
719 }
720 
721 static void
722 idm_set_tgt_connect_options(ksocket_t ks)
723 {
724 	int32_t		rcvbuf = IDM_RCVBUF_SIZE;
725 	int32_t		sndbuf = IDM_SNDBUF_SIZE;
726 	const int	on = 1;
727 
728 	/* Set connect options */
729 	(void) ksocket_setsockopt(ks, SOL_SOCKET, SO_RCVBUF,
730 	    (char *)&rcvbuf, sizeof (int), CRED());
731 	(void) ksocket_setsockopt(ks, SOL_SOCKET, SO_SNDBUF,
732 	    (char *)&sndbuf, sizeof (int), CRED());
733 	(void) ksocket_setsockopt(ks, IPPROTO_TCP, TCP_NODELAY,
734 	    (char *)&on, sizeof (on), CRED());
735 }
736 
737 static uint32_t
738 n2h24(const uchar_t *ptr)
739 {
740 	return ((ptr[0] << 16) | (ptr[1] << 8) | ptr[2]);
741 }
742 
743 
744 static idm_status_t
745 idm_sorecvhdr(idm_conn_t *ic, idm_pdu_t *pdu)
746 {
747 	iscsi_hdr_t	*bhs;
748 	uint32_t	hdr_digest_crc;
749 	uint32_t	crc_calculated;
750 	void		*new_hdr;
751 	int		ahslen = 0;
752 	int		total_len = 0;
753 	int		iovlen = 0;
754 	struct iovec	iov[2];
755 	idm_so_conn_t	*so_conn;
756 	int		rc;
757 
758 	so_conn = ic->ic_transport_private;
759 
760 	/*
761 	 * Read BHS
762 	 */
763 	bhs = pdu->isp_hdr;
764 	rc = idm_sorecv(so_conn->ic_so, pdu->isp_hdr, sizeof (iscsi_hdr_t));
765 	if (rc != IDM_STATUS_SUCCESS) {
766 		return (IDM_STATUS_FAIL);
767 	}
768 
769 	/*
770 	 * Check actual AHS length against the amount available in the buffer
771 	 */
772 	pdu->isp_hdrlen = sizeof (iscsi_hdr_t) +
773 	    (bhs->hlength * sizeof (uint32_t));
774 	pdu->isp_datalen = n2h24(bhs->dlength);
775 	if (ic->ic_conn_type == CONN_TYPE_TGT &&
776 	    pdu->isp_datalen > ic->ic_conn_params.max_recv_dataseglen) {
777 		IDM_CONN_LOG(CE_WARN,
778 		    "idm_sorecvhdr: exceeded the max data segment length");
779 		return (IDM_STATUS_FAIL);
780 	}
781 	if (bhs->hlength > IDM_SORX_CACHE_AHSLEN) {
782 		/* Allocate a new header segment and change the callback */
783 		new_hdr = kmem_alloc(pdu->isp_hdrlen, KM_SLEEP);
784 		bcopy(pdu->isp_hdr, new_hdr, sizeof (iscsi_hdr_t));
785 		pdu->isp_hdr = new_hdr;
786 		pdu->isp_flags |= IDM_PDU_ADDL_HDR;
787 
788 		/*
789 		 * This callback will restore the expected values after
790 		 * the RX PDU has been processed.
791 		 */
792 		pdu->isp_callback = idm_sorx_addl_pdu_cb;
793 	}
794 
795 	/*
796 	 * Setup receipt of additional header and header digest (if enabled).
797 	 */
798 	if (bhs->hlength > 0) {
799 		iov[iovlen].iov_base = (caddr_t)(pdu->isp_hdr + 1);
800 		ahslen = pdu->isp_hdrlen - sizeof (iscsi_hdr_t);
801 		iov[iovlen].iov_len = ahslen;
802 		total_len += iov[iovlen].iov_len;
803 		iovlen++;
804 	}
805 
806 	if (ic->ic_conn_flags & IDM_CONN_HEADER_DIGEST) {
807 		iov[iovlen].iov_base = (caddr_t)&hdr_digest_crc;
808 		iov[iovlen].iov_len = sizeof (hdr_digest_crc);
809 		total_len += iov[iovlen].iov_len;
810 		iovlen++;
811 	}
812 
813 	if ((iovlen != 0) &&
814 	    (idm_iov_sorecv(so_conn->ic_so, &iov[0], iovlen,
815 	    total_len) != 0)) {
816 		return (IDM_STATUS_FAIL);
817 	}
818 
819 	/*
820 	 * Validate header digest if enabled
821 	 */
822 	if (ic->ic_conn_flags & IDM_CONN_HEADER_DIGEST) {
823 		crc_calculated = idm_crc32c(pdu->isp_hdr,
824 		    sizeof (iscsi_hdr_t) + ahslen);
825 		if (crc_calculated != hdr_digest_crc) {
826 			/* Invalid Header Digest */
827 			return (IDM_STATUS_HEADER_DIGEST);
828 		}
829 	}
830 
831 	return (0);
832 }
833 
834 /*
835  * idm_so_ini_conn_create()
836  * Allocate the sockets transport connection resources.
837  */
838 static idm_status_t
839 idm_so_ini_conn_create(idm_conn_req_t *cr, idm_conn_t *ic)
840 {
841 	ksocket_t	so;
842 	idm_so_conn_t	*so_conn;
843 	idm_status_t	idmrc;
844 
845 	so = idm_socreate(cr->cr_domain, cr->cr_type,
846 	    cr->cr_protocol);
847 	if (so == NULL) {
848 		return (IDM_STATUS_FAIL);
849 	}
850 
851 	/* Bind the socket if configured to do so */
852 	if (cr->cr_bound) {
853 		if (ksocket_bind(so, &cr->cr_bound_addr.sin,
854 		    SIZEOF_SOCKADDR(&cr->cr_bound_addr.sin), CRED()) != 0) {
855 			idm_sodestroy(so);
856 			return (IDM_STATUS_FAIL);
857 		}
858 	}
859 
860 	idmrc = idm_so_conn_create_common(ic, so);
861 	if (idmrc != IDM_STATUS_SUCCESS) {
862 		idm_soshutdown(so);
863 		idm_sodestroy(so);
864 		return (IDM_STATUS_FAIL);
865 	}
866 
867 	so_conn = ic->ic_transport_private;
868 	/* Set up socket options */
869 	idm_set_ini_preconnect_options(so_conn);
870 
871 	return (IDM_STATUS_SUCCESS);
872 }
873 
874 /*
875  * idm_so_ini_conn_destroy()
876  * Tear down the sockets transport connection resources.
877  */
878 static void
879 idm_so_ini_conn_destroy(idm_conn_t *ic)
880 {
881 	idm_so_conn_destroy_common(ic);
882 }
883 
884 /*
885  * idm_so_ini_conn_connect()
886  * Establish the connection referred to by the handle previously allocated via
887  * idm_so_ini_conn_create().
888  */
889 static idm_status_t
890 idm_so_ini_conn_connect(idm_conn_t *ic)
891 {
892 	idm_so_conn_t	*so_conn;
893 	struct sonode	*node = NULL;
894 	int 		rc;
895 	clock_t		lbolt, conn_login_max, conn_login_interval;
896 	boolean_t	nonblock;
897 
898 	so_conn = ic->ic_transport_private;
899 	nonblock = ic->ic_conn_params.nonblock_socket;
900 	conn_login_max = ic->ic_conn_params.conn_login_max;
901 	conn_login_interval = ddi_get_lbolt() +
902 	    SEC_TO_TICK(ic->ic_conn_params.conn_login_interval);
903 
904 	if (nonblock == B_TRUE) {
905 		node = ((struct sonode *)(so_conn->ic_so));
906 		/* Set to none block socket mode */
907 		idm_so_socket_set_nonblock(node);
908 		do {
909 			rc = ksocket_connect(so_conn->ic_so,
910 			    &ic->ic_ini_dst_addr.sin,
911 			    (SIZEOF_SOCKADDR(&ic->ic_ini_dst_addr.sin)),
912 			    CRED());
913 			if (rc == 0 || rc == EISCONN) {
914 				/* socket success or already success */
915 				rc = IDM_STATUS_SUCCESS;
916 				break;
917 			}
918 			if ((rc == ETIMEDOUT) || (rc == ECONNREFUSED) ||
919 			    (rc == ECONNRESET)) {
920 				/* socket connection timeout or refuse */
921 				break;
922 			}
923 			lbolt = ddi_get_lbolt();
924 			if (lbolt > conn_login_max) {
925 				/*
926 				 * Connection retry timeout,
927 				 * failed connect to target.
928 				 */
929 				break;
930 			}
931 			if (lbolt < conn_login_interval) {
932 				if ((rc == EINPROGRESS) || (rc == EALREADY)) {
933 					/* TCP connect still in progress */
934 					delay(SEC_TO_TICK(IN_PROGRESS_DELAY));
935 					continue;
936 				} else {
937 					delay(conn_login_interval - lbolt);
938 				}
939 			}
940 			conn_login_interval = ddi_get_lbolt() +
941 			    SEC_TO_TICK(ic->ic_conn_params.conn_login_interval);
942 		} while (rc != 0);
943 		/* resume to nonblock mode */
944 		if (rc == IDM_STATUS_SUCCESS) {
945 			idm_so_socket_set_block(node);
946 		}
947 	} else {
948 		rc = ksocket_connect(so_conn->ic_so, &ic->ic_ini_dst_addr.sin,
949 		    (SIZEOF_SOCKADDR(&ic->ic_ini_dst_addr.sin)), CRED());
950 	}
951 
952 	if (rc != 0) {
953 		idm_soshutdown(so_conn->ic_so);
954 		return (IDM_STATUS_FAIL);
955 	}
956 
957 	idm_so_conn_connect_common(ic);
958 
959 	idm_set_ini_postconnect_options(so_conn);
960 
961 	return (IDM_STATUS_SUCCESS);
962 }
963 
964 idm_status_t
965 idm_so_tgt_conn_create(idm_conn_t *ic, ksocket_t new_so)
966 {
967 	idm_status_t	idmrc;
968 
969 	idmrc = idm_so_conn_create_common(ic, new_so);
970 
971 	return (idmrc);
972 }
973 
974 static void
975 idm_so_tgt_conn_destroy(idm_conn_t *ic)
976 {
977 	idm_so_conn_destroy_common(ic);
978 }
979 
980 /*
981  * idm_so_tgt_conn_connect()
982  * Establish the connection in ic, passed from idm_tgt_conn_finish(), which
983  * is invoked from the SM as a result of an inbound connection request.
984  */
985 static idm_status_t
986 idm_so_tgt_conn_connect(idm_conn_t *ic)
987 {
988 	idm_so_conn_connect_common(ic);
989 
990 	return (IDM_STATUS_SUCCESS);
991 }
992 
993 static idm_status_t
994 idm_so_conn_create_common(idm_conn_t *ic, ksocket_t new_so)
995 {
996 	idm_so_conn_t	*so_conn;
997 
998 	so_conn = kmem_zalloc(sizeof (idm_so_conn_t), KM_SLEEP);
999 	so_conn->ic_so = new_so;
1000 
1001 	ic->ic_transport_private = so_conn;
1002 	ic->ic_transport_hdrlen = 0;
1003 
1004 	/* Set the scoreboarding flag on this connection */
1005 	ic->ic_conn_flags |= IDM_CONN_USE_SCOREBOARD;
1006 	ic->ic_conn_params.max_recv_dataseglen =
1007 	    ISCSI_DEFAULT_MAX_RECV_SEG_LEN;
1008 	ic->ic_conn_params.max_xmit_dataseglen =
1009 	    ISCSI_DEFAULT_MAX_XMIT_SEG_LEN;
1010 
1011 	/*
1012 	 * Initialize tx thread mutex and list
1013 	 */
1014 	mutex_init(&so_conn->ic_tx_mutex, NULL, MUTEX_DEFAULT, NULL);
1015 	cv_init(&so_conn->ic_tx_cv, NULL, CV_DEFAULT, NULL);
1016 	list_create(&so_conn->ic_tx_list, sizeof (idm_pdu_t),
1017 	    offsetof(idm_pdu_t, idm_tx_link));
1018 
1019 	return (IDM_STATUS_SUCCESS);
1020 }
1021 
1022 static void
1023 idm_so_conn_destroy_common(idm_conn_t *ic)
1024 {
1025 	idm_so_conn_t	*so_conn = ic->ic_transport_private;
1026 
1027 	ic->ic_transport_private = NULL;
1028 	idm_sodestroy(so_conn->ic_so);
1029 	list_destroy(&so_conn->ic_tx_list);
1030 	mutex_destroy(&so_conn->ic_tx_mutex);
1031 	cv_destroy(&so_conn->ic_tx_cv);
1032 
1033 	kmem_free(so_conn, sizeof (idm_so_conn_t));
1034 }
1035 
1036 static void
1037 idm_so_conn_connect_common(idm_conn_t *ic)
1038 {
1039 	idm_so_conn_t	*so_conn;
1040 	struct sockaddr_in6	t_addr;
1041 	socklen_t	t_addrlen = 0;
1042 
1043 	so_conn = ic->ic_transport_private;
1044 	bzero(&t_addr, sizeof (struct sockaddr_in6));
1045 	t_addrlen = sizeof (struct sockaddr_in6);
1046 
1047 	/* Set the local and remote addresses in the idm conn handle */
1048 	ksocket_getsockname(so_conn->ic_so, (struct sockaddr *)&t_addr,
1049 	    &t_addrlen, CRED());
1050 	bcopy(&t_addr, &ic->ic_laddr, t_addrlen);
1051 	ksocket_getpeername(so_conn->ic_so, (struct sockaddr *)&t_addr,
1052 	    &t_addrlen, CRED());
1053 	bcopy(&t_addr, &ic->ic_raddr, t_addrlen);
1054 
1055 	mutex_enter(&ic->ic_mutex);
1056 	so_conn->ic_tx_thread = thread_create(NULL, 0, idm_sotx_thread, ic, 0,
1057 	    &p0, TS_RUN, minclsyspri);
1058 	so_conn->ic_rx_thread = thread_create(NULL, 0, idm_sorx_thread, ic, 0,
1059 	    &p0, TS_RUN, minclsyspri);
1060 
1061 	while (!so_conn->ic_rx_thread_running || !so_conn->ic_tx_thread_running)
1062 		cv_wait(&ic->ic_cv, &ic->ic_mutex);
1063 	mutex_exit(&ic->ic_mutex);
1064 }
1065 
1066 /*
1067  * idm_so_conn_disconnect()
1068  * Shutdown the socket connection and stop the thread
1069  */
1070 static void
1071 idm_so_conn_disconnect(idm_conn_t *ic)
1072 {
1073 	idm_so_conn_t	*so_conn;
1074 
1075 	so_conn = ic->ic_transport_private;
1076 
1077 	mutex_enter(&ic->ic_mutex);
1078 	so_conn->ic_rx_thread_running = B_FALSE;
1079 	so_conn->ic_tx_thread_running = B_FALSE;
1080 	/* We need to wakeup the TX thread */
1081 	mutex_enter(&so_conn->ic_tx_mutex);
1082 	cv_signal(&so_conn->ic_tx_cv);
1083 	mutex_exit(&so_conn->ic_tx_mutex);
1084 	mutex_exit(&ic->ic_mutex);
1085 
1086 	/* This should wakeup the RX thread if it is sleeping */
1087 	idm_soshutdown(so_conn->ic_so);
1088 
1089 	thread_join(so_conn->ic_tx_thread_did);
1090 	thread_join(so_conn->ic_rx_thread_did);
1091 }
1092 
1093 /*
1094  * idm_so_tgt_svc_create()
1095  * Establish a service on an IP address and port.  idm_svc_req_t contains
1096  * the service parameters.
1097  */
1098 /*ARGSUSED*/
1099 static idm_status_t
1100 idm_so_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t *is)
1101 {
1102 	idm_so_svc_t		*so_svc;
1103 
1104 	so_svc = kmem_zalloc(sizeof (idm_so_svc_t), KM_SLEEP);
1105 
1106 	/* Set the new sockets service in svc handle */
1107 	is->is_so_svc = (void *)so_svc;
1108 
1109 	return (IDM_STATUS_SUCCESS);
1110 }
1111 
1112 /*
1113  * idm_so_tgt_svc_destroy()
1114  * Teardown sockets resources allocated in idm_so_tgt_svc_create()
1115  */
1116 static void
1117 idm_so_tgt_svc_destroy(idm_svc_t *is)
1118 {
1119 	/* the socket will have been torn down; free the service */
1120 	kmem_free(is->is_so_svc, sizeof (idm_so_svc_t));
1121 }
1122 
1123 /*
1124  * idm_so_tgt_svc_online()
1125  * Launch a watch thread on the svc allocated in idm_so_tgt_svc_create()
1126  */
1127 
1128 static idm_status_t
1129 idm_so_tgt_svc_online(idm_svc_t *is)
1130 {
1131 	idm_so_svc_t		*so_svc;
1132 	idm_svc_req_t		*sr = &is->is_svc_req;
1133 	struct sockaddr_in6	sin6_ip;
1134 	const uint32_t		on = 1;
1135 	const uint32_t		off = 0;
1136 
1137 	mutex_enter(&is->is_mutex);
1138 	so_svc = (idm_so_svc_t *)is->is_so_svc;
1139 
1140 	/*
1141 	 * Try creating an IPv6 socket first
1142 	 */
1143 	if ((so_svc->is_so = idm_socreate(PF_INET6, SOCK_STREAM, 0)) == NULL) {
1144 		mutex_exit(&is->is_mutex);
1145 		return (IDM_STATUS_FAIL);
1146 	} else {
1147 		bzero(&sin6_ip, sizeof (sin6_ip));
1148 		sin6_ip.sin6_family = AF_INET6;
1149 		sin6_ip.sin6_port = htons(sr->sr_port);
1150 		sin6_ip.sin6_addr = in6addr_any;
1151 
1152 		(void) ksocket_setsockopt(so_svc->is_so, SOL_SOCKET,
1153 		    SO_REUSEADDR, (char *)&on, sizeof (on), CRED());
1154 		/*
1155 		 * Turn off SO_MAC_EXEMPT so future sobinds succeed
1156 		 */
1157 		(void) ksocket_setsockopt(so_svc->is_so, SOL_SOCKET,
1158 		    SO_MAC_EXEMPT, (char *)&off, sizeof (off), CRED());
1159 
1160 		if (ksocket_bind(so_svc->is_so, (struct sockaddr *)&sin6_ip,
1161 		    sizeof (sin6_ip), CRED()) != 0) {
1162 			mutex_exit(&is->is_mutex);
1163 			idm_sodestroy(so_svc->is_so);
1164 			return (IDM_STATUS_FAIL);
1165 		}
1166 	}
1167 
1168 	idm_set_tgt_connect_options(so_svc->is_so);
1169 
1170 	if (ksocket_listen(so_svc->is_so, 5, CRED()) != 0) {
1171 		mutex_exit(&is->is_mutex);
1172 		idm_soshutdown(so_svc->is_so);
1173 		idm_sodestroy(so_svc->is_so);
1174 		return (IDM_STATUS_FAIL);
1175 	}
1176 
1177 	/* Launch a watch thread */
1178 	so_svc->is_thread = thread_create(NULL, 0, idm_so_svc_port_watcher,
1179 	    is, 0, &p0, TS_RUN, minclsyspri);
1180 
1181 	if (so_svc->is_thread == NULL) {
1182 		/* Failure to launch; teardown the socket */
1183 		mutex_exit(&is->is_mutex);
1184 		idm_soshutdown(so_svc->is_so);
1185 		idm_sodestroy(so_svc->is_so);
1186 		return (IDM_STATUS_FAIL);
1187 	}
1188 	ksocket_hold(so_svc->is_so);
1189 	/* Wait for the port watcher thread to start */
1190 	while (!so_svc->is_thread_running)
1191 		cv_wait(&is->is_cv, &is->is_mutex);
1192 	mutex_exit(&is->is_mutex);
1193 
1194 	return (IDM_STATUS_SUCCESS);
1195 }
1196 
1197 /*
1198  * idm_so_tgt_svc_offline
1199  *
1200  * Stop listening on the IP address and port identified by idm_svc_t.
1201  */
1202 static void
1203 idm_so_tgt_svc_offline(idm_svc_t *is)
1204 {
1205 	idm_so_svc_t		*so_svc;
1206 	mutex_enter(&is->is_mutex);
1207 	so_svc = (idm_so_svc_t *)is->is_so_svc;
1208 	so_svc->is_thread_running = B_FALSE;
1209 	mutex_exit(&is->is_mutex);
1210 
1211 	/*
1212 	 * Teardown socket
1213 	 */
1214 	idm_sodestroy(so_svc->is_so);
1215 
1216 	/*
1217 	 * Now we expect the port watcher thread to terminate
1218 	 */
1219 	thread_join(so_svc->is_thread_did);
1220 }
1221 
1222 /*
1223  * Watch thread for target service connection establishment.
1224  */
1225 void
1226 idm_so_svc_port_watcher(void *arg)
1227 {
1228 	idm_svc_t		*svc = arg;
1229 	ksocket_t		new_so;
1230 	idm_conn_t		*ic;
1231 	idm_status_t		idmrc;
1232 	idm_so_svc_t		*so_svc;
1233 	int			rc;
1234 	const uint32_t		off = 0;
1235 	struct sockaddr_in6 	t_addr;
1236 	socklen_t		t_addrlen;
1237 
1238 	bzero(&t_addr, sizeof (struct sockaddr_in6));
1239 	t_addrlen = sizeof (struct sockaddr_in6);
1240 	mutex_enter(&svc->is_mutex);
1241 
1242 	so_svc = svc->is_so_svc;
1243 	so_svc->is_thread_running = B_TRUE;
1244 	so_svc->is_thread_did = so_svc->is_thread->t_did;
1245 
1246 	cv_signal(&svc->is_cv);
1247 
1248 	IDM_SVC_LOG(CE_NOTE, "iSCSI service (%p/%d) online", (void *)svc,
1249 	    svc->is_svc_req.sr_port);
1250 
1251 	while (so_svc->is_thread_running) {
1252 		mutex_exit(&svc->is_mutex);
1253 
1254 		if ((rc = ksocket_accept(so_svc->is_so,
1255 		    (struct sockaddr *)&t_addr, &t_addrlen,
1256 		    &new_so, CRED())) != 0) {
1257 			mutex_enter(&svc->is_mutex);
1258 			if (rc == ECONNABORTED)
1259 				continue;
1260 			/* Connection problem */
1261 			break;
1262 		}
1263 		/*
1264 		 * Turn off SO_MAC_EXEMPT so future sobinds succeed
1265 		 */
1266 		(void) ksocket_setsockopt(new_so, SOL_SOCKET, SO_MAC_EXEMPT,
1267 		    (char *)&off, sizeof (off), CRED());
1268 
1269 		idmrc = idm_svc_conn_create(svc, IDM_TRANSPORT_TYPE_SOCKETS,
1270 		    &ic);
1271 		if (idmrc != IDM_STATUS_SUCCESS) {
1272 			/* Drop connection */
1273 			idm_soshutdown(new_so);
1274 			idm_sodestroy(new_so);
1275 			mutex_enter(&svc->is_mutex);
1276 			continue;
1277 		}
1278 
1279 		idmrc = idm_so_tgt_conn_create(ic, new_so);
1280 		if (idmrc != IDM_STATUS_SUCCESS) {
1281 			idm_svc_conn_destroy(ic);
1282 			idm_soshutdown(new_so);
1283 			idm_sodestroy(new_so);
1284 			mutex_enter(&svc->is_mutex);
1285 			continue;
1286 		}
1287 
1288 		/*
1289 		 * Kick the state machine.  At CS_S3_XPT_UP the state machine
1290 		 * will notify the client (target) about the new connection.
1291 		 */
1292 		idm_conn_event(ic, CE_CONNECT_ACCEPT, NULL);
1293 
1294 		mutex_enter(&svc->is_mutex);
1295 	}
1296 	ksocket_rele(so_svc->is_so);
1297 	so_svc->is_thread_running = B_FALSE;
1298 	mutex_exit(&svc->is_mutex);
1299 
1300 	IDM_SVC_LOG(CE_NOTE, "iSCSI service (%p/%d) offline", (void *)svc,
1301 	    svc->is_svc_req.sr_port);
1302 
1303 	thread_exit();
1304 }
1305 
1306 /*
1307  * idm_so_free_task_rsrc() stops any ongoing processing of the task and
1308  * frees resources associated with the task.
1309  *
1310  * It's not clear that this should return idm_status_t.  What do we do
1311  * if it fails?
1312  */
1313 static idm_status_t
1314 idm_so_free_task_rsrc(idm_task_t *idt)
1315 {
1316 	idm_buf_t	*idb;
1317 
1318 	/*
1319 	 * There is nothing to cleanup on initiator connections
1320 	 */
1321 	if (IDM_CONN_ISINI(idt->idt_ic))
1322 		return (IDM_STATUS_SUCCESS);
1323 
1324 	/*
1325 	 * If this is a target connection, call idm_buf_rx_from_ini_done for
1326 	 * any buffer on the "outbufv" list with idb->idb_in_transport==B_TRUE.
1327 	 *
1328 	 * In addition, remove any buffers associated with this task from
1329 	 * the ic_tx_list.  We'll do this by walking the idt_inbufv list, but
1330 	 * items don't actually get removed from that list (and completion
1331 	 * routines called) until idm_task_cleanup.
1332 	 */
1333 	mutex_enter(&idt->idt_mutex);
1334 
1335 	for (idb = list_head(&idt->idt_outbufv); idb != NULL;
1336 	    idb = list_next(&idt->idt_outbufv, idb)) {
1337 		if (idb->idb_in_transport) {
1338 			/*
1339 			 * idm_buf_rx_from_ini_done releases idt->idt_mutex
1340 			 */
1341 			DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic,
1342 			    uintptr_t, idb->idb_buf,
1343 			    uint32_t, idb->idb_bufoffset,
1344 			    uint64_t, 0, uint32_t, 0, uint32_t, 0,
1345 			    uint32_t, idb->idb_xfer_len,
1346 			    int, XFER_BUF_RX_FROM_INI);
1347 			idm_buf_rx_from_ini_done(idt, idb, IDM_STATUS_ABORTED);
1348 			mutex_enter(&idt->idt_mutex);
1349 		}
1350 	}
1351 
1352 	for (idb = list_head(&idt->idt_inbufv); idb != NULL;
1353 	    idb = list_next(&idt->idt_inbufv, idb)) {
1354 		/*
1355 		 * We want to remove these items from the tx_list as well,
1356 		 * but knowing it's in the idt_inbufv list is not a guarantee
1357 		 * that it's in the tx_list.  If it's on the tx list then
1358 		 * let idm_sotx_thread() clean it up.
1359 		 */
1360 		if (idb->idb_in_transport && !idb->idb_tx_thread) {
1361 			/*
1362 			 * idm_buf_tx_to_ini_done releases idt->idt_mutex
1363 			 */
1364 			DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic,
1365 			    uintptr_t, idb->idb_buf,
1366 			    uint32_t, idb->idb_bufoffset,
1367 			    uint64_t, 0, uint32_t, 0, uint32_t, 0,
1368 			    uint32_t, idb->idb_xfer_len,
1369 			    int, XFER_BUF_TX_TO_INI);
1370 			idm_buf_tx_to_ini_done(idt, idb, IDM_STATUS_ABORTED);
1371 			mutex_enter(&idt->idt_mutex);
1372 		}
1373 	}
1374 
1375 	mutex_exit(&idt->idt_mutex);
1376 
1377 	return (IDM_STATUS_SUCCESS);
1378 }
1379 
1380 /*
1381  * idm_so_negotiate_key_values() validates the key values for this connection
1382  */
1383 /* ARGSUSED */
1384 static kv_status_t
1385 idm_so_negotiate_key_values(idm_conn_t *it, nvlist_t *request_nvl,
1386     nvlist_t *response_nvl, nvlist_t *negotiated_nvl)
1387 {
1388 	/* All parameters are negotiated at the iscsit level */
1389 	return (KV_HANDLED);
1390 }
1391 
1392 /*
1393  * idm_so_notice_key_values() activates the negotiated key values for
1394  * this connection.
1395  */
1396 static void
1397 idm_so_notice_key_values(idm_conn_t *it, nvlist_t *negotiated_nvl)
1398 {
1399 	char			*nvp_name;
1400 	nvpair_t		*nvp;
1401 	nvpair_t		*next_nvp;
1402 	int			nvrc;
1403 	idm_status_t		idm_status;
1404 	const idm_kv_xlate_t	*ikvx;
1405 	uint64_t		num_val;
1406 
1407 	for (nvp = nvlist_next_nvpair(negotiated_nvl, NULL);
1408 	    nvp != NULL; nvp = next_nvp) {
1409 		next_nvp = nvlist_next_nvpair(negotiated_nvl, nvp);
1410 		nvp_name = nvpair_name(nvp);
1411 
1412 		ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name));
1413 		switch (ikvx->ik_key_id) {
1414 		case KI_HEADER_DIGEST:
1415 		case KI_DATA_DIGEST:
1416 			idm_status = idm_so_handle_digest(it, nvp, ikvx);
1417 			ASSERT(idm_status == 0);
1418 
1419 			/* Remove processed item from negotiated_nvl list */
1420 			nvrc = nvlist_remove_all(
1421 			    negotiated_nvl, ikvx->ik_key_name);
1422 			ASSERT(nvrc == 0);
1423 			break;
1424 		case KI_MAX_RECV_DATA_SEGMENT_LENGTH:
1425 			/*
1426 			 * Just pass the value down to idm layer.
1427 			 * No need to remove it from negotiated_nvl list here.
1428 			 */
1429 			nvrc = nvpair_value_uint64(nvp, &num_val);
1430 			ASSERT(nvrc == 0);
1431 			it->ic_conn_params.max_xmit_dataseglen =
1432 			    (uint32_t)num_val;
1433 			break;
1434 		default:
1435 			break;
1436 		}
1437 	}
1438 }
1439 
1440 /*
1441  * idm_so_declare_key_values() declares the key values for this connection
1442  */
1443 /* ARGSUSED */
1444 static kv_status_t
1445 idm_so_declare_key_values(idm_conn_t *it, nvlist_t *config_nvl,
1446     nvlist_t *outgoing_nvl)
1447 {
1448 	char			*nvp_name;
1449 	nvpair_t		*nvp;
1450 	nvpair_t		*next_nvp;
1451 	kv_status_t		kvrc;
1452 	int			nvrc = 0;
1453 	const idm_kv_xlate_t	*ikvx;
1454 	uint64_t		num_val;
1455 
1456 	for (nvp = nvlist_next_nvpair(config_nvl, NULL);
1457 	    nvp != NULL && nvrc == 0; nvp = next_nvp) {
1458 		next_nvp = nvlist_next_nvpair(config_nvl, nvp);
1459 		nvp_name = nvpair_name(nvp);
1460 
1461 		ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name));
1462 		switch (ikvx->ik_key_id) {
1463 		case KI_MAX_RECV_DATA_SEGMENT_LENGTH:
1464 			if ((nvrc = nvpair_value_uint64(nvp, &num_val)) != 0) {
1465 				break;
1466 			}
1467 			if (outgoing_nvl &&
1468 			    (nvrc = nvlist_add_uint64(outgoing_nvl,
1469 			    nvp_name, num_val)) != 0) {
1470 				break;
1471 			}
1472 			it->ic_conn_params.max_recv_dataseglen =
1473 			    (uint32_t)num_val;
1474 			break;
1475 		default:
1476 			break;
1477 		}
1478 	}
1479 	kvrc = idm_nvstat_to_kvstat(nvrc);
1480 	return (kvrc);
1481 }
1482 
1483 static idm_status_t
1484 idm_so_handle_digest(idm_conn_t *it, nvpair_t *digest_choice,
1485     const idm_kv_xlate_t *ikvx)
1486 {
1487 	int			nvrc;
1488 	char			*digest_choice_string;
1489 
1490 	nvrc = nvpair_value_string(digest_choice,
1491 	    &digest_choice_string);
1492 	ASSERT(nvrc == 0);
1493 	if (strcasecmp(digest_choice_string, "crc32c") == 0) {
1494 		switch (ikvx->ik_key_id) {
1495 		case KI_HEADER_DIGEST:
1496 			it->ic_conn_flags |= IDM_CONN_HEADER_DIGEST;
1497 			break;
1498 		case KI_DATA_DIGEST:
1499 			it->ic_conn_flags |= IDM_CONN_DATA_DIGEST;
1500 			break;
1501 		default:
1502 			ASSERT(0);
1503 			break;
1504 		}
1505 	} else if (strcasecmp(digest_choice_string, "none") == 0) {
1506 		switch (ikvx->ik_key_id) {
1507 		case KI_HEADER_DIGEST:
1508 			it->ic_conn_flags &= ~IDM_CONN_HEADER_DIGEST;
1509 			break;
1510 		case KI_DATA_DIGEST:
1511 			it->ic_conn_flags &= ~IDM_CONN_DATA_DIGEST;
1512 			break;
1513 		default:
1514 			ASSERT(0);
1515 			break;
1516 		}
1517 	} else {
1518 		ASSERT(0);
1519 	}
1520 
1521 	return (IDM_STATUS_SUCCESS);
1522 }
1523 
1524 
1525 /*
1526  * idm_so_conn_is_capable() verifies that the passed connection is provided
1527  * for by the sockets interface.
1528  */
1529 /* ARGSUSED */
1530 static boolean_t
1531 idm_so_conn_is_capable(idm_conn_req_t *ic, idm_transport_caps_t *caps)
1532 {
1533 	return (B_TRUE);
1534 }
1535 
1536 /*
1537  * idm_so_rx_datain() validates the Data Sequence number of the PDU. The
1538  * idm_sorecv_scsidata() function invoked earlier actually reads the data
1539  * off the socket into the appropriate buffers.
1540  */
1541 static void
1542 idm_so_rx_datain(idm_conn_t *ic, idm_pdu_t *pdu)
1543 {
1544 	iscsi_data_hdr_t	*bhs;
1545 	idm_task_t		*idt;
1546 	idm_buf_t		*idb;
1547 	uint32_t		datasn;
1548 	size_t			offset;
1549 	iscsi_hdr_t		*ihp = (iscsi_hdr_t *)pdu->isp_hdr;
1550 	iscsi_data_rsp_hdr_t    *idrhp = (iscsi_data_rsp_hdr_t *)ihp;
1551 
1552 	ASSERT(ic != NULL);
1553 	ASSERT(pdu != NULL);
1554 
1555 	bhs	= (iscsi_data_hdr_t *)pdu->isp_hdr;
1556 	datasn	= ntohl(bhs->datasn);
1557 	offset	= ntohl(bhs->offset);
1558 
1559 	ASSERT(bhs->opcode == ISCSI_OP_SCSI_DATA_RSP);
1560 
1561 	/*
1562 	 * Look up the task corresponding to the initiator task tag
1563 	 * to get the buffers affiliated with the task.
1564 	 */
1565 	idt = idm_task_find(ic, bhs->itt, bhs->ttt);
1566 	if (idt == NULL) {
1567 		IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: failed to find task");
1568 		idm_pdu_rx_protocol_error(ic, pdu);
1569 		return;
1570 	}
1571 
1572 	idb = pdu->isp_sorx_buf;
1573 	if (idb == NULL) {
1574 		IDM_CONN_LOG(CE_WARN,
1575 		    "idm_so_rx_datain: failed to find buffer");
1576 		idm_task_rele(idt);
1577 		idm_pdu_rx_protocol_error(ic, pdu);
1578 		return;
1579 	}
1580 
1581 	/*
1582 	 * DataSN values should be sequential and should not have any gaps or
1583 	 * repetitions. Check the DataSN with the one stored in the task.
1584 	 */
1585 	if (datasn == idt->idt_exp_datasn) {
1586 		idt->idt_exp_datasn++; /* keep track of DataSN received */
1587 	} else {
1588 		IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: datasn out of order");
1589 		idm_task_rele(idt);
1590 		idm_pdu_rx_protocol_error(ic, pdu);
1591 		return;
1592 	}
1593 
1594 	/*
1595 	 * PDUs in a sequence should be in continuously increasing
1596 	 * address offset
1597 	 */
1598 	if (offset != idb->idb_exp_offset) {
1599 		IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: unexpected offset");
1600 		idm_task_rele(idt);
1601 		idm_pdu_rx_protocol_error(ic, pdu);
1602 		return;
1603 	}
1604 	/* Expected next relative buffer offset */
1605 	idb->idb_exp_offset += n2h24(bhs->dlength);
1606 	idt->idt_rx_bytes += n2h24(bhs->dlength);
1607 
1608 	idm_task_rele(idt);
1609 
1610 	/*
1611 	 * For now call scsi_rsp which will process the data rsp
1612 	 * Revisit, need to provide an explicit client entry point for
1613 	 * phase collapse completions.
1614 	 */
1615 	if (((ihp->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_SCSI_DATA_RSP) &&
1616 	    (idrhp->flags & ISCSI_FLAG_DATA_STATUS)) {
1617 		(*ic->ic_conn_ops.icb_rx_scsi_rsp)(ic, pdu);
1618 	}
1619 
1620 	idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
1621 }
1622 
1623 /*
1624  * The idm_so_rx_dataout() function is used by the iSCSI target to read
1625  * data from the Data-Out PDU sent by the iSCSI initiator.
1626  *
1627  * This function gets the Initiator Task Tag from the PDU BHS and looks up the
1628  * task to get the buffers associated with the PDU. A PDU might span buffers.
1629  * The data is then read into the respective buffer.
1630  */
1631 static void
1632 idm_so_rx_dataout(idm_conn_t *ic, idm_pdu_t *pdu)
1633 {
1634 
1635 	iscsi_data_hdr_t	*bhs;
1636 	idm_task_t		*idt;
1637 	idm_buf_t		*idb;
1638 	size_t			offset;
1639 
1640 	ASSERT(ic != NULL);
1641 	ASSERT(pdu != NULL);
1642 
1643 	bhs = (iscsi_data_hdr_t *)pdu->isp_hdr;
1644 	offset = ntohl(bhs->offset);
1645 	ASSERT(bhs->opcode == ISCSI_OP_SCSI_DATA);
1646 
1647 	/*
1648 	 * Look up the task corresponding to the initiator task tag
1649 	 * to get the buffers affiliated with the task.
1650 	 */
1651 	idt = idm_task_find(ic, bhs->itt, bhs->ttt);
1652 	if (idt == NULL) {
1653 		IDM_CONN_LOG(CE_WARN,
1654 		    "idm_so_rx_dataout: failed to find task");
1655 		idm_pdu_rx_protocol_error(ic, pdu);
1656 		return;
1657 	}
1658 
1659 	idb = pdu->isp_sorx_buf;
1660 	if (idb == NULL) {
1661 		IDM_CONN_LOG(CE_WARN,
1662 		    "idm_so_rx_dataout: failed to find buffer");
1663 		idm_task_rele(idt);
1664 		idm_pdu_rx_protocol_error(ic, pdu);
1665 		return;
1666 	}
1667 
1668 	/* Keep track of data transferred - check data offsets */
1669 	if (offset != idb->idb_exp_offset) {
1670 		IDM_CONN_LOG(CE_NOTE, "idm_so_rx_dataout: offset out of seq: "
1671 		    "%ld, %d", offset, idb->idb_exp_offset);
1672 		idm_task_rele(idt);
1673 		idm_pdu_rx_protocol_error(ic, pdu);
1674 		return;
1675 	}
1676 	/* Expected next relative offset */
1677 	idb->idb_exp_offset += ntoh24(bhs->dlength);
1678 	idt->idt_rx_bytes += n2h24(bhs->dlength);
1679 
1680 	/*
1681 	 * Call the buffer callback when the transfer is complete
1682 	 *
1683 	 * The connection state machine should only abort tasks after
1684 	 * shutting down the connection so we are assured that there
1685 	 * won't be a simultaneous attempt to abort this task at the
1686 	 * same time as we are processing this PDU (due to a connection
1687 	 * state change).
1688 	 */
1689 	if (bhs->flags & ISCSI_FLAG_FINAL) {
1690 		/*
1691 		 * We only want to call idm_buf_rx_from_ini_done once
1692 		 * per transfer.  It's possible that this task has
1693 		 * already been aborted in which case
1694 		 * idm_so_free_task_rsrc will call idm_buf_rx_from_ini_done
1695 		 * for each buffer with idb_in_transport==B_TRUE.  To
1696 		 * close this window and ensure that this doesn't happen,
1697 		 * we'll clear idb->idb_in_transport now while holding
1698 		 * the task mutex.   This is only really an issue for
1699 		 * SCSI task abort -- if tasks were being aborted because
1700 		 * of a connection state change the state machine would
1701 		 * have already stopped the receive thread.
1702 		 */
1703 		mutex_enter(&idt->idt_mutex);
1704 
1705 		/*
1706 		 * Release the task hold here (obtained in idm_task_find)
1707 		 * because the task may complete synchronously during
1708 		 * idm_buf_rx_from_ini_done.  Since we still have an active
1709 		 * buffer we know there is at least one additional hold on idt.
1710 		 */
1711 		idm_task_rele(idt);
1712 
1713 		/*
1714 		 * idm_buf_rx_from_ini_done releases idt->idt_mutex
1715 		 */
1716 		DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic,
1717 		    uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset,
1718 		    uint64_t, 0, uint32_t, 0, uint32_t, 0,
1719 		    uint32_t, idb->idb_xfer_len,
1720 		    int, XFER_BUF_RX_FROM_INI);
1721 		idm_buf_rx_from_ini_done(idt, idb, IDM_STATUS_SUCCESS);
1722 		idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
1723 		return;
1724 	}
1725 
1726 	idm_task_rele(idt);
1727 	idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
1728 }
1729 
1730 /*
1731  * The idm_so_rx_rtt() function is used by the iSCSI initiator to handle
1732  * the R2T PDU sent by the iSCSI target indicating that it is ready to
1733  * accept data. This gets the Initiator Task Tag (itt) from the PDU BHS
1734  * and looks up the task in the task tree using the itt to get the output
1735  * buffers associated the task. The R2T PDU contains the offset of the
1736  * requested data and the data length. This function then constructs a
1737  * sequence of iSCSI PDUs and outputs the requested data. Each Data-Out
1738  * PDU is associated with the R2T by the Target Transfer Tag  (ttt).
1739  */
1740 
1741 static void
1742 idm_so_rx_rtt(idm_conn_t *ic, idm_pdu_t *pdu)
1743 {
1744 	idm_task_t		*idt;
1745 	idm_buf_t		*idb;
1746 	iscsi_rtt_hdr_t		*rtt_hdr;
1747 	uint32_t		data_offset;
1748 	uint32_t		data_length;
1749 
1750 	ASSERT(ic != NULL);
1751 	ASSERT(pdu != NULL);
1752 
1753 	rtt_hdr	= (iscsi_rtt_hdr_t *)pdu->isp_hdr;
1754 	data_offset = ntohl(rtt_hdr->data_offset);
1755 	data_length = ntohl(rtt_hdr->data_length);
1756 	idt	= idm_task_find(ic, rtt_hdr->itt, rtt_hdr->ttt);
1757 
1758 	if (idt == NULL) {
1759 		IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: could not find task");
1760 		idm_pdu_rx_protocol_error(ic, pdu);
1761 		return;
1762 	}
1763 
1764 	/* Find the buffer bound to the task by the iSCSI initiator */
1765 	mutex_enter(&idt->idt_mutex);
1766 	idb = idm_buf_find(&idt->idt_outbufv, data_offset);
1767 	if (idb == NULL) {
1768 		mutex_exit(&idt->idt_mutex);
1769 		idm_task_rele(idt);
1770 		IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: could not find buffer");
1771 		idm_pdu_rx_protocol_error(ic, pdu);
1772 		return;
1773 	}
1774 
1775 	/* return buffer contains this data */
1776 	if (data_offset + data_length > idb->idb_buflen) {
1777 		/* Overflow */
1778 		mutex_exit(&idt->idt_mutex);
1779 		idm_task_rele(idt);
1780 		IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: read from outside "
1781 		    "buffer");
1782 		idm_pdu_rx_protocol_error(ic, pdu);
1783 		return;
1784 	}
1785 
1786 	idt->idt_r2t_ttt = rtt_hdr->ttt;
1787 	idt->idt_exp_datasn = 0;
1788 
1789 	idm_so_send_rtt_data(ic, idt, idb, data_offset,
1790 	    ntohl(rtt_hdr->data_length));
1791 	mutex_exit(&idt->idt_mutex);
1792 
1793 	idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
1794 	idm_task_rele(idt);
1795 
1796 }
1797 
1798 idm_status_t
1799 idm_sorecvdata(idm_conn_t *ic, idm_pdu_t *pdu)
1800 {
1801 	uint8_t		pad[ISCSI_PAD_WORD_LEN];
1802 	int		pad_len;
1803 	uint32_t	data_digest_crc;
1804 	uint32_t	crc_calculated;
1805 	int		total_len;
1806 	idm_so_conn_t	*so_conn;
1807 
1808 	so_conn = ic->ic_transport_private;
1809 
1810 	pad_len = ((ISCSI_PAD_WORD_LEN -
1811 	    (pdu->isp_datalen & (ISCSI_PAD_WORD_LEN - 1))) &
1812 	    (ISCSI_PAD_WORD_LEN - 1));
1813 
1814 	ASSERT(pdu->isp_iovlen < (PDU_MAX_IOVLEN - 2)); /* pad + data digest */
1815 
1816 	total_len = pdu->isp_datalen;
1817 
1818 	if (pad_len) {
1819 		pdu->isp_iov[pdu->isp_iovlen].iov_base	= (char *)&pad;
1820 		pdu->isp_iov[pdu->isp_iovlen].iov_len	= pad_len;
1821 		total_len		+= pad_len;
1822 		pdu->isp_iovlen++;
1823 	}
1824 
1825 	/* setup data digest */
1826 	if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) != 0) {
1827 		pdu->isp_iov[pdu->isp_iovlen].iov_base =
1828 		    (char *)&data_digest_crc;
1829 		pdu->isp_iov[pdu->isp_iovlen].iov_len =
1830 		    sizeof (data_digest_crc);
1831 		total_len		+= sizeof (data_digest_crc);
1832 		pdu->isp_iovlen++;
1833 	}
1834 
1835 	pdu->isp_data = (uint8_t *)(uintptr_t)pdu->isp_iov[0].iov_base;
1836 
1837 	if (idm_iov_sorecv(so_conn->ic_so, &pdu->isp_iov[0],
1838 	    pdu->isp_iovlen, total_len) != 0) {
1839 		return (IDM_STATUS_IO);
1840 	}
1841 
1842 	if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) != 0) {
1843 		crc_calculated = idm_crc32c(pdu->isp_data,
1844 		    pdu->isp_datalen);
1845 		if (pad_len) {
1846 			crc_calculated = idm_crc32c_continued((char *)&pad,
1847 			    pad_len, crc_calculated);
1848 		}
1849 		if (crc_calculated != data_digest_crc) {
1850 			IDM_CONN_LOG(CE_WARN,
1851 			    "idm_sorecvdata: "
1852 			    "CRC error: actual 0x%x, calc 0x%x",
1853 			    data_digest_crc, crc_calculated);
1854 
1855 			/* Invalid Data Digest */
1856 			return (IDM_STATUS_DATA_DIGEST);
1857 		}
1858 	}
1859 
1860 	return (IDM_STATUS_SUCCESS);
1861 }
1862 
1863 /*
1864  * idm_sorecv_scsidata() is used to receive scsi data from the socket. The
1865  * Data-type PDU header must be read into the idm_pdu_t structure prior to
1866  * calling this function.
1867  */
1868 idm_status_t
1869 idm_sorecv_scsidata(idm_conn_t *ic, idm_pdu_t *pdu)
1870 {
1871 	iscsi_data_hdr_t	*bhs;
1872 	idm_task_t		*task;
1873 	uint32_t		offset;
1874 	uint8_t			opcode;
1875 	uint32_t		dlength;
1876 	list_t			*buflst;
1877 	uint32_t		xfer_bytes;
1878 	idm_status_t		status;
1879 
1880 	ASSERT(ic != NULL);
1881 	ASSERT(pdu != NULL);
1882 
1883 	bhs	= (iscsi_data_hdr_t *)pdu->isp_hdr;
1884 
1885 	offset	= ntohl(bhs->offset);
1886 	opcode	= bhs->opcode;
1887 	dlength = n2h24(bhs->dlength);
1888 
1889 	ASSERT((opcode == ISCSI_OP_SCSI_DATA_RSP) ||
1890 	    (opcode == ISCSI_OP_SCSI_DATA));
1891 
1892 	/*
1893 	 * Successful lookup implicitly gets a "hold" on the task.  This
1894 	 * hold must be released before leaving this function.  At one
1895 	 * point we were caching this task context and retaining the hold
1896 	 * but it turned out to be very difficult to release the hold properly.
1897 	 * The task can be aborted and the connection shutdown between this
1898 	 * call and the subsequent expected call to idm_so_rx_datain/
1899 	 * idm_so_rx_dataout (in which case those functions are not called).
1900 	 * Releasing the hold in the PDU callback doesn't work well either
1901 	 * because the whole task may be completed by then at which point
1902 	 * it is too late to release the hold -- for better or worse this
1903 	 * code doesn't wait on the refcnts during normal operation.
1904 	 * idm_task_find() is very fast and it is not a huge burden if we
1905 	 * have to do it twice.
1906 	 */
1907 	task = idm_task_find(ic, bhs->itt, bhs->ttt);
1908 	if (task == NULL) {
1909 		IDM_CONN_LOG(CE_WARN,
1910 		    "idm_sorecv_scsidata: could not find task");
1911 		return (IDM_STATUS_FAIL);
1912 	}
1913 
1914 	mutex_enter(&task->idt_mutex);
1915 	buflst	= (opcode == ISCSI_OP_SCSI_DATA_RSP) ?
1916 	    &task->idt_inbufv : &task->idt_outbufv;
1917 	pdu->isp_sorx_buf = idm_buf_find(buflst, offset);
1918 	mutex_exit(&task->idt_mutex);
1919 
1920 	if (pdu->isp_sorx_buf == NULL) {
1921 		idm_task_rele(task);
1922 		IDM_CONN_LOG(CE_WARN, "idm_sorecv_scsidata: could not find "
1923 		    "buffer for offset %x opcode=%x",
1924 		    offset, opcode);
1925 		return (IDM_STATUS_FAIL);
1926 	}
1927 
1928 	xfer_bytes = idm_fill_iov(pdu, pdu->isp_sorx_buf, offset, dlength);
1929 	ASSERT(xfer_bytes != 0);
1930 	if (xfer_bytes != dlength) {
1931 		idm_task_rele(task);
1932 		/*
1933 		 * Buffer overflow, connection error.  The PDU data is still
1934 		 * sitting in the socket so we can't use the connection
1935 		 * again until that data is drained.
1936 		 */
1937 		return (IDM_STATUS_FAIL);
1938 	}
1939 
1940 	status = idm_sorecvdata(ic, pdu);
1941 
1942 	idm_task_rele(task);
1943 
1944 	return (status);
1945 }
1946 
1947 static uint32_t
1948 idm_fill_iov(idm_pdu_t *pdu, idm_buf_t *idb, uint32_t ro, uint32_t dlength)
1949 {
1950 	uint32_t	buf_ro = ro - idb->idb_bufoffset;
1951 	uint32_t	xfer_len = min(dlength, idb->idb_buflen - buf_ro);
1952 
1953 	ASSERT(ro >= idb->idb_bufoffset);
1954 
1955 	pdu->isp_iov[pdu->isp_iovlen].iov_base	=
1956 	    (caddr_t)idb->idb_buf + buf_ro;
1957 	pdu->isp_iov[pdu->isp_iovlen].iov_len	= xfer_len;
1958 	pdu->isp_iovlen++;
1959 
1960 	return (xfer_len);
1961 }
1962 
1963 int
1964 idm_sorecv_nonscsidata(idm_conn_t *ic, idm_pdu_t *pdu)
1965 {
1966 	pdu->isp_data = kmem_alloc(pdu->isp_datalen, KM_SLEEP);
1967 	ASSERT(pdu->isp_data != NULL);
1968 
1969 	pdu->isp_databuflen = pdu->isp_datalen;
1970 	pdu->isp_iov[0].iov_base = (caddr_t)pdu->isp_data;
1971 	pdu->isp_iov[0].iov_len = pdu->isp_datalen;
1972 	pdu->isp_iovlen = 1;
1973 	/*
1974 	 * Since we are associating a new data buffer with this received
1975 	 * PDU we need to set a specific callback to free the data
1976 	 * after the PDU is processed.
1977 	 */
1978 	pdu->isp_flags |= IDM_PDU_ADDL_DATA;
1979 	pdu->isp_callback = idm_sorx_addl_pdu_cb;
1980 
1981 	return (idm_sorecvdata(ic, pdu));
1982 }
1983 
1984 void
1985 idm_sorx_thread(void *arg)
1986 {
1987 	boolean_t	conn_failure = B_FALSE;
1988 	idm_conn_t	*ic = (idm_conn_t *)arg;
1989 	idm_so_conn_t	*so_conn;
1990 	idm_pdu_t	*pdu;
1991 	idm_status_t	rc;
1992 
1993 	idm_conn_hold(ic);
1994 
1995 	mutex_enter(&ic->ic_mutex);
1996 
1997 	so_conn = ic->ic_transport_private;
1998 	so_conn->ic_rx_thread_running = B_TRUE;
1999 	so_conn->ic_rx_thread_did = so_conn->ic_rx_thread->t_did;
2000 	cv_signal(&ic->ic_cv);
2001 
2002 	while (so_conn->ic_rx_thread_running) {
2003 		mutex_exit(&ic->ic_mutex);
2004 
2005 		/*
2006 		 * Get PDU with default header size (large enough for
2007 		 * BHS plus any anticipated AHS).  PDU from
2008 		 * the cache will have all values set correctly
2009 		 * for sockets RX including callback.
2010 		 */
2011 		pdu = kmem_cache_alloc(idm.idm_sorx_pdu_cache, KM_SLEEP);
2012 		pdu->isp_ic = ic;
2013 		pdu->isp_flags = 0;
2014 		pdu->isp_transport_hdrlen = 0;
2015 
2016 		if ((rc = idm_sorecvhdr(ic, pdu)) != 0) {
2017 			/*
2018 			 * Call idm_pdu_complete so that we call the callback
2019 			 * and ensure any memory allocated in idm_sorecvhdr
2020 			 * gets freed up.
2021 			 */
2022 			idm_pdu_complete(pdu, IDM_STATUS_FAIL);
2023 
2024 			/*
2025 			 * If ic_rx_thread_running is still set then
2026 			 * this is some kind of connection problem
2027 			 * on the socket.  In this case we want to
2028 			 * generate an event.  Otherwise some other
2029 			 * thread closed the socket due to another
2030 			 * issue in which case we don't need to
2031 			 * generate an event.
2032 			 */
2033 			mutex_enter(&ic->ic_mutex);
2034 			if (so_conn->ic_rx_thread_running) {
2035 				conn_failure = B_TRUE;
2036 				so_conn->ic_rx_thread_running = B_FALSE;
2037 			}
2038 
2039 			continue;
2040 		}
2041 
2042 		/*
2043 		 * Header has been read and validated.  Now we need
2044 		 * to read the PDU data payload (if present).  SCSI data
2045 		 * need to be transferred from the socket directly into
2046 		 * the associated transfer buffer for the SCSI task.
2047 		 */
2048 		if (pdu->isp_datalen != 0) {
2049 			if ((IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA) ||
2050 			    (IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA_RSP)) {
2051 				rc = idm_sorecv_scsidata(ic, pdu);
2052 				/*
2053 				 * All SCSI errors are fatal to the
2054 				 * connection right now since we have no
2055 				 * place to put the data.  What we need
2056 				 * is some kind of sink to dispose of unwanted
2057 				 * SCSI data.  For example an invalid task tag
2058 				 * should not kill the connection (although
2059 				 * we may want to drop the connection).
2060 				 */
2061 			} else {
2062 				/*
2063 				 * Not data PDUs so allocate a buffer for the
2064 				 * data segment and read the remaining data.
2065 				 */
2066 				rc = idm_sorecv_nonscsidata(ic, pdu);
2067 			}
2068 			if (rc != 0) {
2069 				/*
2070 				 * Call idm_pdu_complete so that we call the
2071 				 * callback and ensure any memory allocated
2072 				 * in idm_sorecvhdr gets freed up.
2073 				 */
2074 				idm_pdu_complete(pdu, IDM_STATUS_FAIL);
2075 
2076 				/*
2077 				 * If ic_rx_thread_running is still set then
2078 				 * this is some kind of connection problem
2079 				 * on the socket.  In this case we want to
2080 				 * generate an event.  Otherwise some other
2081 				 * thread closed the socket due to another
2082 				 * issue in which case we don't need to
2083 				 * generate an event.
2084 				 */
2085 				mutex_enter(&ic->ic_mutex);
2086 				if (so_conn->ic_rx_thread_running) {
2087 					conn_failure = B_TRUE;
2088 					so_conn->ic_rx_thread_running = B_FALSE;
2089 				}
2090 				continue;
2091 			}
2092 		}
2093 
2094 		/*
2095 		 * Process RX PDU
2096 		 */
2097 		idm_pdu_rx(ic, pdu);
2098 
2099 		mutex_enter(&ic->ic_mutex);
2100 	}
2101 
2102 	mutex_exit(&ic->ic_mutex);
2103 
2104 	/*
2105 	 * If we dropped out of the RX processing loop because of
2106 	 * a socket problem or other connection failure (including
2107 	 * digest errors) then we need to generate a state machine
2108 	 * event to shut the connection down.
2109 	 * If the state machine is already in, for example, INIT_ERROR, this
2110 	 * event will get dropped, and the TX thread will never be notified
2111 	 * to shut down.  To be safe, we'll just notify it here.
2112 	 */
2113 	if (conn_failure) {
2114 		if (so_conn->ic_tx_thread_running) {
2115 			so_conn->ic_tx_thread_running = B_FALSE;
2116 			mutex_enter(&so_conn->ic_tx_mutex);
2117 			cv_signal(&so_conn->ic_tx_cv);
2118 			mutex_exit(&so_conn->ic_tx_mutex);
2119 		}
2120 
2121 		idm_conn_event(ic, CE_TRANSPORT_FAIL, rc);
2122 	}
2123 
2124 	idm_conn_rele(ic);
2125 
2126 	thread_exit();
2127 }
2128 
2129 /*
2130  * idm_so_tx
2131  *
2132  * This is the implementation of idm_transport_ops_t's it_tx_pdu entry
2133  * point.  By definition, it is supposed to be fast.  So, simply queue
2134  * the entry and return.  The real work is done by idm_i_so_tx() via
2135  * idm_sotx_thread().
2136  */
2137 
2138 static void
2139 idm_so_tx(idm_conn_t *ic, idm_pdu_t *pdu)
2140 {
2141 	idm_so_conn_t *so_conn = ic->ic_transport_private;
2142 
2143 	ASSERT(pdu->isp_ic == ic);
2144 	mutex_enter(&so_conn->ic_tx_mutex);
2145 
2146 	if (!so_conn->ic_tx_thread_running) {
2147 		mutex_exit(&so_conn->ic_tx_mutex);
2148 		idm_pdu_complete(pdu, IDM_STATUS_ABORTED);
2149 		return;
2150 	}
2151 
2152 	list_insert_tail(&so_conn->ic_tx_list, (void *)pdu);
2153 	cv_signal(&so_conn->ic_tx_cv);
2154 	mutex_exit(&so_conn->ic_tx_mutex);
2155 }
2156 
2157 static idm_status_t
2158 idm_i_so_tx(idm_pdu_t *pdu)
2159 {
2160 	idm_conn_t	*ic = pdu->isp_ic;
2161 	idm_status_t	status = IDM_STATUS_SUCCESS;
2162 	uint8_t		pad[ISCSI_PAD_WORD_LEN];
2163 	int		pad_len;
2164 	uint32_t	hdr_digest_crc;
2165 	uint32_t	data_digest_crc = 0;
2166 	int		total_len = 0;
2167 	int		iovlen = 0;
2168 	struct iovec	iov[6];
2169 	idm_so_conn_t	*so_conn;
2170 
2171 	so_conn = ic->ic_transport_private;
2172 
2173 	/* Setup BHS */
2174 	iov[iovlen].iov_base	= (caddr_t)pdu->isp_hdr;
2175 	iov[iovlen].iov_len	= pdu->isp_hdrlen;
2176 	total_len		+= iov[iovlen].iov_len;
2177 	iovlen++;
2178 
2179 	/* Setup header digest */
2180 	if (((pdu->isp_flags & IDM_PDU_LOGIN_TX) == 0) &&
2181 	    (ic->ic_conn_flags & IDM_CONN_HEADER_DIGEST)) {
2182 		hdr_digest_crc = idm_crc32c(pdu->isp_hdr, pdu->isp_hdrlen);
2183 
2184 		iov[iovlen].iov_base	= (caddr_t)&hdr_digest_crc;
2185 		iov[iovlen].iov_len	= sizeof (hdr_digest_crc);
2186 		total_len		+= iov[iovlen].iov_len;
2187 		iovlen++;
2188 	}
2189 
2190 	/* Setup the data */
2191 	if (pdu->isp_datalen) {
2192 		idm_task_t		*idt;
2193 		idm_buf_t		*idb;
2194 		iscsi_data_hdr_t	*ihp;
2195 		ihp = (iscsi_data_hdr_t *)pdu->isp_hdr;
2196 		/* Write of immediate data */
2197 		if (ic->ic_ffp &&
2198 		    (ihp->opcode == ISCSI_OP_SCSI_CMD ||
2199 		    ihp->opcode == ISCSI_OP_SCSI_DATA)) {
2200 			idt = idm_task_find(ic, ihp->itt, ihp->ttt);
2201 			if (idt) {
2202 				mutex_enter(&idt->idt_mutex);
2203 				idb = idm_buf_find(&idt->idt_outbufv, 0);
2204 				mutex_exit(&idt->idt_mutex);
2205 				/*
2206 				 * If the initiator call to idm_buf_alloc
2207 				 * failed then we can get to this point
2208 				 * without a bound buffer.  The associated
2209 				 * connection failure will clean things up
2210 				 * later.  It would be nice to come up with
2211 				 * a cleaner way to handle this.  In
2212 				 * particular it seems absurd to look up
2213 				 * the task and the buffer just to update
2214 				 * this counter.
2215 				 */
2216 				if (idb)
2217 					idb->idb_xfer_len += pdu->isp_datalen;
2218 				idm_task_rele(idt);
2219 			}
2220 		}
2221 
2222 		iov[iovlen].iov_base = (caddr_t)pdu->isp_data;
2223 		iov[iovlen].iov_len  = pdu->isp_datalen;
2224 		total_len += iov[iovlen].iov_len;
2225 		iovlen++;
2226 	}
2227 
2228 	/* Setup the data pad if necessary */
2229 	pad_len = ((ISCSI_PAD_WORD_LEN -
2230 	    (pdu->isp_datalen & (ISCSI_PAD_WORD_LEN - 1))) &
2231 	    (ISCSI_PAD_WORD_LEN - 1));
2232 
2233 	if (pad_len) {
2234 		bzero(pad, sizeof (pad));
2235 		iov[iovlen].iov_base = (void *)&pad;
2236 		iov[iovlen].iov_len  = pad_len;
2237 		total_len		+= iov[iovlen].iov_len;
2238 		iovlen++;
2239 	}
2240 
2241 	/*
2242 	 * Setup the data digest if enabled.  Data-digest is not sent
2243 	 * for login-phase PDUs.
2244 	 */
2245 	if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) &&
2246 	    ((pdu->isp_flags & IDM_PDU_LOGIN_TX) == 0) &&
2247 	    (pdu->isp_datalen || pad_len)) {
2248 		/*
2249 		 * RFC3720/10.2.3: A zero-length Data Segment also
2250 		 * implies a zero-length data digest.
2251 		 */
2252 		if (pdu->isp_datalen) {
2253 			data_digest_crc = idm_crc32c(pdu->isp_data,
2254 			    pdu->isp_datalen);
2255 		}
2256 		if (pad_len) {
2257 			data_digest_crc = idm_crc32c_continued(&pad,
2258 			    pad_len, data_digest_crc);
2259 		}
2260 
2261 		iov[iovlen].iov_base	= (caddr_t)&data_digest_crc;
2262 		iov[iovlen].iov_len	= sizeof (data_digest_crc);
2263 		total_len		+= iov[iovlen].iov_len;
2264 		iovlen++;
2265 	}
2266 
2267 	/* Transmit the PDU */
2268 	if (idm_iov_sosend(so_conn->ic_so, &iov[0], iovlen,
2269 	    total_len) != 0) {
2270 		/* Set error status */
2271 		IDM_CONN_LOG(CE_WARN,
2272 		    "idm_so_tx: failed to transmit the PDU, so: %p ic: %p "
2273 		    "data: %p", (void *) so_conn->ic_so, (void *) ic,
2274 		    (void *) pdu->isp_data);
2275 		status = IDM_STATUS_IO;
2276 	}
2277 
2278 	/*
2279 	 * Success does not mean that the PDU actually reached the
2280 	 * remote node since it could get dropped along the way.
2281 	 */
2282 	idm_pdu_complete(pdu, status);
2283 
2284 	return (status);
2285 }
2286 
2287 /*
2288  * The idm_so_buf_tx_to_ini() is used by the target iSCSI layer to transmit the
2289  * Data-In PDUs using sockets. Based on the negotiated MaxRecvDataSegmentLength,
2290  * the buffer is segmented into a sequence of Data-In PDUs, ordered by DataSN.
2291  * A target can invoke this function multiple times for a single read command
2292  * (identified by the same ITT) to split the input into several sequences.
2293  *
2294  * DataSN starts with 0 for the first data PDU of an input command and advances
2295  * by 1 for each subsequent data PDU. Each sequence will have its own F bit,
2296  * which is set to 1 for the last data PDU of a sequence.
2297  *
2298  * Scope for Prototype build:
2299  * The data PDUs within a sequence will be sent in order with the buffer offset
2300  * in increasing order. i.e. initiator and target must have negotiated the
2301  * "DataPDUInOrder" to "Yes". The order between sequences is not enforced.
2302  *
2303  * Caller holds idt->idt_mutex
2304  */
2305 static idm_status_t
2306 idm_so_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb)
2307 {
2308 	idm_so_conn_t	*so_conn = idb->idb_ic->ic_transport_private;
2309 	idm_pdu_t	tmppdu;
2310 
2311 	ASSERT(mutex_owned(&idt->idt_mutex));
2312 
2313 	/*
2314 	 * Put the idm_buf_t on the tx queue.  It will be transmitted by
2315 	 * idm_sotx_thread.
2316 	 */
2317 	mutex_enter(&so_conn->ic_tx_mutex);
2318 
2319 	DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic,
2320 	    uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset,
2321 	    uint64_t, 0, uint32_t, 0, uint32_t, 0,
2322 	    uint32_t, idb->idb_xfer_len, int, XFER_BUF_TX_TO_INI);
2323 
2324 	if (!so_conn->ic_tx_thread_running) {
2325 		mutex_exit(&so_conn->ic_tx_mutex);
2326 		/*
2327 		 * Don't release idt->idt_mutex since we're supposed to hold
2328 		 * in when calling idm_buf_tx_to_ini_done
2329 		 */
2330 		DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic,
2331 		    uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset,
2332 		    uint64_t, 0, uint32_t, 0, uint32_t, 0,
2333 		    uint32_t, idb->idb_xfer_len,
2334 		    int, XFER_BUF_TX_TO_INI);
2335 		idm_buf_tx_to_ini_done(idt, idb, IDM_STATUS_ABORTED);
2336 		return (IDM_STATUS_FAIL);
2337 	}
2338 
2339 	/*
2340 	 * Build a template for the data PDU headers we will use so that
2341 	 * the SN values will stay consistent with other PDU's we are
2342 	 * transmitting like R2T and SCSI status.
2343 	 */
2344 	bzero(&idb->idb_data_hdr_tmpl, sizeof (iscsi_hdr_t));
2345 	tmppdu.isp_hdr = &idb->idb_data_hdr_tmpl;
2346 	(*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, &tmppdu,
2347 	    ISCSI_OP_SCSI_DATA_RSP);
2348 	idb->idb_tx_thread = B_TRUE;
2349 	list_insert_tail(&so_conn->ic_tx_list, (void *)idb);
2350 	cv_signal(&so_conn->ic_tx_cv);
2351 	mutex_exit(&so_conn->ic_tx_mutex);
2352 	mutex_exit(&idt->idt_mutex);
2353 
2354 	/*
2355 	 * Returning success here indicates the transfer was successfully
2356 	 * dispatched -- it does not mean that the transfer completed
2357 	 * successfully.
2358 	 */
2359 	return (IDM_STATUS_SUCCESS);
2360 }
2361 
2362 /*
2363  * The idm_so_buf_rx_from_ini() is used by the target iSCSI layer to specify the
2364  * data blocks it is ready to receive from the initiator in response to a WRITE
2365  * SCSI command. The target iSCSI layer passes the information about the desired
2366  * data blocks to the initiator in one R2T PDU. The receiving buffer, the buffer
2367  * offset and datalen are passed via the 'idb' argument.
2368  *
2369  * Scope for Prototype build:
2370  * R2Ts are required for any Data-Out PDU, i.e. initiator and target must have
2371  * negotiated the "InitialR2T" to "Yes".
2372  *
2373  * Caller holds idt->idt_mutex
2374  */
2375 static idm_status_t
2376 idm_so_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb)
2377 {
2378 	idm_pdu_t		*pdu;
2379 	iscsi_rtt_hdr_t		*rtt;
2380 
2381 	ASSERT(mutex_owned(&idt->idt_mutex));
2382 
2383 	DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic,
2384 	    uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset,
2385 	    uint64_t, 0, uint32_t, 0, uint32_t, 0,
2386 	    uint32_t, idb->idb_xfer_len, int, XFER_BUF_RX_FROM_INI);
2387 
2388 	pdu = kmem_cache_alloc(idm.idm_sotx_pdu_cache, KM_SLEEP);
2389 	pdu->isp_ic = idt->idt_ic;
2390 	bzero(pdu->isp_hdr, sizeof (iscsi_rtt_hdr_t));
2391 
2392 	/* iSCSI layer fills the TTT, ITT, StatSN, ExpCmdSN, MaxCmdSN */
2393 	(*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, pdu, ISCSI_OP_RTT_RSP);
2394 
2395 	/* set the rttsn, rtt.flags, rtt.data_offset and rtt.data_length */
2396 	rtt = (iscsi_rtt_hdr_t *)(pdu->isp_hdr);
2397 
2398 	rtt->opcode		= ISCSI_OP_RTT_RSP;
2399 	rtt->flags		= ISCSI_FLAG_FINAL;
2400 	rtt->data_offset	= htonl(idb->idb_bufoffset);
2401 	rtt->data_length	= htonl(idb->idb_xfer_len);
2402 	rtt->rttsn		= htonl(idt->idt_exp_rttsn++);
2403 
2404 	/* Keep track of buffer offsets */
2405 	idb->idb_exp_offset	= idb->idb_bufoffset;
2406 	mutex_exit(&idt->idt_mutex);
2407 
2408 	/*
2409 	 * Transmit the PDU.
2410 	 */
2411 	idm_pdu_tx(pdu);
2412 
2413 	return (IDM_STATUS_SUCCESS);
2414 }
2415 
2416 static idm_status_t
2417 idm_so_buf_alloc(idm_buf_t *idb, uint64_t buflen)
2418 {
2419 	if ((buflen > IDM_SO_BUF_CACHE_LB) && (buflen <= IDM_SO_BUF_CACHE_UB)) {
2420 		idb->idb_buf = kmem_cache_alloc(idm.idm_so_128k_buf_cache,
2421 		    KM_NOSLEEP);
2422 		idb->idb_buf_private = idm.idm_so_128k_buf_cache;
2423 	} else {
2424 		idb->idb_buf = kmem_alloc(buflen, KM_NOSLEEP);
2425 		idb->idb_buf_private = NULL;
2426 	}
2427 
2428 	if (idb->idb_buf == NULL) {
2429 		IDM_CONN_LOG(CE_NOTE,
2430 		    "idm_so_buf_alloc: failed buffer allocation");
2431 		return (IDM_STATUS_FAIL);
2432 	}
2433 
2434 	return (IDM_STATUS_SUCCESS);
2435 }
2436 
2437 /* ARGSUSED */
2438 static idm_status_t
2439 idm_so_buf_setup(idm_buf_t *idb)
2440 {
2441 	/* Ensure bufalloc'd flag is unset */
2442 	idb->idb_bufalloc = B_FALSE;
2443 
2444 	return (IDM_STATUS_SUCCESS);
2445 }
2446 
2447 /* ARGSUSED */
2448 static void
2449 idm_so_buf_teardown(idm_buf_t *idb)
2450 {
2451 	/* nothing to do here */
2452 }
2453 
2454 static void
2455 idm_so_buf_free(idm_buf_t *idb)
2456 {
2457 	if (idb->idb_buf_private == NULL) {
2458 		kmem_free(idb->idb_buf, idb->idb_buflen);
2459 	} else {
2460 		kmem_cache_free(idb->idb_buf_private, idb->idb_buf);
2461 	}
2462 }
2463 
2464 static void
2465 idm_so_send_rtt_data(idm_conn_t *ic, idm_task_t *idt, idm_buf_t *idb,
2466     uint32_t offset, uint32_t length)
2467 {
2468 	idm_so_conn_t	*so_conn = ic->ic_transport_private;
2469 	idm_pdu_t	tmppdu;
2470 	idm_buf_t	*rtt_buf;
2471 
2472 	ASSERT(mutex_owned(&idt->idt_mutex));
2473 
2474 	/*
2475 	 * Allocate a buffer to represent the RTT transfer.  We could further
2476 	 * optimize this by allocating the buffers internally from an rtt
2477 	 * specific buffer cache since this is socket-specific code but for
2478 	 * now we will keep it simple.
2479 	 */
2480 	rtt_buf = idm_buf_alloc(ic, (uint8_t *)idb->idb_buf + offset, length);
2481 	if (rtt_buf == NULL) {
2482 		/*
2483 		 * If we're in FFP then the failure was likely a resource
2484 		 * allocation issue and we should close the connection by
2485 		 * sending a CE_TRANSPORT_FAIL event.
2486 		 *
2487 		 * If we're not in FFP then idm_buf_alloc will always
2488 		 * fail and the state is transitioning to "complete" anyway
2489 		 * so we won't bother to send an event.
2490 		 */
2491 		mutex_enter(&ic->ic_state_mutex);
2492 		if (ic->ic_ffp)
2493 			idm_conn_event_locked(ic, CE_TRANSPORT_FAIL,
2494 			    NULL, CT_NONE);
2495 		mutex_exit(&ic->ic_state_mutex);
2496 		return;
2497 	}
2498 
2499 	rtt_buf->idb_buf_cb = NULL;
2500 	rtt_buf->idb_cb_arg = NULL;
2501 	rtt_buf->idb_bufoffset = offset;
2502 	rtt_buf->idb_xfer_len = length;
2503 	rtt_buf->idb_ic = idt->idt_ic;
2504 	rtt_buf->idb_task_binding = idt;
2505 
2506 	/*
2507 	 * Put the idm_buf_t on the tx queue.  It will be transmitted by
2508 	 * idm_sotx_thread.
2509 	 */
2510 	mutex_enter(&so_conn->ic_tx_mutex);
2511 
2512 	if (!so_conn->ic_tx_thread_running) {
2513 		idm_buf_free(rtt_buf);
2514 		mutex_exit(&so_conn->ic_tx_mutex);
2515 		return;
2516 	}
2517 
2518 	/*
2519 	 * This new buffer represents an additional reference on the task
2520 	 */
2521 	idm_task_hold(idt);
2522 
2523 	/*
2524 	 * Build a template for the data PDU headers we will use so that
2525 	 * the SN values will stay consistent with other PDU's we are
2526 	 * transmitting like R2T and SCSI status.
2527 	 */
2528 	bzero(&rtt_buf->idb_data_hdr_tmpl, sizeof (iscsi_hdr_t));
2529 	tmppdu.isp_hdr = &rtt_buf->idb_data_hdr_tmpl;
2530 	(*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, &tmppdu,
2531 	    ISCSI_OP_SCSI_DATA);
2532 	rtt_buf->idb_tx_thread = B_TRUE;
2533 	rtt_buf->idb_in_transport = B_TRUE;
2534 	list_insert_tail(&so_conn->ic_tx_list, (void *)rtt_buf);
2535 	cv_signal(&so_conn->ic_tx_cv);
2536 	mutex_exit(&so_conn->ic_tx_mutex);
2537 }
2538 
2539 static void
2540 idm_so_send_rtt_data_done(idm_task_t *idt, idm_buf_t *idb)
2541 {
2542 	/*
2543 	 * Don't worry about status -- we assume any error handling
2544 	 * is performed by the caller (idm_sotx_thread).
2545 	 */
2546 	idb->idb_in_transport = B_FALSE;
2547 	idm_task_rele(idt);
2548 	idm_buf_free(idb);
2549 }
2550 
2551 static idm_status_t
2552 idm_so_send_buf_region(idm_task_t *idt, idm_buf_t *idb,
2553     uint32_t buf_region_offset, uint32_t buf_region_length)
2554 {
2555 	idm_conn_t		*ic;
2556 	uint32_t		max_dataseglen;
2557 	size_t			remainder, chunk;
2558 	uint32_t		data_offset = buf_region_offset;
2559 	iscsi_data_hdr_t	*bhs;
2560 	idm_pdu_t		*pdu;
2561 	idm_status_t		tx_status;
2562 
2563 	ASSERT(mutex_owned(&idt->idt_mutex));
2564 
2565 	ic = idt->idt_ic;
2566 
2567 	max_dataseglen = ic->ic_conn_params.max_xmit_dataseglen;
2568 	remainder = buf_region_length;
2569 
2570 	while (remainder) {
2571 		if (idt->idt_state != TASK_ACTIVE) {
2572 			ASSERT((idt->idt_state != TASK_IDLE) &&
2573 			    (idt->idt_state != TASK_COMPLETE));
2574 			return (IDM_STATUS_ABORTED);
2575 		}
2576 
2577 		/* check to see if we need to chunk the data */
2578 		if (remainder > max_dataseglen) {
2579 			chunk = max_dataseglen;
2580 		} else {
2581 			chunk = remainder;
2582 		}
2583 
2584 		/* Data PDU headers will always be sizeof (iscsi_hdr_t) */
2585 		pdu = kmem_cache_alloc(idm.idm_sotx_pdu_cache, KM_SLEEP);
2586 		pdu->isp_ic = ic;
2587 
2588 		/*
2589 		 * We've already built a build a header template
2590 		 * to use during the transfer.  Use this template so that
2591 		 * the SN values stay consistent with any unrelated PDU's
2592 		 * being transmitted.
2593 		 */
2594 		bcopy(&idb->idb_data_hdr_tmpl, pdu->isp_hdr,
2595 		    sizeof (iscsi_hdr_t));
2596 
2597 		/*
2598 		 * Set DataSN, data offset, and flags in BHS
2599 		 * For the prototype build, A = 0, S = 0, U = 0
2600 		 */
2601 		bhs = (iscsi_data_hdr_t *)(pdu->isp_hdr);
2602 
2603 		bhs->datasn		= htonl(idt->idt_exp_datasn++);
2604 
2605 		hton24(bhs->dlength, chunk);
2606 		bhs->offset = htonl(idb->idb_bufoffset + data_offset);
2607 
2608 		if (chunk == remainder) {
2609 			bhs->flags = ISCSI_FLAG_FINAL; /* F bit set to 1 */
2610 		}
2611 
2612 		/* Instrument the data-send DTrace probe. */
2613 		if (IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA_RSP) {
2614 			DTRACE_ISCSI_2(data__send,
2615 			    idm_conn_t *, idt->idt_ic,
2616 			    iscsi_data_rsp_hdr_t *,
2617 			    (iscsi_data_rsp_hdr_t *)pdu->isp_hdr);
2618 		}
2619 		/* setup data */
2620 		pdu->isp_data	=  (uint8_t *)idb->idb_buf + data_offset;
2621 		pdu->isp_datalen = (uint_t)chunk;
2622 		remainder	-= chunk;
2623 		data_offset	+= chunk;
2624 
2625 		/*
2626 		 * Now that we're done working with idt_exp_datasn,
2627 		 * idt->idt_state and idb->idb_bufoffset we can release
2628 		 * the task lock -- don't want to hold it across the
2629 		 * call to idm_i_so_tx since we could block.
2630 		 */
2631 		mutex_exit(&idt->idt_mutex);
2632 
2633 		/*
2634 		 * Transmit the PDU.  Call the internal routine directly
2635 		 * as there is already implicit ordering.
2636 		 */
2637 		if ((tx_status = idm_i_so_tx(pdu)) != IDM_STATUS_SUCCESS) {
2638 			mutex_enter(&idt->idt_mutex);
2639 			return (tx_status);
2640 		}
2641 
2642 		mutex_enter(&idt->idt_mutex);
2643 		idt->idt_tx_bytes += chunk;
2644 	}
2645 
2646 	return (IDM_STATUS_SUCCESS);
2647 }
2648 
2649 /*
2650  * TX PDU cache
2651  */
2652 /* ARGSUSED */
2653 int
2654 idm_sotx_pdu_constructor(void *hdl, void *arg, int flags)
2655 {
2656 	idm_pdu_t	*pdu = hdl;
2657 
2658 	bzero(pdu, sizeof (idm_pdu_t));
2659 	pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); /* Ptr arithmetic */
2660 	pdu->isp_hdrlen = sizeof (iscsi_hdr_t);
2661 	pdu->isp_callback = idm_sotx_cache_pdu_cb;
2662 	pdu->isp_magic = IDM_PDU_MAGIC;
2663 	bzero(pdu->isp_hdr, sizeof (iscsi_hdr_t));
2664 
2665 	return (0);
2666 }
2667 
2668 /* ARGSUSED */
2669 void
2670 idm_sotx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status)
2671 {
2672 	/* reset values between use */
2673 	pdu->isp_datalen = 0;
2674 
2675 	kmem_cache_free(idm.idm_sotx_pdu_cache, pdu);
2676 }
2677 
2678 /*
2679  * RX PDU cache
2680  */
2681 /* ARGSUSED */
2682 int
2683 idm_sorx_pdu_constructor(void *hdl, void *arg, int flags)
2684 {
2685 	idm_pdu_t	*pdu = hdl;
2686 
2687 	bzero(pdu, sizeof (idm_pdu_t));
2688 	pdu->isp_magic = IDM_PDU_MAGIC;
2689 	pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); /* Ptr arithmetic */
2690 	pdu->isp_callback = idm_sorx_cache_pdu_cb;
2691 
2692 	return (0);
2693 }
2694 
2695 /* ARGSUSED */
2696 static void
2697 idm_sorx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status)
2698 {
2699 	pdu->isp_iovlen = 0;
2700 	pdu->isp_sorx_buf = 0;
2701 	kmem_cache_free(idm.idm_sorx_pdu_cache, pdu);
2702 }
2703 
2704 static void
2705 idm_sorx_addl_pdu_cb(idm_pdu_t *pdu, idm_status_t status)
2706 {
2707 	/*
2708 	 * We had to modify our cached RX PDU with a longer header buffer
2709 	 * and/or a longer data buffer.  Release the new buffers and fix
2710 	 * the fields back to what we would expect for a cached RX PDU.
2711 	 */
2712 	if (pdu->isp_flags & IDM_PDU_ADDL_HDR) {
2713 		kmem_free(pdu->isp_hdr, pdu->isp_hdrlen);
2714 	}
2715 	if (pdu->isp_flags & IDM_PDU_ADDL_DATA) {
2716 		kmem_free(pdu->isp_data, pdu->isp_datalen);
2717 	}
2718 	pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1);
2719 	pdu->isp_hdrlen = sizeof (iscsi_hdr_t);
2720 	pdu->isp_data = NULL;
2721 	pdu->isp_datalen = 0;
2722 	pdu->isp_sorx_buf = 0;
2723 	pdu->isp_callback = idm_sorx_cache_pdu_cb;
2724 	idm_sorx_cache_pdu_cb(pdu, status);
2725 }
2726 
2727 /*
2728  * This thread is only active when I/O is queued for transmit
2729  * because the socket is busy.
2730  */
2731 void
2732 idm_sotx_thread(void *arg)
2733 {
2734 	idm_conn_t	*ic = arg;
2735 	idm_tx_obj_t	*object, *next;
2736 	idm_so_conn_t	*so_conn;
2737 	idm_status_t	status = IDM_STATUS_SUCCESS;
2738 
2739 	idm_conn_hold(ic);
2740 
2741 	mutex_enter(&ic->ic_mutex);
2742 	so_conn = ic->ic_transport_private;
2743 	so_conn->ic_tx_thread_running = B_TRUE;
2744 	so_conn->ic_tx_thread_did = so_conn->ic_tx_thread->t_did;
2745 	cv_signal(&ic->ic_cv);
2746 	mutex_exit(&ic->ic_mutex);
2747 
2748 	mutex_enter(&so_conn->ic_tx_mutex);
2749 
2750 	while (so_conn->ic_tx_thread_running) {
2751 		while (list_is_empty(&so_conn->ic_tx_list)) {
2752 			DTRACE_PROBE1(soconn__tx__sleep, idm_conn_t *, ic);
2753 			cv_wait(&so_conn->ic_tx_cv, &so_conn->ic_tx_mutex);
2754 			DTRACE_PROBE1(soconn__tx__wakeup, idm_conn_t *, ic);
2755 
2756 			if (!so_conn->ic_tx_thread_running) {
2757 				goto tx_bail;
2758 			}
2759 		}
2760 
2761 		object = (idm_tx_obj_t *)list_head(&so_conn->ic_tx_list);
2762 		list_remove(&so_conn->ic_tx_list, object);
2763 		mutex_exit(&so_conn->ic_tx_mutex);
2764 
2765 		switch (object->idm_tx_obj_magic) {
2766 		case IDM_PDU_MAGIC:
2767 			DTRACE_PROBE2(soconn__tx__pdu, idm_conn_t *, ic,
2768 			    idm_pdu_t *, (idm_pdu_t *)object);
2769 
2770 			status = idm_i_so_tx((idm_pdu_t *)object);
2771 			break;
2772 
2773 		case IDM_BUF_MAGIC: {
2774 			idm_buf_t *idb = (idm_buf_t *)object;
2775 			idm_task_t *idt = idb->idb_task_binding;
2776 
2777 			DTRACE_PROBE2(soconn__tx__buf, idm_conn_t *, ic,
2778 			    idm_buf_t *, idb);
2779 
2780 			mutex_enter(&idt->idt_mutex);
2781 			status = idm_so_send_buf_region(idt,
2782 			    idb, 0, idb->idb_xfer_len);
2783 
2784 			/*
2785 			 * TX thread owns the buffer so we expect it to
2786 			 * be "in transport"
2787 			 */
2788 			ASSERT(idb->idb_in_transport);
2789 			if (IDM_CONN_ISTGT(ic)) {
2790 				/*
2791 				 * idm_buf_tx_to_ini_done releases
2792 				 * idt->idt_mutex
2793 				 */
2794 				DTRACE_ISCSI_8(xfer__done,
2795 				    idm_conn_t *, idt->idt_ic,
2796 				    uintptr_t, idb->idb_buf,
2797 				    uint32_t, idb->idb_bufoffset,
2798 				    uint64_t, 0, uint32_t, 0, uint32_t, 0,
2799 				    uint32_t, idb->idb_xfer_len,
2800 				    int, XFER_BUF_TX_TO_INI);
2801 				idm_buf_tx_to_ini_done(idt, idb, status);
2802 			} else {
2803 				idm_so_send_rtt_data_done(idt, idb);
2804 				mutex_exit(&idt->idt_mutex);
2805 			}
2806 			break;
2807 		}
2808 
2809 		default:
2810 			IDM_CONN_LOG(CE_WARN, "idm_sotx_thread: Unknown magic "
2811 			    "(0x%08x)", object->idm_tx_obj_magic);
2812 			status = IDM_STATUS_FAIL;
2813 		}
2814 
2815 		mutex_enter(&so_conn->ic_tx_mutex);
2816 
2817 		if (status != IDM_STATUS_SUCCESS) {
2818 			so_conn->ic_tx_thread_running = B_FALSE;
2819 			idm_conn_event(ic, CE_TRANSPORT_FAIL, status);
2820 		}
2821 	}
2822 
2823 	/*
2824 	 * Before we leave, we need to abort every item remaining in the
2825 	 * TX list.
2826 	 */
2827 
2828 tx_bail:
2829 	object = (idm_tx_obj_t *)list_head(&so_conn->ic_tx_list);
2830 
2831 	while (object != NULL) {
2832 		next = list_next(&so_conn->ic_tx_list, object);
2833 
2834 		list_remove(&so_conn->ic_tx_list, object);
2835 		switch (object->idm_tx_obj_magic) {
2836 		case IDM_PDU_MAGIC:
2837 			idm_pdu_complete((idm_pdu_t *)object,
2838 			    IDM_STATUS_ABORTED);
2839 			break;
2840 
2841 		case IDM_BUF_MAGIC: {
2842 			idm_buf_t *idb = (idm_buf_t *)object;
2843 			idm_task_t *idt = idb->idb_task_binding;
2844 			mutex_exit(&so_conn->ic_tx_mutex);
2845 			mutex_enter(&idt->idt_mutex);
2846 			/*
2847 			 * TX thread owns the buffer so we expect it to
2848 			 * be "in transport"
2849 			 */
2850 			ASSERT(idb->idb_in_transport);
2851 			if (IDM_CONN_ISTGT(ic)) {
2852 				/*
2853 				 * idm_buf_tx_to_ini_done releases
2854 				 * idt->idt_mutex
2855 				 */
2856 				DTRACE_ISCSI_8(xfer__done,
2857 				    idm_conn_t *, idt->idt_ic,
2858 				    uintptr_t, idb->idb_buf,
2859 				    uint32_t, idb->idb_bufoffset,
2860 				    uint64_t, 0, uint32_t, 0, uint32_t, 0,
2861 				    uint32_t, idb->idb_xfer_len,
2862 				    int, XFER_BUF_TX_TO_INI);
2863 				idm_buf_tx_to_ini_done(idt, idb,
2864 				    IDM_STATUS_ABORTED);
2865 			} else {
2866 				idm_so_send_rtt_data_done(idt, idb);
2867 				mutex_exit(&idt->idt_mutex);
2868 			}
2869 			mutex_enter(&so_conn->ic_tx_mutex);
2870 			break;
2871 		}
2872 		default:
2873 			IDM_CONN_LOG(CE_WARN,
2874 			    "idm_sotx_thread: Unexpected magic "
2875 			    "(0x%08x)", object->idm_tx_obj_magic);
2876 		}
2877 
2878 		object = next;
2879 	}
2880 
2881 	mutex_exit(&so_conn->ic_tx_mutex);
2882 	idm_conn_rele(ic);
2883 	thread_exit();
2884 	/*NOTREACHED*/
2885 }
2886 
2887 static void
2888 idm_so_socket_set_nonblock(struct sonode *node)
2889 {
2890 	(void) VOP_SETFL(node->so_vnode, node->so_flag,
2891 	    (node->so_state | FNONBLOCK), CRED(), NULL);
2892 }
2893 
2894 static void
2895 idm_so_socket_set_block(struct sonode *node)
2896 {
2897 	(void) VOP_SETFL(node->so_vnode, node->so_flag,
2898 	    (node->so_state & (~FNONBLOCK)), CRED(), NULL);
2899 }
2900 
2901 
2902 /*
2903  * Called by kernel sockets when the connection has been accepted or
2904  * rejected. In early volo, a "disconnect" callback was sent instead of
2905  * "connectfailed", so we check for both.
2906  */
2907 /* ARGSUSED */
2908 void
2909 idm_so_timed_socket_connect_cb(ksocket_t ks,
2910     ksocket_callback_event_t ev, void *arg, uintptr_t info)
2911 {
2912 	idm_so_timed_socket_t	*itp = arg;
2913 	ASSERT(itp != NULL);
2914 	ASSERT(ev == KSOCKET_EV_CONNECTED ||
2915 	    ev == KSOCKET_EV_CONNECTFAILED ||
2916 	    ev == KSOCKET_EV_DISCONNECTED);
2917 
2918 	mutex_enter(&idm_so_timed_socket_mutex);
2919 	itp->it_callback_called = B_TRUE;
2920 	if (ev == KSOCKET_EV_CONNECTED) {
2921 		itp->it_socket_error_code = 0;
2922 	} else {
2923 		/* Make sure the error code is non-zero on error */
2924 		if (info == 0)
2925 			info = ECONNRESET;
2926 		itp->it_socket_error_code = (int)info;
2927 	}
2928 	cv_signal(&itp->it_cv);
2929 	mutex_exit(&idm_so_timed_socket_mutex);
2930 }
2931 
2932 int
2933 idm_so_timed_socket_connect(ksocket_t ks,
2934     struct sockaddr_storage *sa, int sa_sz, int login_max_usec)
2935 {
2936 	clock_t			conn_login_max;
2937 	int			rc, nonblocking, rval;
2938 	idm_so_timed_socket_t	it;
2939 	ksocket_callbacks_t	ks_cb;
2940 
2941 	conn_login_max = ddi_get_lbolt() + drv_usectohz(login_max_usec);
2942 
2943 	/*
2944 	 * Set to non-block socket mode, with callback on connect
2945 	 * Early volo used "disconnected" instead of "connectfailed",
2946 	 * so set callback to look for both.
2947 	 */
2948 	bzero(&it, sizeof (it));
2949 	ks_cb.ksock_cb_flags = KSOCKET_CB_CONNECTED |
2950 	    KSOCKET_CB_CONNECTFAILED | KSOCKET_CB_DISCONNECTED;
2951 	ks_cb.ksock_cb_connected = idm_so_timed_socket_connect_cb;
2952 	ks_cb.ksock_cb_connectfailed = idm_so_timed_socket_connect_cb;
2953 	ks_cb.ksock_cb_disconnected = idm_so_timed_socket_connect_cb;
2954 	cv_init(&it.it_cv, NULL, CV_DEFAULT, NULL);
2955 	rc = ksocket_setcallbacks(ks, &ks_cb, &it, CRED());
2956 	if (rc != 0)
2957 		return (rc);
2958 
2959 	/* Set to non-blocking mode */
2960 	nonblocking = 1;
2961 	rc = ksocket_ioctl(ks, FIONBIO, (intptr_t)&nonblocking, &rval,
2962 	    CRED());
2963 	if (rc != 0)
2964 		goto cleanup;
2965 
2966 	bzero(&it, sizeof (it));
2967 	for (;;) {
2968 		/*
2969 		 * Warning -- in a loopback scenario, the call to
2970 		 * the connect_cb can occur inside the call to
2971 		 * ksocket_connect. Do not hold the mutex around the
2972 		 * call to ksocket_connect.
2973 		 */
2974 		rc = ksocket_connect(ks, (struct sockaddr *)sa, sa_sz, CRED());
2975 		if (rc == 0 || rc == EISCONN) {
2976 			/* socket success or already success */
2977 			rc = 0;
2978 			break;
2979 		}
2980 		if ((rc != EINPROGRESS) && (rc != EALREADY)) {
2981 			break;
2982 		}
2983 
2984 		/* TCP connect still in progress. See if out of time. */
2985 		if (ddi_get_lbolt() > conn_login_max) {
2986 			/*
2987 			 * Connection retry timeout,
2988 			 * failed connect to target.
2989 			 */
2990 			rc = ETIMEDOUT;
2991 			break;
2992 		}
2993 
2994 		/*
2995 		 * TCP connect still in progress.  Sleep until callback.
2996 		 * Do NOT go to sleep if the callback already occurred!
2997 		 */
2998 		mutex_enter(&idm_so_timed_socket_mutex);
2999 		if (!it.it_callback_called) {
3000 			(void) cv_timedwait(&it.it_cv,
3001 			    &idm_so_timed_socket_mutex, conn_login_max);
3002 		}
3003 		if (it.it_callback_called) {
3004 			rc = it.it_socket_error_code;
3005 			mutex_exit(&idm_so_timed_socket_mutex);
3006 			break;
3007 		}
3008 		/* If timer expires, go call ksocket_connect one last time. */
3009 		mutex_exit(&idm_so_timed_socket_mutex);
3010 	}
3011 
3012 	/* resume blocking mode */
3013 	nonblocking = 0;
3014 	(void)  ksocket_ioctl(ks, FIONBIO, (intptr_t)&nonblocking, &rval,
3015 	    CRED());
3016 cleanup:
3017 	ksocket_setcallbacks(ks, NULL, NULL, CRED());
3018 	cv_destroy(&it.it_cv);
3019 	if (rc != 0) {
3020 		idm_soshutdown(ks);
3021 	}
3022 	return (rc);
3023 }
3024 
3025 
3026 void
3027 idm_addr_to_sa(idm_addr_t *dportal, struct sockaddr_storage *sa)
3028 {
3029 	int			dp_addr_size;
3030 	struct sockaddr_in	*sin;
3031 	struct sockaddr_in6	*sin6;
3032 
3033 	/* Build sockaddr_storage for this portal (idm_addr_t) */
3034 	bzero(sa, sizeof (*sa));
3035 	dp_addr_size = dportal->a_addr.i_insize;
3036 	if (dp_addr_size == sizeof (struct in_addr)) {
3037 		/* IPv4 */
3038 		sa->ss_family = AF_INET;
3039 		sin = (struct sockaddr_in *)sa;
3040 		sin->sin_port = htons(dportal->a_port);
3041 		bcopy(&dportal->a_addr.i_addr.in4,
3042 		    &sin->sin_addr, sizeof (struct in_addr));
3043 	} else if (dp_addr_size == sizeof (struct in6_addr)) {
3044 		/* IPv6 */
3045 		sa->ss_family = AF_INET6;
3046 		sin6 = (struct sockaddr_in6 *)sa;
3047 		sin6->sin6_port = htons(dportal->a_port);
3048 		bcopy(&dportal->a_addr.i_addr.in6,
3049 		    &sin6->sin6_addr, sizeof (struct in6_addr));
3050 	} else {
3051 		ASSERT(0);
3052 	}
3053 }
3054 
3055 
3056 /*
3057  * return a human-readable form of a sockaddr_storage, in the form
3058  * [ip-address]:port.  This is used in calls to logging functions.
3059  * If several calls to idm_sa_ntop are made within the same invocation
3060  * of a logging function, then each one needs its own buf.
3061  */
3062 const char *
3063 idm_sa_ntop(const struct sockaddr_storage *sa,
3064     char *buf, size_t size)
3065 {
3066 	static const char bogus_ip[] = "[0].-1";
3067 	char tmp[INET6_ADDRSTRLEN];
3068 
3069 	switch (sa->ss_family) {
3070 	case AF_INET6:
3071 		{
3072 			const struct sockaddr_in6 *in6 =
3073 			    (const struct sockaddr_in6 *) sa;
3074 
3075 			if (inet_ntop(in6->sin6_family,
3076 			    &in6->sin6_addr, tmp, sizeof (tmp)) == NULL) {
3077 				goto err;
3078 			}
3079 			if (strlen(tmp) + sizeof ("[].65535") > size) {
3080 				goto err;
3081 			}
3082 			/* struct sockaddr_storage gets port info from v4 loc */
3083 			(void) snprintf(buf, size, "[%s].%u", tmp,
3084 			    ntohs(in6->sin6_port));
3085 			return (buf);
3086 		}
3087 	case AF_INET:
3088 		{
3089 			const struct sockaddr_in *in =
3090 			    (const struct sockaddr_in *) sa;
3091 
3092 			if (inet_ntop(in->sin_family, &in->sin_addr,
3093 			    tmp, sizeof (tmp)) == NULL) {
3094 				goto err;
3095 			}
3096 			if (strlen(tmp) + sizeof ("[].65535") > size) {
3097 				goto err;
3098 			}
3099 			(void) snprintf(buf, size,  "[%s].%u", tmp,
3100 			    ntohs(in->sin_port));
3101 			return (buf);
3102 		}
3103 	default:
3104 		break;
3105 	}
3106 err:
3107 	(void) snprintf(buf, size, "%s", bogus_ip);
3108 	return (buf);
3109 }
3110