1 /* $NetBSD: iscsi_send.c,v 1.36 2017/12/03 19:07:10 christos 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 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 552 cv_broadcast(&conn->c_conn_cv); 553 mutex_exit(&conn->c_lock); 554 } 555 556 557 /* 558 * setup_tx_uio: 559 * Initialize the uio structure for sending, including header, 560 * data (if present), padding, and Data Digest. 561 * Header Digest is generated in send thread. 562 * 563 * Parameter: 564 * pdu The PDU 565 * dsl The Data Segment Length 566 * data The data pointer 567 * read TRUE if this is a read operation 568 */ 569 570 STATIC void 571 setup_tx_uio(pdu_t *pdu, uint32_t dsl, void *data, bool read) 572 { 573 static uint8_t pad_bytes[4] = { 0 }; 574 struct uio *uio; 575 int i, pad, hlen; 576 connection_t *conn = pdu->pdu_connection; 577 578 DEB(99, ("SetupTxUio: dlen = %d, dptr: %p, read: %d\n", 579 dsl, data, read)); 580 581 if (!read && dsl) { 582 hton3(dsl, pdu->pdu_hdr.pduh_DataSegmentLength); 583 } 584 hlen = (conn->c_HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE; 585 586 pdu->pdu_io_vec[0].iov_base = &pdu->pdu_hdr; 587 pdu->pdu_io_vec[0].iov_len = hlen; 588 589 uio = &pdu->pdu_uio; 590 591 uio->uio_iov = pdu->pdu_io_vec; 592 uio->uio_iovcnt = 1; 593 uio->uio_rw = UIO_WRITE; 594 uio->uio_resid = hlen; 595 UIO_SETUP_SYSSPACE(uio); 596 597 if (!read && dsl) { 598 uio->uio_iovcnt++; 599 pdu->pdu_io_vec[1].iov_base = data; 600 pdu->pdu_io_vec[1].iov_len = dsl; 601 uio->uio_resid += dsl; 602 603 /* Pad to next multiple of 4 */ 604 pad = uio->uio_resid & 0x03; 605 if (pad) { 606 i = uio->uio_iovcnt++; 607 pad = 4 - pad; 608 pdu->pdu_io_vec[i].iov_base = pad_bytes; 609 pdu->pdu_io_vec[i].iov_len = pad; 610 uio->uio_resid += pad; 611 } 612 613 if (conn->c_DataDigest) { 614 pdu->pdu_data_digest = gen_digest_2(data, dsl, pad_bytes, pad); 615 i = uio->uio_iovcnt++; 616 pdu->pdu_io_vec[i].iov_base = &pdu->pdu_data_digest; 617 pdu->pdu_io_vec[i].iov_len = 4; 618 uio->uio_resid += 4; 619 } 620 } 621 } 622 623 /* 624 * init_login_pdu: 625 * Initialize the login PDU. 626 * 627 * Parameter: 628 * conn The connection 629 * ccb The CCB 630 * pdu The PDU 631 */ 632 633 STATIC void 634 init_login_pdu(connection_t *conn, ccb_t *ccb, pdu_t *ppdu, bool next) 635 { 636 pdu_header_t *hpdu = &ppdu->pdu_hdr; 637 login_isid_t *isid = (login_isid_t *) & hpdu->pduh_LUN; 638 uint8_t c_phase; 639 640 hpdu->pduh_Opcode = IOP_Login_Request | OP_IMMEDIATE; 641 642 mutex_enter(&conn->c_session->s_lock); 643 ccb->ccb_CmdSN = get_sernum(conn->c_session, ppdu); 644 mutex_exit(&conn->c_session->s_lock); 645 646 if (next) { 647 c_phase = (hpdu->pduh_Flags >> CSG_SHIFT) & SG_MASK; 648 hpdu->pduh_Flags = FLAG_TRANSIT | (c_phase << CSG_SHIFT) | 649 NEXT_PHASE(c_phase); 650 } 651 652 memcpy(isid, &iscsi_InitiatorISID, 6); 653 isid->TSIH = conn->c_session->s_TSIH; 654 655 hpdu->pduh_p.login_req.CID = htons(conn->c_id); 656 hpdu->pduh_p.login_req.CmdSN = htonl(ccb->ccb_CmdSN); 657 } 658 659 660 /* 661 * negotiate_login: 662 * Control login negotiation. 663 * 664 * Parameter: 665 * conn The connection 666 * rx_pdu The received login response PDU 667 * tx_ccb The originally sent login CCB 668 */ 669 670 void 671 negotiate_login(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 672 { 673 int rc; 674 bool next = TRUE; 675 pdu_t *tx_pdu; 676 uint8_t c_phase; 677 678 if (rx_pdu->pdu_hdr.pduh_Flags & FLAG_TRANSIT) 679 c_phase = rx_pdu->pdu_hdr.pduh_Flags & SG_MASK; 680 else 681 c_phase = (rx_pdu->pdu_hdr.pduh_Flags >> CSG_SHIFT) & SG_MASK; 682 683 DEB(99, ("NegotiateLogin: Flags=%x Phase=%x\n", 684 rx_pdu->pdu_hdr.pduh_Flags, c_phase)); 685 686 if (c_phase == SG_FULL_FEATURE_PHASE) { 687 session_t *sess = conn->c_session; 688 689 if (!sess->s_TSIH) 690 sess->s_TSIH = ((login_isid_t *) &rx_pdu->pdu_hdr.pduh_LUN)->TSIH; 691 692 if (rx_pdu->pdu_temp_data != NULL) 693 assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, NULL); 694 695 /* negotiated values are now valid */ 696 set_negotiated_parameters(tx_ccb); 697 698 DEBC(conn, 5, ("Login Successful!\n")); 699 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS); 700 return; 701 } 702 703 tx_pdu = get_pdu(conn, TRUE); 704 if (tx_pdu == NULL) 705 return; 706 707 tx_pdu->pdu_hdr.pduh_Flags = c_phase << CSG_SHIFT; 708 709 switch (c_phase) { 710 case SG_SECURITY_NEGOTIATION: 711 rc = assemble_security_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 712 if (rc < 0) 713 next = FALSE; 714 break; 715 716 case SG_LOGIN_OPERATIONAL_NEGOTIATION: 717 rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 718 break; 719 720 default: 721 DEBOUT(("Invalid phase %x in negotiate_login\n", c_phase)); 722 rc = ISCSI_STATUS_TARGET_ERROR; 723 break; 724 } 725 726 if (rc > 0) { 727 wake_ccb(tx_ccb, rc); 728 free_pdu(tx_pdu); 729 } else { 730 init_login_pdu(conn, tx_ccb, tx_pdu, next); 731 setup_tx_uio(tx_pdu, tx_pdu->pdu_temp_data_len, tx_pdu->pdu_temp_data, FALSE); 732 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 733 } 734 } 735 736 737 /* 738 * init_text_pdu: 739 * Initialize the text PDU. 740 * 741 * Parameter: 742 * conn The connection 743 * ccb The transmit CCB 744 * ppdu The transmit PDU 745 * rx_pdu The received PDU if this is an unsolicited negotiation 746 */ 747 748 STATIC void 749 init_text_pdu(connection_t *conn, ccb_t *ccb, pdu_t *ppdu, pdu_t *rx_pdu) 750 { 751 pdu_header_t *hpdu = &ppdu->pdu_hdr; 752 753 hpdu->pduh_Opcode = IOP_Text_Request | OP_IMMEDIATE; 754 hpdu->pduh_Flags = FLAG_FINAL; 755 756 mutex_enter(&conn->c_session->s_lock); 757 ccb->ccb_CmdSN = get_sernum(conn->c_session, ppdu); 758 mutex_exit(&conn->c_session->s_lock); 759 760 if (rx_pdu != NULL) { 761 hpdu->pduh_p.text_req.TargetTransferTag = 762 rx_pdu->pdu_hdr.pduh_p.text_rsp.TargetTransferTag; 763 hpdu->pduh_LUN = rx_pdu->pdu_hdr.pduh_LUN; 764 } else 765 hpdu->pduh_p.text_req.TargetTransferTag = 0xffffffff; 766 767 hpdu->pduh_p.text_req.CmdSN = htonl(ccb->ccb_CmdSN); 768 } 769 770 771 /* 772 * acknowledge_text: 773 * Acknowledge a continued login or text response. 774 * 775 * Parameter: 776 * conn The connection 777 * rx_pdu The received login/text response PDU 778 * tx_ccb The originally sent login/text request CCB 779 */ 780 781 void 782 acknowledge_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 783 { 784 pdu_t *tx_pdu; 785 786 tx_pdu = get_pdu(conn, TRUE); 787 if (tx_pdu == NULL) 788 return; 789 790 if (rx_pdu != NULL && 791 (rx_pdu->pdu_hdr.pduh_Opcode & OPCODE_MASK) == IOP_Login_Request) 792 init_login_pdu(conn, tx_ccb, tx_pdu, FALSE); 793 else 794 init_text_pdu(conn, tx_ccb, tx_pdu, rx_pdu); 795 796 setup_tx_uio(tx_pdu, 0, NULL, FALSE); 797 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 798 } 799 800 801 /* 802 * start_text_negotiation: 803 * Handle target request to negotiate (via asynch event) 804 * 805 * Parameter: 806 * conn The connection 807 */ 808 809 void 810 start_text_negotiation(connection_t *conn) 811 { 812 pdu_t *pdu; 813 ccb_t *ccb; 814 815 ccb = get_ccb(conn, TRUE); 816 if (ccb == NULL) 817 return; 818 pdu = get_pdu(conn, TRUE); 819 if (pdu == NULL) { 820 free_ccb(ccb); 821 return; 822 } 823 824 if (init_text_parameters(conn, ccb)) { 825 free_ccb(ccb); 826 free_pdu(pdu); 827 return; 828 } 829 830 init_text_pdu(conn, ccb, pdu, NULL); 831 setup_tx_uio(pdu, 0, NULL, FALSE); 832 send_pdu(ccb, pdu, CCBDISP_FREE, PDUDISP_WAIT); 833 } 834 835 836 /* 837 * negotiate_text: 838 * Handle received text negotiation. 839 * 840 * Parameter: 841 * conn The connection 842 * rx_pdu The received text response PDU 843 * tx_ccb The original CCB 844 */ 845 846 void 847 negotiate_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 848 { 849 int rc; 850 pdu_t *tx_pdu; 851 852 if (tx_ccb->ccb_flags & CCBF_SENDTARGET) { 853 if (!(rx_pdu->pdu_hdr.pduh_Flags & FLAG_FINAL)) { 854 handle_connection_error(conn, ISCSI_STATUS_PROTOCOL_ERROR, 855 LOGOUT_CONNECTION); 856 return; 857 } 858 /* transfer ownership of text to CCB */ 859 tx_ccb->ccb_text_data = rx_pdu->pdu_temp_data; 860 tx_ccb->ccb_text_len = rx_pdu->pdu_temp_data_len; 861 rx_pdu->pdu_temp_data = NULL; 862 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS); 863 } else { 864 if (!(rx_pdu->pdu_hdr.pduh_Flags & FLAG_FINAL)) 865 tx_pdu = get_pdu(conn, TRUE); 866 else 867 tx_pdu = NULL; 868 869 rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 870 if (rc) { 871 if (tx_pdu != NULL) 872 free_pdu(tx_pdu); 873 874 handle_connection_error(conn, rc, LOGOUT_CONNECTION); 875 } else if (tx_pdu != NULL) { 876 init_text_pdu(conn, tx_ccb, tx_pdu, rx_pdu); 877 setup_tx_uio(tx_pdu, tx_pdu->pdu_temp_data_len, 878 tx_pdu->pdu_temp_data, FALSE); 879 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 880 } else { 881 set_negotiated_parameters(tx_ccb); 882 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS); 883 } 884 } 885 } 886 887 888 /* 889 * send_send_targets: 890 * Send out a SendTargets text request. 891 * The result is stored in the fields in the session structure. 892 * 893 * Parameter: 894 * session The session 895 * key The text key to use 896 * 897 * Returns: 0 on success, else an error code. 898 */ 899 900 int 901 send_send_targets(session_t *sess, uint8_t *key) 902 { 903 ccb_t *ccb; 904 pdu_t *pdu; 905 int rc = 0; 906 connection_t *conn; 907 908 DEB(9, ("Send_send_targets\n")); 909 910 conn = assign_connection(sess, TRUE); 911 if (conn == NULL || conn->c_terminating || conn->c_state != ST_FULL_FEATURE) 912 return (conn != NULL && conn->c_terminating) ? conn->c_terminating 913 : ISCSI_STATUS_CONNECTION_FAILED; 914 915 ccb = get_ccb(conn, TRUE); 916 if (ccb == NULL) 917 return conn->c_terminating; 918 pdu = get_pdu(conn, TRUE); 919 if (pdu == NULL) { 920 free_ccb(ccb); 921 return conn->c_terminating; 922 } 923 924 ccb->ccb_flags |= CCBF_SENDTARGET; 925 926 if ((rc = assemble_send_targets(pdu, key)) != 0) { 927 free_ccb(ccb); 928 free_pdu(pdu); 929 return rc; 930 } 931 932 init_text_pdu(conn, ccb, pdu, NULL); 933 934 setup_tx_uio(pdu, pdu->pdu_temp_data_len, pdu->pdu_temp_data, FALSE); 935 send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_WAIT); 936 937 rc = ccb->ccb_status; 938 if (!rc) { 939 /* transfer ownership of data */ 940 sess->s_target_list = ccb->ccb_text_data; 941 sess->s_target_list_len = ccb->ccb_text_len; 942 ccb->ccb_text_data = NULL; 943 } 944 free_ccb(ccb); 945 return rc; 946 } 947 948 949 /* 950 * send_nop_out: 951 * Send nop out request. 952 * 953 * Parameter: 954 * conn The connection 955 * rx_pdu The received Nop-In PDU 956 * 957 * Returns: 0 on success, else an error code. 958 */ 959 960 int 961 send_nop_out(connection_t *conn, pdu_t *rx_pdu) 962 { 963 session_t *sess; 964 ccb_t *ccb; 965 pdu_t *ppdu; 966 pdu_header_t *hpdu; 967 uint32_t sn; 968 969 if (rx_pdu != NULL) { 970 ccb = NULL; 971 ppdu = get_pdu(conn, TRUE); 972 if (ppdu == NULL) 973 return 1; 974 } else { 975 ccb = get_ccb(conn, FALSE); 976 if (ccb == NULL) { 977 DEBOUT(("Can't get CCB in send_nop_out\n")); 978 return 1; 979 } 980 ppdu = get_pdu(conn, FALSE); 981 if (ppdu == NULL) { 982 free_ccb(ccb); 983 DEBOUT(("Can't get PDU in send_nop_out\n")); 984 return 1; 985 } 986 } 987 988 hpdu = &ppdu->pdu_hdr; 989 hpdu->pduh_Flags = FLAG_FINAL; 990 hpdu->pduh_Opcode = IOP_NOP_Out | OP_IMMEDIATE; 991 992 sess = conn->c_session; 993 994 mutex_enter(&sess->s_lock); 995 sn = get_sernum(sess, ppdu); 996 mutex_exit(&sess->s_lock); 997 998 if (rx_pdu != NULL) { 999 hpdu->pduh_p.nop_out.TargetTransferTag = 1000 rx_pdu->pdu_hdr.pduh_p.nop_in.TargetTransferTag; 1001 hpdu->pduh_InitiatorTaskTag = rx_pdu->pdu_hdr.pduh_InitiatorTaskTag; 1002 hpdu->pduh_p.nop_out.CmdSN = htonl(sn); 1003 hpdu->pduh_LUN = rx_pdu->pdu_hdr.pduh_LUN; 1004 } else { 1005 hpdu->pduh_p.nop_out.TargetTransferTag = 0xffffffff; 1006 hpdu->pduh_InitiatorTaskTag = 0xffffffff; 1007 ccb->ccb_CmdSN = sn; 1008 hpdu->pduh_p.nop_out.CmdSN = htonl(sn); 1009 } 1010 1011 DEBC(conn, 10, ("Send NOP_Out CmdSN=%d, rx_pdu=%p\n", sn, rx_pdu)); 1012 1013 setup_tx_uio(ppdu, 0, NULL, FALSE); 1014 send_pdu(ccb, ppdu, (rx_pdu != NULL) ? CCBDISP_NOWAIT : CCBDISP_FREE, 1015 PDUDISP_FREE); 1016 return 0; 1017 } 1018 1019 1020 /* 1021 * snack_missing: 1022 * Send SNACK request for missing data. 1023 * 1024 * Parameter: 1025 * conn The connection 1026 * ccb The task's CCB (for Data NAK only) 1027 * type The SNACK type 1028 * BegRun The BegRun field 1029 * RunLength The RunLength field 1030 */ 1031 1032 void 1033 snack_missing(connection_t *conn, ccb_t *ccb, uint8_t type, 1034 uint32_t BegRun, uint32_t RunLength) 1035 { 1036 pdu_t *ppdu; 1037 pdu_header_t *hpdu; 1038 1039 ppdu = get_pdu(conn, TRUE); 1040 if (ppdu == NULL) 1041 return; 1042 hpdu = &ppdu->pdu_hdr; 1043 hpdu->pduh_Opcode = IOP_SNACK_Request; 1044 hpdu->pduh_Flags = FLAG_FINAL | type; 1045 1046 hpdu->pduh_InitiatorTaskTag = (type == SNACK_DATA_NAK) ? ccb->ccb_ITT : 0xffffffff; 1047 hpdu->pduh_p.snack.TargetTransferTag = 0xffffffff; 1048 hpdu->pduh_p.snack.BegRun = htonl(BegRun); 1049 hpdu->pduh_p.snack.RunLength = htonl(RunLength); 1050 1051 ppdu->pdu_flags = PDUF_PRIORITY; 1052 1053 setup_tx_uio(ppdu, 0, NULL, FALSE); 1054 send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE); 1055 } 1056 1057 1058 /* 1059 * send_snack: 1060 * Send SNACK request. 1061 * 1062 * Parameter: 1063 * conn The connection 1064 * rx_pdu The received data in PDU 1065 * tx_ccb The original command CCB (required for Data ACK only) 1066 * type The SNACK type 1067 * 1068 * Returns: 0 on success, else an error code. 1069 */ 1070 1071 void 1072 send_snack(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb, uint8_t type) 1073 { 1074 pdu_t *ppdu; 1075 pdu_header_t *hpdu; 1076 1077 ppdu = get_pdu(conn, TRUE); 1078 if (ppdu == NULL) 1079 return; 1080 hpdu = &ppdu->pdu_hdr; 1081 hpdu->pduh_Opcode = IOP_SNACK_Request; 1082 hpdu->pduh_Flags = FLAG_FINAL | type; 1083 1084 switch (type) { 1085 case SNACK_DATA_NAK: 1086 hpdu->pduh_InitiatorTaskTag = rx_pdu->pdu_hdr.pduh_InitiatorTaskTag; 1087 hpdu->pduh_p.snack.TargetTransferTag = 0xffffffff; 1088 hpdu->pduh_p.snack.BegRun = rx_pdu->pdu_hdr.pduh_p.data_in.DataSN; 1089 hpdu->pduh_p.snack.RunLength = htonl(1); 1090 break; 1091 1092 case SNACK_STATUS_NAK: 1093 hpdu->pduh_InitiatorTaskTag = 0xffffffff; 1094 hpdu->pduh_p.snack.TargetTransferTag = 0xffffffff; 1095 hpdu->pduh_p.snack.BegRun = rx_pdu->pdu_hdr.pduh_p.response.StatSN; 1096 hpdu->pduh_p.snack.RunLength = htonl(1); 1097 break; 1098 1099 case SNACK_DATA_ACK: 1100 hpdu->pduh_InitiatorTaskTag = 0xffffffff; 1101 hpdu->pduh_p.snack.TargetTransferTag = 1102 rx_pdu->pdu_hdr.pduh_p.data_in.TargetTransferTag; 1103 hpdu->pduh_p.snack.BegRun = tx_ccb->ccb_DataSN_buf.ExpSN; 1104 hpdu->pduh_p.snack.RunLength = 0; 1105 break; 1106 1107 default: 1108 DEBOUT(("Invalid type %d in send_snack\n", type)); 1109 return; 1110 } 1111 1112 hpdu->pduh_LUN = rx_pdu->pdu_hdr.pduh_LUN; 1113 1114 ppdu->pdu_flags = PDUF_PRIORITY; 1115 1116 setup_tx_uio(ppdu, 0, NULL, FALSE); 1117 send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE); 1118 } 1119 1120 1121 /* 1122 * send_login: 1123 * Send login request. 1124 * 1125 * Parameter: 1126 * conn The connection 1127 * par The login parameters (for negotiation) 1128 * 1129 * Returns: 0 on success, else an error code. 1130 */ 1131 1132 int 1133 send_login(connection_t *conn) 1134 { 1135 ccb_t *ccb; 1136 pdu_t *pdu; 1137 int rc; 1138 1139 DEBC(conn, 9, ("Send_login\n")); 1140 ccb = get_ccb(conn, TRUE); 1141 /* only if terminating (which couldn't possibly happen here, but...) */ 1142 if (ccb == NULL) 1143 return conn->c_terminating; 1144 pdu = get_pdu(conn, TRUE); 1145 if (pdu == NULL) { 1146 free_ccb(ccb); 1147 return conn->c_terminating; 1148 } 1149 1150 if ((rc = assemble_login_parameters(conn, ccb, pdu)) <= 0) { 1151 init_login_pdu(conn, ccb, pdu, !rc); 1152 setup_tx_uio(pdu, pdu->pdu_temp_data_len, pdu->pdu_temp_data, FALSE); 1153 send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_FREE); 1154 rc = ccb->ccb_status; 1155 } else { 1156 free_pdu(pdu); 1157 } 1158 free_ccb(ccb); 1159 return rc; 1160 } 1161 1162 1163 /* 1164 * send_logout: 1165 * Send logout request. 1166 * NOTE: This function does not wait for the logout to complete. 1167 * 1168 * Parameter: 1169 * conn The connection 1170 * refconn The referenced connection 1171 * reason The reason code 1172 * wait Wait for completion if TRUE 1173 * 1174 * Returns: 0 on success (logout sent), else an error code. 1175 */ 1176 1177 int 1178 send_logout(connection_t *conn, connection_t *refconn, int reason, 1179 bool wait) 1180 { 1181 ccb_t *ccb; 1182 pdu_t *ppdu; 1183 pdu_header_t *hpdu; 1184 1185 DEBC(conn, 5, ("Send_logout\n")); 1186 ccb = get_ccb(conn, TRUE); 1187 /* can only happen if terminating... */ 1188 if (ccb == NULL) 1189 return conn->c_terminating; 1190 ppdu = get_pdu(conn, TRUE); 1191 if (ppdu == NULL) { 1192 free_ccb(ccb); 1193 return conn->c_terminating; 1194 } 1195 1196 hpdu = &ppdu->pdu_hdr; 1197 hpdu->pduh_Opcode = IOP_Logout_Request | OP_IMMEDIATE; 1198 1199 hpdu->pduh_Flags = FLAG_FINAL | reason; 1200 ccb->ccb_CmdSN = conn->c_session->s_CmdSN; 1201 hpdu->pduh_p.logout_req.CmdSN = htonl(ccb->ccb_CmdSN); 1202 if (reason > 0) 1203 hpdu->pduh_p.logout_req.CID = htons(refconn->c_id); 1204 1205 ccb->ccb_par = refconn; 1206 if (refconn != conn) { 1207 ccb->ccb_flags |= CCBF_OTHERCONN; 1208 } else { 1209 conn->c_state = ST_LOGOUT_SENT; 1210 conn->c_loggedout = LOGOUT_SENT; 1211 } 1212 1213 setup_tx_uio(ppdu, 0, NULL, FALSE); 1214 send_pdu(ccb, ppdu, (wait) ? CCBDISP_WAIT : CCBDISP_FREE, PDUDISP_FREE); 1215 1216 if (wait) { 1217 int rc = ccb->ccb_status; 1218 free_ccb (ccb); 1219 return rc; 1220 } 1221 return 0; 1222 } 1223 1224 1225 /* 1226 * send_task_management: 1227 * Send task management request. 1228 * 1229 * Parameter: 1230 * conn The connection 1231 * ref_ccb The referenced command (NULL if none) 1232 * xs The scsipi command structure (NULL if not a scsipi request) 1233 * function The function code 1234 * 1235 * Returns: 0 on success, else an error code. 1236 */ 1237 1238 int 1239 send_task_management(connection_t *conn, ccb_t *ref_ccb, struct scsipi_xfer *xs, 1240 int function) 1241 { 1242 ccb_t *ccb; 1243 pdu_t *ppdu; 1244 pdu_header_t *hpdu; 1245 1246 DEBC(conn, 5, ("Send_task_management, ref_ccb=%p, func = %d\n", 1247 ref_ccb, function)); 1248 1249 if (function == TASK_REASSIGN && conn->c_session->s_ErrorRecoveryLevel < 2) 1250 return ISCSI_STATUS_CANT_REASSIGN; 1251 1252 ccb = get_ccb(conn, xs == NULL); 1253 /* can only happen if terminating... */ 1254 if (ccb == NULL) { 1255 DEBC(conn, 0, ("send_task_management, ref_ccb=%p, xs=%p, term=%d. No CCB\n", 1256 ref_ccb, xs, conn->c_terminating)); 1257 return conn->c_terminating; 1258 } 1259 ppdu = get_pdu(conn, xs == NULL); 1260 if (ppdu == NULL) { 1261 DEBC(conn, 0, ("send_task_management, ref_ccb=%p, xs=%p, term=%d. No PDU\n", 1262 ref_ccb, xs, conn->c_terminating)); 1263 free_ccb(ccb); 1264 return conn->c_terminating; 1265 } 1266 1267 ccb->ccb_xs = xs; 1268 1269 hpdu = &ppdu->pdu_hdr; 1270 hpdu->pduh_Opcode = IOP_SCSI_Task_Management | OP_IMMEDIATE; 1271 hpdu->pduh_Flags = FLAG_FINAL | function; 1272 1273 ccb->ccb_CmdSN = conn->c_session->s_CmdSN; 1274 hpdu->pduh_p.task_req.CmdSN = htonl(ccb->ccb_CmdSN); 1275 1276 if (ref_ccb != NULL) { 1277 hpdu->pduh_p.task_req.ReferencedTaskTag = ref_ccb->ccb_ITT; 1278 hpdu->pduh_p.task_req.RefCmdSN = htonl(ref_ccb->ccb_CmdSN); 1279 hpdu->pduh_p.task_req.ExpDataSN = htonl(ref_ccb->ccb_DataSN_buf.ExpSN); 1280 } else 1281 hpdu->pduh_p.task_req.ReferencedTaskTag = 0xffffffff; 1282 1283 ppdu->pdu_flags |= PDUF_PRIORITY; 1284 1285 setup_tx_uio(ppdu, 0, NULL, FALSE); 1286 send_pdu(ccb, ppdu, (xs) ? CCBDISP_SCSIPI : CCBDISP_WAIT, PDUDISP_FREE); 1287 1288 if (xs == NULL) { 1289 int rc = ccb->ccb_status; 1290 free_ccb(ccb); 1291 return rc; 1292 } 1293 return 0; 1294 } 1295 1296 1297 /* 1298 * send_data_out: 1299 * Send data to target in response to an R2T or as unsolicited data. 1300 * 1301 * Parameter: 1302 * conn The connection 1303 * rx_pdu The received R2T PDU (NULL if unsolicited) 1304 * tx_ccb The originally sent command CCB 1305 * waitok Whether it's OK to wait for an available PDU or not 1306 */ 1307 1308 int 1309 send_data_out(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb, 1310 ccb_disp_t disp, bool waitok) 1311 { 1312 pdu_header_t *hpdu; 1313 uint32_t totlen, len, offs, sn; 1314 pdu_t *tx_pdu; 1315 1316 KASSERT(conn->c_max_transfer != 0); 1317 1318 if (rx_pdu) { 1319 offs = ntohl(rx_pdu->pdu_hdr.pduh_p.r2t.BufferOffset); 1320 totlen = ntohl(rx_pdu->pdu_hdr.pduh_p.r2t.DesiredDataTransferLength); 1321 } else { 1322 offs = conn->c_max_firstimmed; 1323 totlen = min(conn->c_max_firstdata - offs, tx_ccb->ccb_data_len - offs); 1324 } 1325 sn = 0; 1326 1327 while (totlen) { 1328 len = min(totlen, conn->c_max_transfer); 1329 1330 tx_pdu = get_pdu(conn, waitok); 1331 if (tx_pdu == NULL) { 1332 DEBC(conn, 5, ("No PDU in send_data_out\n")); 1333 1334 tx_ccb->ccb_disp = disp; 1335 tx_ccb->ccb_status = ISCSI_STATUS_NO_RESOURCES; 1336 handle_connection_error(conn, ISCSI_STATUS_NO_RESOURCES, NO_LOGOUT); 1337 1338 return ISCSI_STATUS_NO_RESOURCES; 1339 } 1340 1341 totlen -= len; 1342 hpdu = &tx_pdu->pdu_hdr; 1343 hpdu->pduh_Opcode = IOP_SCSI_Data_out; 1344 if (!totlen) 1345 hpdu->pduh_Flags = FLAG_FINAL; 1346 1347 if (rx_pdu != NULL) 1348 hpdu->pduh_p.data_out.TargetTransferTag = 1349 rx_pdu->pdu_hdr.pduh_p.r2t.TargetTransferTag; 1350 else 1351 hpdu->pduh_p.data_out.TargetTransferTag = 0xffffffff; 1352 hpdu->pduh_p.data_out.BufferOffset = htonl(offs); 1353 hpdu->pduh_p.data_out.DataSN = htonl(sn); 1354 1355 DEBC(conn, 10, ("Send DataOut: DataSN %d, len %d offs %x totlen %d\n", 1356 sn, len, offs, totlen)); 1357 1358 setup_tx_uio(tx_pdu, len, tx_ccb->ccb_data_ptr + offs, FALSE); 1359 send_pdu(tx_ccb, tx_pdu, (totlen) ? CCBDISP_NOWAIT : disp, PDUDISP_FREE); 1360 1361 sn++; 1362 offs += len; 1363 } 1364 return 0; 1365 } 1366 1367 1368 /* 1369 * send_command: 1370 * Send a SCSI command request. 1371 * 1372 * Parameter: 1373 * CCB The CCB 1374 * disp The CCB disposition 1375 */ 1376 1377 void 1378 send_command(ccb_t *ccb, ccb_disp_t disp, bool waitok, bool immed) 1379 { 1380 uint32_t totlen, len; 1381 connection_t *conn = ccb->ccb_connection; 1382 session_t *sess = ccb->ccb_session; 1383 pdu_t *ppdu; 1384 pdu_header_t *hpdu; 1385 1386 mutex_enter(&sess->s_lock); 1387 while (!sernum_in_window(sess)) { 1388 mutex_exit(&sess->s_lock); 1389 ccb->ccb_disp = disp; 1390 wake_ccb(ccb, ISCSI_STATUS_QUEUE_FULL); 1391 return; 1392 } 1393 mutex_exit(&sess->s_lock); 1394 1395 /* Don't confuse targets during (re-)negotations */ 1396 if (conn->c_state != ST_FULL_FEATURE) { 1397 DEBOUT(("Invalid connection for send_command, ccb = %p\n",ccb)); 1398 ccb->ccb_disp = disp; 1399 wake_ccb(ccb, ISCSI_STATUS_TARGET_BUSY); 1400 return; 1401 } 1402 1403 ppdu = get_pdu(conn, waitok); 1404 if (ppdu == NULL) { 1405 DEBOUT(("No PDU for send_command, ccb = %p\n",ccb)); 1406 ccb->ccb_disp = disp; 1407 wake_ccb(ccb, ISCSI_STATUS_NO_RESOURCES); 1408 return; 1409 } 1410 1411 totlen = len = ccb->ccb_data_len; 1412 1413 hpdu = &ppdu->pdu_hdr; 1414 hpdu->pduh_LUN = htonq(ccb->ccb_lun); 1415 memcpy(hpdu->pduh_p.command.SCSI_CDB, ccb->ccb_cmd, ccb->ccb_cmdlen); 1416 hpdu->pduh_Opcode = IOP_SCSI_Command; 1417 if (immed) 1418 hpdu->pduh_Opcode |= OP_IMMEDIATE; 1419 hpdu->pduh_p.command.ExpectedDataTransferLength = htonl(totlen); 1420 1421 if (totlen) { 1422 if (ccb->ccb_data_in) { 1423 hpdu->pduh_Flags = FLAG_READ; 1424 totlen = 0; 1425 } else { 1426 hpdu->pduh_Flags = FLAG_WRITE; 1427 /* immediate data we can send */ 1428 len = min(totlen, conn->c_max_firstimmed); 1429 1430 /* can we send more unsolicited data ? */ 1431 totlen = conn->c_max_firstdata ? totlen - len : 0; 1432 } 1433 } 1434 if (!totlen) 1435 hpdu->pduh_Flags |= FLAG_FINAL; 1436 hpdu->pduh_Flags |= ccb->ccb_tag; 1437 1438 if (ccb->ccb_data_in) 1439 init_sernum(&ccb->ccb_DataSN_buf); 1440 1441 ccb->ccb_sense_len_got = 0; 1442 ccb->ccb_xfer_len = 0; 1443 ccb->ccb_residual = 0; 1444 ccb->ccb_flags |= CCBF_REASSIGN; 1445 1446 mutex_enter(&sess->s_lock); 1447 ccb->ccb_CmdSN = get_sernum(sess, ppdu); 1448 mutex_exit(&sess->s_lock); 1449 1450 hpdu->pduh_p.command.CmdSN = htonl(ccb->ccb_CmdSN); 1451 1452 DEBC(conn, 10, ("Send Command: CmdSN %d (%d), data_in %d, len %d, totlen %d\n", 1453 ccb->ccb_CmdSN, sess->s_MaxCmdSN, ccb->ccb_data_in, len, totlen)); 1454 1455 setup_tx_uio(ppdu, len, ccb->ccb_data_ptr, ccb->ccb_data_in); 1456 send_pdu(ccb, ppdu, (totlen) ? CCBDISP_DEFER : disp, PDUDISP_WAIT); 1457 1458 if (totlen) 1459 send_data_out(conn, NULL, ccb, disp, waitok); 1460 } 1461 1462 1463 /* 1464 * send_run_xfer: 1465 * Handle a SCSI command transfer request from scsipi. 1466 * 1467 * Parameter: 1468 * session The session 1469 * xs The transfer parameters 1470 */ 1471 1472 void 1473 send_run_xfer(session_t *session, struct scsipi_xfer *xs) 1474 { 1475 ccb_t *ccb; 1476 connection_t *conn; 1477 bool waitok; 1478 1479 waitok = !(xs->xs_control & XS_CTL_NOSLEEP); 1480 1481 DEB(10, ("RunXfer: flags=%x, data=%p, datalen=%d, resid=%d, cmdlen=%d, " 1482 "waitok=%d\n", xs->xs_control, xs->data, xs->datalen, 1483 xs->resid, xs->cmdlen, waitok)); 1484 1485 conn = assign_connection(session, waitok); 1486 1487 if (conn == NULL || conn->c_terminating || conn->c_state != ST_FULL_FEATURE) { 1488 xs->error = XS_SELTIMEOUT; 1489 DEBC(conn, 10, ("run_xfer on dead connection\n")); 1490 scsipi_done(xs); 1491 unref_session(session); 1492 return; 1493 } 1494 1495 if (xs->xs_control & XS_CTL_RESET) { 1496 if (send_task_management(conn, NULL, xs, TARGET_WARM_RESET)) { 1497 DEBC(conn, 0, ("send_task_management TARGET_WARM_RESET failed\n")); 1498 xs->error = XS_SELTIMEOUT; 1499 scsipi_done(xs); 1500 unref_session(session); 1501 } 1502 return; 1503 } 1504 1505 ccb = get_ccb(conn, waitok); 1506 if (ccb == NULL) { 1507 xs->error = XS_BUSY; 1508 DEBC(conn, 5, ("No CCB in run_xfer, %d in use.\n", conn->c_usecount)); 1509 scsipi_done(xs); 1510 unref_session(session); 1511 return; 1512 } 1513 /* copy parameters into CCB for easier access */ 1514 ccb->ccb_xs = xs; 1515 1516 ccb->ccb_data_in = (xs->xs_control & XS_CTL_DATA_IN) != 0; 1517 ccb->ccb_data_len = (uint32_t) xs->datalen; 1518 ccb->ccb_data_ptr = xs->data; 1519 1520 ccb->ccb_sense_len_req = sizeof(xs->sense.scsi_sense); 1521 ccb->ccb_sense_ptr = &xs->sense; 1522 1523 ccb->ccb_lun = ((uint64_t) (uint8_t) xs->xs_periph->periph_lun) << 48; 1524 ccb->ccb_cmd = (uint8_t *) xs->cmd; 1525 ccb->ccb_cmdlen = xs->cmdlen; 1526 DEB(10, ("RunXfer: Periph_lun = %d, cmd[1] = %x, cmdlen = %d\n", 1527 xs->xs_periph->periph_lun, ccb->ccb_cmd[1], xs->cmdlen)); 1528 1529 ccb->ccb_ITT |= xs->xs_tag_id << 24; 1530 switch (xs->xs_tag_type) { 1531 case MSG_ORDERED_Q_TAG: 1532 ccb->ccb_tag = ATTR_ORDERED; 1533 break; 1534 case MSG_SIMPLE_Q_TAG: 1535 ccb->ccb_tag = ATTR_SIMPLE; 1536 break; 1537 case MSG_HEAD_OF_Q_TAG: 1538 ccb->ccb_tag = ATTR_HEAD_OF_QUEUE; 1539 break; 1540 default: 1541 ccb->ccb_tag = 0; 1542 break; 1543 } 1544 1545 #ifdef LUN_1 1546 ccb->ccb_lun += 0x1000000000000LL; 1547 ccb->ccb_cmd[1] += 0x10; 1548 #endif 1549 send_command(ccb, CCBDISP_SCSIPI, waitok, FALSE); 1550 } 1551 1552 1553 #ifndef ISCSI_MINIMAL 1554 /* 1555 * send_io_command: 1556 * Handle a SCSI io command request from user space. 1557 * 1558 * Parameter: 1559 * session The session 1560 * lun The LUN to use 1561 * req The SCSI request block 1562 * immed Immediate command if TRUE 1563 * conn_id Assign to this connection ID if nonzero 1564 */ 1565 1566 int 1567 send_io_command(session_t *session, uint64_t lun, scsireq_t *req, 1568 bool immed, uint32_t conn_id) 1569 { 1570 ccb_t *ccb; 1571 connection_t *conn; 1572 int rc; 1573 1574 DEB(9, ("IoCommand: lun=%x, datalen=%d, cmdlen=%d, immed=%d, cid=%d\n", 1575 (int) lun, (int) req->datalen, (int) req->cmdlen, immed, conn_id)); 1576 1577 conn = (conn_id) ? find_connection(session, conn_id) 1578 : assign_connection(session, TRUE); 1579 1580 if (conn == NULL || conn->c_terminating || conn->c_state != ST_FULL_FEATURE) { 1581 DEBOUT(("io_command on dead connection (state = %d)\n", 1582 (conn != NULL) ? conn->c_state : -1)); 1583 return ISCSI_STATUS_INVALID_CONNECTION_ID; 1584 } 1585 1586 ccb = get_ccb(conn, TRUE); 1587 if (ccb == NULL) { 1588 DEBOUT(("No CCB in io_command\n")); 1589 return ISCSI_STATUS_NO_RESOURCES; 1590 } 1591 1592 ccb->ccb_data_in = (req->flags & SCCMD_READ) != 0; 1593 ccb->ccb_data_len = (uint32_t) req->datalen; 1594 ccb->ccb_data_ptr = req->databuf; 1595 1596 ccb->ccb_sense_len_req = req->senselen; 1597 ccb->ccb_sense_ptr = &req->sense; 1598 1599 ccb->ccb_lun = lun; 1600 ccb->ccb_cmd = (uint8_t *) req->cmd; 1601 ccb->ccb_cmdlen = req->cmdlen; 1602 DEBC(conn, 10, ("IoCommand: cmd[1] = %x, cmdlen = %d\n", 1603 ccb->ccb_cmd[1], ccb->ccb_cmdlen)); 1604 1605 send_command(ccb, CCBDISP_WAIT, TRUE, immed); 1606 1607 rc = ccb->ccb_status; 1608 1609 req->senselen_used = ccb->ccb_sense_len_got; 1610 req->datalen_used = req->datalen - ccb->ccb_residual; 1611 1612 free_ccb(ccb); 1613 1614 return rc; 1615 } 1616 #endif 1617 1618 1619 /***************************************************************************** 1620 * Timeout handlers 1621 *****************************************************************************/ 1622 /* 1623 * connection_timeout: 1624 * Handle prolonged silence on a connection by checking whether 1625 * it's still alive. 1626 * This has the side effect of discovering missing status or lost commands 1627 * before those time out. 1628 * 1629 * Parameter: 1630 * conn The connection 1631 */ 1632 1633 void 1634 connection_timeout(connection_t *conn) 1635 { 1636 1637 if (++conn->c_num_timeouts > MAX_CONN_TIMEOUTS) 1638 handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, NO_LOGOUT); 1639 else { 1640 if (conn->c_state == ST_FULL_FEATURE) 1641 send_nop_out(conn, NULL); 1642 1643 connection_timeout_start(conn, CONNECTION_TIMEOUT); 1644 } 1645 } 1646 1647 /* 1648 * ccb_timeout: 1649 * Handle timeout of a sent command. 1650 * 1651 * Parameter: 1652 * ccb The CCB 1653 */ 1654 1655 void 1656 ccb_timeout(ccb_t *ccb) 1657 { 1658 connection_t *conn = ccb->ccb_connection; 1659 1660 ccb->ccb_total_tries++; 1661 1662 DEBC(conn, 0, ("ccb_timeout: num=%d total=%d disp=%d\n", 1663 ccb->ccb_num_timeouts+1, ccb->ccb_total_tries, ccb->ccb_disp)); 1664 1665 if (++ccb->ccb_num_timeouts > MAX_CCB_TIMEOUTS || 1666 ccb->ccb_total_tries > MAX_CCB_TRIES || 1667 ccb->ccb_disp <= CCBDISP_FREE || 1668 !ccb->ccb_session->s_ErrorRecoveryLevel) { 1669 1670 wake_ccb(ccb, ISCSI_STATUS_TIMEOUT); 1671 handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, RECOVER_CONNECTION); 1672 } else { 1673 if (ccb->ccb_data_in && ccb->ccb_xfer_len < ccb->ccb_data_len) { 1674 /* request resend of all missing data */ 1675 snack_missing(conn, ccb, SNACK_DATA_NAK, 0, 0); 1676 } else { 1677 /* request resend of all missing status */ 1678 snack_missing(conn, NULL, SNACK_STATUS_NAK, 0, 0); 1679 } 1680 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 1681 } 1682 } 1683 1684