1 /* $NetBSD: iscsi_rcv.c,v 1.22 2016/06/15 04:33:52 mlelstv Exp $ */ 2 3 /*- 4 * Copyright (c) 2004,2005,2006,2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Wasabi Systems, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 #include "iscsi_globals.h" 32 33 #include <sys/file.h> 34 #include <sys/socket.h> 35 #include <sys/socketvar.h> 36 37 /*****************************************************************************/ 38 39 /* 40 * my_soo_read: 41 * Replacement for soo_read with flag handling. 42 * 43 * Parameter: 44 * conn The connection 45 * u The uio descriptor 46 * flags Read flags 47 * 48 * Returns: 0 on success, else 1 49 */ 50 51 STATIC int 52 my_soo_read(connection_t *conn, struct uio *u, int flags) 53 { 54 struct socket *so = conn->sock->f_socket; 55 int ret; 56 #ifdef ISCSI_DEBUG 57 size_t resid = u->uio_resid; 58 #endif 59 60 DEBC(conn, 99, ("soo_read req: %zu\n", resid)); 61 62 if (flags & MSG_WAITALL) { 63 flags &= ~MSG_WAITALL; 64 do { 65 int oresid = u->uio_resid; 66 ret = (*so->so_receive)(so, NULL, u, NULL, NULL, &flags); 67 if (!ret && u->uio_resid == oresid) 68 break; 69 } while (!ret && u->uio_resid > 0); 70 } else 71 ret = (*so->so_receive)(so, NULL, u, NULL, NULL, &flags); 72 73 if (ret || (flags != MSG_DONTWAIT && u->uio_resid)) { 74 DEBC(conn, 1, ("Read failed (ret: %d, req: %zu, out: %zu)\n", 75 ret, resid, u->uio_resid)); 76 handle_connection_error(conn, ISCSI_STATUS_SOCKET_ERROR, 77 RECOVER_CONNECTION); 78 return 1; 79 } 80 return 0; 81 } 82 83 84 /* 85 * try_resynch_receive: 86 * Skip over everything in the socket's receive buffer, in the hope of 87 * ending up at the start of a new PDU. 88 * 89 * Parameter: 90 * conn The connection 91 */ 92 93 STATIC void 94 try_resynch_receive(connection_t *conn) 95 { 96 uint8_t buffer[64]; 97 struct uio uio; 98 struct iovec io_vec; 99 int rc; 100 101 uio.uio_rw = UIO_READ; 102 UIO_SETUP_SYSSPACE(&uio); 103 104 do { 105 io_vec.iov_base = buffer; 106 uio.uio_iov = &io_vec; 107 uio.uio_iovcnt = 1; 108 uio.uio_resid = io_vec.iov_len = sizeof(buffer); 109 110 rc = my_soo_read(conn, &uio, MSG_DONTWAIT); 111 DEBC(conn, 9, ("try_resynch_receive: rc = %d, resid = %zu\n", 112 rc, uio.uio_resid)); 113 } while (!rc && !uio.uio_resid); 114 } 115 116 117 /* 118 * ccb_from_itt 119 * Translate ITT into CCB pointer. 120 * 121 * Parameter: 122 * conn The connection 123 * itt The Initiator Task Tag 124 * 125 * Returns: 126 * Pointer to CCB, or NULL if ITT is not a valid CCB index. 127 */ 128 129 STATIC ccb_t * 130 ccb_from_itt(connection_t *conn, uint32_t itt) 131 { 132 ccb_t *ccb; 133 int cidx; 134 135 if (itt == 0xffffffff) 136 return NULL; 137 138 cidx = itt & 0xff; 139 if (cidx >= CCBS_PER_SESSION) 140 return NULL; 141 142 ccb = &conn->session->ccb[cidx]; 143 144 if (ccb->ITT != itt) { 145 DEBC(conn, 0, 146 ("ccb_from_itt: received invalid CCB itt %08x != %08x\n", 147 itt, ccb->ITT)); 148 return NULL; 149 } 150 151 if (ccb->disp <= CCBDISP_BUSY) { 152 DEBC(conn, 0, 153 ("ccb_from_itt: received CCB with invalid disp %d\n", 154 ccb->disp)); 155 return NULL; 156 } 157 158 return ccb; 159 } 160 161 162 /* 163 * read_pdu_data: 164 * Initialize the uio structure for receiving everything after the 165 * header, including data (if present), and padding. Read the data. 166 * 167 * Parameter: 168 * pdu The PDU 169 * data Pointer to data (may be NULL for auto-allocation) 170 * offset The offset into the data pointer 171 * 172 * Returns: 0 on success 173 * 1 if an error occurs during read 174 * -1 if the data digest was incorrect (PDU must be ignored) 175 */ 176 177 STATIC int 178 read_pdu_data(pdu_t *pdu, uint8_t *data, uint32_t offset) 179 { 180 static uint8_t pad_bytes[4]; 181 uint32_t len, digest; 182 struct uio *uio; 183 int i, pad; 184 connection_t *conn = pdu->connection; 185 186 DEB(15, ("read_pdu_data: data segment length = %d\n", 187 ntoh3(pdu->pdu.DataSegmentLength))); 188 if (!(len = ntoh3(pdu->pdu.DataSegmentLength))) { 189 return 0; 190 } 191 pad = len & 0x03; 192 if (pad) { 193 pad = 4 - pad; 194 } 195 196 KASSERT(data != NULL || offset == 0); 197 198 if (data == NULL) { 199 /* 200 * NOTE: Always allocate 2 extra bytes when reading temp data, 201 * since temp data is mostly used for received text, and we can 202 * make sure there's a double zero at the end of the data to mark EOF. 203 */ 204 if ((data = (uint8_t *) malloc(len + 2, M_TEMP, M_WAITOK)) == NULL) { 205 DEBOUT(("ran out of mem on receive\n")); 206 handle_connection_error(pdu->connection, 207 ISCSI_STATUS_NO_RESOURCES, LOGOUT_SESSION); 208 return 1; 209 } 210 pdu->temp_data = data; 211 pdu->temp_data_len = len; 212 } 213 214 pdu->io_vec[0].iov_base = data + offset; 215 pdu->io_vec[0].iov_len = len; 216 217 uio = &pdu->uio; 218 219 uio->uio_iov = pdu->io_vec; 220 uio->uio_iovcnt = 1; 221 uio->uio_rw = UIO_READ; 222 uio->uio_resid = len; 223 UIO_SETUP_SYSSPACE(uio); 224 225 if (pad) { 226 uio->uio_iovcnt++; 227 uio->uio_iov[1].iov_base = pad_bytes; 228 uio->uio_iov[1].iov_len = pad; 229 uio->uio_resid += pad; 230 } 231 232 if (conn->DataDigest) { 233 i = uio->uio_iovcnt++; 234 pdu->io_vec[i].iov_base = &pdu->data_digest; 235 pdu->io_vec[i].iov_len = 4; 236 uio->uio_resid += 4; 237 } 238 239 /* get the data */ 240 if (my_soo_read(conn, &pdu->uio, MSG_WAITALL) != 0) { 241 return 1; 242 } 243 if (conn->DataDigest) { 244 digest = gen_digest_2(data, len, pad_bytes, pad); 245 246 if (digest != pdu->data_digest) { 247 DEBOUT(("Data Digest Error: comp = %08x, rx = %08x\n", 248 digest, pdu->data_digest)); 249 switch (pdu->pdu.Opcode & OPCODE_MASK) { 250 case TOP_SCSI_Response: 251 case TOP_Text_Response: 252 send_snack(pdu->connection, pdu, NULL, SNACK_STATUS_NAK); 253 break; 254 255 case TOP_SCSI_Data_in: 256 send_snack(pdu->connection, pdu, NULL, SNACK_DATA_NAK); 257 break; 258 259 default: 260 /* ignore all others */ 261 break; 262 } 263 return -1; 264 } 265 } 266 return 0; 267 } 268 269 270 /* 271 * collect_text_data 272 * Handle text continuation in login and text response PDUs 273 * 274 * Parameter: 275 * pdu The received PDU 276 * req_CCB The CCB associated with the original request 277 * 278 * Returns: -1 if continue flag is set 279 * 0 if text is complete 280 * +1 if an error occurred (out of resources) 281 */ 282 STATIC int 283 collect_text_data(pdu_t *pdu, ccb_t *req_ccb) 284 { 285 286 if (req_ccb->text_data) { 287 int nlen; 288 uint8_t *newp; 289 290 nlen = req_ccb->text_len + pdu->temp_data_len; 291 /* Note: allocate extra 2 bytes for text terminator */ 292 if ((newp = malloc(nlen + 2, M_TEMP, M_WAITOK)) == NULL) { 293 DEBOUT(("Collect Text Data: Out of Memory, ccb = %p\n", req_ccb)); 294 req_ccb->status = ISCSI_STATUS_NO_RESOURCES; 295 /* XXX where is CCB freed? */ 296 return 1; 297 } 298 memcpy(newp, req_ccb->text_data, req_ccb->text_len); 299 memcpy(&newp[req_ccb->text_len], pdu->temp_data, pdu->temp_data_len); 300 301 free(req_ccb->text_data, M_TEMP); 302 free(pdu->temp_data, M_TEMP); 303 304 req_ccb->text_data = NULL; 305 pdu->temp_data = newp; 306 pdu->temp_data_len = nlen; 307 } 308 309 if (pdu->pdu.Flags & FLAG_CONTINUE) { 310 req_ccb->text_data = pdu->temp_data; 311 req_ccb->text_len = pdu->temp_data_len; 312 pdu->temp_data = NULL; 313 314 acknowledge_text(req_ccb->connection, pdu, req_ccb); 315 return -1; 316 } 317 return 0; 318 } 319 320 321 /* 322 * check_StatSN 323 * Check received vs. expected StatSN 324 * 325 * Parameter: 326 * conn The connection 327 * nw_sn The received StatSN in network byte order 328 * ack Acknowledge this SN if TRUE 329 */ 330 331 STATIC int 332 check_StatSN(connection_t *conn, uint32_t nw_sn, bool ack) 333 { 334 int rc; 335 uint32_t sn = ntohl(nw_sn); 336 337 rc = add_sernum(&conn->StatSN_buf, sn); 338 339 if (ack) 340 ack_sernum(&conn->StatSN_buf, sn); 341 342 if (rc != 1) { 343 if (rc == 0) { 344 DEBOUT(("Duplicate PDU, ExpSN %d, Recvd: %d\n", 345 conn->StatSN_buf.ExpSN, sn)); 346 return -1; 347 } 348 349 if (rc < 0) { 350 DEBOUT(("Excessive outstanding Status PDUs, ExpSN %d, Recvd: %d\n", 351 conn->StatSN_buf.ExpSN, sn)); 352 handle_connection_error(conn, ISCSI_STATUS_PDUS_LOST, 353 RECOVER_CONNECTION); 354 return rc; 355 } 356 357 DEBOUT(("Missing Status PDUs: First %d, num: %d\n", 358 conn->StatSN_buf.ExpSN, rc - 1)); 359 if (conn->state == ST_FULL_FEATURE && 360 conn->session->ErrorRecoveryLevel) { 361 snack_missing(conn, NULL, SNACK_STATUS_NAK, 362 conn->StatSN_buf.ExpSN, rc - 1); 363 } else { 364 DEBOUT(("StatSN killing connection (State = %d, " 365 "ErrorRecoveryLevel = %d)\n", 366 conn->state, conn->session->ErrorRecoveryLevel)); 367 handle_connection_error(conn, ISCSI_STATUS_PDUS_LOST, 368 RECOVER_CONNECTION); 369 return -1; 370 } 371 } 372 return 0; 373 } 374 375 376 /* 377 * check_CmdSN 378 * Check received vs. expected CmdSN 379 * 380 * Parameter: 381 * conn The connection 382 * nw_sn The received ExpCmdSN in network byte order 383 */ 384 385 STATIC void 386 check_CmdSN(connection_t *conn, uint32_t nw_sn) 387 { 388 uint32_t sn = ntohl(nw_sn); 389 ccb_t *ccb, *nxt; 390 391 TAILQ_FOREACH_SAFE(ccb, &conn->ccbs_waiting, chain, nxt) { 392 DEBC(conn, 10, 393 ("CheckCmdSN - CmdSN=%d, ExpCmdSn=%d, waiting=%p, flags=%x\n", 394 ccb->CmdSN, sn, ccb->pdu_waiting, ccb->flags)); 395 if (ccb->pdu_waiting != NULL && 396 sn_a_lt_b(sn, ccb->CmdSN) && 397 !(ccb->flags & CCBF_GOT_RSP)) { 398 DEBC(conn, 1, ("CheckCmdSN resending - CmdSN=%d, ExpCmdSn=%d\n", 399 ccb->CmdSN, sn)); 400 401 ccb->total_tries++; 402 403 if (++ccb->num_timeouts > MAX_CCB_TIMEOUTS || 404 ccb->total_tries > MAX_CCB_TRIES) { 405 handle_connection_error(conn, 406 ISCSI_STATUS_TIMEOUT, 407 (ccb->total_tries <= MAX_CCB_TRIES) 408 ? RECOVER_CONNECTION 409 : LOGOUT_CONNECTION); 410 break; 411 } else { 412 resend_pdu(ccb); 413 } 414 } 415 416 /* 417 * The target can respond to a NOP-In before subsequent 418 * commands are processed. So our CmdSN can exceed the 419 * returned ExpCmdSN by the number of commands that are 420 * in flight. Adjust the expected value accordingly. 421 */ 422 sn++; 423 } 424 } 425 426 427 /* 428 * receive_login_pdu 429 * Handle receipt of a login response PDU. 430 * 431 * Parameter: 432 * conn The connection 433 * pdu The PDU 434 * req_CCB The CCB associated with the original request (if any) 435 */ 436 437 STATIC int 438 receive_login_pdu(connection_t *conn, pdu_t *pdu, ccb_t *req_ccb) 439 { 440 int rc; 441 442 DEBC(conn, 9, ("Received Login Response PDU, op=%x, flags=%x, sn=%u\n", 443 pdu->pdu.Opcode, pdu->pdu.Flags, 444 ntohl(pdu->pdu.p.login_rsp.StatSN))); 445 446 if (req_ccb == NULL) { 447 /* Duplicate?? */ 448 DEBOUT(("Received duplicate login response (no associated CCB)\n")); 449 return -1; 450 } 451 452 if (pdu->pdu.p.login_rsp.StatusClass) { 453 DEBC(conn, 1, ("Login problem - Class = %x, Detail = %x\n", 454 pdu->pdu.p.login_rsp.StatusClass, 455 pdu->pdu.p.login_rsp.StatusDetail)); 456 wake_ccb(req_ccb, ISCSI_STATUS_LOGIN_FAILED); 457 return 0; 458 } 459 460 if (!conn->StatSN_buf.next_sn) { 461 conn->StatSN_buf.next_sn = conn->StatSN_buf.ExpSN = 462 ntohl(pdu->pdu.p.login_rsp.StatSN) + 1; 463 } else if (check_StatSN(conn, pdu->pdu.p.login_rsp.StatSN, TRUE)) 464 return -1; 465 466 if (pdu->temp_data_len) { 467 if ((rc = collect_text_data(pdu, req_ccb)) != 0) 468 return max(rc, 0); 469 } 470 471 negotiate_login(conn, pdu, req_ccb); 472 473 /* negotiate_login will decide whether login is complete or not */ 474 return 0; 475 } 476 477 478 /* 479 * receive_text_response_pdu 480 * Handle receipt of a text response PDU. 481 * 482 * Parameter: 483 * conn The connection 484 * pdu The PDU 485 * req_CCB The CCB associated with the original request (if any) 486 */ 487 488 STATIC int 489 receive_text_response_pdu(connection_t *conn, pdu_t *pdu, ccb_t *req_ccb) 490 { 491 int rc; 492 493 DEBC(conn, 9, ("Received Text Response PDU, op=%x, flags=%x\n", 494 pdu->pdu.Opcode, pdu->pdu.Flags)); 495 496 if (check_StatSN(conn, pdu->pdu.p.text_rsp.StatSN, TRUE)) { 497 return -1; 498 } 499 if (req_ccb == NULL) { 500 DEBOUT(("Received unsolicited text response\n")); 501 handle_connection_error(conn, ISCSI_STATUS_TARGET_ERROR, 502 LOGOUT_CONNECTION); 503 return -1; 504 } 505 506 if (req_ccb->pdu_waiting != NULL) { 507 ccb_timeout_start(req_ccb, COMMAND_TIMEOUT); 508 req_ccb->num_timeouts = 0; 509 } 510 511 if ((rc = collect_text_data(pdu, req_ccb)) != 0) { 512 return max(0, rc); 513 } 514 negotiate_text(conn, pdu, req_ccb); 515 516 return 0; 517 } 518 519 520 /* 521 * receive_logout_pdu 522 * Handle receipt of a logout response PDU. 523 * 524 * Parameter: 525 * conn The connection 526 * pdu The PDU 527 * req_CCB The CCB associated with the original request (if any) 528 */ 529 530 STATIC int 531 receive_logout_pdu(connection_t *conn, pdu_t *pdu, ccb_t *req_ccb) 532 { 533 bool otherconn; 534 uint8_t response; 535 uint32_t status; 536 537 otherconn = (req_ccb != NULL) ? (req_ccb->flags & CCBF_OTHERCONN) != 0 : 1; 538 response = pdu->pdu.OpcodeSpecific [0]; 539 DEBC(conn, 1, 540 ("Received Logout PDU - CCB = %p, otherconn=%d, response=%d\n", 541 req_ccb, otherconn, response)); 542 543 if (req_ccb == NULL) 544 return 0; 545 546 if (otherconn && check_StatSN(conn, pdu->pdu.p.logout_rsp.StatSN, TRUE)) 547 return -1; 548 549 switch (response) { 550 case 0: 551 status = ISCSI_STATUS_SUCCESS; 552 break; 553 case 1: 554 status = ISCSI_STATUS_LOGOUT_CID_NOT_FOUND; 555 break; 556 case 2: 557 status = ISCSI_STATUS_LOGOUT_RECOVERY_NS; 558 break; 559 default: 560 status = ISCSI_STATUS_LOGOUT_ERROR; 561 break; 562 } 563 564 if (conn->session->ErrorRecoveryLevel >= 2 && response != 1) { 565 connection_t *refconn = (otherconn) ? req_ccb->par : conn; 566 567 refconn->Time2Wait = ntohs(pdu->pdu.p.logout_rsp.Time2Wait); 568 refconn->Time2Retain = ntohs(pdu->pdu.p.logout_rsp.Time2Retain); 569 } 570 571 wake_ccb(req_ccb, status); 572 573 if (!otherconn && conn->state == ST_LOGOUT_SENT) { 574 conn->terminating = ISCSI_STATUS_LOGOUT; 575 conn->state = ST_SETTLING; 576 conn->loggedout = (response) ? LOGOUT_FAILED : LOGOUT_SUCCESS; 577 578 connection_timeout_stop(conn); 579 580 /* let send thread take over next step of cleanup */ 581 cv_broadcast(&conn->conn_cv); 582 } 583 584 return !otherconn; 585 } 586 587 588 /* 589 * receive_data_in_pdu 590 * Handle receipt of a data in PDU. 591 * 592 * Parameter: 593 * conn The connection 594 * pdu The PDU 595 * req_CCB The CCB associated with the original request (if any) 596 */ 597 598 STATIC int 599 receive_data_in_pdu(connection_t *conn, pdu_t *pdu, ccb_t *req_ccb) 600 { 601 uint32_t dsl, sn; 602 bool done; 603 int rc; 604 605 dsl = ntoh3(pdu->pdu.DataSegmentLength); 606 607 if (req_ccb == NULL || !req_ccb->data_in || !req_ccb->data_len) { 608 DEBOUT(("Received Data In, but req_ccb not waiting for it, ignored\n")); 609 return 0; 610 } 611 req_ccb->flags |= CCBF_GOT_RSP; 612 613 if (req_ccb->pdu_waiting != NULL) { 614 ccb_timeout_start(req_ccb, COMMAND_TIMEOUT); 615 req_ccb->num_timeouts = 0; 616 } 617 618 sn = ntohl(pdu->pdu.p.data_in.DataSN); 619 620 if ((rc = add_sernum(&req_ccb->DataSN_buf, sn)) != 1) { 621 if (!rc) { 622 return -1; 623 } 624 if (rc < 0) { 625 DEBOUT(("Excessive outstanding Data PDUs\n")); 626 handle_connection_error(req_ccb->connection, 627 ISCSI_STATUS_PDUS_LOST, LOGOUT_CONNECTION); 628 return -1; 629 } 630 DEBOUT(("Missing Data PDUs: First %d, num: %d\n", 631 req_ccb->DataSN_buf.ExpSN, rc - 1)); 632 633 if (conn->state == ST_FULL_FEATURE && 634 conn->session->ErrorRecoveryLevel) { 635 snack_missing(req_ccb->connection, req_ccb, 636 SNACK_DATA_NAK, req_ccb->DataSN_buf.ExpSN, 637 rc - 1); 638 } else { 639 DEBOUT(("Killing connection (State=%d, ErrorRecoveryLevel=%d)\n", 640 conn->state, conn->session->ErrorRecoveryLevel)); 641 handle_connection_error(conn, ISCSI_STATUS_PDUS_LOST, 642 LOGOUT_CONNECTION); 643 return -1; 644 } 645 } 646 647 ack_sernum(&req_ccb->DataSN_buf, sn); 648 649 req_ccb->xfer_len += dsl; 650 651 if ((pdu->pdu.Flags & FLAG_ACK) && conn->session->ErrorRecoveryLevel) 652 send_snack(conn, pdu, req_ccb, SNACK_DATA_ACK); 653 654 done = sn_empty(&req_ccb->DataSN_buf); 655 656 if (pdu->pdu.Flags & FLAG_STATUS) { 657 DEBC(conn, 10, ("Rx Data In %d, done = %d\n", 658 req_ccb->CmdSN, done)); 659 660 req_ccb->flags |= CCBF_COMPLETE; 661 /* successful transfer, reset recover count */ 662 conn->recover = 0; 663 664 if (done) 665 wake_ccb(req_ccb, ISCSI_STATUS_SUCCESS); 666 if (check_StatSN(conn, pdu->pdu.p.data_in.StatSN, done)) 667 return -1; 668 669 } else if (done && (req_ccb->flags & CCBF_COMPLETE)) { 670 wake_ccb(req_ccb, ISCSI_STATUS_SUCCESS); 671 } 672 /* else wait for command response */ 673 674 return 0; 675 } 676 677 678 /* 679 * receive_r2t_pdu 680 * Handle receipt of a R2T PDU. 681 * 682 * Parameter: 683 * conn The connection 684 * pdu The PDU 685 * req_CCB The CCB associated with the original request (if any) 686 */ 687 688 STATIC int 689 receive_r2t_pdu(connection_t *conn, pdu_t *pdu, ccb_t *req_ccb) 690 { 691 692 DEBC(conn, 10, ("Received R2T PDU - CCB = %p\n", req_ccb)); 693 694 if (req_ccb != NULL) { 695 if (req_ccb->pdu_waiting != NULL) { 696 ccb_timeout_start(req_ccb, COMMAND_TIMEOUT); 697 req_ccb->num_timeouts = 0; 698 } 699 send_data_out(conn, pdu, req_ccb, CCBDISP_NOWAIT, TRUE); 700 } 701 702 return 0; 703 } 704 705 706 /* 707 * receive_command_response_pdu 708 * Handle receipt of a command response PDU. 709 * 710 * Parameter: 711 * conn The connection 712 * pdu The PDU 713 * req_CCB The CCB associated with the original request (if any) 714 */ 715 716 STATIC int 717 receive_command_response_pdu(connection_t *conn, pdu_t *pdu, ccb_t *req_ccb) 718 { 719 int len, rc; 720 bool done; 721 uint32_t status; 722 723 /* Read any provided data */ 724 if (pdu->temp_data_len && req_ccb != NULL && req_ccb->sense_len_req) { 725 len = min(req_ccb->sense_len_req, 726 ntohs(*((uint16_t *) pdu->temp_data))); 727 memcpy(req_ccb->sense_ptr, ((uint16_t *) pdu->temp_data) + 1, 728 len); 729 req_ccb->sense_len_got = len; 730 } 731 732 if (req_ccb == NULL) { 733 /* Assume duplicate... */ 734 DEBOUT(("Possibly duplicate command response (no associated CCB)\n")); 735 return -1; 736 } 737 738 if (req_ccb->pdu_waiting != NULL) { 739 ccb_timeout_start(req_ccb, COMMAND_TIMEOUT); 740 req_ccb->num_timeouts = 0; 741 } 742 743 req_ccb->flags |= CCBF_COMPLETE; 744 conn->recover = 0; /* successful transfer, reset recover count */ 745 746 if (pdu->pdu.OpcodeSpecific[0]) { /* Response */ 747 status = ISCSI_STATUS_TARGET_FAILURE; 748 } else { 749 switch (pdu->pdu.OpcodeSpecific[1]) { /* Status */ 750 case 0x00: 751 status = ISCSI_STATUS_SUCCESS; 752 break; 753 754 case 0x02: 755 status = ISCSI_STATUS_CHECK_CONDITION; 756 break; 757 758 case 0x08: 759 status = ISCSI_STATUS_TARGET_BUSY; 760 break; 761 762 default: 763 status = ISCSI_STATUS_TARGET_ERROR; 764 break; 765 } 766 } 767 768 if (pdu->pdu.Flags & (FLAG_OVERFLOW | FLAG_UNDERFLOW)) 769 req_ccb->residual = ntohl(pdu->pdu.p.response.ResidualCount); 770 771 done = status || sn_empty(&req_ccb->DataSN_buf); 772 773 DEBC(conn, 10, ("Rx Response: CmdSN %d, rsp = %x, status = %x\n", 774 req_ccb->CmdSN, 775 pdu->pdu.OpcodeSpecific[0], 776 pdu->pdu.OpcodeSpecific[1])); 777 778 rc = check_StatSN(conn, pdu->pdu.p.response.StatSN, done); 779 780 if (done) 781 wake_ccb(req_ccb, status); 782 783 return rc; 784 } 785 786 787 /* 788 * receive_asynch_pdu 789 * Handle receipt of an asynchronous message PDU. 790 * 791 * Parameter: 792 * conn The connection 793 * pdu The PDU 794 */ 795 796 STATIC int 797 receive_asynch_pdu(connection_t *conn, pdu_t *pdu) 798 { 799 800 DEBOUT(("Received Asynch PDU, Event %d\n", pdu->pdu.p.asynch.AsyncEvent)); 801 802 switch (pdu->pdu.p.asynch.AsyncEvent) { 803 case 0: /* SCSI Asynch event. Don't know what to do with it... */ 804 break; 805 806 case 1: /* Target requests logout. */ 807 if (conn->session->active_connections > 1) { 808 kill_connection(conn, ISCSI_STATUS_TARGET_LOGOUT, 809 LOGOUT_CONNECTION, FALSE); 810 } else { 811 kill_session(conn->session, ISCSI_STATUS_TARGET_LOGOUT, 812 LOGOUT_SESSION, FALSE); 813 } 814 break; 815 816 case 2: /* Target is dropping connection */ 817 conn = find_connection(conn->session, 818 ntohs(pdu->pdu.p.asynch.Parameter1)); 819 if (conn != NULL) { 820 conn->Time2Wait = ntohs(pdu->pdu.p.asynch.Parameter2); 821 conn->Time2Retain = ntohs(pdu->pdu.p.asynch.Parameter3); 822 kill_connection(conn, ISCSI_STATUS_TARGET_DROP, 823 NO_LOGOUT, TRUE); 824 } 825 break; 826 827 case 3: /* Target is dropping all connections of session */ 828 conn->session->DefaultTime2Wait = ntohs(pdu->pdu.p.asynch.Parameter2); 829 conn->session->DefaultTime2Retain = ntohs(pdu->pdu.p.asynch.Parameter3); 830 kill_session(conn->session, ISCSI_STATUS_TARGET_DROP, NO_LOGOUT, TRUE); 831 break; 832 833 case 4: /* Target requests parameter negotiation */ 834 start_text_negotiation(conn); 835 break; 836 837 default: 838 /* ignore */ 839 break; 840 } 841 return 0; 842 } 843 844 845 /* 846 * receive_reject_pdu 847 * Handle receipt of a reject PDU. 848 * 849 * Parameter: 850 * conn The connection 851 * pdu The PDU 852 */ 853 854 STATIC int 855 receive_reject_pdu(connection_t *conn, pdu_t *pdu) 856 { 857 pdu_header_t *hpdu; 858 ccb_t *req_ccb; 859 uint32_t status; 860 861 DEBOUT(("Received Reject PDU, reason = %x, data_len = %d\n", 862 pdu->pdu.OpcodeSpecific[0], pdu->temp_data_len)); 863 864 if (pdu->temp_data_len >= BHS_SIZE) { 865 hpdu = (pdu_header_t *) pdu->temp_data; 866 req_ccb = ccb_from_itt(conn, hpdu->InitiatorTaskTag); 867 868 DEBC(conn, 9, ("Reject PDU ITT (ccb)= %x (%p)\n", 869 hpdu->InitiatorTaskTag, req_ccb)); 870 if (!req_ccb) { 871 return 0; 872 } 873 switch (pdu->pdu.OpcodeSpecific[0]) { 874 case REJECT_DIGEST_ERROR: 875 /* don't retransmit data out */ 876 if ((hpdu->Opcode & OPCODE_MASK) == IOP_SCSI_Data_out) 877 return 0; 878 resend_pdu(req_ccb); 879 return 0; 880 881 case REJECT_IMMED_COMMAND: 882 case REJECT_LONG_OPERATION: 883 resend_pdu(req_ccb); 884 return 0; 885 886 case REJECT_SNACK: 887 case REJECT_PROTOCOL_ERROR: 888 status = ISCSI_STATUS_PROTOCOL_ERROR; 889 break; 890 891 case REJECT_CMD_NOT_SUPPORTED: 892 status = ISCSI_STATUS_CMD_NOT_SUPPORTED; 893 break; 894 895 case REJECT_INVALID_PDU_FIELD: 896 status = ISCSI_STATUS_PDU_ERROR; 897 break; 898 899 default: 900 status = ISCSI_STATUS_GENERAL_ERROR; 901 break; 902 } 903 904 wake_ccb(req_ccb, status); 905 handle_connection_error(conn, ISCSI_STATUS_PROTOCOL_ERROR, 906 LOGOUT_CONNECTION); 907 } 908 return 0; 909 } 910 911 912 /* 913 * receive_task_management_pdu 914 * Handle receipt of a task management PDU. 915 * 916 * Parameter: 917 * conn The connection 918 * pdu The PDU 919 * req_CCB The CCB associated with the original request (if any) 920 */ 921 922 STATIC int 923 receive_task_management_pdu(connection_t *conn, pdu_t *pdu, ccb_t *req_ccb) 924 { 925 uint32_t status; 926 927 DEBC(conn, 2, ("Received Task Management PDU, response %d, req_ccb %p\n", 928 pdu->pdu.OpcodeSpecific[0], req_ccb)); 929 930 if (req_ccb != NULL) { 931 switch (pdu->pdu.OpcodeSpecific[0]) { /* Response */ 932 case 0: 933 status = ISCSI_STATUS_SUCCESS; 934 break; 935 case 1: 936 status = ISCSI_STATUS_TASK_NOT_FOUND; 937 break; 938 case 2: 939 status = ISCSI_STATUS_LUN_NOT_FOUND; 940 break; 941 case 3: 942 status = ISCSI_STATUS_TASK_ALLEGIANT; 943 break; 944 case 4: 945 status = ISCSI_STATUS_CANT_REASSIGN; 946 break; 947 case 5: 948 status = ISCSI_STATUS_FUNCTION_UNSUPPORTED; 949 break; 950 case 6: 951 status = ISCSI_STATUS_FUNCTION_NOT_AUTHORIZED; 952 break; 953 case 255: 954 status = ISCSI_STATUS_FUNCTION_REJECTED; 955 break; 956 default: 957 status = ISCSI_STATUS_UNKNOWN_REASON; 958 break; 959 } 960 wake_ccb(req_ccb, status); 961 } 962 963 check_StatSN(conn, pdu->pdu.p.task_rsp.StatSN, TRUE); 964 965 return 0; 966 } 967 968 969 /* 970 * receive_nop_in_pdu 971 * Handle receipt of a Nop-In PDU. 972 * 973 * Parameter: 974 * conn The connection 975 * pdu The PDU 976 * req_CCB The CCB associated with the original request (if any) 977 */ 978 979 STATIC int 980 receive_nop_in_pdu(connection_t *conn, pdu_t *pdu, ccb_t *req_ccb) 981 { 982 DEBC(conn, 10, 983 ("Received NOP_In PDU, req_ccb=%p, ITT=%x, TTT=%x, StatSN=%u\n", 984 req_ccb, pdu->pdu.InitiatorTaskTag, 985 pdu->pdu.p.nop_in.TargetTransferTag, 986 ntohl(pdu->pdu.p.nop_in.StatSN))); 987 988 if (pdu->pdu.InitiatorTaskTag == 0xffffffff) { 989 /* this is a target ping - respond with a pong */ 990 if (pdu->pdu.p.nop_in.TargetTransferTag != 0xffffffff) 991 send_nop_out(conn, pdu); 992 993 /* 994 Any receive resets the connection timeout, but we got a ping, which 995 means that it's likely the other side was waiting for something to 996 happen on the connection. If we aren't idle, send a ping right 997 away to synch counters (don't synch on this ping because other 998 PDUs may be on the way). 999 */ 1000 if (TAILQ_FIRST(&conn->ccbs_waiting) != NULL) 1001 send_nop_out(conn, NULL); 1002 } else if (req_ccb != NULL) { 1003 /* this is a solicited ping, check CmdSN for lost commands */ 1004 /* and advance StatSN */ 1005 check_CmdSN(conn, pdu->pdu.p.nop_in.ExpCmdSN); 1006 1007 wake_ccb(req_ccb, ISCSI_STATUS_SUCCESS); 1008 1009 check_StatSN(conn, pdu->pdu.p.nop_in.StatSN, TRUE); 1010 } else { 1011 DEBC(conn, 0, ("Received unsolicted NOP_In, itt=%08x\n", 1012 pdu->pdu.InitiatorTaskTag)); 1013 } 1014 1015 return 0; 1016 } 1017 1018 1019 /* 1020 * receive_pdu 1021 * Get parameters, call the appropriate handler for a received PDU. 1022 * 1023 * Parameter: 1024 * conn The connection 1025 * pdu The PDU 1026 * 1027 * Returns: 0 on success, nonzero if the connection is broken. 1028 */ 1029 1030 STATIC int 1031 receive_pdu(connection_t *conn, pdu_t *pdu) 1032 { 1033 ccb_t *req_ccb; 1034 int rc; 1035 uint32_t MaxCmdSN, ExpCmdSN, digest; 1036 session_t *sess = conn->session; 1037 1038 if (conn->HeaderDigest) { 1039 digest = gen_digest(&pdu->pdu, BHS_SIZE); 1040 if (digest != pdu->pdu.HeaderDigest) { 1041 DEBOUT(("Header Digest Error: comp = %08x, rx = %08x\n", 1042 digest, pdu->pdu.HeaderDigest)); 1043 /* try to skip to next PDU */ 1044 try_resynch_receive(conn); 1045 free_pdu(pdu); 1046 return 0; 1047 } 1048 } 1049 1050 DEBC(conn, 10, ("Received PDU StatSN=%u, ExpCmdSN=%u MaxCmdSN=%u ExpDataSN=%u\n", 1051 ntohl(pdu->pdu.p.response.StatSN), 1052 ntohl(pdu->pdu.p.response.ExpCmdSN), 1053 ntohl(pdu->pdu.p.response.MaxCmdSN), 1054 ntohl(pdu->pdu.p.response.ExpDataSN))); 1055 1056 req_ccb = ccb_from_itt(conn, pdu->pdu.InitiatorTaskTag); 1057 1058 if (req_ccb != NULL && req_ccb->data_in && req_ccb->data_len && 1059 (pdu->pdu.Opcode & OPCODE_MASK) == TOP_SCSI_Data_in) { 1060 uint32_t dsl, offset; 1061 1062 dsl = ntoh3(pdu->pdu.DataSegmentLength); 1063 offset = ntohl(pdu->pdu.p.data_in.BufferOffset); 1064 1065 if ((offset + dsl) > req_ccb->data_len) { 1066 DEBOUT(("Received more data than requested (len %d, offset %d)\n", 1067 dsl, offset)); 1068 handle_connection_error(conn, ISCSI_STATUS_TARGET_ERROR, NO_LOGOUT); 1069 return 1; 1070 } 1071 DEBC(conn, 10, 1072 ("Received Data in PDU - CCB = %p, Datalen = %d, Offset = %d\n", 1073 req_ccb, dsl, offset)); 1074 1075 rc = read_pdu_data(pdu, req_ccb->data_ptr, offset); 1076 } else { 1077 rc = read_pdu_data(pdu, NULL, 0); 1078 } 1079 if (!rc && (conn->state <= ST_WINDING_DOWN || 1080 (pdu->pdu.Opcode & OPCODE_MASK) == TOP_Logout_Response)) { 1081 1082 switch (pdu->pdu.Opcode & OPCODE_MASK) { 1083 case TOP_NOP_In: 1084 rc = receive_nop_in_pdu(conn, pdu, req_ccb); 1085 break; 1086 1087 case TOP_SCSI_Response: 1088 rc = receive_command_response_pdu(conn, pdu, req_ccb); 1089 break; 1090 1091 case TOP_SCSI_Task_Management: 1092 rc = receive_task_management_pdu(conn, pdu, req_ccb); 1093 break; 1094 1095 case TOP_Login_Response: 1096 rc = receive_login_pdu(conn, pdu, req_ccb); 1097 break; 1098 1099 case TOP_Text_Response: 1100 rc = receive_text_response_pdu(conn, pdu, req_ccb); 1101 break; 1102 1103 case TOP_SCSI_Data_in: 1104 rc = receive_data_in_pdu(conn, pdu, req_ccb); 1105 break; 1106 1107 case TOP_Logout_Response: 1108 rc = receive_logout_pdu(conn, pdu, req_ccb); 1109 break; 1110 1111 case TOP_R2T: 1112 rc = receive_r2t_pdu(conn, pdu, req_ccb); 1113 break; 1114 1115 case TOP_Asynchronous_Message: 1116 rc = receive_asynch_pdu(conn, pdu); 1117 break; 1118 1119 case TOP_Reject: 1120 rc = receive_reject_pdu(conn, pdu); 1121 break; 1122 1123 default: 1124 DEBOUT(("Received Invalid Opcode %x\n", pdu->pdu.Opcode)); 1125 try_resynch_receive(conn); 1126 rc = -1; 1127 break; 1128 } 1129 } 1130 1131 free_pdu(pdu); 1132 if (rc) 1133 return rc; 1134 1135 /* MaxCmdSN and ExpCmdSN are in the same place in all received PDUs */ 1136 ExpCmdSN = ntohl(pdu->pdu.p.nop_in.ExpCmdSN); 1137 MaxCmdSN = ntohl(pdu->pdu.p.nop_in.MaxCmdSN); 1138 1139 /* received a valid frame, reset timeout */ 1140 if ((pdu->pdu.Opcode & OPCODE_MASK) == TOP_NOP_In && 1141 TAILQ_EMPTY(&conn->ccbs_waiting)) 1142 connection_timeout_start(conn, conn->idle_timeout_val); 1143 else 1144 connection_timeout_start(conn, CONNECTION_TIMEOUT); 1145 conn->num_timeouts = 0; 1146 1147 /* Update session window */ 1148 mutex_enter(&sess->lock); 1149 if (sn_a_le_b(ExpCmdSN - 1, MaxCmdSN)) { 1150 if (sn_a_lt_b(sess->ExpCmdSN, ExpCmdSN)) 1151 sess->ExpCmdSN = ExpCmdSN; 1152 if (sn_a_lt_b(sess->MaxCmdSN, MaxCmdSN)) 1153 sess->MaxCmdSN = MaxCmdSN; 1154 } 1155 mutex_exit(&sess->lock); 1156 1157 return 0; 1158 } 1159 1160 /*****************************************************************************/ 1161 1162 /* 1163 * iscsi_receive_thread 1164 * Per connection thread handling receive data. 1165 * 1166 * Parameter: 1167 * conn The connection 1168 */ 1169 1170 void 1171 iscsi_rcv_thread(void *par) 1172 { 1173 connection_t *conn = (connection_t *) par; 1174 pdu_t *pdu; 1175 size_t hlen; 1176 1177 do { 1178 while (!conn->terminating) { 1179 pdu = get_pdu(conn, TRUE); 1180 if (pdu == NULL) { 1181 KASSERT(conn->terminating); 1182 break; 1183 } 1184 1185 pdu->uio.uio_iov = pdu->io_vec; 1186 UIO_SETUP_SYSSPACE(&pdu->uio); 1187 pdu->uio.uio_iovcnt = 1; 1188 pdu->uio.uio_rw = UIO_READ; 1189 1190 pdu->io_vec[0].iov_base = &pdu->pdu; 1191 hlen = (conn->HeaderDigest) ? BHS_SIZE + 4 : BHS_SIZE; 1192 pdu->io_vec[0].iov_len = hlen; 1193 pdu->uio.uio_resid = hlen; 1194 1195 DEBC(conn, 99, ("Receive thread waiting for data\n")); 1196 if (my_soo_read(conn, &pdu->uio, MSG_WAITALL)) { 1197 free_pdu(pdu); 1198 break; 1199 } 1200 /* Check again for header digest */ 1201 /* (it may have changed during the wait) */ 1202 if (hlen == BHS_SIZE && conn->HeaderDigest) { 1203 pdu->uio.uio_iov = pdu->io_vec; 1204 pdu->uio.uio_iovcnt = 1; 1205 pdu->io_vec[0].iov_base = &pdu->pdu.HeaderDigest; 1206 pdu->io_vec[0].iov_len = 4; 1207 pdu->uio.uio_resid = 4; 1208 if (my_soo_read(conn, &pdu->uio, MSG_WAITALL)) { 1209 free_pdu(pdu); 1210 break; 1211 } 1212 } 1213 1214 if (receive_pdu(conn, pdu) > 0) { 1215 break; 1216 } 1217 } 1218 mutex_enter(&conn->lock); 1219 if (!conn->destroy) { 1220 cv_timedwait(&conn->idle_cv, &conn->lock, CONNECTION_IDLE_TIMEOUT); 1221 } 1222 mutex_exit(&conn->lock); 1223 } while (!conn->destroy); 1224 1225 conn->rcvproc = NULL; 1226 DEBC(conn, 5, ("Receive thread exits\n")); 1227 kthread_exit(0); 1228 } 1229