1/* $NetBSD: iscsi_send.c,v 1.1.8.1 2012/06/12 19:41:25 riz 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 shutdown 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 355 /* wake up any non-reassignable waiting CCBs */ 356 for (ccb = TAILQ_FIRST(&conn->ccbs_waiting); ccb != NULL; ccb = nccb) { 357 nccb = TAILQ_NEXT(ccb, chain); 358 if (!(ccb->flags & CCBF_REASSIGN) || ccb->pdu_waiting == NULL) { 359 DEBC(conn, 9, ("Terminating CCB %p (t=%p)\n", 360 ccb,&ccb->timeout)); 361 ccb->status = conn->terminating; 362 wake_ccb(ccb); 363 } else { 364 callout_stop(&ccb->timeout); 365 ccb->num_timeouts = 0; 366 } 367 } 368 369 /* clean out anything left in send queue */ 370 while ((pdu = TAILQ_FIRST(&conn->pdus_to_send)) != NULL) { 371 TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain); 372 pdu->flags &= ~(PDUF_INQUEUE | PDUF_BUSY); 373 /* if it's not attached to a waiting CCB, free it */ 374 if (pdu->owner == NULL || 375 pdu->owner->pdu_waiting != pdu) { 376 free_pdu(pdu); 377 } 378 } 379 380 /* If there's another connection available, transfer pending tasks */ 381 if (sess->active_connections && 382 TAILQ_FIRST(&conn->ccbs_waiting) != NULL) { 383 reassign_tasks (conn); 384 } else if (!conn->destroy && conn->Time2Wait) { 385 tsleep(&s, PRIBIO, "Time2Wait", conn->Time2Wait * hz); 386 } 387 /* notify event handlers of connection shutdown */ 388 add_event((conn->destroy) ? ISCSI_CONNECTION_TERMINATED 389 : ISCSI_RECOVER_CONNECTION, 390 sess->id, conn->id, conn->terminating); 391 392 if (!conn->destroy) 393 tsleep(conn, PRIBIO, "conn_idle", 0); 394 395 } while (!conn->destroy); 396 397 /* wake up anyone waiting for a PDU */ 398 wakeup(&conn->pdu_pool); 399 400 /* wake up any waiting CCBs */ 401 while ((ccb = TAILQ_FIRST(&conn->ccbs_waiting)) != NULL) { 402 ccb->status = conn->terminating; 403 wake_ccb(ccb); 404 /* NOTE: wake_ccb will remove the CCB from the queue */ 405 } 406 407 s = splbio(); 408 if (conn->in_session) { 409 conn->in_session = FALSE; 410 TAILQ_REMOVE(&sess->conn_list, conn, connections); 411 sess->mru_connection = TAILQ_FIRST(&sess->conn_list); 412 } 413 414 TAILQ_INSERT_TAIL(&cleanup_list, conn, connections); 415 splx(s); 416 417 wakeup(&cleanup_list); 418 419 conn->sendproc = NULL; 420 DEBC(conn, 5, ("Send thread exits\n")); 421 num_send_threads--; 422 kthread_exit(0); 423} 424 425 426/* 427 * send_pdu: 428 * Enqueue a PDU to be sent, and handle its disposition as well as 429 * the disposition of its associated CCB. 430 * 431 * Parameter: 432 * ccb The associated CCB. May be NULL if cdisp is CCBDISP_NOWAIT 433 * and pdisp is not PDUDISP_WAIT 434 * cdisp The CCB's disposition 435 * pdu The PDU 436 * pdisp The PDU's disposition 437 */ 438 439STATIC void 440send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_disp_t cdisp, pdu_disp_t pdisp) 441{ 442 connection_t *conn = pdu->connection; 443 ccb_disp_t prev_cdisp = 0; 444 445 if (ccb != NULL) { 446 prev_cdisp = ccb->disp; 447 pdu->pdu.InitiatorTaskTag = ccb->ITT; 448 pdu->owner = ccb; 449 if (cdisp != CCBDISP_NOWAIT) 450 ccb->disp = cdisp; 451 } 452 453 pdu->disp = pdisp; 454 455 DEBC(conn, 10, ("Send_pdu: ccb=%p, pcd=%d, cdsp=%d, pdu=%p, pdsp=%d\n", 456 ccb, prev_cdisp, cdisp, pdu, pdisp)); 457 458 CS_BEGIN; 459 if (pdisp == PDUDISP_WAIT) { 460 ccb->pdu_waiting = pdu; 461 462 /* save UIO and IOVEC for retransmit */ 463 pdu->save_uio = pdu->uio; 464 memcpy(pdu->save_iovec, pdu->io_vec, sizeof(pdu->save_iovec)); 465 466 pdu->flags |= PDUF_BUSY; 467 } 468 /* Enqueue for sending */ 469 pdu->flags |= PDUF_INQUEUE; 470 471 if (pdu->flags & PDUF_PRIORITY) 472 TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain); 473 else 474 TAILQ_INSERT_TAIL(&conn->pdus_to_send, pdu, send_chain); 475 476 wakeup(&conn->pdus_to_send); 477 478 if (cdisp != CCBDISP_NOWAIT) { 479 SET_CCB_TIMEOUT(conn, ccb, COMMAND_TIMEOUT); 480 481 if (prev_cdisp <= CCBDISP_NOWAIT) 482 TAILQ_INSERT_TAIL(&conn->ccbs_waiting, ccb, chain); 483 484 if (cdisp == CCBDISP_WAIT) 485 tsleep(ccb, PWAIT, "sendpdu", 0); 486 } 487 CS_END; 488} 489 490 491/* 492 * resend_pdu: 493 * Re-Enqueue a PDU that has apparently gotten lost. 494 * 495 * Parameter: 496 * ccb The associated CCB. 497 */ 498 499void 500resend_pdu(ccb_t *ccb) 501{ 502 connection_t *conn = ccb->connection; 503 pdu_t *pdu = ccb->pdu_waiting; 504 int s; 505 506 s = splbio (); 507 if (pdu == NULL || (pdu->flags & PDUF_BUSY)) { 508 splx (s); 509 return; 510 } 511 pdu->flags |= PDUF_BUSY; 512 splx (s); 513 514 /* restore UIO and IOVEC */ 515 pdu->uio = pdu->save_uio; 516 memcpy(pdu->io_vec, pdu->save_iovec, sizeof(pdu->io_vec)); 517 518 DEBC(conn, 8, ("ReSend_pdu ccb=%p, pdu=%p\n", ccb, pdu)); 519 520 s = splbio (); 521 522 /* Enqueue for sending */ 523 pdu->flags |= PDUF_INQUEUE; 524 525 if (pdu->flags & PDUF_PRIORITY) { 526 TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain); 527 } else { 528 TAILQ_INSERT_TAIL(&conn->pdus_to_send, pdu, send_chain); 529 } 530 SET_CCB_TIMEOUT(conn, ccb, COMMAND_TIMEOUT); 531 splx (s); 532 533 wakeup(&conn->pdus_to_send); 534} 535 536 537/* 538 * setup_tx_uio: 539 * Initialize the uio structure for sending, including header, 540 * data (if present), padding, and Data Digest. 541 * Header Digest is generated in send thread. 542 * 543 * Parameter: 544 * pdu The PDU 545 * dsl The Data Segment Length 546 * data The data pointer 547 * read TRUE if this is a read operation 548 */ 549 550STATIC void 551setup_tx_uio(pdu_t *pdu, uint32_t dsl, void *data, bool read) 552{ 553 static uint8_t pad_bytes[4] = { 0 }; 554 struct uio *uio; 555 int i, pad, hlen; 556 connection_t *conn = pdu->connection; 557 558 DEB(99, ("SetupTxUio: dlen = %d, dptr: %p, read: %d\n", 559 dsl, data, read)); 560 561 if (!read && dsl) { 562 hton3(dsl, pdu->pdu.DataSegmentLength); 563 } 564 hlen = (conn->HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE; 565 566 pdu->io_vec[0].iov_base = &pdu->pdu; 567 pdu->io_vec[0].iov_len = hlen; 568 569 uio = &pdu->uio; 570 571 uio->uio_iov = pdu->io_vec; 572 uio->uio_iovcnt = 1; 573 uio->uio_rw = UIO_WRITE; 574 uio->uio_resid = hlen; 575 UIO_SETUP_SYSSPACE(uio); 576 577 if (!read && dsl) { 578 uio->uio_iovcnt++; 579 pdu->io_vec[1].iov_base = data; 580 pdu->io_vec[1].iov_len = dsl; 581 uio->uio_resid += dsl; 582 583 /* Pad to next multiple of 4 */ 584 pad = uio->uio_resid & 0x03; 585 if (pad) { 586 i = uio->uio_iovcnt++; 587 pad = 4 - pad; 588 pdu->io_vec[i].iov_base = pad_bytes; 589 pdu->io_vec[i].iov_len = pad; 590 uio->uio_resid += pad; 591 } 592 593 if (conn->DataDigest) { 594 pdu->data_digest = gen_digest_2(data, dsl, pad_bytes, pad); 595 i = uio->uio_iovcnt++; 596 pdu->io_vec[i].iov_base = &pdu->data_digest; 597 pdu->io_vec[i].iov_len = 4; 598 uio->uio_resid += 4; 599 } 600 } 601} 602 603/* 604 * init_login_pdu: 605 * Initialize the login PDU. 606 * 607 * Parameter: 608 * conn The connection 609 * pdu The PDU 610 */ 611 612STATIC void 613init_login_pdu(connection_t *conn, pdu_t *ppdu, bool next) 614{ 615 pdu_header_t *pdu = &ppdu->pdu; 616 login_isid_t *isid = (login_isid_t *) & pdu->LUN; 617 uint8_t c_phase; 618 619 pdu->Opcode = IOP_Login_Request | OP_IMMEDIATE; 620 621 if (next) { 622 c_phase = (pdu->Flags >> CSG_SHIFT) & SG_MASK; 623 pdu->Flags = FLAG_TRANSIT | (c_phase << CSG_SHIFT) | 624 NEXT_PHASE(c_phase); 625 } 626 627 memcpy(isid, &InitiatorISID, 6); 628 isid->TSIH = conn->session->TSIH; 629 630 pdu->p.login_req.CID = htons(conn->id); 631 pdu->p.login_req.CmdSN = htonl(conn->session->CmdSN); 632} 633 634 635/* 636 * negotiate_login: 637 * Control login negotiation. 638 * 639 * Parameter: 640 * conn The connection 641 * rx_pdu The received login response PDU 642 * tx_ccb The originally sent login CCB 643 */ 644 645void 646negotiate_login(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 647{ 648 int rc; 649 bool next = TRUE; 650 pdu_t *tx_pdu; 651 uint8_t c_phase; 652 653 if (rx_pdu->pdu.Flags & FLAG_TRANSIT) 654 c_phase = rx_pdu->pdu.Flags & SG_MASK; 655 else 656 c_phase = (rx_pdu->pdu.Flags >> CSG_SHIFT) & SG_MASK; 657 658 DEB(99, ("NegotiateLogin: Flags=%x Phase=%x\n", 659 rx_pdu->pdu.Flags, c_phase)); 660 661 if (c_phase == SG_FULL_FEATURE_PHASE) { 662 session_t *sess = conn->session; 663 664 if (!sess->TSIH) 665 sess->TSIH = ((login_isid_t *) &rx_pdu->pdu.LUN)->TSIH; 666 667 if (rx_pdu->temp_data != NULL) 668 assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, NULL); 669 670 /* negotiated values are now valid */ 671 set_negotiated_parameters(tx_ccb); 672 673 DEBC(conn, 5, ("Login Successful!\n")); 674 wake_ccb(tx_ccb); 675 return; 676 } 677 678 tx_pdu = get_pdu(conn); 679 if (tx_pdu == NULL) 680 return; 681 682 tx_pdu->pdu.Flags = c_phase << CSG_SHIFT; 683 684 switch (c_phase) { 685 case SG_SECURITY_NEGOTIATION: 686 rc = assemble_security_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 687 if (rc < 0) 688 next = FALSE; 689 break; 690 691 case SG_LOGIN_OPERATIONAL_NEGOTIATION: 692 rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 693 break; 694 695 default: 696 DEBOUT(("Invalid phase %x in negotiate_login\n", c_phase)); 697 rc = ISCSI_STATUS_TARGET_ERROR; 698 break; 699 } 700 701 if (rc > 0) { 702 tx_ccb->status = rc; 703 wake_ccb(tx_ccb); 704 free_pdu(tx_pdu); 705 } else { 706 init_login_pdu(conn, tx_pdu, next); 707 setup_tx_uio(tx_pdu, tx_pdu->temp_data_len, tx_pdu->temp_data, FALSE); 708 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 709 } 710} 711 712 713/* 714 * init_text_pdu: 715 * Initialize the text PDU. 716 * 717 * Parameter: 718 * conn The connection 719 * ppdu The transmit PDU 720 * rx_pdu The received PDU if this is an unsolicited negotiation 721 */ 722 723STATIC void 724init_text_pdu(connection_t *conn, pdu_t *ppdu, pdu_t *rx_pdu) 725{ 726 pdu_header_t *pdu = &ppdu->pdu; 727 728 pdu->Opcode = IOP_Text_Request | OP_IMMEDIATE; 729 pdu->Flags = FLAG_FINAL; 730 731 if (rx_pdu != NULL) { 732 pdu->p.text_req.TargetTransferTag = 733 rx_pdu->pdu.p.text_rsp.TargetTransferTag; 734 pdu->LUN = rx_pdu->pdu.LUN; 735 } else 736 pdu->p.text_req.TargetTransferTag = 0xffffffff; 737 738 pdu->p.text_req.CmdSN = htonl(conn->session->CmdSN); 739} 740 741 742/* 743 * acknowledge_text: 744 * Acknowledge a continued login or text response. 745 * 746 * Parameter: 747 * conn The connection 748 * rx_pdu The received login/text response PDU 749 * tx_ccb The originally sent login/text request CCB 750 */ 751 752void 753acknowledge_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 754{ 755 pdu_t *tx_pdu; 756 757 tx_pdu = get_pdu(conn); 758 if (tx_pdu == NULL) 759 return; 760 761 if (rx_pdu != NULL && 762 (rx_pdu->pdu.Opcode & OPCODE_MASK) == IOP_Login_Request) 763 init_login_pdu(conn, tx_pdu, FALSE); 764 else 765 init_text_pdu(conn, tx_pdu, rx_pdu); 766 767 setup_tx_uio(tx_pdu, 0, NULL, FALSE); 768 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 769} 770 771 772/* 773 * start_text_negotiation: 774 * Handle target request to negotiate (via asynch event) 775 * 776 * Parameter: 777 * conn The connection 778 */ 779 780void 781start_text_negotiation(connection_t *conn) 782{ 783 pdu_t *pdu; 784 ccb_t *ccb; 785 786 ccb = get_ccb(conn, TRUE); 787 if (ccb == NULL) 788 return; 789 pdu = get_pdu(conn); 790 if (pdu == NULL) { 791 free_ccb(ccb); 792 return; 793 } 794 795 if (init_text_parameters(conn, ccb)) { 796 free_ccb(ccb); 797 free_pdu(pdu); 798 return; 799 } 800 801 init_text_pdu(conn, pdu, NULL); 802 setup_tx_uio(pdu, 0, NULL, FALSE); 803 send_pdu(ccb, pdu, CCBDISP_FREE, PDUDISP_WAIT); 804} 805 806 807/* 808 * negotiate_text: 809 * Handle received text negotiation. 810 * 811 * Parameter: 812 * conn The connection 813 * rx_pdu The received text response PDU 814 * tx_ccb The original CCB 815 */ 816 817void 818negotiate_text(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb) 819{ 820 int rc; 821 pdu_t *tx_pdu; 822 823 if (tx_ccb->flags & CCBF_SENDTARGET) { 824 if (!(rx_pdu->pdu.Flags & FLAG_FINAL)) { 825 handle_connection_error(conn, ISCSI_STATUS_PROTOCOL_ERROR, 826 LOGOUT_CONNECTION); 827 return; 828 } 829 /* transfer ownership of text to CCB */ 830 tx_ccb->text_data = rx_pdu->temp_data; 831 tx_ccb->text_len = rx_pdu->temp_data_len; 832 rx_pdu->temp_data = NULL; 833 wake_ccb(tx_ccb); 834 } else { 835 if (!(rx_pdu->pdu.Flags & FLAG_FINAL)) 836 tx_pdu = get_pdu(conn); 837 else 838 tx_pdu = NULL; 839 840 rc = assemble_negotiation_parameters(conn, tx_ccb, rx_pdu, tx_pdu); 841 if (rc) { 842 if (tx_pdu != NULL) 843 free_pdu(tx_pdu); 844 845 handle_connection_error(conn, rc, LOGOUT_CONNECTION); 846 } else if (tx_pdu != NULL) { 847 init_text_pdu(conn, tx_pdu, rx_pdu); 848 setup_tx_uio(tx_pdu, tx_pdu->temp_data_len, tx_pdu->temp_data, 849 FALSE); 850 send_pdu(tx_ccb, tx_pdu, CCBDISP_NOWAIT, PDUDISP_FREE); 851 } else { 852 set_negotiated_parameters(tx_ccb); 853 wake_ccb(tx_ccb); 854 } 855 } 856} 857 858 859/* 860 * send_send_targets: 861 * Send out a SendTargets text request. 862 * The result is stored in the fields in the session structure. 863 * 864 * Parameter: 865 * session The session 866 * key The text key to use 867 * 868 * Returns: 0 on success, else an error code. 869 */ 870 871int 872send_send_targets(session_t *session, uint8_t *key) 873{ 874 ccb_t *ccb; 875 pdu_t *pdu; 876 int rc = 0; 877 connection_t *conn; 878 879 DEB(9, ("Send_send_targets\n")); 880 881 conn = assign_connection(session, TRUE); 882 if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) 883 return (conn != NULL && conn->terminating) ? conn->terminating 884 : ISCSI_STATUS_CONNECTION_FAILED; 885 886 ccb = get_ccb(conn, TRUE); 887 if (ccb == NULL) 888 return conn->terminating; 889 pdu = get_pdu(conn); 890 if (pdu == NULL) { 891 free_ccb(ccb); 892 return conn->terminating; 893 } 894 895 ccb->flags |= CCBF_SENDTARGET; 896 897 if ((rc = assemble_send_targets(pdu, key)) != 0) { 898 free_ccb(ccb); 899 free_pdu(pdu); 900 return rc; 901 } 902 903 init_text_pdu(conn, pdu, NULL); 904 905 setup_tx_uio(pdu, pdu->temp_data_len, pdu->temp_data, FALSE); 906 send_pdu(ccb, pdu, CCBDISP_WAIT, PDUDISP_WAIT); 907 908 rc = ccb->status; 909 if (!rc) { 910 /* transfer ownership of data */ 911 session->target_list = ccb->text_data; 912 session->target_list_len = ccb->text_len; 913 ccb->text_data = NULL; 914 } 915 free_ccb(ccb); 916 return rc; 917} 918 919 920/* 921 * send_nop_out: 922 * Send nop out request. 923 * 924 * Parameter: 925 * conn The connection 926 * rx_pdu The received Nop-In PDU 927 * 928 * Returns: 0 on success, else an error code. 929 */ 930 931int 932send_nop_out(connection_t *conn, pdu_t *rx_pdu) 933{ 934 ccb_t *ccb; 935 pdu_t *ppdu; 936 pdu_header_t *pdu; 937 938 DEBC(conn, 10, ("Send NOP_Out rx_pdu=%p\n", rx_pdu)); 939 940 if (rx_pdu != NULL) { 941 ccb = NULL; 942 ppdu = get_pdu(conn); 943 if (ppdu == NULL) 944 return 1; 945 } else { 946 ccb = get_ccb(conn, FALSE); 947 if (ccb == NULL) { 948 DEBOUT(("Can't get CCB in send_nop_out\n")); 949 return 1; 950 } 951 ppdu = get_pdu_c(conn, FALSE); 952 if (ppdu == NULL) { 953 free_ccb(ccb); 954 DEBOUT(("Can't get PDU in send_nop_out\n")); 955 return 1; 956 } 957 } 958 959 pdu = &ppdu->pdu; 960 pdu->Flags = FLAG_FINAL; 961 pdu->Opcode = IOP_NOP_Out | OP_IMMEDIATE; 962 963 if (rx_pdu != NULL) { 964 pdu->p.nop_out.TargetTransferTag = 965 rx_pdu->pdu.p.nop_in.TargetTransferTag; 966 pdu->InitiatorTaskTag = rx_pdu->pdu.InitiatorTaskTag; 967 pdu->p.nop_out.CmdSN = htonl(conn->session->CmdSN); 968 pdu->LUN = rx_pdu->pdu.LUN; 969 } else { 970 pdu->p.nop_out.TargetTransferTag = 0xffffffff; 971 ccb->CmdSN = ccb->session->CmdSN; 972 pdu->p.nop_out.CmdSN = htonl(ccb->CmdSN); 973 } 974 975 setup_tx_uio(ppdu, 0, NULL, FALSE); 976 send_pdu(ccb, ppdu, (rx_pdu != NULL) ? CCBDISP_NOWAIT : CCBDISP_FREE, 977 PDUDISP_FREE); 978 return 0; 979} 980 981 982/* 983 * snack_missing: 984 * Send SNACK request for missing data. 985 * 986 * Parameter: 987 * conn The connection 988 * ccb The task's CCB (for Data NAK only) 989 * type The SNACK type 990 * BegRun The BegRun field 991 * RunLength The RunLength field 992 */ 993 994void 995snack_missing(connection_t *conn, ccb_t *ccb, uint8_t type, 996 uint32_t BegRun, uint32_t RunLength) 997{ 998 pdu_t *ppdu; 999 pdu_header_t *pdu; 1000 1001 PDEBC(conn, 1, ("SNACK Missing type = %d, BegRun %d RunLength %d\n", 1002 type, BegRun, RunLength)); 1003 1004 ppdu = get_pdu(conn); 1005 if (ppdu == NULL) 1006 return; 1007 pdu = &ppdu->pdu; 1008 pdu->Opcode = IOP_SNACK_Request; 1009 pdu->Flags = FLAG_FINAL | type; 1010 1011 pdu->InitiatorTaskTag = (type == SNACK_DATA_NAK) ? ccb->ITT : 0xffffffff; 1012 pdu->p.snack.TargetTransferTag = 0xffffffff; 1013 pdu->p.snack.BegRun = htonl(BegRun); 1014 pdu->p.snack.RunLength = htonl(RunLength); 1015 1016 ppdu->flags = PDUF_PRIORITY; 1017 1018 setup_tx_uio(ppdu, 0, NULL, FALSE); 1019 send_pdu(NULL, ppdu, CCBDISP_NOWAIT, PDUDISP_FREE); 1020} 1021 1022 1023/* 1024 * send_snack: 1025 * Send SNACK request. 1026 * 1027 * Parameter: 1028 * conn The connection 1029 * rx_pdu The received data in PDU 1030 * tx_ccb The original command CCB (required for Data ACK only) 1031 * type The SNACK type 1032 * 1033 * Returns: 0 on success, else an error code. 1034 */ 1035 1036void 1037send_snack(connection_t *conn, pdu_t *rx_pdu, ccb_t *tx_ccb, uint8_t type) 1038{ 1039 pdu_t *ppdu; 1040 pdu_header_t *pdu; 1041 1042 PDEBC(conn, 1, ("Send SNACK type = %d\n", type)); 1043 1044 ppdu = get_pdu(conn); 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); 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); 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); 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 assert(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_c(conn, waitok); 1294 if (tx_pdu == NULL) { 1295 DEBOUT(("No PDU in send_data_out\n")); 1296 1297 tx_ccb->status = ISCSI_STATUS_NO_RESOURCES; 1298 handle_connection_error(conn, ISCSI_STATUS_NO_RESOURCES, NO_LOGOUT); 1299 1300 return ISCSI_STATUS_NO_RESOURCES; 1301 } 1302 1303 totlen -= len; 1304 pdu = &tx_pdu->pdu; 1305 pdu->Opcode = IOP_SCSI_Data_out; 1306 if (!totlen) 1307 pdu->Flags = FLAG_FINAL; 1308 1309 if (rx_pdu != NULL) 1310 pdu->p.data_out.TargetTransferTag = 1311 rx_pdu->pdu.p.r2t.TargetTransferTag; 1312 else 1313 pdu->p.data_out.TargetTransferTag = 0xffffffff; 1314 pdu->p.data_out.BufferOffset = htonl(offs); 1315 pdu->p.data_out.DataSN = htonl(sn); 1316 1317 PERF_PDUSET(tx_pdu, tx_ccb, PERF_BEGIN_PDUWRITEDATA); 1318 1319 DEBC(conn, 10, ("Send DataOut: DataSN %d, len %d offs %x totlen %d\n", 1320 sn, len, offs, totlen)); 1321 1322 setup_tx_uio(tx_pdu, len, tx_ccb->data_ptr + offs, FALSE); 1323 1324 send_pdu(tx_ccb, tx_pdu, (totlen) ? CCBDISP_NOWAIT : disp, PDUDISP_FREE); 1325 1326 sn++; 1327 offs += len; 1328 } 1329 return 0; 1330} 1331 1332 1333/* 1334 * send_command: 1335 * Send a SCSI command request. 1336 * 1337 * Parameter: 1338 * CCB The CCB 1339 * disp The CCB disposition 1340 */ 1341 1342void 1343send_command(ccb_t *ccb, ccb_disp_t disp, bool waitok, bool immed) 1344{ 1345 uint32_t totlen, len; 1346 connection_t *conn = ccb->connection; 1347 session_t *sess = ccb->session; 1348 pdu_t *ppdu; 1349 pdu_header_t *pdu; 1350 int s; 1351 1352 PERF_BEGIN(ccb, !waitok); 1353 1354 if (!waitok) { 1355 s = splbio(); 1356 if (/*CONSTCOND*/ISCSI_TROTTLING_ENABLED && 1357 /*CONSTCOND*/ISCSI_SERVER_TRUSTED && 1358 !sn_a_le_b(sess->CmdSN, sess->MaxCmdSN)) { 1359 ccb->disp = disp; 1360 TAILQ_INSERT_TAIL(&sess->ccbs_throttled, ccb, chain); 1361 splx(s); 1362 PDEBOUT(("Throttling S - CmdSN = %d, MaxCmdSN = %d\n", 1363 sess->CmdSN, sess->MaxCmdSN)); 1364 return; 1365 } 1366 splx(s); 1367 ppdu = get_pdu_c(conn, FALSE); 1368 if (ppdu == NULL) { 1369 ccb->status = ISCSI_STATUS_NO_RESOURCES; 1370 iscsi_done(ccb); 1371 return; 1372 } 1373 } else { 1374 s = splbio(); 1375 while (/*CONSTCOND*/ISCSI_TROTTLING_ENABLED && 1376 /*CONSTCOND*/ISCSI_SERVER_TRUSTED && 1377 !sn_a_le_b(sess->CmdSN, sess->MaxCmdSN)) { 1378 ccb->disp = disp; 1379 ccb->flags |= CCBF_WAITING; 1380 TAILQ_INSERT_TAIL(&sess->ccbs_throttled, ccb, chain); 1381 PDEBOUT(("Throttling W - CmdSN = %d, MaxCmdSN = %d\n", 1382 sess->CmdSN, sess->MaxCmdSN)); 1383 tsleep(ccb, PWAIT, "waitMaxCmd", 0); 1384 splbio(); 1385 } 1386 splx(s); 1387 ppdu = get_pdu(conn); 1388 } 1389 1390 pdu = &ppdu->pdu; 1391 pdu->LUN = htonq(ccb->lun); 1392 memcpy(pdu->p.command.SCSI_CDB, ccb->cmd, ccb->cmdlen); 1393 totlen = len = ccb->data_len; 1394 pdu->Opcode = IOP_SCSI_Command; 1395 if (immed) 1396 pdu->Opcode |= OP_IMMEDIATE; 1397 pdu->p.command.ExpectedDataTransferLength = htonl(totlen); 1398 1399 1400 if (totlen) { 1401 if (ccb->data_in) { 1402 pdu->Flags = FLAG_READ; 1403 totlen = 0; 1404 } else { 1405 pdu->Flags = FLAG_WRITE; 1406 /* immediate data we can send */ 1407 len = min(totlen, conn->max_firstimmed); 1408 1409 /* can we send more unsolicited data ? */ 1410 totlen = conn->max_firstdata ? totlen - len : 0; 1411 } 1412 } 1413 1414 if (!totlen) 1415 pdu->Flags |= FLAG_FINAL; 1416 1417 if (ccb->data_in) 1418 init_sernum(&ccb->DataSN_buf); 1419 1420 ccb->sense_len_got = 0; 1421 ccb->xfer_len = 0; 1422 ccb->residual = 0; 1423 ccb->flags |= CCBF_REASSIGN; 1424 1425 s = splbio(); 1426 ccb->CmdSN = sess->CmdSN; 1427 if (!immed) 1428 sess->CmdSN++; 1429 splx(s); 1430 1431 pdu->p.command.CmdSN = htonl(ccb->CmdSN); 1432 1433 DEBC(conn, 10, ("Send Command: CmdSN %d, data_in %d, len %d, totlen %d\n", 1434 ccb->CmdSN, ccb->data_in, len, totlen)); 1435 1436 PERF_PDUSET(ppdu, ccb, PERF_BEGIN_PDUWRITECMD); 1437 1438 setup_tx_uio(ppdu, len, ccb->data_ptr, ccb->data_in); 1439 1440 send_pdu(ccb, ppdu, (totlen) ? CCBDISP_DEFER : disp, PDUDISP_WAIT); 1441 1442 if (totlen) 1443 send_data_out(conn, NULL, ccb, disp, waitok); 1444} 1445 1446 1447/* 1448 * send_run_xfer: 1449 * Handle a SCSI command transfer request from scsipi. 1450 * 1451 * Parameter: 1452 * session The session 1453 * xs The transfer parameters 1454 */ 1455 1456void 1457send_run_xfer(session_t *session, struct scsipi_xfer *xs) 1458{ 1459 ccb_t *ccb; 1460 connection_t *conn; 1461 bool waitok; 1462 1463 waitok = !(xs->xs_control & XS_CTL_NOSLEEP); 1464 1465 DEB(10, ("RunXfer: flags=%x, data=%p, datalen=%d, resid=%d, cmdlen=%d, " 1466 "waitok=%d\n", xs->xs_control, xs->data, xs->datalen, 1467 xs->resid, xs->cmdlen, waitok)); 1468 1469 conn = assign_connection(session, waitok); 1470 1471 if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) { 1472 xs->error = XS_SELTIMEOUT; 1473 DEBC(conn, 10, ("run_xfer on dead connection\n")); 1474 scsipi_done(xs); 1475 return; 1476 } 1477 1478 if (xs->xs_control & XS_CTL_RESET) { 1479 if (send_task_management(conn, NULL, xs, TARGET_WARM_RESET)) { 1480 xs->error = XS_SELTIMEOUT; 1481 scsipi_done(xs); 1482 } 1483 return; 1484 } 1485 1486 ccb = get_ccb(conn, waitok); 1487 if (ccb == NULL) { 1488 xs->error = XS_RESOURCE_SHORTAGE; 1489 DEBC(conn, 0, ("No CCB in run_xfer\n")); 1490 scsipi_done(xs); 1491 return; 1492 } 1493 /* copy parameters into CCB for easier access */ 1494 ccb->xs = xs; 1495 1496 ccb->data_in = (xs->xs_control & XS_CTL_DATA_IN) != 0; 1497 ccb->data_len = (uint32_t) xs->datalen; 1498 ccb->data_ptr = xs->data; 1499 1500 ccb->sense_len_req = sizeof(xs->sense.scsi_sense); 1501 ccb->sense_ptr = &xs->sense; 1502 1503 ccb->lun = (uint64_t) xs->xs_periph->periph_lun << 48; 1504 ccb->cmd = (uint8_t *) xs->cmd; 1505 ccb->cmdlen = xs->cmdlen; 1506 DEB(10, ("RunXfer: Periph_lun = %d, cmd[1] = %x, cmdlen = %d\n", 1507 xs->xs_periph->periph_lun, ccb->cmd[1], xs->cmdlen)); 1508 1509#ifdef LUN_1 1510 ccb->lun += 0x1000000000000LL; 1511 ccb->cmd[1] += 0x10; 1512#endif 1513 ccb->disp = CCBDISP_SCSIPI; 1514 send_command(ccb, CCBDISP_SCSIPI, waitok, FALSE); 1515} 1516 1517 1518#ifndef ISCSI_MINIMAL 1519/* 1520 * send_io_command: 1521 * Handle a SCSI io command request from user space. 1522 * 1523 * Parameter: 1524 * session The session 1525 * lun The LUN to use 1526 * req The SCSI request block 1527 * immed Immediate command if TRUE 1528 * conn_id Assign to this connection ID if nonzero 1529 */ 1530 1531int 1532send_io_command(session_t *session, uint64_t lun, scsireq_t *req, 1533 bool immed, uint32_t conn_id) 1534{ 1535 ccb_t *ccb; 1536 connection_t *conn; 1537 int rc; 1538 1539 DEB(9, ("IoCommand: lun=%x, datalen=%d, cmdlen=%d, immed=%d, cid=%d\n", 1540 (int) lun, (int) req->datalen, (int) req->cmdlen, immed, conn_id)); 1541 1542 conn = (conn_id) ? find_connection(session, conn_id) 1543 : assign_connection(session, TRUE); 1544 1545 if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) { 1546 DEBOUT(("io_command on dead connection (state = %d)\n", 1547 (conn != NULL) ? conn->state : -1)); 1548 return ISCSI_STATUS_INVALID_CONNECTION_ID; 1549 } 1550 1551 ccb = get_ccb(conn, TRUE); 1552 if (ccb == NULL) { 1553 DEBOUT(("No CCB in io_command\n")); 1554 return ISCSI_STATUS_NO_RESOURCES; 1555 } 1556 1557 ccb->data_in = (req->flags & SCCMD_READ) != 0; 1558 ccb->data_len = (uint32_t) req->datalen; 1559 ccb->data_ptr = req->databuf; 1560 1561 ccb->sense_len_req = req->senselen; 1562 ccb->sense_ptr = &req->sense; 1563 1564 ccb->lun = lun; 1565 ccb->cmd = (uint8_t *) req->cmd; 1566 ccb->cmdlen = req->cmdlen; 1567 DEBC(conn, 10, ("IoCommand: cmd[1] = %x, cmdlen = %d\n", 1568 ccb->cmd[1], ccb->cmdlen)); 1569 1570 send_command(ccb, CCBDISP_WAIT, TRUE, immed); 1571 1572 rc = ccb->status; 1573 1574 req->senselen_used = ccb->sense_len_got; 1575 req->datalen_used = req->datalen - ccb->residual; 1576 1577 free_ccb(ccb); 1578 1579 return rc; 1580} 1581#endif 1582 1583 1584/***************************************************************************** 1585 * Timeout handlers 1586 *****************************************************************************/ 1587/* 1588 * connection_timeout: 1589 * Handle prolonged silence on a connection by checking whether 1590 * it's still alive. 1591 * This has the side effect of discovering missing status or lost commands 1592 * before those time out. 1593 * 1594 * Parameter: 1595 * par The connection 1596 */ 1597 1598void 1599connection_timeout(void *par) 1600{ 1601 connection_t *conn = (connection_t *) par; 1602 1603 PDEBC(conn, 1, ("Connection Timeout, num_timeouts=%d\n", 1604 conn->num_timeouts)); 1605 1606 if (++conn->num_timeouts > MAX_CONN_TIMEOUTS) 1607 handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, NO_LOGOUT); 1608 else { 1609 if (conn->state == ST_FULL_FEATURE) 1610 send_nop_out(conn, NULL); 1611 1612 SET_CONN_TIMEOUT(conn, CONNECTION_TIMEOUT); 1613 } 1614} 1615 1616/* 1617 * ccb_timeout: 1618 * Handle timeout of a sent command. 1619 * 1620 * Parameter: 1621 * par The CCB 1622 */ 1623 1624void 1625ccb_timeout(void *par) 1626{ 1627 ccb_t *ccb = (ccb_t *) par; 1628 connection_t *conn = ccb->connection; 1629 PDEBC(conn, 1, ("CCB Timeout, ccb=%x, num_timeouts=%d\n", 1630 (int) ccb, ccb->num_timeouts)); 1631 1632 ccb->total_tries++; 1633 1634 if (++ccb->num_timeouts > MAX_CCB_TIMEOUTS || 1635 ccb->total_tries > MAX_CCB_TRIES || 1636 ccb->disp <= CCBDISP_FREE || 1637 !ccb->session->ErrorRecoveryLevel) { 1638 ccb->status = ISCSI_STATUS_TIMEOUT; 1639 complete_ccb(ccb); 1640 1641 handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, RECOVER_CONNECTION); 1642 } else { 1643 if (ccb->data_in && ccb->xfer_len < ccb->data_len) { 1644 /* request resend of all missing data */ 1645 snack_missing(conn, ccb, SNACK_DATA_NAK, 0, 0); 1646 } else { 1647 /* request resend of all missing status */ 1648 snack_missing(conn, NULL, SNACK_STATUS_NAK, 0, 0); 1649 } 1650 SET_CCB_TIMEOUT(conn, ccb, COMMAND_TIMEOUT); 1651 } 1652} 1653