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