1 /* $NetBSD: iscsi_send.c,v 1.33 2017/02/05 12:05:46 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->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->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->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 *session, bool waitok) 91 { 92 connection_t *conn, *next; 93 94 mutex_enter(&session->lock); 95 do { 96 if (session->terminating || 97 (conn = session->mru_connection) == NULL) { 98 mutex_exit(&session->lock); 99 return NULL; 100 } 101 next = conn; 102 do { 103 next = TAILQ_NEXT(next, connections); 104 if (next == NULL) { 105 next = TAILQ_FIRST(&session->conn_list); 106 } 107 } while (next != NULL && next != conn && 108 next->state != ST_FULL_FEATURE); 109 110 if (next->state != ST_FULL_FEATURE) { 111 if (waitok) { 112 cv_wait(&session->sess_cv, &session->lock); 113 next = TAILQ_FIRST(&session->conn_list); 114 } else { 115 mutex_exit(&session->lock); 116 return NULL; 117 } 118 } else { 119 session->mru_connection = next; 120 } 121 } while (next != NULL && next->state != ST_FULL_FEATURE); 122 mutex_exit(&session->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->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->id, oldconn->id)); 153 /* XXX here we need to abort the waiting CCBs */ 154 return; 155 } 156 157 if (sess->ErrorRecoveryLevel >= 2) { 158 if (oldconn->loggedout == NOT_LOGGED_OUT) { 159 oldconn->loggedout = LOGOUT_SENT; 160 no_tm = send_logout(conn, oldconn, RECOVER_CONNECTION, TRUE); 161 oldconn->loggedout = (rc) ? LOGOUT_FAILED : LOGOUT_SUCCESS; 162 if (!oldconn->Time2Retain) { 163 DEBC(conn, 1, ("Time2Retain is zero, setting no_tm\n")); 164 no_tm = 1; 165 } 166 } else if (oldconn->loggedout == LOGOUT_SUCCESS) { 167 no_tm = 0; 168 } 169 if (!no_tm && oldconn->Time2Wait) { 170 DEBC(conn, 1, ("Time2Wait=%d, hz=%d, waiting...\n", 171 oldconn->Time2Wait, hz)); 172 kpause("Time2Wait", false, oldconn->Time2Wait * hz, NULL); 173 } 174 } 175 176 DEBC(conn, 1, ("Reassign_tasks: Session %d, conn %d -> conn %d, no_tm=%d\n", 177 sess->id, oldconn->id, conn->id, no_tm)); 178 179 180 /* XXX reassign waiting CCBs to new connection */ 181 182 while ((ccb = TAILQ_FIRST(&oldconn->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->ccbs_waiting, ccb, chain); 190 191 opdu = ccb->pdu_waiting; 192 KASSERT((opdu->flags & PDUF_INQUEUE) == 0); 193 194 *pdu = *opdu; 195 196 /* restore overwritten back ptr */ 197 pdu->connection = conn; 198 199 /* fixup saved UIO and IOVEC (regular one will be overwritten anyway) */ 200 pdu->save_uio.uio_iov = pdu->io_vec; 201 pdu->save_iovec [0].iov_base = &pdu->pdu; 202 203 if (conn->DataDigest && pdu->save_uio.uio_iovcnt > 1) { 204 if (pdu->save_iovec [2].iov_base == NULL) { 205 pdu->save_iovec [2].iov_base = &pdu->data_digest; 206 pdu->save_uio.uio_iovcnt = 3; 207 } else { 208 pdu->save_iovec [3].iov_base = &pdu->data_digest; 209 pdu->save_uio.uio_iovcnt = 4; 210 } 211 } 212 pdu->save_iovec [0].iov_len = 213 (conn->HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE; 214 215 /* link new PDU into old CCB */ 216 ccb->pdu_waiting = pdu; 217 /* link new CCB into new connection */ 218 ccb->connection = conn; 219 /* reset timeouts */ 220 ccb->num_timeouts = 0; 221 222 /* fixup reference counts */ 223 oldconn->usecount--; 224 atomic_inc_uint(&conn->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->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->lock); 237 suspend_ccb(ccb, TRUE); 238 mutex_exit(&conn->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->ccbs_waiting)) != NULL) { 245 wake_ccb(ccb, oldconn->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->ccbs_waiting, 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->lock); 259 if (ccb->CmdSN < sess->ExpCmdSN) { 260 pdu = 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->CmdSN, sn)); 266 ccb->CmdSN = sn; 267 pdu->pdu.p.command.CmdSN = htonl(ccb->CmdSN); 268 } 269 mutex_exit(&sess->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->session; 300 /* so cleanup thread knows there's someone left */ 301 iscsi_num_send_threads++; 302 303 do { 304 mutex_enter(&conn->lock); 305 while (!conn->terminating) { 306 while (!conn->terminating && 307 (pdu = TAILQ_FIRST(&conn->pdus_to_send)) != NULL) { 308 TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain); 309 pdu->flags &= ~PDUF_INQUEUE; 310 mutex_exit(&conn->lock); 311 312 /* update ExpStatSN here to avoid discontinuities */ 313 /* and delays in updating target */ 314 pdu->pdu.p.command.ExpStatSN = htonl(conn->StatSN_buf.ExpSN); 315 316 if (conn->HeaderDigest) 317 pdu->pdu.HeaderDigest = gen_digest(&pdu->pdu, BHS_SIZE); 318 319 DEBC(conn, 99, ("Transmitting PDU CmdSN = %u, ExpStatSN = %u\n", 320 ntohl(pdu->pdu.p.command.CmdSN), 321 ntohl(pdu->pdu.p.command.ExpStatSN))); 322 my_soo_write(conn, &pdu->uio); 323 324 mutex_enter(&conn->lock); 325 pdisp = pdu->disp; 326 if (pdisp > PDUDISP_FREE) 327 pdu->flags &= ~PDUF_BUSY; 328 mutex_exit(&conn->lock); 329 if (pdisp <= PDUDISP_FREE) 330 free_pdu(pdu); 331 332 mutex_enter(&conn->lock); 333 } 334 335 if (!conn->terminating) 336 cv_wait(&conn->conn_cv, &conn->lock); 337 } 338 mutex_exit(&conn->lock); 339 340 /* ------------------------------------------------------------------------ 341 * Here this thread takes over cleanup of the terminating connection. 342 * ------------------------------------------------------------------------ 343 */ 344 connection_timeout_stop(conn); 345 conn->idle_timeout_val = CONNECTION_IDLE_TIMEOUT; 346 347 fp = conn->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->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->ccbs_waiting, chain, nccb) { 360 if (!(ccb->flags & CCBF_REASSIGN) || ccb->pdu_waiting == NULL) { 361 DEBC(conn, 1, ("Terminating CCB %p (t=%p)\n", 362 ccb,&ccb->timeout)); 363 wake_ccb(ccb, conn->terminating); 364 } else { 365 ccb_timeout_stop(ccb); 366 ccb->num_timeouts = 0; 367 } 368 } 369 370 /* clean out anything left in send queue */ 371 mutex_enter(&conn->lock); 372 while ((pdu = TAILQ_FIRST(&conn->pdus_to_send)) != NULL) { 373 TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain); 374 pdu->flags &= ~(PDUF_INQUEUE | PDUF_BUSY); 375 mutex_exit(&conn->lock); 376 /* if it's not attached to a waiting CCB, free it */ 377 if (pdu->owner == NULL || 378 pdu->owner->pdu_waiting != pdu) { 379 free_pdu(pdu); 380 } 381 mutex_enter(&conn->lock); 382 } 383 mutex_exit(&conn->lock); 384 385 /* If there's another connection available, transfer pending tasks */ 386 if (sess->active_connections && 387 TAILQ_FIRST(&conn->ccbs_waiting) != NULL) { 388 389 reassign_tasks(conn); 390 } else if (!conn->destroy && conn->Time2Wait) { 391 DEBC(conn, 1, ("Time2Wait\n")); 392 kpause("Time2Wait", false, conn->Time2Wait * hz, NULL); 393 DEBC(conn, 1, ("Time2Wait\n")); 394 } 395 /* notify event handlers of connection shutdown */ 396 DEBC(conn, 1, ("%s\n", (conn->destroy) ? "TERMINATED" : "RECOVER")); 397 add_event((conn->destroy) ? ISCSI_CONNECTION_TERMINATED 398 : ISCSI_RECOVER_CONNECTION, 399 sess->id, conn->id, conn->terminating); 400 401 DEBC(conn, 1, ("Waiting for conn_idle\n")); 402 mutex_enter(&conn->lock); 403 if (!conn->destroy) 404 cv_timedwait(&conn->idle_cv, &conn->lock, CONNECTION_IDLE_TIMEOUT); 405 mutex_exit(&conn->lock); 406 DEBC(conn, 1, ("Waited for conn_idle, destroy = %d\n", conn->destroy)); 407 408 } while (!conn->destroy); 409 410 /* wake up anyone waiting for a PDU */ 411 mutex_enter(&conn->lock); 412 cv_broadcast(&conn->conn_cv); 413 mutex_exit(&conn->lock); 414 415 /* wake up any waiting CCBs */ 416 while ((ccb = TAILQ_FIRST(&conn->ccbs_waiting)) != NULL) { 417 KASSERT(ccb->disp >= CCBDISP_NOWAIT); 418 wake_ccb(ccb, conn->terminating); 419 /* NOTE: wake_ccb will remove the CCB from the queue */ 420 } 421 422 if (conn->in_session) { 423 conn->in_session = FALSE; 424 TAILQ_REMOVE(&sess->conn_list, conn, connections); 425 sess->mru_connection = TAILQ_FIRST(&sess->conn_list); 426 } 427 428 add_connection_cleanup(conn); 429 430 conn->sendproc = NULL; 431 DEBC(conn, 1, ("Send thread exits\n")); 432 iscsi_num_send_threads--; 433 kthread_exit(0); 434 } 435 436 437 /* 438 * send_pdu: 439 * Enqueue a PDU to be sent, and handle its disposition as well as 440 * the disposition of its associated CCB. 441 * 442 * Parameter: 443 * ccb The associated CCB. May be NULL if cdisp is CCBDISP_NOWAIT 444 * and pdisp is not PDUDISP_WAIT 445 * cdisp The CCB's disposition 446 * pdu The PDU 447 * pdisp The PDU's disposition 448 */ 449 450 STATIC void 451 send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_disp_t cdisp, pdu_disp_t pdisp) 452 { 453 connection_t *conn = pdu->connection; 454 ccb_disp_t prev_cdisp = 0; 455 456 if (ccb != NULL) { 457 prev_cdisp = ccb->disp; 458 pdu->pdu.InitiatorTaskTag = ccb->ITT; 459 pdu->owner = ccb; 460 if (cdisp != CCBDISP_NOWAIT) 461 ccb->disp = cdisp; 462 } 463 464 pdu->disp = pdisp; 465 466 DEBC(conn, 10, ("Send_pdu: CmdSN=%u ExpStatSN~%u ccb=%p, pdu=%p\n", 467 ntohl(pdu->pdu.p.command.CmdSN), 468 conn->StatSN_buf.ExpSN, 469 ccb, pdu)); 470 471 mutex_enter(&conn->lock); 472 if (pdisp == PDUDISP_WAIT) { 473 KASSERT(ccb != NULL); 474 475 ccb->pdu_waiting = pdu; 476 477 /* save UIO and IOVEC for retransmit */ 478 pdu->save_uio = pdu->uio; 479 memcpy(pdu->save_iovec, pdu->io_vec, sizeof(pdu->save_iovec)); 480 481 pdu->flags |= PDUF_BUSY; 482 } 483 /* Enqueue for sending */ 484 pdu->flags |= PDUF_INQUEUE; 485 486 if (pdu->flags & PDUF_PRIORITY) 487 TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain); 488 else 489 TAILQ_INSERT_TAIL(&conn->pdus_to_send, pdu, send_chain); 490 491 cv_broadcast(&conn->conn_cv); 492 493 if (cdisp != CCBDISP_NOWAIT) { 494 KASSERT(ccb != NULL); 495 KASSERTMSG(ccb->connection == conn, "conn mismatch %p != %p\n", ccb->connection, conn); 496 497 if (prev_cdisp <= CCBDISP_NOWAIT) 498 suspend_ccb(ccb, TRUE); 499 500 mutex_exit(&conn->lock); 501 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 502 mutex_enter(&conn->lock); 503 504 while (ccb->disp == CCBDISP_WAIT) { 505 DEBC(conn, 15, ("Send_pdu: ccb=%p cdisp=%d waiting\n", 506 ccb, ccb->disp)); 507 cv_wait(&conn->ccb_cv, &conn->lock); 508 DEBC(conn, 15, ("Send_pdu: ccb=%p cdisp=%d returned\n", 509 ccb, ccb->disp)); 510 } 511 } 512 513 mutex_exit(&conn->lock); 514 } 515 516 517 /* 518 * resend_pdu: 519 * Re-Enqueue a PDU that has apparently gotten lost. 520 * 521 * Parameter: 522 * ccb The associated CCB. 523 */ 524 525 void 526 resend_pdu(ccb_t *ccb) 527 { 528 connection_t *conn = ccb->connection; 529 pdu_t *pdu = ccb->pdu_waiting; 530 531 mutex_enter(&conn->lock); 532 if (pdu == NULL || (pdu->flags & PDUF_BUSY)) { 533 mutex_exit(&conn->lock); 534 return; 535 } 536 pdu->flags |= PDUF_BUSY; 537 mutex_exit(&conn->lock); 538 539 /* restore UIO and IOVEC */ 540 pdu->uio = pdu->save_uio; 541 memcpy(pdu->io_vec, pdu->save_iovec, sizeof(pdu->io_vec)); 542 543 DEBC(conn, 8, ("ReSend_pdu: CmdSN=%u ExpStatSN~%u ccb=%p, pdu=%p\n", 544 ntohl(pdu->pdu.p.command.CmdSN), 545 conn->StatSN_buf.ExpSN, 546 ccb, pdu)); 547 548 mutex_enter(&conn->lock); 549 /* Enqueue for sending */ 550 pdu->flags |= PDUF_INQUEUE; 551 552 if (pdu->flags & PDUF_PRIORITY) { 553 TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain); 554 } else { 555 TAILQ_INSERT_TAIL(&conn->pdus_to_send, pdu, send_chain); 556 } 557 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 558 cv_broadcast(&conn->conn_cv); 559 mutex_exit(&conn->lock); 560 } 561 562 563 /* 564 * setup_tx_uio: 565 * Initialize the uio structure for sending, including header, 566 * data (if present), padding, and Data Digest. 567 * Header Digest is generated in send thread. 568 * 569 * Parameter: 570 * pdu The PDU 571 * dsl The Data Segment Length 572 * data The data pointer 573 * read TRUE if this is a read operation 574 */ 575 576 STATIC void 577 setup_tx_uio(pdu_t *pdu, uint32_t dsl, void *data, bool read) 578 { 579 static uint8_t pad_bytes[4] = { 0 }; 580 struct uio *uio; 581 int i, pad, hlen; 582 connection_t *conn = pdu->connection; 583 584 DEB(99, ("SetupTxUio: dlen = %d, dptr: %p, read: %d\n", 585 dsl, data, read)); 586 587 if (!read && dsl) { 588 hton3(dsl, pdu->pdu.DataSegmentLength); 589 } 590 hlen = (conn->HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE; 591 592 pdu->io_vec[0].iov_base = &pdu->pdu; 593 pdu->io_vec[0].iov_len = hlen; 594 595 uio = &pdu->uio; 596 597 uio->uio_iov = pdu->io_vec; 598 uio->uio_iovcnt = 1; 599 uio->uio_rw = UIO_WRITE; 600 uio->uio_resid = hlen; 601 UIO_SETUP_SYSSPACE(uio); 602 603 if (!read && dsl) { 604 uio->uio_iovcnt++; 605 pdu->io_vec[1].iov_base = data; 606 pdu->io_vec[1].iov_len = dsl; 607 uio->uio_resid += dsl; 608 609 /* Pad to next multiple of 4 */ 610 pad = uio->uio_resid & 0x03; 611 if (pad) { 612 i = uio->uio_iovcnt++; 613 pad = 4 - pad; 614 pdu->io_vec[i].iov_base = pad_bytes; 615 pdu->io_vec[i].iov_len = pad; 616 uio->uio_resid += pad; 617 } 618 619 if (conn->DataDigest) { 620 pdu->data_digest = gen_digest_2(data, dsl, pad_bytes, pad); 621 i = uio->uio_iovcnt++; 622 pdu->io_vec[i].iov_base = &pdu->data_digest; 623 pdu->io_vec[i].iov_len = 4; 624 uio->uio_resid += 4; 625 } 626 } 627 } 628 629 /* 630 * init_login_pdu: 631 * Initialize the login PDU. 632 * 633 * Parameter: 634 * conn The connection 635 * ccb The CCB 636 * pdu The PDU 637 */ 638 639 STATIC void 640 init_login_pdu(connection_t *conn, ccb_t *ccb, pdu_t *ppdu, bool next) 641 { 642 pdu_header_t *pdu = &ppdu->pdu; 643 login_isid_t *isid = (login_isid_t *) & pdu->LUN; 644 uint8_t c_phase; 645 646 pdu->Opcode = IOP_Login_Request | OP_IMMEDIATE; 647 648 mutex_enter(&conn->session->lock); 649 ccb->CmdSN = get_sernum(conn->session, ppdu); 650 mutex_exit(&conn->session->lock); 651 652 if (next) { 653 c_phase = (pdu->Flags >> CSG_SHIFT) & SG_MASK; 654 pdu->Flags = FLAG_TRANSIT | (c_phase << CSG_SHIFT) | 655 NEXT_PHASE(c_phase); 656 } 657 658 memcpy(isid, &iscsi_InitiatorISID, 6); 659 isid->TSIH = conn->session->TSIH; 660 661 pdu->p.login_req.CID = htons(conn->id); 662 pdu->p.login_req.CmdSN = htonl(ccb->CmdSN); 663 } 664 665 666 /* 667 * negotiate_login: 668 * Control login negotiation. 669 * 670 * Parameter: 671 * conn The connection 672 * rx_pdu The received login response PDU 673 * tx_ccb The originally sent login CCB 674 */ 675 676 void 677 negotiate_login(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 678 { 679 int rc; 680 bool next = TRUE; 681 pdu_t *tx_pdu; 682 uint8_t c_phase; 683 684 if (rx_pdu->pdu.Flags & FLAG_TRANSIT) 685 c_phase = rx_pdu->pdu.Flags & SG_MASK; 686 else 687 c_phase = (rx_pdu->pdu.Flags >> CSG_SHIFT) & SG_MASK; 688 689 DEB(99, ("NegotiateLogin: Flags=%x Phase=%x\n", 690 rx_pdu->pdu.Flags, c_phase)); 691 692 if (c_phase == SG_FULL_FEATURE_PHASE) { 693 session_t *sess = conn->session; 694 695 if (!sess->TSIH) 696 sess->TSIH = ((login_isid_t *) &rx_pdu->pdu.LUN)->TSIH; 697 698 if (rx_pdu->temp_data != NULL) 699 assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, NULL); 700 701 /* negotiated values are now valid */ 702 set_negotiated_parameters(tx_ccb); 703 704 DEBC(conn, 5, ("Login Successful!\n")); 705 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS); 706 return; 707 } 708 709 tx_pdu = get_pdu(conn, TRUE); 710 if (tx_pdu == NULL) 711 return; 712 713 tx_pdu->pdu.Flags = c_phase << CSG_SHIFT; 714 715 switch (c_phase) { 716 case SG_SECURITY_NEGOTIATION: 717 rc = assemble_security_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 718 if (rc < 0) 719 next = FALSE; 720 break; 721 722 case SG_LOGIN_OPERATIONAL_NEGOTIATION: 723 rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 724 break; 725 726 default: 727 DEBOUT(("Invalid phase %x in negotiate_login\n", c_phase)); 728 rc = ISCSI_STATUS_TARGET_ERROR; 729 break; 730 } 731 732 if (rc > 0) { 733 wake_ccb(tx_ccb, rc); 734 free_pdu(tx_pdu); 735 } else { 736 init_login_pdu(conn, tx_ccb, tx_pdu, next); 737 setup_tx_uio(tx_pdu, tx_pdu->temp_data_len, tx_pdu->temp_data, FALSE); 738 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 739 } 740 } 741 742 743 /* 744 * init_text_pdu: 745 * Initialize the text PDU. 746 * 747 * Parameter: 748 * conn The connection 749 * ccb The transmit CCB 750 * ppdu The transmit PDU 751 * rx_pdu The received PDU if this is an unsolicited negotiation 752 */ 753 754 STATIC void 755 init_text_pdu(connection_t *conn, ccb_t *ccb, pdu_t *ppdu, pdu_t *rx_pdu) 756 { 757 pdu_header_t *pdu = &ppdu->pdu; 758 759 pdu->Opcode = IOP_Text_Request | OP_IMMEDIATE; 760 pdu->Flags = FLAG_FINAL; 761 762 mutex_enter(&conn->session->lock); 763 ccb->CmdSN = get_sernum(conn->session, ppdu); 764 mutex_exit(&conn->session->lock); 765 766 if (rx_pdu != NULL) { 767 pdu->p.text_req.TargetTransferTag = 768 rx_pdu->pdu.p.text_rsp.TargetTransferTag; 769 pdu->LUN = rx_pdu->pdu.LUN; 770 } else 771 pdu->p.text_req.TargetTransferTag = 0xffffffff; 772 773 pdu->p.text_req.CmdSN = htonl(ccb->CmdSN); 774 } 775 776 777 /* 778 * acknowledge_text: 779 * Acknowledge a continued login or text response. 780 * 781 * Parameter: 782 * conn The connection 783 * rx_pdu The received login/text response PDU 784 * tx_ccb The originally sent login/text request CCB 785 */ 786 787 void 788 acknowledge_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 789 { 790 pdu_t *tx_pdu; 791 792 tx_pdu = get_pdu(conn, TRUE); 793 if (tx_pdu == NULL) 794 return; 795 796 if (rx_pdu != NULL && 797 (rx_pdu->pdu.Opcode & OPCODE_MASK) == IOP_Login_Request) 798 init_login_pdu(conn, tx_ccb, tx_pdu, FALSE); 799 else 800 init_text_pdu(conn, tx_ccb, tx_pdu, rx_pdu); 801 802 setup_tx_uio(tx_pdu, 0, NULL, FALSE); 803 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 804 } 805 806 807 /* 808 * start_text_negotiation: 809 * Handle target request to negotiate (via asynch event) 810 * 811 * Parameter: 812 * conn The connection 813 */ 814 815 void 816 start_text_negotiation(connection_t *conn) 817 { 818 pdu_t *pdu; 819 ccb_t *ccb; 820 821 ccb = get_ccb(conn, TRUE); 822 if (ccb == NULL) 823 return; 824 pdu = get_pdu(conn, TRUE); 825 if (pdu == NULL) { 826 free_ccb(ccb); 827 return; 828 } 829 830 if (init_text_parameters(conn, ccb)) { 831 free_ccb(ccb); 832 free_pdu(pdu); 833 return; 834 } 835 836 init_text_pdu(conn, ccb, pdu, NULL); 837 setup_tx_uio(pdu, 0, NULL, FALSE); 838 send_pdu(ccb, pdu, CCBDISP_FREE, PDUDISP_WAIT); 839 } 840 841 842 /* 843 * negotiate_text: 844 * Handle received text negotiation. 845 * 846 * Parameter: 847 * conn The connection 848 * rx_pdu The received text response PDU 849 * tx_ccb The original CCB 850 */ 851 852 void 853 negotiate_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 854 { 855 int rc; 856 pdu_t *tx_pdu; 857 858 if (tx_ccb->flags & CCBF_SENDTARGET) { 859 if (!(rx_pdu->pdu.Flags & FLAG_FINAL)) { 860 handle_connection_error(conn, ISCSI_STATUS_PROTOCOL_ERROR, 861 LOGOUT_CONNECTION); 862 return; 863 } 864 /* transfer ownership of text to CCB */ 865 tx_ccb->text_data = rx_pdu->temp_data; 866 tx_ccb->text_len = rx_pdu->temp_data_len; 867 rx_pdu->temp_data = NULL; 868 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS); 869 } else { 870 if (!(rx_pdu->pdu.Flags & FLAG_FINAL)) 871 tx_pdu = get_pdu(conn, TRUE); 872 else 873 tx_pdu = NULL; 874 875 rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 876 if (rc) { 877 if (tx_pdu != NULL) 878 free_pdu(tx_pdu); 879 880 handle_connection_error(conn, rc, LOGOUT_CONNECTION); 881 } else if (tx_pdu != NULL) { 882 init_text_pdu(conn, tx_ccb, tx_pdu, rx_pdu); 883 setup_tx_uio(tx_pdu, tx_pdu->temp_data_len, 884 tx_pdu->temp_data, FALSE); 885 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 886 } else { 887 set_negotiated_parameters(tx_ccb); 888 wake_ccb(tx_ccb, ISCSI_STATUS_SUCCESS); 889 } 890 } 891 } 892 893 894 /* 895 * send_send_targets: 896 * Send out a SendTargets text request. 897 * The result is stored in the fields in the session structure. 898 * 899 * Parameter: 900 * session The session 901 * key The text key to use 902 * 903 * Returns: 0 on success, else an error code. 904 */ 905 906 int 907 send_send_targets(session_t *session, uint8_t *key) 908 { 909 ccb_t *ccb; 910 pdu_t *pdu; 911 int rc = 0; 912 connection_t *conn; 913 914 DEB(9, ("Send_send_targets\n")); 915 916 conn = assign_connection(session, TRUE); 917 if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) 918 return (conn != NULL && conn->terminating) ? conn->terminating 919 : ISCSI_STATUS_CONNECTION_FAILED; 920 921 ccb = get_ccb(conn, TRUE); 922 if (ccb == NULL) 923 return conn->terminating; 924 pdu = get_pdu(conn, TRUE); 925 if (pdu == NULL) { 926 free_ccb(ccb); 927 return conn->terminating; 928 } 929 930 ccb->flags |= CCBF_SENDTARGET; 931 932 if ((rc = assemble_send_targets(pdu, key)) != 0) { 933 free_ccb(ccb); 934 free_pdu(pdu); 935 return rc; 936 } 937 938 init_text_pdu(conn, ccb, pdu, NULL); 939 940 setup_tx_uio(pdu, pdu->temp_data_len, pdu->temp_data, FALSE); 941 send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_WAIT); 942 943 rc = ccb->status; 944 if (!rc) { 945 /* transfer ownership of data */ 946 session->target_list = ccb->text_data; 947 session->target_list_len = ccb->text_len; 948 ccb->text_data = NULL; 949 } 950 free_ccb(ccb); 951 return rc; 952 } 953 954 955 /* 956 * send_nop_out: 957 * Send nop out request. 958 * 959 * Parameter: 960 * conn The connection 961 * rx_pdu The received Nop-In PDU 962 * 963 * Returns: 0 on success, else an error code. 964 */ 965 966 int 967 send_nop_out(connection_t *conn, pdu_t *rx_pdu) 968 { 969 session_t *sess; 970 ccb_t *ccb; 971 pdu_t *ppdu; 972 pdu_header_t *pdu; 973 uint32_t sn; 974 975 if (rx_pdu != NULL) { 976 ccb = NULL; 977 ppdu = get_pdu(conn, TRUE); 978 if (ppdu == NULL) 979 return 1; 980 } else { 981 ccb = get_ccb(conn, FALSE); 982 if (ccb == NULL) { 983 DEBOUT(("Can't get CCB in send_nop_out\n")); 984 return 1; 985 } 986 ppdu = get_pdu(conn, FALSE); 987 if (ppdu == NULL) { 988 free_ccb(ccb); 989 DEBOUT(("Can't get PDU in send_nop_out\n")); 990 return 1; 991 } 992 } 993 994 pdu = &ppdu->pdu; 995 pdu->Flags = FLAG_FINAL; 996 pdu->Opcode = IOP_NOP_Out | OP_IMMEDIATE; 997 998 sess = conn->session; 999 1000 mutex_enter(&sess->lock); 1001 sn = get_sernum(sess, ppdu); 1002 mutex_exit(&sess->lock); 1003 1004 if (rx_pdu != NULL) { 1005 pdu->p.nop_out.TargetTransferTag = 1006 rx_pdu->pdu.p.nop_in.TargetTransferTag; 1007 pdu->InitiatorTaskTag = rx_pdu->pdu.InitiatorTaskTag; 1008 pdu->p.nop_out.CmdSN = htonl(sn); 1009 pdu->LUN = rx_pdu->pdu.LUN; 1010 } else { 1011 pdu->p.nop_out.TargetTransferTag = 0xffffffff; 1012 pdu->InitiatorTaskTag = 0xffffffff; 1013 ccb->CmdSN = sn; 1014 pdu->p.nop_out.CmdSN = htonl(sn); 1015 } 1016 1017 DEBC(conn, 10, ("Send NOP_Out CmdSN=%d, rx_pdu=%p\n", sn, rx_pdu)); 1018 1019 setup_tx_uio(ppdu, 0, NULL, FALSE); 1020 send_pdu(ccb, ppdu, (rx_pdu != NULL) ? CCBDISP_NOWAIT : CCBDISP_FREE, 1021 PDUDISP_FREE); 1022 return 0; 1023 } 1024 1025 1026 /* 1027 * snack_missing: 1028 * Send SNACK request for missing data. 1029 * 1030 * Parameter: 1031 * conn The connection 1032 * ccb The task's CCB (for Data NAK only) 1033 * type The SNACK type 1034 * BegRun The BegRun field 1035 * RunLength The RunLength field 1036 */ 1037 1038 void 1039 snack_missing(connection_t *conn, ccb_t *ccb, uint8_t type, 1040 uint32_t BegRun, uint32_t RunLength) 1041 { 1042 pdu_t *ppdu; 1043 pdu_header_t *pdu; 1044 1045 ppdu = get_pdu(conn, TRUE); 1046 if (ppdu == NULL) 1047 return; 1048 pdu = &ppdu->pdu; 1049 pdu->Opcode = IOP_SNACK_Request; 1050 pdu->Flags = FLAG_FINAL | type; 1051 1052 pdu->InitiatorTaskTag = (type == SNACK_DATA_NAK) ? ccb->ITT : 0xffffffff; 1053 pdu->p.snack.TargetTransferTag = 0xffffffff; 1054 pdu->p.snack.BegRun = htonl(BegRun); 1055 pdu->p.snack.RunLength = htonl(RunLength); 1056 1057 ppdu->flags = PDUF_PRIORITY; 1058 1059 setup_tx_uio(ppdu, 0, NULL, FALSE); 1060 send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE); 1061 } 1062 1063 1064 /* 1065 * send_snack: 1066 * Send SNACK request. 1067 * 1068 * Parameter: 1069 * conn The connection 1070 * rx_pdu The received data in PDU 1071 * tx_ccb The original command CCB (required for Data ACK only) 1072 * type The SNACK type 1073 * 1074 * Returns: 0 on success, else an error code. 1075 */ 1076 1077 void 1078 send_snack(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb, uint8_t type) 1079 { 1080 pdu_t *ppdu; 1081 pdu_header_t *pdu; 1082 1083 ppdu = get_pdu(conn, TRUE); 1084 if (ppdu == NULL) 1085 return; 1086 pdu = &ppdu->pdu; 1087 pdu->Opcode = IOP_SNACK_Request; 1088 pdu->Flags = FLAG_FINAL | type; 1089 1090 switch (type) { 1091 case SNACK_DATA_NAK: 1092 pdu->InitiatorTaskTag = rx_pdu->pdu.InitiatorTaskTag; 1093 pdu->p.snack.TargetTransferTag = 0xffffffff; 1094 pdu->p.snack.BegRun = rx_pdu->pdu.p.data_in.DataSN; 1095 pdu->p.snack.RunLength = htonl(1); 1096 break; 1097 1098 case SNACK_STATUS_NAK: 1099 pdu->InitiatorTaskTag = 0xffffffff; 1100 pdu->p.snack.TargetTransferTag = 0xffffffff; 1101 pdu->p.snack.BegRun = rx_pdu->pdu.p.response.StatSN; 1102 pdu->p.snack.RunLength = htonl(1); 1103 break; 1104 1105 case SNACK_DATA_ACK: 1106 pdu->InitiatorTaskTag = 0xffffffff; 1107 pdu->p.snack.TargetTransferTag = 1108 rx_pdu->pdu.p.data_in.TargetTransferTag; 1109 pdu->p.snack.BegRun = tx_ccb->DataSN_buf.ExpSN; 1110 pdu->p.snack.RunLength = 0; 1111 break; 1112 1113 default: 1114 DEBOUT(("Invalid type %d in send_snack\n", type)); 1115 return; 1116 } 1117 1118 pdu->LUN = rx_pdu->pdu.LUN; 1119 1120 ppdu->flags = PDUF_PRIORITY; 1121 1122 setup_tx_uio(ppdu, 0, NULL, FALSE); 1123 send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE); 1124 } 1125 1126 1127 /* 1128 * send_login: 1129 * Send login request. 1130 * 1131 * Parameter: 1132 * conn The connection 1133 * par The login parameters (for negotiation) 1134 * 1135 * Returns: 0 on success, else an error code. 1136 */ 1137 1138 int 1139 send_login(connection_t *conn) 1140 { 1141 ccb_t *ccb; 1142 pdu_t *pdu; 1143 int rc; 1144 1145 DEBC(conn, 9, ("Send_login\n")); 1146 ccb = get_ccb(conn, TRUE); 1147 /* only if terminating (which couldn't possibly happen here, but...) */ 1148 if (ccb == NULL) 1149 return conn->terminating; 1150 pdu = get_pdu(conn, TRUE); 1151 if (pdu == NULL) { 1152 free_ccb(ccb); 1153 return conn->terminating; 1154 } 1155 1156 if ((rc = assemble_login_parameters(conn, ccb, pdu)) <= 0) { 1157 init_login_pdu(conn, ccb, pdu, !rc); 1158 setup_tx_uio(pdu, pdu->temp_data_len, pdu->temp_data, FALSE); 1159 send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_FREE); 1160 rc = ccb->status; 1161 } else { 1162 free_pdu(pdu); 1163 } 1164 free_ccb(ccb); 1165 return rc; 1166 } 1167 1168 1169 /* 1170 * send_logout: 1171 * Send logout request. 1172 * NOTE: This function does not wait for the logout to complete. 1173 * 1174 * Parameter: 1175 * conn The connection 1176 * refconn The referenced connection 1177 * reason The reason code 1178 * wait Wait for completion if TRUE 1179 * 1180 * Returns: 0 on success (logout sent), else an error code. 1181 */ 1182 1183 int 1184 send_logout(connection_t *conn, connection_t *refconn, int reason, 1185 bool wait) 1186 { 1187 ccb_t *ccb; 1188 pdu_t *ppdu; 1189 pdu_header_t *pdu; 1190 1191 DEBC(conn, 5, ("Send_logout\n")); 1192 ccb = get_ccb(conn, TRUE); 1193 /* can only happen if terminating... */ 1194 if (ccb == NULL) 1195 return conn->terminating; 1196 ppdu = get_pdu(conn, TRUE); 1197 if (ppdu == NULL) { 1198 free_ccb(ccb); 1199 return conn->terminating; 1200 } 1201 1202 pdu = &ppdu->pdu; 1203 pdu->Opcode = IOP_Logout_Request | OP_IMMEDIATE; 1204 1205 pdu->Flags = FLAG_FINAL | reason; 1206 ccb->CmdSN = conn->session->CmdSN; 1207 pdu->p.logout_req.CmdSN = htonl(ccb->CmdSN); 1208 if (reason > 0) 1209 pdu->p.logout_req.CID = htons(refconn->id); 1210 1211 ccb->par = refconn; 1212 if (refconn != conn) { 1213 ccb->flags |= CCBF_OTHERCONN; 1214 } else { 1215 conn->state = ST_LOGOUT_SENT; 1216 conn->loggedout = LOGOUT_SENT; 1217 } 1218 1219 setup_tx_uio(ppdu, 0, NULL, FALSE); 1220 send_pdu(ccb, ppdu, (wait) ? CCBDISP_WAIT : CCBDISP_FREE, PDUDISP_FREE); 1221 1222 if (wait) { 1223 int rc = ccb->status; 1224 free_ccb (ccb); 1225 return rc; 1226 } 1227 return 0; 1228 } 1229 1230 1231 /* 1232 * send_task_management: 1233 * Send task management request. 1234 * 1235 * Parameter: 1236 * conn The connection 1237 * ref_ccb The referenced command (NULL if none) 1238 * xs The scsipi command structure (NULL if not a scsipi request) 1239 * function The function code 1240 * 1241 * Returns: 0 on success, else an error code. 1242 */ 1243 1244 int 1245 send_task_management(connection_t *conn, ccb_t *ref_ccb, struct scsipi_xfer *xs, 1246 int function) 1247 { 1248 ccb_t *ccb; 1249 pdu_t *ppdu; 1250 pdu_header_t *pdu; 1251 1252 DEBC(conn, 5, ("Send_task_management, ref_ccb=%p, func = %d\n", 1253 ref_ccb, function)); 1254 1255 if (function == TASK_REASSIGN && conn->session->ErrorRecoveryLevel < 2) 1256 return ISCSI_STATUS_CANT_REASSIGN; 1257 1258 ccb = get_ccb(conn, xs == NULL); 1259 /* can only happen if terminating... */ 1260 if (ccb == NULL) 1261 return conn->terminating; 1262 ppdu = get_pdu(conn, xs == NULL); 1263 if (ppdu == NULL) { 1264 free_ccb(ccb); 1265 return conn->terminating; 1266 } 1267 1268 ccb->xs = xs; 1269 1270 pdu = &ppdu->pdu; 1271 pdu->Opcode = IOP_SCSI_Task_Management | OP_IMMEDIATE; 1272 pdu->Flags = FLAG_FINAL | function; 1273 1274 ccb->CmdSN = conn->session->CmdSN; 1275 pdu->p.task_req.CmdSN = htonl(ccb->CmdSN); 1276 1277 if (ref_ccb != NULL) { 1278 pdu->p.task_req.ReferencedTaskTag = ref_ccb->ITT; 1279 pdu->p.task_req.RefCmdSN = htonl(ref_ccb->CmdSN); 1280 pdu->p.task_req.ExpDataSN = htonl(ref_ccb->DataSN_buf.ExpSN); 1281 } else 1282 pdu->p.task_req.ReferencedTaskTag = 0xffffffff; 1283 1284 ppdu->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->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 *pdu; 1314 uint32_t totlen, len, offs, sn; 1315 pdu_t *tx_pdu; 1316 1317 KASSERT(conn->max_transfer != 0); 1318 1319 if (rx_pdu) { 1320 offs = ntohl(rx_pdu->pdu.p.r2t.BufferOffset); 1321 totlen = ntohl(rx_pdu->pdu.p.r2t.DesiredDataTransferLength); 1322 } else { 1323 offs = conn->max_firstimmed; 1324 totlen = min(conn->max_firstdata - offs, tx_ccb->data_len - offs); 1325 } 1326 sn = 0; 1327 1328 while (totlen) { 1329 len = min(totlen, conn->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->disp = disp; 1336 tx_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 pdu = &tx_pdu->pdu; 1344 pdu->Opcode = IOP_SCSI_Data_out; 1345 if (!totlen) 1346 pdu->Flags = FLAG_FINAL; 1347 1348 if (rx_pdu != NULL) 1349 pdu->p.data_out.TargetTransferTag = 1350 rx_pdu->pdu.p.r2t.TargetTransferTag; 1351 else 1352 pdu->p.data_out.TargetTransferTag = 0xffffffff; 1353 pdu->p.data_out.BufferOffset = htonl(offs); 1354 pdu->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->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->connection; 1383 session_t *sess = ccb->session; 1384 pdu_t *ppdu; 1385 pdu_header_t *pdu; 1386 1387 mutex_enter(&sess->lock); 1388 while (!sernum_in_window(sess)) { 1389 mutex_exit(&sess->lock); 1390 ccb->disp = disp; 1391 wake_ccb(ccb, ISCSI_STATUS_QUEUE_FULL); 1392 return; 1393 } 1394 mutex_exit(&sess->lock); 1395 1396 /* Don't confuse targets during (re-)negotations */ 1397 if (conn->state != ST_FULL_FEATURE) { 1398 DEBOUT(("Invalid connection for send_command, ccb = %p\n",ccb)); 1399 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->disp = disp; 1408 wake_ccb(ccb, ISCSI_STATUS_NO_RESOURCES); 1409 return; 1410 } 1411 1412 totlen = len = ccb->data_len; 1413 1414 pdu = &ppdu->pdu; 1415 pdu->LUN = htonq(ccb->lun); 1416 memcpy(pdu->p.command.SCSI_CDB, ccb->cmd, ccb->cmdlen); 1417 pdu->Opcode = IOP_SCSI_Command; 1418 if (immed) 1419 pdu->Opcode |= OP_IMMEDIATE; 1420 pdu->p.command.ExpectedDataTransferLength = htonl(totlen); 1421 1422 if (totlen) { 1423 if (ccb->data_in) { 1424 pdu->Flags = FLAG_READ; 1425 totlen = 0; 1426 } else { 1427 pdu->Flags = FLAG_WRITE; 1428 /* immediate data we can send */ 1429 len = min(totlen, conn->max_firstimmed); 1430 1431 /* can we send more unsolicited data ? */ 1432 totlen = conn->max_firstdata ? totlen - len : 0; 1433 } 1434 } 1435 if (!totlen) 1436 pdu->Flags |= FLAG_FINAL; 1437 pdu->Flags |= ccb->tag; 1438 1439 if (ccb->data_in) 1440 init_sernum(&ccb->DataSN_buf); 1441 1442 ccb->sense_len_got = 0; 1443 ccb->xfer_len = 0; 1444 ccb->residual = 0; 1445 ccb->flags |= CCBF_REASSIGN; 1446 1447 mutex_enter(&sess->lock); 1448 ccb->CmdSN = get_sernum(sess, ppdu); 1449 mutex_exit(&sess->lock); 1450 1451 pdu->p.command.CmdSN = htonl(ccb->CmdSN); 1452 1453 DEBC(conn, 10, ("Send Command: CmdSN %d (%d), data_in %d, len %d, totlen %d\n", 1454 ccb->CmdSN, sess->MaxCmdSN, ccb->data_in, len, totlen)); 1455 1456 setup_tx_uio(ppdu, len, ccb->data_ptr, 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->terminating || conn->state != ST_FULL_FEATURE) { 1489 xs->error = XS_SELTIMEOUT; 1490 DEBC(conn, 10, ("run_xfer on dead connection\n")); 1491 scsipi_done(xs); 1492 unref_session(session); 1493 return; 1494 } 1495 1496 if (xs->xs_control & XS_CTL_RESET) { 1497 if (send_task_management(conn, NULL, xs, TARGET_WARM_RESET)) { 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->usecount)); 1509 scsipi_done(xs); 1510 unref_session(session); 1511 return; 1512 } 1513 /* copy parameters into CCB for easier access */ 1514 ccb->xs = xs; 1515 1516 ccb->data_in = (xs->xs_control & XS_CTL_DATA_IN) != 0; 1517 ccb->data_len = (uint32_t) xs->datalen; 1518 ccb->data_ptr = xs->data; 1519 1520 ccb->sense_len_req = sizeof(xs->sense.scsi_sense); 1521 ccb->sense_ptr = &xs->sense; 1522 1523 ccb->lun = ((uint64_t) (uint8_t) xs->xs_periph->periph_lun) << 48; 1524 ccb->cmd = (uint8_t *) xs->cmd; 1525 ccb->cmdlen = xs->cmdlen; 1526 DEB(10, ("RunXfer: Periph_lun = %d, cmd[1] = %x, cmdlen = %d\n", 1527 xs->xs_periph->periph_lun, ccb->cmd[1], xs->cmdlen)); 1528 1529 ccb->ITT |= xs->xs_tag_id << 24; 1530 switch (xs->xs_tag_type) { 1531 case MSG_ORDERED_Q_TAG: 1532 ccb->tag = ATTR_ORDERED; 1533 break; 1534 case MSG_SIMPLE_Q_TAG: 1535 ccb->tag = ATTR_SIMPLE; 1536 break; 1537 case MSG_HEAD_OF_Q_TAG: 1538 ccb->tag = ATTR_HEAD_OF_QUEUE; 1539 break; 1540 default: 1541 ccb->tag = 0; 1542 break; 1543 } 1544 1545 #ifdef LUN_1 1546 ccb->lun += 0x1000000000000LL; 1547 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->terminating || conn->state != ST_FULL_FEATURE) { 1581 DEBOUT(("io_command on dead connection (state = %d)\n", 1582 (conn != NULL) ? conn->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->data_in = (req->flags & SCCMD_READ) != 0; 1593 ccb->data_len = (uint32_t) req->datalen; 1594 ccb->data_ptr = req->databuf; 1595 1596 ccb->sense_len_req = req->senselen; 1597 ccb->sense_ptr = &req->sense; 1598 1599 ccb->lun = lun; 1600 ccb->cmd = (uint8_t *) req->cmd; 1601 ccb->cmdlen = req->cmdlen; 1602 DEBC(conn, 10, ("IoCommand: cmd[1] = %x, cmdlen = %d\n", 1603 ccb->cmd[1], ccb->cmdlen)); 1604 1605 send_command(ccb, CCBDISP_WAIT, TRUE, immed); 1606 1607 rc = ccb->status; 1608 1609 req->senselen_used = ccb->sense_len_got; 1610 req->datalen_used = req->datalen - 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->num_timeouts > MAX_CONN_TIMEOUTS) 1638 handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, NO_LOGOUT); 1639 else { 1640 if (conn->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->connection; 1659 1660 ccb->total_tries++; 1661 1662 DEBC(conn, 0, ("ccb_timeout: num=%d total=%d disp=%d\n", 1663 ccb->num_timeouts+1, ccb->total_tries, ccb->disp)); 1664 1665 if (++ccb->num_timeouts > MAX_CCB_TIMEOUTS || 1666 ccb->total_tries > MAX_CCB_TRIES || 1667 ccb->disp <= CCBDISP_FREE || 1668 !ccb->session->ErrorRecoveryLevel) { 1669 1670 wake_ccb(ccb, ISCSI_STATUS_TIMEOUT); 1671 handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, RECOVER_CONNECTION); 1672 } else { 1673 if (ccb->data_in && ccb->xfer_len < 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