1/* $NetBSD: iscsi_send.c,v 1.40 2023/11/25 10:08:27 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 53STATIC int 54my_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 96connection_t * 97assign_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 144STATIC void 145reassign_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 325void 326iscsi_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 mutex_exit(&conn->c_lock); 347 348 /* update ExpStatSN here to avoid discontinuities */ 349 /* and delays in updating target */ 350 pdu->pdu_hdr.pduh_p.command.ExpStatSN = htonl(conn->c_StatSN_buf.ExpSN); 351 352 if (conn->c_HeaderDigest) 353 pdu->pdu_hdr.pduh_HeaderDigest = gen_digest(&pdu->pdu_hdr, BHS_SIZE); 354 355 DEBC(conn, 99, ("Transmitting PDU CmdSN = %u, ExpStatSN = %u\n", 356 ntohl(pdu->pdu_hdr.pduh_p.command.CmdSN), 357 ntohl(pdu->pdu_hdr.pduh_p.command.ExpStatSN))); 358 my_soo_write(conn, &pdu->pdu_uio); 359 360 mutex_enter(&conn->c_lock); 361 pdisp = pdu->pdu_disp; 362 if (pdisp > PDUDISP_FREE) 363 pdu->pdu_flags &= ~PDUF_BUSY; 364 mutex_exit(&conn->c_lock); 365 if (pdisp <= PDUDISP_FREE) 366 free_pdu(pdu); 367 368 mutex_enter(&conn->c_lock); 369 } 370 371 if (!conn->c_terminating) 372 cv_wait(&conn->c_conn_cv, &conn->c_lock); 373 } 374 mutex_exit(&conn->c_lock); 375 376 /* ------------------------------------------------------------------------ 377 * Here this thread takes over cleanup of the terminating connection. 378 * ------------------------------------------------------------------------ 379 */ 380 connection_timeout_stop(conn); 381 conn->c_idle_timeout_val = CONNECTION_IDLE_TIMEOUT; 382 383 fp = conn->c_sock; 384 385 /* 386 * We shutdown the socket here to force the receive 387 * thread to wake up 388 */ 389 DEBC(conn, 1, ("Closing Socket %p\n", conn->c_sock)); 390 solock(fp->f_socket); 391 soshutdown(fp->f_socket, SHUT_RDWR); 392 sounlock(fp->f_socket); 393 394 /* wake up any non-reassignable waiting CCBs */ 395 TAILQ_FOREACH_SAFE(ccb, &conn->c_ccbs_waiting, ccb_chain, nccb) { 396 if (!(ccb->ccb_flags & CCBF_REASSIGN) || ccb->ccb_pdu_waiting == NULL) { 397 DEBC(conn, 1, ("Terminating CCB %p (t=%p)\n", 398 ccb,&ccb->ccb_timeout)); 399 wake_ccb(ccb, conn->c_terminating); 400 } else { 401 ccb_timeout_stop(ccb); 402 ccb->ccb_num_timeouts = 0; 403 } 404 } 405 406 /* clean out anything left in send queue */ 407 mutex_enter(&conn->c_lock); 408 while ((pdu = TAILQ_FIRST(&conn->c_pdus_to_send)) != NULL) { 409 TAILQ_REMOVE(&conn->c_pdus_to_send, pdu, pdu_send_chain); 410 pdu->pdu_flags &= ~(PDUF_INQUEUE | PDUF_BUSY); 411 mutex_exit(&conn->c_lock); 412 /* if it's not attached to a waiting CCB, free it */ 413 if (pdu->pdu_owner == NULL || 414 pdu->pdu_owner->ccb_pdu_waiting != pdu) { 415 free_pdu(pdu); 416 } 417 mutex_enter(&conn->c_lock); 418 } 419 mutex_exit(&conn->c_lock); 420 421 /* If there's another connection available, transfer pending tasks */ 422 if (sess->s_active_connections && 423 TAILQ_FIRST(&conn->c_ccbs_waiting) != NULL) { 424 425 reassign_tasks(conn); 426 } else if (!conn->c_destroy && conn->c_Time2Wait) { 427 DEBC(conn, 1, ("Time2Wait\n")); 428 kpause("Time2Wait", false, conn->c_Time2Wait * hz, NULL); 429 DEBC(conn, 1, ("Time2Wait\n")); 430 } 431 /* notify event handlers of connection shutdown */ 432 DEBC(conn, 1, ("%s\n", conn->c_destroy ? "TERMINATED" : "RECOVER")); 433 add_event(conn->c_destroy ? ISCSI_CONNECTION_TERMINATED 434 : ISCSI_RECOVER_CONNECTION, 435 sess->s_id, conn->c_id, conn->c_terminating); 436 437 DEBC(conn, 1, ("Waiting for conn_idle\n")); 438 mutex_enter(&conn->c_lock); 439 if (!conn->c_destroy) 440 cv_timedwait(&conn->c_idle_cv, &conn->c_lock, CONNECTION_IDLE_TIMEOUT); 441 mutex_exit(&conn->c_lock); 442 DEBC(conn, 1, ("Waited for conn_idle, destroy = %d\n", conn->c_destroy)); 443 444 } while (!conn->c_destroy); 445 446 /* wake up anyone waiting for a PDU */ 447 mutex_enter(&conn->c_lock); 448 cv_broadcast(&conn->c_conn_cv); 449 mutex_exit(&conn->c_lock); 450 451 /* wake up any waiting CCBs */ 452 while ((ccb = TAILQ_FIRST(&conn->c_ccbs_waiting)) != NULL) { 453 KASSERT(ccb->ccb_disp >= CCBDISP_NOWAIT); 454 wake_ccb(ccb, conn->c_terminating); 455 /* NOTE: wake_ccb will remove the CCB from the queue */ 456 } 457 458 add_connection_cleanup(conn); 459 460 conn->c_sendproc = NULL; 461 DEBC(conn, 1, ("Send thread exits\n")); 462 iscsi_num_send_threads--; 463 kthread_exit(0); 464} 465 466 467/* 468 * send_pdu: 469 * Enqueue a PDU to be sent, and handle its disposition as well as 470 * the disposition of its associated CCB. 471 * 472 * Parameter: 473 * ccb The associated CCB. May be NULL if cdisp is CCBDISP_NOWAIT 474 * and pdisp is not PDUDISP_WAIT 475 * cdisp The CCB's disposition 476 * pdu The PDU 477 * pdisp The PDU's disposition 478 */ 479 480STATIC void 481send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_disp_t cdisp, pdu_disp_t pdisp) 482{ 483 connection_t *conn = pdu->pdu_connection; 484 ccb_disp_t prev_cdisp = 0; 485 486 if (ccb != NULL) { 487 prev_cdisp = ccb->ccb_disp; 488 pdu->pdu_hdr.pduh_InitiatorTaskTag = ccb->ccb_ITT; 489 pdu->pdu_owner = ccb; 490 if (cdisp != CCBDISP_NOWAIT) 491 ccb->ccb_disp = cdisp; 492 } 493 494 pdu->pdu_disp = pdisp; 495 496 DEBC(conn, 10, ("Send_pdu: CmdSN=%u ExpStatSN~%u ccb=%p, pdu=%p\n", 497 ntohl(pdu->pdu_hdr.pduh_p.command.CmdSN), 498 conn->c_StatSN_buf.ExpSN, 499 ccb, pdu)); 500 501 mutex_enter(&conn->c_lock); 502 if (pdisp == PDUDISP_WAIT) { 503 KASSERT(ccb != NULL); 504 505 ccb->ccb_pdu_waiting = pdu; 506 507 /* save UIO and IOVEC for retransmit */ 508 pdu->pdu_save_uio = pdu->pdu_uio; 509 memcpy(pdu->pdu_save_iovec, pdu->pdu_io_vec, sizeof(pdu->pdu_save_iovec)); 510 511 pdu->pdu_flags |= PDUF_BUSY; 512 } 513 /* Enqueue for sending */ 514 pdu->pdu_flags |= PDUF_INQUEUE; 515 516 if (pdu->pdu_flags & PDUF_PRIORITY) 517 TAILQ_INSERT_HEAD(&conn->c_pdus_to_send, pdu, pdu_send_chain); 518 else 519 TAILQ_INSERT_TAIL(&conn->c_pdus_to_send, pdu, pdu_send_chain); 520 521 cv_broadcast(&conn->c_conn_cv); 522 523 if (cdisp != CCBDISP_NOWAIT) { 524 KASSERT(ccb != NULL); 525 KASSERTMSG(ccb->ccb_connection == conn, "conn mismatch %p != %p\n", ccb->ccb_connection, conn); 526 527 if (prev_cdisp <= CCBDISP_NOWAIT) 528 suspend_ccb(ccb, TRUE); 529 530 mutex_exit(&conn->c_lock); 531 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 532 mutex_enter(&conn->c_lock); 533 534 while (ccb->ccb_disp == CCBDISP_WAIT) { 535 DEBC(conn, 15, ("Send_pdu: ccb=%p cdisp=%d waiting\n", 536 ccb, ccb->ccb_disp)); 537 cv_wait(&conn->c_ccb_cv, &conn->c_lock); 538 DEBC(conn, 15, ("Send_pdu: ccb=%p cdisp=%d returned\n", 539 ccb, ccb->ccb_disp)); 540 } 541 } 542 543 mutex_exit(&conn->c_lock); 544} 545 546 547/* 548 * resend_pdu: 549 * Re-Enqueue a PDU that has apparently gotten lost. 550 * 551 * Parameter: 552 * ccb The associated CCB. 553 */ 554 555void 556resend_pdu(ccb_t *ccb) 557{ 558 connection_t *conn = ccb->ccb_connection; 559 pdu_t *pdu = ccb->ccb_pdu_waiting; 560 561 mutex_enter(&conn->c_lock); 562 if (pdu == NULL || (pdu->pdu_flags & PDUF_BUSY)) { 563 mutex_exit(&conn->c_lock); 564 return; 565 } 566 pdu->pdu_flags |= PDUF_BUSY; 567 mutex_exit(&conn->c_lock); 568 569 /* restore UIO and IOVEC */ 570 pdu->pdu_uio = pdu->pdu_save_uio; 571 memcpy(pdu->pdu_io_vec, pdu->pdu_save_iovec, sizeof(pdu->pdu_io_vec)); 572 573 DEBC(conn, 8, ("ReSend_pdu: CmdSN=%u ExpStatSN~%u ccb=%p, pdu=%p\n", 574 ntohl(pdu->pdu_hdr.pduh_p.command.CmdSN), 575 conn->c_StatSN_buf.ExpSN, 576 ccb, pdu)); 577 578 mutex_enter(&conn->c_lock); 579 /* Enqueue for sending */ 580 pdu->pdu_flags |= PDUF_INQUEUE; 581 582 if (pdu->pdu_flags & PDUF_PRIORITY) { 583 TAILQ_INSERT_HEAD(&conn->c_pdus_to_send, pdu, pdu_send_chain); 584 } else { 585 TAILQ_INSERT_TAIL(&conn->c_pdus_to_send, pdu, pdu_send_chain); 586 } 587 cv_broadcast(&conn->c_conn_cv); 588 mutex_exit(&conn->c_lock); 589 590 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 591} 592 593 594/* 595 * setup_tx_uio: 596 * Initialize the uio structure for sending, including header, 597 * data (if present), padding, and Data Digest. 598 * Header Digest is generated in send thread. 599 * 600 * Parameter: 601 * pdu The PDU 602 * dsl The Data Segment Length 603 * data The data pointer 604 * read TRUE if this is a read operation 605 */ 606 607STATIC void 608setup_tx_uio(pdu_t *pdu, uint32_t dsl, void *data, bool read) 609{ 610 static uint8_t pad_bytes[4] = { 0 }; 611 struct uio *uio; 612 int i, pad, hlen; 613 connection_t *conn = pdu->pdu_connection; 614 615 DEB(99, ("SetupTxUio: dlen = %d, dptr: %p, read: %d\n", 616 dsl, data, read)); 617 618 if (!read && dsl) { 619 hton3(dsl, pdu->pdu_hdr.pduh_DataSegmentLength); 620 } 621 hlen = (conn->c_HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE; 622 623 pdu->pdu_io_vec[0].iov_base = &pdu->pdu_hdr; 624 pdu->pdu_io_vec[0].iov_len = hlen; 625 626 uio = &pdu->pdu_uio; 627 628 uio->uio_iov = pdu->pdu_io_vec; 629 uio->uio_iovcnt = 1; 630 uio->uio_rw = UIO_WRITE; 631 uio->uio_resid = hlen; 632 UIO_SETUP_SYSSPACE(uio); 633 634 if (!read && dsl) { 635 uio->uio_iovcnt++; 636 pdu->pdu_io_vec[1].iov_base = data; 637 pdu->pdu_io_vec[1].iov_len = dsl; 638 uio->uio_resid += dsl; 639 640 /* Pad to next multiple of 4 */ 641 pad = uio->uio_resid & 0x03; 642 if (pad) { 643 i = uio->uio_iovcnt++; 644 pad = 4 - pad; 645 pdu->pdu_io_vec[i].iov_base = pad_bytes; 646 pdu->pdu_io_vec[i].iov_len = pad; 647 uio->uio_resid += pad; 648 } 649 650 if (conn->c_DataDigest) { 651 pdu->pdu_data_digest = gen_digest_2(data, dsl, pad_bytes, pad); 652 i = uio->uio_iovcnt++; 653 pdu->pdu_io_vec[i].iov_base = &pdu->pdu_data_digest; 654 pdu->pdu_io_vec[i].iov_len = 4; 655 uio->uio_resid += 4; 656 } 657 } 658} 659 660/* 661 * init_login_pdu: 662 * Initialize the login PDU. 663 * 664 * Parameter: 665 * conn The connection 666 * ccb The CCB 667 * pdu The PDU 668 */ 669 670STATIC void 671init_login_pdu(connection_t *conn, ccb_t *ccb, pdu_t *ppdu, bool next) 672{ 673 pdu_header_t *hpdu = &ppdu->pdu_hdr; 674 login_isid_t *isid = (login_isid_t *) & hpdu->pduh_LUN; 675 uint8_t c_phase; 676 677 hpdu->pduh_Opcode = IOP_Login_Request | OP_IMMEDIATE; 678 679 mutex_enter(&conn->c_session->s_lock); 680 ccb->ccb_CmdSN = get_sernum(conn->c_session, ppdu); 681 mutex_exit(&conn->c_session->s_lock); 682 683 if (next) { 684 c_phase = (hpdu->pduh_Flags >> CSG_SHIFT) & SG_MASK; 685 hpdu->pduh_Flags = FLAG_TRANSIT | (c_phase << CSG_SHIFT) | 686 NEXT_PHASE(c_phase); 687 } 688 689 DEB(99, ("InitLoginPdu: Flags=%x Phase=%x->%x\n", 690 hpdu->pduh_Flags, 691 (hpdu->pduh_Flags >> CSG_SHIFT) & SG_MASK, 692 hpdu->pduh_Flags & SG_MASK)); 693 694 memcpy(isid, &iscsi_InitiatorISID, 6); 695 isid->TSIH = conn->c_session->s_TSIH; 696 697 hpdu->pduh_p.login_req.CID = htons(conn->c_id); 698 hpdu->pduh_p.login_req.CmdSN = htonl(ccb->ccb_CmdSN); 699} 700 701 702/* 703 * negotiate_login: 704 * Control login negotiation. 705 * 706 * Parameter: 707 * conn The connection 708 * rx_pdu The received login response PDU 709 * tx_ccb The originally sent login CCB 710 */ 711 712void 713negotiate_login(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 714{ 715 int rc; 716 bool next = TRUE; 717 pdu_t *tx_pdu; 718 uint8_t c_phase; 719 720 if (rx_pdu->pdu_hdr.pduh_Flags & FLAG_TRANSIT) 721 c_phase = rx_pdu->pdu_hdr.pduh_Flags & SG_MASK; 722 else 723 c_phase = (rx_pdu->pdu_hdr.pduh_Flags >> CSG_SHIFT) & SG_MASK; 724 725 DEB(99, ("NegotiateLogin: Flags=%x Phase=%x\n", 726 rx_pdu->pdu_hdr.pduh_Flags, c_phase)); 727 728 if (c_phase == SG_FULL_FEATURE_PHASE) { 729 session_t *sess = conn->c_session; 730 731 if (!sess->s_TSIH) 732 sess->s_TSIH = ((login_isid_t *) &rx_pdu->pdu_hdr.pduh_LUN)->TSIH; 733 734 if (rx_pdu->pdu_temp_data != NULL) 735 assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, NULL); 736 737 /* negotiated values are now valid */ 738 set_negotiated_parameters(tx_ccb); 739 740 DEBC(conn, 5, ("Login Successful!\n")); 741 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS); 742 return; 743 } 744 745 tx_pdu = get_pdu(conn, TRUE); 746 if (tx_pdu == NULL) 747 return; 748 749 tx_pdu->pdu_hdr.pduh_Flags = c_phase << CSG_SHIFT; 750 751 switch (c_phase) { 752 case SG_SECURITY_NEGOTIATION: 753 rc = assemble_security_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 754 if (rc < 0) 755 next = FALSE; 756 break; 757 758 case SG_LOGIN_OPERATIONAL_NEGOTIATION: 759 760 if (conn->c_state == ST_SEC_FIN) { 761 762 /* 763 * Both sides announced to continue with 764 * operational negotation, but this is the 765 * last target packet from mutual CHAP 766 * that needs to be validated. 767 */ 768 rc = assemble_security_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 769 if (rc) 770 break; 771 772 /* 773 * Response was valid, drop (security) parameters 774 * so that we start negotiating operational 775 * parameters. 776 */ 777 rx_pdu->pdu_temp_data = NULL; 778 } 779 780 rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 781 break; 782 783 default: 784 DEBOUT(("Invalid phase %x in negotiate_login\n", c_phase)); 785 rc = ISCSI_STATUS_TARGET_ERROR; 786 break; 787 } 788 789 if (rc > 0) { 790 wake_ccb(tx_ccb, rc); 791 free_pdu(tx_pdu); 792 } else { 793 init_login_pdu(conn, tx_ccb, tx_pdu, next); 794 setup_tx_uio(tx_pdu, tx_pdu->pdu_temp_data_len, tx_pdu->pdu_temp_data, FALSE); 795 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 796 } 797} 798 799 800/* 801 * init_text_pdu: 802 * Initialize the text PDU. 803 * 804 * Parameter: 805 * conn The connection 806 * ccb The transmit CCB 807 * ppdu The transmit PDU 808 * rx_pdu The received PDU if this is an unsolicited negotiation 809 */ 810 811STATIC void 812init_text_pdu(connection_t *conn, ccb_t *ccb, pdu_t *ppdu, pdu_t *rx_pdu) 813{ 814 pdu_header_t *hpdu = &ppdu->pdu_hdr; 815 816 hpdu->pduh_Opcode = IOP_Text_Request | OP_IMMEDIATE; 817 hpdu->pduh_Flags = FLAG_FINAL; 818 819 mutex_enter(&conn->c_session->s_lock); 820 ccb->ccb_CmdSN = get_sernum(conn->c_session, ppdu); 821 mutex_exit(&conn->c_session->s_lock); 822 823 if (rx_pdu != NULL) { 824 hpdu->pduh_p.text_req.TargetTransferTag = 825 rx_pdu->pdu_hdr.pduh_p.text_rsp.TargetTransferTag; 826 hpdu->pduh_LUN = rx_pdu->pdu_hdr.pduh_LUN; 827 } else 828 hpdu->pduh_p.text_req.TargetTransferTag = 0xffffffff; 829 830 hpdu->pduh_p.text_req.CmdSN = htonl(ccb->ccb_CmdSN); 831} 832 833 834/* 835 * acknowledge_text: 836 * Acknowledge a continued login or text response. 837 * 838 * Parameter: 839 * conn The connection 840 * rx_pdu The received login/text response PDU 841 * tx_ccb The originally sent login/text request CCB 842 */ 843 844void 845acknowledge_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 846{ 847 pdu_t *tx_pdu; 848 849 tx_pdu = get_pdu(conn, TRUE); 850 if (tx_pdu == NULL) 851 return; 852 853 if (rx_pdu != NULL && 854 (rx_pdu->pdu_hdr.pduh_Opcode & OPCODE_MASK) == IOP_Login_Request) 855 init_login_pdu(conn, tx_ccb, tx_pdu, FALSE); 856 else 857 init_text_pdu(conn, tx_ccb, tx_pdu, rx_pdu); 858 859 setup_tx_uio(tx_pdu, 0, NULL, FALSE); 860 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 861} 862 863 864/* 865 * start_text_negotiation: 866 * Handle target request to negotiate (via asynch event) 867 * 868 * Parameter: 869 * conn The connection 870 */ 871 872void 873start_text_negotiation(connection_t *conn) 874{ 875 pdu_t *pdu; 876 ccb_t *ccb; 877 878 ccb = get_ccb(conn, TRUE); 879 if (ccb == NULL) 880 return; 881 pdu = get_pdu(conn, TRUE); 882 if (pdu == NULL) { 883 free_ccb(ccb); 884 return; 885 } 886 887 if (init_text_parameters(conn, ccb)) { 888 free_ccb(ccb); 889 free_pdu(pdu); 890 return; 891 } 892 893 init_text_pdu(conn, ccb, pdu, NULL); 894 setup_tx_uio(pdu, 0, NULL, FALSE); 895 send_pdu(ccb, pdu, CCBDISP_FREE, PDUDISP_WAIT); 896} 897 898 899/* 900 * negotiate_text: 901 * Handle received text negotiation. 902 * 903 * Parameter: 904 * conn The connection 905 * rx_pdu The received text response PDU 906 * tx_ccb The original CCB 907 */ 908 909void 910negotiate_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 911{ 912 int rc; 913 pdu_t *tx_pdu; 914 915 if (tx_ccb->ccb_flags & CCBF_SENDTARGET) { 916 if (!(rx_pdu->pdu_hdr.pduh_Flags & FLAG_FINAL)) { 917 handle_connection_error(conn, ISCSI_STATUS_PROTOCOL_ERROR, 918 LOGOUT_CONNECTION); 919 return; 920 } 921 /* transfer ownership of text to CCB */ 922 tx_ccb->ccb_text_data = rx_pdu->pdu_temp_data; 923 tx_ccb->ccb_text_len = rx_pdu->pdu_temp_data_len; 924 rx_pdu->pdu_temp_data = NULL; 925 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS); 926 } else { 927 if (!(rx_pdu->pdu_hdr.pduh_Flags & FLAG_FINAL)) 928 tx_pdu = get_pdu(conn, TRUE); 929 else 930 tx_pdu = NULL; 931 932 rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 933 if (rc) { 934 if (tx_pdu != NULL) 935 free_pdu(tx_pdu); 936 937 handle_connection_error(conn, rc, LOGOUT_CONNECTION); 938 } else if (tx_pdu != NULL) { 939 init_text_pdu(conn, tx_ccb, tx_pdu, rx_pdu); 940 setup_tx_uio(tx_pdu, tx_pdu->pdu_temp_data_len, 941 tx_pdu->pdu_temp_data, FALSE); 942 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 943 } else { 944 set_negotiated_parameters(tx_ccb); 945 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS); 946 } 947 } 948} 949 950 951/* 952 * send_send_targets: 953 * Send out a SendTargets text request. 954 * The result is stored in the fields in the session structure. 955 * 956 * Parameter: 957 * session The session 958 * key The text key to use 959 * 960 * Returns: 0 on success, else an error code. 961 */ 962 963int 964send_send_targets(session_t *sess, uint8_t *key) 965{ 966 ccb_t *ccb; 967 pdu_t *pdu; 968 int rc = 0; 969 connection_t *conn; 970 971 DEB(9, ("Send_send_targets\n")); 972 973 conn = assign_connection(sess, TRUE); 974 if (conn == NULL || conn->c_terminating || conn->c_state != ST_FULL_FEATURE) 975 return (conn != NULL && conn->c_terminating) ? conn->c_terminating 976 : ISCSI_STATUS_CONNECTION_FAILED; 977 978 ccb = get_ccb(conn, TRUE); 979 if (ccb == NULL) 980 return conn->c_terminating; 981 pdu = get_pdu(conn, TRUE); 982 if (pdu == NULL) { 983 free_ccb(ccb); 984 return conn->c_terminating; 985 } 986 987 ccb->ccb_flags |= CCBF_SENDTARGET; 988 989 if ((rc = assemble_send_targets(pdu, key)) != 0) { 990 free_ccb(ccb); 991 free_pdu(pdu); 992 return rc; 993 } 994 995 init_text_pdu(conn, ccb, pdu, NULL); 996 997 setup_tx_uio(pdu, pdu->pdu_temp_data_len, pdu->pdu_temp_data, FALSE); 998 send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_WAIT); 999 1000 rc = ccb->ccb_status; 1001 if (!rc) { 1002 /* transfer ownership of data */ 1003 sess->s_target_list = ccb->ccb_text_data; 1004 sess->s_target_list_len = ccb->ccb_text_len; 1005 ccb->ccb_text_data = NULL; 1006 } 1007 free_ccb(ccb); 1008 return rc; 1009} 1010 1011 1012/* 1013 * send_nop_out: 1014 * Send nop out request. 1015 * 1016 * Parameter: 1017 * conn The connection 1018 * rx_pdu The received Nop-In PDU 1019 * 1020 * Returns: 0 on success, else an error code. 1021 */ 1022 1023int 1024send_nop_out(connection_t *conn, pdu_t *rx_pdu) 1025{ 1026 session_t *sess; 1027 ccb_t *ccb; 1028 pdu_t *ppdu; 1029 pdu_header_t *hpdu; 1030 uint32_t sn; 1031 1032 if (rx_pdu != NULL) { 1033 ccb = NULL; 1034 ppdu = get_pdu(conn, TRUE); 1035 if (ppdu == NULL) 1036 return 1; 1037 } else { 1038 ccb = get_ccb(conn, FALSE); 1039 if (ccb == NULL) { 1040 DEBOUT(("Can't get CCB in send_nop_out\n")); 1041 return 1; 1042 } 1043 ppdu = get_pdu(conn, FALSE); 1044 if (ppdu == NULL) { 1045 free_ccb(ccb); 1046 DEBOUT(("Can't get PDU in send_nop_out\n")); 1047 return 1; 1048 } 1049 } 1050 1051 hpdu = &ppdu->pdu_hdr; 1052 hpdu->pduh_Flags = FLAG_FINAL; 1053 hpdu->pduh_Opcode = IOP_NOP_Out | OP_IMMEDIATE; 1054 1055 sess = conn->c_session; 1056 1057 mutex_enter(&sess->s_lock); 1058 sn = get_sernum(sess, ppdu); 1059 mutex_exit(&sess->s_lock); 1060 1061 if (rx_pdu != NULL) { 1062 hpdu->pduh_p.nop_out.TargetTransferTag = 1063 rx_pdu->pdu_hdr.pduh_p.nop_in.TargetTransferTag; 1064 hpdu->pduh_InitiatorTaskTag = rx_pdu->pdu_hdr.pduh_InitiatorTaskTag; 1065 hpdu->pduh_p.nop_out.CmdSN = htonl(sn); 1066 hpdu->pduh_LUN = rx_pdu->pdu_hdr.pduh_LUN; 1067 } else { 1068 hpdu->pduh_p.nop_out.TargetTransferTag = 0xffffffff; 1069 hpdu->pduh_InitiatorTaskTag = 0xffffffff; 1070 ccb->ccb_CmdSN = sn; 1071 hpdu->pduh_p.nop_out.CmdSN = htonl(sn); 1072 } 1073 1074 DEBC(conn, 10, ("Send NOP_Out CmdSN=%d, rx_pdu=%p\n", sn, rx_pdu)); 1075 1076 setup_tx_uio(ppdu, 0, NULL, FALSE); 1077 send_pdu(ccb, ppdu, (rx_pdu != NULL) ? CCBDISP_NOWAIT : CCBDISP_FREE, 1078 PDUDISP_FREE); 1079 return 0; 1080} 1081 1082 1083/* 1084 * snack_missing: 1085 * Send SNACK request for missing data. 1086 * 1087 * Parameter: 1088 * conn The connection 1089 * ccb The task's CCB (for Data NAK only) 1090 * type The SNACK type 1091 * BegRun The BegRun field 1092 * RunLength The RunLength field 1093 */ 1094 1095void 1096snack_missing(connection_t *conn, ccb_t *ccb, uint8_t type, 1097 uint32_t BegRun, uint32_t RunLength) 1098{ 1099 pdu_t *ppdu; 1100 pdu_header_t *hpdu; 1101 1102 ppdu = get_pdu(conn, TRUE); 1103 if (ppdu == NULL) 1104 return; 1105 hpdu = &ppdu->pdu_hdr; 1106 hpdu->pduh_Opcode = IOP_SNACK_Request; 1107 hpdu->pduh_Flags = FLAG_FINAL | type; 1108 1109 hpdu->pduh_InitiatorTaskTag = (type == SNACK_DATA_NAK) ? ccb->ccb_ITT : 0xffffffff; 1110 hpdu->pduh_p.snack.TargetTransferTag = 0xffffffff; 1111 hpdu->pduh_p.snack.BegRun = htonl(BegRun); 1112 hpdu->pduh_p.snack.RunLength = htonl(RunLength); 1113 1114 ppdu->pdu_flags = PDUF_PRIORITY; 1115 1116 setup_tx_uio(ppdu, 0, NULL, FALSE); 1117 send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE); 1118} 1119 1120 1121/* 1122 * send_snack: 1123 * Send SNACK request. 1124 * 1125 * Parameter: 1126 * conn The connection 1127 * rx_pdu The received data in PDU 1128 * tx_ccb The original command CCB (required for Data ACK only) 1129 * type The SNACK type 1130 * 1131 * Returns: 0 on success, else an error code. 1132 */ 1133 1134void 1135send_snack(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb, uint8_t type) 1136{ 1137 pdu_t *ppdu; 1138 pdu_header_t *hpdu; 1139 1140 ppdu = get_pdu(conn, TRUE); 1141 if (ppdu == NULL) 1142 return; 1143 hpdu = &ppdu->pdu_hdr; 1144 hpdu->pduh_Opcode = IOP_SNACK_Request; 1145 hpdu->pduh_Flags = FLAG_FINAL | type; 1146 1147 switch (type) { 1148 case SNACK_DATA_NAK: 1149 hpdu->pduh_InitiatorTaskTag = rx_pdu->pdu_hdr.pduh_InitiatorTaskTag; 1150 hpdu->pduh_p.snack.TargetTransferTag = 0xffffffff; 1151 hpdu->pduh_p.snack.BegRun = rx_pdu->pdu_hdr.pduh_p.data_in.DataSN; 1152 hpdu->pduh_p.snack.RunLength = htonl(1); 1153 break; 1154 1155 case SNACK_STATUS_NAK: 1156 hpdu->pduh_InitiatorTaskTag = 0xffffffff; 1157 hpdu->pduh_p.snack.TargetTransferTag = 0xffffffff; 1158 hpdu->pduh_p.snack.BegRun = rx_pdu->pdu_hdr.pduh_p.response.StatSN; 1159 hpdu->pduh_p.snack.RunLength = htonl(1); 1160 break; 1161 1162 case SNACK_DATA_ACK: 1163 hpdu->pduh_InitiatorTaskTag = 0xffffffff; 1164 hpdu->pduh_p.snack.TargetTransferTag = 1165 rx_pdu->pdu_hdr.pduh_p.data_in.TargetTransferTag; 1166 hpdu->pduh_p.snack.BegRun = tx_ccb->ccb_DataSN_buf.ExpSN; 1167 hpdu->pduh_p.snack.RunLength = 0; 1168 break; 1169 1170 default: 1171 DEBOUT(("Invalid type %d in send_snack\n", type)); 1172 return; 1173 } 1174 1175 hpdu->pduh_LUN = rx_pdu->pdu_hdr.pduh_LUN; 1176 1177 ppdu->pdu_flags = PDUF_PRIORITY; 1178 1179 setup_tx_uio(ppdu, 0, NULL, FALSE); 1180 send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE); 1181} 1182 1183 1184/* 1185 * send_login: 1186 * Send login request. 1187 * 1188 * Parameter: 1189 * conn The connection 1190 * par The login parameters (for negotiation) 1191 * 1192 * Returns: 0 on success, else an error code. 1193 */ 1194 1195int 1196send_login(connection_t *conn) 1197{ 1198 ccb_t *ccb; 1199 pdu_t *pdu; 1200 int rc; 1201 1202 DEBC(conn, 9, ("Send_login\n")); 1203 ccb = get_ccb(conn, TRUE); 1204 /* only if terminating (which couldn't possibly happen here, but...) */ 1205 if (ccb == NULL) 1206 return conn->c_terminating; 1207 pdu = get_pdu(conn, TRUE); 1208 if (pdu == NULL) { 1209 free_ccb(ccb); 1210 return conn->c_terminating; 1211 } 1212 1213 if ((rc = assemble_login_parameters(conn, ccb, pdu)) <= 0) { 1214 init_login_pdu(conn, ccb, pdu, !rc); 1215 setup_tx_uio(pdu, pdu->pdu_temp_data_len, pdu->pdu_temp_data, FALSE); 1216 send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_FREE); 1217 rc = ccb->ccb_status; 1218 } else { 1219 free_pdu(pdu); 1220 } 1221 free_ccb(ccb); 1222 return rc; 1223} 1224 1225 1226/* 1227 * send_logout: 1228 * Send logout request. 1229 * NOTE: This function does not wait for the logout to complete. 1230 * 1231 * Parameter: 1232 * conn The connection 1233 * refconn The referenced connection 1234 * reason The reason code 1235 * wait Wait for completion if TRUE 1236 * 1237 * Returns: 0 on success (logout sent), else an error code. 1238 */ 1239 1240int 1241send_logout(connection_t *conn, connection_t *refconn, int reason, 1242 bool wait) 1243{ 1244 ccb_t *ccb; 1245 pdu_t *ppdu; 1246 pdu_header_t *hpdu; 1247 1248 DEBC(conn, 5, ("Send_logout\n")); 1249 ccb = get_ccb(conn, TRUE); 1250 /* can only happen if terminating... */ 1251 if (ccb == NULL) 1252 return conn->c_terminating; 1253 ppdu = get_pdu(conn, TRUE); 1254 if (ppdu == NULL) { 1255 free_ccb(ccb); 1256 return conn->c_terminating; 1257 } 1258 1259 hpdu = &ppdu->pdu_hdr; 1260 hpdu->pduh_Opcode = IOP_Logout_Request | OP_IMMEDIATE; 1261 1262 hpdu->pduh_Flags = FLAG_FINAL | reason; 1263 ccb->ccb_CmdSN = conn->c_session->s_CmdSN; 1264 hpdu->pduh_p.logout_req.CmdSN = htonl(ccb->ccb_CmdSN); 1265 if (reason > 0) 1266 hpdu->pduh_p.logout_req.CID = htons(refconn->c_id); 1267 1268 ccb->ccb_par = refconn; 1269 if (refconn != conn) { 1270 ccb->ccb_flags |= CCBF_OTHERCONN; 1271 } else { 1272 conn->c_state = ST_LOGOUT_SENT; 1273 conn->c_loggedout = LOGOUT_SENT; 1274 } 1275 1276 setup_tx_uio(ppdu, 0, NULL, FALSE); 1277 send_pdu(ccb, ppdu, (wait) ? CCBDISP_WAIT : CCBDISP_FREE, PDUDISP_FREE); 1278 1279 if (wait) { 1280 int rc = ccb->ccb_status; 1281 free_ccb (ccb); 1282 return rc; 1283 } 1284 return 0; 1285} 1286 1287 1288/* 1289 * send_task_management: 1290 * Send task management request. 1291 * 1292 * Parameter: 1293 * conn The connection 1294 * ref_ccb The referenced command (NULL if none) 1295 * xs The scsipi command structure (NULL if not a scsipi request) 1296 * function The function code 1297 * 1298 * Returns: 0 on success, else an error code. 1299 */ 1300 1301int 1302send_task_management(connection_t *conn, ccb_t *ref_ccb, struct scsipi_xfer *xs, 1303 int function) 1304{ 1305 ccb_t *ccb; 1306 pdu_t *ppdu; 1307 pdu_header_t *hpdu; 1308 1309 DEBC(conn, 5, ("Send_task_management, ref_ccb=%p, func = %d\n", 1310 ref_ccb, function)); 1311 1312 if (function == TASK_REASSIGN && conn->c_session->s_ErrorRecoveryLevel < 2) 1313 return ISCSI_STATUS_CANT_REASSIGN; 1314 1315 ccb = get_ccb(conn, xs == NULL); 1316 /* can only happen if terminating... */ 1317 if (ccb == NULL) { 1318 DEBC(conn, 0, ("send_task_management, ref_ccb=%p, xs=%p, term=%d. No CCB\n", 1319 ref_ccb, xs, conn->c_terminating)); 1320 return conn->c_terminating; 1321 } 1322 ppdu = get_pdu(conn, xs == NULL); 1323 if (ppdu == NULL) { 1324 DEBC(conn, 0, ("send_task_management, ref_ccb=%p, xs=%p, term=%d. No PDU\n", 1325 ref_ccb, xs, conn->c_terminating)); 1326 free_ccb(ccb); 1327 return conn->c_terminating; 1328 } 1329 1330 ccb->ccb_xs = xs; 1331 1332 hpdu = &ppdu->pdu_hdr; 1333 hpdu->pduh_Opcode = IOP_SCSI_Task_Management | OP_IMMEDIATE; 1334 hpdu->pduh_Flags = FLAG_FINAL | function; 1335 1336 ccb->ccb_CmdSN = conn->c_session->s_CmdSN; 1337 hpdu->pduh_p.task_req.CmdSN = htonl(ccb->ccb_CmdSN); 1338 1339 if (ref_ccb != NULL) { 1340 hpdu->pduh_p.task_req.ReferencedTaskTag = ref_ccb->ccb_ITT; 1341 hpdu->pduh_p.task_req.RefCmdSN = htonl(ref_ccb->ccb_CmdSN); 1342 hpdu->pduh_p.task_req.ExpDataSN = htonl(ref_ccb->ccb_DataSN_buf.ExpSN); 1343 } else 1344 hpdu->pduh_p.task_req.ReferencedTaskTag = 0xffffffff; 1345 1346 ppdu->pdu_flags |= PDUF_PRIORITY; 1347 1348 setup_tx_uio(ppdu, 0, NULL, FALSE); 1349 send_pdu(ccb, ppdu, (xs) ? CCBDISP_SCSIPI : CCBDISP_WAIT, PDUDISP_FREE); 1350 1351 if (xs == NULL) { 1352 int rc = ccb->ccb_status; 1353 free_ccb(ccb); 1354 return rc; 1355 } 1356 return 0; 1357} 1358 1359 1360/* 1361 * send_data_out: 1362 * Send data to target in response to an R2T or as unsolicited data. 1363 * 1364 * Parameter: 1365 * conn The connection 1366 * rx_pdu The received R2T PDU (NULL if unsolicited) 1367 * tx_ccb The originally sent command CCB 1368 * waitok Whether it's OK to wait for an available PDU or not 1369 */ 1370 1371int 1372send_data_out(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb, 1373 ccb_disp_t disp, bool waitok) 1374{ 1375 pdu_header_t *hpdu; 1376 uint32_t totlen, len, offs, sn; 1377 pdu_t *tx_pdu; 1378 1379 KASSERT(conn->c_max_transfer != 0); 1380 1381 if (rx_pdu) { 1382 offs = ntohl(rx_pdu->pdu_hdr.pduh_p.r2t.BufferOffset); 1383 totlen = ntohl(rx_pdu->pdu_hdr.pduh_p.r2t.DesiredDataTransferLength); 1384 } else { 1385 offs = conn->c_max_firstimmed; 1386 totlen = min(conn->c_max_firstdata - offs, tx_ccb->ccb_data_len - offs); 1387 } 1388 sn = 0; 1389 1390 while (totlen) { 1391 len = min(totlen, conn->c_max_transfer); 1392 1393 tx_pdu = get_pdu(conn, waitok); 1394 if (tx_pdu == NULL) { 1395 DEBC(conn, 5, ("No PDU in send_data_out\n")); 1396 1397 tx_ccb->ccb_disp = disp; 1398 tx_ccb->ccb_status = ISCSI_STATUS_NO_RESOURCES; 1399 handle_connection_error(conn, ISCSI_STATUS_NO_RESOURCES, NO_LOGOUT); 1400 1401 return ISCSI_STATUS_NO_RESOURCES; 1402 } 1403 1404 totlen -= len; 1405 hpdu = &tx_pdu->pdu_hdr; 1406 hpdu->pduh_Opcode = IOP_SCSI_Data_out; 1407 if (!totlen) 1408 hpdu->pduh_Flags = FLAG_FINAL; 1409 1410 if (rx_pdu != NULL) 1411 hpdu->pduh_p.data_out.TargetTransferTag = 1412 rx_pdu->pdu_hdr.pduh_p.r2t.TargetTransferTag; 1413 else 1414 hpdu->pduh_p.data_out.TargetTransferTag = 0xffffffff; 1415 hpdu->pduh_p.data_out.BufferOffset = htonl(offs); 1416 hpdu->pduh_p.data_out.DataSN = htonl(sn); 1417 1418 DEBC(conn, 10, ("Send DataOut: DataSN %d, len %d offs %x totlen %d\n", 1419 sn, len, offs, totlen)); 1420 1421 setup_tx_uio(tx_pdu, len, tx_ccb->ccb_data_ptr + offs, FALSE); 1422 send_pdu(tx_ccb, tx_pdu, (totlen) ? CCBDISP_NOWAIT : disp, PDUDISP_FREE); 1423 1424 sn++; 1425 offs += len; 1426 } 1427 return 0; 1428} 1429 1430 1431/* 1432 * send_command: 1433 * Send a SCSI command request. 1434 * 1435 * Parameter: 1436 * CCB The CCB 1437 * disp The CCB disposition 1438 */ 1439 1440void 1441send_command(ccb_t *ccb, ccb_disp_t disp, bool waitok, bool immed) 1442{ 1443 uint32_t totlen, len; 1444 connection_t *conn = ccb->ccb_connection; 1445 session_t *sess = ccb->ccb_session; 1446 pdu_t *ppdu; 1447 pdu_header_t *hpdu; 1448 1449 mutex_enter(&sess->s_lock); 1450 while (!sernum_in_window(sess)) { 1451 mutex_exit(&sess->s_lock); 1452 ccb->ccb_disp = disp; 1453 wake_ccb(ccb, ISCSI_STATUS_QUEUE_FULL); 1454 return; 1455 } 1456 mutex_exit(&sess->s_lock); 1457 1458 /* Don't confuse targets during (re-)negotations */ 1459 if (conn->c_state != ST_FULL_FEATURE) { 1460 DEBOUT(("Invalid connection for send_command, ccb = %p\n",ccb)); 1461 ccb->ccb_disp = disp; 1462 wake_ccb(ccb, ISCSI_STATUS_TARGET_BUSY); 1463 return; 1464 } 1465 1466 ppdu = get_pdu(conn, waitok); 1467 if (ppdu == NULL) { 1468 DEBOUT(("No PDU for send_command, ccb = %p\n",ccb)); 1469 ccb->ccb_disp = disp; 1470 wake_ccb(ccb, ISCSI_STATUS_NO_RESOURCES); 1471 return; 1472 } 1473 1474 totlen = len = ccb->ccb_data_len; 1475 1476 hpdu = &ppdu->pdu_hdr; 1477 hpdu->pduh_LUN = htonq(ccb->ccb_lun); 1478 memcpy(hpdu->pduh_p.command.SCSI_CDB, ccb->ccb_cmd, ccb->ccb_cmdlen); 1479 hpdu->pduh_Opcode = IOP_SCSI_Command; 1480 if (immed) 1481 hpdu->pduh_Opcode |= OP_IMMEDIATE; 1482 hpdu->pduh_p.command.ExpectedDataTransferLength = htonl(totlen); 1483 1484 if (totlen) { 1485 if (ccb->ccb_data_in) { 1486 hpdu->pduh_Flags = FLAG_READ; 1487 totlen = 0; 1488 } else { 1489 hpdu->pduh_Flags = FLAG_WRITE; 1490 /* immediate data we can send */ 1491 len = min(totlen, conn->c_max_firstimmed); 1492 1493 /* can we send more unsolicited data ? */ 1494 totlen = conn->c_max_firstdata ? totlen - len : 0; 1495 } 1496 } 1497 if (!totlen) 1498 hpdu->pduh_Flags |= FLAG_FINAL; 1499 hpdu->pduh_Flags |= ccb->ccb_tag; 1500 1501 if (ccb->ccb_data_in) 1502 init_sernum(&ccb->ccb_DataSN_buf); 1503 1504 ccb->ccb_sense_len_got = 0; 1505 ccb->ccb_xfer_len = 0; 1506 ccb->ccb_residual = 0; 1507 ccb->ccb_flags |= CCBF_REASSIGN; 1508 1509 mutex_enter(&sess->s_lock); 1510 ccb->ccb_CmdSN = get_sernum(sess, ppdu); 1511 mutex_exit(&sess->s_lock); 1512 1513 hpdu->pduh_p.command.CmdSN = htonl(ccb->ccb_CmdSN); 1514 1515 DEBC(conn, 10, ("Send Command: CmdSN %d (%d), data_in %d, len %d, totlen %d\n", 1516 ccb->ccb_CmdSN, sess->s_MaxCmdSN, ccb->ccb_data_in, len, totlen)); 1517 1518 setup_tx_uio(ppdu, len, ccb->ccb_data_ptr, ccb->ccb_data_in); 1519 send_pdu(ccb, ppdu, (totlen) ? CCBDISP_DEFER : disp, PDUDISP_WAIT); 1520 1521 if (totlen) 1522 send_data_out(conn, NULL, ccb, disp, waitok); 1523} 1524 1525 1526/* 1527 * send_run_xfer: 1528 * Handle a SCSI command transfer request from scsipi. 1529 * 1530 * Parameter: 1531 * session The session 1532 * xs The transfer parameters 1533 */ 1534 1535void 1536send_run_xfer(session_t *session, struct scsipi_xfer *xs) 1537{ 1538 ccb_t *ccb; 1539 connection_t *conn; 1540 bool waitok; 1541 1542 waitok = !(xs->xs_control & XS_CTL_NOSLEEP); 1543 1544 DEB(10, ("RunXfer: flags=%x, data=%p, datalen=%d, resid=%d, cmdlen=%d, " 1545 "waitok=%d\n", xs->xs_control, xs->data, xs->datalen, 1546 xs->resid, xs->cmdlen, waitok)); 1547 1548 conn = assign_connection(session, waitok); 1549 1550 if (conn == NULL || conn->c_terminating || conn->c_state != ST_FULL_FEATURE) { 1551 if (session->s_terminating) 1552 xs->error = XS_SELTIMEOUT; 1553 else 1554 xs->error = XS_BUSY; 1555 DEBC(conn, 10, ("run_xfer on dead connection\n")); 1556 scsipi_done(xs); 1557 unref_session(session); 1558 return; 1559 } 1560 1561 if (xs->xs_control & XS_CTL_RESET) { 1562 if (send_task_management(conn, NULL, xs, TARGET_WARM_RESET)) { 1563 DEBC(conn, 0, ("send_task_management TARGET_WARM_RESET failed\n")); 1564 xs->error = XS_SELTIMEOUT; 1565 scsipi_done(xs); 1566 unref_session(session); 1567 } 1568 return; 1569 } 1570 1571 ccb = get_ccb(conn, waitok); 1572 if (ccb == NULL) { 1573 xs->error = XS_BUSY; 1574 DEBC(conn, 5, ("No CCB in run_xfer, %d in use.\n", conn->c_usecount)); 1575 scsipi_done(xs); 1576 unref_session(session); 1577 return; 1578 } 1579 /* copy parameters into CCB for easier access */ 1580 ccb->ccb_xs = xs; 1581 1582 ccb->ccb_data_in = (xs->xs_control & XS_CTL_DATA_IN) != 0; 1583 ccb->ccb_data_len = (uint32_t) xs->datalen; 1584 ccb->ccb_data_ptr = xs->data; 1585 1586 ccb->ccb_sense_len_req = sizeof(xs->sense.scsi_sense); 1587 ccb->ccb_sense_ptr = &xs->sense; 1588 1589 ccb->ccb_lun = ((uint64_t) (uint8_t) xs->xs_periph->periph_lun) << 48; 1590 ccb->ccb_cmd = (uint8_t *) xs->cmd; 1591 ccb->ccb_cmdlen = xs->cmdlen; 1592 DEB(10, ("RunXfer: Periph_lun = %d, cmd[1] = %x, cmdlen = %d\n", 1593 xs->xs_periph->periph_lun, ccb->ccb_cmd[1], xs->cmdlen)); 1594 1595 ccb->ccb_ITT |= xs->xs_tag_id << 24; 1596 switch (xs->xs_tag_type) { 1597 case MSG_ORDERED_Q_TAG: 1598 ccb->ccb_tag = ATTR_ORDERED; 1599 break; 1600 case MSG_SIMPLE_Q_TAG: 1601 ccb->ccb_tag = ATTR_SIMPLE; 1602 break; 1603 case MSG_HEAD_OF_Q_TAG: 1604 ccb->ccb_tag = ATTR_HEAD_OF_QUEUE; 1605 break; 1606 default: 1607 ccb->ccb_tag = 0; 1608 break; 1609 } 1610 1611#ifdef LUN_1 1612 ccb->ccb_lun += 0x1000000000000LL; 1613 ccb->ccb_cmd[1] += 0x10; 1614#endif 1615 send_command(ccb, CCBDISP_SCSIPI, waitok, FALSE); 1616} 1617 1618 1619#ifndef ISCSI_MINIMAL 1620/* 1621 * send_io_command: 1622 * Handle a SCSI io command request from user space. 1623 * 1624 * Parameter: 1625 * session The session 1626 * lun The LUN to use 1627 * req The SCSI request block 1628 * immed Immediate command if TRUE 1629 * conn_id Assign to this connection ID if nonzero 1630 */ 1631 1632int 1633send_io_command(session_t *session, uint64_t lun, scsireq_t *req, 1634 bool immed, uint32_t conn_id) 1635{ 1636 ccb_t *ccb; 1637 connection_t *conn; 1638 int rc; 1639 1640 DEB(9, ("IoCommand: lun=%x, datalen=%d, cmdlen=%d, immed=%d, cid=%d\n", 1641 (int) lun, (int) req->datalen, (int) req->cmdlen, immed, conn_id)); 1642 1643 conn = (conn_id) ? find_connection(session, conn_id) 1644 : assign_connection(session, TRUE); 1645 1646 if (conn == NULL || conn->c_terminating || conn->c_state != ST_FULL_FEATURE) { 1647 DEBOUT(("io_command on dead connection (state = %d)\n", 1648 (conn != NULL) ? conn->c_state : -1)); 1649 return ISCSI_STATUS_INVALID_CONNECTION_ID; 1650 } 1651 1652 ccb = get_ccb(conn, TRUE); 1653 if (ccb == NULL) { 1654 DEBOUT(("No CCB in io_command\n")); 1655 return ISCSI_STATUS_NO_RESOURCES; 1656 } 1657 1658 ccb->ccb_data_in = (req->flags & SCCMD_READ) != 0; 1659 ccb->ccb_data_len = (uint32_t) req->datalen; 1660 ccb->ccb_data_ptr = req->databuf; 1661 1662 ccb->ccb_sense_len_req = req->senselen; 1663 ccb->ccb_sense_ptr = &req->sense; 1664 1665 ccb->ccb_lun = lun; 1666 ccb->ccb_cmd = (uint8_t *) req->cmd; 1667 ccb->ccb_cmdlen = req->cmdlen; 1668 DEBC(conn, 10, ("IoCommand: cmd[1] = %x, cmdlen = %d\n", 1669 ccb->ccb_cmd[1], ccb->ccb_cmdlen)); 1670 1671 send_command(ccb, CCBDISP_WAIT, TRUE, immed); 1672 1673 rc = ccb->ccb_status; 1674 1675 req->senselen_used = ccb->ccb_sense_len_got; 1676 req->datalen_used = req->datalen - ccb->ccb_residual; 1677 1678 free_ccb(ccb); 1679 1680 return rc; 1681} 1682#endif 1683 1684 1685/***************************************************************************** 1686 * Timeout handlers 1687 *****************************************************************************/ 1688/* 1689 * connection_timeout: 1690 * Handle prolonged silence on a connection by checking whether 1691 * it's still alive. 1692 * This has the side effect of discovering missing status or lost commands 1693 * before those time out. 1694 * 1695 * Parameter: 1696 * conn The connection 1697 */ 1698 1699void 1700connection_timeout(connection_t *conn) 1701{ 1702 if (++conn->c_num_timeouts > MAX_CONN_TIMEOUTS) { 1703 DEBC(conn, 1, ("connection timeout %d\n", conn->c_num_timeouts)); 1704 handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, NO_LOGOUT); 1705 } else { 1706 if (conn->c_state == ST_FULL_FEATURE) 1707 send_nop_out(conn, NULL); 1708 1709 connection_timeout_start(conn, CONNECTION_TIMEOUT); 1710 } 1711} 1712 1713/* 1714 * ccb_timeout: 1715 * Handle timeout of a sent command. 1716 * 1717 * Parameter: 1718 * ccb The CCB 1719 */ 1720 1721void 1722ccb_timeout(ccb_t *ccb) 1723{ 1724 connection_t *conn = ccb->ccb_connection; 1725 1726 ccb->ccb_total_tries++; 1727 1728 DEBC(conn, 0, ("ccb_timeout: num=%d total=%d disp=%d\n", 1729 ccb->ccb_num_timeouts+1, ccb->ccb_total_tries, ccb->ccb_disp)); 1730 1731 /* 1732 * XXX can we time out after connection is closed ? 1733 */ 1734 if (conn == NULL) { 1735 wake_ccb(ccb, ISCSI_STATUS_TIMEOUT); 1736 return; 1737 } 1738 1739 if (++ccb->ccb_num_timeouts > MAX_CCB_TIMEOUTS || 1740 ccb->ccb_total_tries > MAX_CCB_TRIES || 1741 ccb->ccb_disp <= CCBDISP_FREE || 1742 !ccb->ccb_session->s_ErrorRecoveryLevel) { 1743 1744 wake_ccb(ccb, ISCSI_STATUS_TIMEOUT); 1745 handle_connection_error(conn, 1746 ISCSI_STATUS_TIMEOUT, RECOVER_CONNECTION); 1747 } else { 1748 if (ccb->ccb_data_in && ccb->ccb_xfer_len < ccb->ccb_data_len) { 1749 /* request resend of all missing data */ 1750 snack_missing(conn, ccb, SNACK_DATA_NAK, 0, 0); 1751 } else { 1752 /* request resend of all missing status */ 1753 snack_missing(conn, NULL, SNACK_STATUS_NAK, 0, 0); 1754 } 1755 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 1756 } 1757} 1758 1759