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