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 /* 2263528ae4SJames Moore * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23a6d42e7dSPeter Dunlap * Use is subject to license terms. 24a6d42e7dSPeter Dunlap */ 25a6d42e7dSPeter Dunlap 26a6d42e7dSPeter Dunlap #include <sys/conf.h> 27a6d42e7dSPeter Dunlap #include <sys/stat.h> 28a6d42e7dSPeter Dunlap #include <sys/file.h> 29a6d42e7dSPeter Dunlap #include <sys/ddi.h> 30a6d42e7dSPeter Dunlap #include <sys/sunddi.h> 31a6d42e7dSPeter Dunlap #include <sys/modctl.h> 32a6d42e7dSPeter Dunlap #include <sys/priv.h> 33a6d42e7dSPeter Dunlap #include <sys/cpuvar.h> 34a6d42e7dSPeter Dunlap #include <sys/socket.h> 35a6d42e7dSPeter Dunlap #include <sys/strsubr.h> 36a6d42e7dSPeter Dunlap #include <sys/sysmacros.h> 37a6d42e7dSPeter Dunlap #include <sys/sdt.h> 38a6d42e7dSPeter Dunlap #include <netinet/tcp.h> 39a6d42e7dSPeter Dunlap #include <inet/tcp.h> 40a6d42e7dSPeter Dunlap #include <sys/socketvar.h> 41a6d42e7dSPeter Dunlap #include <sys/pathname.h> 42a6d42e7dSPeter Dunlap #include <sys/fs/snode.h> 43a6d42e7dSPeter Dunlap #include <sys/fs/dv_node.h> 44a6d42e7dSPeter Dunlap #include <sys/vnode.h> 45a6d42e7dSPeter Dunlap #include <netinet/in.h> 46a6d42e7dSPeter Dunlap #include <net/if.h> 47a6d42e7dSPeter Dunlap #include <sys/sockio.h> 480f1702c5SYu Xiangning #include <sys/ksocket.h> 49*56261083SCharles Ting #include <sys/iscsi_protocol.h> 50a6d42e7dSPeter Dunlap #include <sys/idm/idm.h> 51a6d42e7dSPeter Dunlap #include <sys/idm/idm_so.h> 52a6d42e7dSPeter Dunlap #include <sys/idm/idm_text.h> 53a6d42e7dSPeter Dunlap 54aff4bce5Syi zhang - Sun Microsystems - Beijing China #define IN_PROGRESS_DELAY 1 55aff4bce5Syi zhang - Sun Microsystems - Beijing China 56a6d42e7dSPeter Dunlap /* 57a6d42e7dSPeter Dunlap * in6addr_any is currently all zeroes, but use the macro in case this 58a6d42e7dSPeter Dunlap * ever changes. 59a6d42e7dSPeter Dunlap */ 60e42a0851Speter dunlap static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 61a6d42e7dSPeter Dunlap 62a6d42e7dSPeter Dunlap static void idm_sorx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status); 63a6d42e7dSPeter Dunlap static void idm_sorx_addl_pdu_cb(idm_pdu_t *pdu, idm_status_t status); 64a6d42e7dSPeter Dunlap static void idm_sotx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status); 65a6d42e7dSPeter Dunlap 660f1702c5SYu Xiangning static idm_status_t idm_so_conn_create_common(idm_conn_t *ic, ksocket_t new_so); 67a6d42e7dSPeter Dunlap static void idm_so_conn_destroy_common(idm_conn_t *ic); 68a6d42e7dSPeter Dunlap static void idm_so_conn_connect_common(idm_conn_t *ic); 69a6d42e7dSPeter Dunlap 70a6d42e7dSPeter Dunlap static void idm_set_ini_preconnect_options(idm_so_conn_t *sc); 71a6d42e7dSPeter Dunlap static void idm_set_ini_postconnect_options(idm_so_conn_t *sc); 720f1702c5SYu Xiangning static void idm_set_tgt_connect_options(ksocket_t so); 73a6d42e7dSPeter Dunlap static idm_status_t idm_i_so_tx(idm_pdu_t *pdu); 74a6d42e7dSPeter Dunlap 75a6d42e7dSPeter Dunlap static idm_status_t idm_sorecvdata(idm_conn_t *ic, idm_pdu_t *pdu); 7630e7468fSPeter Dunlap static void idm_so_send_rtt_data(idm_conn_t *ic, idm_task_t *idt, 7730e7468fSPeter Dunlap idm_buf_t *idb, uint32_t offset, uint32_t length); 7830e7468fSPeter Dunlap static void idm_so_send_rtt_data_done(idm_task_t *idt, idm_buf_t *idb); 7930e7468fSPeter Dunlap static idm_status_t idm_so_send_buf_region(idm_task_t *idt, 80a6d42e7dSPeter Dunlap idm_buf_t *idb, uint32_t buf_region_offset, uint32_t buf_region_length); 81a6d42e7dSPeter Dunlap 82a6d42e7dSPeter Dunlap static uint32_t idm_fill_iov(idm_pdu_t *pdu, idm_buf_t *idb, 83a6d42e7dSPeter Dunlap uint32_t ro, uint32_t dlength); 84a6d42e7dSPeter Dunlap 85a6d42e7dSPeter Dunlap static idm_status_t idm_so_handle_digest(idm_conn_t *it, 86a6d42e7dSPeter Dunlap nvpair_t *digest_choice, const idm_kv_xlate_t *ikvx); 87a6d42e7dSPeter Dunlap 88aff4bce5Syi zhang - Sun Microsystems - Beijing China static void idm_so_socket_set_nonblock(struct sonode *node); 89aff4bce5Syi zhang - Sun Microsystems - Beijing China static void idm_so_socket_set_block(struct sonode *node); 90aff4bce5Syi zhang - Sun Microsystems - Beijing China 91a6d42e7dSPeter Dunlap /* 92a6d42e7dSPeter Dunlap * Transport ops prototypes 93a6d42e7dSPeter Dunlap */ 94a6d42e7dSPeter Dunlap static void idm_so_tx(idm_conn_t *ic, idm_pdu_t *pdu); 95a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb); 96a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb); 97a6d42e7dSPeter Dunlap static void idm_so_rx_datain(idm_conn_t *ic, idm_pdu_t *pdu); 98a6d42e7dSPeter Dunlap static void idm_so_rx_rtt(idm_conn_t *ic, idm_pdu_t *pdu); 99a6d42e7dSPeter Dunlap static void idm_so_rx_dataout(idm_conn_t *ic, idm_pdu_t *pdu); 100a6d42e7dSPeter Dunlap static idm_status_t idm_so_free_task_rsrc(idm_task_t *idt); 101a6d42e7dSPeter Dunlap static kv_status_t idm_so_negotiate_key_values(idm_conn_t *it, 102a6d42e7dSPeter Dunlap nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl); 10330e7468fSPeter Dunlap static void idm_so_notice_key_values(idm_conn_t *it, 104a6d42e7dSPeter Dunlap nvlist_t *negotiated_nvl); 105*56261083SCharles Ting static kv_status_t idm_so_declare_key_values(idm_conn_t *it, 106*56261083SCharles Ting nvlist_t *config_nvl, nvlist_t *outgoing_nvl); 107a6d42e7dSPeter Dunlap static boolean_t idm_so_conn_is_capable(idm_conn_req_t *ic, 108a6d42e7dSPeter Dunlap idm_transport_caps_t *caps); 109a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_alloc(idm_buf_t *idb, uint64_t buflen); 110a6d42e7dSPeter Dunlap static void idm_so_buf_free(idm_buf_t *idb); 111a6d42e7dSPeter Dunlap static idm_status_t idm_so_buf_setup(idm_buf_t *idb); 112a6d42e7dSPeter Dunlap static void idm_so_buf_teardown(idm_buf_t *idb); 113a6d42e7dSPeter Dunlap static idm_status_t idm_so_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t *is); 114a6d42e7dSPeter Dunlap static void idm_so_tgt_svc_destroy(idm_svc_t *is); 115a6d42e7dSPeter Dunlap static idm_status_t idm_so_tgt_svc_online(idm_svc_t *is); 116a6d42e7dSPeter Dunlap static void idm_so_tgt_svc_offline(idm_svc_t *is); 117a6d42e7dSPeter Dunlap static void idm_so_tgt_conn_destroy(idm_conn_t *ic); 118a6d42e7dSPeter Dunlap static idm_status_t idm_so_tgt_conn_connect(idm_conn_t *ic); 119a6d42e7dSPeter Dunlap static void idm_so_conn_disconnect(idm_conn_t *ic); 120a6d42e7dSPeter Dunlap static idm_status_t idm_so_ini_conn_create(idm_conn_req_t *cr, idm_conn_t *ic); 121a6d42e7dSPeter Dunlap static void idm_so_ini_conn_destroy(idm_conn_t *ic); 122a6d42e7dSPeter Dunlap static idm_status_t idm_so_ini_conn_connect(idm_conn_t *ic); 123a6d42e7dSPeter Dunlap 124a6d42e7dSPeter Dunlap /* 125a6d42e7dSPeter Dunlap * IDM Native Sockets transport operations 126a6d42e7dSPeter Dunlap */ 127a6d42e7dSPeter Dunlap static 128a6d42e7dSPeter Dunlap idm_transport_ops_t idm_so_transport_ops = { 129a6d42e7dSPeter Dunlap idm_so_tx, /* it_tx_pdu */ 130a6d42e7dSPeter Dunlap idm_so_buf_tx_to_ini, /* it_buf_tx_to_ini */ 131a6d42e7dSPeter Dunlap idm_so_buf_rx_from_ini, /* it_buf_rx_from_ini */ 132a6d42e7dSPeter Dunlap idm_so_rx_datain, /* it_rx_datain */ 133a6d42e7dSPeter Dunlap idm_so_rx_rtt, /* it_rx_rtt */ 134a6d42e7dSPeter Dunlap idm_so_rx_dataout, /* it_rx_dataout */ 135a6d42e7dSPeter Dunlap NULL, /* it_alloc_conn_rsrc */ 136a6d42e7dSPeter Dunlap NULL, /* it_free_conn_rsrc */ 137a6d42e7dSPeter Dunlap NULL, /* it_tgt_enable_datamover */ 138a6d42e7dSPeter Dunlap NULL, /* it_ini_enable_datamover */ 139a6d42e7dSPeter Dunlap NULL, /* it_conn_terminate */ 140a6d42e7dSPeter Dunlap idm_so_free_task_rsrc, /* it_free_task_rsrc */ 141a6d42e7dSPeter Dunlap idm_so_negotiate_key_values, /* it_negotiate_key_values */ 142a6d42e7dSPeter Dunlap idm_so_notice_key_values, /* it_notice_key_values */ 143a6d42e7dSPeter Dunlap idm_so_conn_is_capable, /* it_conn_is_capable */ 144a6d42e7dSPeter Dunlap idm_so_buf_alloc, /* it_buf_alloc */ 145a6d42e7dSPeter Dunlap idm_so_buf_free, /* it_buf_free */ 146a6d42e7dSPeter Dunlap idm_so_buf_setup, /* it_buf_setup */ 147a6d42e7dSPeter Dunlap idm_so_buf_teardown, /* it_buf_teardown */ 148a6d42e7dSPeter Dunlap idm_so_tgt_svc_create, /* it_tgt_svc_create */ 149a6d42e7dSPeter Dunlap idm_so_tgt_svc_destroy, /* it_tgt_svc_destroy */ 150a6d42e7dSPeter Dunlap idm_so_tgt_svc_online, /* it_tgt_svc_online */ 151a6d42e7dSPeter Dunlap idm_so_tgt_svc_offline, /* it_tgt_svc_offline */ 152a6d42e7dSPeter Dunlap idm_so_tgt_conn_destroy, /* it_tgt_conn_destroy */ 153a6d42e7dSPeter Dunlap idm_so_tgt_conn_connect, /* it_tgt_conn_connect */ 154a6d42e7dSPeter Dunlap idm_so_conn_disconnect, /* it_tgt_conn_disconnect */ 155a6d42e7dSPeter Dunlap idm_so_ini_conn_create, /* it_ini_conn_create */ 156a6d42e7dSPeter Dunlap idm_so_ini_conn_destroy, /* it_ini_conn_destroy */ 157a6d42e7dSPeter Dunlap idm_so_ini_conn_connect, /* it_ini_conn_connect */ 158*56261083SCharles Ting idm_so_conn_disconnect, /* it_ini_conn_disconnect */ 159*56261083SCharles Ting idm_so_declare_key_values /* it_declare_key_values */ 160a6d42e7dSPeter Dunlap }; 161a6d42e7dSPeter Dunlap 162a6d42e7dSPeter Dunlap /* 163a6d42e7dSPeter Dunlap * idm_so_init() 164a6d42e7dSPeter Dunlap * Sockets transport initialization 165a6d42e7dSPeter Dunlap */ 166a6d42e7dSPeter Dunlap void 167a6d42e7dSPeter Dunlap idm_so_init(idm_transport_t *it) 168a6d42e7dSPeter Dunlap { 169a6d42e7dSPeter Dunlap /* Cache for IDM Data and R2T Transmit PDU's */ 170a6d42e7dSPeter Dunlap idm.idm_sotx_pdu_cache = kmem_cache_create("idm_tx_pdu_cache", 171a6d42e7dSPeter Dunlap sizeof (idm_pdu_t) + sizeof (iscsi_hdr_t), 8, 172a6d42e7dSPeter Dunlap &idm_sotx_pdu_constructor, NULL, NULL, NULL, NULL, KM_SLEEP); 173a6d42e7dSPeter Dunlap 174a6d42e7dSPeter Dunlap /* Cache for IDM Receive PDU's */ 175a6d42e7dSPeter Dunlap idm.idm_sorx_pdu_cache = kmem_cache_create("idm_rx_pdu_cache", 176a6d42e7dSPeter Dunlap sizeof (idm_pdu_t) + IDM_SORX_CACHE_HDRLEN, 8, 177a6d42e7dSPeter Dunlap &idm_sorx_pdu_constructor, NULL, NULL, NULL, NULL, KM_SLEEP); 178a6d42e7dSPeter Dunlap 179cf8c0ebaSPeter Dunlap /* 128k buffer cache */ 180cf8c0ebaSPeter Dunlap idm.idm_so_128k_buf_cache = kmem_cache_create("idm_128k_buf_cache", 181cf8c0ebaSPeter Dunlap IDM_SO_BUF_CACHE_UB, 8, NULL, NULL, NULL, NULL, NULL, KM_SLEEP); 182cf8c0ebaSPeter Dunlap 183a6d42e7dSPeter Dunlap /* Set the sockets transport ops */ 184a6d42e7dSPeter Dunlap it->it_ops = &idm_so_transport_ops; 185a6d42e7dSPeter Dunlap } 186a6d42e7dSPeter Dunlap 187a6d42e7dSPeter Dunlap /* 188a6d42e7dSPeter Dunlap * idm_so_fini() 189a6d42e7dSPeter Dunlap * Sockets transport teardown 190a6d42e7dSPeter Dunlap */ 191a6d42e7dSPeter Dunlap void 192a6d42e7dSPeter Dunlap idm_so_fini(void) 193a6d42e7dSPeter Dunlap { 194cf8c0ebaSPeter Dunlap kmem_cache_destroy(idm.idm_so_128k_buf_cache); 195a6d42e7dSPeter Dunlap kmem_cache_destroy(idm.idm_sotx_pdu_cache); 196a6d42e7dSPeter Dunlap kmem_cache_destroy(idm.idm_sorx_pdu_cache); 197a6d42e7dSPeter Dunlap } 198a6d42e7dSPeter Dunlap 1990f1702c5SYu Xiangning ksocket_t 200a6d42e7dSPeter Dunlap idm_socreate(int domain, int type, int protocol) 201a6d42e7dSPeter Dunlap { 2020f1702c5SYu Xiangning ksocket_t ks; 203a6d42e7dSPeter Dunlap 2040f1702c5SYu Xiangning if (!ksocket_socket(&ks, domain, type, protocol, KSOCKET_NOSLEEP, 2050f1702c5SYu Xiangning CRED())) { 2060f1702c5SYu Xiangning return (ks); 2070f1702c5SYu Xiangning } else { 2080f1702c5SYu Xiangning return (NULL); 209a6d42e7dSPeter Dunlap } 210a6d42e7dSPeter Dunlap } 211a6d42e7dSPeter Dunlap 212a6d42e7dSPeter Dunlap /* 213a6d42e7dSPeter Dunlap * idm_soshutdown will disconnect the socket and prevent subsequent PDU 214a6d42e7dSPeter Dunlap * reception and transmission. The sonode still exists but its state 215a6d42e7dSPeter Dunlap * gets modified to indicate it is no longer connected. Calls to 216a6d42e7dSPeter Dunlap * idm_sorecv/idm_iov_sorecv will return so idm_soshutdown can be used 217a6d42e7dSPeter Dunlap * regain control of a thread stuck in idm_sorecv. 218a6d42e7dSPeter Dunlap */ 219a6d42e7dSPeter Dunlap void 2200f1702c5SYu Xiangning idm_soshutdown(ksocket_t so) 221a6d42e7dSPeter Dunlap { 2220f1702c5SYu Xiangning (void) ksocket_shutdown(so, SHUT_RDWR, CRED()); 223a6d42e7dSPeter Dunlap } 224a6d42e7dSPeter Dunlap 225a6d42e7dSPeter Dunlap /* 226a6d42e7dSPeter Dunlap * idm_sodestroy releases all resources associated with a socket previously 227a6d42e7dSPeter Dunlap * created with idm_socreate. The socket must be shutdown using 228a6d42e7dSPeter Dunlap * idm_soshutdown before the socket is destroyed with idm_sodestroy, 229a6d42e7dSPeter Dunlap * otherwise undefined behavior will result. 230a6d42e7dSPeter Dunlap */ 231a6d42e7dSPeter Dunlap void 2320f1702c5SYu Xiangning idm_sodestroy(ksocket_t ks) 233a6d42e7dSPeter Dunlap { 2340f1702c5SYu Xiangning (void) ksocket_close(ks, CRED()); 235a6d42e7dSPeter Dunlap } 236a6d42e7dSPeter Dunlap 237e42a0851Speter dunlap /* 238e42a0851Speter dunlap * Function to compare two addresses in sockaddr_storage format 239e42a0851Speter dunlap */ 240e42a0851Speter dunlap 241e42a0851Speter dunlap int 242e42a0851Speter dunlap idm_ss_compare(const struct sockaddr_storage *cmp_ss1, 243e42a0851Speter dunlap const struct sockaddr_storage *cmp_ss2, 244e42a0851Speter dunlap boolean_t v4_mapped_as_v4) 245e42a0851Speter dunlap { 246e42a0851Speter dunlap struct sockaddr_storage mapped_v4_ss1, mapped_v4_ss2; 247e42a0851Speter dunlap const struct sockaddr_storage *ss1, *ss2; 248e42a0851Speter dunlap struct in_addr *in1, *in2; 249e42a0851Speter dunlap struct in6_addr *in61, *in62; 250e42a0851Speter dunlap int i; 251e42a0851Speter dunlap 252e42a0851Speter dunlap /* 253e42a0851Speter dunlap * Normalize V4-mapped IPv6 addresses into V4 format if 254e42a0851Speter dunlap * v4_mapped_as_v4 is B_TRUE. 255e42a0851Speter dunlap */ 256e42a0851Speter dunlap ss1 = cmp_ss1; 257e42a0851Speter dunlap ss2 = cmp_ss2; 258e42a0851Speter dunlap if (v4_mapped_as_v4 && (ss1->ss_family == AF_INET6)) { 259e42a0851Speter dunlap in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr; 260e42a0851Speter dunlap if (IN6_IS_ADDR_V4MAPPED(in61)) { 261e42a0851Speter dunlap bzero(&mapped_v4_ss1, sizeof (mapped_v4_ss1)); 262e42a0851Speter dunlap mapped_v4_ss1.ss_family = AF_INET; 263e42a0851Speter dunlap ((struct sockaddr_in *)&mapped_v4_ss1)->sin_port = 264e42a0851Speter dunlap ((struct sockaddr_in *)ss1)->sin_port; 265e42a0851Speter dunlap IN6_V4MAPPED_TO_INADDR(in61, 266e42a0851Speter dunlap &((struct sockaddr_in *)&mapped_v4_ss1)->sin_addr); 267e42a0851Speter dunlap ss1 = &mapped_v4_ss1; 268e42a0851Speter dunlap } 269e42a0851Speter dunlap } 270e42a0851Speter dunlap ss2 = cmp_ss2; 271e42a0851Speter dunlap if (v4_mapped_as_v4 && (ss2->ss_family == AF_INET6)) { 272e42a0851Speter dunlap in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr; 273e42a0851Speter dunlap if (IN6_IS_ADDR_V4MAPPED(in62)) { 274e42a0851Speter dunlap bzero(&mapped_v4_ss2, sizeof (mapped_v4_ss2)); 275e42a0851Speter dunlap mapped_v4_ss2.ss_family = AF_INET; 276e42a0851Speter dunlap ((struct sockaddr_in *)&mapped_v4_ss2)->sin_port = 277e42a0851Speter dunlap ((struct sockaddr_in *)ss2)->sin_port; 278e42a0851Speter dunlap IN6_V4MAPPED_TO_INADDR(in62, 279e42a0851Speter dunlap &((struct sockaddr_in *)&mapped_v4_ss2)->sin_addr); 280e42a0851Speter dunlap ss2 = &mapped_v4_ss2; 281e42a0851Speter dunlap } 282e42a0851Speter dunlap } 283e42a0851Speter dunlap 284e42a0851Speter dunlap /* 285e42a0851Speter dunlap * Compare ports, then address family, then ip address 286e42a0851Speter dunlap */ 287e42a0851Speter dunlap if (((struct sockaddr_in *)ss1)->sin_port != 288e42a0851Speter dunlap ((struct sockaddr_in *)ss2)->sin_port) { 289e42a0851Speter dunlap if (((struct sockaddr_in *)ss1)->sin_port > 290e42a0851Speter dunlap ((struct sockaddr_in *)ss2)->sin_port) 291e42a0851Speter dunlap return (1); 292e42a0851Speter dunlap else 293e42a0851Speter dunlap return (-1); 294e42a0851Speter dunlap } 295e42a0851Speter dunlap 296e42a0851Speter dunlap /* 297e42a0851Speter dunlap * ports are the same 298e42a0851Speter dunlap */ 299e42a0851Speter dunlap if (ss1->ss_family != ss2->ss_family) { 300e42a0851Speter dunlap if (ss1->ss_family == AF_INET) 301e42a0851Speter dunlap return (1); 302e42a0851Speter dunlap else 303e42a0851Speter dunlap return (-1); 304e42a0851Speter dunlap } 305e42a0851Speter dunlap 306e42a0851Speter dunlap /* 307e42a0851Speter dunlap * address families are the same 308e42a0851Speter dunlap */ 309e42a0851Speter dunlap if (ss1->ss_family == AF_INET) { 310e42a0851Speter dunlap in1 = &((struct sockaddr_in *)ss1)->sin_addr; 311e42a0851Speter dunlap in2 = &((struct sockaddr_in *)ss2)->sin_addr; 312e42a0851Speter dunlap 313e42a0851Speter dunlap if (in1->s_addr > in2->s_addr) 314e42a0851Speter dunlap return (1); 315e42a0851Speter dunlap else if (in1->s_addr < in2->s_addr) 316e42a0851Speter dunlap return (-1); 317e42a0851Speter dunlap else 318e42a0851Speter dunlap return (0); 319e42a0851Speter dunlap } else if (ss1->ss_family == AF_INET6) { 320e42a0851Speter dunlap in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr; 321e42a0851Speter dunlap in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr; 322e42a0851Speter dunlap 323e42a0851Speter dunlap for (i = 0; i < 4; i++) { 324e42a0851Speter dunlap if (in61->s6_addr32[i] > in62->s6_addr32[i]) 325e42a0851Speter dunlap return (1); 326e42a0851Speter dunlap else if (in61->s6_addr32[i] < in62->s6_addr32[i]) 327e42a0851Speter dunlap return (-1); 328e42a0851Speter dunlap } 329e42a0851Speter dunlap return (0); 330e42a0851Speter dunlap } 331e42a0851Speter dunlap 332e42a0851Speter dunlap return (1); 333e42a0851Speter dunlap } 334e42a0851Speter dunlap 335a6d42e7dSPeter Dunlap /* 336a6d42e7dSPeter Dunlap * IP address filter functions to flag addresses that should not 337a6d42e7dSPeter Dunlap * go out to initiators through discovery. 338a6d42e7dSPeter Dunlap */ 339a6d42e7dSPeter Dunlap static boolean_t 340a6d42e7dSPeter Dunlap idm_v4_addr_okay(struct in_addr *in_addr) 341a6d42e7dSPeter Dunlap { 342a6d42e7dSPeter Dunlap in_addr_t addr = ntohl(in_addr->s_addr); 343a6d42e7dSPeter Dunlap 344a6d42e7dSPeter Dunlap if ((INADDR_NONE == addr) || 345a6d42e7dSPeter Dunlap (IN_MULTICAST(addr)) || 346a6d42e7dSPeter Dunlap ((addr >> IN_CLASSA_NSHIFT) == 0) || 347a6d42e7dSPeter Dunlap ((addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)) { 348a6d42e7dSPeter Dunlap return (B_FALSE); 349a6d42e7dSPeter Dunlap } 350a6d42e7dSPeter Dunlap return (B_TRUE); 351a6d42e7dSPeter Dunlap } 352a6d42e7dSPeter Dunlap 353a6d42e7dSPeter Dunlap static boolean_t 354a6d42e7dSPeter Dunlap idm_v6_addr_okay(struct in6_addr *addr6) 355a6d42e7dSPeter Dunlap { 356a6d42e7dSPeter Dunlap 357a6d42e7dSPeter Dunlap if ((IN6_IS_ADDR_UNSPECIFIED(addr6)) || 358a6d42e7dSPeter Dunlap (IN6_IS_ADDR_LOOPBACK(addr6)) || 359a6d42e7dSPeter Dunlap (IN6_IS_ADDR_MULTICAST(addr6)) || 360a6d42e7dSPeter Dunlap (IN6_IS_ADDR_V4MAPPED(addr6)) || 361a6d42e7dSPeter Dunlap (IN6_IS_ADDR_V4COMPAT(addr6)) || 362a6d42e7dSPeter Dunlap (IN6_IS_ADDR_LINKLOCAL(addr6))) { 363a6d42e7dSPeter Dunlap return (B_FALSE); 364a6d42e7dSPeter Dunlap } 365a6d42e7dSPeter Dunlap return (B_TRUE); 366a6d42e7dSPeter Dunlap } 367a6d42e7dSPeter Dunlap 368a6d42e7dSPeter Dunlap /* 369a6d42e7dSPeter Dunlap * idm_get_ipaddr will retrieve a list of IP Addresses which the host is 370a6d42e7dSPeter Dunlap * configured with by sending down a sequence of kernel ioctl to IP STREAMS. 371a6d42e7dSPeter Dunlap */ 372a6d42e7dSPeter Dunlap int 373a6d42e7dSPeter Dunlap idm_get_ipaddr(idm_addr_list_t **ipaddr_p) 374a6d42e7dSPeter Dunlap { 3750f1702c5SYu Xiangning ksocket_t so4, so6; 376a6d42e7dSPeter Dunlap struct lifnum lifn; 377a6d42e7dSPeter Dunlap struct lifconf lifc; 378a6d42e7dSPeter Dunlap struct lifreq *lp; 379a6d42e7dSPeter Dunlap int rval; 380a6d42e7dSPeter Dunlap int numifs; 381a6d42e7dSPeter Dunlap int bufsize; 382a6d42e7dSPeter Dunlap void *buf; 383a6d42e7dSPeter Dunlap int i, j, n, rc; 384a6d42e7dSPeter Dunlap struct sockaddr_storage ss; 385a6d42e7dSPeter Dunlap struct sockaddr_in *sin; 386a6d42e7dSPeter Dunlap struct sockaddr_in6 *sin6; 387a6d42e7dSPeter Dunlap idm_addr_t *ip; 388a6d42e7dSPeter Dunlap idm_addr_list_t *ipaddr; 389a6d42e7dSPeter Dunlap int size_ipaddr; 390a6d42e7dSPeter Dunlap 391a6d42e7dSPeter Dunlap *ipaddr_p = NULL; 392a6d42e7dSPeter Dunlap size_ipaddr = 0; 393a6d42e7dSPeter Dunlap buf = NULL; 394a6d42e7dSPeter Dunlap 395a6d42e7dSPeter Dunlap /* create an ipv4 and ipv6 UDP socket */ 396a6d42e7dSPeter Dunlap if ((so6 = idm_socreate(PF_INET6, SOCK_DGRAM, 0)) == NULL) 397a6d42e7dSPeter Dunlap return (0); 398a6d42e7dSPeter Dunlap if ((so4 = idm_socreate(PF_INET, SOCK_DGRAM, 0)) == NULL) { 399a6d42e7dSPeter Dunlap idm_sodestroy(so6); 400a6d42e7dSPeter Dunlap return (0); 401a6d42e7dSPeter Dunlap } 402a6d42e7dSPeter Dunlap 403a6d42e7dSPeter Dunlap 404a6d42e7dSPeter Dunlap retry_count: 405a6d42e7dSPeter Dunlap /* snapshot the current number of interfaces */ 406a6d42e7dSPeter Dunlap lifn.lifn_family = PF_UNSPEC; 407a6d42e7dSPeter Dunlap lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES; 408a6d42e7dSPeter Dunlap lifn.lifn_count = 0; 4090f1702c5SYu Xiangning /* use vp6 for ioctls with unspecified families by default */ 4100f1702c5SYu Xiangning if (ksocket_ioctl(so6, SIOCGLIFNUM, (intptr_t)&lifn, &rval, CRED()) 4110f1702c5SYu Xiangning != 0) { 412a6d42e7dSPeter Dunlap goto cleanup; 413a6d42e7dSPeter Dunlap } 414a6d42e7dSPeter Dunlap 415a6d42e7dSPeter Dunlap numifs = lifn.lifn_count; 416a6d42e7dSPeter Dunlap if (numifs <= 0) { 417a6d42e7dSPeter Dunlap goto cleanup; 418a6d42e7dSPeter Dunlap } 419a6d42e7dSPeter Dunlap 420a6d42e7dSPeter Dunlap /* allocate extra room in case more interfaces appear */ 421a6d42e7dSPeter Dunlap numifs += 10; 422a6d42e7dSPeter Dunlap 423a6d42e7dSPeter Dunlap /* get the interface names and ip addresses */ 424a6d42e7dSPeter Dunlap bufsize = numifs * sizeof (struct lifreq); 425a6d42e7dSPeter Dunlap buf = kmem_alloc(bufsize, KM_SLEEP); 426a6d42e7dSPeter Dunlap 427a6d42e7dSPeter Dunlap lifc.lifc_family = AF_UNSPEC; 428a6d42e7dSPeter Dunlap lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES; 429a6d42e7dSPeter Dunlap lifc.lifc_len = bufsize; 430a6d42e7dSPeter Dunlap lifc.lifc_buf = buf; 4310f1702c5SYu Xiangning rc = ksocket_ioctl(so6, SIOCGLIFCONF, (intptr_t)&lifc, &rval, CRED()); 432a6d42e7dSPeter Dunlap if (rc != 0) { 433a6d42e7dSPeter Dunlap goto cleanup; 434a6d42e7dSPeter Dunlap } 435a6d42e7dSPeter Dunlap /* if our extra room is used up, try again */ 436a6d42e7dSPeter Dunlap if (bufsize <= lifc.lifc_len) { 437a6d42e7dSPeter Dunlap kmem_free(buf, bufsize); 438a6d42e7dSPeter Dunlap buf = NULL; 439a6d42e7dSPeter Dunlap goto retry_count; 440a6d42e7dSPeter Dunlap } 441a6d42e7dSPeter Dunlap /* calc actual number of ifconfs */ 442a6d42e7dSPeter Dunlap n = lifc.lifc_len / sizeof (struct lifreq); 443a6d42e7dSPeter Dunlap 444a6d42e7dSPeter Dunlap /* get ip address */ 445a6d42e7dSPeter Dunlap if (n > 0) { 446a6d42e7dSPeter Dunlap size_ipaddr = sizeof (idm_addr_list_t) + 447a6d42e7dSPeter Dunlap (n - 1) * sizeof (idm_addr_t); 448a6d42e7dSPeter Dunlap ipaddr = kmem_zalloc(size_ipaddr, KM_SLEEP); 449a6d42e7dSPeter Dunlap } else { 450a6d42e7dSPeter Dunlap goto cleanup; 451a6d42e7dSPeter Dunlap } 452a6d42e7dSPeter Dunlap 453a6d42e7dSPeter Dunlap /* 454a6d42e7dSPeter Dunlap * Examine the array of interfaces and filter uninteresting ones 455a6d42e7dSPeter Dunlap */ 456a6d42e7dSPeter Dunlap for (i = 0, j = 0, lp = lifc.lifc_req; i < n; i++, lp++) { 457a6d42e7dSPeter Dunlap 458a6d42e7dSPeter Dunlap /* 459a6d42e7dSPeter Dunlap * Copy the address as the SIOCGLIFFLAGS ioctl is destructive 460a6d42e7dSPeter Dunlap */ 461a6d42e7dSPeter Dunlap ss = lp->lifr_addr; 462a6d42e7dSPeter Dunlap /* 463a6d42e7dSPeter Dunlap * fetch the flags using the socket of the correct family 464a6d42e7dSPeter Dunlap */ 465a6d42e7dSPeter Dunlap switch (ss.ss_family) { 466a6d42e7dSPeter Dunlap case AF_INET: 4670f1702c5SYu Xiangning rc = ksocket_ioctl(so4, SIOCGLIFFLAGS, (intptr_t)lp, 4680f1702c5SYu Xiangning &rval, CRED()); 469a6d42e7dSPeter Dunlap break; 470a6d42e7dSPeter Dunlap case AF_INET6: 4710f1702c5SYu Xiangning rc = ksocket_ioctl(so6, SIOCGLIFFLAGS, (intptr_t)lp, 4720f1702c5SYu Xiangning &rval, CRED()); 473a6d42e7dSPeter Dunlap break; 474a6d42e7dSPeter Dunlap default: 475a6d42e7dSPeter Dunlap continue; 476a6d42e7dSPeter Dunlap } 477a6d42e7dSPeter Dunlap if (rc == 0) { 478a6d42e7dSPeter Dunlap /* 479a6d42e7dSPeter Dunlap * If we got the flags, skip uninteresting 480a6d42e7dSPeter Dunlap * interfaces based on flags 481a6d42e7dSPeter Dunlap */ 482a6d42e7dSPeter Dunlap if ((lp->lifr_flags & IFF_UP) != IFF_UP) 483a6d42e7dSPeter Dunlap continue; 484a6d42e7dSPeter Dunlap if (lp->lifr_flags & 485a6d42e7dSPeter Dunlap (IFF_ANYCAST|IFF_NOLOCAL|IFF_DEPRECATED)) 486a6d42e7dSPeter Dunlap continue; 487a6d42e7dSPeter Dunlap } 488a6d42e7dSPeter Dunlap 489a6d42e7dSPeter Dunlap /* save ip address */ 490a6d42e7dSPeter Dunlap ip = &ipaddr->al_addrs[j]; 491a6d42e7dSPeter Dunlap switch (ss.ss_family) { 492a6d42e7dSPeter Dunlap case AF_INET: 493a6d42e7dSPeter Dunlap sin = (struct sockaddr_in *)&ss; 494a6d42e7dSPeter Dunlap if (!idm_v4_addr_okay(&sin->sin_addr)) 495a6d42e7dSPeter Dunlap continue; 496a6d42e7dSPeter Dunlap ip->a_addr.i_addr.in4 = sin->sin_addr; 497a6d42e7dSPeter Dunlap ip->a_addr.i_insize = sizeof (struct in_addr); 498a6d42e7dSPeter Dunlap break; 499a6d42e7dSPeter Dunlap case AF_INET6: 500a6d42e7dSPeter Dunlap sin6 = (struct sockaddr_in6 *)&ss; 501a6d42e7dSPeter Dunlap if (!idm_v6_addr_okay(&sin6->sin6_addr)) 502a6d42e7dSPeter Dunlap continue; 503a6d42e7dSPeter Dunlap ip->a_addr.i_addr.in6 = sin6->sin6_addr; 504a6d42e7dSPeter Dunlap ip->a_addr.i_insize = sizeof (struct in6_addr); 505a6d42e7dSPeter Dunlap break; 506a6d42e7dSPeter Dunlap default: 507a6d42e7dSPeter Dunlap continue; 508a6d42e7dSPeter Dunlap } 509a6d42e7dSPeter Dunlap j++; 510a6d42e7dSPeter Dunlap } 511a6d42e7dSPeter Dunlap 512a6d42e7dSPeter Dunlap if (j == 0) { 513a6d42e7dSPeter Dunlap /* no valid ifaddr */ 514a6d42e7dSPeter Dunlap kmem_free(ipaddr, size_ipaddr); 515a6d42e7dSPeter Dunlap size_ipaddr = 0; 516a6d42e7dSPeter Dunlap ipaddr = NULL; 517a6d42e7dSPeter Dunlap } else { 518a6d42e7dSPeter Dunlap ipaddr->al_out_cnt = j; 519a6d42e7dSPeter Dunlap } 520a6d42e7dSPeter Dunlap 521a6d42e7dSPeter Dunlap 522a6d42e7dSPeter Dunlap cleanup: 523a6d42e7dSPeter Dunlap idm_sodestroy(so6); 524a6d42e7dSPeter Dunlap idm_sodestroy(so4); 525a6d42e7dSPeter Dunlap 526a6d42e7dSPeter Dunlap if (buf != NULL) 527a6d42e7dSPeter Dunlap kmem_free(buf, bufsize); 528a6d42e7dSPeter Dunlap 529a6d42e7dSPeter Dunlap *ipaddr_p = ipaddr; 530a6d42e7dSPeter Dunlap return (size_ipaddr); 531a6d42e7dSPeter Dunlap } 532a6d42e7dSPeter Dunlap 533a6d42e7dSPeter Dunlap int 5340f1702c5SYu Xiangning idm_sorecv(ksocket_t so, void *msg, size_t len) 535a6d42e7dSPeter Dunlap { 536a6d42e7dSPeter Dunlap iovec_t iov; 537a6d42e7dSPeter Dunlap 538a6d42e7dSPeter Dunlap ASSERT(so != NULL); 539a6d42e7dSPeter Dunlap ASSERT(len != 0); 540a6d42e7dSPeter Dunlap 541a6d42e7dSPeter Dunlap /* 542a6d42e7dSPeter Dunlap * Fill in iovec and receive data 543a6d42e7dSPeter Dunlap */ 544a6d42e7dSPeter Dunlap iov.iov_base = msg; 545a6d42e7dSPeter Dunlap iov.iov_len = len; 546a6d42e7dSPeter Dunlap 547a6d42e7dSPeter Dunlap return (idm_iov_sorecv(so, &iov, 1, len)); 548a6d42e7dSPeter Dunlap } 549a6d42e7dSPeter Dunlap 550a6d42e7dSPeter Dunlap /* 551a6d42e7dSPeter Dunlap * idm_sosendto - Sends a buffered data on a non-connected socket. 552a6d42e7dSPeter Dunlap * 553a6d42e7dSPeter Dunlap * This function puts the data provided on the wire by calling sosendmsg. 554a6d42e7dSPeter Dunlap * It will return only when all the data has been sent or if an error 555a6d42e7dSPeter Dunlap * occurs. 556a6d42e7dSPeter Dunlap * 557a6d42e7dSPeter Dunlap * Returns 0 for success, the socket errno value if sosendmsg fails, and 558a6d42e7dSPeter Dunlap * -1 if sosendmsg returns success but uio_resid != 0 559a6d42e7dSPeter Dunlap */ 560a6d42e7dSPeter Dunlap int 5610f1702c5SYu Xiangning idm_sosendto(ksocket_t so, void *buff, size_t len, 562a6d42e7dSPeter Dunlap struct sockaddr *name, socklen_t namelen) 563a6d42e7dSPeter Dunlap { 564a6d42e7dSPeter Dunlap struct msghdr msg; 565a6d42e7dSPeter Dunlap struct iovec iov[1]; 566a6d42e7dSPeter Dunlap int error; 5670f1702c5SYu Xiangning size_t sent = 0; 568a6d42e7dSPeter Dunlap 569a6d42e7dSPeter Dunlap iov[0].iov_base = buff; 570a6d42e7dSPeter Dunlap iov[0].iov_len = len; 571a6d42e7dSPeter Dunlap 572a6d42e7dSPeter Dunlap /* Initialization of the message header. */ 573a6d42e7dSPeter Dunlap bzero(&msg, sizeof (msg)); 574a6d42e7dSPeter Dunlap msg.msg_iov = iov; 575a6d42e7dSPeter Dunlap msg.msg_iovlen = 1; 576a6d42e7dSPeter Dunlap msg.msg_name = name; 577a6d42e7dSPeter Dunlap msg.msg_namelen = namelen; 578a6d42e7dSPeter Dunlap 5790f1702c5SYu Xiangning if ((error = ksocket_sendmsg(so, &msg, 0, &sent, CRED())) == 0) { 580a6d42e7dSPeter Dunlap /* Data sent */ 5810f1702c5SYu Xiangning if (sent == len) { 582a6d42e7dSPeter Dunlap /* All data sent. Success. */ 583a6d42e7dSPeter Dunlap return (0); 584a6d42e7dSPeter Dunlap } else { 585a6d42e7dSPeter Dunlap /* Not all data was sent. Failure */ 586a6d42e7dSPeter Dunlap return (-1); 587a6d42e7dSPeter Dunlap } 588a6d42e7dSPeter Dunlap } 589a6d42e7dSPeter Dunlap 590a6d42e7dSPeter Dunlap /* Send failed */ 591a6d42e7dSPeter Dunlap return (error); 592a6d42e7dSPeter Dunlap } 593a6d42e7dSPeter Dunlap 594a6d42e7dSPeter Dunlap /* 595a6d42e7dSPeter Dunlap * idm_iov_sosend - Sends an iovec on a connection. 596a6d42e7dSPeter Dunlap * 597a6d42e7dSPeter Dunlap * This function puts the data provided on the wire by calling sosendmsg. 598a6d42e7dSPeter Dunlap * It will return only when all the data has been sent or if an error 599a6d42e7dSPeter Dunlap * occurs. 600a6d42e7dSPeter Dunlap * 601a6d42e7dSPeter Dunlap * Returns 0 for success, the socket errno value if sosendmsg fails, and 602a6d42e7dSPeter Dunlap * -1 if sosendmsg returns success but uio_resid != 0 603a6d42e7dSPeter Dunlap */ 604a6d42e7dSPeter Dunlap int 6050f1702c5SYu Xiangning idm_iov_sosend(ksocket_t so, iovec_t *iop, int iovlen, size_t total_len) 606a6d42e7dSPeter Dunlap { 607a6d42e7dSPeter Dunlap struct msghdr msg; 608a6d42e7dSPeter Dunlap int error; 6090f1702c5SYu Xiangning size_t sent = 0; 610a6d42e7dSPeter Dunlap 611a6d42e7dSPeter Dunlap ASSERT(iop != NULL); 612a6d42e7dSPeter Dunlap 613a6d42e7dSPeter Dunlap /* Initialization of the message header. */ 614a6d42e7dSPeter Dunlap bzero(&msg, sizeof (msg)); 615a6d42e7dSPeter Dunlap msg.msg_iov = iop; 616a6d42e7dSPeter Dunlap msg.msg_iovlen = iovlen; 617a6d42e7dSPeter Dunlap 6180f1702c5SYu Xiangning if ((error = ksocket_sendmsg(so, &msg, 0, &sent, CRED())) 6190f1702c5SYu Xiangning == 0) { 620a6d42e7dSPeter Dunlap /* Data sent */ 6210f1702c5SYu Xiangning if (sent == total_len) { 622a6d42e7dSPeter Dunlap /* All data sent. Success. */ 623a6d42e7dSPeter Dunlap return (0); 624a6d42e7dSPeter Dunlap } else { 625a6d42e7dSPeter Dunlap /* Not all data was sent. Failure */ 626a6d42e7dSPeter Dunlap return (-1); 627a6d42e7dSPeter Dunlap } 628a6d42e7dSPeter Dunlap } 629a6d42e7dSPeter Dunlap 630a6d42e7dSPeter Dunlap /* Send failed */ 631a6d42e7dSPeter Dunlap return (error); 632a6d42e7dSPeter Dunlap } 633a6d42e7dSPeter Dunlap 634a6d42e7dSPeter Dunlap /* 635a6d42e7dSPeter Dunlap * idm_iov_sorecv - Receives an iovec from a connection 636a6d42e7dSPeter Dunlap * 637a6d42e7dSPeter Dunlap * This function gets the data asked for from the socket. It will return 638a6d42e7dSPeter Dunlap * only when all the requested data has been retrieved or if an error 639a6d42e7dSPeter Dunlap * occurs. 640a6d42e7dSPeter Dunlap * 641a6d42e7dSPeter Dunlap * Returns 0 for success, the socket errno value if sorecvmsg fails, and 642a6d42e7dSPeter Dunlap * -1 if sorecvmsg returns success but uio_resid != 0 643a6d42e7dSPeter Dunlap */ 644a6d42e7dSPeter Dunlap int 6450f1702c5SYu Xiangning idm_iov_sorecv(ksocket_t so, iovec_t *iop, int iovlen, size_t total_len) 646a6d42e7dSPeter Dunlap { 647a6d42e7dSPeter Dunlap struct msghdr msg; 648a6d42e7dSPeter Dunlap int error; 6490f1702c5SYu Xiangning size_t recv; 6500f1702c5SYu Xiangning int flags; 651a6d42e7dSPeter Dunlap 652a6d42e7dSPeter Dunlap ASSERT(iop != NULL); 653a6d42e7dSPeter Dunlap 654a6d42e7dSPeter Dunlap /* Initialization of the message header. */ 655a6d42e7dSPeter Dunlap bzero(&msg, sizeof (msg)); 656a6d42e7dSPeter Dunlap msg.msg_iov = iop; 657a6d42e7dSPeter Dunlap msg.msg_iovlen = iovlen; 6580f1702c5SYu Xiangning flags = MSG_WAITALL; 659a6d42e7dSPeter Dunlap 6600f1702c5SYu Xiangning if ((error = ksocket_recvmsg(so, &msg, flags, &recv, CRED())) 6610f1702c5SYu Xiangning == 0) { 662a6d42e7dSPeter Dunlap /* Received data */ 6630f1702c5SYu Xiangning if (recv == total_len) { 664a6d42e7dSPeter Dunlap /* All requested data received. Success */ 665a6d42e7dSPeter Dunlap return (0); 666a6d42e7dSPeter Dunlap } else { 667a6d42e7dSPeter Dunlap /* 668a6d42e7dSPeter Dunlap * Not all data was received. The connection has 669a6d42e7dSPeter Dunlap * probably failed. 670a6d42e7dSPeter Dunlap */ 671a6d42e7dSPeter Dunlap return (-1); 672a6d42e7dSPeter Dunlap } 673a6d42e7dSPeter Dunlap } 674a6d42e7dSPeter Dunlap 675a6d42e7dSPeter Dunlap /* Receive failed */ 676a6d42e7dSPeter Dunlap return (error); 677a6d42e7dSPeter Dunlap } 678a6d42e7dSPeter Dunlap 679a6d42e7dSPeter Dunlap static void 680a6d42e7dSPeter Dunlap idm_set_ini_preconnect_options(idm_so_conn_t *sc) 681a6d42e7dSPeter Dunlap { 682a6d42e7dSPeter Dunlap int conn_abort = 10000; 683a6d42e7dSPeter Dunlap int conn_notify = 2000; 684a6d42e7dSPeter Dunlap int abort = 30000; 685a6d42e7dSPeter Dunlap 686a6d42e7dSPeter Dunlap /* Pre-connect socket options */ 6870f1702c5SYu Xiangning (void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP, 6880f1702c5SYu Xiangning TCP_CONN_NOTIFY_THRESHOLD, (char *)&conn_notify, sizeof (int), 6890f1702c5SYu Xiangning CRED()); 6900f1702c5SYu Xiangning (void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP, 6910f1702c5SYu Xiangning TCP_CONN_ABORT_THRESHOLD, (char *)&conn_abort, sizeof (int), 6920f1702c5SYu Xiangning CRED()); 6930f1702c5SYu Xiangning (void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP, TCP_ABORT_THRESHOLD, 6940f1702c5SYu Xiangning (char *)&abort, sizeof (int), CRED()); 695a6d42e7dSPeter Dunlap } 696a6d42e7dSPeter Dunlap 697a6d42e7dSPeter Dunlap static void 698a6d42e7dSPeter Dunlap idm_set_ini_postconnect_options(idm_so_conn_t *sc) 699a6d42e7dSPeter Dunlap { 700a6d42e7dSPeter Dunlap int32_t rcvbuf = IDM_RCVBUF_SIZE; 701a6d42e7dSPeter Dunlap int32_t sndbuf = IDM_SNDBUF_SIZE; 702a6d42e7dSPeter Dunlap const int on = 1; 703a6d42e7dSPeter Dunlap 704a6d42e7dSPeter Dunlap /* Set postconnect options */ 7050f1702c5SYu Xiangning (void) ksocket_setsockopt(sc->ic_so, IPPROTO_TCP, TCP_NODELAY, 7060f1702c5SYu Xiangning (char *)&on, sizeof (int), CRED()); 7070f1702c5SYu Xiangning (void) ksocket_setsockopt(sc->ic_so, SOL_SOCKET, SO_RCVBUF, 7080f1702c5SYu Xiangning (char *)&rcvbuf, sizeof (int), CRED()); 7090f1702c5SYu Xiangning (void) ksocket_setsockopt(sc->ic_so, SOL_SOCKET, SO_SNDBUF, 7100f1702c5SYu Xiangning (char *)&sndbuf, sizeof (int), CRED()); 711a6d42e7dSPeter Dunlap } 712a6d42e7dSPeter Dunlap 713a6d42e7dSPeter Dunlap static void 7140f1702c5SYu Xiangning idm_set_tgt_connect_options(ksocket_t ks) 715a6d42e7dSPeter Dunlap { 716a6d42e7dSPeter Dunlap int32_t rcvbuf = IDM_RCVBUF_SIZE; 717a6d42e7dSPeter Dunlap int32_t sndbuf = IDM_SNDBUF_SIZE; 718a6d42e7dSPeter Dunlap const int on = 1; 719a6d42e7dSPeter Dunlap 720a6d42e7dSPeter Dunlap /* Set connect options */ 7210f1702c5SYu Xiangning (void) ksocket_setsockopt(ks, SOL_SOCKET, SO_RCVBUF, 7220f1702c5SYu Xiangning (char *)&rcvbuf, sizeof (int), CRED()); 7230f1702c5SYu Xiangning (void) ksocket_setsockopt(ks, SOL_SOCKET, SO_SNDBUF, 7240f1702c5SYu Xiangning (char *)&sndbuf, sizeof (int), 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); 767*56261083SCharles Ting if (ic->ic_conn_type == CONN_TYPE_TGT && 768*56261083SCharles Ting pdu->isp_datalen > ic->ic_conn_params.max_recv_dataseglen) { 769*56261083SCharles Ting IDM_CONN_LOG(CE_WARN, 770*56261083SCharles Ting "idm_sorecvhdr: exceeded the max data segment length"); 771*56261083SCharles Ting return (IDM_STATUS_FAIL); 772*56261083SCharles 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 */ 861a6d42e7dSPeter Dunlap idm_set_ini_preconnect_options(so_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); 895aff4bce5Syi zhang - Sun Microsystems - Beijing China 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 } 943a6d42e7dSPeter Dunlap 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 951a6d42e7dSPeter Dunlap idm_set_ini_postconnect_options(so_conn); 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 961a6d42e7dSPeter Dunlap idmrc = idm_so_conn_create_common(ic, new_so); 962a6d42e7dSPeter Dunlap 963a6d42e7dSPeter Dunlap return (idmrc); 964a6d42e7dSPeter Dunlap } 965a6d42e7dSPeter Dunlap 966a6d42e7dSPeter Dunlap static void 967a6d42e7dSPeter Dunlap idm_so_tgt_conn_destroy(idm_conn_t *ic) 968a6d42e7dSPeter Dunlap { 969a6d42e7dSPeter Dunlap idm_so_conn_destroy_common(ic); 970a6d42e7dSPeter Dunlap } 971a6d42e7dSPeter Dunlap 972a6d42e7dSPeter Dunlap /* 973a6d42e7dSPeter Dunlap * idm_so_tgt_conn_connect() 974a6d42e7dSPeter Dunlap * Establish the connection in ic, passed from idm_tgt_conn_finish(), which 975a6d42e7dSPeter Dunlap * is invoked from the SM as a result of an inbound connection request. 976a6d42e7dSPeter Dunlap */ 977a6d42e7dSPeter Dunlap static idm_status_t 978a6d42e7dSPeter Dunlap idm_so_tgt_conn_connect(idm_conn_t *ic) 979a6d42e7dSPeter Dunlap { 980a6d42e7dSPeter Dunlap idm_so_conn_connect_common(ic); 981a6d42e7dSPeter Dunlap 982a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 983a6d42e7dSPeter Dunlap } 984a6d42e7dSPeter Dunlap 985a6d42e7dSPeter Dunlap static idm_status_t 9860f1702c5SYu Xiangning idm_so_conn_create_common(idm_conn_t *ic, ksocket_t new_so) 987a6d42e7dSPeter Dunlap { 988a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 989a6d42e7dSPeter Dunlap 990a6d42e7dSPeter Dunlap so_conn = kmem_zalloc(sizeof (idm_so_conn_t), KM_SLEEP); 991a6d42e7dSPeter Dunlap so_conn->ic_so = new_so; 992a6d42e7dSPeter Dunlap 993a6d42e7dSPeter Dunlap ic->ic_transport_private = so_conn; 994a6d42e7dSPeter Dunlap ic->ic_transport_hdrlen = 0; 995a6d42e7dSPeter Dunlap 996a6d42e7dSPeter Dunlap /* Set the scoreboarding flag on this connection */ 997a6d42e7dSPeter Dunlap ic->ic_conn_flags |= IDM_CONN_USE_SCOREBOARD; 998*56261083SCharles Ting ic->ic_conn_params.max_recv_dataseglen = 999*56261083SCharles Ting ISCSI_DEFAULT_MAX_RECV_SEG_LEN; 1000*56261083SCharles Ting ic->ic_conn_params.max_xmit_dataseglen = 1001*56261083SCharles Ting ISCSI_DEFAULT_MAX_XMIT_SEG_LEN; 1002a6d42e7dSPeter Dunlap 1003a6d42e7dSPeter Dunlap /* 1004a6d42e7dSPeter Dunlap * Initialize tx thread mutex and list 1005a6d42e7dSPeter Dunlap */ 1006a6d42e7dSPeter Dunlap mutex_init(&so_conn->ic_tx_mutex, NULL, MUTEX_DEFAULT, NULL); 1007a6d42e7dSPeter Dunlap cv_init(&so_conn->ic_tx_cv, NULL, CV_DEFAULT, NULL); 1008a6d42e7dSPeter Dunlap list_create(&so_conn->ic_tx_list, sizeof (idm_pdu_t), 1009a6d42e7dSPeter Dunlap offsetof(idm_pdu_t, idm_tx_link)); 1010a6d42e7dSPeter Dunlap 1011a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1012a6d42e7dSPeter Dunlap } 1013a6d42e7dSPeter Dunlap 1014a6d42e7dSPeter Dunlap static void 1015a6d42e7dSPeter Dunlap idm_so_conn_destroy_common(idm_conn_t *ic) 1016a6d42e7dSPeter Dunlap { 1017a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn = ic->ic_transport_private; 1018a6d42e7dSPeter Dunlap 1019a6d42e7dSPeter Dunlap ic->ic_transport_private = NULL; 1020a6d42e7dSPeter Dunlap idm_sodestroy(so_conn->ic_so); 1021a6d42e7dSPeter Dunlap list_destroy(&so_conn->ic_tx_list); 1022a6d42e7dSPeter Dunlap mutex_destroy(&so_conn->ic_tx_mutex); 1023a6d42e7dSPeter Dunlap cv_destroy(&so_conn->ic_tx_cv); 1024a6d42e7dSPeter Dunlap 1025a6d42e7dSPeter Dunlap kmem_free(so_conn, sizeof (idm_so_conn_t)); 1026a6d42e7dSPeter Dunlap } 1027a6d42e7dSPeter Dunlap 1028a6d42e7dSPeter Dunlap static void 1029a6d42e7dSPeter Dunlap idm_so_conn_connect_common(idm_conn_t *ic) 1030a6d42e7dSPeter Dunlap { 1031a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 10320f1702c5SYu Xiangning struct sockaddr_in6 t_addr; 10330f1702c5SYu Xiangning socklen_t t_addrlen = 0; 1034a6d42e7dSPeter Dunlap 1035a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 10360f1702c5SYu Xiangning bzero(&t_addr, sizeof (struct sockaddr_in6)); 10370f1702c5SYu Xiangning t_addrlen = sizeof (struct sockaddr_in6); 1038a6d42e7dSPeter Dunlap 1039a6d42e7dSPeter Dunlap /* Set the local and remote addresses in the idm conn handle */ 10400f1702c5SYu Xiangning ksocket_getsockname(so_conn->ic_so, (struct sockaddr *)&t_addr, 10410f1702c5SYu Xiangning &t_addrlen, CRED()); 10420f1702c5SYu Xiangning bcopy(&t_addr, &ic->ic_laddr, t_addrlen); 10430f1702c5SYu Xiangning ksocket_getpeername(so_conn->ic_so, (struct sockaddr *)&t_addr, 10440f1702c5SYu Xiangning &t_addrlen, CRED()); 10450f1702c5SYu Xiangning bcopy(&t_addr, &ic->ic_raddr, t_addrlen); 1046a6d42e7dSPeter Dunlap 1047a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 1048a6d42e7dSPeter Dunlap so_conn->ic_tx_thread = thread_create(NULL, 0, idm_sotx_thread, ic, 0, 1049a6d42e7dSPeter Dunlap &p0, TS_RUN, minclsyspri); 1050a6d42e7dSPeter Dunlap so_conn->ic_rx_thread = thread_create(NULL, 0, idm_sorx_thread, ic, 0, 1051a6d42e7dSPeter Dunlap &p0, TS_RUN, minclsyspri); 1052a6d42e7dSPeter Dunlap 1053a6d42e7dSPeter Dunlap while (!so_conn->ic_rx_thread_running || !so_conn->ic_tx_thread_running) 1054a6d42e7dSPeter Dunlap cv_wait(&ic->ic_cv, &ic->ic_mutex); 1055a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_mutex); 1056a6d42e7dSPeter Dunlap } 1057a6d42e7dSPeter Dunlap 1058a6d42e7dSPeter Dunlap /* 1059a6d42e7dSPeter Dunlap * idm_so_conn_disconnect() 1060a6d42e7dSPeter Dunlap * Shutdown the socket connection and stop the thread 1061a6d42e7dSPeter Dunlap */ 1062a6d42e7dSPeter Dunlap static void 1063a6d42e7dSPeter Dunlap idm_so_conn_disconnect(idm_conn_t *ic) 1064a6d42e7dSPeter Dunlap { 1065a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 1066a6d42e7dSPeter Dunlap 1067a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 1068a6d42e7dSPeter Dunlap 1069a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 1070a6d42e7dSPeter Dunlap so_conn->ic_rx_thread_running = B_FALSE; 1071a6d42e7dSPeter Dunlap so_conn->ic_tx_thread_running = B_FALSE; 1072a6d42e7dSPeter Dunlap /* We need to wakeup the TX thread */ 1073a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 1074a6d42e7dSPeter Dunlap cv_signal(&so_conn->ic_tx_cv); 1075a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 1076a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_mutex); 1077a6d42e7dSPeter Dunlap 1078a6d42e7dSPeter Dunlap /* This should wakeup the RX thread if it is sleeping */ 1079a6d42e7dSPeter Dunlap idm_soshutdown(so_conn->ic_so); 1080a6d42e7dSPeter Dunlap 1081a6d42e7dSPeter Dunlap thread_join(so_conn->ic_tx_thread_did); 1082a6d42e7dSPeter Dunlap thread_join(so_conn->ic_rx_thread_did); 1083a6d42e7dSPeter Dunlap } 1084a6d42e7dSPeter Dunlap 1085a6d42e7dSPeter Dunlap /* 1086a6d42e7dSPeter Dunlap * idm_so_tgt_svc_create() 1087a6d42e7dSPeter Dunlap * Establish a service on an IP address and port. idm_svc_req_t contains 1088a6d42e7dSPeter Dunlap * the service parameters. 1089a6d42e7dSPeter Dunlap */ 1090a6d42e7dSPeter Dunlap /*ARGSUSED*/ 1091a6d42e7dSPeter Dunlap static idm_status_t 1092a6d42e7dSPeter Dunlap idm_so_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t *is) 1093a6d42e7dSPeter Dunlap { 1094a6d42e7dSPeter Dunlap idm_so_svc_t *so_svc; 1095a6d42e7dSPeter Dunlap 1096a6d42e7dSPeter Dunlap so_svc = kmem_zalloc(sizeof (idm_so_svc_t), KM_SLEEP); 1097a6d42e7dSPeter Dunlap 1098a6d42e7dSPeter Dunlap /* Set the new sockets service in svc handle */ 1099a6d42e7dSPeter Dunlap is->is_so_svc = (void *)so_svc; 1100a6d42e7dSPeter Dunlap 1101a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1102a6d42e7dSPeter Dunlap } 1103a6d42e7dSPeter Dunlap 1104a6d42e7dSPeter Dunlap /* 1105a6d42e7dSPeter Dunlap * idm_so_tgt_svc_destroy() 1106a6d42e7dSPeter Dunlap * Teardown sockets resources allocated in idm_so_tgt_svc_create() 1107a6d42e7dSPeter Dunlap */ 1108a6d42e7dSPeter Dunlap static void 1109a6d42e7dSPeter Dunlap idm_so_tgt_svc_destroy(idm_svc_t *is) 1110a6d42e7dSPeter Dunlap { 1111a6d42e7dSPeter Dunlap /* the socket will have been torn down; free the service */ 1112a6d42e7dSPeter Dunlap kmem_free(is->is_so_svc, sizeof (idm_so_svc_t)); 1113a6d42e7dSPeter Dunlap } 1114a6d42e7dSPeter Dunlap 1115a6d42e7dSPeter Dunlap /* 1116a6d42e7dSPeter Dunlap * idm_so_tgt_svc_online() 1117a6d42e7dSPeter Dunlap * Launch a watch thread on the svc allocated in idm_so_tgt_svc_create() 1118a6d42e7dSPeter Dunlap */ 1119a6d42e7dSPeter Dunlap 1120a6d42e7dSPeter Dunlap static idm_status_t 1121a6d42e7dSPeter Dunlap idm_so_tgt_svc_online(idm_svc_t *is) 1122a6d42e7dSPeter Dunlap { 1123a6d42e7dSPeter Dunlap idm_so_svc_t *so_svc; 1124a6d42e7dSPeter Dunlap idm_svc_req_t *sr = &is->is_svc_req; 1125a6d42e7dSPeter Dunlap struct sockaddr_in6 sin6_ip; 1126a6d42e7dSPeter Dunlap const uint32_t on = 1; 1127a6d42e7dSPeter Dunlap const uint32_t off = 0; 1128a6d42e7dSPeter Dunlap 1129a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex); 1130a6d42e7dSPeter Dunlap so_svc = (idm_so_svc_t *)is->is_so_svc; 1131a6d42e7dSPeter Dunlap 1132a6d42e7dSPeter Dunlap /* 1133a6d42e7dSPeter Dunlap * Try creating an IPv6 socket first 1134a6d42e7dSPeter Dunlap */ 1135a6d42e7dSPeter Dunlap if ((so_svc->is_so = idm_socreate(PF_INET6, SOCK_STREAM, 0)) == NULL) { 1136a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1137a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1138a6d42e7dSPeter Dunlap } else { 1139a6d42e7dSPeter Dunlap bzero(&sin6_ip, sizeof (sin6_ip)); 1140a6d42e7dSPeter Dunlap sin6_ip.sin6_family = AF_INET6; 1141a6d42e7dSPeter Dunlap sin6_ip.sin6_port = htons(sr->sr_port); 1142a6d42e7dSPeter Dunlap sin6_ip.sin6_addr = in6addr_any; 1143a6d42e7dSPeter Dunlap 11440f1702c5SYu Xiangning (void) ksocket_setsockopt(so_svc->is_so, SOL_SOCKET, 11450f1702c5SYu Xiangning SO_REUSEADDR, (char *)&on, sizeof (on), CRED()); 1146a6d42e7dSPeter Dunlap /* 1147a6d42e7dSPeter Dunlap * Turn off SO_MAC_EXEMPT so future sobinds succeed 1148a6d42e7dSPeter Dunlap */ 11490f1702c5SYu Xiangning (void) ksocket_setsockopt(so_svc->is_so, SOL_SOCKET, 11500f1702c5SYu Xiangning SO_MAC_EXEMPT, (char *)&off, sizeof (off), CRED()); 1151a6d42e7dSPeter Dunlap 11520f1702c5SYu Xiangning if (ksocket_bind(so_svc->is_so, (struct sockaddr *)&sin6_ip, 11530f1702c5SYu Xiangning sizeof (sin6_ip), CRED()) != 0) { 1154a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1155a6d42e7dSPeter Dunlap idm_sodestroy(so_svc->is_so); 1156a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1157a6d42e7dSPeter Dunlap } 1158a6d42e7dSPeter Dunlap } 1159a6d42e7dSPeter Dunlap 1160a6d42e7dSPeter Dunlap idm_set_tgt_connect_options(so_svc->is_so); 1161a6d42e7dSPeter Dunlap 11620f1702c5SYu Xiangning if (ksocket_listen(so_svc->is_so, 5, CRED()) != 0) { 1163a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1164a6d42e7dSPeter Dunlap idm_soshutdown(so_svc->is_so); 1165a6d42e7dSPeter Dunlap idm_sodestroy(so_svc->is_so); 1166a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1167a6d42e7dSPeter Dunlap } 1168a6d42e7dSPeter Dunlap 1169a6d42e7dSPeter Dunlap /* Launch a watch thread */ 1170a6d42e7dSPeter Dunlap so_svc->is_thread = thread_create(NULL, 0, idm_so_svc_port_watcher, 1171a6d42e7dSPeter Dunlap is, 0, &p0, TS_RUN, minclsyspri); 1172a6d42e7dSPeter Dunlap 1173a6d42e7dSPeter Dunlap if (so_svc->is_thread == NULL) { 1174a6d42e7dSPeter Dunlap /* Failure to launch; teardown the socket */ 1175a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1176a6d42e7dSPeter Dunlap idm_soshutdown(so_svc->is_so); 1177a6d42e7dSPeter Dunlap idm_sodestroy(so_svc->is_so); 1178a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1179a6d42e7dSPeter Dunlap } 11800f1702c5SYu Xiangning ksocket_hold(so_svc->is_so); 1181a6d42e7dSPeter Dunlap /* Wait for the port watcher thread to start */ 1182a6d42e7dSPeter Dunlap while (!so_svc->is_thread_running) 1183a6d42e7dSPeter Dunlap cv_wait(&is->is_cv, &is->is_mutex); 1184a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1185a6d42e7dSPeter Dunlap 1186a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1187a6d42e7dSPeter Dunlap } 1188a6d42e7dSPeter Dunlap 1189a6d42e7dSPeter Dunlap /* 1190a6d42e7dSPeter Dunlap * idm_so_tgt_svc_offline 1191a6d42e7dSPeter Dunlap * 1192a6d42e7dSPeter Dunlap * Stop listening on the IP address and port identified by idm_svc_t. 1193a6d42e7dSPeter Dunlap */ 1194a6d42e7dSPeter Dunlap static void 1195a6d42e7dSPeter Dunlap idm_so_tgt_svc_offline(idm_svc_t *is) 1196a6d42e7dSPeter Dunlap { 1197a6d42e7dSPeter Dunlap idm_so_svc_t *so_svc; 1198a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex); 1199a6d42e7dSPeter Dunlap so_svc = (idm_so_svc_t *)is->is_so_svc; 1200a6d42e7dSPeter Dunlap so_svc->is_thread_running = B_FALSE; 1201a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex); 1202a6d42e7dSPeter Dunlap 1203a6d42e7dSPeter Dunlap /* 12040f1702c5SYu Xiangning * Teardown socket 1205a6d42e7dSPeter Dunlap */ 12060f1702c5SYu Xiangning idm_sodestroy(so_svc->is_so); 1207a6d42e7dSPeter Dunlap 1208a6d42e7dSPeter Dunlap /* 1209a6d42e7dSPeter Dunlap * Now we expect the port watcher thread to terminate 1210a6d42e7dSPeter Dunlap */ 1211a6d42e7dSPeter Dunlap thread_join(so_svc->is_thread_did); 1212a6d42e7dSPeter Dunlap } 1213a6d42e7dSPeter Dunlap 1214a6d42e7dSPeter Dunlap /* 1215a6d42e7dSPeter Dunlap * Watch thread for target service connection establishment. 1216a6d42e7dSPeter Dunlap */ 1217a6d42e7dSPeter Dunlap void 1218a6d42e7dSPeter Dunlap idm_so_svc_port_watcher(void *arg) 1219a6d42e7dSPeter Dunlap { 1220a6d42e7dSPeter Dunlap idm_svc_t *svc = arg; 12210f1702c5SYu Xiangning ksocket_t new_so; 1222a6d42e7dSPeter Dunlap idm_conn_t *ic; 1223a6d42e7dSPeter Dunlap idm_status_t idmrc; 1224a6d42e7dSPeter Dunlap idm_so_svc_t *so_svc; 1225a6d42e7dSPeter Dunlap int rc; 1226a6d42e7dSPeter Dunlap const uint32_t off = 0; 12270f1702c5SYu Xiangning struct sockaddr_in6 t_addr; 12280f1702c5SYu Xiangning socklen_t t_addrlen; 1229a6d42e7dSPeter Dunlap 12300f1702c5SYu Xiangning bzero(&t_addr, sizeof (struct sockaddr_in6)); 12310f1702c5SYu Xiangning t_addrlen = sizeof (struct sockaddr_in6); 1232a6d42e7dSPeter Dunlap mutex_enter(&svc->is_mutex); 1233a6d42e7dSPeter Dunlap 1234a6d42e7dSPeter Dunlap so_svc = svc->is_so_svc; 1235a6d42e7dSPeter Dunlap so_svc->is_thread_running = B_TRUE; 1236a6d42e7dSPeter Dunlap so_svc->is_thread_did = so_svc->is_thread->t_did; 1237a6d42e7dSPeter Dunlap 1238a6d42e7dSPeter Dunlap cv_signal(&svc->is_cv); 1239a6d42e7dSPeter Dunlap 1240a6d42e7dSPeter Dunlap IDM_SVC_LOG(CE_NOTE, "iSCSI service (%p/%d) online", (void *)svc, 1241a6d42e7dSPeter Dunlap svc->is_svc_req.sr_port); 1242a6d42e7dSPeter Dunlap 1243a6d42e7dSPeter Dunlap while (so_svc->is_thread_running) { 1244a6d42e7dSPeter Dunlap mutex_exit(&svc->is_mutex); 1245a6d42e7dSPeter Dunlap 12460f1702c5SYu Xiangning if ((rc = ksocket_accept(so_svc->is_so, 12470f1702c5SYu Xiangning (struct sockaddr *)&t_addr, &t_addrlen, 12480f1702c5SYu Xiangning &new_so, CRED())) != 0) { 1249a6d42e7dSPeter Dunlap mutex_enter(&svc->is_mutex); 1250a6d42e7dSPeter Dunlap if (rc == ECONNABORTED) 1251a6d42e7dSPeter Dunlap continue; 1252a6d42e7dSPeter Dunlap /* Connection problem */ 1253a6d42e7dSPeter Dunlap break; 1254a6d42e7dSPeter Dunlap } 1255a6d42e7dSPeter Dunlap /* 1256a6d42e7dSPeter Dunlap * Turn off SO_MAC_EXEMPT so future sobinds succeed 1257a6d42e7dSPeter Dunlap */ 12580f1702c5SYu Xiangning (void) ksocket_setsockopt(new_so, SOL_SOCKET, SO_MAC_EXEMPT, 12590f1702c5SYu Xiangning (char *)&off, sizeof (off), CRED()); 1260a6d42e7dSPeter Dunlap 1261a6d42e7dSPeter Dunlap idmrc = idm_svc_conn_create(svc, IDM_TRANSPORT_TYPE_SOCKETS, 1262a6d42e7dSPeter Dunlap &ic); 1263a6d42e7dSPeter Dunlap if (idmrc != IDM_STATUS_SUCCESS) { 1264a6d42e7dSPeter Dunlap /* Drop connection */ 1265a6d42e7dSPeter Dunlap idm_soshutdown(new_so); 1266a6d42e7dSPeter Dunlap idm_sodestroy(new_so); 1267a6d42e7dSPeter Dunlap mutex_enter(&svc->is_mutex); 1268a6d42e7dSPeter Dunlap continue; 1269a6d42e7dSPeter Dunlap } 1270a6d42e7dSPeter Dunlap 1271a6d42e7dSPeter Dunlap idmrc = idm_so_tgt_conn_create(ic, new_so); 1272a6d42e7dSPeter Dunlap if (idmrc != IDM_STATUS_SUCCESS) { 1273a6d42e7dSPeter Dunlap idm_svc_conn_destroy(ic); 1274a6d42e7dSPeter Dunlap idm_soshutdown(new_so); 1275a6d42e7dSPeter Dunlap idm_sodestroy(new_so); 1276a6d42e7dSPeter Dunlap mutex_enter(&svc->is_mutex); 1277a6d42e7dSPeter Dunlap continue; 1278a6d42e7dSPeter Dunlap } 1279a6d42e7dSPeter Dunlap 1280a6d42e7dSPeter Dunlap /* 1281a6d42e7dSPeter Dunlap * Kick the state machine. At CS_S3_XPT_UP the state machine 1282a6d42e7dSPeter Dunlap * will notify the client (target) about the new connection. 1283a6d42e7dSPeter Dunlap */ 1284a6d42e7dSPeter Dunlap idm_conn_event(ic, CE_CONNECT_ACCEPT, NULL); 1285a6d42e7dSPeter Dunlap 1286a6d42e7dSPeter Dunlap mutex_enter(&svc->is_mutex); 1287a6d42e7dSPeter Dunlap } 12880f1702c5SYu Xiangning ksocket_rele(so_svc->is_so); 1289a6d42e7dSPeter Dunlap so_svc->is_thread_running = B_FALSE; 1290a6d42e7dSPeter Dunlap mutex_exit(&svc->is_mutex); 1291a6d42e7dSPeter Dunlap 1292a6d42e7dSPeter Dunlap IDM_SVC_LOG(CE_NOTE, "iSCSI service (%p/%d) offline", (void *)svc, 1293a6d42e7dSPeter Dunlap svc->is_svc_req.sr_port); 1294a6d42e7dSPeter Dunlap 1295a6d42e7dSPeter Dunlap thread_exit(); 1296a6d42e7dSPeter Dunlap } 1297a6d42e7dSPeter Dunlap 1298a6d42e7dSPeter Dunlap /* 1299a6d42e7dSPeter Dunlap * idm_so_free_task_rsrc() stops any ongoing processing of the task and 1300a6d42e7dSPeter Dunlap * frees resources associated with the task. 1301a6d42e7dSPeter Dunlap * 1302a6d42e7dSPeter Dunlap * It's not clear that this should return idm_status_t. What do we do 1303a6d42e7dSPeter Dunlap * if it fails? 1304a6d42e7dSPeter Dunlap */ 1305a6d42e7dSPeter Dunlap static idm_status_t 1306a6d42e7dSPeter Dunlap idm_so_free_task_rsrc(idm_task_t *idt) 1307a6d42e7dSPeter Dunlap { 1308a6d42e7dSPeter Dunlap idm_buf_t *idb; 1309a6d42e7dSPeter Dunlap 131030e7468fSPeter Dunlap /* 131130e7468fSPeter Dunlap * There is nothing to cleanup on initiator connections 131230e7468fSPeter Dunlap */ 131330e7468fSPeter Dunlap if (IDM_CONN_ISINI(idt->idt_ic)) 131430e7468fSPeter Dunlap return (IDM_STATUS_SUCCESS); 131530e7468fSPeter Dunlap 1316a6d42e7dSPeter Dunlap /* 1317a6d42e7dSPeter Dunlap * If this is a target connection, call idm_buf_rx_from_ini_done for 1318a6d42e7dSPeter Dunlap * any buffer on the "outbufv" list with idb->idb_in_transport==B_TRUE. 1319a6d42e7dSPeter Dunlap * 1320a6d42e7dSPeter Dunlap * In addition, remove any buffers associated with this task from 1321a6d42e7dSPeter Dunlap * the ic_tx_list. We'll do this by walking the idt_inbufv list, but 1322a6d42e7dSPeter Dunlap * items don't actually get removed from that list (and completion 1323a6d42e7dSPeter Dunlap * routines called) until idm_task_cleanup. 1324a6d42e7dSPeter Dunlap */ 1325a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1326a6d42e7dSPeter Dunlap 1327a6d42e7dSPeter Dunlap for (idb = list_head(&idt->idt_outbufv); idb != NULL; 1328a6d42e7dSPeter Dunlap idb = list_next(&idt->idt_outbufv, idb)) { 1329a6d42e7dSPeter Dunlap if (idb->idb_in_transport) { 1330a6d42e7dSPeter Dunlap /* 1331a6d42e7dSPeter Dunlap * idm_buf_rx_from_ini_done releases idt->idt_mutex 1332a6d42e7dSPeter Dunlap */ 1333a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic, 1334a668b114SPriya Krishnan uintptr_t, idb->idb_buf, 1335a668b114SPriya Krishnan uint32_t, idb->idb_bufoffset, 1336a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 1337a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 1338a668b114SPriya Krishnan int, XFER_BUF_RX_FROM_INI); 1339a6d42e7dSPeter Dunlap idm_buf_rx_from_ini_done(idt, idb, IDM_STATUS_ABORTED); 1340a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1341a6d42e7dSPeter Dunlap } 1342a6d42e7dSPeter Dunlap } 1343a6d42e7dSPeter Dunlap 1344a6d42e7dSPeter Dunlap for (idb = list_head(&idt->idt_inbufv); idb != NULL; 1345a6d42e7dSPeter Dunlap idb = list_next(&idt->idt_inbufv, idb)) { 1346a6d42e7dSPeter Dunlap /* 1347a6d42e7dSPeter Dunlap * We want to remove these items from the tx_list as well, 1348a6d42e7dSPeter Dunlap * but knowing it's in the idt_inbufv list is not a guarantee 1349a6d42e7dSPeter Dunlap * that it's in the tx_list. If it's on the tx list then 1350a6d42e7dSPeter Dunlap * let idm_sotx_thread() clean it up. 1351a6d42e7dSPeter Dunlap */ 1352a6d42e7dSPeter Dunlap if (idb->idb_in_transport && !idb->idb_tx_thread) { 1353a6d42e7dSPeter Dunlap /* 1354a6d42e7dSPeter Dunlap * idm_buf_tx_to_ini_done releases idt->idt_mutex 1355a6d42e7dSPeter Dunlap */ 1356a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic, 1357a668b114SPriya Krishnan uintptr_t, idb->idb_buf, 1358a668b114SPriya Krishnan uint32_t, idb->idb_bufoffset, 1359a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 1360a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 1361a668b114SPriya Krishnan int, XFER_BUF_TX_TO_INI); 1362a6d42e7dSPeter Dunlap idm_buf_tx_to_ini_done(idt, idb, IDM_STATUS_ABORTED); 1363a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1364a6d42e7dSPeter Dunlap } 1365a6d42e7dSPeter Dunlap } 1366a6d42e7dSPeter Dunlap 1367a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1368a6d42e7dSPeter Dunlap 1369a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1370a6d42e7dSPeter Dunlap } 1371a6d42e7dSPeter Dunlap 1372a6d42e7dSPeter Dunlap /* 1373a6d42e7dSPeter Dunlap * idm_so_negotiate_key_values() validates the key values for this connection 1374a6d42e7dSPeter Dunlap */ 1375a6d42e7dSPeter Dunlap /* ARGSUSED */ 1376a6d42e7dSPeter Dunlap static kv_status_t 1377a6d42e7dSPeter Dunlap idm_so_negotiate_key_values(idm_conn_t *it, nvlist_t *request_nvl, 1378a6d42e7dSPeter Dunlap nvlist_t *response_nvl, nvlist_t *negotiated_nvl) 1379a6d42e7dSPeter Dunlap { 1380a6d42e7dSPeter Dunlap /* All parameters are negotiated at the iscsit level */ 1381a6d42e7dSPeter Dunlap return (KV_HANDLED); 1382a6d42e7dSPeter Dunlap } 1383a6d42e7dSPeter Dunlap 1384a6d42e7dSPeter Dunlap /* 1385a6d42e7dSPeter Dunlap * idm_so_notice_key_values() activates the negotiated key values for 1386a6d42e7dSPeter Dunlap * this connection. 1387a6d42e7dSPeter Dunlap */ 138830e7468fSPeter Dunlap static void 1389a6d42e7dSPeter Dunlap idm_so_notice_key_values(idm_conn_t *it, nvlist_t *negotiated_nvl) 1390a6d42e7dSPeter Dunlap { 1391a6d42e7dSPeter Dunlap char *nvp_name; 1392a6d42e7dSPeter Dunlap nvpair_t *nvp; 1393a6d42e7dSPeter Dunlap nvpair_t *next_nvp; 1394a6d42e7dSPeter Dunlap int nvrc; 1395a6d42e7dSPeter Dunlap idm_status_t idm_status; 1396a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx; 1397*56261083SCharles Ting uint64_t num_val; 1398a6d42e7dSPeter Dunlap 1399a6d42e7dSPeter Dunlap for (nvp = nvlist_next_nvpair(negotiated_nvl, NULL); 1400a6d42e7dSPeter Dunlap nvp != NULL; nvp = next_nvp) { 1401a6d42e7dSPeter Dunlap next_nvp = nvlist_next_nvpair(negotiated_nvl, nvp); 1402a6d42e7dSPeter Dunlap nvp_name = nvpair_name(nvp); 1403a6d42e7dSPeter Dunlap 1404a6d42e7dSPeter Dunlap ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name)); 1405a6d42e7dSPeter Dunlap switch (ikvx->ik_key_id) { 1406a6d42e7dSPeter Dunlap case KI_HEADER_DIGEST: 1407a6d42e7dSPeter Dunlap case KI_DATA_DIGEST: 1408a6d42e7dSPeter Dunlap idm_status = idm_so_handle_digest(it, nvp, ikvx); 1409a6d42e7dSPeter Dunlap ASSERT(idm_status == 0); 1410a6d42e7dSPeter Dunlap 1411a6d42e7dSPeter Dunlap /* Remove processed item from negotiated_nvl list */ 1412a6d42e7dSPeter Dunlap nvrc = nvlist_remove_all( 1413a6d42e7dSPeter Dunlap negotiated_nvl, ikvx->ik_key_name); 1414a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 1415a6d42e7dSPeter Dunlap break; 1416*56261083SCharles Ting case KI_MAX_RECV_DATA_SEGMENT_LENGTH: 1417*56261083SCharles Ting /* 1418*56261083SCharles Ting * Just pass the value down to idm layer. 1419*56261083SCharles Ting * No need to remove it from negotiated_nvl list here. 1420*56261083SCharles Ting */ 1421*56261083SCharles Ting nvrc = nvpair_value_uint64(nvp, &num_val); 1422*56261083SCharles Ting ASSERT(nvrc == 0); 1423*56261083SCharles Ting it->ic_conn_params.max_xmit_dataseglen = 1424*56261083SCharles Ting (uint32_t)num_val; 1425*56261083SCharles Ting break; 1426a6d42e7dSPeter Dunlap default: 1427a6d42e7dSPeter Dunlap break; 1428a6d42e7dSPeter Dunlap } 1429a6d42e7dSPeter Dunlap } 1430a6d42e7dSPeter Dunlap } 1431a6d42e7dSPeter Dunlap 1432*56261083SCharles Ting /* 1433*56261083SCharles Ting * idm_so_declare_key_values() declares the key values for this connection 1434*56261083SCharles Ting */ 1435*56261083SCharles Ting /* ARGSUSED */ 1436*56261083SCharles Ting static kv_status_t 1437*56261083SCharles Ting idm_so_declare_key_values(idm_conn_t *it, nvlist_t *config_nvl, 1438*56261083SCharles Ting nvlist_t *outgoing_nvl) 1439*56261083SCharles Ting { 1440*56261083SCharles Ting char *nvp_name; 1441*56261083SCharles Ting nvpair_t *nvp; 1442*56261083SCharles Ting nvpair_t *next_nvp; 1443*56261083SCharles Ting kv_status_t kvrc; 1444*56261083SCharles Ting int nvrc = 0; 1445*56261083SCharles Ting const idm_kv_xlate_t *ikvx; 1446*56261083SCharles Ting uint64_t num_val; 1447*56261083SCharles Ting 1448*56261083SCharles Ting for (nvp = nvlist_next_nvpair(config_nvl, NULL); 1449*56261083SCharles Ting nvp != NULL && nvrc == 0; nvp = next_nvp) { 1450*56261083SCharles Ting next_nvp = nvlist_next_nvpair(config_nvl, nvp); 1451*56261083SCharles Ting nvp_name = nvpair_name(nvp); 1452*56261083SCharles Ting 1453*56261083SCharles Ting ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name)); 1454*56261083SCharles Ting switch (ikvx->ik_key_id) { 1455*56261083SCharles Ting case KI_MAX_RECV_DATA_SEGMENT_LENGTH: 1456*56261083SCharles Ting if ((nvrc = nvpair_value_uint64(nvp, &num_val)) != 0) { 1457*56261083SCharles Ting break; 1458*56261083SCharles Ting } 1459*56261083SCharles Ting if (outgoing_nvl && 1460*56261083SCharles Ting (nvrc = nvlist_add_uint64(outgoing_nvl, 1461*56261083SCharles Ting nvp_name, num_val)) != 0) { 1462*56261083SCharles Ting break; 1463*56261083SCharles Ting } 1464*56261083SCharles Ting it->ic_conn_params.max_recv_dataseglen = 1465*56261083SCharles Ting (uint32_t)num_val; 1466*56261083SCharles Ting break; 1467*56261083SCharles Ting default: 1468*56261083SCharles Ting break; 1469*56261083SCharles Ting } 1470*56261083SCharles Ting } 1471*56261083SCharles Ting kvrc = idm_nvstat_to_kvstat(nvrc); 1472*56261083SCharles Ting return (kvrc); 1473*56261083SCharles Ting } 1474a6d42e7dSPeter Dunlap 1475a6d42e7dSPeter Dunlap static idm_status_t 1476a6d42e7dSPeter Dunlap idm_so_handle_digest(idm_conn_t *it, nvpair_t *digest_choice, 1477a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx) 1478a6d42e7dSPeter Dunlap { 1479a6d42e7dSPeter Dunlap int nvrc; 1480a6d42e7dSPeter Dunlap char *digest_choice_string; 1481a6d42e7dSPeter Dunlap 1482a6d42e7dSPeter Dunlap nvrc = nvpair_value_string(digest_choice, 1483a6d42e7dSPeter Dunlap &digest_choice_string); 1484a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 1485a6d42e7dSPeter Dunlap if (strcasecmp(digest_choice_string, "crc32c") == 0) { 1486a6d42e7dSPeter Dunlap switch (ikvx->ik_key_id) { 1487a6d42e7dSPeter Dunlap case KI_HEADER_DIGEST: 1488a6d42e7dSPeter Dunlap it->ic_conn_flags |= IDM_CONN_HEADER_DIGEST; 1489a6d42e7dSPeter Dunlap break; 1490a6d42e7dSPeter Dunlap case KI_DATA_DIGEST: 1491a6d42e7dSPeter Dunlap it->ic_conn_flags |= IDM_CONN_DATA_DIGEST; 1492a6d42e7dSPeter Dunlap break; 1493a6d42e7dSPeter Dunlap default: 1494a6d42e7dSPeter Dunlap ASSERT(0); 1495a6d42e7dSPeter Dunlap break; 1496a6d42e7dSPeter Dunlap } 1497a6d42e7dSPeter Dunlap } else if (strcasecmp(digest_choice_string, "none") == 0) { 1498a6d42e7dSPeter Dunlap switch (ikvx->ik_key_id) { 1499a6d42e7dSPeter Dunlap case KI_HEADER_DIGEST: 1500a6d42e7dSPeter Dunlap it->ic_conn_flags &= ~IDM_CONN_HEADER_DIGEST; 1501a6d42e7dSPeter Dunlap break; 1502a6d42e7dSPeter Dunlap case KI_DATA_DIGEST: 1503a6d42e7dSPeter Dunlap it->ic_conn_flags &= ~IDM_CONN_DATA_DIGEST; 1504a6d42e7dSPeter Dunlap break; 1505a6d42e7dSPeter Dunlap default: 1506a6d42e7dSPeter Dunlap ASSERT(0); 1507a6d42e7dSPeter Dunlap break; 1508a6d42e7dSPeter Dunlap } 1509a6d42e7dSPeter Dunlap } else { 1510a6d42e7dSPeter Dunlap ASSERT(0); 1511a6d42e7dSPeter Dunlap } 1512a6d42e7dSPeter Dunlap 1513a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1514a6d42e7dSPeter Dunlap } 1515a6d42e7dSPeter Dunlap 1516a6d42e7dSPeter Dunlap 1517a6d42e7dSPeter Dunlap /* 1518a6d42e7dSPeter Dunlap * idm_so_conn_is_capable() verifies that the passed connection is provided 1519a6d42e7dSPeter Dunlap * for by the sockets interface. 1520a6d42e7dSPeter Dunlap */ 1521a6d42e7dSPeter Dunlap /* ARGSUSED */ 1522a6d42e7dSPeter Dunlap static boolean_t 1523a6d42e7dSPeter Dunlap idm_so_conn_is_capable(idm_conn_req_t *ic, idm_transport_caps_t *caps) 1524a6d42e7dSPeter Dunlap { 1525a6d42e7dSPeter Dunlap return (B_TRUE); 1526a6d42e7dSPeter Dunlap } 1527a6d42e7dSPeter Dunlap 1528a6d42e7dSPeter Dunlap /* 1529a6d42e7dSPeter Dunlap * idm_so_rx_datain() validates the Data Sequence number of the PDU. The 1530a6d42e7dSPeter Dunlap * idm_sorecv_scsidata() function invoked earlier actually reads the data 1531a6d42e7dSPeter Dunlap * off the socket into the appropriate buffers. 1532a6d42e7dSPeter Dunlap */ 1533a6d42e7dSPeter Dunlap static void 1534a6d42e7dSPeter Dunlap idm_so_rx_datain(idm_conn_t *ic, idm_pdu_t *pdu) 1535a6d42e7dSPeter Dunlap { 1536a6d42e7dSPeter Dunlap iscsi_data_hdr_t *bhs; 1537a6d42e7dSPeter Dunlap idm_task_t *idt; 1538a6d42e7dSPeter Dunlap idm_buf_t *idb; 1539a6d42e7dSPeter Dunlap uint32_t datasn; 1540a6d42e7dSPeter Dunlap size_t offset; 1541a6d42e7dSPeter Dunlap iscsi_hdr_t *ihp = (iscsi_hdr_t *)pdu->isp_hdr; 1542a6d42e7dSPeter Dunlap iscsi_data_rsp_hdr_t *idrhp = (iscsi_data_rsp_hdr_t *)ihp; 1543a6d42e7dSPeter Dunlap 1544a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 1545a6d42e7dSPeter Dunlap ASSERT(pdu != NULL); 1546a6d42e7dSPeter Dunlap 1547a6d42e7dSPeter Dunlap bhs = (iscsi_data_hdr_t *)pdu->isp_hdr; 1548a6d42e7dSPeter Dunlap datasn = ntohl(bhs->datasn); 1549a6d42e7dSPeter Dunlap offset = ntohl(bhs->offset); 1550a6d42e7dSPeter Dunlap 1551a6d42e7dSPeter Dunlap ASSERT(bhs->opcode == ISCSI_OP_SCSI_DATA_RSP); 1552a6d42e7dSPeter Dunlap 1553a6d42e7dSPeter Dunlap /* 1554a6d42e7dSPeter Dunlap * Look up the task corresponding to the initiator task tag 1555a6d42e7dSPeter Dunlap * to get the buffers affiliated with the task. 1556a6d42e7dSPeter Dunlap */ 1557a6d42e7dSPeter Dunlap idt = idm_task_find(ic, bhs->itt, bhs->ttt); 1558a6d42e7dSPeter Dunlap if (idt == NULL) { 1559a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: failed to find task"); 1560a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1561a6d42e7dSPeter Dunlap return; 1562a6d42e7dSPeter Dunlap } 1563a6d42e7dSPeter Dunlap 1564a6d42e7dSPeter Dunlap idb = pdu->isp_sorx_buf; 1565a6d42e7dSPeter Dunlap if (idb == NULL) { 1566a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 1567a6d42e7dSPeter Dunlap "idm_so_rx_datain: failed to find buffer"); 1568a6d42e7dSPeter Dunlap idm_task_rele(idt); 1569a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1570a6d42e7dSPeter Dunlap return; 1571a6d42e7dSPeter Dunlap } 1572a6d42e7dSPeter Dunlap 1573a6d42e7dSPeter Dunlap /* 1574a6d42e7dSPeter Dunlap * DataSN values should be sequential and should not have any gaps or 1575a6d42e7dSPeter Dunlap * repetitions. Check the DataSN with the one stored in the task. 1576a6d42e7dSPeter Dunlap */ 1577a6d42e7dSPeter Dunlap if (datasn == idt->idt_exp_datasn) { 1578a6d42e7dSPeter Dunlap idt->idt_exp_datasn++; /* keep track of DataSN received */ 1579a6d42e7dSPeter Dunlap } else { 1580a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: datasn out of order"); 1581a6d42e7dSPeter Dunlap idm_task_rele(idt); 1582a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1583a6d42e7dSPeter Dunlap return; 1584a6d42e7dSPeter Dunlap } 1585a6d42e7dSPeter Dunlap 1586a6d42e7dSPeter Dunlap /* 1587a6d42e7dSPeter Dunlap * PDUs in a sequence should be in continuously increasing 1588a6d42e7dSPeter Dunlap * address offset 1589a6d42e7dSPeter Dunlap */ 1590a6d42e7dSPeter Dunlap if (offset != idb->idb_exp_offset) { 1591a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_datain: unexpected offset"); 159230e7468fSPeter Dunlap idm_task_rele(idt); 1593a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1594a6d42e7dSPeter Dunlap return; 1595a6d42e7dSPeter Dunlap } 1596a6d42e7dSPeter Dunlap /* Expected next relative buffer offset */ 1597a6d42e7dSPeter Dunlap idb->idb_exp_offset += n2h24(bhs->dlength); 159830e7468fSPeter Dunlap idt->idt_rx_bytes += n2h24(bhs->dlength); 159930e7468fSPeter Dunlap 160030e7468fSPeter Dunlap idm_task_rele(idt); 1601a6d42e7dSPeter Dunlap 1602a6d42e7dSPeter Dunlap /* 1603a6d42e7dSPeter Dunlap * For now call scsi_rsp which will process the data rsp 1604a6d42e7dSPeter Dunlap * Revisit, need to provide an explicit client entry point for 1605a6d42e7dSPeter Dunlap * phase collapse completions. 1606a6d42e7dSPeter Dunlap */ 1607a6d42e7dSPeter Dunlap if (((ihp->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_SCSI_DATA_RSP) && 1608a6d42e7dSPeter Dunlap (idrhp->flags & ISCSI_FLAG_DATA_STATUS)) { 1609a6d42e7dSPeter Dunlap (*ic->ic_conn_ops.icb_rx_scsi_rsp)(ic, pdu); 1610a6d42e7dSPeter Dunlap } 1611a6d42e7dSPeter Dunlap 1612a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 1613a6d42e7dSPeter Dunlap } 1614a6d42e7dSPeter Dunlap 1615a6d42e7dSPeter Dunlap /* 1616a6d42e7dSPeter Dunlap * The idm_so_rx_dataout() function is used by the iSCSI target to read 1617a6d42e7dSPeter Dunlap * data from the Data-Out PDU sent by the iSCSI initiator. 1618a6d42e7dSPeter Dunlap * 1619a6d42e7dSPeter Dunlap * This function gets the Initiator Task Tag from the PDU BHS and looks up the 1620a6d42e7dSPeter Dunlap * task to get the buffers associated with the PDU. A PDU might span buffers. 1621a6d42e7dSPeter Dunlap * The data is then read into the respective buffer. 1622a6d42e7dSPeter Dunlap */ 1623a6d42e7dSPeter Dunlap static void 1624a6d42e7dSPeter Dunlap idm_so_rx_dataout(idm_conn_t *ic, idm_pdu_t *pdu) 1625a6d42e7dSPeter Dunlap { 1626a6d42e7dSPeter Dunlap 1627a6d42e7dSPeter Dunlap iscsi_data_hdr_t *bhs; 1628a6d42e7dSPeter Dunlap idm_task_t *idt; 1629a6d42e7dSPeter Dunlap idm_buf_t *idb; 1630a6d42e7dSPeter Dunlap size_t offset; 1631a6d42e7dSPeter Dunlap 1632a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 1633a6d42e7dSPeter Dunlap ASSERT(pdu != NULL); 1634a6d42e7dSPeter Dunlap 1635a6d42e7dSPeter Dunlap bhs = (iscsi_data_hdr_t *)pdu->isp_hdr; 1636a6d42e7dSPeter Dunlap offset = ntohl(bhs->offset); 1637a6d42e7dSPeter Dunlap ASSERT(bhs->opcode == ISCSI_OP_SCSI_DATA); 1638a6d42e7dSPeter Dunlap 1639a6d42e7dSPeter Dunlap /* 1640a6d42e7dSPeter Dunlap * Look up the task corresponding to the initiator task tag 1641a6d42e7dSPeter Dunlap * to get the buffers affiliated with the task. 1642a6d42e7dSPeter Dunlap */ 1643a6d42e7dSPeter Dunlap idt = idm_task_find(ic, bhs->itt, bhs->ttt); 1644a6d42e7dSPeter Dunlap if (idt == NULL) { 1645a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 1646a6d42e7dSPeter Dunlap "idm_so_rx_dataout: failed to find task"); 1647a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1648a6d42e7dSPeter Dunlap return; 1649a6d42e7dSPeter Dunlap } 1650a6d42e7dSPeter Dunlap 1651a6d42e7dSPeter Dunlap idb = pdu->isp_sorx_buf; 1652a6d42e7dSPeter Dunlap if (idb == NULL) { 1653a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 1654a6d42e7dSPeter Dunlap "idm_so_rx_dataout: failed to find buffer"); 1655a6d42e7dSPeter Dunlap idm_task_rele(idt); 1656a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1657a6d42e7dSPeter Dunlap return; 1658a6d42e7dSPeter Dunlap } 1659a6d42e7dSPeter Dunlap 1660a6d42e7dSPeter Dunlap /* Keep track of data transferred - check data offsets */ 1661a6d42e7dSPeter Dunlap if (offset != idb->idb_exp_offset) { 1662a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_NOTE, "idm_so_rx_dataout: offset out of seq: " 1663a6d42e7dSPeter Dunlap "%ld, %d", offset, idb->idb_exp_offset); 1664a6d42e7dSPeter Dunlap idm_task_rele(idt); 1665a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1666a6d42e7dSPeter Dunlap return; 1667a6d42e7dSPeter Dunlap } 1668a6d42e7dSPeter Dunlap /* Expected next relative offset */ 1669a6d42e7dSPeter Dunlap idb->idb_exp_offset += ntoh24(bhs->dlength); 167030e7468fSPeter Dunlap idt->idt_rx_bytes += n2h24(bhs->dlength); 1671a6d42e7dSPeter Dunlap 1672a6d42e7dSPeter Dunlap /* 1673a6d42e7dSPeter Dunlap * Call the buffer callback when the transfer is complete 1674a6d42e7dSPeter Dunlap * 1675a6d42e7dSPeter Dunlap * The connection state machine should only abort tasks after 1676a6d42e7dSPeter Dunlap * shutting down the connection so we are assured that there 1677a6d42e7dSPeter Dunlap * won't be a simultaneous attempt to abort this task at the 1678a6d42e7dSPeter Dunlap * same time as we are processing this PDU (due to a connection 1679a6d42e7dSPeter Dunlap * state change). 1680a6d42e7dSPeter Dunlap */ 1681a6d42e7dSPeter Dunlap if (bhs->flags & ISCSI_FLAG_FINAL) { 1682a6d42e7dSPeter Dunlap /* 1683a6d42e7dSPeter Dunlap * We only want to call idm_buf_rx_from_ini_done once 1684a6d42e7dSPeter Dunlap * per transfer. It's possible that this task has 1685a6d42e7dSPeter Dunlap * already been aborted in which case 1686a6d42e7dSPeter Dunlap * idm_so_free_task_rsrc will call idm_buf_rx_from_ini_done 1687a6d42e7dSPeter Dunlap * for each buffer with idb_in_transport==B_TRUE. To 1688a6d42e7dSPeter Dunlap * close this window and ensure that this doesn't happen, 1689a6d42e7dSPeter Dunlap * we'll clear idb->idb_in_transport now while holding 1690a6d42e7dSPeter Dunlap * the task mutex. This is only really an issue for 1691a6d42e7dSPeter Dunlap * SCSI task abort -- if tasks were being aborted because 1692a6d42e7dSPeter Dunlap * of a connection state change the state machine would 1693a6d42e7dSPeter Dunlap * have already stopped the receive thread. 1694a6d42e7dSPeter Dunlap */ 1695a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1696a6d42e7dSPeter Dunlap 1697a6d42e7dSPeter Dunlap /* 1698a6d42e7dSPeter Dunlap * Release the task hold here (obtained in idm_task_find) 1699a6d42e7dSPeter Dunlap * because the task may complete synchronously during 1700a6d42e7dSPeter Dunlap * idm_buf_rx_from_ini_done. Since we still have an active 1701a6d42e7dSPeter Dunlap * buffer we know there is at least one additional hold on idt. 1702a6d42e7dSPeter Dunlap */ 1703a6d42e7dSPeter Dunlap idm_task_rele(idt); 1704a6d42e7dSPeter Dunlap 1705a6d42e7dSPeter Dunlap /* 1706a6d42e7dSPeter Dunlap * idm_buf_rx_from_ini_done releases idt->idt_mutex 1707a6d42e7dSPeter Dunlap */ 1708a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, idm_conn_t *, idt->idt_ic, 1709a668b114SPriya Krishnan uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset, 1710a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 1711a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 1712a668b114SPriya Krishnan int, XFER_BUF_RX_FROM_INI); 1713a6d42e7dSPeter Dunlap idm_buf_rx_from_ini_done(idt, idb, IDM_STATUS_SUCCESS); 1714a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 1715a6d42e7dSPeter Dunlap return; 1716a6d42e7dSPeter Dunlap } 1717a6d42e7dSPeter Dunlap 1718a6d42e7dSPeter Dunlap idm_task_rele(idt); 1719a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 1720a6d42e7dSPeter Dunlap } 1721a6d42e7dSPeter Dunlap 1722a6d42e7dSPeter Dunlap /* 1723a6d42e7dSPeter Dunlap * The idm_so_rx_rtt() function is used by the iSCSI initiator to handle 1724a6d42e7dSPeter Dunlap * the R2T PDU sent by the iSCSI target indicating that it is ready to 1725a6d42e7dSPeter Dunlap * accept data. This gets the Initiator Task Tag (itt) from the PDU BHS 1726a6d42e7dSPeter Dunlap * and looks up the task in the task tree using the itt to get the output 1727a6d42e7dSPeter Dunlap * buffers associated the task. The R2T PDU contains the offset of the 1728a6d42e7dSPeter Dunlap * requested data and the data length. This function then constructs a 1729a6d42e7dSPeter Dunlap * sequence of iSCSI PDUs and outputs the requested data. Each Data-Out 1730a6d42e7dSPeter Dunlap * PDU is associated with the R2T by the Target Transfer Tag (ttt). 1731a6d42e7dSPeter Dunlap */ 173230e7468fSPeter Dunlap 1733a6d42e7dSPeter Dunlap static void 1734a6d42e7dSPeter Dunlap idm_so_rx_rtt(idm_conn_t *ic, idm_pdu_t *pdu) 1735a6d42e7dSPeter Dunlap { 1736a6d42e7dSPeter Dunlap idm_task_t *idt; 1737a6d42e7dSPeter Dunlap idm_buf_t *idb; 1738a6d42e7dSPeter Dunlap iscsi_rtt_hdr_t *rtt_hdr; 1739a6d42e7dSPeter Dunlap uint32_t data_offset; 174030e7468fSPeter Dunlap uint32_t data_length; 1741a6d42e7dSPeter Dunlap 1742a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 1743a6d42e7dSPeter Dunlap ASSERT(pdu != NULL); 1744a6d42e7dSPeter Dunlap 1745a6d42e7dSPeter Dunlap rtt_hdr = (iscsi_rtt_hdr_t *)pdu->isp_hdr; 1746a6d42e7dSPeter Dunlap data_offset = ntohl(rtt_hdr->data_offset); 174730e7468fSPeter Dunlap data_length = ntohl(rtt_hdr->data_length); 1748a6d42e7dSPeter Dunlap idt = idm_task_find(ic, rtt_hdr->itt, rtt_hdr->ttt); 1749a6d42e7dSPeter Dunlap 1750a6d42e7dSPeter Dunlap if (idt == NULL) { 1751a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: could not find task"); 1752a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1753a6d42e7dSPeter Dunlap return; 1754a6d42e7dSPeter Dunlap } 1755a6d42e7dSPeter Dunlap 1756a6d42e7dSPeter Dunlap /* Find the buffer bound to the task by the iSCSI initiator */ 1757a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 1758a6d42e7dSPeter Dunlap idb = idm_buf_find(&idt->idt_outbufv, data_offset); 1759a6d42e7dSPeter Dunlap if (idb == NULL) { 1760a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1761a6d42e7dSPeter Dunlap idm_task_rele(idt); 1762a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: could not find buffer"); 1763a6d42e7dSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 1764a6d42e7dSPeter Dunlap return; 1765a6d42e7dSPeter Dunlap } 1766a6d42e7dSPeter Dunlap 176730e7468fSPeter Dunlap /* return buffer contains this data */ 176830e7468fSPeter Dunlap if (data_offset + data_length > idb->idb_buflen) { 176930e7468fSPeter Dunlap /* Overflow */ 177030e7468fSPeter Dunlap mutex_exit(&idt->idt_mutex); 177130e7468fSPeter Dunlap idm_task_rele(idt); 177230e7468fSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_so_rx_rtt: read from outside " 177330e7468fSPeter Dunlap "buffer"); 177430e7468fSPeter Dunlap idm_pdu_rx_protocol_error(ic, pdu); 177530e7468fSPeter Dunlap return; 177630e7468fSPeter Dunlap } 177730e7468fSPeter Dunlap 177830e7468fSPeter Dunlap idt->idt_r2t_ttt = rtt_hdr->ttt; 177930e7468fSPeter Dunlap idt->idt_exp_datasn = 0; 178030e7468fSPeter Dunlap 178130e7468fSPeter Dunlap idm_so_send_rtt_data(ic, idt, idb, data_offset, 178230e7468fSPeter Dunlap ntohl(rtt_hdr->data_length)); 1783a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 1784a6d42e7dSPeter Dunlap 1785a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 1786a6d42e7dSPeter Dunlap idm_task_rele(idt); 1787a6d42e7dSPeter Dunlap 1788a6d42e7dSPeter Dunlap } 1789a6d42e7dSPeter Dunlap 1790a6d42e7dSPeter Dunlap idm_status_t 1791a6d42e7dSPeter Dunlap idm_sorecvdata(idm_conn_t *ic, idm_pdu_t *pdu) 1792a6d42e7dSPeter Dunlap { 1793a6d42e7dSPeter Dunlap uint8_t pad[ISCSI_PAD_WORD_LEN]; 1794a6d42e7dSPeter Dunlap int pad_len; 1795a6d42e7dSPeter Dunlap uint32_t data_digest_crc; 1796a6d42e7dSPeter Dunlap uint32_t crc_calculated; 1797a6d42e7dSPeter Dunlap int total_len; 1798a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 1799a6d42e7dSPeter Dunlap 1800a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 1801a6d42e7dSPeter Dunlap 1802a6d42e7dSPeter Dunlap pad_len = ((ISCSI_PAD_WORD_LEN - 1803a6d42e7dSPeter Dunlap (pdu->isp_datalen & (ISCSI_PAD_WORD_LEN - 1))) & 1804a6d42e7dSPeter Dunlap (ISCSI_PAD_WORD_LEN - 1)); 1805a6d42e7dSPeter Dunlap 1806a6d42e7dSPeter Dunlap ASSERT(pdu->isp_iovlen < (PDU_MAX_IOVLEN - 2)); /* pad + data digest */ 1807a6d42e7dSPeter Dunlap 1808a6d42e7dSPeter Dunlap total_len = pdu->isp_datalen; 1809a6d42e7dSPeter Dunlap 1810a6d42e7dSPeter Dunlap if (pad_len) { 1811a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_base = (char *)&pad; 1812a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_len = pad_len; 1813a6d42e7dSPeter Dunlap total_len += pad_len; 1814a6d42e7dSPeter Dunlap pdu->isp_iovlen++; 1815a6d42e7dSPeter Dunlap } 1816a6d42e7dSPeter Dunlap 1817a6d42e7dSPeter Dunlap /* setup data digest */ 1818a6d42e7dSPeter Dunlap if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) != 0) { 1819a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_base = 1820a6d42e7dSPeter Dunlap (char *)&data_digest_crc; 1821a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_len = 1822a6d42e7dSPeter Dunlap sizeof (data_digest_crc); 1823a6d42e7dSPeter Dunlap total_len += sizeof (data_digest_crc); 1824a6d42e7dSPeter Dunlap pdu->isp_iovlen++; 1825a6d42e7dSPeter Dunlap } 1826a6d42e7dSPeter Dunlap 182730e7468fSPeter Dunlap pdu->isp_data = (uint8_t *)(uintptr_t)pdu->isp_iov[0].iov_base; 182830e7468fSPeter Dunlap 1829a6d42e7dSPeter Dunlap if (idm_iov_sorecv(so_conn->ic_so, &pdu->isp_iov[0], 1830a6d42e7dSPeter Dunlap pdu->isp_iovlen, total_len) != 0) { 1831a6d42e7dSPeter Dunlap return (IDM_STATUS_IO); 1832a6d42e7dSPeter Dunlap } 1833a6d42e7dSPeter Dunlap 1834a6d42e7dSPeter Dunlap if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) != 0) { 1835a6d42e7dSPeter Dunlap crc_calculated = idm_crc32c(pdu->isp_data, 1836a6d42e7dSPeter Dunlap pdu->isp_datalen); 1837a6d42e7dSPeter Dunlap if (pad_len) { 1838a6d42e7dSPeter Dunlap crc_calculated = idm_crc32c_continued((char *)&pad, 1839a6d42e7dSPeter Dunlap pad_len, crc_calculated); 1840a6d42e7dSPeter Dunlap } 1841a6d42e7dSPeter Dunlap if (crc_calculated != data_digest_crc) { 1842a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 1843a6d42e7dSPeter Dunlap "idm_sorecvdata: " 1844a6d42e7dSPeter Dunlap "CRC error: actual 0x%x, calc 0x%x", 1845a6d42e7dSPeter Dunlap data_digest_crc, crc_calculated); 1846a6d42e7dSPeter Dunlap 1847a6d42e7dSPeter Dunlap /* Invalid Data Digest */ 1848a6d42e7dSPeter Dunlap return (IDM_STATUS_DATA_DIGEST); 1849a6d42e7dSPeter Dunlap } 1850a6d42e7dSPeter Dunlap } 1851a6d42e7dSPeter Dunlap 1852a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1853a6d42e7dSPeter Dunlap } 1854a6d42e7dSPeter Dunlap 1855a6d42e7dSPeter Dunlap /* 1856a6d42e7dSPeter Dunlap * idm_sorecv_scsidata() is used to receive scsi data from the socket. The 1857a6d42e7dSPeter Dunlap * Data-type PDU header must be read into the idm_pdu_t structure prior to 1858a6d42e7dSPeter Dunlap * calling this function. 1859a6d42e7dSPeter Dunlap */ 1860a6d42e7dSPeter Dunlap idm_status_t 1861a6d42e7dSPeter Dunlap idm_sorecv_scsidata(idm_conn_t *ic, idm_pdu_t *pdu) 1862a6d42e7dSPeter Dunlap { 1863a6d42e7dSPeter Dunlap iscsi_data_hdr_t *bhs; 1864a6d42e7dSPeter Dunlap idm_task_t *task; 1865a6d42e7dSPeter Dunlap uint32_t offset; 1866a6d42e7dSPeter Dunlap uint8_t opcode; 1867a6d42e7dSPeter Dunlap uint32_t dlength; 1868a6d42e7dSPeter Dunlap list_t *buflst; 1869a6d42e7dSPeter Dunlap uint32_t xfer_bytes; 1870a6d42e7dSPeter Dunlap idm_status_t status; 1871a6d42e7dSPeter Dunlap 1872a6d42e7dSPeter Dunlap ASSERT(ic != NULL); 1873a6d42e7dSPeter Dunlap ASSERT(pdu != NULL); 1874a6d42e7dSPeter Dunlap 1875a6d42e7dSPeter Dunlap bhs = (iscsi_data_hdr_t *)pdu->isp_hdr; 1876a6d42e7dSPeter Dunlap 1877a6d42e7dSPeter Dunlap offset = ntohl(bhs->offset); 1878a6d42e7dSPeter Dunlap opcode = bhs->opcode; 1879a6d42e7dSPeter Dunlap dlength = n2h24(bhs->dlength); 1880a6d42e7dSPeter Dunlap 1881a6d42e7dSPeter Dunlap ASSERT((opcode == ISCSI_OP_SCSI_DATA_RSP) || 1882a6d42e7dSPeter Dunlap (opcode == ISCSI_OP_SCSI_DATA)); 1883a6d42e7dSPeter Dunlap 1884a6d42e7dSPeter Dunlap /* 1885a6d42e7dSPeter Dunlap * Successful lookup implicitly gets a "hold" on the task. This 1886a6d42e7dSPeter Dunlap * hold must be released before leaving this function. At one 1887a6d42e7dSPeter Dunlap * point we were caching this task context and retaining the hold 1888a6d42e7dSPeter Dunlap * but it turned out to be very difficult to release the hold properly. 1889a6d42e7dSPeter Dunlap * The task can be aborted and the connection shutdown between this 1890a6d42e7dSPeter Dunlap * call and the subsequent expected call to idm_so_rx_datain/ 1891a6d42e7dSPeter Dunlap * idm_so_rx_dataout (in which case those functions are not called). 1892a6d42e7dSPeter Dunlap * Releasing the hold in the PDU callback doesn't work well either 1893a6d42e7dSPeter Dunlap * because the whole task may be completed by then at which point 1894a6d42e7dSPeter Dunlap * it is too late to release the hold -- for better or worse this 1895a6d42e7dSPeter Dunlap * code doesn't wait on the refcnts during normal operation. 1896a6d42e7dSPeter Dunlap * idm_task_find() is very fast and it is not a huge burden if we 1897a6d42e7dSPeter Dunlap * have to do it twice. 1898a6d42e7dSPeter Dunlap */ 1899a6d42e7dSPeter Dunlap task = idm_task_find(ic, bhs->itt, bhs->ttt); 1900a6d42e7dSPeter Dunlap if (task == NULL) { 1901a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 1902a6d42e7dSPeter Dunlap "idm_sorecv_scsidata: could not find task"); 1903a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1904a6d42e7dSPeter Dunlap } 1905a6d42e7dSPeter Dunlap 1906a6d42e7dSPeter Dunlap mutex_enter(&task->idt_mutex); 1907a6d42e7dSPeter Dunlap buflst = (opcode == ISCSI_OP_SCSI_DATA_RSP) ? 1908a6d42e7dSPeter Dunlap &task->idt_inbufv : &task->idt_outbufv; 1909a6d42e7dSPeter Dunlap pdu->isp_sorx_buf = idm_buf_find(buflst, offset); 1910a6d42e7dSPeter Dunlap mutex_exit(&task->idt_mutex); 1911a6d42e7dSPeter Dunlap 1912a6d42e7dSPeter Dunlap if (pdu->isp_sorx_buf == NULL) { 1913a6d42e7dSPeter Dunlap idm_task_rele(task); 1914a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_sorecv_scsidata: could not find " 1915a6d42e7dSPeter Dunlap "buffer for offset %x opcode=%x", 1916a6d42e7dSPeter Dunlap offset, opcode); 1917a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1918a6d42e7dSPeter Dunlap } 1919a6d42e7dSPeter Dunlap 1920a6d42e7dSPeter Dunlap xfer_bytes = idm_fill_iov(pdu, pdu->isp_sorx_buf, offset, dlength); 1921a6d42e7dSPeter Dunlap ASSERT(xfer_bytes != 0); 1922a6d42e7dSPeter Dunlap if (xfer_bytes != dlength) { 1923a6d42e7dSPeter Dunlap idm_task_rele(task); 1924a6d42e7dSPeter Dunlap /* 1925a6d42e7dSPeter Dunlap * Buffer overflow, connection error. The PDU data is still 1926a6d42e7dSPeter Dunlap * sitting in the socket so we can't use the connection 1927a6d42e7dSPeter Dunlap * again until that data is drained. 1928a6d42e7dSPeter Dunlap */ 1929a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1930a6d42e7dSPeter Dunlap } 1931a6d42e7dSPeter Dunlap 1932a6d42e7dSPeter Dunlap status = idm_sorecvdata(ic, pdu); 1933a6d42e7dSPeter Dunlap 1934a6d42e7dSPeter Dunlap idm_task_rele(task); 1935a6d42e7dSPeter Dunlap 1936a6d42e7dSPeter Dunlap return (status); 1937a6d42e7dSPeter Dunlap } 1938a6d42e7dSPeter Dunlap 1939a6d42e7dSPeter Dunlap static uint32_t 1940a6d42e7dSPeter Dunlap idm_fill_iov(idm_pdu_t *pdu, idm_buf_t *idb, uint32_t ro, uint32_t dlength) 1941a6d42e7dSPeter Dunlap { 1942a6d42e7dSPeter Dunlap uint32_t buf_ro = ro - idb->idb_bufoffset; 1943a6d42e7dSPeter Dunlap uint32_t xfer_len = min(dlength, idb->idb_buflen - buf_ro); 1944a6d42e7dSPeter Dunlap 1945a6d42e7dSPeter Dunlap ASSERT(ro >= idb->idb_bufoffset); 1946a6d42e7dSPeter Dunlap 1947a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_base = 1948a6d42e7dSPeter Dunlap (caddr_t)idb->idb_buf + buf_ro; 1949a6d42e7dSPeter Dunlap pdu->isp_iov[pdu->isp_iovlen].iov_len = xfer_len; 1950a6d42e7dSPeter Dunlap pdu->isp_iovlen++; 1951a6d42e7dSPeter Dunlap 1952a6d42e7dSPeter Dunlap return (xfer_len); 1953a6d42e7dSPeter Dunlap } 1954a6d42e7dSPeter Dunlap 1955a6d42e7dSPeter Dunlap int 1956a6d42e7dSPeter Dunlap idm_sorecv_nonscsidata(idm_conn_t *ic, idm_pdu_t *pdu) 1957a6d42e7dSPeter Dunlap { 1958a6d42e7dSPeter Dunlap pdu->isp_data = kmem_alloc(pdu->isp_datalen, KM_SLEEP); 1959a6d42e7dSPeter Dunlap ASSERT(pdu->isp_data != NULL); 1960a6d42e7dSPeter Dunlap 1961a6d42e7dSPeter Dunlap pdu->isp_databuflen = pdu->isp_datalen; 1962a6d42e7dSPeter Dunlap pdu->isp_iov[0].iov_base = (caddr_t)pdu->isp_data; 1963a6d42e7dSPeter Dunlap pdu->isp_iov[0].iov_len = pdu->isp_datalen; 1964a6d42e7dSPeter Dunlap pdu->isp_iovlen = 1; 1965a6d42e7dSPeter Dunlap /* 1966a6d42e7dSPeter Dunlap * Since we are associating a new data buffer with this received 1967a6d42e7dSPeter Dunlap * PDU we need to set a specific callback to free the data 1968a6d42e7dSPeter Dunlap * after the PDU is processed. 1969a6d42e7dSPeter Dunlap */ 1970a6d42e7dSPeter Dunlap pdu->isp_flags |= IDM_PDU_ADDL_DATA; 1971a6d42e7dSPeter Dunlap pdu->isp_callback = idm_sorx_addl_pdu_cb; 1972a6d42e7dSPeter Dunlap 1973a6d42e7dSPeter Dunlap return (idm_sorecvdata(ic, pdu)); 1974a6d42e7dSPeter Dunlap } 1975a6d42e7dSPeter Dunlap 1976a6d42e7dSPeter Dunlap void 1977a6d42e7dSPeter Dunlap idm_sorx_thread(void *arg) 1978a6d42e7dSPeter Dunlap { 1979a6d42e7dSPeter Dunlap boolean_t conn_failure = B_FALSE; 1980a6d42e7dSPeter Dunlap idm_conn_t *ic = (idm_conn_t *)arg; 1981a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 1982a6d42e7dSPeter Dunlap idm_pdu_t *pdu; 1983a6d42e7dSPeter Dunlap idm_status_t rc; 1984a6d42e7dSPeter Dunlap 1985a6d42e7dSPeter Dunlap idm_conn_hold(ic); 1986a6d42e7dSPeter Dunlap 1987a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 1988a6d42e7dSPeter Dunlap 1989a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 1990a6d42e7dSPeter Dunlap so_conn->ic_rx_thread_running = B_TRUE; 1991a6d42e7dSPeter Dunlap so_conn->ic_rx_thread_did = so_conn->ic_rx_thread->t_did; 1992a6d42e7dSPeter Dunlap cv_signal(&ic->ic_cv); 1993a6d42e7dSPeter Dunlap 1994a6d42e7dSPeter Dunlap while (so_conn->ic_rx_thread_running) { 1995a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_mutex); 1996a6d42e7dSPeter Dunlap 1997a6d42e7dSPeter Dunlap /* 1998a6d42e7dSPeter Dunlap * Get PDU with default header size (large enough for 1999a6d42e7dSPeter Dunlap * BHS plus any anticipated AHS). PDU from 2000a6d42e7dSPeter Dunlap * the cache will have all values set correctly 2001a6d42e7dSPeter Dunlap * for sockets RX including callback. 2002a6d42e7dSPeter Dunlap */ 2003a6d42e7dSPeter Dunlap pdu = kmem_cache_alloc(idm.idm_sorx_pdu_cache, KM_SLEEP); 2004a6d42e7dSPeter Dunlap pdu->isp_ic = ic; 2005a6d42e7dSPeter Dunlap pdu->isp_flags = 0; 2006a6d42e7dSPeter Dunlap pdu->isp_transport_hdrlen = 0; 2007a6d42e7dSPeter Dunlap 2008a6d42e7dSPeter Dunlap if ((rc = idm_sorecvhdr(ic, pdu)) != 0) { 2009a6d42e7dSPeter Dunlap /* 2010a6d42e7dSPeter Dunlap * Call idm_pdu_complete so that we call the callback 2011a6d42e7dSPeter Dunlap * and ensure any memory allocated in idm_sorecvhdr 2012a6d42e7dSPeter Dunlap * gets freed up. 2013a6d42e7dSPeter Dunlap */ 2014a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_FAIL); 2015a6d42e7dSPeter Dunlap 2016a6d42e7dSPeter Dunlap /* 2017a6d42e7dSPeter Dunlap * If ic_rx_thread_running is still set then 2018a6d42e7dSPeter Dunlap * this is some kind of connection problem 2019a6d42e7dSPeter Dunlap * on the socket. In this case we want to 2020a6d42e7dSPeter Dunlap * generate an event. Otherwise some other 2021a6d42e7dSPeter Dunlap * thread closed the socket due to another 2022a6d42e7dSPeter Dunlap * issue in which case we don't need to 2023a6d42e7dSPeter Dunlap * generate an event. 2024a6d42e7dSPeter Dunlap */ 2025a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 2026a6d42e7dSPeter Dunlap if (so_conn->ic_rx_thread_running) { 2027a6d42e7dSPeter Dunlap conn_failure = B_TRUE; 2028a6d42e7dSPeter Dunlap so_conn->ic_rx_thread_running = B_FALSE; 2029a6d42e7dSPeter Dunlap } 2030a6d42e7dSPeter Dunlap 2031a6d42e7dSPeter Dunlap continue; 2032a6d42e7dSPeter Dunlap } 2033a6d42e7dSPeter Dunlap 2034a6d42e7dSPeter Dunlap /* 2035a6d42e7dSPeter Dunlap * Header has been read and validated. Now we need 2036a6d42e7dSPeter Dunlap * to read the PDU data payload (if present). SCSI data 2037a6d42e7dSPeter Dunlap * need to be transferred from the socket directly into 2038a6d42e7dSPeter Dunlap * the associated transfer buffer for the SCSI task. 2039a6d42e7dSPeter Dunlap */ 2040a6d42e7dSPeter Dunlap if (pdu->isp_datalen != 0) { 2041a6d42e7dSPeter Dunlap if ((IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA) || 2042a6d42e7dSPeter Dunlap (IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA_RSP)) { 2043a6d42e7dSPeter Dunlap rc = idm_sorecv_scsidata(ic, pdu); 2044a6d42e7dSPeter Dunlap /* 2045a6d42e7dSPeter Dunlap * All SCSI errors are fatal to the 2046a6d42e7dSPeter Dunlap * connection right now since we have no 2047a6d42e7dSPeter Dunlap * place to put the data. What we need 2048a6d42e7dSPeter Dunlap * is some kind of sink to dispose of unwanted 2049a6d42e7dSPeter Dunlap * SCSI data. For example an invalid task tag 2050a6d42e7dSPeter Dunlap * should not kill the connection (although 2051a6d42e7dSPeter Dunlap * we may want to drop the connection). 2052a6d42e7dSPeter Dunlap */ 2053a6d42e7dSPeter Dunlap } else { 2054a6d42e7dSPeter Dunlap /* 2055a6d42e7dSPeter Dunlap * Not data PDUs so allocate a buffer for the 2056a6d42e7dSPeter Dunlap * data segment and read the remaining data. 2057a6d42e7dSPeter Dunlap */ 2058a6d42e7dSPeter Dunlap rc = idm_sorecv_nonscsidata(ic, pdu); 2059a6d42e7dSPeter Dunlap } 2060a6d42e7dSPeter Dunlap if (rc != 0) { 2061a6d42e7dSPeter Dunlap /* 2062a6d42e7dSPeter Dunlap * Call idm_pdu_complete so that we call the 2063a6d42e7dSPeter Dunlap * callback and ensure any memory allocated 2064a6d42e7dSPeter Dunlap * in idm_sorecvhdr gets freed up. 2065a6d42e7dSPeter Dunlap */ 2066a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_FAIL); 2067a6d42e7dSPeter Dunlap 2068a6d42e7dSPeter Dunlap /* 2069a6d42e7dSPeter Dunlap * If ic_rx_thread_running is still set then 2070a6d42e7dSPeter Dunlap * this is some kind of connection problem 2071a6d42e7dSPeter Dunlap * on the socket. In this case we want to 2072a6d42e7dSPeter Dunlap * generate an event. Otherwise some other 2073a6d42e7dSPeter Dunlap * thread closed the socket due to another 2074a6d42e7dSPeter Dunlap * issue in which case we don't need to 2075a6d42e7dSPeter Dunlap * generate an event. 2076a6d42e7dSPeter Dunlap */ 2077a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 2078a6d42e7dSPeter Dunlap if (so_conn->ic_rx_thread_running) { 2079a6d42e7dSPeter Dunlap conn_failure = B_TRUE; 2080a6d42e7dSPeter Dunlap so_conn->ic_rx_thread_running = B_FALSE; 2081a6d42e7dSPeter Dunlap } 2082a6d42e7dSPeter Dunlap continue; 2083a6d42e7dSPeter Dunlap } 2084a6d42e7dSPeter Dunlap } 2085a6d42e7dSPeter Dunlap 2086a6d42e7dSPeter Dunlap /* 2087a6d42e7dSPeter Dunlap * Process RX PDU 2088a6d42e7dSPeter Dunlap */ 2089a6d42e7dSPeter Dunlap idm_pdu_rx(ic, pdu); 2090a6d42e7dSPeter Dunlap 2091a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 2092a6d42e7dSPeter Dunlap } 2093a6d42e7dSPeter Dunlap 2094a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_mutex); 2095a6d42e7dSPeter Dunlap 2096a6d42e7dSPeter Dunlap /* 2097a6d42e7dSPeter Dunlap * If we dropped out of the RX processing loop because of 2098a6d42e7dSPeter Dunlap * a socket problem or other connection failure (including 2099a6d42e7dSPeter Dunlap * digest errors) then we need to generate a state machine 2100a6d42e7dSPeter Dunlap * event to shut the connection down. 2101a6d42e7dSPeter Dunlap * If the state machine is already in, for example, INIT_ERROR, this 2102a6d42e7dSPeter Dunlap * event will get dropped, and the TX thread will never be notified 2103a6d42e7dSPeter Dunlap * to shut down. To be safe, we'll just notify it here. 2104a6d42e7dSPeter Dunlap */ 2105a6d42e7dSPeter Dunlap if (conn_failure) { 2106a6d42e7dSPeter Dunlap if (so_conn->ic_tx_thread_running) { 2107a6d42e7dSPeter Dunlap so_conn->ic_tx_thread_running = B_FALSE; 2108a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2109a6d42e7dSPeter Dunlap cv_signal(&so_conn->ic_tx_cv); 2110a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2111a6d42e7dSPeter Dunlap } 2112a6d42e7dSPeter Dunlap 2113a6d42e7dSPeter Dunlap idm_conn_event(ic, CE_TRANSPORT_FAIL, rc); 2114a6d42e7dSPeter Dunlap } 2115a6d42e7dSPeter Dunlap 2116a6d42e7dSPeter Dunlap idm_conn_rele(ic); 2117a6d42e7dSPeter Dunlap 2118a6d42e7dSPeter Dunlap thread_exit(); 2119a6d42e7dSPeter Dunlap } 2120a6d42e7dSPeter Dunlap 2121a6d42e7dSPeter Dunlap /* 2122a6d42e7dSPeter Dunlap * idm_so_tx 2123a6d42e7dSPeter Dunlap * 2124a6d42e7dSPeter Dunlap * This is the implementation of idm_transport_ops_t's it_tx_pdu entry 2125a6d42e7dSPeter Dunlap * point. By definition, it is supposed to be fast. So, simply queue 2126a6d42e7dSPeter Dunlap * the entry and return. The real work is done by idm_i_so_tx() via 2127a6d42e7dSPeter Dunlap * idm_sotx_thread(). 2128a6d42e7dSPeter Dunlap */ 2129a6d42e7dSPeter Dunlap 2130a6d42e7dSPeter Dunlap static void 2131a6d42e7dSPeter Dunlap idm_so_tx(idm_conn_t *ic, idm_pdu_t *pdu) 2132a6d42e7dSPeter Dunlap { 2133a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn = ic->ic_transport_private; 2134a6d42e7dSPeter Dunlap 2135a6d42e7dSPeter Dunlap ASSERT(pdu->isp_ic == ic); 2136a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2137a6d42e7dSPeter Dunlap 2138a6d42e7dSPeter Dunlap if (!so_conn->ic_tx_thread_running) { 2139a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2140a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_ABORTED); 2141a6d42e7dSPeter Dunlap return; 2142a6d42e7dSPeter Dunlap } 2143a6d42e7dSPeter Dunlap 2144a6d42e7dSPeter Dunlap list_insert_tail(&so_conn->ic_tx_list, (void *)pdu); 2145a6d42e7dSPeter Dunlap cv_signal(&so_conn->ic_tx_cv); 2146a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2147a6d42e7dSPeter Dunlap } 2148a6d42e7dSPeter Dunlap 2149a6d42e7dSPeter Dunlap static idm_status_t 2150a6d42e7dSPeter Dunlap idm_i_so_tx(idm_pdu_t *pdu) 2151a6d42e7dSPeter Dunlap { 2152a6d42e7dSPeter Dunlap idm_conn_t *ic = pdu->isp_ic; 2153a6d42e7dSPeter Dunlap idm_status_t status = IDM_STATUS_SUCCESS; 2154a6d42e7dSPeter Dunlap uint8_t pad[ISCSI_PAD_WORD_LEN]; 2155a6d42e7dSPeter Dunlap int pad_len; 2156a6d42e7dSPeter Dunlap uint32_t hdr_digest_crc; 2157a6d42e7dSPeter Dunlap uint32_t data_digest_crc = 0; 2158a6d42e7dSPeter Dunlap int total_len = 0; 2159a6d42e7dSPeter Dunlap int iovlen = 0; 2160a6d42e7dSPeter Dunlap struct iovec iov[6]; 2161a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 2162a6d42e7dSPeter Dunlap 2163a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 2164a6d42e7dSPeter Dunlap 2165a6d42e7dSPeter Dunlap /* Setup BHS */ 2166a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (caddr_t)pdu->isp_hdr; 2167a6d42e7dSPeter Dunlap iov[iovlen].iov_len = pdu->isp_hdrlen; 2168a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 2169a6d42e7dSPeter Dunlap iovlen++; 2170a6d42e7dSPeter Dunlap 2171a6d42e7dSPeter Dunlap /* Setup header digest */ 2172a6d42e7dSPeter Dunlap if (((pdu->isp_flags & IDM_PDU_LOGIN_TX) == 0) && 2173a6d42e7dSPeter Dunlap (ic->ic_conn_flags & IDM_CONN_HEADER_DIGEST)) { 2174a6d42e7dSPeter Dunlap hdr_digest_crc = idm_crc32c(pdu->isp_hdr, pdu->isp_hdrlen); 2175a6d42e7dSPeter Dunlap 2176a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (caddr_t)&hdr_digest_crc; 2177a6d42e7dSPeter Dunlap iov[iovlen].iov_len = sizeof (hdr_digest_crc); 2178a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 2179a6d42e7dSPeter Dunlap iovlen++; 2180a6d42e7dSPeter Dunlap } 2181a6d42e7dSPeter Dunlap 2182a6d42e7dSPeter Dunlap /* Setup the data */ 2183a6d42e7dSPeter Dunlap if (pdu->isp_datalen) { 2184a6d42e7dSPeter Dunlap idm_task_t *idt; 2185a6d42e7dSPeter Dunlap idm_buf_t *idb; 2186a6d42e7dSPeter Dunlap iscsi_data_hdr_t *ihp; 2187a6d42e7dSPeter Dunlap ihp = (iscsi_data_hdr_t *)pdu->isp_hdr; 2188a6d42e7dSPeter Dunlap /* Write of immediate data */ 2189a6d42e7dSPeter Dunlap if (ic->ic_ffp && 2190a6d42e7dSPeter Dunlap (ihp->opcode == ISCSI_OP_SCSI_CMD || 2191a6d42e7dSPeter Dunlap ihp->opcode == ISCSI_OP_SCSI_DATA)) { 2192a6d42e7dSPeter Dunlap idt = idm_task_find(ic, ihp->itt, ihp->ttt); 2193a6d42e7dSPeter Dunlap if (idt) { 2194a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 2195a6d42e7dSPeter Dunlap idb = idm_buf_find(&idt->idt_outbufv, 0); 2196a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 219730e7468fSPeter Dunlap /* 219830e7468fSPeter Dunlap * If the initiator call to idm_buf_alloc 219930e7468fSPeter Dunlap * failed then we can get to this point 220030e7468fSPeter Dunlap * without a bound buffer. The associated 220130e7468fSPeter Dunlap * connection failure will clean things up 220230e7468fSPeter Dunlap * later. It would be nice to come up with 220330e7468fSPeter Dunlap * a cleaner way to handle this. In 220430e7468fSPeter Dunlap * particular it seems absurd to look up 220530e7468fSPeter Dunlap * the task and the buffer just to update 220630e7468fSPeter Dunlap * this counter. 220730e7468fSPeter Dunlap */ 220830e7468fSPeter Dunlap if (idb) 220930e7468fSPeter Dunlap idb->idb_xfer_len += pdu->isp_datalen; 221030e7468fSPeter Dunlap idm_task_rele(idt); 2211a6d42e7dSPeter Dunlap } 2212a6d42e7dSPeter Dunlap } 2213a6d42e7dSPeter Dunlap 2214a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (caddr_t)pdu->isp_data; 2215a6d42e7dSPeter Dunlap iov[iovlen].iov_len = pdu->isp_datalen; 2216a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 2217a6d42e7dSPeter Dunlap iovlen++; 2218a6d42e7dSPeter Dunlap } 2219a6d42e7dSPeter Dunlap 2220a6d42e7dSPeter Dunlap /* Setup the data pad if necessary */ 2221a6d42e7dSPeter Dunlap pad_len = ((ISCSI_PAD_WORD_LEN - 2222a6d42e7dSPeter Dunlap (pdu->isp_datalen & (ISCSI_PAD_WORD_LEN - 1))) & 2223a6d42e7dSPeter Dunlap (ISCSI_PAD_WORD_LEN - 1)); 2224a6d42e7dSPeter Dunlap 2225a6d42e7dSPeter Dunlap if (pad_len) { 2226a6d42e7dSPeter Dunlap bzero(pad, sizeof (pad)); 2227a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (void *)&pad; 2228a6d42e7dSPeter Dunlap iov[iovlen].iov_len = pad_len; 2229a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 2230a6d42e7dSPeter Dunlap iovlen++; 2231a6d42e7dSPeter Dunlap } 2232a6d42e7dSPeter Dunlap 2233a6d42e7dSPeter Dunlap /* 2234a6d42e7dSPeter Dunlap * Setup the data digest if enabled. Data-digest is not sent 2235a6d42e7dSPeter Dunlap * for login-phase PDUs. 2236a6d42e7dSPeter Dunlap */ 2237a6d42e7dSPeter Dunlap if ((ic->ic_conn_flags & IDM_CONN_DATA_DIGEST) && 2238a6d42e7dSPeter Dunlap ((pdu->isp_flags & IDM_PDU_LOGIN_TX) == 0) && 2239a6d42e7dSPeter Dunlap (pdu->isp_datalen || pad_len)) { 2240a6d42e7dSPeter Dunlap /* 2241a6d42e7dSPeter Dunlap * RFC3720/10.2.3: A zero-length Data Segment also 2242a6d42e7dSPeter Dunlap * implies a zero-length data digest. 2243a6d42e7dSPeter Dunlap */ 2244a6d42e7dSPeter Dunlap if (pdu->isp_datalen) { 2245a6d42e7dSPeter Dunlap data_digest_crc = idm_crc32c(pdu->isp_data, 2246a6d42e7dSPeter Dunlap pdu->isp_datalen); 2247a6d42e7dSPeter Dunlap } 2248a6d42e7dSPeter Dunlap if (pad_len) { 2249a6d42e7dSPeter Dunlap data_digest_crc = idm_crc32c_continued(&pad, 2250a6d42e7dSPeter Dunlap pad_len, data_digest_crc); 2251a6d42e7dSPeter Dunlap } 2252a6d42e7dSPeter Dunlap 2253a6d42e7dSPeter Dunlap iov[iovlen].iov_base = (caddr_t)&data_digest_crc; 2254a6d42e7dSPeter Dunlap iov[iovlen].iov_len = sizeof (data_digest_crc); 2255a6d42e7dSPeter Dunlap total_len += iov[iovlen].iov_len; 2256a6d42e7dSPeter Dunlap iovlen++; 2257a6d42e7dSPeter Dunlap } 2258a6d42e7dSPeter Dunlap 2259a6d42e7dSPeter Dunlap /* Transmit the PDU */ 2260a6d42e7dSPeter Dunlap if (idm_iov_sosend(so_conn->ic_so, &iov[0], iovlen, 2261a6d42e7dSPeter Dunlap total_len) != 0) { 2262a6d42e7dSPeter Dunlap /* Set error status */ 2263a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 2264a6d42e7dSPeter Dunlap "idm_so_tx: failed to transmit the PDU, so: %p ic: %p " 2265a6d42e7dSPeter Dunlap "data: %p", (void *) so_conn->ic_so, (void *) ic, 2266a6d42e7dSPeter Dunlap (void *) pdu->isp_data); 2267a6d42e7dSPeter Dunlap status = IDM_STATUS_IO; 2268a6d42e7dSPeter Dunlap } 2269a6d42e7dSPeter Dunlap 2270a6d42e7dSPeter Dunlap /* 2271a6d42e7dSPeter Dunlap * Success does not mean that the PDU actually reached the 2272a6d42e7dSPeter Dunlap * remote node since it could get dropped along the way. 2273a6d42e7dSPeter Dunlap */ 2274a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, status); 2275a6d42e7dSPeter Dunlap 2276a6d42e7dSPeter Dunlap return (status); 2277a6d42e7dSPeter Dunlap } 2278a6d42e7dSPeter Dunlap 2279a6d42e7dSPeter Dunlap /* 2280a6d42e7dSPeter Dunlap * The idm_so_buf_tx_to_ini() is used by the target iSCSI layer to transmit the 2281a6d42e7dSPeter Dunlap * Data-In PDUs using sockets. Based on the negotiated MaxRecvDataSegmentLength, 2282a6d42e7dSPeter Dunlap * the buffer is segmented into a sequence of Data-In PDUs, ordered by DataSN. 2283a6d42e7dSPeter Dunlap * A target can invoke this function multiple times for a single read command 2284a6d42e7dSPeter Dunlap * (identified by the same ITT) to split the input into several sequences. 2285a6d42e7dSPeter Dunlap * 2286a6d42e7dSPeter Dunlap * DataSN starts with 0 for the first data PDU of an input command and advances 2287a6d42e7dSPeter Dunlap * by 1 for each subsequent data PDU. Each sequence will have its own F bit, 2288a6d42e7dSPeter Dunlap * which is set to 1 for the last data PDU of a sequence. 2289a6d42e7dSPeter Dunlap * 2290a6d42e7dSPeter Dunlap * Scope for Prototype build: 2291a6d42e7dSPeter Dunlap * The data PDUs within a sequence will be sent in order with the buffer offset 2292a6d42e7dSPeter Dunlap * in increasing order. i.e. initiator and target must have negotiated the 2293a6d42e7dSPeter Dunlap * "DataPDUInOrder" to "Yes". The order between sequences is not enforced. 2294a6d42e7dSPeter Dunlap * 2295a6d42e7dSPeter Dunlap * Caller holds idt->idt_mutex 2296a6d42e7dSPeter Dunlap */ 2297a6d42e7dSPeter Dunlap static idm_status_t 2298a6d42e7dSPeter Dunlap idm_so_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb) 2299a6d42e7dSPeter Dunlap { 2300a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn = idb->idb_ic->ic_transport_private; 2301a6d42e7dSPeter Dunlap idm_pdu_t tmppdu; 2302a6d42e7dSPeter Dunlap 2303a6d42e7dSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 2304a6d42e7dSPeter Dunlap 2305a6d42e7dSPeter Dunlap /* 2306a6d42e7dSPeter Dunlap * Put the idm_buf_t on the tx queue. It will be transmitted by 2307a6d42e7dSPeter Dunlap * idm_sotx_thread. 2308a6d42e7dSPeter Dunlap */ 2309a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2310a6d42e7dSPeter Dunlap 2311a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic, 2312a668b114SPriya Krishnan uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset, 2313a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 2314a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, int, XFER_BUF_TX_TO_INI); 2315a668b114SPriya Krishnan 2316a6d42e7dSPeter Dunlap if (!so_conn->ic_tx_thread_running) { 2317a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2318a6d42e7dSPeter Dunlap /* 2319a6d42e7dSPeter Dunlap * Don't release idt->idt_mutex since we're supposed to hold 2320a6d42e7dSPeter Dunlap * in when calling idm_buf_tx_to_ini_done 2321a6d42e7dSPeter Dunlap */ 2322a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, 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, 2326a668b114SPriya Krishnan int, XFER_BUF_TX_TO_INI); 2327a6d42e7dSPeter Dunlap idm_buf_tx_to_ini_done(idt, idb, IDM_STATUS_ABORTED); 2328a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 2329a6d42e7dSPeter Dunlap } 2330a6d42e7dSPeter Dunlap 2331a6d42e7dSPeter Dunlap /* 2332a6d42e7dSPeter Dunlap * Build a template for the data PDU headers we will use so that 2333a6d42e7dSPeter Dunlap * the SN values will stay consistent with other PDU's we are 2334a6d42e7dSPeter Dunlap * transmitting like R2T and SCSI status. 2335a6d42e7dSPeter Dunlap */ 2336a6d42e7dSPeter Dunlap bzero(&idb->idb_data_hdr_tmpl, sizeof (iscsi_hdr_t)); 2337a6d42e7dSPeter Dunlap tmppdu.isp_hdr = &idb->idb_data_hdr_tmpl; 2338a6d42e7dSPeter Dunlap (*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, &tmppdu, 2339a6d42e7dSPeter Dunlap ISCSI_OP_SCSI_DATA_RSP); 2340a6d42e7dSPeter Dunlap idb->idb_tx_thread = B_TRUE; 2341a6d42e7dSPeter Dunlap list_insert_tail(&so_conn->ic_tx_list, (void *)idb); 2342a6d42e7dSPeter Dunlap cv_signal(&so_conn->ic_tx_cv); 2343a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2344a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 2345a6d42e7dSPeter Dunlap 2346a6d42e7dSPeter Dunlap /* 2347a6d42e7dSPeter Dunlap * Returning success here indicates the transfer was successfully 2348a6d42e7dSPeter Dunlap * dispatched -- it does not mean that the transfer completed 2349a6d42e7dSPeter Dunlap * successfully. 2350a6d42e7dSPeter Dunlap */ 2351a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 2352a6d42e7dSPeter Dunlap } 2353a6d42e7dSPeter Dunlap 2354a6d42e7dSPeter Dunlap /* 2355a6d42e7dSPeter Dunlap * The idm_so_buf_rx_from_ini() is used by the target iSCSI layer to specify the 2356a6d42e7dSPeter Dunlap * data blocks it is ready to receive from the initiator in response to a WRITE 2357a6d42e7dSPeter Dunlap * SCSI command. The target iSCSI layer passes the information about the desired 2358a6d42e7dSPeter Dunlap * data blocks to the initiator in one R2T PDU. The receiving buffer, the buffer 2359a6d42e7dSPeter Dunlap * offset and datalen are passed via the 'idb' argument. 2360a6d42e7dSPeter Dunlap * 2361a6d42e7dSPeter Dunlap * Scope for Prototype build: 2362a6d42e7dSPeter Dunlap * R2Ts are required for any Data-Out PDU, i.e. initiator and target must have 2363a6d42e7dSPeter Dunlap * negotiated the "InitialR2T" to "Yes". 2364a6d42e7dSPeter Dunlap * 2365a6d42e7dSPeter Dunlap * Caller holds idt->idt_mutex 2366a6d42e7dSPeter Dunlap */ 2367a6d42e7dSPeter Dunlap static idm_status_t 2368a6d42e7dSPeter Dunlap idm_so_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb) 2369a6d42e7dSPeter Dunlap { 2370a6d42e7dSPeter Dunlap idm_pdu_t *pdu; 2371a6d42e7dSPeter Dunlap iscsi_rtt_hdr_t *rtt; 2372a6d42e7dSPeter Dunlap 2373a6d42e7dSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 2374a6d42e7dSPeter Dunlap 2375a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic, 2376a668b114SPriya Krishnan uintptr_t, idb->idb_buf, uint32_t, idb->idb_bufoffset, 2377a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 2378a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, int, XFER_BUF_RX_FROM_INI); 2379a668b114SPriya Krishnan 2380a6d42e7dSPeter Dunlap pdu = kmem_cache_alloc(idm.idm_sotx_pdu_cache, KM_SLEEP); 2381a6d42e7dSPeter Dunlap pdu->isp_ic = idt->idt_ic; 2382a6d42e7dSPeter Dunlap bzero(pdu->isp_hdr, sizeof (iscsi_rtt_hdr_t)); 2383a6d42e7dSPeter Dunlap 2384a6d42e7dSPeter Dunlap /* iSCSI layer fills the TTT, ITT, StatSN, ExpCmdSN, MaxCmdSN */ 2385a6d42e7dSPeter Dunlap (*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, pdu, ISCSI_OP_RTT_RSP); 2386a6d42e7dSPeter Dunlap 2387a6d42e7dSPeter Dunlap /* set the rttsn, rtt.flags, rtt.data_offset and rtt.data_length */ 2388a6d42e7dSPeter Dunlap rtt = (iscsi_rtt_hdr_t *)(pdu->isp_hdr); 2389a6d42e7dSPeter Dunlap 2390a6d42e7dSPeter Dunlap rtt->opcode = ISCSI_OP_RTT_RSP; 2391a6d42e7dSPeter Dunlap rtt->flags = ISCSI_FLAG_FINAL; 2392a6d42e7dSPeter Dunlap rtt->data_offset = htonl(idb->idb_bufoffset); 2393a6d42e7dSPeter Dunlap rtt->data_length = htonl(idb->idb_xfer_len); 2394a6d42e7dSPeter Dunlap rtt->rttsn = htonl(idt->idt_exp_rttsn++); 2395a6d42e7dSPeter Dunlap 2396a6d42e7dSPeter Dunlap /* Keep track of buffer offsets */ 2397a6d42e7dSPeter Dunlap idb->idb_exp_offset = idb->idb_bufoffset; 2398a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 2399a6d42e7dSPeter Dunlap 2400a6d42e7dSPeter Dunlap /* 240163528ae4SJames Moore * Transmit the PDU. 2402a6d42e7dSPeter Dunlap */ 240363528ae4SJames Moore idm_pdu_tx(pdu); 2404a6d42e7dSPeter Dunlap 2405a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 2406a6d42e7dSPeter Dunlap } 2407a6d42e7dSPeter Dunlap 2408a6d42e7dSPeter Dunlap static idm_status_t 2409a6d42e7dSPeter Dunlap idm_so_buf_alloc(idm_buf_t *idb, uint64_t buflen) 2410a6d42e7dSPeter Dunlap { 2411cf8c0ebaSPeter Dunlap if ((buflen > IDM_SO_BUF_CACHE_LB) && (buflen <= IDM_SO_BUF_CACHE_UB)) { 2412cf8c0ebaSPeter Dunlap idb->idb_buf = kmem_cache_alloc(idm.idm_so_128k_buf_cache, 2413cf8c0ebaSPeter Dunlap KM_NOSLEEP); 2414cf8c0ebaSPeter Dunlap idb->idb_buf_private = idm.idm_so_128k_buf_cache; 2415cf8c0ebaSPeter Dunlap } else { 2416cf8c0ebaSPeter Dunlap idb->idb_buf = kmem_alloc(buflen, KM_NOSLEEP); 2417cf8c0ebaSPeter Dunlap idb->idb_buf_private = NULL; 2418cf8c0ebaSPeter Dunlap } 2419cf8c0ebaSPeter Dunlap 2420a6d42e7dSPeter Dunlap if (idb->idb_buf == NULL) { 2421a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_NOTE, 2422a6d42e7dSPeter Dunlap "idm_so_buf_alloc: failed buffer allocation"); 2423a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 2424a6d42e7dSPeter Dunlap } 2425cf8c0ebaSPeter Dunlap 2426a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 2427a6d42e7dSPeter Dunlap } 2428a6d42e7dSPeter Dunlap 2429a6d42e7dSPeter Dunlap /* ARGSUSED */ 2430a6d42e7dSPeter Dunlap static idm_status_t 2431a6d42e7dSPeter Dunlap idm_so_buf_setup(idm_buf_t *idb) 2432a6d42e7dSPeter Dunlap { 243330e7468fSPeter Dunlap /* Ensure bufalloc'd flag is unset */ 243430e7468fSPeter Dunlap idb->idb_bufalloc = B_FALSE; 243530e7468fSPeter Dunlap 2436a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 2437a6d42e7dSPeter Dunlap } 2438a6d42e7dSPeter Dunlap 2439a6d42e7dSPeter Dunlap /* ARGSUSED */ 2440a6d42e7dSPeter Dunlap static void 2441a6d42e7dSPeter Dunlap idm_so_buf_teardown(idm_buf_t *idb) 2442a6d42e7dSPeter Dunlap { 2443a6d42e7dSPeter Dunlap /* nothing to do here */ 2444a6d42e7dSPeter Dunlap } 2445a6d42e7dSPeter Dunlap 2446a6d42e7dSPeter Dunlap static void 2447a6d42e7dSPeter Dunlap idm_so_buf_free(idm_buf_t *idb) 2448a6d42e7dSPeter Dunlap { 2449cf8c0ebaSPeter Dunlap if (idb->idb_buf_private == NULL) { 2450cf8c0ebaSPeter Dunlap kmem_free(idb->idb_buf, idb->idb_buflen); 2451cf8c0ebaSPeter Dunlap } else { 2452cf8c0ebaSPeter Dunlap kmem_cache_free(idb->idb_buf_private, idb->idb_buf); 2453cf8c0ebaSPeter Dunlap } 2454a6d42e7dSPeter Dunlap } 2455a6d42e7dSPeter Dunlap 245630e7468fSPeter Dunlap static void 245730e7468fSPeter Dunlap idm_so_send_rtt_data(idm_conn_t *ic, idm_task_t *idt, idm_buf_t *idb, 245830e7468fSPeter Dunlap uint32_t offset, uint32_t length) 245930e7468fSPeter Dunlap { 246030e7468fSPeter Dunlap idm_so_conn_t *so_conn = ic->ic_transport_private; 246130e7468fSPeter Dunlap idm_pdu_t tmppdu; 246230e7468fSPeter Dunlap idm_buf_t *rtt_buf; 246330e7468fSPeter Dunlap 246430e7468fSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 246530e7468fSPeter Dunlap 246630e7468fSPeter Dunlap /* 246730e7468fSPeter Dunlap * Allocate a buffer to represent the RTT transfer. We could further 246830e7468fSPeter Dunlap * optimize this by allocating the buffers internally from an rtt 246930e7468fSPeter Dunlap * specific buffer cache since this is socket-specific code but for 247030e7468fSPeter Dunlap * now we will keep it simple. 247130e7468fSPeter Dunlap */ 247230e7468fSPeter Dunlap rtt_buf = idm_buf_alloc(ic, (uint8_t *)idb->idb_buf + offset, length); 247330e7468fSPeter Dunlap if (rtt_buf == NULL) { 247430e7468fSPeter Dunlap /* 247530e7468fSPeter Dunlap * If we're in FFP then the failure was likely a resource 247630e7468fSPeter Dunlap * allocation issue and we should close the connection by 247730e7468fSPeter Dunlap * sending a CE_TRANSPORT_FAIL event. 247830e7468fSPeter Dunlap * 247930e7468fSPeter Dunlap * If we're not in FFP then idm_buf_alloc will always 248030e7468fSPeter Dunlap * fail and the state is transitioning to "complete" anyway 248130e7468fSPeter Dunlap * so we won't bother to send an event. 248230e7468fSPeter Dunlap */ 248330e7468fSPeter Dunlap mutex_enter(&ic->ic_state_mutex); 248430e7468fSPeter Dunlap if (ic->ic_ffp) 248530e7468fSPeter Dunlap idm_conn_event_locked(ic, CE_TRANSPORT_FAIL, 248630e7468fSPeter Dunlap NULL, CT_NONE); 248730e7468fSPeter Dunlap mutex_exit(&ic->ic_state_mutex); 248830e7468fSPeter Dunlap return; 248930e7468fSPeter Dunlap } 249030e7468fSPeter Dunlap 249130e7468fSPeter Dunlap rtt_buf->idb_buf_cb = NULL; 249230e7468fSPeter Dunlap rtt_buf->idb_cb_arg = NULL; 249330e7468fSPeter Dunlap rtt_buf->idb_bufoffset = offset; 249430e7468fSPeter Dunlap rtt_buf->idb_xfer_len = length; 249530e7468fSPeter Dunlap rtt_buf->idb_ic = idt->idt_ic; 249630e7468fSPeter Dunlap rtt_buf->idb_task_binding = idt; 249730e7468fSPeter Dunlap 249830e7468fSPeter Dunlap /* 249930e7468fSPeter Dunlap * Put the idm_buf_t on the tx queue. It will be transmitted by 250030e7468fSPeter Dunlap * idm_sotx_thread. 250130e7468fSPeter Dunlap */ 250230e7468fSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 250330e7468fSPeter Dunlap 250430e7468fSPeter Dunlap if (!so_conn->ic_tx_thread_running) { 250530e7468fSPeter Dunlap idm_buf_free(rtt_buf); 250630e7468fSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 250730e7468fSPeter Dunlap return; 250830e7468fSPeter Dunlap } 250930e7468fSPeter Dunlap 251030e7468fSPeter Dunlap /* 251130e7468fSPeter Dunlap * This new buffer represents an additional reference on the task 251230e7468fSPeter Dunlap */ 251330e7468fSPeter Dunlap idm_task_hold(idt); 251430e7468fSPeter Dunlap 251530e7468fSPeter Dunlap /* 251630e7468fSPeter Dunlap * Build a template for the data PDU headers we will use so that 251730e7468fSPeter Dunlap * the SN values will stay consistent with other PDU's we are 251830e7468fSPeter Dunlap * transmitting like R2T and SCSI status. 251930e7468fSPeter Dunlap */ 252030e7468fSPeter Dunlap bzero(&rtt_buf->idb_data_hdr_tmpl, sizeof (iscsi_hdr_t)); 252130e7468fSPeter Dunlap tmppdu.isp_hdr = &rtt_buf->idb_data_hdr_tmpl; 252230e7468fSPeter Dunlap (*idt->idt_ic->ic_conn_ops.icb_build_hdr)(idt, &tmppdu, 252330e7468fSPeter Dunlap ISCSI_OP_SCSI_DATA); 252430e7468fSPeter Dunlap rtt_buf->idb_tx_thread = B_TRUE; 252530e7468fSPeter Dunlap rtt_buf->idb_in_transport = B_TRUE; 252630e7468fSPeter Dunlap list_insert_tail(&so_conn->ic_tx_list, (void *)rtt_buf); 252730e7468fSPeter Dunlap cv_signal(&so_conn->ic_tx_cv); 252830e7468fSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 252930e7468fSPeter Dunlap } 253030e7468fSPeter Dunlap 253130e7468fSPeter Dunlap static void 253230e7468fSPeter Dunlap idm_so_send_rtt_data_done(idm_task_t *idt, idm_buf_t *idb) 253330e7468fSPeter Dunlap { 253430e7468fSPeter Dunlap /* 253530e7468fSPeter Dunlap * Don't worry about status -- we assume any error handling 253630e7468fSPeter Dunlap * is performed by the caller (idm_sotx_thread). 253730e7468fSPeter Dunlap */ 253830e7468fSPeter Dunlap idb->idb_in_transport = B_FALSE; 253930e7468fSPeter Dunlap idm_task_rele(idt); 254030e7468fSPeter Dunlap idm_buf_free(idb); 254130e7468fSPeter Dunlap } 254230e7468fSPeter Dunlap 254330e7468fSPeter Dunlap static idm_status_t 254430e7468fSPeter Dunlap idm_so_send_buf_region(idm_task_t *idt, idm_buf_t *idb, 2545a6d42e7dSPeter Dunlap uint32_t buf_region_offset, uint32_t buf_region_length) 2546a6d42e7dSPeter Dunlap { 2547a6d42e7dSPeter Dunlap idm_conn_t *ic; 2548a6d42e7dSPeter Dunlap uint32_t max_dataseglen; 2549a6d42e7dSPeter Dunlap size_t remainder, chunk; 2550a6d42e7dSPeter Dunlap uint32_t data_offset = buf_region_offset; 2551a6d42e7dSPeter Dunlap iscsi_data_hdr_t *bhs; 2552a6d42e7dSPeter Dunlap idm_pdu_t *pdu; 255330e7468fSPeter Dunlap idm_status_t tx_status; 2554a6d42e7dSPeter Dunlap 2555a6d42e7dSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex)); 2556a6d42e7dSPeter Dunlap 2557a6d42e7dSPeter Dunlap ic = idt->idt_ic; 2558a6d42e7dSPeter Dunlap 2559*56261083SCharles Ting max_dataseglen = ic->ic_conn_params.max_xmit_dataseglen; 2560a6d42e7dSPeter Dunlap remainder = buf_region_length; 2561a6d42e7dSPeter Dunlap 2562a6d42e7dSPeter Dunlap while (remainder) { 2563a6d42e7dSPeter Dunlap if (idt->idt_state != TASK_ACTIVE) { 2564a6d42e7dSPeter Dunlap ASSERT((idt->idt_state != TASK_IDLE) && 2565a6d42e7dSPeter Dunlap (idt->idt_state != TASK_COMPLETE)); 2566a6d42e7dSPeter Dunlap return (IDM_STATUS_ABORTED); 2567a6d42e7dSPeter Dunlap } 2568a6d42e7dSPeter Dunlap 2569a6d42e7dSPeter Dunlap /* check to see if we need to chunk the data */ 2570a6d42e7dSPeter Dunlap if (remainder > max_dataseglen) { 2571a6d42e7dSPeter Dunlap chunk = max_dataseglen; 2572a6d42e7dSPeter Dunlap } else { 2573a6d42e7dSPeter Dunlap chunk = remainder; 2574a6d42e7dSPeter Dunlap } 2575a6d42e7dSPeter Dunlap 2576a6d42e7dSPeter Dunlap /* Data PDU headers will always be sizeof (iscsi_hdr_t) */ 2577a6d42e7dSPeter Dunlap pdu = kmem_cache_alloc(idm.idm_sotx_pdu_cache, KM_SLEEP); 2578a6d42e7dSPeter Dunlap pdu->isp_ic = ic; 2579a6d42e7dSPeter Dunlap 2580a6d42e7dSPeter Dunlap /* 258130e7468fSPeter Dunlap * We've already built a build a header template 2582a6d42e7dSPeter Dunlap * to use during the transfer. Use this template so that 2583a6d42e7dSPeter Dunlap * the SN values stay consistent with any unrelated PDU's 2584a6d42e7dSPeter Dunlap * being transmitted. 2585a6d42e7dSPeter Dunlap */ 258630e7468fSPeter Dunlap bcopy(&idb->idb_data_hdr_tmpl, pdu->isp_hdr, 258730e7468fSPeter Dunlap sizeof (iscsi_hdr_t)); 2588a6d42e7dSPeter Dunlap 2589a6d42e7dSPeter Dunlap /* 2590a6d42e7dSPeter Dunlap * Set DataSN, data offset, and flags in BHS 2591a6d42e7dSPeter Dunlap * For the prototype build, A = 0, S = 0, U = 0 2592a6d42e7dSPeter Dunlap */ 2593a6d42e7dSPeter Dunlap bhs = (iscsi_data_hdr_t *)(pdu->isp_hdr); 2594a6d42e7dSPeter Dunlap 2595a6d42e7dSPeter Dunlap bhs->datasn = htonl(idt->idt_exp_datasn++); 2596a6d42e7dSPeter Dunlap 2597a6d42e7dSPeter Dunlap hton24(bhs->dlength, chunk); 2598a6d42e7dSPeter Dunlap bhs->offset = htonl(idb->idb_bufoffset + data_offset); 2599a6d42e7dSPeter Dunlap 2600a6d42e7dSPeter Dunlap if (chunk == remainder) { 2601a6d42e7dSPeter Dunlap bhs->flags = ISCSI_FLAG_FINAL; /* F bit set to 1 */ 2602a6d42e7dSPeter Dunlap } 2603a6d42e7dSPeter Dunlap 2604a668b114SPriya Krishnan /* Instrument the data-send DTrace probe. */ 2605a668b114SPriya Krishnan if (IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA_RSP) { 2606a668b114SPriya Krishnan DTRACE_ISCSI_2(data__send, 2607a668b114SPriya Krishnan idm_conn_t *, idt->idt_ic, 2608a668b114SPriya Krishnan iscsi_data_rsp_hdr_t *, 2609a668b114SPriya Krishnan (iscsi_data_rsp_hdr_t *)pdu->isp_hdr); 2610a668b114SPriya Krishnan } 2611a6d42e7dSPeter Dunlap /* setup data */ 2612a6d42e7dSPeter Dunlap pdu->isp_data = (uint8_t *)idb->idb_buf + data_offset; 2613a6d42e7dSPeter Dunlap pdu->isp_datalen = (uint_t)chunk; 2614a6d42e7dSPeter Dunlap remainder -= chunk; 2615a6d42e7dSPeter Dunlap data_offset += chunk; 2616a6d42e7dSPeter Dunlap 2617a6d42e7dSPeter Dunlap /* 2618a6d42e7dSPeter Dunlap * Now that we're done working with idt_exp_datasn, 2619a6d42e7dSPeter Dunlap * idt->idt_state and idb->idb_bufoffset we can release 2620a6d42e7dSPeter Dunlap * the task lock -- don't want to hold it across the 2621a6d42e7dSPeter Dunlap * call to idm_i_so_tx since we could block. 2622a6d42e7dSPeter Dunlap */ 2623a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex); 2624a6d42e7dSPeter Dunlap 2625a6d42e7dSPeter Dunlap /* 2626a6d42e7dSPeter Dunlap * Transmit the PDU. Call the internal routine directly 2627a6d42e7dSPeter Dunlap * as there is already implicit ordering. 2628a6d42e7dSPeter Dunlap */ 262930e7468fSPeter Dunlap if ((tx_status = idm_i_so_tx(pdu)) != IDM_STATUS_SUCCESS) { 263030e7468fSPeter Dunlap mutex_enter(&idt->idt_mutex); 263130e7468fSPeter Dunlap return (tx_status); 263230e7468fSPeter Dunlap } 2633a6d42e7dSPeter Dunlap 2634a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 263530e7468fSPeter Dunlap idt->idt_tx_bytes += chunk; 2636a6d42e7dSPeter Dunlap } 2637a6d42e7dSPeter Dunlap 2638a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 2639a6d42e7dSPeter Dunlap } 2640a6d42e7dSPeter Dunlap 2641a6d42e7dSPeter Dunlap /* 2642a6d42e7dSPeter Dunlap * TX PDU cache 2643a6d42e7dSPeter Dunlap */ 2644a6d42e7dSPeter Dunlap /* ARGSUSED */ 2645a6d42e7dSPeter Dunlap int 2646a6d42e7dSPeter Dunlap idm_sotx_pdu_constructor(void *hdl, void *arg, int flags) 2647a6d42e7dSPeter Dunlap { 2648a6d42e7dSPeter Dunlap idm_pdu_t *pdu = hdl; 2649a6d42e7dSPeter Dunlap 2650a6d42e7dSPeter Dunlap bzero(pdu, sizeof (idm_pdu_t)); 2651a6d42e7dSPeter Dunlap pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); /* Ptr arithmetic */ 2652a6d42e7dSPeter Dunlap pdu->isp_hdrlen = sizeof (iscsi_hdr_t); 2653a6d42e7dSPeter Dunlap pdu->isp_callback = idm_sotx_cache_pdu_cb; 2654a6d42e7dSPeter Dunlap pdu->isp_magic = IDM_PDU_MAGIC; 2655a6d42e7dSPeter Dunlap bzero(pdu->isp_hdr, sizeof (iscsi_hdr_t)); 2656a6d42e7dSPeter Dunlap 2657a6d42e7dSPeter Dunlap return (0); 2658a6d42e7dSPeter Dunlap } 2659a6d42e7dSPeter Dunlap 2660a6d42e7dSPeter Dunlap /* ARGSUSED */ 2661a6d42e7dSPeter Dunlap void 2662a6d42e7dSPeter Dunlap idm_sotx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status) 2663a6d42e7dSPeter Dunlap { 2664a6d42e7dSPeter Dunlap /* reset values between use */ 2665a6d42e7dSPeter Dunlap pdu->isp_datalen = 0; 2666a6d42e7dSPeter Dunlap 2667a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_sotx_pdu_cache, pdu); 2668a6d42e7dSPeter Dunlap } 2669a6d42e7dSPeter Dunlap 2670a6d42e7dSPeter Dunlap /* 2671a6d42e7dSPeter Dunlap * RX PDU cache 2672a6d42e7dSPeter Dunlap */ 2673a6d42e7dSPeter Dunlap /* ARGSUSED */ 2674a6d42e7dSPeter Dunlap int 2675a6d42e7dSPeter Dunlap idm_sorx_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_magic = IDM_PDU_MAGIC; 2681a6d42e7dSPeter Dunlap pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); /* Ptr arithmetic */ 2682a6d42e7dSPeter Dunlap pdu->isp_callback = idm_sorx_cache_pdu_cb; 2683a6d42e7dSPeter Dunlap 2684a6d42e7dSPeter Dunlap return (0); 2685a6d42e7dSPeter Dunlap } 2686a6d42e7dSPeter Dunlap 2687a6d42e7dSPeter Dunlap /* ARGSUSED */ 2688a6d42e7dSPeter Dunlap static void 2689a6d42e7dSPeter Dunlap idm_sorx_cache_pdu_cb(idm_pdu_t *pdu, idm_status_t status) 2690a6d42e7dSPeter Dunlap { 2691a6d42e7dSPeter Dunlap pdu->isp_iovlen = 0; 2692a6d42e7dSPeter Dunlap pdu->isp_sorx_buf = 0; 2693a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_sorx_pdu_cache, pdu); 2694a6d42e7dSPeter Dunlap } 2695a6d42e7dSPeter Dunlap 2696a6d42e7dSPeter Dunlap static void 2697a6d42e7dSPeter Dunlap idm_sorx_addl_pdu_cb(idm_pdu_t *pdu, idm_status_t status) 2698a6d42e7dSPeter Dunlap { 2699a6d42e7dSPeter Dunlap /* 2700a6d42e7dSPeter Dunlap * We had to modify our cached RX PDU with a longer header buffer 2701a6d42e7dSPeter Dunlap * and/or a longer data buffer. Release the new buffers and fix 2702a6d42e7dSPeter Dunlap * the fields back to what we would expect for a cached RX PDU. 2703a6d42e7dSPeter Dunlap */ 2704a6d42e7dSPeter Dunlap if (pdu->isp_flags & IDM_PDU_ADDL_HDR) { 2705a6d42e7dSPeter Dunlap kmem_free(pdu->isp_hdr, pdu->isp_hdrlen); 2706a6d42e7dSPeter Dunlap } 2707a6d42e7dSPeter Dunlap if (pdu->isp_flags & IDM_PDU_ADDL_DATA) { 2708a6d42e7dSPeter Dunlap kmem_free(pdu->isp_data, pdu->isp_datalen); 2709a6d42e7dSPeter Dunlap } 2710a6d42e7dSPeter Dunlap pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); 2711a6d42e7dSPeter Dunlap pdu->isp_hdrlen = sizeof (iscsi_hdr_t); 2712a6d42e7dSPeter Dunlap pdu->isp_data = NULL; 2713a6d42e7dSPeter Dunlap pdu->isp_datalen = 0; 2714a6d42e7dSPeter Dunlap pdu->isp_sorx_buf = 0; 2715a6d42e7dSPeter Dunlap pdu->isp_callback = idm_sorx_cache_pdu_cb; 2716a6d42e7dSPeter Dunlap idm_sorx_cache_pdu_cb(pdu, status); 2717a6d42e7dSPeter Dunlap } 2718a6d42e7dSPeter Dunlap 2719a6d42e7dSPeter Dunlap /* 2720a6d42e7dSPeter Dunlap * This thread is only active when I/O is queued for transmit 2721a6d42e7dSPeter Dunlap * because the socket is busy. 2722a6d42e7dSPeter Dunlap */ 2723a6d42e7dSPeter Dunlap void 2724a6d42e7dSPeter Dunlap idm_sotx_thread(void *arg) 2725a6d42e7dSPeter Dunlap { 2726a6d42e7dSPeter Dunlap idm_conn_t *ic = arg; 2727a6d42e7dSPeter Dunlap idm_tx_obj_t *object, *next; 2728a6d42e7dSPeter Dunlap idm_so_conn_t *so_conn; 2729a6d42e7dSPeter Dunlap idm_status_t status = IDM_STATUS_SUCCESS; 2730a6d42e7dSPeter Dunlap 2731a6d42e7dSPeter Dunlap idm_conn_hold(ic); 2732a6d42e7dSPeter Dunlap 2733a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_mutex); 2734a6d42e7dSPeter Dunlap so_conn = ic->ic_transport_private; 2735a6d42e7dSPeter Dunlap so_conn->ic_tx_thread_running = B_TRUE; 2736a6d42e7dSPeter Dunlap so_conn->ic_tx_thread_did = so_conn->ic_tx_thread->t_did; 2737a6d42e7dSPeter Dunlap cv_signal(&ic->ic_cv); 2738a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_mutex); 2739a6d42e7dSPeter Dunlap 2740a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2741a6d42e7dSPeter Dunlap 2742a6d42e7dSPeter Dunlap while (so_conn->ic_tx_thread_running) { 2743a6d42e7dSPeter Dunlap while (list_is_empty(&so_conn->ic_tx_list)) { 2744a6d42e7dSPeter Dunlap DTRACE_PROBE1(soconn__tx__sleep, idm_conn_t *, ic); 2745a6d42e7dSPeter Dunlap cv_wait(&so_conn->ic_tx_cv, &so_conn->ic_tx_mutex); 2746a6d42e7dSPeter Dunlap DTRACE_PROBE1(soconn__tx__wakeup, idm_conn_t *, ic); 2747a6d42e7dSPeter Dunlap 2748a6d42e7dSPeter Dunlap if (!so_conn->ic_tx_thread_running) { 2749a6d42e7dSPeter Dunlap goto tx_bail; 2750a6d42e7dSPeter Dunlap } 2751a6d42e7dSPeter Dunlap } 2752a6d42e7dSPeter Dunlap 2753a6d42e7dSPeter Dunlap object = (idm_tx_obj_t *)list_head(&so_conn->ic_tx_list); 2754a6d42e7dSPeter Dunlap list_remove(&so_conn->ic_tx_list, object); 2755a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2756a6d42e7dSPeter Dunlap 2757a6d42e7dSPeter Dunlap switch (object->idm_tx_obj_magic) { 2758a6d42e7dSPeter Dunlap case IDM_PDU_MAGIC: 2759a6d42e7dSPeter Dunlap DTRACE_PROBE2(soconn__tx__pdu, idm_conn_t *, ic, 2760a6d42e7dSPeter Dunlap idm_pdu_t *, (idm_pdu_t *)object); 2761a6d42e7dSPeter Dunlap 2762a6d42e7dSPeter Dunlap status = idm_i_so_tx((idm_pdu_t *)object); 2763a6d42e7dSPeter Dunlap break; 2764a6d42e7dSPeter Dunlap 2765a6d42e7dSPeter Dunlap case IDM_BUF_MAGIC: { 2766a6d42e7dSPeter Dunlap idm_buf_t *idb = (idm_buf_t *)object; 2767a6d42e7dSPeter Dunlap idm_task_t *idt = idb->idb_task_binding; 2768a6d42e7dSPeter Dunlap 2769a6d42e7dSPeter Dunlap DTRACE_PROBE2(soconn__tx__buf, idm_conn_t *, ic, 2770a6d42e7dSPeter Dunlap idm_buf_t *, idb); 2771a6d42e7dSPeter Dunlap 2772a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 2773a6d42e7dSPeter Dunlap status = idm_so_send_buf_region(idt, 277430e7468fSPeter Dunlap idb, 0, idb->idb_xfer_len); 2775a6d42e7dSPeter Dunlap 2776a6d42e7dSPeter Dunlap /* 2777a6d42e7dSPeter Dunlap * TX thread owns the buffer so we expect it to 2778a6d42e7dSPeter Dunlap * be "in transport" 2779a6d42e7dSPeter Dunlap */ 2780a6d42e7dSPeter Dunlap ASSERT(idb->idb_in_transport); 278130e7468fSPeter Dunlap if (IDM_CONN_ISTGT(ic)) { 278230e7468fSPeter Dunlap /* 278330e7468fSPeter Dunlap * idm_buf_tx_to_ini_done releases 278430e7468fSPeter Dunlap * idt->idt_mutex 278530e7468fSPeter Dunlap */ 2786a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, 2787a668b114SPriya Krishnan idm_conn_t *, idt->idt_ic, 2788a668b114SPriya Krishnan uintptr_t, idb->idb_buf, 2789a668b114SPriya Krishnan uint32_t, idb->idb_bufoffset, 2790a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 2791a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 2792a668b114SPriya Krishnan int, XFER_BUF_TX_TO_INI); 279330e7468fSPeter Dunlap idm_buf_tx_to_ini_done(idt, idb, status); 279430e7468fSPeter Dunlap } else { 279530e7468fSPeter Dunlap idm_so_send_rtt_data_done(idt, idb); 279630e7468fSPeter Dunlap mutex_exit(&idt->idt_mutex); 279730e7468fSPeter Dunlap } 2798a6d42e7dSPeter Dunlap break; 2799a6d42e7dSPeter Dunlap } 2800a6d42e7dSPeter Dunlap 2801a6d42e7dSPeter Dunlap default: 2802a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_sotx_thread: Unknown magic " 2803a6d42e7dSPeter Dunlap "(0x%08x)", object->idm_tx_obj_magic); 2804a6d42e7dSPeter Dunlap status = IDM_STATUS_FAIL; 2805a6d42e7dSPeter Dunlap } 2806a6d42e7dSPeter Dunlap 2807a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2808a6d42e7dSPeter Dunlap 2809a6d42e7dSPeter Dunlap if (status != IDM_STATUS_SUCCESS) { 2810a6d42e7dSPeter Dunlap so_conn->ic_tx_thread_running = B_FALSE; 2811a6d42e7dSPeter Dunlap idm_conn_event(ic, CE_TRANSPORT_FAIL, status); 2812a6d42e7dSPeter Dunlap } 2813a6d42e7dSPeter Dunlap } 2814a6d42e7dSPeter Dunlap 2815a6d42e7dSPeter Dunlap /* 2816a6d42e7dSPeter Dunlap * Before we leave, we need to abort every item remaining in the 2817a6d42e7dSPeter Dunlap * TX list. 2818a6d42e7dSPeter Dunlap */ 2819a6d42e7dSPeter Dunlap 2820a6d42e7dSPeter Dunlap tx_bail: 2821a6d42e7dSPeter Dunlap object = (idm_tx_obj_t *)list_head(&so_conn->ic_tx_list); 2822a6d42e7dSPeter Dunlap 2823a6d42e7dSPeter Dunlap while (object != NULL) { 2824a6d42e7dSPeter Dunlap next = list_next(&so_conn->ic_tx_list, object); 2825a6d42e7dSPeter Dunlap 2826a6d42e7dSPeter Dunlap list_remove(&so_conn->ic_tx_list, object); 2827a6d42e7dSPeter Dunlap switch (object->idm_tx_obj_magic) { 2828a6d42e7dSPeter Dunlap case IDM_PDU_MAGIC: 2829a6d42e7dSPeter Dunlap idm_pdu_complete((idm_pdu_t *)object, 2830a6d42e7dSPeter Dunlap IDM_STATUS_ABORTED); 2831a6d42e7dSPeter Dunlap break; 2832a6d42e7dSPeter Dunlap 2833a6d42e7dSPeter Dunlap case IDM_BUF_MAGIC: { 2834a6d42e7dSPeter Dunlap idm_buf_t *idb = (idm_buf_t *)object; 2835a6d42e7dSPeter Dunlap idm_task_t *idt = idb->idb_task_binding; 2836a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2837a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex); 2838a6d42e7dSPeter Dunlap /* 2839a6d42e7dSPeter Dunlap * TX thread owns the buffer so we expect it to 2840a6d42e7dSPeter Dunlap * be "in transport" 2841a6d42e7dSPeter Dunlap */ 2842a6d42e7dSPeter Dunlap ASSERT(idb->idb_in_transport); 284330e7468fSPeter Dunlap if (IDM_CONN_ISTGT(ic)) { 284430e7468fSPeter Dunlap /* 284530e7468fSPeter Dunlap * idm_buf_tx_to_ini_done releases 284630e7468fSPeter Dunlap * idt->idt_mutex 284730e7468fSPeter Dunlap */ 2848a668b114SPriya Krishnan DTRACE_ISCSI_8(xfer__done, 2849a668b114SPriya Krishnan idm_conn_t *, idt->idt_ic, 2850a668b114SPriya Krishnan uintptr_t, idb->idb_buf, 2851a668b114SPriya Krishnan uint32_t, idb->idb_bufoffset, 2852a668b114SPriya Krishnan uint64_t, 0, uint32_t, 0, uint32_t, 0, 2853a668b114SPriya Krishnan uint32_t, idb->idb_xfer_len, 2854a668b114SPriya Krishnan int, XFER_BUF_TX_TO_INI); 285530e7468fSPeter Dunlap idm_buf_tx_to_ini_done(idt, idb, 285630e7468fSPeter Dunlap IDM_STATUS_ABORTED); 285730e7468fSPeter Dunlap } else { 285830e7468fSPeter Dunlap idm_so_send_rtt_data_done(idt, idb); 285930e7468fSPeter Dunlap mutex_exit(&idt->idt_mutex); 286030e7468fSPeter Dunlap } 2861a6d42e7dSPeter Dunlap mutex_enter(&so_conn->ic_tx_mutex); 2862a6d42e7dSPeter Dunlap break; 2863a6d42e7dSPeter Dunlap } 2864a6d42e7dSPeter Dunlap default: 2865a6d42e7dSPeter Dunlap IDM_CONN_LOG(CE_WARN, 2866a6d42e7dSPeter Dunlap "idm_sotx_thread: Unexpected magic " 2867a6d42e7dSPeter Dunlap "(0x%08x)", object->idm_tx_obj_magic); 2868a6d42e7dSPeter Dunlap } 2869a6d42e7dSPeter Dunlap 2870a6d42e7dSPeter Dunlap object = next; 2871a6d42e7dSPeter Dunlap } 2872a6d42e7dSPeter Dunlap 2873a6d42e7dSPeter Dunlap mutex_exit(&so_conn->ic_tx_mutex); 2874a6d42e7dSPeter Dunlap idm_conn_rele(ic); 2875a6d42e7dSPeter Dunlap thread_exit(); 2876a6d42e7dSPeter Dunlap /*NOTREACHED*/ 2877a6d42e7dSPeter Dunlap } 2878aff4bce5Syi zhang - Sun Microsystems - Beijing China 2879aff4bce5Syi zhang - Sun Microsystems - Beijing China static void 2880aff4bce5Syi zhang - Sun Microsystems - Beijing China idm_so_socket_set_nonblock(struct sonode *node) 2881aff4bce5Syi zhang - Sun Microsystems - Beijing China { 2882aff4bce5Syi zhang - Sun Microsystems - Beijing China (void) VOP_SETFL(node->so_vnode, node->so_flag, 2883aff4bce5Syi zhang - Sun Microsystems - Beijing China (node->so_state | FNONBLOCK), CRED(), NULL); 2884aff4bce5Syi zhang - Sun Microsystems - Beijing China } 2885aff4bce5Syi zhang - Sun Microsystems - Beijing China 2886aff4bce5Syi zhang - Sun Microsystems - Beijing China static void 2887aff4bce5Syi zhang - Sun Microsystems - Beijing China idm_so_socket_set_block(struct sonode *node) 2888aff4bce5Syi zhang - Sun Microsystems - Beijing China { 2889aff4bce5Syi zhang - Sun Microsystems - Beijing China (void) VOP_SETFL(node->so_vnode, node->so_flag, 2890aff4bce5Syi zhang - Sun Microsystems - Beijing China (node->so_state & (~FNONBLOCK)), CRED(), NULL); 2891aff4bce5Syi zhang - Sun Microsystems - Beijing China } 2892