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