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