1 /* $NetBSD: iscsi_send.c,v 1.14 2015/05/30 18:09:31 joerg 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 53 STATIC int 54 my_soo_write(connection_t *conn, struct uio *u) 55 { 56 struct socket *so = conn->sock->f_socket; 57 size_t resid = u->uio_resid; 58 int ret; 59 60 assert(resid != 0); 61 62 ret = sosend(so, NULL, u, NULL, NULL, 0, conn->threadobj); 63 64 DEB(99, ("soo_write done: len = %zu\n", u->uio_resid)); 65 66 if (ret != 0 || u->uio_resid) { 67 DEBC(conn, 0, ("Write failed sock %p (ret: %d, req: %zu, resid: %zu)\n", 68 conn->sock, ret, resid, u->uio_resid)); 69 handle_connection_error(conn, ISCSI_STATUS_SOCKET_ERROR, NO_LOGOUT); 70 return EIO; 71 } 72 return 0; 73 } 74 75 /*****************************************************************************/ 76 77 /* 78 * assign_connection: 79 * This function returns the connection to use for the next transaction. 80 * 81 * Parameter: The session 82 * 83 * Returns: The connection 84 */ 85 86 connection_t * 87 assign_connection(session_t *session, bool waitok) 88 { 89 connection_t *conn, *next; 90 91 do { 92 if ((conn = session->mru_connection) == NULL) { 93 return NULL; 94 } 95 next = conn; 96 do { 97 next = TAILQ_NEXT(next, connections); 98 if (next == NULL) { 99 next = TAILQ_FIRST(&session->conn_list); 100 } 101 } while (next != NULL && next != conn && 102 next->state != ST_FULL_FEATURE); 103 104 if (next->state != ST_FULL_FEATURE) { 105 if (waitok) { 106 tsleep(session, PRIBIO, "iscsi_assign_connection", 0); 107 next = TAILQ_FIRST(&session->conn_list); 108 } else { 109 return NULL; 110 } 111 } else { 112 session->mru_connection = next; 113 } 114 } while (next != NULL && next->state != ST_FULL_FEATURE); 115 116 return next; 117 } 118 119 120 /* 121 * reassign_tasks: 122 * Reassign pending commands to one of the still existing connections 123 * of a session. 124 * 125 * Parameter: 126 * oldconn The terminating connection 127 */ 128 129 STATIC void 130 reassign_tasks(connection_t *oldconn) 131 { 132 session_t *sess = oldconn->session; 133 connection_t *conn; 134 ccb_t *ccb; 135 pdu_t *pdu = NULL; 136 pdu_t *opdu; 137 int no_tm = 1; 138 int rc = 1; 139 int s; 140 141 if ((conn = assign_connection(sess, FALSE)) == NULL) { 142 DEB(1, ("Reassign_tasks of Session %d, connection %d failed, " 143 "no active connection\n", 144 sess->id, oldconn->id)); 145 /* XXX here we need to abort the waiting CCBs */ 146 return; 147 } 148 149 if (sess->ErrorRecoveryLevel >= 2) { 150 if (oldconn->loggedout == NOT_LOGGED_OUT) { 151 oldconn->loggedout = LOGOUT_SENT; 152 no_tm = send_logout(conn, oldconn, RECOVER_CONNECTION, TRUE); 153 oldconn->loggedout = (rc) ? LOGOUT_FAILED : LOGOUT_SUCCESS; 154 if (!oldconn->Time2Retain) { 155 DEBC(conn, 1, ("Time2Retain is zero, setting no_tm\n")); 156 no_tm = 1; 157 } 158 } else if (oldconn->loggedout == LOGOUT_SUCCESS) { 159 no_tm = 0; 160 } 161 if (!no_tm && oldconn->Time2Wait) { 162 DEBC(conn, 1, ("Time2Wait=%d, hz=%d, waiting...\n", 163 oldconn->Time2Wait, hz)); 164 tsleep(&no_tm, PRIBIO, "Time2Wait", oldconn->Time2Wait * hz); 165 } 166 } 167 168 DEBC(conn, 1, ("Reassign_tasks: Session %d, conn %d -> conn %d, no_tm=%d\n", 169 sess->id, oldconn->id, conn->id, no_tm)); 170 171 172 /* XXX reassign waiting CCBs to new connection */ 173 174 while ((ccb = TAILQ_FIRST(&oldconn->ccbs_waiting)) != NULL) { 175 /* Copy PDU contents (PDUs are bound to connection) */ 176 if ((pdu = get_pdu(conn, TRUE)) == NULL) { 177 break; 178 } 179 180 /* adjust CCB and clone PDU for new connection */ 181 TAILQ_REMOVE(&oldconn->ccbs_waiting, ccb, chain); 182 183 opdu = ccb->pdu_waiting; 184 *pdu = *opdu; 185 186 /* restore overwritten back ptr */ 187 pdu->connection = conn; 188 189 /* fixup saved UIO and IOVEC (regular one will be overwritten anyway) */ 190 pdu->save_uio.uio_iov = pdu->io_vec; 191 pdu->save_iovec [0].iov_base = &pdu->pdu; 192 193 if (conn->DataDigest && pdu->save_uio.uio_iovcnt > 1) { 194 if (pdu->save_iovec [2].iov_base == NULL) { 195 pdu->save_iovec [2].iov_base = &pdu->data_digest; 196 pdu->save_uio.uio_iovcnt = 3; 197 } else { 198 pdu->save_iovec [3].iov_base = &pdu->data_digest; 199 pdu->save_uio.uio_iovcnt = 4; 200 } 201 } 202 pdu->save_iovec [0].iov_len = 203 (conn->HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE; 204 205 206 /* link new PDU into old CCB */ 207 ccb->pdu_waiting = pdu; 208 /* link new CCB into new connection */ 209 ccb->connection = conn; 210 /* reset timeouts */ 211 ccb->num_timeouts = 0; 212 213 /* fixup reference counts */ 214 oldconn->usecount--; 215 conn->usecount++; 216 217 DEBC(conn, 1, ("CCB %p: Copied PDU %p to %p\n", 218 ccb, opdu, pdu)); 219 220 /* kill temp pointer that is now referenced by the new PDU */ 221 opdu->temp_data = NULL; 222 223 /* and free the old PDU */ 224 free_pdu(opdu); 225 226 /* put ready CCB into waiting list of new connection */ 227 s = splbio(); 228 suspend_ccb(ccb, TRUE); 229 splx(s); 230 } 231 232 if (pdu == NULL) { 233 DEBC(conn, 1, ("Error while copying PDUs in reassign_tasks!\n")); 234 /* give up recovering, the other connection is screwed up as well... */ 235 while ((ccb = TAILQ_FIRST(&oldconn->ccbs_waiting)) != NULL) { 236 wake_ccb(ccb, oldconn->terminating); 237 } 238 /* XXX some CCBs might have been moved to new connection, but how is the 239 * new connection handled or killed ? */ 240 return; 241 } 242 243 TAILQ_FOREACH(ccb, &conn->ccbs_waiting, chain) { 244 if (!no_tm) { 245 rc = send_task_management(conn, ccb, NULL, TASK_REASSIGN); 246 } 247 /* if we get an error on reassign, restart the original request */ 248 if (no_tm || rc) { 249 if (ccb->CmdSN < sess->ExpCmdSN) { 250 pdu = ccb->pdu_waiting; 251 252 /* update CmdSN */ 253 DEBC(conn, 1, ("Resend Updating CmdSN - old %d, new %d\n", 254 ccb->CmdSN, sess->CmdSN)); 255 ccb->CmdSN = sess->CmdSN; 256 if (!(pdu->pdu.Opcode & OP_IMMEDIATE)) { 257 sess->CmdSN++; 258 } 259 pdu->pdu.p.command.CmdSN = htonl(ccb->CmdSN); 260 } 261 resend_pdu(ccb); 262 } else { 263 callout_schedule(&ccb->timeout, COMMAND_TIMEOUT); 264 } 265 DEBC(conn, 1, ("Reassign ccb %p, no_tm=%d, rc=%d\n", 266 ccb, no_tm, rc)); 267 } 268 } 269 270 271 /* 272 * iscsi_send_thread: 273 * This thread services the send queue, writing the PDUs to the socket. 274 * It also handles the cleanup when the connection is terminated. 275 * 276 * Parameter: 277 * par The connection this thread services 278 */ 279 280 void 281 iscsi_send_thread(void *par) 282 { 283 connection_t *conn = (connection_t *) par; 284 session_t *sess; 285 ccb_t *ccb, *nccb; 286 pdu_t *pdu; 287 struct file *fp; 288 int s; 289 290 sess = conn->session; 291 /* so cleanup thread knows there's someone left */ 292 iscsi_num_send_threads++; 293 294 do { 295 while (!conn->terminating) { 296 s = splbio(); 297 while (!conn->terminating && 298 (pdu = TAILQ_FIRST(&conn->pdus_to_send)) != NULL) { 299 TAILQ_REMOVE(&conn->pdus_to_send, pdu, send_chain); 300 pdu->flags &= ~PDUF_INQUEUE; 301 splx(s); 302 303 #ifdef ISCSI_DEBUG 304 if (!pdu->uio.uio_resid) { 305 DEBOUT(("uio.resid = 0 in iscsi_send_thread! pdu=%p\n", 306 pdu)); 307 assert(pdu->uio.uio_resid != 0); 308 } 309 #endif 310 /*DEB (99,("Send thread woke up, pdu = %x)\n", (int)pdu)); */ 311 312 /* update ExpStatSN here to avoid discontinuities */ 313 /* and delays in updating target */ 314 pdu->pdu.p.command.ExpStatSN = htonl(conn->StatSN_buf.ExpSN); 315 316 if (conn->HeaderDigest) 317 pdu->pdu.HeaderDigest = gen_digest(&pdu->pdu, BHS_SIZE); 318 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 } 325 s = splbio(); 326 } 327 328 /*DEB (99,("Send thread done, waiting (conn->terminating = %d)\n", */ 329 /* conn->terminating)); */ 330 331 if (!conn->terminating) { 332 tsleep(&conn->pdus_to_send, PRIBIO, 333 "iscsisend", 0); 334 } 335 336 splx(s); 337 } 338 339 /* ------------------------------------------------------------------------ 340 * Here this thread takes over cleanup of the terminating connection. 341 * ------------------------------------------------------------------------ 342 */ 343 callout_stop(&conn->timeout); 344 conn->idle_timeout_val = CONNECTION_IDLE_TIMEOUT; 345 346 fp = conn->sock; 347 348 /* 349 * We shutdown the socket here to force the receive 350 * thread to wake up 351 */ 352 DEBC(conn, 1, ("Closing Socket %p\n", conn->sock)); 353 solock(fp->f_socket); 354 soshutdown(fp->f_socket, SHUT_RDWR); 355 sounlock(fp->f_socket); 356 357 /* wake up any non-reassignable waiting CCBs */ 358 TAILQ_FOREACH_SAFE(ccb, &conn->ccbs_waiting, chain, nccb) { 359 if (!(ccb->flags & CCBF_REASSIGN) || ccb->pdu_waiting == NULL) { 360 DEBC(conn, 1, ("Terminating CCB %p (t=%p)\n", 361 ccb,&ccb->timeout)); 362 wake_ccb(ccb, conn->terminating); 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 DEBC(conn, 1, ("Reassign Tasks\n")); 384 reassign_tasks(conn); 385 } else if (!conn->destroy && conn->Time2Wait) { 386 DEBC(conn, 1, ("Time2Wait\n")); 387 tsleep(&s, PRIBIO, "Time2Wait", conn->Time2Wait * hz); 388 DEBC(conn, 1, ("Time2Wait\n")); 389 } 390 /* notify event handlers of connection shutdown */ 391 DEBC(conn, 1, ("%s\n", (conn->destroy) ? "TERMINATED" : "RECOVER")); 392 add_event((conn->destroy) ? ISCSI_CONNECTION_TERMINATED 393 : ISCSI_RECOVER_CONNECTION, 394 sess->id, conn->id, conn->terminating); 395 396 DEBC(conn, 1, ("Waiting for conn_idle\n")); 397 if (!conn->destroy) 398 tsleep(conn, PRIBIO, "conn_idle", 30 * hz); 399 DEBC(conn, 1, ("Waited for conn_idle, destroy = %d\n", conn->destroy)); 400 401 } while (!conn->destroy); 402 403 /* wake up anyone waiting for a PDU */ 404 wakeup(&conn->pdu_pool); 405 406 /* wake up any waiting CCBs */ 407 while ((ccb = TAILQ_FIRST(&conn->ccbs_waiting)) != NULL) { 408 wake_ccb(ccb, conn->terminating); 409 /* NOTE: wake_ccb will remove the CCB from the queue */ 410 } 411 412 s = splbio(); 413 if (conn->in_session) { 414 conn->in_session = FALSE; 415 TAILQ_REMOVE(&sess->conn_list, conn, connections); 416 sess->mru_connection = TAILQ_FIRST(&sess->conn_list); 417 } 418 419 TAILQ_INSERT_TAIL(&iscsi_cleanupc_list, conn, connections); 420 splx(s); 421 422 wakeup(&iscsi_cleanupc_list); 423 424 conn->sendproc = NULL; 425 DEBC(conn, 1, ("Send thread exits\n")); 426 iscsi_num_send_threads--; 427 kthread_exit(0); 428 } 429 430 431 /* 432 * send_pdu: 433 * Enqueue a PDU to be sent, and handle its disposition as well as 434 * the disposition of its associated CCB. 435 * 436 * Parameter: 437 * ccb The associated CCB. May be NULL if cdisp is CCBDISP_NOWAIT 438 * and pdisp is not PDUDISP_WAIT 439 * cdisp The CCB's disposition 440 * pdu The PDU 441 * pdisp The PDU's disposition 442 */ 443 444 STATIC void 445 send_pdu(ccb_t *ccb, pdu_t *pdu, ccb_disp_t cdisp, pdu_disp_t pdisp) 446 { 447 connection_t *conn = pdu->connection; 448 ccb_disp_t prev_cdisp = 0; 449 int s; 450 451 if (ccb != NULL) { 452 prev_cdisp = ccb->disp; 453 pdu->pdu.InitiatorTaskTag = ccb->ITT; 454 pdu->owner = ccb; 455 if (cdisp != CCBDISP_NOWAIT) 456 ccb->disp = cdisp; 457 } 458 459 pdu->disp = pdisp; 460 461 DEBC(conn, 10, ("Send_pdu: ccb=%p, pcd=%d, cdsp=%d, pdu=%p, pdsp=%d\n", 462 ccb, prev_cdisp, cdisp, pdu, pdisp)); 463 464 s = splbio(); 465 if (pdisp == PDUDISP_WAIT) { 466 ccb->pdu_waiting = pdu; 467 468 /* save UIO and IOVEC for retransmit */ 469 pdu->save_uio = pdu->uio; 470 memcpy(pdu->save_iovec, pdu->io_vec, sizeof(pdu->save_iovec)); 471 472 pdu->flags |= PDUF_BUSY; 473 } 474 /* Enqueue for sending */ 475 pdu->flags |= PDUF_INQUEUE; 476 477 if (pdu->flags & PDUF_PRIORITY) 478 TAILQ_INSERT_HEAD(&conn->pdus_to_send, pdu, send_chain); 479 else 480 TAILQ_INSERT_TAIL(&conn->pdus_to_send, pdu, send_chain); 481 482 wakeup(&conn->pdus_to_send); 483 484 if (cdisp != CCBDISP_NOWAIT) { 485 callout_schedule(&ccb->timeout, COMMAND_TIMEOUT); 486 487 if (prev_cdisp <= CCBDISP_NOWAIT) 488 suspend_ccb(ccb, TRUE); 489 490 if (cdisp == CCBDISP_WAIT) 491 tsleep(ccb, PWAIT, "sendpdu", 0); 492 } 493 splx(s); 494 } 495 496 497 /* 498 * resend_pdu: 499 * Re-Enqueue a PDU that has apparently gotten lost. 500 * 501 * Parameter: 502 * ccb The associated CCB. 503 */ 504 505 void 506 resend_pdu(ccb_t *ccb) 507 { 508 connection_t *conn = ccb->connection; 509 pdu_t *pdu = ccb->pdu_waiting; 510 int s; 511 512 s = splbio (); 513 if (pdu == NULL || (pdu->flags & PDUF_BUSY)) { 514 splx (s); 515 return; 516 } 517 pdu->flags |= PDUF_BUSY; 518 splx (s); 519 520 /* restore UIO and IOVEC */ 521 pdu->uio = pdu->save_uio; 522 memcpy(pdu->io_vec, pdu->save_iovec, sizeof(pdu->io_vec)); 523 524 DEBC(conn, 8, ("ReSend_pdu ccb=%p, pdu=%p\n", ccb, pdu)); 525 526 s = splbio (); 527 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 callout_schedule(&ccb->timeout, COMMAND_TIMEOUT); 537 splx (s); 538 539 wakeup(&conn->pdus_to_send); 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 556 STATIC void 557 setup_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 618 STATIC void 619 init_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 651 void 652 negotiate_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 728 STATIC void 729 init_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 757 void 758 acknowledge_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 785 void 786 start_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 822 void 823 negotiate_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 876 int 877 send_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 936 int 937 send_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 999 void 1000 snack_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 1038 void 1039 send_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 1099 int 1100 send_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 1144 int 1145 send_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 1206 int 1207 send_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 1271 int 1272 send_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(conn, waitok); 1294 if (tx_pdu == NULL) { 1295 DEBOUT(("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 1341 void 1342 send_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 s = splbio(); 1352 while (/*CONSTCOND*/ISCSI_THROTTLING_ENABLED && 1353 /*CONSTCOND*/!ISCSI_SERVER_TRUSTED && 1354 !sn_a_le_b(sess->CmdSN, sess->MaxCmdSN)) { 1355 1356 ccb->disp = disp; 1357 if (waitok) 1358 ccb->flags |= CCBF_WAITING; 1359 throttle_ccb(ccb, TRUE); 1360 1361 if (!waitok) { 1362 splx(s); 1363 return; 1364 } 1365 1366 tsleep(ccb, PWAIT, "waitMaxCmd", 0); 1367 1368 throttle_ccb(ccb, FALSE); 1369 ccb->flags &= ~CCBF_WAITING; 1370 } 1371 splx(s); 1372 ppdu = get_pdu(conn, FALSE); 1373 if (ppdu == NULL) { 1374 wake_ccb(ccb, ISCSI_STATUS_NO_RESOURCES); 1375 return; 1376 } 1377 1378 totlen = len = ccb->data_len; 1379 1380 pdu = &ppdu->pdu; 1381 pdu->LUN = htonq(ccb->lun); 1382 memcpy(pdu->p.command.SCSI_CDB, ccb->cmd, ccb->cmdlen); 1383 pdu->Opcode = IOP_SCSI_Command; 1384 if (immed) 1385 pdu->Opcode |= OP_IMMEDIATE; 1386 pdu->p.command.ExpectedDataTransferLength = htonl(totlen); 1387 1388 if (totlen) { 1389 if (ccb->data_in) { 1390 pdu->Flags = FLAG_READ; 1391 totlen = 0; 1392 } else { 1393 pdu->Flags = FLAG_WRITE; 1394 /* immediate data we can send */ 1395 len = min(totlen, conn->max_firstimmed); 1396 1397 /* can we send more unsolicited data ? */ 1398 totlen = conn->max_firstdata ? totlen - len : 0; 1399 } 1400 } 1401 1402 if (!totlen) 1403 pdu->Flags |= FLAG_FINAL; 1404 1405 if (ccb->data_in) 1406 init_sernum(&ccb->DataSN_buf); 1407 1408 ccb->sense_len_got = 0; 1409 ccb->xfer_len = 0; 1410 ccb->residual = 0; 1411 ccb->flags |= CCBF_REASSIGN; 1412 1413 s = splbio(); 1414 ccb->CmdSN = sess->CmdSN; 1415 if (!immed) 1416 sess->CmdSN++; 1417 splx(s); 1418 1419 pdu->p.command.CmdSN = htonl(ccb->CmdSN); 1420 1421 DEBC(conn, 10, ("Send Command: CmdSN %d, data_in %d, len %d, totlen %d\n", 1422 ccb->CmdSN, ccb->data_in, len, totlen)); 1423 1424 setup_tx_uio(ppdu, len, ccb->data_ptr, ccb->data_in); 1425 send_pdu(ccb, ppdu, (totlen) ? CCBDISP_DEFER : disp, PDUDISP_WAIT); 1426 1427 if (totlen) 1428 send_data_out(conn, NULL, ccb, disp, waitok); 1429 } 1430 1431 1432 /* 1433 * send_run_xfer: 1434 * Handle a SCSI command transfer request from scsipi. 1435 * 1436 * Parameter: 1437 * session The session 1438 * xs The transfer parameters 1439 */ 1440 1441 void 1442 send_run_xfer(session_t *session, struct scsipi_xfer *xs) 1443 { 1444 ccb_t *ccb; 1445 connection_t *conn; 1446 bool waitok; 1447 1448 waitok = !(xs->xs_control & XS_CTL_NOSLEEP); 1449 1450 DEB(10, ("RunXfer: flags=%x, data=%p, datalen=%d, resid=%d, cmdlen=%d, " 1451 "waitok=%d\n", xs->xs_control, xs->data, xs->datalen, 1452 xs->resid, xs->cmdlen, waitok)); 1453 1454 conn = assign_connection(session, waitok); 1455 1456 if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) { 1457 xs->error = XS_SELTIMEOUT; 1458 DEBC(conn, 10, ("run_xfer on dead connection\n")); 1459 scsipi_done(xs); 1460 return; 1461 } 1462 1463 if (xs->xs_control & XS_CTL_RESET) { 1464 if (send_task_management(conn, NULL, xs, TARGET_WARM_RESET)) { 1465 xs->error = XS_SELTIMEOUT; 1466 scsipi_done(xs); 1467 } 1468 return; 1469 } 1470 1471 ccb = get_ccb(conn, waitok); 1472 if (ccb == NULL) { 1473 xs->error = XS_BUSY; 1474 xs->status = SCSI_QUEUE_FULL; 1475 DEBC(conn, 0, ("No CCB in run_xfer\n")); 1476 scsipi_done(xs); 1477 return; 1478 } 1479 /* copy parameters into CCB for easier access */ 1480 ccb->xs = xs; 1481 1482 ccb->data_in = (xs->xs_control & XS_CTL_DATA_IN) != 0; 1483 ccb->data_len = (uint32_t) xs->datalen; 1484 ccb->data_ptr = xs->data; 1485 1486 ccb->sense_len_req = sizeof(xs->sense.scsi_sense); 1487 ccb->sense_ptr = &xs->sense; 1488 1489 ccb->lun = ((uint64_t) (uint8_t) xs->xs_periph->periph_lun) << 48; 1490 ccb->cmd = (uint8_t *) xs->cmd; 1491 ccb->cmdlen = xs->cmdlen; 1492 DEB(10, ("RunXfer: Periph_lun = %d, cmd[1] = %x, cmdlen = %d\n", 1493 xs->xs_periph->periph_lun, ccb->cmd[1], xs->cmdlen)); 1494 1495 #ifdef LUN_1 1496 ccb->lun += 0x1000000000000LL; 1497 ccb->cmd[1] += 0x10; 1498 #endif 1499 send_command(ccb, CCBDISP_SCSIPI, waitok, FALSE); 1500 } 1501 1502 1503 #ifndef ISCSI_MINIMAL 1504 /* 1505 * send_io_command: 1506 * Handle a SCSI io command request from user space. 1507 * 1508 * Parameter: 1509 * session The session 1510 * lun The LUN to use 1511 * req The SCSI request block 1512 * immed Immediate command if TRUE 1513 * conn_id Assign to this connection ID if nonzero 1514 */ 1515 1516 int 1517 send_io_command(session_t *session, uint64_t lun, scsireq_t *req, 1518 bool immed, uint32_t conn_id) 1519 { 1520 ccb_t *ccb; 1521 connection_t *conn; 1522 int rc; 1523 1524 DEB(9, ("IoCommand: lun=%x, datalen=%d, cmdlen=%d, immed=%d, cid=%d\n", 1525 (int) lun, (int) req->datalen, (int) req->cmdlen, immed, conn_id)); 1526 1527 conn = (conn_id) ? find_connection(session, conn_id) 1528 : assign_connection(session, TRUE); 1529 1530 if (conn == NULL || conn->terminating || conn->state != ST_FULL_FEATURE) { 1531 DEBOUT(("io_command on dead connection (state = %d)\n", 1532 (conn != NULL) ? conn->state : -1)); 1533 return ISCSI_STATUS_INVALID_CONNECTION_ID; 1534 } 1535 1536 ccb = get_ccb(conn, TRUE); 1537 if (ccb == NULL) { 1538 DEBOUT(("No CCB in io_command\n")); 1539 return ISCSI_STATUS_NO_RESOURCES; 1540 } 1541 1542 ccb->data_in = (req->flags & SCCMD_READ) != 0; 1543 ccb->data_len = (uint32_t) req->datalen; 1544 ccb->data_ptr = req->databuf; 1545 1546 ccb->sense_len_req = req->senselen; 1547 ccb->sense_ptr = &req->sense; 1548 1549 ccb->lun = lun; 1550 ccb->cmd = (uint8_t *) req->cmd; 1551 ccb->cmdlen = req->cmdlen; 1552 DEBC(conn, 10, ("IoCommand: cmd[1] = %x, cmdlen = %d\n", 1553 ccb->cmd[1], ccb->cmdlen)); 1554 1555 send_command(ccb, CCBDISP_WAIT, TRUE, immed); 1556 1557 rc = ccb->status; 1558 1559 req->senselen_used = ccb->sense_len_got; 1560 req->datalen_used = req->datalen - ccb->residual; 1561 1562 free_ccb(ccb); 1563 1564 return rc; 1565 } 1566 #endif 1567 1568 1569 /***************************************************************************** 1570 * Timeout handlers 1571 *****************************************************************************/ 1572 /* 1573 * connection_timeout: 1574 * Handle prolonged silence on a connection by checking whether 1575 * it's still alive. 1576 * This has the side effect of discovering missing status or lost commands 1577 * before those time out. 1578 * 1579 * Parameter: 1580 * par The connection 1581 */ 1582 1583 void 1584 connection_timeout(void *par) 1585 { 1586 connection_t *conn = (connection_t *) par; 1587 1588 if (++conn->num_timeouts > MAX_CONN_TIMEOUTS) 1589 handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, NO_LOGOUT); 1590 else { 1591 if (conn->state == ST_FULL_FEATURE) 1592 send_nop_out(conn, NULL); 1593 1594 callout_schedule(&conn->timeout, CONNECTION_TIMEOUT); 1595 } 1596 } 1597 1598 /* 1599 * ccb_timeout: 1600 * Handle timeout of a sent command. 1601 * 1602 * Parameter: 1603 * par The CCB 1604 */ 1605 1606 void 1607 ccb_timeout(void *par) 1608 { 1609 ccb_t *ccb = (ccb_t *) par; 1610 connection_t *conn = ccb->connection; 1611 1612 ccb->total_tries++; 1613 1614 if (++ccb->num_timeouts > MAX_CCB_TIMEOUTS || 1615 ccb->total_tries > MAX_CCB_TRIES || 1616 ccb->disp <= CCBDISP_FREE || 1617 !ccb->session->ErrorRecoveryLevel) { 1618 1619 wake_ccb(ccb, ISCSI_STATUS_TIMEOUT); 1620 handle_connection_error(conn, ISCSI_STATUS_TIMEOUT, RECOVER_CONNECTION); 1621 } else { 1622 if (ccb->data_in && ccb->xfer_len < ccb->data_len) { 1623 /* request resend of all missing data */ 1624 snack_missing(conn, ccb, SNACK_DATA_NAK, 0, 0); 1625 } else { 1626 /* request resend of all missing status */ 1627 snack_missing(conn, NULL, SNACK_STATUS_NAK, 0, 0); 1628 } 1629 callout_schedule(&ccb->timeout, COMMAND_TIMEOUT); 1630 } 1631 } 1632