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