1 /* $NetBSD: iscsi_ioctl.c,v 1.34 2023/11/25 10:08:27 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 32 #include "iscsi_globals.h" 33 34 #include <sys/file.h> 35 #include <sys/filedesc.h> 36 #include <sys/proc.h> 37 #include <sys/kmem.h> 38 39 static kmutex_t iscsi_cleanup_mtx; 40 static kcondvar_t iscsi_cleanup_cv; 41 static kcondvar_t iscsi_event_cv; 42 static struct lwp *iscsi_cleanproc = NULL; 43 44 static uint16_t current_id = 0; /* Global session ID counter */ 45 46 /* list of event handlers */ 47 static event_handler_list_t event_handlers = 48 TAILQ_HEAD_INITIALIZER(event_handlers); 49 50 static connection_list_t iscsi_timeout_conn_list = 51 TAILQ_HEAD_INITIALIZER(iscsi_timeout_conn_list); 52 53 static ccb_list_t iscsi_timeout_ccb_list = 54 TAILQ_HEAD_INITIALIZER(iscsi_timeout_ccb_list); 55 56 static session_list_t iscsi_cleanups_list = 57 TAILQ_HEAD_INITIALIZER(iscsi_cleanups_list); 58 59 static connection_list_t iscsi_cleanupc_list = 60 TAILQ_HEAD_INITIALIZER(iscsi_cleanupc_list); 61 62 static uint32_t handler_id = 0; /* Handler ID counter */ 63 64 /* -------------------------------------------------------------------------- */ 65 66 /* Event management functions */ 67 68 /* 69 * find_handler: 70 * Search the event handler list for the given ID. 71 * 72 * Parameter: 73 * id The handler ID. 74 * 75 * Returns: 76 * Pointer to handler if found, else NULL. 77 */ 78 79 80 static event_handler_t * 81 find_handler(uint32_t id) 82 { 83 event_handler_t *curr; 84 85 KASSERT(mutex_owned(&iscsi_cleanup_mtx)); 86 87 TAILQ_FOREACH(curr, &event_handlers, evh_link) 88 if (curr->evh_id == id) 89 break; 90 91 return curr; 92 } 93 94 95 /* 96 * register_event: 97 * Create event handler entry, return ID. 98 * 99 * Parameter: 100 * par The parameter. 101 */ 102 103 static void 104 register_event(iscsi_register_event_parameters_t *par) 105 { 106 event_handler_t *handler; 107 int was_empty; 108 109 handler = malloc(sizeof(event_handler_t), M_DEVBUF, M_WAITOK | M_ZERO); 110 if (handler == NULL) { 111 DEBOUT(("No mem for event handler\n")); 112 par->status = ISCSI_STATUS_NO_RESOURCES; 113 return; 114 } 115 116 TAILQ_INIT(&handler->evh_events); 117 118 mutex_enter(&iscsi_cleanup_mtx); 119 /* create a unique ID */ 120 do { 121 ++handler_id; 122 } while (!handler_id || find_handler(handler_id) != NULL); 123 par->event_id = handler->evh_id = handler_id; 124 125 was_empty = TAILQ_FIRST(&event_handlers) == NULL; 126 TAILQ_INSERT_TAIL(&event_handlers, handler, evh_link); 127 if (was_empty) 128 iscsi_notify_cleanup(); 129 mutex_exit(&iscsi_cleanup_mtx); 130 131 par->status = ISCSI_STATUS_SUCCESS; 132 DEB(5, ("Register Event OK, ID %d\n", par->event_id)); 133 } 134 135 136 /* 137 * deregister_event: 138 * Destroy handler entry and any waiting events, wake up waiter. 139 * 140 * Parameter: 141 * par The parameter. 142 */ 143 144 static void 145 deregister_event(iscsi_register_event_parameters_t *par) 146 { 147 event_handler_t *handler; 148 event_t *evt; 149 150 mutex_enter(&iscsi_cleanup_mtx); 151 handler = find_handler(par->event_id); 152 if (handler == NULL) { 153 mutex_exit(&iscsi_cleanup_mtx); 154 DEB(1, ("Deregister Event ID %d not found\n", par->event_id)); 155 par->status = ISCSI_STATUS_INVALID_EVENT_ID; 156 return; 157 } 158 159 TAILQ_REMOVE(&event_handlers, handler, evh_link); 160 if (handler->evh_waiter != NULL) { 161 handler->evh_waiter->status = ISCSI_STATUS_EVENT_DEREGISTERED; 162 cv_broadcast(&iscsi_event_cv); 163 } 164 165 while ((evt = TAILQ_FIRST(&handler->evh_events)) != NULL) { 166 TAILQ_REMOVE(&handler->evh_events, evt, ev_link); 167 free(evt, M_TEMP); 168 } 169 mutex_exit(&iscsi_cleanup_mtx); 170 171 free(handler, M_DEVBUF); 172 par->status = ISCSI_STATUS_SUCCESS; 173 DEB(5, ("Deregister Event ID %d complete\n", par->event_id)); 174 } 175 176 177 /* 178 * check_event: 179 * Return first queued event. Optionally wait for arrival of event. 180 * 181 * Parameter: 182 * par The parameter. 183 * wait Wait for event if true 184 */ 185 186 static void 187 check_event(iscsi_wait_event_parameters_t *par, bool wait) 188 { 189 event_handler_t *handler; 190 event_t *evt; 191 int rc; 192 193 mutex_enter(&iscsi_cleanup_mtx); 194 handler = find_handler(par->event_id); 195 if (handler == NULL) { 196 mutex_exit(&iscsi_cleanup_mtx); 197 DEBOUT(("Wait Event ID %d not found\n", par->event_id)); 198 par->status = ISCSI_STATUS_INVALID_EVENT_ID; 199 return; 200 } 201 if (handler->evh_waiter != NULL) { 202 mutex_exit(&iscsi_cleanup_mtx); 203 DEBOUT(("Wait Event ID %d already waiting\n", par->event_id)); 204 par->status = ISCSI_STATUS_EVENT_WAITING; 205 return; 206 } 207 par->status = ISCSI_STATUS_SUCCESS; 208 DEB(99, ("Wait Event ID %d\n", par->event_id)); 209 210 do { 211 evt = TAILQ_FIRST(&handler->evh_events); 212 if (evt != NULL) { 213 TAILQ_REMOVE(&handler->evh_events, evt, ev_link); 214 } else { 215 if (!wait) { 216 par->status = ISCSI_STATUS_LIST_EMPTY; 217 return; 218 } 219 if (par->status != ISCSI_STATUS_SUCCESS) { 220 return; 221 } 222 handler->evh_waiter = par; 223 rc = cv_wait_sig(&iscsi_event_cv, &iscsi_cleanup_mtx); 224 if (rc) { 225 mutex_exit(&iscsi_cleanup_mtx); 226 par->status = ISCSI_STATUS_LIST_EMPTY; 227 return; 228 } 229 } 230 } while (evt == NULL); 231 mutex_exit(&iscsi_cleanup_mtx); 232 233 par->connection_id = evt->ev_connection_id; 234 par->session_id = evt->ev_session_id; 235 par->event_kind = evt->ev_event_kind; 236 par->reason = evt->ev_reason; 237 238 free(evt, M_TEMP); 239 } 240 241 /* 242 * add_event 243 * Adds an event entry to each registered handler queue. 244 * Note that events are simply duplicated because we expect the number of 245 * handlers to be very small, usually 1 (the daemon). 246 * 247 * Parameters: 248 * kind The event kind 249 * sid The ID of the affected session 250 * cid The ID of the affected connection 251 * reason The reason code 252 */ 253 254 void 255 add_event(iscsi_event_t kind, uint32_t sid, uint32_t cid, uint32_t reason) 256 { 257 event_handler_t *curr; 258 event_t *evt; 259 260 DEB(9, ("Add_event kind %d, sid %d, cid %d, reason %d\n", 261 kind, sid, cid, reason)); 262 263 mutex_enter(&iscsi_cleanup_mtx); 264 TAILQ_FOREACH(curr, &event_handlers, evh_link) { 265 evt = malloc(sizeof(*evt), M_TEMP, M_NOWAIT); 266 if (evt == NULL) { 267 DEBOUT(("Cannot allocate event\n")); 268 break; 269 } 270 evt->ev_event_kind = kind; 271 evt->ev_session_id = sid; 272 evt->ev_connection_id = cid; 273 evt->ev_reason = reason; 274 275 TAILQ_INSERT_TAIL(&curr->evh_events, evt, ev_link); 276 if (curr->evh_waiter != NULL) { 277 curr->evh_waiter = NULL; 278 cv_broadcast(&iscsi_event_cv); 279 } 280 } 281 mutex_exit(&iscsi_cleanup_mtx); 282 } 283 284 285 /* 286 * check_event_handlers 287 * Checks for dead event handlers. A dead event handler would deplete 288 * memory over time, so we have to make sure someone at the other 289 * end is actively monitoring events. 290 * This function is called every 30 seconds or so (less frequent if there 291 * is other activity for the cleanup thread to deal with) to go through 292 * the list of handlers and check whether the first element in the event 293 * list has changed at all. If not, the event is deregistered. 294 * Note that this will not detect dead handlers if no events are pending, 295 * but we don't care as long as events don't accumulate in the list. 296 * 297 */ 298 299 static void 300 check_event_handlers(void) 301 { 302 event_handler_t *curr, *next; 303 event_t *evt; 304 305 KASSERT(mutex_owned(&iscsi_cleanup_mtx)); 306 307 for (curr = TAILQ_FIRST(&event_handlers); curr != NULL; curr = next) { 308 next = TAILQ_NEXT(curr, evh_link); 309 evt = TAILQ_FIRST(&curr->evh_events); 310 311 if (evt != NULL && evt == curr->evh_first_in_list) { 312 DEBOUT(("Found Dead Event Handler %d, removing\n", curr->evh_id)); 313 314 TAILQ_REMOVE(&event_handlers, curr, evh_link); 315 while ((evt = TAILQ_FIRST(&curr->evh_events)) != NULL) { 316 TAILQ_REMOVE(&curr->evh_events, evt, ev_link); 317 free(evt, M_TEMP); 318 } 319 free(curr, M_DEVBUF); 320 } else 321 curr->evh_first_in_list = evt; 322 } 323 } 324 325 326 /* -------------------------------------------------------------------------- */ 327 328 /* 329 * get_socket: 330 * Get the file pointer from the socket handle passed into login. 331 * 332 * Parameter: 333 * fdes IN: The socket handle 334 * fpp OUT: The pointer to the resulting file pointer 335 * 336 * Returns: 0 on success, else an error code. 337 * 338 */ 339 340 static int 341 get_socket(int fdes, struct file **fpp) 342 { 343 struct file *fp; 344 345 if ((fp = fd_getfile(fdes)) == NULL) { 346 return EBADF; 347 } 348 if (fp->f_type != DTYPE_SOCKET) { 349 return ENOTSOCK; 350 } 351 352 /* Add the reference */ 353 mutex_enter(&fp->f_lock); 354 fp->f_count++; 355 mutex_exit(&fp->f_lock); 356 357 *fpp = fp; 358 return 0; 359 } 360 361 /* 362 * release_socket: 363 * Release the file pointer from the socket handle passed into login. 364 * 365 * Parameter: 366 * fp IN: The pointer to the resulting file pointer 367 * 368 */ 369 370 static void 371 release_socket(struct file *fp) 372 { 373 /* Add the reference */ 374 mutex_enter(&fp->f_lock); 375 fp->f_count--; 376 mutex_exit(&fp->f_lock); 377 } 378 379 380 /* 381 * find_session: 382 * Find a session by ID. 383 * 384 * Parameter: the session ID 385 * 386 * Returns: The pointer to the session (or NULL if not found) 387 */ 388 389 session_t * 390 find_session(uint32_t id) 391 { 392 session_t *sess; 393 394 KASSERT(mutex_owned(&iscsi_cleanup_mtx)); 395 396 TAILQ_FOREACH(sess, &iscsi_sessions, s_sessions) 397 if (sess->s_id == id) { 398 break; 399 } 400 return sess; 401 } 402 403 404 /* 405 * find_connection: 406 * Find a connection by ID. 407 * 408 * Parameter: the session pointer and the connection ID 409 * 410 * Returns: The pointer to the connection (or NULL if not found) 411 */ 412 413 connection_t * 414 find_connection(session_t *sess, uint32_t id) 415 { 416 connection_t *conn; 417 418 KASSERT(mutex_owned(&iscsi_cleanup_mtx)); 419 420 TAILQ_FOREACH(conn, &sess->s_conn_list, c_connections) 421 if (conn->c_id == id) { 422 break; 423 } 424 return conn; 425 } 426 427 /* 428 * ref_session: 429 * Reference a session 430 * 431 * Session cannot be release until reference count reaches zero 432 * 433 * Returns: 1 if reference counter would overflow 434 */ 435 436 int 437 ref_session(session_t *sess) 438 { 439 int rc = 1; 440 441 mutex_enter(&iscsi_cleanup_mtx); 442 KASSERT(sess != NULL); 443 if (sess->s_refcount <= CCBS_PER_SESSION) { 444 sess->s_refcount++; 445 rc = 0; 446 } 447 mutex_exit(&iscsi_cleanup_mtx); 448 449 return rc; 450 } 451 452 /* 453 * unref_session: 454 * Unreference a session 455 * 456 * Release session reference, trigger cleanup 457 */ 458 459 void 460 unref_session(session_t *session) 461 { 462 463 mutex_enter(&iscsi_cleanup_mtx); 464 KASSERT(session != NULL); 465 KASSERT(session->s_refcount > 0); 466 if (--session->s_refcount == 0) 467 cv_broadcast(&session->s_sess_cv); 468 mutex_exit(&iscsi_cleanup_mtx); 469 } 470 471 472 /* 473 * kill_connection: 474 * Terminate the connection as gracefully as possible. 475 * 476 * Parameter: 477 * conn The connection to terminate 478 * status The status code for the connection's "terminating" field 479 * logout The logout reason code 480 * recover Attempt to recover connection 481 */ 482 483 void 484 kill_connection(connection_t *conn, uint32_t status, int logout, bool recover) 485 { 486 session_t *sess = conn->c_session; 487 int terminating; 488 489 DEBC(conn, 1, ("Kill_connection: terminating=%d, status=%d, logout=%d, " 490 "state=%d\n", 491 conn->c_terminating, status, logout, conn->c_state)); 492 493 mutex_enter(&iscsi_cleanup_mtx); 494 if (recover && 495 !conn->c_destroy && 496 conn->c_recover > MAX_RECOVERY_ATTEMPTS) { 497 DEBC(conn, 1, ("Kill_connection: Too many recovery attempts, " 498 "destroying\n")); 499 conn->c_destroy = TRUE; 500 } 501 502 if (!recover || conn->c_destroy) { 503 504 if (conn->c_in_session) { 505 conn->c_in_session = FALSE; 506 TAILQ_REMOVE(&sess->s_conn_list, conn, c_connections); 507 sess->s_mru_connection = TAILQ_FIRST(&sess->s_conn_list); 508 } 509 510 if (!conn->c_destroy) { 511 DEBC(conn, 1, ("Kill_connection setting destroy flag\n")); 512 conn->c_destroy = TRUE; 513 } 514 } 515 516 terminating = conn->c_terminating; 517 if (!terminating) 518 conn->c_terminating = status; 519 520 /* Don't recurse */ 521 if (terminating) { 522 mutex_exit(&iscsi_cleanup_mtx); 523 524 KASSERT(conn->c_state != ST_FULL_FEATURE); 525 DEBC(conn, 1, ("Kill_connection exiting (already terminating)\n")); 526 goto done; 527 } 528 529 if (conn->c_state == ST_FULL_FEATURE) { 530 sess->s_active_connections--; 531 conn->c_state = ST_WINDING_DOWN; 532 533 /* If this is the last connection and ERL < 2, reset TSIH */ 534 if (!sess->s_active_connections && sess->s_ErrorRecoveryLevel < 2) 535 sess->s_TSIH = 0; 536 537 /* Don't try to log out if the socket is broken or we're in the middle */ 538 /* of logging in */ 539 if (logout >= 0) { 540 if (sess->s_ErrorRecoveryLevel < 2 && 541 logout == RECOVER_CONNECTION) { 542 logout = LOGOUT_CONNECTION; 543 } 544 if (!sess->s_active_connections && 545 logout == LOGOUT_CONNECTION) { 546 logout = LOGOUT_SESSION; 547 } 548 mutex_exit(&iscsi_cleanup_mtx); 549 550 DEBC(conn, 1, ("Send_logout for reason %d\n", logout)); 551 552 connection_timeout_start(conn, CONNECTION_TIMEOUT); 553 554 if (!send_logout(conn, conn, logout, FALSE)) { 555 conn->c_terminating = ISCSI_STATUS_SUCCESS; 556 return; 557 } 558 /* 559 * if the logout request was successfully sent, 560 * the logout response handler will do the rest 561 * of the termination processing. If the logout 562 * doesn't get a response, we'll get back in here 563 * once the timeout hits. 564 */ 565 566 mutex_enter(&iscsi_cleanup_mtx); 567 } 568 569 } 570 571 conn->c_state = ST_SETTLING; 572 mutex_exit(&iscsi_cleanup_mtx); 573 574 done: 575 /* let send thread take over next step of cleanup */ 576 mutex_enter(&conn->c_lock); 577 cv_broadcast(&conn->c_conn_cv); 578 mutex_exit(&conn->c_lock); 579 580 DEBC(conn, 5, ("kill_connection returns\n")); 581 } 582 583 584 /* 585 * kill_session: 586 * Terminate the session as gracefully as possible. 587 * 588 * Parameter: 589 * session Session to terminate 590 * status The status code for the termination 591 * logout The logout reason code 592 593 */ 594 595 void 596 kill_session(uint32_t sid, uint32_t status, int logout, bool recover) 597 { 598 session_t *sess; 599 connection_t *conn; 600 601 DEB(1, ("ISCSI: kill_session %d, status %d, logout %d, recover %d\n", 602 sid, status, logout, recover)); 603 604 mutex_enter(&iscsi_cleanup_mtx); 605 606 sess = find_session(sid); 607 if (sess == NULL) { 608 mutex_exit(&iscsi_cleanup_mtx); 609 610 DEB(5, ("Session %u already gone\n", sid)); 611 return; 612 } 613 614 if (sess->s_terminating) { 615 mutex_exit(&iscsi_cleanup_mtx); 616 617 DEB(5, ("Session is being killed with status %d\n",sess->s_terminating)); 618 return; 619 } 620 621 /* 622 * don't do anything if session isn't established yet, termination will be 623 * handled elsewhere 624 */ 625 if (sess->s_sessions.tqe_next == NULL && sess->s_sessions.tqe_prev == NULL) { 626 mutex_exit(&iscsi_cleanup_mtx); 627 628 DEB(5, ("Session is being killed which is not yet established\n")); 629 return; 630 } 631 632 if (recover) { 633 mutex_exit(&iscsi_cleanup_mtx); 634 635 /* 636 * Only recover when there's just one active connection left. 637 * Otherwise we get in all sorts of timing problems, and it doesn't 638 * make much sense anyway to recover when the other side has 639 * requested that we kill a multipathed session. 640 */ 641 if (sess->s_active_connections == 1) { 642 conn = assign_connection(sess, FALSE); 643 if (conn != NULL) 644 kill_connection(conn, status, logout, TRUE); 645 } 646 return; 647 } 648 649 if (sess->s_refcount > 0) { 650 mutex_exit(&iscsi_cleanup_mtx); 651 652 DEB(5, ("Session is being killed while in use (refcnt = %d)\n", 653 sess->s_refcount)); 654 return; 655 } 656 657 /* Remove session from global list */ 658 sess->s_terminating = status; 659 TAILQ_REMOVE(&iscsi_sessions, sess, s_sessions); 660 sess->s_sessions.tqe_next = NULL; 661 sess->s_sessions.tqe_prev = NULL; 662 663 /* 664 * If all connections are already gone, trigger cleanup 665 * otherwise, the last connection will do this 666 */ 667 if (sess->s_active_connections == 0) 668 iscsi_notify_cleanup(); 669 670 mutex_exit(&iscsi_cleanup_mtx); 671 672 /* kill all connections */ 673 while ((conn = TAILQ_FIRST(&sess->s_conn_list)) != NULL) { 674 kill_connection(conn, status, logout, FALSE); 675 logout = NO_LOGOUT; 676 } 677 } 678 679 680 /* 681 * create_connection: 682 * Create and init the necessary framework for a connection: 683 * Take over userland socket 684 * Alloc the connection structure itself 685 * Copy connection parameters 686 * Create the send and receive threads 687 * And finally, log in. 688 * 689 * Parameter: 690 * par IN/OUT: The login parameters 691 * session IN: The owning session 692 * l IN: The lwp pointer of the caller 693 * 694 * Returns: 0 on success 695 * >0 on failure, connection structure deleted 696 * <0 on failure, connection is still terminating 697 */ 698 699 static int 700 create_connection(iscsi_login_parameters_t *par, session_t *sess, 701 struct lwp *l) 702 { 703 connection_t *conn; 704 int rc; 705 706 DEB(1, ("Create Connection for Session %d\n", sess->s_id)); 707 708 if (sess->s_MaxConnections && 709 sess->s_active_connections >= sess->s_MaxConnections) { 710 DEBOUT(("Too many connections (max = %d, curr = %d)\n", 711 sess->s_MaxConnections, sess->s_active_connections)); 712 /* Always close descriptor */ 713 fd_close(par->socket); 714 715 par->status = ISCSI_STATUS_MAXED_CONNECTIONS; 716 return EIO; 717 } 718 719 conn = malloc(sizeof(*conn), M_DEVBUF, M_WAITOK | M_ZERO); 720 if (conn == NULL) { 721 DEBOUT(("No mem for connection\n")); 722 723 /* Always close descriptor */ 724 fd_close(par->socket); 725 726 par->status = ISCSI_STATUS_NO_RESOURCES; 727 return EIO; 728 } 729 730 rc = get_socket(par->socket, &conn->c_sock); 731 if (rc != EBADF) 732 fd_close(par->socket); 733 734 if (rc) { 735 DEBOUT(("Invalid socket %d\n", par->socket)); 736 free(conn, M_DEVBUF); 737 par->status = ISCSI_STATUS_INVALID_SOCKET; 738 return rc; 739 } 740 741 DEBC(conn, 1, ("get_socket: par_sock=%d, fdesc=%p\n", 742 par->socket, conn->c_sock)); 743 744 mutex_enter(&iscsi_cleanup_mtx); 745 /* create a unique ID */ 746 do { 747 ++sess->s_conn_id; 748 } while (!sess->s_conn_id || 749 find_connection(sess, sess->s_conn_id) != NULL); 750 par->connection_id = conn->c_id = sess->s_conn_id; 751 mutex_exit(&iscsi_cleanup_mtx); 752 DEB(99, ("Connection ID = %d\n", conn->c_id)); 753 754 conn->c_session = sess; 755 756 TAILQ_INIT(&conn->c_ccbs_waiting); 757 TAILQ_INIT(&conn->c_pdus_to_send); 758 TAILQ_INIT(&conn->c_pdu_pool); 759 760 mutex_init(&conn->c_lock, MUTEX_DEFAULT, IPL_BIO); 761 cv_init(&conn->c_conn_cv, "conn"); 762 cv_init(&conn->c_pdu_cv, "pdupool"); 763 cv_init(&conn->c_ccb_cv, "ccbwait"); 764 cv_init(&conn->c_idle_cv, "idle"); 765 rw_init(&conn->c_sock_rw); 766 767 callout_init(&conn->c_timeout, CALLOUT_MPSAFE); 768 callout_setfunc(&conn->c_timeout, connection_timeout_co, conn); 769 conn->c_idle_timeout_val = CONNECTION_IDLE_TIMEOUT; 770 771 init_sernum(&conn->c_StatSN_buf); 772 create_pdus(conn); 773 774 conn->c_threadobj = l; 775 conn->c_login_par = par; 776 777 DEB(5, ("Creating receive thread\n")); 778 if ((rc = kthread_create(PRI_BIO, KTHREAD_MPSAFE, NULL, iscsi_rcv_thread, 779 conn, &conn->c_rcvproc, 780 "ConnRcv")) != 0) { 781 DEBOUT(("Can't create rcv thread (rc %d)\n", rc)); 782 783 release_socket(conn->c_sock); 784 rw_destroy(&conn->c_sock_rw); 785 callout_destroy(&conn->c_timeout); 786 cv_destroy(&conn->c_idle_cv); 787 cv_destroy(&conn->c_ccb_cv); 788 cv_destroy(&conn->c_pdu_cv); 789 cv_destroy(&conn->c_conn_cv); 790 mutex_destroy(&conn->c_lock); 791 free(conn, M_DEVBUF); 792 par->status = ISCSI_STATUS_NO_RESOURCES; 793 return rc; 794 } 795 DEB(5, ("Creating send thread\n")); 796 if ((rc = kthread_create(PRI_BIO, KTHREAD_MPSAFE, NULL, iscsi_send_thread, 797 conn, &conn->c_sendproc, 798 "ConnSend")) != 0) { 799 DEBOUT(("Can't create send thread (rc %d)\n", rc)); 800 801 conn->c_terminating = ISCSI_STATUS_NO_RESOURCES; 802 803 /* 804 * We must close the socket here to force the receive 805 * thread to wake up 806 */ 807 DEBC(conn, 1, ("Closing Socket %p\n", conn->c_sock)); 808 mutex_enter(&conn->c_sock->f_lock); 809 conn->c_sock->f_count += 1; 810 mutex_exit(&conn->c_sock->f_lock); 811 closef(conn->c_sock); 812 813 /* give receive thread time to exit */ 814 kpause("settle", false, 2 * hz, NULL); 815 816 release_socket(conn->c_sock); 817 callout_destroy(&conn->c_timeout); 818 rw_destroy(&conn->c_sock_rw); 819 cv_destroy(&conn->c_idle_cv); 820 cv_destroy(&conn->c_ccb_cv); 821 cv_destroy(&conn->c_pdu_cv); 822 cv_destroy(&conn->c_conn_cv); 823 mutex_destroy(&conn->c_lock); 824 free(conn, M_DEVBUF); 825 par->status = ISCSI_STATUS_NO_RESOURCES; 826 return rc; 827 } 828 829 /* 830 * At this point, each thread will tie 'sock' into its own file descriptor 831 * tables w/o increasing the use count - they will inherit the use 832 * increments performed in get_socket(). 833 */ 834 835 if ((rc = send_login(conn)) != 0) { 836 DEBC(conn, 0, ("Login failed (rc %d)\n", rc)); 837 /* Don't attempt to recover, there seems to be something amiss */ 838 kill_connection(conn, rc, NO_LOGOUT, FALSE); 839 par->status = rc; 840 return -1; 841 } 842 843 mutex_enter(&iscsi_cleanup_mtx); 844 if (sess->s_terminating) { 845 mutex_exit(&iscsi_cleanup_mtx); 846 DEBC(conn, 0, ("Session terminating\n")); 847 kill_connection(conn, rc, NO_LOGOUT, FALSE); 848 par->status = sess->s_terminating; 849 return -1; 850 } 851 conn->c_state = ST_FULL_FEATURE; 852 TAILQ_INSERT_TAIL(&sess->s_conn_list, conn, c_connections); 853 conn->c_in_session = TRUE; 854 sess->s_total_connections++; 855 sess->s_active_connections++; 856 sess->s_mru_connection = conn; 857 mutex_exit(&iscsi_cleanup_mtx); 858 859 DEBC(conn, 5, ("Connection created successfully!\n")); 860 return 0; 861 } 862 863 864 /* 865 * recreate_connection: 866 * Revive dead connection 867 * 868 * Parameter: 869 * par IN/OUT: The login parameters 870 * conn IN: The connection 871 * l IN: The lwp pointer of the caller 872 * 873 * Returns: 0 on success 874 * >0 on failure, connection structure deleted 875 * <0 on failure, connection is still terminating 876 */ 877 878 static int 879 recreate_connection(iscsi_login_parameters_t *par, session_t *sess, 880 connection_t *conn, struct lwp *l) 881 { 882 int rc; 883 ccb_t *ccb; 884 ccb_list_t old_waiting; 885 pdu_t *pdu; 886 uint32_t sn; 887 888 DEB(1, ("ReCreate Connection %d for Session %d, ERL=%d\n", 889 conn->c_id, conn->c_session->s_id, 890 conn->c_session->s_ErrorRecoveryLevel)); 891 892 if (sess->s_MaxConnections && 893 sess->s_active_connections >= sess->s_MaxConnections) { 894 DEBOUT(("Too many connections (max = %d, curr = %d)\n", 895 sess->s_MaxConnections, sess->s_active_connections)); 896 897 /* Close the desecriptor */ 898 rc = EIO; 899 if (fd_getfile(par->socket) != NULL) 900 rc = fd_close(par->socket); 901 902 par->status = ISCSI_STATUS_MAXED_CONNECTIONS; 903 return rc; 904 } 905 906 rw_enter(&conn->c_sock_rw, RW_WRITER); 907 if (conn->c_sock != NULL) { 908 closef(conn->c_sock); 909 conn->c_sock = NULL; 910 } 911 rc = get_socket(par->socket, &conn->c_sock); 912 rw_exit(&conn->c_sock_rw); 913 if (rc != EBADF) 914 fd_close(par->socket); 915 916 if (rc) { 917 DEBOUT(("Invalid socket %d\n", par->socket)); 918 par->status = ISCSI_STATUS_INVALID_SOCKET; 919 return rc; 920 } 921 922 DEBC(conn, 1, ("get_socket: par_sock=%d, fdesc=%p\n", 923 par->socket, conn->c_sock)); 924 925 conn->c_threadobj = l; 926 conn->c_login_par = par; 927 conn->c_terminating = ISCSI_STATUS_SUCCESS; 928 conn->c_recover++; 929 conn->c_num_timeouts = 0; 930 conn->c_state = ST_SEC_NEG; 931 conn->c_HeaderDigest = 0; 932 conn->c_DataDigest = 0; 933 934 sess->s_active_connections++; 935 936 TAILQ_INIT(&old_waiting); 937 938 mutex_enter(&conn->c_lock); 939 while ((ccb = TAILQ_FIRST(&conn->c_ccbs_waiting)) != NULL) { 940 suspend_ccb(ccb, FALSE); 941 TAILQ_INSERT_TAIL(&old_waiting, ccb, ccb_chain); 942 } 943 init_sernum(&conn->c_StatSN_buf); 944 cv_broadcast(&conn->c_idle_cv); 945 mutex_exit(&conn->c_lock); 946 947 if ((rc = send_login(conn)) != 0) { 948 DEBC(conn, 0, ("Re-Login failed (rc %d)\n", rc)); 949 while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) { 950 TAILQ_REMOVE(&old_waiting, ccb, ccb_chain); 951 wake_ccb(ccb, rc); 952 } 953 /* Don't attempt to recover, there seems to be something amiss */ 954 kill_connection(conn, rc, NO_LOGOUT, FALSE); 955 par->status = rc; 956 return -1; 957 } 958 959 DEBC(conn, 9, ("Re-Login successful\n")); 960 par->status = ISCSI_STATUS_SUCCESS; 961 962 conn->c_state = ST_FULL_FEATURE; 963 sess->s_mru_connection = conn; 964 965 while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) { 966 TAILQ_REMOVE(&old_waiting, ccb, ccb_chain); 967 mutex_enter(&conn->c_lock); 968 suspend_ccb(ccb, TRUE); 969 mutex_exit(&conn->c_lock); 970 971 rc = send_task_management(conn, ccb, NULL, TASK_REASSIGN); 972 /* if we get an error on reassign, restart the original request */ 973 if (rc && ccb->ccb_pdu_waiting != NULL) { 974 mutex_enter(&sess->s_lock); 975 if (sn_a_lt_b(ccb->ccb_CmdSN, sess->s_ExpCmdSN)) { 976 pdu = ccb->ccb_pdu_waiting; 977 sn = get_sernum(sess, pdu); 978 979 /* update CmdSN */ 980 DEBC(conn, 0, ("Resend ccb %p (%d) - updating CmdSN old %u, new %u\n", 981 ccb, rc, ccb->ccb_CmdSN, sn)); 982 ccb->ccb_CmdSN = sn; 983 pdu->pdu_hdr.pduh_p.command.CmdSN = htonl(ccb->ccb_CmdSN); 984 } else { 985 DEBC(conn, 0, ("Resend ccb %p (%d) - CmdSN %u\n", 986 ccb, rc, ccb->ccb_CmdSN)); 987 } 988 mutex_exit(&sess->s_lock); 989 resend_pdu(ccb); 990 } else { 991 DEBC(conn, 0, ("Resend ccb %p (%d) CmdSN %u - reassigned\n", 992 ccb, rc, ccb->ccb_CmdSN)); 993 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 994 } 995 } 996 997 mutex_enter(&sess->s_lock); 998 cv_broadcast(&sess->s_sess_cv); 999 mutex_exit(&sess->s_lock); 1000 1001 DEBC(conn, 0, ("Connection ReCreated successfully - status %d\n", 1002 par->status)); 1003 1004 return 0; 1005 } 1006 1007 /* -------------------------------------------------------------------------- */ 1008 1009 /* 1010 * check_login_pars: 1011 * Check the parameters passed into login/add_connection 1012 * for validity and consistency. 1013 * 1014 * Parameter: 1015 * par The login parameters 1016 * 1017 * Returns: 0 on success, else an error code. 1018 */ 1019 1020 static int 1021 check_login_pars(iscsi_login_parameters_t *par) 1022 { 1023 int i, n; 1024 1025 if (par->is_present.auth_info) { 1026 /* check consistency of authentication parameters */ 1027 1028 if (par->auth_info.auth_number > ISCSI_AUTH_OPTIONS) { 1029 DEBOUT(("Auth number invalid: %d\n", par->auth_info.auth_number)); 1030 return ISCSI_STATUS_PARAMETER_INVALID; 1031 } 1032 1033 if (par->auth_info.auth_number > 2) { 1034 DEBOUT(("Auth number invalid: %d\n", par->auth_info.auth_number)); 1035 return ISCSI_STATUS_NOTIMPL; 1036 } 1037 1038 for (i = 0, n = 0; i < par->auth_info.auth_number; i++) { 1039 #if 0 1040 if (par->auth_info.auth_type[i] < ISCSI_AUTH_None) { 1041 DEBOUT(("Auth type invalid: %d\n", 1042 par->auth_info.auth_type[i])); 1043 return ISCSI_STATUS_PARAMETER_INVALID; 1044 } 1045 #endif 1046 if (par->auth_info.auth_type[i] > ISCSI_AUTH_CHAP) { 1047 DEBOUT(("Auth type invalid: %d\n", 1048 par->auth_info.auth_type[i])); 1049 return ISCSI_STATUS_NOTIMPL; 1050 } 1051 n = max(n, par->auth_info.auth_type[i]); 1052 } 1053 if (n) { 1054 if (!par->is_present.password || 1055 (par->auth_info.mutual_auth && 1056 !par->is_present.target_password)) { 1057 DEBOUT(("Password missing\n")); 1058 return ISCSI_STATUS_PARAMETER_MISSING; 1059 } 1060 /* Note: Default for user-name is initiator name */ 1061 } 1062 } 1063 if (par->login_type != ISCSI_LOGINTYPE_DISCOVERY && 1064 !par->is_present.TargetName) { 1065 DEBOUT(("Target name missing, login type %d\n", par->login_type)); 1066 return ISCSI_STATUS_PARAMETER_MISSING; 1067 } 1068 if (par->is_present.MaxRecvDataSegmentLength) { 1069 if (par->MaxRecvDataSegmentLength < 512 || 1070 par->MaxRecvDataSegmentLength > 0xffffff) { 1071 DEBOUT(("MaxRecvDataSegmentLength invalid: %d\n", 1072 par->MaxRecvDataSegmentLength)); 1073 return ISCSI_STATUS_PARAMETER_INVALID; 1074 } 1075 } 1076 return 0; 1077 } 1078 1079 1080 /* 1081 * login: 1082 * Handle the login ioctl - Create a session: 1083 * Alloc the session structure 1084 * Copy session parameters 1085 * And call create_connection to establish the connection. 1086 * 1087 * Parameter: 1088 * par IN/OUT: The login parameters 1089 * l IN: The lwp pointer of the caller 1090 */ 1091 1092 static void 1093 login(iscsi_login_parameters_t *par, struct lwp *l, device_t dev) 1094 { 1095 session_t *sess; 1096 int rc; 1097 1098 DEB(99, ("ISCSI: login\n")); 1099 1100 if (!iscsi_InitiatorName[0]) { 1101 DEB(1, ("No Initiator Name\n")); 1102 par->status = ISCSI_STATUS_NO_INITIATOR_NAME; 1103 return; 1104 } 1105 1106 if ((par->status = check_login_pars(par)) != 0) 1107 return; 1108 1109 /* alloc the session */ 1110 sess = malloc(sizeof(*sess), M_DEVBUF, M_WAITOK | M_ZERO); 1111 if (sess == NULL) { 1112 DEBOUT(("No mem for session\n")); 1113 par->status = ISCSI_STATUS_NO_RESOURCES; 1114 return; 1115 } 1116 TAILQ_INIT(&sess->s_conn_list); 1117 TAILQ_INIT(&sess->s_ccb_pool); 1118 1119 mutex_init(&sess->s_lock, MUTEX_DEFAULT, IPL_BIO); 1120 cv_init(&sess->s_sess_cv, "session"); 1121 cv_init(&sess->s_ccb_cv, "ccb"); 1122 1123 mutex_enter(&iscsi_cleanup_mtx); 1124 /* create a unique ID */ 1125 do { 1126 ++current_id; 1127 } while (!current_id || find_session(current_id) != NULL); 1128 par->session_id = sess->s_id = current_id; 1129 mutex_exit(&iscsi_cleanup_mtx); 1130 1131 create_ccbs(sess); 1132 sess->s_login_type = par->login_type; 1133 sess->s_CmdSN = 1; 1134 1135 if ((rc = create_connection(par, sess, l)) != 0) { 1136 if (rc > 0) { 1137 destroy_ccbs(sess); 1138 cv_destroy(&sess->s_ccb_cv); 1139 cv_destroy(&sess->s_sess_cv); 1140 mutex_destroy(&sess->s_lock); 1141 free(sess, M_DEVBUF); 1142 } 1143 return; 1144 } 1145 1146 mutex_enter(&iscsi_cleanup_mtx); 1147 TAILQ_INSERT_HEAD(&iscsi_sessions, sess, s_sessions); 1148 mutex_exit(&iscsi_cleanup_mtx); 1149 1150 /* Session established, map LUNs? */ 1151 if (par->login_type == ISCSI_LOGINTYPE_MAP) { 1152 copyinstr(par->TargetName, sess->s_tgtname, 1153 sizeof(sess->s_tgtname), NULL); 1154 DEB(1, ("Login: map session %d\n", sess->s_id)); 1155 if (!map_session(sess, dev)) { 1156 DEB(1, ("Login: map session %d failed\n", sess->s_id)); 1157 kill_session(par->session_id, ISCSI_STATUS_MAP_FAILED, 1158 LOGOUT_SESSION, FALSE); 1159 par->status = ISCSI_STATUS_MAP_FAILED; 1160 return; 1161 } 1162 } 1163 } 1164 1165 1166 /* 1167 * logout: 1168 * Handle the logout ioctl - Kill a session. 1169 * 1170 * Parameter: 1171 * par IN/OUT: The login parameters 1172 */ 1173 1174 static void 1175 logout(iscsi_logout_parameters_t *par) 1176 { 1177 session_t *session; 1178 1179 DEB(5, ("ISCSI: logout session %d\n", par->session_id)); 1180 1181 mutex_enter(&iscsi_cleanup_mtx); 1182 if ((session = find_session(par->session_id)) == NULL) { 1183 mutex_exit(&iscsi_cleanup_mtx); 1184 DEBOUT(("Session %d not found\n", par->session_id)); 1185 par->status = ISCSI_STATUS_INVALID_SESSION_ID; 1186 return; 1187 } 1188 mutex_exit(&iscsi_cleanup_mtx); 1189 /* If the session exists, this always succeeds */ 1190 par->status = ISCSI_STATUS_SUCCESS; 1191 1192 kill_session(par->session_id, 1193 ISCSI_STATUS_LOGOUT, LOGOUT_SESSION, 1194 FALSE); 1195 } 1196 1197 1198 /* 1199 * add_connection: 1200 * Handle the add_connection ioctl. 1201 * 1202 * Parameter: 1203 * par IN/OUT: The login parameters 1204 * l IN: The lwp pointer of the caller 1205 */ 1206 1207 static int 1208 add_connection(iscsi_login_parameters_t *par, struct lwp *l) 1209 { 1210 session_t *session; 1211 1212 DEB(5, ("ISCSI: add_connection to session %d\n", par->session_id)); 1213 1214 mutex_enter(&iscsi_cleanup_mtx); 1215 if ((session = find_session(par->session_id)) == NULL) { 1216 mutex_exit(&iscsi_cleanup_mtx); 1217 DEBOUT(("Session %d not found\n", par->session_id)); 1218 par->status = ISCSI_STATUS_INVALID_SESSION_ID; 1219 return -1; 1220 } 1221 mutex_exit(&iscsi_cleanup_mtx); 1222 1223 par->status = check_login_pars(par); 1224 if (par->status) 1225 return -1; 1226 1227 return create_connection(par, session, l); 1228 } 1229 1230 1231 /* 1232 * remove_connection: 1233 * Handle the remove_connection ioctl. 1234 * 1235 * Parameter: 1236 * par IN/OUT: The remove parameters 1237 */ 1238 1239 static void 1240 remove_connection(iscsi_remove_parameters_t *par) 1241 { 1242 connection_t *conn; 1243 session_t *session; 1244 1245 DEB(5, ("ISCSI: remove_connection %d from session %d\n", 1246 par->connection_id, par->session_id)); 1247 1248 mutex_enter(&iscsi_cleanup_mtx); 1249 if ((session = find_session(par->session_id)) == NULL) { 1250 mutex_exit(&iscsi_cleanup_mtx); 1251 DEBOUT(("Session %d not found\n", par->session_id)); 1252 par->status = ISCSI_STATUS_INVALID_SESSION_ID; 1253 return; 1254 } 1255 1256 if ((conn = find_connection(session, par->connection_id)) == NULL) { 1257 mutex_exit(&iscsi_cleanup_mtx); 1258 DEBOUT(("Connection %d not found in session %d\n", 1259 par->connection_id, par->session_id)); 1260 1261 par->status = ISCSI_STATUS_INVALID_CONNECTION_ID; 1262 } else { 1263 mutex_exit(&iscsi_cleanup_mtx); 1264 kill_connection(conn, ISCSI_STATUS_LOGOUT, LOGOUT_CONNECTION, 1265 FALSE); 1266 par->status = ISCSI_STATUS_SUCCESS; 1267 } 1268 } 1269 1270 1271 /* 1272 * restore_connection: 1273 * Handle the restore_connection ioctl. 1274 * 1275 * Parameter: 1276 * par IN/OUT: The login parameters 1277 * l IN: The lwp pointer of the caller 1278 */ 1279 1280 static void 1281 restore_connection(iscsi_login_parameters_t *par, struct lwp *l) 1282 { 1283 session_t *sess; 1284 connection_t *conn; 1285 1286 DEB(1, ("ISCSI: restore_connection %d of session %d\n", 1287 par->connection_id, par->session_id)); 1288 1289 mutex_enter(&iscsi_cleanup_mtx); 1290 if ((sess = find_session(par->session_id)) == NULL) { 1291 mutex_exit(&iscsi_cleanup_mtx); 1292 DEBOUT(("Session %d not found\n", par->session_id)); 1293 par->status = ISCSI_STATUS_INVALID_SESSION_ID; 1294 return; 1295 } 1296 if ((conn = find_connection(sess, par->connection_id)) == NULL) { 1297 mutex_exit(&iscsi_cleanup_mtx); 1298 DEBOUT(("Connection %d not found in session %d\n", 1299 par->connection_id, par->session_id)); 1300 par->status = ISCSI_STATUS_INVALID_CONNECTION_ID; 1301 return; 1302 } 1303 if (!conn->c_terminating) { 1304 mutex_exit(&iscsi_cleanup_mtx); 1305 DEBC(conn, 0, ("Connection is alive\n")); 1306 par->status = ISCSI_STATUS_SUCCESS; 1307 return; 1308 } 1309 mutex_exit(&iscsi_cleanup_mtx); 1310 1311 if ((par->status = check_login_pars(par)) == 0) { 1312 recreate_connection(par, sess, conn, l); 1313 } 1314 } 1315 1316 1317 #ifndef ISCSI_MINIMAL 1318 1319 /* 1320 * io_command: 1321 * Handle the io_command ioctl. 1322 * 1323 * Parameter: 1324 * par IN/OUT: The iocommand parameters 1325 * l IN: The lwp pointer of the caller 1326 */ 1327 1328 static void 1329 io_command(iscsi_iocommand_parameters_t *par, struct lwp *l) 1330 { 1331 uint32_t datalen = par->req.datalen; 1332 session_t *session; 1333 void *kbuf = NULL; 1334 int error; 1335 1336 DEB(9, ("ISCSI: io_command, SID=%d, lun=%" PRIu64 "\n", par->session_id, par->lun)); 1337 mutex_enter(&iscsi_cleanup_mtx); 1338 if ((session = find_session(par->session_id)) == NULL) { 1339 mutex_exit(&iscsi_cleanup_mtx); 1340 DEBOUT(("Session %d not found\n", par->session_id)); 1341 par->status = ISCSI_STATUS_INVALID_SESSION_ID; 1342 return; 1343 } 1344 mutex_exit(&iscsi_cleanup_mtx); 1345 1346 par->req.senselen_used = 0; 1347 par->req.datalen_used = 0; 1348 par->req.error = 0; 1349 par->req.status = 0; 1350 par->req.retsts = SCCMD_UNKNOWN; /* init to failure code */ 1351 1352 if (par->req.cmdlen > 16 || par->req.senselen > sizeof(par->req.sense)) { 1353 par->status = ISCSI_STATUS_PARAMETER_INVALID; 1354 return; 1355 } 1356 1357 if (datalen) { 1358 /* Arbitrarily limit datalen to 8k. */ 1359 if (datalen > 8192) { 1360 par->status = ISCSI_STATUS_PARAMETER_INVALID; 1361 return; 1362 } 1363 kbuf = kmem_zalloc(datalen, KM_SLEEP); 1364 if ((par->req.flags & SCCMD_WRITE) != 0) { 1365 error = copyin(par->req.databuf, kbuf, datalen); 1366 if (error) { 1367 kmem_free(kbuf, datalen); 1368 par->status = ISCSI_STATUS_PARAMETER_INVALID; 1369 return; 1370 } 1371 } 1372 } 1373 par->status = send_io_command(session, par->lun, &par->req, 1374 par->options.immediate, par->connection_id); 1375 1376 if (kbuf) { 1377 if ((par->req.flags & SCCMD_READ) != 0) { 1378 (void) copyout(kbuf, par->req.databuf, datalen); 1379 } 1380 kmem_free(kbuf, datalen); 1381 } 1382 switch (par->status) { 1383 case ISCSI_STATUS_SUCCESS: 1384 par->req.retsts = SCCMD_OK; 1385 break; 1386 1387 case ISCSI_STATUS_TARGET_BUSY: 1388 par->req.retsts = SCCMD_BUSY; 1389 break; 1390 1391 case ISCSI_STATUS_TIMEOUT: 1392 case ISCSI_STATUS_SOCKET_ERROR: 1393 par->req.retsts = SCCMD_TIMEOUT; 1394 break; 1395 1396 default: 1397 par->req.retsts = (par->req.senselen_used) ? SCCMD_SENSE 1398 : SCCMD_UNKNOWN; 1399 break; 1400 } 1401 } 1402 #endif 1403 1404 /* 1405 * send_targets: 1406 * Handle the send_targets ioctl. 1407 * Note: If the passed buffer is too small to hold the complete response, 1408 * the response is kept in the session structure so it can be 1409 * retrieved with the next call to this function without having to go to 1410 * the target again. Once the complete response has been retrieved, it 1411 * is discarded. 1412 * 1413 * Parameter: 1414 * par IN/OUT: The send_targets parameters 1415 */ 1416 1417 static void 1418 send_targets(iscsi_send_targets_parameters_t *par) 1419 { 1420 int rc; 1421 uint32_t rlen, cplen; 1422 session_t *sess; 1423 1424 mutex_enter(&iscsi_cleanup_mtx); 1425 if ((sess = find_session(par->session_id)) == NULL) { 1426 mutex_exit(&iscsi_cleanup_mtx); 1427 DEBOUT(("Session %d not found\n", par->session_id)); 1428 par->status = ISCSI_STATUS_INVALID_SESSION_ID; 1429 return; 1430 } 1431 mutex_exit(&iscsi_cleanup_mtx); 1432 1433 DEB(9, ("ISCSI: send_targets, rsp_size=%d; Saved list: %p\n", 1434 par->response_size, sess->s_target_list)); 1435 1436 if (sess->s_target_list == NULL) { 1437 rc = send_send_targets(sess, par->key); 1438 if (rc) { 1439 par->status = rc; 1440 return; 1441 } 1442 } 1443 rlen = sess->s_target_list_len; 1444 par->response_total = rlen; 1445 cplen = min(par->response_size, rlen); 1446 if (cplen) { 1447 copyout(sess->s_target_list, par->response_buffer, cplen); 1448 } 1449 par->response_used = cplen; 1450 1451 /* If all of the response was copied, don't keep it around */ 1452 if (rlen && par->response_used == rlen) { 1453 free(sess->s_target_list, M_TEMP); 1454 sess->s_target_list = NULL; 1455 } 1456 1457 par->status = ISCSI_STATUS_SUCCESS; 1458 } 1459 1460 1461 /* 1462 * set_node_name: 1463 * Handle the set_node_name ioctl. 1464 * 1465 * Parameter: 1466 * par IN/OUT: The set_node_name parameters 1467 */ 1468 1469 static void 1470 set_node_name(iscsi_set_node_name_parameters_t *par) 1471 { 1472 1473 if (strlen(par->InitiatorName) >= ISCSI_STRING_LENGTH || 1474 strlen(par->InitiatorAlias) >= ISCSI_STRING_LENGTH) { 1475 DEBOUT(("*** set_node_name string too long!\n")); 1476 par->status = ISCSI_STATUS_PARAMETER_INVALID; 1477 return; 1478 } 1479 strlcpy(iscsi_InitiatorName, par->InitiatorName, sizeof(iscsi_InitiatorName)); 1480 strlcpy(iscsi_InitiatorAlias, par->InitiatorAlias, sizeof(iscsi_InitiatorAlias)); 1481 memcpy(&iscsi_InitiatorISID, par->ISID, 6); 1482 DEB(5, ("ISCSI: set_node_name, ISID A=%x, B=%x, C=%x, D=%x\n", 1483 iscsi_InitiatorISID.ISID_A, iscsi_InitiatorISID.ISID_B, 1484 iscsi_InitiatorISID.ISID_C, iscsi_InitiatorISID.ISID_D)); 1485 1486 if (!iscsi_InitiatorISID.ISID_A && !iscsi_InitiatorISID.ISID_B && 1487 !iscsi_InitiatorISID.ISID_C && !iscsi_InitiatorISID.ISID_D) { 1488 iscsi_InitiatorISID.ISID_A = T_FORMAT_EN; 1489 iscsi_InitiatorISID.ISID_B = htons(0x1); 1490 iscsi_InitiatorISID.ISID_C = 0x37; 1491 iscsi_InitiatorISID.ISID_D = 0; 1492 } 1493 1494 par->status = ISCSI_STATUS_SUCCESS; 1495 } 1496 1497 1498 /* 1499 * connection_status: 1500 * Handle the connection_status ioctl. 1501 * 1502 * Parameter: 1503 * par IN/OUT: The status parameters 1504 */ 1505 1506 static void 1507 connection_status(iscsi_conn_status_parameters_t *par) 1508 { 1509 connection_t *conn; 1510 session_t *sess; 1511 1512 mutex_enter(&iscsi_cleanup_mtx); 1513 if ((sess = find_session(par->session_id)) == NULL) { 1514 mutex_exit(&iscsi_cleanup_mtx); 1515 par->status = ISCSI_STATUS_INVALID_SESSION_ID; 1516 return; 1517 } 1518 1519 if (par->connection_id) { 1520 conn = find_connection(sess, par->connection_id); 1521 } else { 1522 conn = TAILQ_FIRST(&sess->s_conn_list); 1523 } 1524 par->status = (conn == NULL) ? ISCSI_STATUS_INVALID_CONNECTION_ID : 1525 ISCSI_STATUS_SUCCESS; 1526 mutex_exit(&iscsi_cleanup_mtx); 1527 DEB(9, ("ISCSI: connection_status, session %d connection %d --> %d\n", 1528 par->session_id, par->connection_id, par->status)); 1529 } 1530 1531 1532 /* 1533 * get_version: 1534 * Handle the get_version ioctl. 1535 * 1536 * Parameter: 1537 * par IN/OUT: The version parameters 1538 */ 1539 1540 static void 1541 get_version(iscsi_get_version_parameters_t *par) 1542 { 1543 par->status = ISCSI_STATUS_SUCCESS; 1544 par->interface_version = INTERFACE_VERSION; 1545 par->major = VERSION_MAJOR; 1546 par->minor = VERSION_MINOR; 1547 strlcpy(par->version_string, VERSION_STRING, 1548 sizeof(par->version_string)); 1549 } 1550 1551 1552 /* -------------------------------------------------------------------- */ 1553 1554 /* 1555 * kill_all_sessions: 1556 * Terminate all sessions (called when the driver unloads). 1557 */ 1558 1559 int 1560 kill_all_sessions(void) 1561 { 1562 session_t *sess; 1563 int rc = 0; 1564 uint32_t sid; 1565 1566 mutex_enter(&iscsi_cleanup_mtx); 1567 while ((sess = TAILQ_FIRST(&iscsi_sessions)) != NULL) { 1568 sid = sess->s_id; 1569 mutex_exit(&iscsi_cleanup_mtx); 1570 kill_session(sid, ISCSI_STATUS_DRIVER_UNLOAD, LOGOUT_SESSION, 1571 FALSE); 1572 mutex_enter(&iscsi_cleanup_mtx); 1573 } 1574 if (TAILQ_FIRST(&iscsi_sessions) != NULL) { 1575 DEBOUT(("Failed to kill all sessions\n")); 1576 rc = EBUSY; 1577 } 1578 mutex_exit(&iscsi_cleanup_mtx); 1579 1580 return rc; 1581 } 1582 1583 /* 1584 * handle_connection_error: 1585 * Deal with a problem during send or receive. 1586 * 1587 * Parameter: 1588 * conn The connection the problem is associated with 1589 * status The status code to insert into any unfinished CCBs 1590 * dologout Whether Logout should be attempted 1591 */ 1592 1593 void 1594 handle_connection_error(connection_t *conn, uint32_t status, int dologout) 1595 { 1596 DEBC(conn, 0, ("*** Connection Error, status=%d, logout=%d, state=%d\n", 1597 status, dologout, conn->c_state)); 1598 1599 if (!conn->c_terminating && conn->c_state <= ST_LOGOUT_SENT) { 1600 /* if we get an error while winding down, escalate it */ 1601 if (dologout >= 0 && conn->c_state >= ST_WINDING_DOWN) { 1602 dologout = NO_LOGOUT; 1603 } 1604 kill_connection(conn, status, dologout, TRUE); 1605 } 1606 } 1607 1608 /* 1609 * remove a connection from session and add to the cleanup list 1610 */ 1611 void 1612 add_connection_cleanup(connection_t *conn) 1613 { 1614 session_t *sess = NULL; 1615 1616 mutex_enter(&iscsi_cleanup_mtx); 1617 if (conn->c_in_session) { 1618 sess = conn->c_session; 1619 conn->c_in_session = FALSE; 1620 conn->c_session = NULL; 1621 TAILQ_REMOVE(&sess->s_conn_list, conn, c_connections); 1622 sess->s_mru_connection = TAILQ_FIRST(&sess->s_conn_list); 1623 } 1624 TAILQ_INSERT_TAIL(&iscsi_cleanupc_list, conn, c_connections); 1625 iscsi_notify_cleanup(); 1626 mutex_exit(&iscsi_cleanup_mtx); 1627 } 1628 1629 /* 1630 * callout wrappers for timeouts, the work is done by the cleanup thread 1631 */ 1632 void 1633 connection_timeout_co(void *par) 1634 { 1635 connection_t *conn = par; 1636 1637 mutex_enter(&iscsi_cleanup_mtx); 1638 conn->c_timedout = TOUT_QUEUED; 1639 TAILQ_INSERT_TAIL(&iscsi_timeout_conn_list, conn, c_tchain); 1640 iscsi_notify_cleanup(); 1641 mutex_exit(&iscsi_cleanup_mtx); 1642 } 1643 1644 void 1645 connection_timeout_start(connection_t *conn, int ticks) 1646 { 1647 mutex_enter(&iscsi_cleanup_mtx); 1648 if (conn->c_timedout != TOUT_QUEUED) { 1649 conn->c_timedout = TOUT_ARMED; 1650 callout_schedule(&conn->c_timeout, ticks); 1651 } 1652 mutex_exit(&iscsi_cleanup_mtx); 1653 } 1654 1655 void 1656 connection_timeout_stop(connection_t *conn) 1657 { 1658 callout_stop(&conn->c_timeout); 1659 mutex_enter(&iscsi_cleanup_mtx); 1660 if (conn->c_timedout == TOUT_QUEUED) { 1661 TAILQ_REMOVE(&iscsi_timeout_conn_list, conn, c_tchain); 1662 conn->c_timedout = TOUT_NONE; 1663 } 1664 if (curlwp != iscsi_cleanproc) { 1665 while (conn->c_timedout == TOUT_BUSY) 1666 kpause("connbusy", false, 1, &iscsi_cleanup_mtx); 1667 } 1668 mutex_exit(&iscsi_cleanup_mtx); 1669 } 1670 1671 void 1672 ccb_timeout_co(void *par) 1673 { 1674 ccb_t *ccb = par; 1675 1676 mutex_enter(&iscsi_cleanup_mtx); 1677 ccb->ccb_timedout = TOUT_QUEUED; 1678 TAILQ_INSERT_TAIL(&iscsi_timeout_ccb_list, ccb, ccb_tchain); 1679 iscsi_notify_cleanup(); 1680 mutex_exit(&iscsi_cleanup_mtx); 1681 } 1682 1683 void 1684 ccb_timeout_start(ccb_t *ccb, int ticks) 1685 { 1686 mutex_enter(&iscsi_cleanup_mtx); 1687 if (ccb->ccb_timedout != TOUT_QUEUED) { 1688 ccb->ccb_timedout = TOUT_ARMED; 1689 callout_schedule(&ccb->ccb_timeout, ticks); 1690 } 1691 mutex_exit(&iscsi_cleanup_mtx); 1692 } 1693 1694 void 1695 ccb_timeout_stop(ccb_t *ccb) 1696 { 1697 callout_stop(&ccb->ccb_timeout); 1698 mutex_enter(&iscsi_cleanup_mtx); 1699 if (ccb->ccb_timedout == TOUT_QUEUED) { 1700 TAILQ_REMOVE(&iscsi_timeout_ccb_list, ccb, ccb_tchain); 1701 ccb->ccb_timedout = TOUT_NONE; 1702 } 1703 if (curlwp != iscsi_cleanproc) { 1704 while (ccb->ccb_timedout == TOUT_BUSY) 1705 kpause("ccbbusy", false, 1, &iscsi_cleanup_mtx); 1706 } 1707 mutex_exit(&iscsi_cleanup_mtx); 1708 } 1709 1710 /* 1711 * iscsi_cleanup_thread 1712 * Global thread to handle connection and session cleanup after termination. 1713 */ 1714 1715 static void 1716 iscsi_cleanup_thread(void *par) 1717 { 1718 int s, rc; 1719 session_t *sess, *nxts; 1720 connection_t *conn, *nxtc; 1721 ccb_t *ccb; 1722 1723 mutex_enter(&iscsi_cleanup_mtx); 1724 while (iscsi_num_send_threads || !iscsi_detaching || 1725 !TAILQ_EMPTY(&iscsi_cleanupc_list) || !TAILQ_EMPTY(&iscsi_cleanups_list)) { 1726 TAILQ_FOREACH_SAFE(conn, &iscsi_cleanupc_list, c_connections, nxtc) { 1727 1728 TAILQ_REMOVE(&iscsi_cleanupc_list, conn, c_connections); 1729 mutex_exit(&iscsi_cleanup_mtx); 1730 1731 sess = conn->c_session; 1732 1733 /* 1734 * This implies that connection cleanup only runs when 1735 * the send/recv threads have been killed 1736 */ 1737 DEBC(conn, 5, ("Cleanup: Waiting for threads to exit\n")); 1738 1739 mutex_enter(&conn->c_lock); 1740 while (conn->c_sendproc || conn->c_rcvproc) 1741 kpause("threads", false, hz, &conn->c_lock); 1742 1743 for (s=1; conn->c_usecount > 0 && s < 3; ++s) 1744 kpause("usecount", false, hz, &conn->c_lock); 1745 1746 if (conn->c_usecount > 0) { 1747 DEBC(conn, 5, ("Cleanup: %d CCBs busy\n", conn->c_usecount)); 1748 mutex_exit(&conn->c_lock); 1749 /* retry later */ 1750 mutex_enter(&iscsi_cleanup_mtx); 1751 TAILQ_INSERT_HEAD(&iscsi_cleanupc_list, conn, c_connections); 1752 continue; 1753 } 1754 mutex_exit(&conn->c_lock); 1755 1756 KASSERT(!conn->c_in_session); 1757 1758 callout_halt(&conn->c_timeout, NULL); 1759 closef(conn->c_sock); 1760 callout_destroy(&conn->c_timeout); 1761 rw_destroy(&conn->c_sock_rw); 1762 cv_destroy(&conn->c_idle_cv); 1763 cv_destroy(&conn->c_ccb_cv); 1764 cv_destroy(&conn->c_pdu_cv); 1765 cv_destroy(&conn->c_conn_cv); 1766 mutex_destroy(&conn->c_lock); 1767 free(conn, M_DEVBUF); 1768 1769 mutex_enter(&iscsi_cleanup_mtx); 1770 1771 if (--sess->s_total_connections == 0) { 1772 DEB(1, ("Cleanup: session %d\n", sess->s_id)); 1773 if (!sess->s_terminating) { 1774 sess->s_terminating = ISCSI_CONNECTION_TERMINATED; 1775 KASSERT(sess->s_sessions.tqe_prev != NULL); 1776 TAILQ_REMOVE(&iscsi_sessions, sess, s_sessions); 1777 sess->s_sessions.tqe_next = NULL; 1778 sess->s_sessions.tqe_prev = NULL; 1779 } 1780 KASSERT(sess->s_sessions.tqe_prev == NULL); 1781 TAILQ_INSERT_HEAD(&iscsi_cleanups_list, sess, s_sessions); 1782 } 1783 } 1784 1785 TAILQ_FOREACH_SAFE(sess, &iscsi_cleanups_list, s_sessions, nxts) { 1786 if (sess->s_refcount > 0) 1787 continue; 1788 TAILQ_REMOVE(&iscsi_cleanups_list, sess, s_sessions); 1789 sess->s_sessions.tqe_next = NULL; 1790 sess->s_sessions.tqe_prev = NULL; 1791 mutex_exit(&iscsi_cleanup_mtx); 1792 1793 DEB(1, ("Cleanup: Unmap session %d\n", sess->s_id)); 1794 if (unmap_session(sess) == 0) { 1795 DEB(1, ("Cleanup: Unmap session %d failed\n", sess->s_id)); 1796 mutex_enter(&iscsi_cleanup_mtx); 1797 TAILQ_INSERT_HEAD(&iscsi_cleanups_list, sess, s_sessions); 1798 continue; 1799 } 1800 1801 if (sess->s_target_list != NULL) 1802 free(sess->s_target_list, M_TEMP); 1803 1804 /* notify event handlers of session shutdown */ 1805 add_event(ISCSI_SESSION_TERMINATED, sess->s_id, 0, sess->s_terminating); 1806 DEB(1, ("Cleanup: session ended %d\n", sess->s_id)); 1807 1808 destroy_ccbs(sess); 1809 cv_destroy(&sess->s_ccb_cv); 1810 cv_destroy(&sess->s_sess_cv); 1811 mutex_destroy(&sess->s_lock); 1812 free(sess, M_DEVBUF); 1813 1814 mutex_enter(&iscsi_cleanup_mtx); 1815 } 1816 1817 /* handle ccb timeouts */ 1818 while ((ccb = TAILQ_FIRST(&iscsi_timeout_ccb_list)) != NULL) { 1819 TAILQ_REMOVE(&iscsi_timeout_ccb_list, ccb, ccb_tchain); 1820 KASSERT(ccb->ccb_timedout == TOUT_QUEUED); 1821 ccb->ccb_timedout = TOUT_BUSY; 1822 mutex_exit(&iscsi_cleanup_mtx); 1823 ccb_timeout(ccb); 1824 mutex_enter(&iscsi_cleanup_mtx); 1825 if (ccb->ccb_timedout == TOUT_BUSY) 1826 ccb->ccb_timedout = TOUT_NONE; 1827 } 1828 1829 /* handle connection timeouts */ 1830 while ((conn = TAILQ_FIRST(&iscsi_timeout_conn_list)) != NULL) { 1831 TAILQ_REMOVE(&iscsi_timeout_conn_list, conn, c_tchain); 1832 KASSERT(conn->c_timedout == TOUT_QUEUED); 1833 conn->c_timedout = TOUT_BUSY; 1834 mutex_exit(&iscsi_cleanup_mtx); 1835 connection_timeout(conn); 1836 mutex_enter(&iscsi_cleanup_mtx); 1837 if (conn->c_timedout == TOUT_BUSY) 1838 conn->c_timedout = TOUT_NONE; 1839 } 1840 1841 /* Go to sleep, but wake up every 120 seconds to 1842 * check for dead event handlers */ 1843 rc = cv_timedwait(&iscsi_cleanup_cv, &iscsi_cleanup_mtx, 1844 (TAILQ_FIRST(&event_handlers)) ? 120 * hz : 0); 1845 1846 /* if timed out, not woken up */ 1847 if (rc == EWOULDBLOCK) 1848 check_event_handlers(); 1849 } 1850 mutex_exit(&iscsi_cleanup_mtx); 1851 1852 add_event(ISCSI_DRIVER_TERMINATING, 0, 0, ISCSI_STATUS_DRIVER_UNLOAD); 1853 1854 /* 1855 * Wait for all event handlers to deregister, but don't wait more 1856 * than 1 minute (assume registering app has died if it takes longer). 1857 */ 1858 mutex_enter(&iscsi_cleanup_mtx); 1859 for (s = 0; TAILQ_FIRST(&event_handlers) != NULL && s < 60; s++) 1860 kpause("waiteventclr", true, hz, &iscsi_cleanup_mtx); 1861 mutex_exit(&iscsi_cleanup_mtx); 1862 1863 iscsi_cleanproc = NULL; 1864 DEB(5, ("Cleanup thread exits\n")); 1865 kthread_exit(0); 1866 } 1867 1868 void 1869 iscsi_init_cleanup(void) 1870 { 1871 1872 mutex_init(&iscsi_cleanup_mtx, MUTEX_DEFAULT, IPL_BIO); 1873 cv_init(&iscsi_cleanup_cv, "cleanup"); 1874 cv_init(&iscsi_event_cv, "iscsievtwait"); 1875 1876 if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, iscsi_cleanup_thread, 1877 NULL, &iscsi_cleanproc, "iscsi_cleanup") != 0) { 1878 panic("Can't create cleanup thread!"); 1879 } 1880 } 1881 1882 int 1883 iscsi_destroy_cleanup(void) 1884 { 1885 1886 iscsi_detaching = true; 1887 mutex_enter(&iscsi_cleanup_mtx); 1888 while (iscsi_cleanproc != NULL) { 1889 iscsi_notify_cleanup(); 1890 kpause("detach_wait", false, hz, &iscsi_cleanup_mtx); 1891 } 1892 mutex_exit(&iscsi_cleanup_mtx); 1893 1894 cv_destroy(&iscsi_event_cv); 1895 cv_destroy(&iscsi_cleanup_cv); 1896 mutex_destroy(&iscsi_cleanup_mtx); 1897 1898 return 0; 1899 } 1900 1901 void 1902 iscsi_notify_cleanup(void) 1903 { 1904 KASSERT(mutex_owned(&iscsi_cleanup_mtx)); 1905 1906 cv_signal(&iscsi_cleanup_cv); 1907 } 1908 1909 1910 /* -------------------------------------------------------------------- */ 1911 1912 /* 1913 * iscsi_ioctl: 1914 * Driver ioctl entry. 1915 * 1916 * Parameter: 1917 * file File structure 1918 * cmd The ioctl Command 1919 * addr IN/OUT: The command parameter 1920 * flag Flags (ignored) 1921 * l IN: The lwp object of the caller 1922 */ 1923 1924 int 1925 iscsiioctl(struct file *fp, u_long cmd, void *addr) 1926 { 1927 struct lwp *l = curlwp; 1928 struct iscsifd *d = fp->f_iscsi; 1929 1930 DEB(1, ("ISCSI Ioctl cmd = %x\n", (int) cmd)); 1931 1932 switch (cmd) { 1933 case ISCSI_GET_VERSION: 1934 get_version((iscsi_get_version_parameters_t *) addr); 1935 break; 1936 1937 case ISCSI_LOGIN: 1938 login((iscsi_login_parameters_t *) addr, l, d->fd_dev); 1939 break; 1940 1941 case ISCSI_ADD_CONNECTION: 1942 add_connection((iscsi_login_parameters_t *) addr, l); 1943 break; 1944 1945 case ISCSI_RESTORE_CONNECTION: 1946 restore_connection((iscsi_login_parameters_t *) addr, l); 1947 break; 1948 1949 case ISCSI_LOGOUT: 1950 logout((iscsi_logout_parameters_t *) addr); 1951 break; 1952 1953 case ISCSI_REMOVE_CONNECTION: 1954 remove_connection((iscsi_remove_parameters_t *) addr); 1955 break; 1956 1957 #ifndef ISCSI_MINIMAL 1958 case ISCSI_IO_COMMAND: 1959 io_command((iscsi_iocommand_parameters_t *) addr, l); 1960 break; 1961 #endif 1962 1963 case ISCSI_SEND_TARGETS: 1964 send_targets((iscsi_send_targets_parameters_t *) addr); 1965 break; 1966 1967 case ISCSI_SET_NODE_NAME: 1968 set_node_name((iscsi_set_node_name_parameters_t *) addr); 1969 break; 1970 1971 case ISCSI_CONNECTION_STATUS: 1972 connection_status((iscsi_conn_status_parameters_t *) addr); 1973 break; 1974 1975 case ISCSI_REGISTER_EVENT: 1976 register_event((iscsi_register_event_parameters_t *) addr); 1977 break; 1978 1979 case ISCSI_DEREGISTER_EVENT: 1980 deregister_event((iscsi_register_event_parameters_t *) addr); 1981 break; 1982 1983 case ISCSI_WAIT_EVENT: 1984 check_event((iscsi_wait_event_parameters_t *) addr, TRUE); 1985 break; 1986 1987 case ISCSI_POLL_EVENT: 1988 check_event((iscsi_wait_event_parameters_t *) addr, FALSE); 1989 break; 1990 1991 default: 1992 DEBOUT(("Invalid IO-Control Code\n")); 1993 return ENOTTY; 1994 } 1995 1996 /* 1997 * NOTE: We return 0 even if the function fails as long as the ioctl code 1998 * is good, so the status code is copied back to the caller. 1999 */ 2000 return 0; 2001 } 2002