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