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