1 /* $NetBSD: iscsi_send.c,v 1.42 2026/06/06 08:29:08 mlelstv Exp $ */ 2 3 /*- 4 * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Wasabi Systems, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 #include "iscsi_globals.h" 32 33 #include <sys/file.h> 34 #include <sys/filedesc.h> 35 #include <sys/socket.h> 36 #include <sys/socketvar.h> 37 38 /*#define LUN_1 1 */ 39 40 /*****************************************************************************/ 41 42 /* 43 * my_soo_write: 44 * Replacement for soo_write with flag handling. 45 * 46 * Parameter: 47 * conn The connection 48 * u The uio descriptor 49 * 50 * Returns: 0 on success, else EIO. 51 */ 52 53 STATIC int 54 my_soo_write(connection_t *conn, struct uio *u) 55 { 56 struct socket *so; 57 int ret; 58 #ifdef ISCSI_DEBUG 59 size_t resid = u->uio_resid; 60 #endif 61 62 KASSERT(u->uio_resid != 0); 63 64 rw_enter(&conn->c_sock_rw, RW_READER); 65 if (conn->c_sock == NULL) { 66 ret = EIO; 67 } else { 68 so = conn->c_sock->f_socket; 69 ret = (*so->so_send)(so, NULL, u, 70 NULL, NULL, 0, conn->c_threadobj); 71 } 72 rw_exit(&conn->c_sock_rw); 73 74 DEB(99, ("soo_write done: len = %zu\n", u->uio_resid)); 75 76 if (ret != 0 || u->uio_resid) { 77 DEBC(conn, 0, ("Write failed sock %p (ret: %d, req: %zu, resid: %zu)\n", 78 conn->c_sock, ret, resid, u->uio_resid)); 79 handle_connection_error(conn, ISCSI_STATUS_SOCKET_ERROR, NO_LOGOUT); 80 return EIO; 81 } 82 return 0; 83 } 84 85 /*****************************************************************************/ 86 87 /* 88 * assign_connection: 89 * This function returns the connection to use for the next transaction. 90 * 91 * Parameter: The session 92 * 93 * Returns: The connection 94 */ 95 96 connection_t * 97 assign_connection(session_t *sess, bool waitok) 98 { 99 connection_t *conn, *next; 100 101 mutex_enter(&sess->s_lock); 102 do { 103 if (sess->s_terminating || 104 (conn = sess->s_mru_connection) == NULL) { 105 mutex_exit(&sess->s_lock); 106 return NULL; 107 } 108 next = conn; 109 do { 110 next = TAILQ_NEXT(next, c_connections); 111 if (next == NULL) { 112 next = TAILQ_FIRST(&sess->s_conn_list); 113 } 114 } while (next != NULL && next != conn && 115 next->c_state != ST_FULL_FEATURE); 116 117 if (next->c_state != ST_FULL_FEATURE) { 118 if (waitok) { 119 cv_wait(&sess->s_sess_cv, &sess->s_lock); 120 next = TAILQ_FIRST(&sess->s_conn_list); 121 } else { 122 mutex_exit(&sess->s_lock); 123 return NULL; 124 } 125 } else { 126 sess->s_mru_connection = next; 127 } 128 } while (next != NULL && next->c_state != ST_FULL_FEATURE); 129 mutex_exit(&sess->s_lock); 130 131 return next; 132 } 133 134 135 /* 136 * reassign_tasks: 137 * Reassign pending commands to one of the still existing connections 138 * of a session. 139 * 140 * Parameter: 141 * oldconn The terminating connection 142 */ 143 144 STATIC void 145 reassign_tasks(connection_t *oldconn) 146 { 147 session_t *sess = oldconn->c_session; 148 connection_t *conn; 149 ccb_t *ccb; 150 ccb_list_t old_waiting; 151 pdu_t *pdu = NULL; 152 pdu_t *opdu; 153 int no_tm = 1; 154 int rc = 1; 155 uint32_t sn; 156 157 if ((conn = assign_connection(sess, FALSE)) == NULL) { 158 DEB(1, ("Reassign_tasks of Session %d, connection %d failed, " 159 "no active connection\n", 160 sess->s_id, oldconn->c_id)); 161 /* XXX here we need to abort the waiting CCBs */ 162 return; 163 } 164 165 TAILQ_INIT(&old_waiting); 166 167 mutex_enter(&oldconn->c_lock); 168 169 if (sess->s_ErrorRecoveryLevel >= 2) { 170 if (oldconn->c_loggedout == NOT_LOGGED_OUT) { 171 oldconn->c_loggedout = LOGOUT_SENT; 172 no_tm = send_logout(conn, oldconn, RECOVER_CONNECTION, TRUE); 173 oldconn->c_loggedout = (rc) ? LOGOUT_FAILED : LOGOUT_SUCCESS; 174 if (!oldconn->c_Time2Retain) { 175 DEBC(conn, 1, ("Time2Retain is zero, setting no_tm\n")); 176 no_tm = 1; 177 } 178 } else if (oldconn->c_loggedout == LOGOUT_SUCCESS) { 179 no_tm = 0; 180 } 181 if (!no_tm && oldconn->c_Time2Wait) { 182 DEBC(conn, 1, ("Time2Wait=%d, hz=%d, waiting...\n", 183 oldconn->c_Time2Wait, hz)); 184 kpause("Time2Wait", false, oldconn->c_Time2Wait * hz, &oldconn->c_lock); 185 } 186 } 187 188 while ((ccb = TAILQ_FIRST(&oldconn->c_ccbs_waiting)) != NULL) { 189 suspend_ccb(ccb, FALSE); 190 TAILQ_INSERT_TAIL(&old_waiting, ccb, ccb_chain); 191 } 192 193 mutex_exit(&oldconn->c_lock); 194 195 DEBC(conn, 1, ("Reassign_tasks: S%dC%d -> S%dC%d, no_tm=%d, pdus old %d + new %d\n", 196 sess->s_id, oldconn->c_id, sess->s_id, conn->c_id, no_tm, 197 oldconn->c_pducount, conn->c_pducount)); 198 199 /* XXX reassign waiting CCBs to new connection */ 200 201 while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) { 202 /* Copy PDU contents (PDUs are bound to connection) */ 203 if ((pdu = get_pdu(conn, TRUE)) == NULL) { 204 DEBC(conn, 0, ("get_pdu failed, terminating=%d\n", conn->c_terminating)); 205 /* new connection is terminating */ 206 break; 207 } 208 209 TAILQ_REMOVE(&old_waiting, ccb, ccb_chain); 210 211 /* adjust CCB and clone PDU for new connection */ 212 213 opdu = ccb->ccb_pdu_waiting; 214 KASSERT((opdu->pdu_flags & PDUF_INQUEUE) == 0); 215 216 *pdu = *opdu; 217 218 /* restore overwritten back ptr */ 219 pdu->pdu_connection = conn; 220 221 /* fixup saved UIO and IOVEC (regular one will be overwritten anyway) */ 222 pdu->pdu_save_uio.uio_iov = pdu->pdu_io_vec; 223 pdu->pdu_save_iovec [0].iov_base = &pdu->pdu_hdr; 224 225 if (conn->c_DataDigest && pdu->pdu_save_uio.uio_iovcnt > 1) { 226 if (pdu->pdu_save_iovec [2].iov_base == NULL) { 227 pdu->pdu_save_iovec [2].iov_base = &pdu->pdu_data_digest; 228 pdu->pdu_save_uio.uio_iovcnt = 3; 229 } else { 230 pdu->pdu_save_iovec [3].iov_base = &pdu->pdu_data_digest; 231 pdu->pdu_save_uio.uio_iovcnt = 4; 232 } 233 } 234 pdu->pdu_save_iovec [0].iov_len = 235 (conn->c_HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE; 236 237 /* link new PDU into old CCB */ 238 ccb->ccb_pdu_waiting = pdu; 239 /* link new CCB into new connection */ 240 ccb->ccb_connection = conn; 241 /* reset timeouts */ 242 ccb->ccb_num_timeouts = 0; 243 244 DEBC(conn, 1, ("CCB %p: Copied PDU %p to %p\n", 245 ccb, opdu, pdu)); 246 247 /* kill temp pointer that is now referenced by the new PDU */ 248 opdu->pdu_temp_data = NULL; 249 250 /* and free the old PDU */ 251 free_pdu(opdu); 252 253 mutex_enter(&conn->c_lock); 254 255 /* fixup reference counts */ 256 mutex_enter(&oldconn->c_lock); 257 oldconn->c_usecount--; 258 conn->c_usecount++; 259 mutex_exit(&oldconn->c_lock); 260 261 /* put ready CCB into waiting list of new connection */ 262 suspend_ccb(ccb, TRUE); 263 264 mutex_exit(&conn->c_lock); 265 } 266 267 if (TAILQ_FIRST(&old_waiting) != NULL) { 268 DEBC(conn, 0, ("Error while copying PDUs in reassign_tasks!\n")); 269 /* 270 * give up recovering, the other connection is screwed up 271 * as well... 272 */ 273 274 while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) { 275 TAILQ_REMOVE(&old_waiting, ccb, ccb_chain); 276 277 DEBC(oldconn, 1, ("Wake CCB %p for connection %d, terminating %d\n", 278 ccb, ccb->ccb_connection->c_id, oldconn->c_terminating)); 279 mutex_enter(&oldconn->c_lock); 280 suspend_ccb(ccb, TRUE); 281 mutex_exit(&oldconn->c_lock); 282 wake_ccb(ccb, oldconn->c_terminating); 283 } 284 285 return; 286 } 287 288 TAILQ_FOREACH(ccb, &conn->c_ccbs_waiting, ccb_chain) { 289 if (!no_tm) { 290 rc = send_task_management(conn, ccb, NULL, TASK_REASSIGN); 291 } 292 /* if we get an error on reassign, restart the original request */ 293 if (no_tm || rc) { 294 mutex_enter(&sess->s_lock); 295 if (ccb->ccb_CmdSN < sess->s_ExpCmdSN) { 296 pdu = ccb->ccb_pdu_waiting; 297 sn = get_sernum(sess, pdu); 298 299 /* update CmdSN */ 300 DEBC(conn, 1, ("Resend Updating CmdSN - old %d, new %d\n", 301 ccb->ccb_CmdSN, sn)); 302 ccb->ccb_CmdSN = sn; 303 pdu->pdu_hdr.pduh_p.command.CmdSN = htonl(ccb->ccb_CmdSN); 304 } 305 mutex_exit(&sess->s_lock); 306 resend_pdu(ccb); 307 } else { 308 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 309 } 310 DEBC(conn, 1, ("Reassign ccb %p, no_tm=%d, rc=%d\n", 311 ccb, no_tm, rc)); 312 } 313 } 314 315 316 /* 317 * iscsi_send_thread: 318 * This thread services the send queue, writing the PDUs to the socket. 319 * It also handles the cleanup when the connection is terminated. 320 * 321 * Parameter: 322 * par The connection this thread services 323 */ 324 325 void 326 iscsi_send_thread(void *par) 327 { 328 connection_t *conn = (connection_t *) par; 329 session_t *sess; 330 ccb_t *ccb, *nccb; 331 pdu_t *pdu; 332 struct file *fp; 333 pdu_disp_t pdisp; 334 335 sess = conn->c_session; 336 /* so cleanup thread knows there's someone left */ 337 iscsi_num_send_threads++; 338 339 do { 340 mutex_enter(&conn->c_lock); 341 while (!conn->c_terminating) { 342 while (!conn->c_terminating && 343 (pdu = TAILQ_FIRST(&conn->c_pdus_to_send)) != NULL) { 344 TAILQ_REMOVE(&conn->c_pdus_to_send, pdu, pdu_send_chain); 345 pdu->pdu_flags &= ~PDUF_INQUEUE; 346 pdisp = pdu->pdu_disp; 347 if (pdisp > PDUDISP_FREE) 348 pdu->pdu_flags &= ~PDUF_BUSY; 349 mutex_exit(&conn->c_lock); 350 351 /* update ExpStatSN here to avoid discontinuities */ 352 /* and delays in updating target */ 353 pdu->pdu_hdr.pduh_p.command.ExpStatSN = htonl(conn->c_StatSN_buf.ExpSN); 354 355 if (conn->c_HeaderDigest) 356 pdu->pdu_hdr.pduh_HeaderDigest = gen_digest(&pdu->pdu_hdr, BHS_SIZE); 357 358 DEBC(conn, 99, ("Transmitting PDU CmdSN = %u, ExpStatSN = %u\n", 359 ntohl(pdu->pdu_hdr.pduh_p.command.CmdSN), 360 ntohl(pdu->pdu_hdr.pduh_p.command.ExpStatSN))); 361 my_soo_write(conn, &pdu->pdu_uio); 362 363 if (pdisp <= PDUDISP_FREE) 364 free_pdu(pdu); 365 366 mutex_enter(&conn->c_lock); 367 } 368 369 if (!conn->c_terminating) 370 cv_wait(&conn->c_conn_cv, &conn->c_lock); 371 } 372 mutex_exit(&conn->c_lock); 373 374 /* ------------------------------------------------------------------------ 375 * Here this thread takes over cleanup of the terminating connection. 376 * ------------------------------------------------------------------------ 377 */ 378 connection_timeout_stop(conn); 379 conn->c_idle_timeout_val = CONNECTION_IDLE_TIMEOUT; 380 381 fp = conn->c_sock; 382 383 /* 384 * We shutdown the socket here to force the receive 385 * thread to wake up 386 */ 387 DEBC(conn, 1, ("Closing Socket %p\n", conn->c_sock)); 388 solock(fp->f_socket); 389 soshutdown(fp->f_socket, SHUT_RDWR); 390 sounlock(fp->f_socket); 391 392 /* wake up any non-reassignable waiting CCBs */ 393 TAILQ_FOREACH_SAFE(ccb, &conn->c_ccbs_waiting, ccb_chain, nccb) { 394 if (!(ccb->ccb_flags & CCBF_REASSIGN) || ccb->ccb_pdu_waiting == NULL) { 395 DEBC(conn, 1, ("Terminating CCB %p (t=%p)\n", 396 ccb,&ccb->ccb_timeout)); 397 wake_ccb(ccb, conn->c_terminating); 398 } else { 399 ccb_timeout_stop(ccb); 400 ccb->ccb_num_timeouts = 0; 401 } 402 } 403 404 /* clean out anything left in send queue */ 405 mutex_enter(&conn->c_lock); 406 while ((pdu = TAILQ_FIRST(&conn->c_pdus_to_send)) != NULL) { 407 TAILQ_REMOVE(&conn->c_pdus_to_send, pdu, pdu_send_chain); 408 pdu->pdu_flags &= ~(PDUF_INQUEUE | PDUF_BUSY); 409 mutex_exit(&conn->c_lock); 410 /* if it's not attached to a waiting CCB, free it */ 411 if (pdu->pdu_owner == NULL || 412 pdu->pdu_owner->ccb_pdu_waiting != pdu) { 413 free_pdu(pdu); 414 } 415 mutex_enter(&conn->c_lock); 416 } 417 mutex_exit(&conn->c_lock); 418 419 /* If there's another connection available, transfer pending tasks */ 420 if (sess->s_active_connections && 421 TAILQ_FIRST(&conn->c_ccbs_waiting) != NULL) { 422 423 reassign_tasks(conn); 424 } else if (!conn->c_destroy && conn->c_Time2Wait) { 425 DEBC(conn, 1, ("Time2Wait\n")); 426 kpause("Time2Wait", false, conn->c_Time2Wait * hz, NULL); 427 DEBC(conn, 1, ("Time2Wait\n")); 428 } 429 /* notify event handlers of connection shutdown */ 430 DEBC(conn, 1, ("%s\n", conn->c_destroy ? "TERMINATED" : "RECOVER")); 431 add_event(conn->c_destroy ? ISCSI_CONNECTION_TERMINATED 432 : ISCSI_RECOVER_CONNECTION, 433 sess->s_id, conn->c_id, conn->c_terminating); 434 435 DEBC(conn, 1, ("Waiting for conn_idle\n")); 436 mutex_enter(&conn->c_lock); 437 if (!conn->c_destroy) 438 cv_timedwait(&conn->c_idle_cv, &conn->c_lock, CONNECTION_IDLE_TIMEOUT); 439 mutex_exit(&conn->c_lock); 440 DEBC(conn, 1, ("Waited for conn_idle, destroy = %d\n", conn->c_destroy)); 441 442 } while (!conn->c_destroy); 443 444 /* wake up anyone waiting for a PDU */ 445 mutex_enter(&conn->c_lock); 446 cv_broadcast(&conn->c_conn_cv); 447 mutex_exit(&conn->c_lock); 448 449 /* wake up any waiting CCBs */ 450 while ((ccb = TAILQ_FIRST(&conn->c_ccbs_waiting)) != NULL) { 451 KASSERT(ccb->ccb_disp >= CCBDISP_NOWAIT); 452 wake_ccb(ccb, conn->c_terminating); 453 /* NOTE: wake_ccb will remove the CCB from the queue */ 454 } 455 456 add_connection_cleanup(conn); 457 458 conn->c_sendproc = NULL; 459 DEBC(conn, 1, ("Send thread exits\n")); 460 iscsi_num_send_threads--; 461 kthread_exit(0); 462 } 463 464 465 /* 466 * send_pdu: 467 * Enqueue a PDU to be sent, and handle its disposition as well as 468 * the disposition of its associated CCB. 469 * 470 * Parameter: 471 * ccb The associated CCB. May be NULL if cdisp is CCBDISP_NOWAIT 472 * and pdisp is not PDUDISP_WAIT 473 * cdisp The CCB's disposition 474 * pdu The PDU 475 * pdisp The PDU's disposition 476 */ 477 478 STATIC void 479 send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_disp_t cdisp, pdu_disp_t pdisp) 480 { 481 connection_t *conn = pdu->pdu_connection; 482 ccb_disp_t prev_cdisp = 0; 483 484 if (ccb != NULL) { 485 prev_cdisp = ccb->ccb_disp; 486 pdu->pdu_hdr.pduh_InitiatorTaskTag = ccb->ccb_ITT; 487 pdu->pdu_owner = ccb; 488 if (cdisp != CCBDISP_NOWAIT) 489 ccb->ccb_disp = cdisp; 490 } 491 492 pdu->pdu_disp = pdisp; 493 494 DEBC(conn, 10, ("Send_pdu: CmdSN=%u ExpStatSN~%u ccb=%p, pdu=%p\n", 495 ntohl(pdu->pdu_hdr.pduh_p.command.CmdSN), 496 conn->c_StatSN_buf.ExpSN, 497 ccb, pdu)); 498 499 mutex_enter(&conn->c_lock); 500 if (pdisp == PDUDISP_WAIT) { 501 KASSERT(ccb != NULL); 502 503 ccb->ccb_pdu_waiting = pdu; 504 505 /* save UIO and IOVEC for retransmit */ 506 pdu->pdu_save_uio = pdu->pdu_uio; 507 memcpy(pdu->pdu_save_iovec, pdu->pdu_io_vec, sizeof(pdu->pdu_save_iovec)); 508 509 pdu->pdu_flags |= PDUF_BUSY; 510 } 511 /* Enqueue for sending */ 512 pdu->pdu_flags |= PDUF_INQUEUE; 513 514 if (pdu->pdu_flags & PDUF_PRIORITY) 515 TAILQ_INSERT_HEAD(&conn->c_pdus_to_send, pdu, pdu_send_chain); 516 else 517 TAILQ_INSERT_TAIL(&conn->c_pdus_to_send, pdu, pdu_send_chain); 518 519 cv_broadcast(&conn->c_conn_cv); 520 521 if (cdisp != CCBDISP_NOWAIT) { 522 KASSERT(ccb != NULL); 523 KASSERTMSG(ccb->ccb_connection == conn, "conn mismatch %p != %p\n", ccb->ccb_connection, conn); 524 525 if (prev_cdisp <= CCBDISP_NOWAIT) 526 suspend_ccb(ccb, TRUE); 527 528 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 529 530 while (ccb->ccb_disp == CCBDISP_WAIT) { 531 DEBC(conn, 15, ("Send_pdu: ccb=%p cdisp=%d waiting\n", 532 ccb, ccb->ccb_disp)); 533 cv_wait(&conn->c_ccb_cv, &conn->c_lock); 534 DEBC(conn, 15, ("Send_pdu: ccb=%p cdisp=%d returned\n", 535 ccb, ccb->ccb_disp)); 536 } 537 } 538 539 mutex_exit(&conn->c_lock); 540 } 541 542 543 /* 544 * resend_pdu: 545 * Re-Enqueue a PDU that has apparently gotten lost. 546 * 547 * Parameter: 548 * ccb The associated CCB. 549 */ 550 551 void 552 resend_pdu(ccb_t *ccb) 553 { 554 connection_t *conn = ccb->ccb_connection; 555 pdu_t *pdu = ccb->ccb_pdu_waiting; 556 557 mutex_enter(&conn->c_lock); 558 if (pdu == NULL || (pdu->pdu_flags & PDUF_BUSY)) { 559 mutex_exit(&conn->c_lock); 560 return; 561 } 562 pdu->pdu_flags |= PDUF_BUSY; 563 mutex_exit(&conn->c_lock); 564 565 /* restore UIO and IOVEC */ 566 pdu->pdu_uio = pdu->pdu_save_uio; 567 memcpy(pdu->pdu_io_vec, pdu->pdu_save_iovec, sizeof(pdu->pdu_io_vec)); 568 569 DEBC(conn, 8, ("ReSend_pdu: CmdSN=%u ExpStatSN~%u ccb=%p, pdu=%p\n", 570 ntohl(pdu->pdu_hdr.pduh_p.command.CmdSN), 571 conn->c_StatSN_buf.ExpSN, 572 ccb, pdu)); 573 574 mutex_enter(&conn->c_lock); 575 /* Enqueue for sending */ 576 pdu->pdu_flags |= PDUF_INQUEUE; 577 578 if (pdu->pdu_flags & PDUF_PRIORITY) { 579 TAILQ_INSERT_HEAD(&conn->c_pdus_to_send, pdu, pdu_send_chain); 580 } else { 581 TAILQ_INSERT_TAIL(&conn->c_pdus_to_send, pdu, pdu_send_chain); 582 } 583 cv_broadcast(&conn->c_conn_cv); 584 mutex_exit(&conn->c_lock); 585 586 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 587 } 588 589 590 /* 591 * setup_tx_uio: 592 * Initialize the uio structure for sending, including header, 593 * data (if present), padding, and Data Digest. 594 * Header Digest is generated in send thread. 595 * 596 * Parameter: 597 * pdu The PDU 598 * dsl The Data Segment Length 599 * data The data pointer 600 * read TRUE if this is a read operation 601 */ 602 603 STATIC void 604 setup_tx_uio(pdu_t *pdu, uint32_t dsl, void *data, bool read) 605 { 606 static uint8_t pad_bytes[4] = { 0 }; 607 struct uio *uio; 608 int i, pad, hlen; 609 connection_t *conn = pdu->pdu_connection; 610 611 DEB(99, ("SetupTxUio: dlen = %d, dptr: %p, read: %d\n", 612 dsl, data, read)); 613 614 if (!read && dsl) { 615 hton3(dsl, pdu->pdu_hdr.pduh_DataSegmentLength); 616 } 617 hlen = (conn->c_HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE; 618 619 pdu->pdu_io_vec[0].iov_base = &pdu->pdu_hdr; 620 pdu->pdu_io_vec[0].iov_len = hlen; 621 622 uio = &pdu->pdu_uio; 623 624 uio->uio_iov = pdu->pdu_io_vec; 625 uio->uio_iovcnt = 1; 626 uio->uio_rw = UIO_WRITE; 627 uio->uio_resid = hlen; 628 UIO_SETUP_SYSSPACE(uio); 629 630 if (!read && dsl) { 631 uio->uio_iovcnt++; 632 pdu->pdu_io_vec[1].iov_base = data; 633 pdu->pdu_io_vec[1].iov_len = dsl; 634 uio->uio_resid += dsl; 635 636 /* Pad to next multiple of 4 */ 637 pad = uio->uio_resid & 0x03; 638 if (pad) { 639 i = uio->uio_iovcnt++; 640 pad = 4 - pad; 641 pdu->pdu_io_vec[i].iov_base = pad_bytes; 642 pdu->pdu_io_vec[i].iov_len = pad; 643 uio->uio_resid += pad; 644 } 645 646 if (conn->c_DataDigest) { 647 pdu->pdu_data_digest = gen_digest_2(data, dsl, pad_bytes, pad); 648 i = uio->uio_iovcnt++; 649 pdu->pdu_io_vec[i].iov_base = &pdu->pdu_data_digest; 650 pdu->pdu_io_vec[i].iov_len = 4; 651 uio->uio_resid += 4; 652 } 653 } 654 } 655 656 /* 657 * init_login_pdu: 658 * Initialize the login PDU. 659 * 660 * Parameter: 661 * conn The connection 662 * ccb The CCB 663 * pdu The PDU 664 */ 665 666 STATIC void 667 init_login_pdu(connection_t *conn, ccb_t *ccb, pdu_t *ppdu, bool next) 668 { 669 pdu_header_t *hpdu = &ppdu->pdu_hdr; 670 login_isid_t *isid = (login_isid_t *) & hpdu->pduh_LUN; 671 uint8_t c_phase; 672 673 hpdu->pduh_Opcode = IOP_Login_Request | OP_IMMEDIATE; 674 675 mutex_enter(&conn->c_session->s_lock); 676 ccb->ccb_CmdSN = get_sernum(conn->c_session, ppdu); 677 mutex_exit(&conn->c_session->s_lock); 678 679 if (next) { 680 c_phase = (hpdu->pduh_Flags >> CSG_SHIFT) & SG_MASK; 681 hpdu->pduh_Flags = FLAG_TRANSIT | (c_phase << CSG_SHIFT) | 682 NEXT_PHASE(c_phase); 683 } 684 685 DEB(99, ("InitLoginPdu: Flags=%x Phase=%x->%x\n", 686 hpdu->pduh_Flags, 687 (hpdu->pduh_Flags >> CSG_SHIFT) & SG_MASK, 688 hpdu->pduh_Flags & SG_MASK)); 689 690 memcpy(isid, &iscsi_InitiatorISID, 6); 691 isid->TSIH = conn->c_session->s_TSIH; 692 693 hpdu->pduh_p.login_req.CID = htons(conn->c_id); 694 hpdu->pduh_p.login_req.CmdSN = htonl(ccb->ccb_CmdSN); 695 } 696 697 698 /* 699 * negotiate_login: 700 * Control login negotiation. 701 * 702 * Parameter: 703 * conn The connection 704 * rx_pdu The received login response PDU 705 * tx_ccb The originally sent login CCB 706 */ 707 708 void 709 negotiate_login(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 710 { 711 int rc; 712 bool next = TRUE; 713 pdu_t *tx_pdu; 714 uint8_t c_phase; 715 716 if (rx_pdu->pdu_hdr.pduh_Flags & FLAG_TRANSIT) 717 c_phase = rx_pdu->pdu_hdr.pduh_Flags & SG_MASK; 718 else 719 c_phase = (rx_pdu->pdu_hdr.pduh_Flags >> CSG_SHIFT) & SG_MASK; 720 721 DEB(99, ("NegotiateLogin: Flags=%x Phase=%x\n", 722 rx_pdu->pdu_hdr.pduh_Flags, c_phase)); 723 724 if (c_phase == SG_FULL_FEATURE_PHASE) { 725 session_t *sess = conn->c_session; 726 727 if (!sess->s_TSIH) 728 sess->s_TSIH = ((login_isid_t *) &rx_pdu->pdu_hdr.pduh_LUN)->TSIH; 729 730 if (rx_pdu->pdu_temp_data != NULL) 731 assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, NULL); 732 733 /* negotiated values are now valid */ 734 set_negotiated_parameters(tx_ccb); 735 736 DEBC(conn, 5, ("Login Successful!\n")); 737 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS); 738 return; 739 } 740 741 tx_pdu = get_pdu(conn, TRUE); 742 if (tx_pdu == NULL) 743 return; 744 745 tx_pdu->pdu_hdr.pduh_Flags = c_phase << CSG_SHIFT; 746 747 switch (c_phase) { 748 case SG_SECURITY_NEGOTIATION: 749 rc = assemble_security_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 750 if (rc < 0) 751 next = FALSE; 752 break; 753 754 case SG_LOGIN_OPERATIONAL_NEGOTIATION: 755 756 if (conn->c_state == ST_SEC_FIN) { 757 758 /* 759 * Both sides announced to continue with 760 * operational negotation, but this is the 761 * last target packet from mutual CHAP 762 * that needs to be validated. 763 */ 764 rc = assemble_security_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 765 if (rc) 766 break; 767 768 /* 769 * Response was valid, drop (security) parameters 770 * so that we start negotiating operational 771 * parameters. 772 */ 773 rx_pdu->pdu_temp_data = NULL; 774 } 775 776 rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 777 break; 778 779 default: 780 DEBOUT(("Invalid phase %x in negotiate_login\n", c_phase)); 781 rc = ISCSI_STATUS_TARGET_ERROR; 782 break; 783 } 784 785 if (rc > 0) { 786 wake_ccb(tx_ccb, rc); 787 free_pdu(tx_pdu); 788 } else { 789 init_login_pdu(conn, tx_ccb, tx_pdu, next); 790 setup_tx_uio(tx_pdu, tx_pdu->pdu_temp_data_len, tx_pdu->pdu_temp_data, FALSE); 791 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 792 } 793 } 794 795 796 /* 797 * init_text_pdu: 798 * Initialize the text PDU. 799 * 800 * Parameter: 801 * conn The connection 802 * ccb The transmit CCB 803 * ppdu The transmit PDU 804 * rx_pdu The received PDU if this is an unsolicited negotiation 805 */ 806 807 STATIC void 808 init_text_pdu(connection_t *conn, ccb_t *ccb, pdu_t *ppdu, pdu_t *rx_pdu) 809 { 810 pdu_header_t *hpdu = &ppdu->pdu_hdr; 811 812 hpdu->pduh_Opcode = IOP_Text_Request | OP_IMMEDIATE; 813 hpdu->pduh_Flags = FLAG_FINAL; 814 815 mutex_enter(&conn->c_session->s_lock); 816 ccb->ccb_CmdSN = get_sernum(conn->c_session, ppdu); 817 mutex_exit(&conn->c_session->s_lock); 818 819 if (rx_pdu != NULL) { 820 hpdu->pduh_p.text_req.TargetTransferTag = 821 rx_pdu->pdu_hdr.pduh_p.text_rsp.TargetTransferTag; 822 hpdu->pduh_LUN = rx_pdu->pdu_hdr.pduh_LUN; 823 } else 824 hpdu->pduh_p.text_req.TargetTransferTag = 0xffffffff; 825 826 hpdu->pduh_p.text_req.CmdSN = htonl(ccb->ccb_CmdSN); 827 } 828 829 830 /* 831 * acknowledge_text: 832 * Acknowledge a continued login or text response. 833 * 834 * Parameter: 835 * conn The connection 836 * rx_pdu The received login/text response PDU 837 * tx_ccb The originally sent login/text request CCB 838 */ 839 840 void 841 acknowledge_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 842 { 843 pdu_t *tx_pdu; 844 845 tx_pdu = get_pdu(conn, TRUE); 846 if (tx_pdu == NULL) 847 return; 848 849 if (rx_pdu != NULL && 850 (rx_pdu->pdu_hdr.pduh_Opcode & OPCODE_MASK) == IOP_Login_Request) 851 init_login_pdu(conn, tx_ccb, tx_pdu, FALSE); 852 else 853 init_text_pdu(conn, tx_ccb, tx_pdu, rx_pdu); 854 855 setup_tx_uio(tx_pdu, 0, NULL, FALSE); 856 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 857 } 858 859 860 /* 861 * start_text_negotiation: 862 * Handle target request to negotiate (via asynch event) 863 * 864 * Parameter: 865 * conn The connection 866 */ 867 868 void 869 start_text_negotiation(connection_t *conn) 870 { 871 pdu_t *pdu; 872 ccb_t *ccb; 873 874 ccb = get_ccb(conn, TRUE); 875 if (ccb == NULL) 876 return; 877 pdu = get_pdu(conn, TRUE); 878 if (pdu == NULL) { 879 free_ccb(ccb); 880 return; 881 } 882 883 if (init_text_parameters(conn, ccb)) { 884 free_ccb(ccb); 885 free_pdu(pdu); 886 return; 887 } 888 889 init_text_pdu(conn, ccb, pdu, NULL); 890 setup_tx_uio(pdu, 0, NULL, FALSE); 891 send_pdu(ccb, pdu, CCBDISP_FREE, PDUDISP_WAIT); 892 } 893 894 895 /* 896 * negotiate_text: 897 * Handle received text negotiation. 898 * 899 * Parameter: 900 * conn The connection 901 * rx_pdu The received text response PDU 902 * tx_ccb The original CCB 903 */ 904 905 void 906 negotiate_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 907 { 908 int rc; 909 pdu_t *tx_pdu; 910 911 if (tx_ccb->ccb_flags & CCBF_SENDTARGET) { 912 if (!(rx_pdu->pdu_hdr.pduh_Flags & FLAG_FINAL)) { 913 handle_connection_error(conn, ISCSI_STATUS_PROTOCOL_ERROR, 914 LOGOUT_CONNECTION); 915 return; 916 } 917 /* transfer ownership of text to CCB */ 918 tx_ccb->ccb_text_data = rx_pdu->pdu_temp_data; 919 tx_ccb->ccb_text_len = rx_pdu->pdu_temp_data_len; 920 rx_pdu->pdu_temp_data = NULL; 921 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS); 922 } else { 923 if (!(rx_pdu->pdu_hdr.pduh_Flags & FLAG_FINAL)) 924 tx_pdu = get_pdu(conn, TRUE); 925 else 926 tx_pdu = NULL; 927 928 rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 929 if (rc) { 930 if (tx_pdu != NULL) 931 free_pdu(tx_pdu); 932 933 handle_connection_error(conn, rc, LOGOUT_CONNECTION); 934 } else if (tx_pdu != NULL) { 935 init_text_pdu(conn, tx_ccb, tx_pdu, rx_pdu); 936 setup_tx_uio(tx_pdu, tx_pdu->pdu_temp_data_len, 937 tx_pdu->pdu_temp_data, FALSE); 938 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 939 } else { 940 set_negotiated_parameters(tx_ccb); 941 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS); 942 } 943 } 944 } 945 946 947 /* 948 * send_send_targets: 949 * Send out a SendTargets text request. 950 * The result is stored in the fields in the session structure. 951 * 952 * Parameter: 953 * session The session 954 * key The text key to use 955 * 956 * Returns: 0 on success, else an error code. 957 */ 958 959 int 960 send_send_targets(session_t *sess, uint8_t *key) 961 { 962 ccb_t *ccb; 963 pdu_t *pdu; 964 int rc = 0; 965 connection_t *conn; 966 967 DEB(9, ("Send_send_targets\n")); 968 969 conn = assign_connection(sess, TRUE); 970 if (conn == NULL || conn->c_terminating || conn->c_state != ST_FULL_FEATURE) 971 return (conn != NULL && conn->c_terminating) ? conn->c_terminating 972 : ISCSI_STATUS_CONNECTION_FAILED; 973 974 ccb = get_ccb(conn, TRUE); 975 if (ccb == NULL) 976 return conn->c_terminating; 977 pdu = get_pdu(conn, TRUE); 978 if (pdu == NULL) { 979 free_ccb(ccb); 980 return conn->c_terminating; 981 } 982 983 ccb->ccb_flags |= CCBF_SENDTARGET; 984 985 if ((rc = assemble_send_targets(pdu, key)) != 0) { 986 free_ccb(ccb); 987 free_pdu(pdu); 988 return rc; 989 } 990 991 init_text_pdu(conn, ccb, pdu, NULL); 992 993 setup_tx_uio(pdu, pdu->pdu_temp_data_len, pdu->pdu_temp_data, FALSE); 994 send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_WAIT); 995 996 rc = ccb->ccb_status; 997 if (!rc) { 998 /* transfer ownership of data */ 999 sess->s_target_list = ccb->ccb_text_data; 1000 sess->s_target_list_len = ccb->ccb_text_len; 1001 ccb->ccb_text_data = NULL; 1002 } 1003 free_ccb(ccb); 1004 return rc; 1005 } 1006 1007 1008 /* 1009 * send_nop_out: 1010 * Send nop out request. 1011 * 1012 * Parameter: 1013 * conn The connection 1014 * rx_pdu The received Nop-In PDU 1015 * 1016 * Returns: 0 on success, else an error code. 1017 */ 1018 1019 int 1020 send_nop_out(connection_t *conn, pdu_t *rx_pdu) 1021 { 1022 session_t *sess; 1023 ccb_t *ccb; 1024 pdu_t *ppdu; 1025 pdu_header_t *hpdu; 1026 uint32_t sn; 1027 1028 if (rx_pdu != NULL) { 1029 ccb = NULL; 1030 ppdu = get_pdu(conn, TRUE); 1031 if (ppdu == NULL) 1032 return 1; 1033 } else { 1034 ccb = get_ccb(conn, FALSE); 1035 if (ccb == NULL) { 1036 DEBOUT(("Can't get CCB in send_nop_out\n")); 1037 return 1; 1038 } 1039 ppdu = get_pdu(conn, FALSE); 1040 if (ppdu == NULL) { 1041 free_ccb(ccb); 1042 DEBOUT(("Can't get PDU in send_nop_out\n")); 1043 return 1; 1044 } 1045 } 1046 1047 hpdu = &ppdu->pdu_hdr; 1048 hpdu->pduh_Flags = FLAG_FINAL; 1049 hpdu->pduh_Opcode = IOP_NOP_Out | OP_IMMEDIATE; 1050 1051 sess = conn->c_session; 1052 1053 mutex_enter(&sess->s_lock); 1054 sn = get_sernum(sess, ppdu); 1055 mutex_exit(&sess->s_lock); 1056 1057 if (rx_pdu != NULL) { 1058 hpdu->pduh_p.nop_out.TargetTransferTag = 1059 rx_pdu->pdu_hdr.pduh_p.nop_in.TargetTransferTag; 1060 hpdu->pduh_InitiatorTaskTag = rx_pdu->pdu_hdr.pduh_InitiatorTaskTag; 1061 hpdu->pduh_p.nop_out.CmdSN = htonl(sn); 1062 hpdu->pduh_LUN = rx_pdu->pdu_hdr.pduh_LUN; 1063 } else { 1064 hpdu->pduh_p.nop_out.TargetTransferTag = 0xffffffff; 1065 hpdu->pduh_InitiatorTaskTag = 0xffffffff; 1066 ccb->ccb_CmdSN = sn; 1067 hpdu->pduh_p.nop_out.CmdSN = htonl(sn); 1068 } 1069 1070 DEBC(conn, 10, ("Send NOP_Out CmdSN=%d, rx_pdu=%p\n", sn, rx_pdu)); 1071 1072 setup_tx_uio(ppdu, 0, NULL, FALSE); 1073 send_pdu(ccb, ppdu, (rx_pdu != NULL) ? CCBDISP_NOWAIT : CCBDISP_FREE, 1074 PDUDISP_FREE); 1075 return 0; 1076 } 1077 1078 1079 /* 1080 * snack_missing: 1081 * Send SNACK request for missing data. 1082 * 1083 * Parameter: 1084 * conn The connection 1085 * ccb The task's CCB (for Data NAK only) 1086 * type The SNACK type 1087 * BegRun The BegRun field 1088 * RunLength The RunLength field 1089 */ 1090 1091 void 1092 snack_missing(connection_t *conn, ccb_t *ccb, uint8_t type, 1093 uint32_t BegRun, uint32_t RunLength) 1094 { 1095 pdu_t *ppdu; 1096 pdu_header_t *hpdu; 1097 1098 ppdu = get_pdu(conn, TRUE); 1099 if (ppdu == NULL) 1100 return; 1101 hpdu = &ppdu->pdu_hdr; 1102 hpdu->pduh_Opcode = IOP_SNACK_Request; 1103 hpdu->pduh_Flags = FLAG_FINAL | type; 1104 1105 hpdu->pduh_InitiatorTaskTag = (type == SNACK_DATA_NAK) ? ccb->ccb_ITT : 0xffffffff; 1106 hpdu->pduh_p.snack.TargetTransferTag = 0xffffffff; 1107 hpdu->pduh_p.snack.BegRun = htonl(BegRun); 1108 hpdu->pduh_p.snack.RunLength = htonl(RunLength); 1109 1110 ppdu->pdu_flags = PDUF_PRIORITY; 1111 1112 setup_tx_uio(ppdu, 0, NULL, FALSE); 1113 send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE); 1114 } 1115 1116 1117 /* 1118 * send_snack: 1119 * Send SNACK request. 1120 * 1121 * Parameter: 1122 * conn The connection 1123 * rx_pdu The received data in PDU 1124 * tx_ccb The original command CCB (required for Data ACK only) 1125 * type The SNACK type 1126 * 1127 * Returns: 0 on success, else an error code. 1128 */ 1129 1130 void 1131 send_snack(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb, uint8_t type) 1132 { 1133 pdu_t *ppdu; 1134 pdu_header_t *hpdu; 1135 1136 ppdu = get_pdu(conn, TRUE); 1137 if (ppdu == NULL) 1138 return; 1139 hpdu = &ppdu->pdu_hdr; 1140 hpdu->pduh_Opcode = IOP_SNACK_Request; 1141 hpdu->pduh_Flags = FLAG_FINAL | type; 1142 1143 switch (type) { 1144 case SNACK_DATA_NAK: 1145 hpdu->pduh_InitiatorTaskTag = rx_pdu->pdu_hdr.pduh_InitiatorTaskTag; 1146 hpdu->pduh_p.snack.TargetTransferTag = 0xffffffff; 1147 hpdu->pduh_p.snack.BegRun = rx_pdu->pdu_hdr.pduh_p.data_in.DataSN; 1148 hpdu->pduh_p.snack.RunLength = htonl(1); 1149 break; 1150 1151 case SNACK_STATUS_NAK: 1152 hpdu->pduh_InitiatorTaskTag = 0xffffffff; 1153 hpdu->pduh_p.snack.TargetTransferTag = 0xffffffff; 1154 hpdu->pduh_p.snack.BegRun = rx_pdu->pdu_hdr.pduh_p.response.StatSN; 1155 hpdu->pduh_p.snack.RunLength = htonl(1); 1156 break; 1157 1158 case SNACK_DATA_ACK: 1159 hpdu->pduh_InitiatorTaskTag = 0xffffffff; 1160 hpdu->pduh_p.snack.TargetTransferTag = 1161 rx_pdu->pdu_hdr.pduh_p.data_in.TargetTransferTag; 1162 hpdu->pduh_p.snack.BegRun = tx_ccb->ccb_DataSN_buf.ExpSN; 1163 hpdu->pduh_p.snack.RunLength = 0; 1164 break; 1165 1166 default: 1167 DEBOUT(("Invalid type %d in send_snack\n", type)); 1168 return; 1169 } 1170 1171 hpdu->pduh_LUN = rx_pdu->pdu_hdr.pduh_LUN; 1172 1173 ppdu->pdu_flags = PDUF_PRIORITY; 1174 1175 setup_tx_uio(ppdu, 0, NULL, FALSE); 1176 send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE); 1177 } 1178 1179 1180 /* 1181 * send_login: 1182 * Send login request. 1183 * 1184 * Parameter: 1185 * conn The connection 1186 * par The login parameters (for negotiation) 1187 * 1188 * Returns: 0 on success, else an error code. 1189 */ 1190 1191 int 1192 send_login(connection_t *conn) 1193 { 1194 ccb_t *ccb; 1195 pdu_t *pdu; 1196 int rc; 1197 1198 DEBC(conn, 9, ("Send_login\n")); 1199 ccb = get_ccb(conn, TRUE); 1200 /* only if terminating (which couldn't possibly happen here, but...) */ 1201 if (ccb == NULL) 1202 return conn->c_terminating; 1203 pdu = get_pdu(conn, TRUE); 1204 if (pdu == NULL) { 1205 free_ccb(ccb); 1206 return conn->c_terminating; 1207 } 1208 1209 if ((rc = assemble_login_parameters(conn, ccb, pdu)) <= 0) { 1210 init_login_pdu(conn, ccb, pdu, !rc); 1211 setup_tx_uio(pdu, pdu->pdu_temp_data_len, pdu->pdu_temp_data, FALSE); 1212 send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_FREE); 1213 rc = ccb->ccb_status; 1214 } else { 1215 free_pdu(pdu); 1216 } 1217 free_ccb(ccb); 1218 return rc; 1219 } 1220 1221 1222 /* 1223 * send_logout: 1224 * Send logout request. 1225 * NOTE: This function does not wait for the logout to complete. 1226 * 1227 * Parameter: 1228 * conn The connection 1229 * refconn The referenced connection 1230 * reason The reason code 1231 * wait Wait for completion if TRUE 1232 * 1233 * Returns: 0 on success (logout sent), else an error code. 1234 */ 1235 1236 int 1237 send_logout(connection_t *conn, connection_t *refconn, int reason, 1238 bool wait) 1239 { 1240 ccb_t *ccb; 1241 pdu_t *ppdu; 1242 pdu_header_t *hpdu; 1243 1244 DEBC(conn, 5, ("Send_logout\n")); 1245 ccb = get_ccb(conn, TRUE); 1246 /* can only happen if terminating... */ 1247 if (ccb == NULL) 1248 return conn->c_terminating; 1249 ppdu = get_pdu(conn, TRUE); 1250 if (ppdu == NULL) { 1251 free_ccb(ccb); 1252 return conn->c_terminating; 1253 } 1254 1255 hpdu = &ppdu->pdu_hdr; 1256 hpdu->pduh_Opcode = IOP_Logout_Request | OP_IMMEDIATE; 1257 1258 hpdu->pduh_Flags = FLAG_FINAL | reason; 1259 ccb->ccb_CmdSN = conn->c_session->s_CmdSN; 1260 hpdu->pduh_p.logout_req.CmdSN = htonl(ccb->ccb_CmdSN); 1261 if (reason > 0) 1262 hpdu->pduh_p.logout_req.CID = htons(refconn->c_id); 1263 1264 ccb->ccb_par = refconn; 1265 if (refconn != conn) { 1266 ccb->ccb_flags |= CCBF_OTHERCONN; 1267 } else { 1268 conn->c_state = ST_LOGOUT_SENT; 1269 conn->c_loggedout = LOGOUT_SENT; 1270 } 1271 1272 setup_tx_uio(ppdu, 0, NULL, FALSE); 1273 send_pdu(ccb, ppdu, (wait) ? CCBDISP_WAIT : CCBDISP_FREE, PDUDISP_FREE); 1274 1275 if (wait) { 1276 int rc = ccb->ccb_status; 1277 free_ccb (ccb); 1278 return rc; 1279 } 1280 return 0; 1281 } 1282 1283 1284 /* 1285 * send_task_management: 1286 * Send task management request. 1287 * 1288 * Parameter: 1289 * conn The connection 1290 * ref_ccb The referenced command (NULL if none) 1291 * xs The scsipi command structure (NULL if not a scsipi request) 1292 * function The function code 1293 * 1294 * Returns: 0 on success, else an error code. 1295 */ 1296 1297 int 1298 send_task_management(connection_t *conn, ccb_t *ref_ccb, struct scsipi_xfer *xs, 1299 int function) 1300 { 1301 ccb_t *ccb; 1302 pdu_t *ppdu; 1303 pdu_header_t *hpdu; 1304 1305 DEBC(conn, 5, ("Send_task_management, ref_ccb=%p, func = %d\n", 1306 ref_ccb, function)); 1307 1308 if (function == TASK_REASSIGN && conn->c_session->s_ErrorRecoveryLevel < 2) 1309 return ISCSI_STATUS_CANT_REASSIGN; 1310 1311 ccb = get_ccb(conn, xs == NULL); 1312 /* can only happen if terminating... */ 1313 if (ccb == NULL) { 1314 DEBC(conn, 0, ("send_task_management, ref_ccb=%p, xs=%p, term=%d. No CCB\n", 1315 ref_ccb, xs, conn->c_terminating)); 1316 return conn->c_terminating; 1317 } 1318 ppdu = get_pdu(conn, xs == NULL); 1319 if (ppdu == NULL) { 1320 DEBC(conn, 0, ("send_task_management, ref_ccb=%p, xs=%p, term=%d. No PDU\n", 1321 ref_ccb, xs, conn->c_terminating)); 1322 free_ccb(ccb); 1323 return conn->c_terminating; 1324 } 1325 1326 ccb->ccb_xs = xs; 1327 1328 hpdu = &ppdu->pdu_hdr; 1329 hpdu->pduh_Opcode = IOP_SCSI_Task_Management | OP_IMMEDIATE; 1330 hpdu->pduh_Flags = FLAG_FINAL | function; 1331 1332 ccb->ccb_CmdSN = conn->c_session->s_CmdSN; 1333 hpdu->pduh_p.task_req.CmdSN = htonl(ccb->ccb_CmdSN); 1334 1335 if (ref_ccb != NULL) { 1336 hpdu->pduh_p.task_req.ReferencedTaskTag = ref_ccb->ccb_ITT; 1337 hpdu->pduh_p.task_req.RefCmdSN = htonl(ref_ccb->ccb_CmdSN); 1338 hpdu->pduh_p.task_req.ExpDataSN = htonl(ref_ccb->ccb_DataSN_buf.ExpSN); 1339 } else 1340 hpdu->pduh_p.task_req.ReferencedTaskTag = 0xffffffff; 1341 1342 ppdu->pdu_flags |= PDUF_PRIORITY; 1343 1344 setup_tx_uio(ppdu, 0, NULL, FALSE); 1345 send_pdu(ccb, ppdu, (xs) ? CCBDISP_SCSIPI : CCBDISP_WAIT, PDUDISP_FREE); 1346 1347 if (xs == NULL) { 1348 int rc = ccb->ccb_status; 1349 free_ccb(ccb); 1350 return rc; 1351 } 1352 return 0; 1353 } 1354 1355 1356 /* 1357 * send_data_out: 1358 * Send data to target in response to an R2T or as unsolicited data. 1359 * 1360 * Parameter: 1361 * conn The connection 1362 * rx_pdu The received R2T PDU (NULL if unsolicited) 1363 * tx_ccb The originally sent command CCB 1364 * waitok Whether it's OK to wait for an available PDU or not 1365 */ 1366 1367 int 1368 send_data_out(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb, 1369 ccb_disp_t disp, bool waitok) 1370 { 1371 pdu_header_t *hpdu; 1372 uint32_t totlen, len, offs, sn; 1373 pdu_t *tx_pdu; 1374 1375 KASSERT(conn->c_max_transfer != 0); 1376 1377 if (rx_pdu) { 1378 offs = ntohl(rx_pdu->pdu_hdr.pduh_p.r2t.BufferOffset); 1379 totlen = ntohl(rx_pdu->pdu_hdr.pduh_p.r2t.DesiredDataTransferLength); 1380 } else { 1381 offs = conn->c_max_firstimmed; 1382 totlen = min(conn->c_max_firstdata - offs, tx_ccb->ccb_data_len - offs); 1383 } 1384 sn = 0; 1385 1386 while (totlen) { 1387 len = min(totlen, conn->c_max_transfer); 1388 1389 tx_pdu = get_pdu(conn, waitok); 1390 if (tx_pdu == NULL) { 1391 DEBC(conn, 5, ("No PDU in send_data_out\n")); 1392 1393 tx_ccb->ccb_disp = disp; 1394 tx_ccb->ccb_status = ISCSI_STATUS_NO_RESOURCES; 1395 handle_connection_error(conn, ISCSI_STATUS_NO_RESOURCES, NO_LOGOUT); 1396 1397 return ISCSI_STATUS_NO_RESOURCES; 1398 } 1399 1400 totlen -= len; 1401 hpdu = &tx_pdu->pdu_hdr; 1402 hpdu->pduh_Opcode = IOP_SCSI_Data_out; 1403 if (!totlen) 1404 hpdu->pduh_Flags = FLAG_FINAL; 1405 1406 if (rx_pdu != NULL) 1407 hpdu->pduh_p.data_out.TargetTransferTag = 1408 rx_pdu->pdu_hdr.pduh_p.r2t.TargetTransferTag; 1409 else 1410 hpdu->pduh_p.data_out.TargetTransferTag = 0xffffffff; 1411 hpdu->pduh_p.data_out.BufferOffset = htonl(offs); 1412 hpdu->pduh_p.data_out.DataSN = htonl(sn); 1413 1414 DEBC(conn, 10, ("Send DataOut: DataSN %d, len %d offs %x totlen %d\n", 1415 sn, len, offs, totlen)); 1416 1417 setup_tx_uio(tx_pdu, len, tx_ccb->ccb_data_ptr + offs, FALSE); 1418 send_pdu(tx_ccb, tx_pdu, (totlen) ? CCBDISP_NOWAIT : disp, PDUDISP_FREE); 1419 1420 sn++; 1421 offs += len; 1422 } 1423 return 0; 1424 } 1425 1426 1427 /* 1428 * send_command: 1429 * Send a SCSI command request. 1430 * 1431 * Parameter: 1432 * CCB The CCB 1433 * disp The CCB disposition 1434 */ 1435 1436 void 1437 send_command(ccb_t *ccb, ccb_disp_t disp, bool waitok, bool immed) 1438 { 1439 uint32_t totlen, len; 1440 connection_t *conn = ccb->ccb_connection; 1441 session_t *sess = ccb->ccb_session; 1442 pdu_t *ppdu; 1443 pdu_header_t *hpdu; 1444 1445 mutex_enter(&sess->s_lock); 1446 while (!sernum_in_window(sess)) { 1447 mutex_exit(&sess->s_lock); 1448 ccb->ccb_disp = disp; 1449 wake_ccb(ccb, ISCSI_STATUS_QUEUE_FULL); 1450 return; 1451 } 1452 mutex_exit(&sess->s_lock); 1453 1454 /* Don't confuse targets during (re-)negotations */ 1455 if (conn->c_state != ST_FULL_FEATURE) { 1456 DEBOUT(("Invalid connection for send_command, ccb = %p\n",ccb)); 1457 ccb->ccb_disp = disp; 1458 wake_ccb(ccb, ISCSI_STATUS_TARGET_BUSY); 1459 return; 1460 } 1461 1462 ppdu = get_pdu(conn, waitok); 1463 if (ppdu == NULL) { 1464 DEBOUT(("No PDU for send_command, ccb = %p\n",ccb)); 1465 ccb->ccb_disp = disp; 1466 wake_ccb(ccb, ISCSI_STATUS_NO_RESOURCES); 1467 return; 1468 } 1469 1470 totlen = len = ccb->ccb_data_len; 1471 1472 hpdu = &ppdu->pdu_hdr; 1473 hpdu->pduh_LUN = htonq(ccb->ccb_lun); 1474 memcpy(hpdu->pduh_p.command.SCSI_CDB, ccb->ccb_cmd, ccb->ccb_cmdlen); 1475 hpdu->pduh_Opcode = IOP_SCSI_Command; 1476 if (immed) 1477 hpdu->pduh_Opcode |= OP_IMMEDIATE; 1478 hpdu->pduh_p.command.ExpectedDataTransferLength = htonl(totlen); 1479 1480 if (totlen) { 1481 if (ccb->ccb_data_in) { 1482 hpdu->pduh_Flags = FLAG_READ; 1483 totlen = 0; 1484 } else { 1485 hpdu->pduh_Flags = FLAG_WRITE; 1486 /* immediate data we can send */ 1487 len = min(totlen, conn->c_max_firstimmed); 1488 1489 /* can we send more unsolicited data ? */ 1490 totlen = conn->c_max_firstdata ? totlen - len : 0; 1491 } 1492 } 1493 if (!totlen) 1494 hpdu->pduh_Flags |= FLAG_FINAL; 1495 hpdu->pduh_Flags |= ccb->ccb_tag; 1496 1497 if (ccb->ccb_data_in) 1498 init_sernum(&ccb->ccb_DataSN_buf); 1499 1500 ccb->ccb_sense_len_got = 0; 1501 ccb->ccb_xfer_len = 0; 1502 ccb->ccb_residual = 0; 1503 ccb->ccb_flags |= CCBF_REASSIGN; 1504 1505 mutex_enter(&sess->s_lock); 1506 ccb->ccb_CmdSN = get_sernum(sess, ppdu); 1507 mutex_exit(&sess->s_lock); 1508 1509 hpdu->pduh_p.command.CmdSN = htonl(ccb->ccb_CmdSN); 1510 1511 DEBC(conn, 10, ("Send Command: CmdSN %d (%d), data_in %d, len %d, totlen %d\n", 1512 ccb->ccb_CmdSN, sess->s_MaxCmdSN, ccb->ccb_data_in, len, totlen)); 1513 1514 setup_tx_uio(ppdu, len, ccb->ccb_data_ptr, ccb->ccb_data_in); 1515 send_pdu(ccb, ppdu, (totlen) ? CCBDISP_DEFER : disp, PDUDISP_WAIT); 1516 1517 if (totlen) 1518 send_data_out(conn, NULL, ccb, disp, waitok); 1519 } 1520 1521 1522 /* 1523 * send_run_xfer: 1524 * Handle a SCSI command transfer request from scsipi. 1525 * 1526 * Parameter: 1527 * session The session 1528 * xs The transfer parameters 1529 */ 1530 1531 void 1532 send_run_xfer(session_t *session, struct scsipi_xfer *xs) 1533 { 1534 ccb_t *ccb; 1535 connection_t *conn; 1536 bool waitok; 1537 1538 waitok = !(xs->xs_control & XS_CTL_NOSLEEP); 1539 1540 DEB(10, ("RunXfer: flags=%x, data=%p, datalen=%d, resid=%d, cmdlen=%d, " 1541 "waitok=%d\n", xs->xs_control, xs->data, xs->datalen, 1542 xs->resid, xs->cmdlen, waitok)); 1543 1544 conn = assign_connection(session, waitok); 1545 1546 if (conn == NULL || conn->c_terminating || conn->c_state != ST_FULL_FEATURE) { 1547 if (session->s_terminating) 1548 xs->error = XS_SELTIMEOUT; 1549 else 1550 xs->error = XS_BUSY; 1551 DEBC(conn, 10, ("run_xfer on dead connection\n")); 1552 scsipi_done(xs); 1553 unref_session(session); 1554 return; 1555 } 1556 1557 if (xs->xs_control & XS_CTL_RESET) { 1558 if (send_task_management(conn, NULL, xs, TARGET_WARM_RESET)) { 1559 DEBC(conn, 0, ("send_task_management TARGET_WARM_RESET failed\n")); 1560 xs->error = XS_SELTIMEOUT; 1561 scsipi_done(xs); 1562 unref_session(session); 1563 } 1564 return; 1565 } 1566 1567 ccb = get_ccb(conn, waitok); 1568 if (ccb == NULL) { 1569 xs->error = XS_BUSY; 1570 DEBC(conn, 5, ("No CCB in run_xfer, %d in use.\n", conn->c_usecount)); 1571 scsipi_done(xs); 1572 unref_session(session); 1573 return; 1574 } 1575 /* copy parameters into CCB for easier access */ 1576 ccb->ccb_xs = xs; 1577 1578 ccb->ccb_data_in = (xs->xs_control & XS_CTL_DATA_IN) != 0; 1579 ccb->ccb_data_len = (uint32_t) xs->datalen; 1580 ccb->ccb_data_ptr = xs->data; 1581 1582 ccb->ccb_sense_len_req = sizeof(xs->sense.scsi_sense); 1583 ccb->ccb_sense_ptr = &xs->sense; 1584 1585 ccb->ccb_lun = ((uint64_t) (uint8_t) xs->xs_periph->periph_lun) << 48; 1586 ccb->ccb_cmd = (uint8_t *) xs->cmd; 1587 ccb->ccb_cmdlen = xs->cmdlen; 1588 DEB(10, ("RunXfer: Periph_lun = %d, cmd[1] = %x, cmdlen = %d\n", 1589 xs->xs_periph->periph_lun, ccb->ccb_cmd[1], xs->cmdlen)); 1590 1591 ccb->ccb_ITT |= xs->xs_tag_id << 24; 1592 switch (xs->xs_tag_type) { 1593 case MSG_ORDERED_Q_TAG: 1594 ccb->ccb_tag = ATTR_ORDERED; 1595 break; 1596 case MSG_SIMPLE_Q_TAG: 1597 ccb->ccb_tag = ATTR_SIMPLE; 1598 break; 1599 case MSG_HEAD_OF_Q_TAG: 1600 ccb->ccb_tag = ATTR_HEAD_OF_QUEUE; 1601 break; 1602 default: 1603 ccb->ccb_tag = 0; 1604 break; 1605 } 1606 1607 #ifdef LUN_1 1608 ccb->ccb_lun += 0x1000000000000LL; 1609 ccb->ccb_cmd[1] += 0x10; 1610 #endif 1611 send_command(ccb, CCBDISP_SCSIPI, waitok, FALSE); 1612 } 1613 1614 1615 #ifndef ISCSI_MINIMAL 1616 /* 1617 * send_io_command: 1618 * Handle a SCSI io command request from user space. 1619 * 1620 * Parameter: 1621 * session The session 1622 * lun The LUN to use 1623 * req The SCSI request block 1624 * immed Immediate command if TRUE 1625 * conn_id Assign to this connection ID if nonzero 1626 */ 1627 1628 int 1629 send_io_command(session_t *session, uint64_t lun, scsireq_t *req, 1630 bool immed, uint32_t conn_id) 1631 { 1632 ccb_t *ccb; 1633 connection_t *conn; 1634 int rc; 1635 1636 DEB(9, ("IoCommand: lun=%x, datalen=%d, cmdlen=%d, immed=%d, cid=%d\n", 1637 (int) lun, (int) req->datalen, (int) req->cmdlen, immed, conn_id)); 1638 1639 conn = (conn_id) ? find_connection(session, conn_id) 1640 : assign_connection(session, TRUE); 1641 1642 if (conn == NULL || conn->c_terminating || conn->c_state != ST_FULL_FEATURE) { 1643 DEBOUT(("io_command on dead connection (state = %d)\n", 1644 (conn != NULL) ? conn->c_state : -1)); 1645 return ISCSI_STATUS_INVALID_CONNECTION_ID; 1646 } 1647 1648 ccb = get_ccb(conn, TRUE); 1649 if (ccb == NULL) { 1650 DEBOUT(("No CCB in io_command\n")); 1651 return ISCSI_STATUS_NO_RESOURCES; 1652 } 1653 1654 ccb->ccb_data_in = (req->flags & SCCMD_READ) != 0; 1655 ccb->ccb_data_len = (uint32_t) req->datalen; 1656 ccb->ccb_data_ptr = req->databuf; 1657 1658 ccb->ccb_sense_len_req = req->senselen; 1659 ccb->ccb_sense_ptr = &req->sense; 1660 1661 ccb->ccb_lun = lun; 1662 ccb->ccb_cmd = (uint8_t *) req->cmd; 1663 ccb->ccb_cmdlen = req->cmdlen; 1664 DEBC(conn, 10, ("IoCommand: cmd[1] = %x, cmdlen = %d\n", 1665 ccb->ccb_cmd[1], ccb->ccb_cmdlen)); 1666 1667 send_command(ccb, CCBDISP_WAIT, TRUE, immed); 1668 1669 rc = ccb->ccb_status; 1670 1671 req->senselen_used = ccb->ccb_sense_len_got; 1672 req->datalen_used = req->datalen - ccb->ccb_residual; 1673 1674 free_ccb(ccb); 1675 1676 return rc; 1677 } 1678 #endif 1679 1680 1681 /***************************************************************************** 1682 * Timeout handlers 1683 *****************************************************************************/ 1684 /* 1685 * connection_timeout: 1686 * Handle prolonged silence on a connection by checking whether 1687 * it's still alive. 1688 * This has the side effect of discovering missing status or lost commands 1689 * before those time out. 1690 * 1691 * Parameter: 1692 * conn The connection 1693 */ 1694 1695 void 1696 connection_timeout(connection_t *conn) 1697 { 1698 if (++conn->c_num_timeouts > MAX_CONN_TIMEOUTS) { 1699 DEBC(conn, 1, ("connection timeout %d\n", conn->c_num_timeouts)); 1700 handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, NO_LOGOUT); 1701 } else { 1702 if (conn->c_state == ST_FULL_FEATURE) 1703 send_nop_out(conn, NULL); 1704 1705 connection_timeout_start(conn, CONNECTION_TIMEOUT); 1706 } 1707 } 1708 1709 /* 1710 * ccb_timeout: 1711 * Handle timeout of a sent command. 1712 * 1713 * Parameter: 1714 * ccb The CCB 1715 */ 1716 1717 void 1718 ccb_timeout(ccb_t *ccb) 1719 { 1720 connection_t *conn = ccb->ccb_connection; 1721 1722 if (conn == NULL) { 1723 /* XXX Should never happen */ 1724 printf("ccb_timeout: num=%d total=%d disp=%d invalid ccb=%p\n", 1725 ccb->ccb_num_timeouts+1, ccb->ccb_total_tries, 1726 ccb->ccb_disp, ccb); 1727 return; 1728 } 1729 1730 ccb->ccb_total_tries++; 1731 1732 DEBC(conn, 0, ("ccb_timeout: num=%d total=%d disp=%d\n", 1733 ccb->ccb_num_timeouts+1, ccb->ccb_total_tries, ccb->ccb_disp)); 1734 1735 if (++ccb->ccb_num_timeouts > MAX_CCB_TIMEOUTS || 1736 ccb->ccb_total_tries > MAX_CCB_TRIES || 1737 ccb->ccb_disp <= CCBDISP_FREE || 1738 !ccb->ccb_session->s_ErrorRecoveryLevel) { 1739 1740 wake_ccb(ccb, ISCSI_STATUS_TIMEOUT); 1741 handle_connection_error(conn, 1742 ISCSI_STATUS_TIMEOUT, RECOVER_CONNECTION); 1743 } else { 1744 if (ccb->ccb_data_in && ccb->ccb_xfer_len < ccb->ccb_data_len) { 1745 /* request resend of all missing data */ 1746 snack_missing(conn, ccb, SNACK_DATA_NAK, 0, 0); 1747 } else { 1748 /* request resend of all missing status */ 1749 snack_missing(conn, NULL, SNACK_STATUS_NAK, 0, 0); 1750 } 1751 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 1752 } 1753 } 1754 1755