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