1 /* $NetBSD: iscsi_ioctl.c,v 1.37 2024/11/03 10:53:02 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 mutex_enter(&conn->c_lock); 517 terminating = conn->c_terminating; 518 if (!terminating) 519 conn->c_terminating = status; 520 mutex_exit(&conn->c_lock); 521 522 /* Don't recurse */ 523 if (terminating) { 524 mutex_exit(&iscsi_cleanup_mtx); 525 526 KASSERT(conn->c_state != ST_FULL_FEATURE); 527 DEBC(conn, 1, ("Kill_connection exiting (already terminating)\n")); 528 goto done; 529 } 530 531 if (conn->c_state == ST_FULL_FEATURE) { 532 sess->s_active_connections--; 533 conn->c_state = ST_WINDING_DOWN; 534 535 /* If this is the last connection and ERL < 2, reset TSIH */ 536 if (!sess->s_active_connections && sess->s_ErrorRecoveryLevel < 2) 537 sess->s_TSIH = 0; 538 539 /* Don't try to log out if the socket is broken or we're in the middle */ 540 /* of logging in */ 541 if (logout >= 0) { 542 if (sess->s_ErrorRecoveryLevel < 2 && 543 logout == RECOVER_CONNECTION) { 544 logout = LOGOUT_CONNECTION; 545 } 546 if (!sess->s_active_connections && 547 logout == LOGOUT_CONNECTION) { 548 logout = LOGOUT_SESSION; 549 } 550 551 /* connection is terminating, prevent cleanup */ 552 mutex_enter(&conn->c_lock); 553 conn->c_usecount++; 554 mutex_exit(&conn->c_lock); 555 556 mutex_exit(&iscsi_cleanup_mtx); 557 558 DEBC(conn, 1, ("Send_logout for reason %d\n", logout)); 559 560 connection_timeout_start(conn, CONNECTION_TIMEOUT); 561 562 if (!send_logout(conn, conn, logout, FALSE)) { 563 mutex_enter(&conn->c_lock); 564 conn->c_usecount--; 565 conn->c_terminating = ISCSI_STATUS_SUCCESS; 566 mutex_exit(&conn->c_lock); 567 return; 568 } 569 /* 570 * if the logout request was successfully sent, 571 * the logout response handler will do the rest 572 * of the termination processing. If the logout 573 * doesn't get a response, we'll get back in here 574 * once the timeout hits. 575 */ 576 577 mutex_enter(&iscsi_cleanup_mtx); 578 579 /* release connection */ 580 mutex_enter(&conn->c_lock); 581 conn->c_usecount--; 582 mutex_exit(&conn->c_lock); 583 } 584 585 } 586 587 conn->c_state = ST_SETTLING; 588 mutex_exit(&iscsi_cleanup_mtx); 589 590 done: 591 /* let send thread take over next step of cleanup */ 592 mutex_enter(&conn->c_lock); 593 cv_broadcast(&conn->c_conn_cv); 594 mutex_exit(&conn->c_lock); 595 596 DEBC(conn, 5, ("kill_connection returns\n")); 597 } 598 599 600 /* 601 * kill_session: 602 * Terminate the session as gracefully as possible. 603 * 604 * Parameter: 605 * session Session to terminate 606 * status The status code for the termination 607 * logout The logout reason code 608 609 */ 610 611 void 612 kill_session(uint32_t sid, uint32_t status, int logout, bool recover) 613 { 614 session_t *sess; 615 connection_t *conn; 616 617 DEB(1, ("ISCSI: kill_session %d, status %d, logout %d, recover %d\n", 618 sid, status, logout, recover)); 619 620 mutex_enter(&iscsi_cleanup_mtx); 621 622 sess = find_session(sid); 623 if (sess == NULL) { 624 mutex_exit(&iscsi_cleanup_mtx); 625 626 DEB(5, ("Session %u already gone\n", sid)); 627 return; 628 } 629 630 if (sess->s_terminating) { 631 mutex_exit(&iscsi_cleanup_mtx); 632 633 DEB(5, ("Session is being killed with status %d\n",sess->s_terminating)); 634 return; 635 } 636 637 /* 638 * don't do anything if session isn't established yet, termination will be 639 * handled elsewhere 640 */ 641 if (sess->s_sessions.tqe_next == NULL && sess->s_sessions.tqe_prev == NULL) { 642 mutex_exit(&iscsi_cleanup_mtx); 643 644 DEB(5, ("Session is being killed which is not yet established\n")); 645 return; 646 } 647 648 if (recover) { 649 /* 650 * Only recover when there's just one active connection left. 651 * Otherwise we get in all sorts of timing problems, and it doesn't 652 * make much sense anyway to recover when the other side has 653 * requested that we kill a multipathed session. 654 */ 655 conn = NULL; 656 if (sess->s_active_connections == 1) 657 conn = assign_connection(sess, FALSE); 658 659 mutex_exit(&iscsi_cleanup_mtx); 660 661 if (conn != NULL) 662 kill_connection(conn, status, logout, TRUE); 663 return; 664 } 665 666 if (sess->s_refcount > 0) { 667 mutex_exit(&iscsi_cleanup_mtx); 668 669 DEB(5, ("Session is being killed while in use (refcnt = %d)\n", 670 sess->s_refcount)); 671 return; 672 } 673 674 /* Remove session from global list */ 675 sess->s_terminating = status; 676 TAILQ_REMOVE(&iscsi_sessions, sess, s_sessions); 677 sess->s_sessions.tqe_next = NULL; 678 sess->s_sessions.tqe_prev = NULL; 679 680 /* 681 * If all connections are already gone, trigger cleanup 682 * otherwise, the last connection will do this 683 */ 684 if (sess->s_active_connections == 0) 685 iscsi_notify_cleanup(); 686 687 mutex_exit(&iscsi_cleanup_mtx); 688 689 /* kill all connections */ 690 while ((conn = TAILQ_FIRST(&sess->s_conn_list)) != NULL) { 691 kill_connection(conn, status, logout, FALSE); 692 logout = NO_LOGOUT; 693 } 694 } 695 696 697 /* 698 * create_connection: 699 * Create and init the necessary framework for a connection: 700 * Take over userland socket 701 * Alloc the connection structure itself 702 * Copy connection parameters 703 * Create the send and receive threads 704 * And finally, log in. 705 * 706 * Parameter: 707 * par IN/OUT: The login parameters 708 * session IN: The owning session 709 * l IN: The lwp pointer of the caller 710 * 711 * Returns: 0 on success 712 * >0 on failure, connection structure deleted 713 * <0 on failure, connection is still terminating 714 */ 715 716 static int 717 create_connection(iscsi_login_parameters_t *par, session_t *sess, 718 struct lwp *l) 719 { 720 connection_t *conn; 721 int rc; 722 723 DEB(1, ("Create Connection for Session %d\n", sess->s_id)); 724 725 if (sess->s_MaxConnections && 726 sess->s_active_connections >= sess->s_MaxConnections) { 727 DEBOUT(("Too many connections (max = %d, curr = %d)\n", 728 sess->s_MaxConnections, sess->s_active_connections)); 729 /* Always close descriptor */ 730 fd_close(par->socket); 731 732 par->status = ISCSI_STATUS_MAXED_CONNECTIONS; 733 return EIO; 734 } 735 736 conn = malloc(sizeof(*conn), M_DEVBUF, M_WAITOK | M_ZERO); 737 if (conn == NULL) { 738 DEBOUT(("No mem for connection\n")); 739 740 /* Always close descriptor */ 741 fd_close(par->socket); 742 743 par->status = ISCSI_STATUS_NO_RESOURCES; 744 return EIO; 745 } 746 747 rc = get_socket(par->socket, &conn->c_sock); 748 if (rc != EBADF) 749 fd_close(par->socket); 750 751 if (rc) { 752 DEBOUT(("Invalid socket %d\n", par->socket)); 753 free(conn, M_DEVBUF); 754 par->status = ISCSI_STATUS_INVALID_SOCKET; 755 return rc; 756 } 757 758 DEBC(conn, 1, ("get_socket: par_sock=%d, fdesc=%p\n", 759 par->socket, conn->c_sock)); 760 761 mutex_enter(&iscsi_cleanup_mtx); 762 /* create a unique ID */ 763 do { 764 ++sess->s_conn_id; 765 } while (!sess->s_conn_id || 766 find_connection(sess, sess->s_conn_id) != NULL); 767 par->connection_id = conn->c_id = sess->s_conn_id; 768 mutex_exit(&iscsi_cleanup_mtx); 769 DEB(99, ("Connection ID = %d\n", conn->c_id)); 770 771 conn->c_session = sess; 772 773 TAILQ_INIT(&conn->c_ccbs_waiting); 774 TAILQ_INIT(&conn->c_pdus_to_send); 775 TAILQ_INIT(&conn->c_pdu_pool); 776 777 mutex_init(&conn->c_lock, MUTEX_DEFAULT, IPL_BIO); 778 cv_init(&conn->c_conn_cv, "conn"); 779 cv_init(&conn->c_pdu_cv, "pdupool"); 780 cv_init(&conn->c_ccb_cv, "ccbwait"); 781 cv_init(&conn->c_idle_cv, "idle"); 782 rw_init(&conn->c_sock_rw); 783 784 callout_init(&conn->c_timeout, CALLOUT_MPSAFE); 785 callout_setfunc(&conn->c_timeout, connection_timeout_co, conn); 786 conn->c_idle_timeout_val = CONNECTION_IDLE_TIMEOUT; 787 788 init_sernum(&conn->c_StatSN_buf); 789 create_pdus(conn); 790 791 conn->c_threadobj = l; 792 conn->c_login_par = par; 793 794 DEB(5, ("Creating receive thread\n")); 795 if ((rc = kthread_create(PRI_BIO, KTHREAD_MPSAFE, NULL, iscsi_rcv_thread, 796 conn, &conn->c_rcvproc, 797 "ConnRcv")) != 0) { 798 DEBOUT(("Can't create rcv thread (rc %d)\n", rc)); 799 800 release_socket(conn->c_sock); 801 rw_destroy(&conn->c_sock_rw); 802 callout_destroy(&conn->c_timeout); 803 cv_destroy(&conn->c_idle_cv); 804 cv_destroy(&conn->c_ccb_cv); 805 cv_destroy(&conn->c_pdu_cv); 806 cv_destroy(&conn->c_conn_cv); 807 mutex_destroy(&conn->c_lock); 808 free(conn, M_DEVBUF); 809 par->status = ISCSI_STATUS_NO_RESOURCES; 810 return rc; 811 } 812 DEB(5, ("Creating send thread\n")); 813 if ((rc = kthread_create(PRI_BIO, KTHREAD_MPSAFE, NULL, iscsi_send_thread, 814 conn, &conn->c_sendproc, 815 "ConnSend")) != 0) { 816 DEBOUT(("Can't create send thread (rc %d)\n", rc)); 817 818 conn->c_terminating = ISCSI_STATUS_NO_RESOURCES; 819 820 /* 821 * We must close the socket here to force the receive 822 * thread to wake up 823 */ 824 DEBC(conn, 1, ("Closing Socket %p\n", conn->c_sock)); 825 mutex_enter(&conn->c_sock->f_lock); 826 conn->c_sock->f_count += 1; 827 mutex_exit(&conn->c_sock->f_lock); 828 closef(conn->c_sock); 829 830 /* give receive thread time to exit */ 831 kpause("settle", false, 2 * hz, NULL); 832 833 release_socket(conn->c_sock); 834 callout_destroy(&conn->c_timeout); 835 rw_destroy(&conn->c_sock_rw); 836 cv_destroy(&conn->c_idle_cv); 837 cv_destroy(&conn->c_ccb_cv); 838 cv_destroy(&conn->c_pdu_cv); 839 cv_destroy(&conn->c_conn_cv); 840 mutex_destroy(&conn->c_lock); 841 free(conn, M_DEVBUF); 842 par->status = ISCSI_STATUS_NO_RESOURCES; 843 return rc; 844 } 845 846 /* 847 * At this point, each thread will tie 'sock' into its own file descriptor 848 * tables w/o increasing the use count - they will inherit the use 849 * increments performed in get_socket(). 850 */ 851 852 if ((rc = send_login(conn)) != 0) { 853 DEBC(conn, 0, ("Login failed (rc %d)\n", rc)); 854 /* Don't attempt to recover, there seems to be something amiss */ 855 kill_connection(conn, rc, NO_LOGOUT, FALSE); 856 par->status = rc; 857 return -1; 858 } 859 860 mutex_enter(&iscsi_cleanup_mtx); 861 if (sess->s_terminating) { 862 mutex_exit(&iscsi_cleanup_mtx); 863 DEBC(conn, 0, ("Session terminating\n")); 864 kill_connection(conn, rc, NO_LOGOUT, FALSE); 865 par->status = sess->s_terminating; 866 return -1; 867 } 868 conn->c_state = ST_FULL_FEATURE; 869 TAILQ_INSERT_TAIL(&sess->s_conn_list, conn, c_connections); 870 conn->c_in_session = TRUE; 871 sess->s_total_connections++; 872 sess->s_active_connections++; 873 sess->s_mru_connection = conn; 874 mutex_exit(&iscsi_cleanup_mtx); 875 876 DEBC(conn, 5, ("Connection created successfully!\n")); 877 return 0; 878 } 879 880 881 /* 882 * recreate_connection: 883 * Revive dead connection 884 * 885 * Parameter: 886 * par IN/OUT: The login parameters 887 * conn IN: The connection 888 * l IN: The lwp pointer of the caller 889 * 890 * Returns: 0 on success 891 * >0 on failure, connection structure deleted 892 * <0 on failure, connection is still terminating 893 */ 894 895 static int 896 recreate_connection(iscsi_login_parameters_t *par, session_t *sess, 897 connection_t *conn, struct lwp *l) 898 { 899 int rc; 900 ccb_t *ccb; 901 ccb_list_t old_waiting; 902 pdu_t *pdu; 903 uint32_t sn; 904 905 DEB(1, ("ReCreate Connection %d for Session %d, ERL=%d\n", 906 conn->c_id, conn->c_session->s_id, 907 conn->c_session->s_ErrorRecoveryLevel)); 908 909 if (sess->s_MaxConnections && 910 sess->s_active_connections >= sess->s_MaxConnections) { 911 DEBOUT(("Too many connections (max = %d, curr = %d)\n", 912 sess->s_MaxConnections, sess->s_active_connections)); 913 914 /* Close the desecriptor */ 915 rc = EIO; 916 if (fd_getfile(par->socket) != NULL) 917 rc = fd_close(par->socket); 918 919 par->status = ISCSI_STATUS_MAXED_CONNECTIONS; 920 return rc; 921 } 922 923 rw_enter(&conn->c_sock_rw, RW_WRITER); 924 if (conn->c_sock != NULL) { 925 closef(conn->c_sock); 926 conn->c_sock = NULL; 927 } 928 rc = get_socket(par->socket, &conn->c_sock); 929 rw_exit(&conn->c_sock_rw); 930 if (rc != EBADF) 931 fd_close(par->socket); 932 933 if (rc) { 934 DEBOUT(("Invalid socket %d\n", par->socket)); 935 par->status = ISCSI_STATUS_INVALID_SOCKET; 936 return rc; 937 } 938 939 DEBC(conn, 1, ("get_socket: par_sock=%d, fdesc=%p\n", 940 par->socket, conn->c_sock)); 941 942 conn->c_threadobj = l; 943 conn->c_login_par = par; 944 conn->c_terminating = ISCSI_STATUS_SUCCESS; 945 conn->c_recover++; 946 conn->c_num_timeouts = 0; 947 conn->c_state = ST_SEC_NEG; 948 conn->c_HeaderDigest = 0; 949 conn->c_DataDigest = 0; 950 951 sess->s_active_connections++; 952 953 TAILQ_INIT(&old_waiting); 954 955 mutex_enter(&conn->c_lock); 956 while ((ccb = TAILQ_FIRST(&conn->c_ccbs_waiting)) != NULL) { 957 suspend_ccb(ccb, FALSE); 958 TAILQ_INSERT_TAIL(&old_waiting, ccb, ccb_chain); 959 } 960 init_sernum(&conn->c_StatSN_buf); 961 cv_broadcast(&conn->c_idle_cv); 962 mutex_exit(&conn->c_lock); 963 964 if ((rc = send_login(conn)) != 0) { 965 DEBC(conn, 0, ("Re-Login failed (rc %d)\n", rc)); 966 while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) { 967 TAILQ_REMOVE(&old_waiting, ccb, ccb_chain); 968 wake_ccb(ccb, rc); 969 } 970 /* Don't attempt to recover, there seems to be something amiss */ 971 kill_connection(conn, rc, NO_LOGOUT, FALSE); 972 par->status = rc; 973 return -1; 974 } 975 976 DEBC(conn, 9, ("Re-Login successful\n")); 977 par->status = ISCSI_STATUS_SUCCESS; 978 979 conn->c_state = ST_FULL_FEATURE; 980 sess->s_mru_connection = conn; 981 982 while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) { 983 TAILQ_REMOVE(&old_waiting, ccb, ccb_chain); 984 mutex_enter(&conn->c_lock); 985 suspend_ccb(ccb, TRUE); 986 mutex_exit(&conn->c_lock); 987 988 rc = send_task_management(conn, ccb, NULL, TASK_REASSIGN); 989 /* if we get an error on reassign, restart the original request */ 990 if (rc && ccb->ccb_pdu_waiting != NULL) { 991 mutex_enter(&sess->s_lock); 992 if (sn_a_lt_b(ccb->ccb_CmdSN, sess->s_ExpCmdSN)) { 993 pdu = ccb->ccb_pdu_waiting; 994 sn = get_sernum(sess, pdu); 995 996 /* update CmdSN */ 997 DEBC(conn, 0, ("Resend ccb %p (%d) - updating CmdSN old %u, new %u\n", 998 ccb, rc, ccb->ccb_CmdSN, sn)); 999 ccb->ccb_CmdSN = sn; 1000 pdu->pdu_hdr.pduh_p.command.CmdSN = htonl(ccb->ccb_CmdSN); 1001 } else { 1002 DEBC(conn, 0, ("Resend ccb %p (%d) - CmdSN %u\n", 1003 ccb, rc, ccb->ccb_CmdSN)); 1004 } 1005 mutex_exit(&sess->s_lock); 1006 resend_pdu(ccb); 1007 } else { 1008 DEBC(conn, 0, ("Resend ccb %p (%d) CmdSN %u - reassigned\n", 1009 ccb, rc, ccb->ccb_CmdSN)); 1010 ccb_timeout_start(ccb, COMMAND_TIMEOUT); 1011 } 1012 } 1013 1014 mutex_enter(&sess->s_lock); 1015 cv_broadcast(&sess->s_sess_cv); 1016 mutex_exit(&sess->s_lock); 1017 1018 DEBC(conn, 0, ("Connection ReCreated successfully - status %d\n", 1019 par->status)); 1020 1021 return 0; 1022 } 1023 1024 /* -------------------------------------------------------------------------- */ 1025 1026 /* 1027 * check_login_pars: 1028 * Check the parameters passed into login/add_connection 1029 * for validity and consistency. 1030 * 1031 * Parameter: 1032 * par The login parameters 1033 * 1034 * Returns: 0 on success, else an error code. 1035 */ 1036 1037 static int 1038 check_login_pars(iscsi_login_parameters_t *par) 1039 { 1040 int i, n; 1041 1042 if (par->is_present.auth_info) { 1043 /* check consistency of authentication parameters */ 1044 1045 if (par->auth_info.auth_number > ISCSI_AUTH_OPTIONS) { 1046 DEBOUT(("Auth number invalid: %d\n", par->auth_info.auth_number)); 1047 return ISCSI_STATUS_PARAMETER_INVALID; 1048 } 1049 1050 if (par->auth_info.auth_number > 2) { 1051 DEBOUT(("Auth number invalid: %d\n", par->auth_info.auth_number)); 1052 return ISCSI_STATUS_NOTIMPL; 1053 } 1054 1055 for (i = 0, n = 0; i < par->auth_info.auth_number; i++) { 1056 #if 0 1057 if (par->auth_info.auth_type[i] < ISCSI_AUTH_None) { 1058 DEBOUT(("Auth type invalid: %d\n", 1059 par->auth_info.auth_type[i])); 1060 return ISCSI_STATUS_PARAMETER_INVALID; 1061 } 1062 #endif 1063 if (par->auth_info.auth_type[i] > ISCSI_AUTH_CHAP) { 1064 DEBOUT(("Auth type invalid: %d\n", 1065 par->auth_info.auth_type[i])); 1066 return ISCSI_STATUS_NOTIMPL; 1067 } 1068 n = max(n, par->auth_info.auth_type[i]); 1069 } 1070 if (n) { 1071 if (!par->is_present.password || 1072 (par->auth_info.mutual_auth && 1073 !par->is_present.target_password)) { 1074 DEBOUT(("Password missing\n")); 1075 return ISCSI_STATUS_PARAMETER_MISSING; 1076 } 1077 /* Note: Default for user-name is initiator name */ 1078 } 1079 } 1080 if (par->login_type != ISCSI_LOGINTYPE_DISCOVERY && 1081 !par->is_present.TargetName) { 1082 DEBOUT(("Target name missing, login type %d\n", par->login_type)); 1083 return ISCSI_STATUS_PARAMETER_MISSING; 1084 } 1085 if (par->is_present.MaxRecvDataSegmentLength) { 1086 if (par->MaxRecvDataSegmentLength < 512 || 1087 par->MaxRecvDataSegmentLength > 0xffffff) { 1088 DEBOUT(("MaxRecvDataSegmentLength invalid: %d\n", 1089 par->MaxRecvDataSegmentLength)); 1090 return ISCSI_STATUS_PARAMETER_INVALID; 1091 } 1092 } 1093 return 0; 1094 } 1095 1096 1097 /* 1098 * login: 1099 * Handle the login ioctl - Create a session: 1100 * Alloc the session structure 1101 * Copy session parameters 1102 * And call create_connection to establish the connection. 1103 * 1104 * Parameter: 1105 * par IN/OUT: The login parameters 1106 * l IN: The lwp pointer of the caller 1107 */ 1108 1109 static void 1110 login(iscsi_login_parameters_t *par, struct lwp *l, device_t dev) 1111 { 1112 session_t *sess; 1113 int rc; 1114 1115 DEB(99, ("ISCSI: login\n")); 1116 1117 if (!iscsi_InitiatorName[0]) { 1118 DEB(1, ("No Initiator Name\n")); 1119 par->status = ISCSI_STATUS_NO_INITIATOR_NAME; 1120 return; 1121 } 1122 1123 if ((par->status = check_login_pars(par)) != 0) 1124 return; 1125 1126 /* alloc the session */ 1127 sess = malloc(sizeof(*sess), M_DEVBUF, M_WAITOK | M_ZERO); 1128 if (sess == NULL) { 1129 DEBOUT(("No mem for session\n")); 1130 par->status = ISCSI_STATUS_NO_RESOURCES; 1131 return; 1132 } 1133 TAILQ_INIT(&sess->s_conn_list); 1134 TAILQ_INIT(&sess->s_ccb_pool); 1135 1136 mutex_init(&sess->s_lock, MUTEX_DEFAULT, IPL_BIO); 1137 cv_init(&sess->s_sess_cv, "session"); 1138 cv_init(&sess->s_ccb_cv, "ccb"); 1139 1140 mutex_enter(&iscsi_cleanup_mtx); 1141 /* create a unique ID */ 1142 do { 1143 ++current_id; 1144 } while (!current_id || find_session(current_id) != NULL); 1145 par->session_id = sess->s_id = current_id; 1146 mutex_exit(&iscsi_cleanup_mtx); 1147 1148 create_ccbs(sess); 1149 sess->s_login_type = par->login_type; 1150 sess->s_CmdSN = 1; 1151 1152 if ((rc = create_connection(par, sess, l)) != 0) { 1153 if (rc > 0) { 1154 destroy_ccbs(sess); 1155 cv_destroy(&sess->s_ccb_cv); 1156 cv_destroy(&sess->s_sess_cv); 1157 mutex_destroy(&sess->s_lock); 1158 free(sess, M_DEVBUF); 1159 } 1160 return; 1161 } 1162 1163 mutex_enter(&iscsi_cleanup_mtx); 1164 TAILQ_INSERT_HEAD(&iscsi_sessions, sess, s_sessions); 1165 mutex_exit(&iscsi_cleanup_mtx); 1166 1167 /* Session established, map LUNs? */ 1168 if (par->login_type == ISCSI_LOGINTYPE_MAP) { 1169 copyinstr(par->TargetName, sess->s_tgtname, 1170 sizeof(sess->s_tgtname), NULL); 1171 DEB(1, ("Login: map session %d\n", sess->s_id)); 1172 if (!map_session(sess, dev)) { 1173 DEB(1, ("Login: map session %d failed\n", sess->s_id)); 1174 kill_session(par->session_id, ISCSI_STATUS_MAP_FAILED, 1175 LOGOUT_SESSION, FALSE); 1176 par->status = ISCSI_STATUS_MAP_FAILED; 1177 return; 1178 } 1179 } 1180 } 1181 1182 1183 /* 1184 * logout: 1185 * Handle the logout ioctl - Kill a session. 1186 * 1187 * Parameter: 1188 * par IN/OUT: The login parameters 1189 */ 1190 1191 static void 1192 logout(iscsi_logout_parameters_t *par) 1193 { 1194 session_t *session; 1195 1196 DEB(5, ("ISCSI: logout session %d\n", par->session_id)); 1197 1198 mutex_enter(&iscsi_cleanup_mtx); 1199 if ((session = find_session(par->session_id)) == NULL) { 1200 mutex_exit(&iscsi_cleanup_mtx); 1201 DEBOUT(("Session %d not found\n", par->session_id)); 1202 par->status = ISCSI_STATUS_INVALID_SESSION_ID; 1203 return; 1204 } 1205 mutex_exit(&iscsi_cleanup_mtx); 1206 /* If the session exists, this always succeeds */ 1207 par->status = ISCSI_STATUS_SUCCESS; 1208 1209 kill_session(par->session_id, 1210 ISCSI_STATUS_LOGOUT, LOGOUT_SESSION, 1211 FALSE); 1212 } 1213 1214 1215 /* 1216 * add_connection: 1217 * Handle the add_connection ioctl. 1218 * 1219 * Parameter: 1220 * par IN/OUT: The login parameters 1221 * l IN: The lwp pointer of the caller 1222 */ 1223 1224 static int 1225 add_connection(iscsi_login_parameters_t *par, struct lwp *l) 1226 { 1227 session_t *session; 1228 1229 DEB(5, ("ISCSI: add_connection to session %d\n", par->session_id)); 1230 1231 mutex_enter(&iscsi_cleanup_mtx); 1232 if ((session = find_session(par->session_id)) == NULL) { 1233 mutex_exit(&iscsi_cleanup_mtx); 1234 DEBOUT(("Session %d not found\n", par->session_id)); 1235 par->status = ISCSI_STATUS_INVALID_SESSION_ID; 1236 return -1; 1237 } 1238 mutex_exit(&iscsi_cleanup_mtx); 1239 1240 par->status = check_login_pars(par); 1241 if (par->status) 1242 return -1; 1243 1244 return create_connection(par, session, l); 1245 } 1246 1247 1248 /* 1249 * remove_connection: 1250 * Handle the remove_connection ioctl. 1251 * 1252 * Parameter: 1253 * par IN/OUT: The remove parameters 1254 */ 1255 1256 static void 1257 remove_connection(iscsi_remove_parameters_t *par) 1258 { 1259 connection_t *conn; 1260 session_t *session; 1261 1262 DEB(5, ("ISCSI: remove_connection %d from session %d\n", 1263 par->connection_id, par->session_id)); 1264 1265 mutex_enter(&iscsi_cleanup_mtx); 1266 if ((session = find_session(par->session_id)) == NULL) { 1267 mutex_exit(&iscsi_cleanup_mtx); 1268 DEBOUT(("Session %d not found\n", par->session_id)); 1269 par->status = ISCSI_STATUS_INVALID_SESSION_ID; 1270 return; 1271 } 1272 1273 if ((conn = find_connection(session, par->connection_id)) == NULL) { 1274 mutex_exit(&iscsi_cleanup_mtx); 1275 DEBOUT(("Connection %d not found in session %d\n", 1276 par->connection_id, par->session_id)); 1277 1278 par->status = ISCSI_STATUS_INVALID_CONNECTION_ID; 1279 } else { 1280 mutex_exit(&iscsi_cleanup_mtx); 1281 kill_connection(conn, ISCSI_STATUS_LOGOUT, LOGOUT_CONNECTION, 1282 FALSE); 1283 par->status = ISCSI_STATUS_SUCCESS; 1284 } 1285 } 1286 1287 1288 /* 1289 * restore_connection: 1290 * Handle the restore_connection ioctl. 1291 * 1292 * Parameter: 1293 * par IN/OUT: The login parameters 1294 * l IN: The lwp pointer of the caller 1295 */ 1296 1297 static void 1298 restore_connection(iscsi_login_parameters_t *par, struct lwp *l) 1299 { 1300 session_t *sess; 1301 connection_t *conn; 1302 1303 DEB(1, ("ISCSI: restore_connection %d of session %d\n", 1304 par->connection_id, par->session_id)); 1305 1306 mutex_enter(&iscsi_cleanup_mtx); 1307 if ((sess = find_session(par->session_id)) == NULL) { 1308 mutex_exit(&iscsi_cleanup_mtx); 1309 DEBOUT(("Session %d not found\n", par->session_id)); 1310 par->status = ISCSI_STATUS_INVALID_SESSION_ID; 1311 return; 1312 } 1313 if ((conn = find_connection(sess, par->connection_id)) == NULL) { 1314 mutex_exit(&iscsi_cleanup_mtx); 1315 DEBOUT(("Connection %d not found in session %d\n", 1316 par->connection_id, par->session_id)); 1317 par->status = ISCSI_STATUS_INVALID_CONNECTION_ID; 1318 return; 1319 } 1320 if (!conn->c_terminating) { 1321 mutex_exit(&iscsi_cleanup_mtx); 1322 DEBC(conn, 0, ("Connection is alive\n")); 1323 par->status = ISCSI_STATUS_SUCCESS; 1324 return; 1325 } 1326 mutex_exit(&iscsi_cleanup_mtx); 1327 1328 if ((par->status = check_login_pars(par)) == 0) { 1329 recreate_connection(par, sess, conn, l); 1330 } 1331 } 1332 1333 1334 #ifndef ISCSI_MINIMAL 1335 1336 /* 1337 * io_command: 1338 * Handle the io_command ioctl. 1339 * 1340 * Parameter: 1341 * par IN/OUT: The iocommand parameters 1342 * l IN: The lwp pointer of the caller 1343 */ 1344 1345 static void 1346 io_command(iscsi_iocommand_parameters_t *par, struct lwp *l) 1347 { 1348 uint32_t datalen = par->req.datalen; 1349 session_t *session; 1350 void *kbuf = NULL; 1351 int error; 1352 1353 DEB(9, ("ISCSI: io_command, SID=%d, lun=%" PRIu64 "\n", par->session_id, par->lun)); 1354 mutex_enter(&iscsi_cleanup_mtx); 1355 if ((session = find_session(par->session_id)) == NULL) { 1356 mutex_exit(&iscsi_cleanup_mtx); 1357 DEBOUT(("Session %d not found\n", par->session_id)); 1358 par->status = ISCSI_STATUS_INVALID_SESSION_ID; 1359 return; 1360 } 1361 mutex_exit(&iscsi_cleanup_mtx); 1362 1363 par->req.senselen_used = 0; 1364 par->req.datalen_used = 0; 1365 par->req.error = 0; 1366 par->req.status = 0; 1367 par->req.retsts = SCCMD_UNKNOWN; /* init to failure code */ 1368 1369 if (par->req.cmdlen > 16 || par->req.senselen > sizeof(par->req.sense)) { 1370 par->status = ISCSI_STATUS_PARAMETER_INVALID; 1371 return; 1372 } 1373 1374 if (datalen) { 1375 /* Arbitrarily limit datalen to 8k. */ 1376 if (datalen > 8192) { 1377 par->status = ISCSI_STATUS_PARAMETER_INVALID; 1378 return; 1379 } 1380 kbuf = kmem_zalloc(datalen, KM_SLEEP); 1381 if ((par->req.flags & SCCMD_WRITE) != 0) { 1382 error = copyin(par->req.databuf, kbuf, datalen); 1383 if (error) { 1384 kmem_free(kbuf, datalen); 1385 par->status = ISCSI_STATUS_PARAMETER_INVALID; 1386 return; 1387 } 1388 } 1389 } 1390 par->status = send_io_command(session, par->lun, &par->req, 1391 par->options.immediate, par->connection_id); 1392 1393 if (kbuf) { 1394 if ((par->req.flags & SCCMD_READ) != 0) { 1395 (void) copyout(kbuf, par->req.databuf, datalen); 1396 } 1397 kmem_free(kbuf, datalen); 1398 } 1399 switch (par->status) { 1400 case ISCSI_STATUS_SUCCESS: 1401 par->req.retsts = SCCMD_OK; 1402 break; 1403 1404 case ISCSI_STATUS_TARGET_BUSY: 1405 par->req.retsts = SCCMD_BUSY; 1406 break; 1407 1408 case ISCSI_STATUS_TIMEOUT: 1409 case ISCSI_STATUS_SOCKET_ERROR: 1410 par->req.retsts = SCCMD_TIMEOUT; 1411 break; 1412 1413 default: 1414 par->req.retsts = (par->req.senselen_used) ? SCCMD_SENSE 1415 : SCCMD_UNKNOWN; 1416 break; 1417 } 1418 } 1419 #endif 1420 1421 /* 1422 * send_targets: 1423 * Handle the send_targets ioctl. 1424 * Note: If the passed buffer is too small to hold the complete response, 1425 * the response is kept in the session structure so it can be 1426 * retrieved with the next call to this function without having to go to 1427 * the target again. Once the complete response has been retrieved, it 1428 * is discarded. 1429 * 1430 * Parameter: 1431 * par IN/OUT: The send_targets parameters 1432 */ 1433 1434 static void 1435 send_targets(iscsi_send_targets_parameters_t *par) 1436 { 1437 int rc; 1438 uint32_t rlen, cplen; 1439 session_t *sess; 1440 1441 mutex_enter(&iscsi_cleanup_mtx); 1442 if ((sess = find_session(par->session_id)) == NULL) { 1443 mutex_exit(&iscsi_cleanup_mtx); 1444 DEBOUT(("Session %d not found\n", par->session_id)); 1445 par->status = ISCSI_STATUS_INVALID_SESSION_ID; 1446 return; 1447 } 1448 mutex_exit(&iscsi_cleanup_mtx); 1449 1450 DEB(9, ("ISCSI: send_targets, rsp_size=%d; Saved list: %p\n", 1451 par->response_size, sess->s_target_list)); 1452 1453 if (sess->s_target_list == NULL) { 1454 rc = send_send_targets(sess, par->key); 1455 if (rc) { 1456 par->status = rc; 1457 return; 1458 } 1459 } 1460 rlen = sess->s_target_list_len; 1461 par->response_total = rlen; 1462 cplen = min(par->response_size, rlen); 1463 if (cplen) { 1464 copyout(sess->s_target_list, par->response_buffer, cplen); 1465 } 1466 par->response_used = cplen; 1467 1468 /* If all of the response was copied, don't keep it around */ 1469 if (rlen && par->response_used == rlen) { 1470 free(sess->s_target_list, M_TEMP); 1471 sess->s_target_list = NULL; 1472 } 1473 1474 par->status = ISCSI_STATUS_SUCCESS; 1475 } 1476 1477 1478 /* 1479 * set_node_name: 1480 * Handle the set_node_name ioctl. 1481 * 1482 * Parameter: 1483 * par IN/OUT: The set_node_name parameters 1484 */ 1485 1486 static void 1487 set_node_name(iscsi_set_node_name_parameters_t *par) 1488 { 1489 1490 if (strlen(par->InitiatorName) >= ISCSI_STRING_LENGTH || 1491 strlen(par->InitiatorAlias) >= ISCSI_STRING_LENGTH) { 1492 DEBOUT(("*** set_node_name string too long!\n")); 1493 par->status = ISCSI_STATUS_PARAMETER_INVALID; 1494 return; 1495 } 1496 strlcpy(iscsi_InitiatorName, par->InitiatorName, sizeof(iscsi_InitiatorName)); 1497 strlcpy(iscsi_InitiatorAlias, par->InitiatorAlias, sizeof(iscsi_InitiatorAlias)); 1498 memcpy(&iscsi_InitiatorISID, par->ISID, 6); 1499 DEB(5, ("ISCSI: set_node_name, ISID A=%x, B=%x, C=%x, D=%x\n", 1500 iscsi_InitiatorISID.ISID_A, iscsi_InitiatorISID.ISID_B, 1501 iscsi_InitiatorISID.ISID_C, iscsi_InitiatorISID.ISID_D)); 1502 1503 if (!iscsi_InitiatorISID.ISID_A && !iscsi_InitiatorISID.ISID_B && 1504 !iscsi_InitiatorISID.ISID_C && !iscsi_InitiatorISID.ISID_D) { 1505 iscsi_InitiatorISID.ISID_A = T_FORMAT_EN; 1506 iscsi_InitiatorISID.ISID_B = htons(0x1); 1507 iscsi_InitiatorISID.ISID_C = 0x37; 1508 iscsi_InitiatorISID.ISID_D = 0; 1509 } 1510 1511 par->status = ISCSI_STATUS_SUCCESS; 1512 } 1513 1514 1515 /* 1516 * connection_status: 1517 * Handle the connection_status ioctl. 1518 * 1519 * Parameter: 1520 * par IN/OUT: The status parameters 1521 */ 1522 1523 static void 1524 connection_status(iscsi_conn_status_parameters_t *par) 1525 { 1526 connection_t *conn; 1527 session_t *sess; 1528 1529 mutex_enter(&iscsi_cleanup_mtx); 1530 if ((sess = find_session(par->session_id)) == NULL) { 1531 mutex_exit(&iscsi_cleanup_mtx); 1532 par->status = ISCSI_STATUS_INVALID_SESSION_ID; 1533 return; 1534 } 1535 1536 if (par->connection_id) { 1537 conn = find_connection(sess, par->connection_id); 1538 } else { 1539 conn = TAILQ_FIRST(&sess->s_conn_list); 1540 } 1541 par->status = (conn == NULL) ? ISCSI_STATUS_INVALID_CONNECTION_ID : 1542 ISCSI_STATUS_SUCCESS; 1543 mutex_exit(&iscsi_cleanup_mtx); 1544 DEB(9, ("ISCSI: connection_status, session %d connection %d --> %d\n", 1545 par->session_id, par->connection_id, par->status)); 1546 } 1547 1548 1549 /* 1550 * get_version: 1551 * Handle the get_version ioctl. 1552 * 1553 * Parameter: 1554 * par IN/OUT: The version parameters 1555 */ 1556 1557 static void 1558 get_version(iscsi_get_version_parameters_t *par) 1559 { 1560 par->status = ISCSI_STATUS_SUCCESS; 1561 par->interface_version = INTERFACE_VERSION; 1562 par->major = VERSION_MAJOR; 1563 par->minor = VERSION_MINOR; 1564 strlcpy(par->version_string, VERSION_STRING, 1565 sizeof(par->version_string)); 1566 } 1567 1568 1569 /* -------------------------------------------------------------------- */ 1570 1571 /* 1572 * kill_all_sessions: 1573 * Terminate all sessions (called when the driver unloads). 1574 */ 1575 1576 int 1577 kill_all_sessions(void) 1578 { 1579 session_t *sess; 1580 int rc = 0; 1581 uint32_t sid; 1582 1583 mutex_enter(&iscsi_cleanup_mtx); 1584 while ((sess = TAILQ_FIRST(&iscsi_sessions)) != NULL) { 1585 sid = sess->s_id; 1586 mutex_exit(&iscsi_cleanup_mtx); 1587 kill_session(sid, ISCSI_STATUS_DRIVER_UNLOAD, LOGOUT_SESSION, 1588 FALSE); 1589 mutex_enter(&iscsi_cleanup_mtx); 1590 } 1591 if (TAILQ_FIRST(&iscsi_sessions) != NULL) { 1592 DEBOUT(("Failed to kill all sessions\n")); 1593 rc = EBUSY; 1594 } 1595 mutex_exit(&iscsi_cleanup_mtx); 1596 1597 return rc; 1598 } 1599 1600 /* 1601 * handle_connection_error: 1602 * Deal with a problem during send or receive. 1603 * 1604 * Parameter: 1605 * conn The connection the problem is associated with 1606 * status The status code to insert into any unfinished CCBs 1607 * dologout Whether Logout should be attempted 1608 */ 1609 1610 void 1611 handle_connection_error(connection_t *conn, uint32_t status, int dologout) 1612 { 1613 DEBC(conn, 0, ("*** Connection Error, status=%d, logout=%d, state=%d\n", 1614 status, dologout, conn->c_state)); 1615 1616 if (!conn->c_terminating && conn->c_state <= ST_LOGOUT_SENT) { 1617 /* if we get an error while winding down, escalate it */ 1618 if (dologout >= 0 && conn->c_state >= ST_WINDING_DOWN) { 1619 dologout = NO_LOGOUT; 1620 } 1621 kill_connection(conn, status, dologout, TRUE); 1622 } 1623 } 1624 1625 /* 1626 * remove a connection from session and add to the cleanup list 1627 */ 1628 void 1629 add_connection_cleanup(connection_t *conn) 1630 { 1631 session_t *sess = NULL; 1632 1633 mutex_enter(&iscsi_cleanup_mtx); 1634 if (conn->c_in_session) { 1635 sess = conn->c_session; 1636 conn->c_in_session = FALSE; 1637 conn->c_session = NULL; 1638 TAILQ_REMOVE(&sess->s_conn_list, conn, c_connections); 1639 sess->s_mru_connection = TAILQ_FIRST(&sess->s_conn_list); 1640 } 1641 TAILQ_INSERT_TAIL(&iscsi_cleanupc_list, conn, c_connections); 1642 iscsi_notify_cleanup(); 1643 mutex_exit(&iscsi_cleanup_mtx); 1644 } 1645 1646 /* 1647 * callout wrappers for timeouts, the work is done by the cleanup thread 1648 */ 1649 void 1650 connection_timeout_co(void *par) 1651 { 1652 connection_t *conn = par; 1653 1654 mutex_enter(&iscsi_cleanup_mtx); 1655 if (conn->c_timedout == TOUT_ARMED) { 1656 conn->c_timedout = TOUT_QUEUED; 1657 TAILQ_INSERT_TAIL(&iscsi_timeout_conn_list, conn, c_tchain); 1658 iscsi_notify_cleanup(); 1659 } 1660 mutex_exit(&iscsi_cleanup_mtx); 1661 } 1662 1663 void 1664 connection_timeout_start(connection_t *conn, int ticks) 1665 { 1666 mutex_enter(&iscsi_cleanup_mtx); 1667 if (conn->c_timedout != TOUT_QUEUED) { 1668 conn->c_timedout = TOUT_ARMED; 1669 callout_schedule(&conn->c_timeout, ticks); 1670 } 1671 mutex_exit(&iscsi_cleanup_mtx); 1672 } 1673 1674 void 1675 connection_timeout_stop(connection_t *conn) 1676 { 1677 callout_stop(&conn->c_timeout); 1678 mutex_enter(&iscsi_cleanup_mtx); 1679 if (conn->c_timedout == TOUT_QUEUED) 1680 TAILQ_REMOVE(&iscsi_timeout_conn_list, conn, c_tchain); 1681 if (curlwp != iscsi_cleanproc) { 1682 while (conn->c_timedout == TOUT_BUSY) 1683 kpause("connbusy", false, 1, &iscsi_cleanup_mtx); 1684 } 1685 conn->c_timedout = TOUT_NONE; 1686 mutex_exit(&iscsi_cleanup_mtx); 1687 } 1688 1689 void 1690 ccb_timeout_co(void *par) 1691 { 1692 ccb_t *ccb = par; 1693 1694 mutex_enter(&iscsi_cleanup_mtx); 1695 if (ccb->ccb_timedout == TOUT_ARMED) { 1696 ccb->ccb_timedout = TOUT_QUEUED; 1697 TAILQ_INSERT_TAIL(&iscsi_timeout_ccb_list, ccb, ccb_tchain); 1698 iscsi_notify_cleanup(); 1699 } 1700 mutex_exit(&iscsi_cleanup_mtx); 1701 } 1702 1703 void 1704 ccb_timeout_start(ccb_t *ccb, int ticks) 1705 { 1706 mutex_enter(&iscsi_cleanup_mtx); 1707 if (ccb->ccb_timedout != TOUT_QUEUED) { 1708 ccb->ccb_timedout = TOUT_ARMED; 1709 callout_schedule(&ccb->ccb_timeout, ticks); 1710 } 1711 mutex_exit(&iscsi_cleanup_mtx); 1712 } 1713 1714 void 1715 ccb_timeout_stop(ccb_t *ccb) 1716 { 1717 callout_stop(&ccb->ccb_timeout); 1718 mutex_enter(&iscsi_cleanup_mtx); 1719 if (ccb->ccb_timedout == TOUT_QUEUED) 1720 TAILQ_REMOVE(&iscsi_timeout_ccb_list, ccb, ccb_tchain); 1721 if (curlwp != iscsi_cleanproc) { 1722 while (ccb->ccb_timedout == TOUT_BUSY) 1723 kpause("ccbbusy", false, 1, &iscsi_cleanup_mtx); 1724 } 1725 ccb->ccb_timedout = TOUT_NONE; 1726 mutex_exit(&iscsi_cleanup_mtx); 1727 } 1728 1729 /* 1730 * iscsi_cleanup_thread 1731 * Global thread to handle connection and session cleanup after termination. 1732 */ 1733 1734 static void 1735 iscsi_cleanup_thread(void *par) 1736 { 1737 int s, rc; 1738 session_t *sess, *nxts; 1739 connection_t *conn, *nxtc; 1740 ccb_t *ccb; 1741 1742 mutex_enter(&iscsi_cleanup_mtx); 1743 while (iscsi_num_send_threads || !iscsi_detaching || 1744 !TAILQ_EMPTY(&iscsi_cleanupc_list) || !TAILQ_EMPTY(&iscsi_cleanups_list)) { 1745 TAILQ_FOREACH_SAFE(conn, &iscsi_cleanupc_list, c_connections, nxtc) { 1746 1747 TAILQ_REMOVE(&iscsi_cleanupc_list, conn, c_connections); 1748 mutex_exit(&iscsi_cleanup_mtx); 1749 1750 sess = conn->c_session; 1751 1752 /* 1753 * This implies that connection cleanup only runs when 1754 * the send/recv threads have been killed 1755 */ 1756 DEBC(conn, 5, ("Cleanup: Waiting for threads to exit\n")); 1757 1758 mutex_enter(&conn->c_lock); 1759 while (conn->c_sendproc || conn->c_rcvproc) 1760 kpause("threads", false, hz, &conn->c_lock); 1761 1762 for (s=1; conn->c_usecount > 0 && s < 3; ++s) 1763 kpause("usecount", false, hz, &conn->c_lock); 1764 1765 if (conn->c_usecount > 0) { 1766 DEBC(conn, 5, ("Cleanup: %d CCBs busy\n", conn->c_usecount)); 1767 mutex_exit(&conn->c_lock); 1768 /* retry later */ 1769 mutex_enter(&iscsi_cleanup_mtx); 1770 TAILQ_INSERT_HEAD(&iscsi_cleanupc_list, conn, c_connections); 1771 continue; 1772 } 1773 mutex_exit(&conn->c_lock); 1774 1775 KASSERT(!conn->c_in_session); 1776 1777 callout_halt(&conn->c_timeout, NULL); 1778 closef(conn->c_sock); 1779 callout_destroy(&conn->c_timeout); 1780 rw_destroy(&conn->c_sock_rw); 1781 cv_destroy(&conn->c_idle_cv); 1782 cv_destroy(&conn->c_ccb_cv); 1783 cv_destroy(&conn->c_pdu_cv); 1784 cv_destroy(&conn->c_conn_cv); 1785 mutex_destroy(&conn->c_lock); 1786 free(conn, M_DEVBUF); 1787 1788 mutex_enter(&iscsi_cleanup_mtx); 1789 1790 if (--sess->s_total_connections == 0) { 1791 DEB(1, ("Cleanup: session %d\n", sess->s_id)); 1792 if (!sess->s_terminating) { 1793 sess->s_terminating = ISCSI_CONNECTION_TERMINATED; 1794 KASSERT(sess->s_sessions.tqe_prev != NULL); 1795 TAILQ_REMOVE(&iscsi_sessions, sess, s_sessions); 1796 sess->s_sessions.tqe_next = NULL; 1797 sess->s_sessions.tqe_prev = NULL; 1798 } 1799 KASSERT(sess->s_sessions.tqe_prev == NULL); 1800 TAILQ_INSERT_HEAD(&iscsi_cleanups_list, sess, s_sessions); 1801 } 1802 } 1803 1804 TAILQ_FOREACH_SAFE(sess, &iscsi_cleanups_list, s_sessions, nxts) { 1805 if (sess->s_refcount > 0) 1806 continue; 1807 TAILQ_REMOVE(&iscsi_cleanups_list, sess, s_sessions); 1808 sess->s_sessions.tqe_next = NULL; 1809 sess->s_sessions.tqe_prev = NULL; 1810 mutex_exit(&iscsi_cleanup_mtx); 1811 1812 DEB(1, ("Cleanup: Unmap session %d\n", sess->s_id)); 1813 if (unmap_session(sess) == 0) { 1814 DEB(1, ("Cleanup: Unmap session %d failed\n", sess->s_id)); 1815 mutex_enter(&iscsi_cleanup_mtx); 1816 TAILQ_INSERT_HEAD(&iscsi_cleanups_list, sess, s_sessions); 1817 continue; 1818 } 1819 1820 if (sess->s_target_list != NULL) 1821 free(sess->s_target_list, M_TEMP); 1822 1823 /* notify event handlers of session shutdown */ 1824 add_event(ISCSI_SESSION_TERMINATED, sess->s_id, 0, sess->s_terminating); 1825 DEB(1, ("Cleanup: session ended %d\n", sess->s_id)); 1826 1827 destroy_ccbs(sess); 1828 cv_destroy(&sess->s_ccb_cv); 1829 cv_destroy(&sess->s_sess_cv); 1830 mutex_destroy(&sess->s_lock); 1831 free(sess, M_DEVBUF); 1832 1833 mutex_enter(&iscsi_cleanup_mtx); 1834 } 1835 1836 /* handle ccb timeouts */ 1837 while ((ccb = TAILQ_FIRST(&iscsi_timeout_ccb_list)) != NULL) { 1838 TAILQ_REMOVE(&iscsi_timeout_ccb_list, ccb, ccb_tchain); 1839 KASSERT(ccb->ccb_timedout == TOUT_QUEUED); 1840 ccb->ccb_timedout = TOUT_BUSY; 1841 mutex_exit(&iscsi_cleanup_mtx); 1842 ccb_timeout(ccb); 1843 mutex_enter(&iscsi_cleanup_mtx); 1844 if (ccb->ccb_timedout == TOUT_BUSY) 1845 ccb->ccb_timedout = TOUT_NONE; 1846 } 1847 1848 /* handle connection timeouts */ 1849 while ((conn = TAILQ_FIRST(&iscsi_timeout_conn_list)) != NULL) { 1850 TAILQ_REMOVE(&iscsi_timeout_conn_list, conn, c_tchain); 1851 KASSERT(conn->c_timedout == TOUT_QUEUED); 1852 conn->c_timedout = TOUT_BUSY; 1853 mutex_exit(&iscsi_cleanup_mtx); 1854 connection_timeout(conn); 1855 mutex_enter(&iscsi_cleanup_mtx); 1856 if (conn->c_timedout == TOUT_BUSY) 1857 conn->c_timedout = TOUT_NONE; 1858 } 1859 1860 /* Go to sleep, but wake up every 120 seconds to 1861 * check for dead event handlers */ 1862 rc = cv_timedwait(&iscsi_cleanup_cv, &iscsi_cleanup_mtx, 1863 (TAILQ_FIRST(&event_handlers)) ? 120 * hz : 0); 1864 1865 /* if timed out, not woken up */ 1866 if (rc == EWOULDBLOCK) 1867 check_event_handlers(); 1868 } 1869 mutex_exit(&iscsi_cleanup_mtx); 1870 1871 add_event(ISCSI_DRIVER_TERMINATING, 0, 0, ISCSI_STATUS_DRIVER_UNLOAD); 1872 1873 /* 1874 * Wait for all event handlers to deregister, but don't wait more 1875 * than 1 minute (assume registering app has died if it takes longer). 1876 */ 1877 mutex_enter(&iscsi_cleanup_mtx); 1878 for (s = 0; TAILQ_FIRST(&event_handlers) != NULL && s < 60; s++) 1879 kpause("waiteventclr", true, hz, &iscsi_cleanup_mtx); 1880 mutex_exit(&iscsi_cleanup_mtx); 1881 1882 iscsi_cleanproc = NULL; 1883 DEB(5, ("Cleanup thread exits\n")); 1884 kthread_exit(0); 1885 } 1886 1887 void 1888 iscsi_init_cleanup(void) 1889 { 1890 1891 mutex_init(&iscsi_cleanup_mtx, MUTEX_DEFAULT, IPL_BIO); 1892 cv_init(&iscsi_cleanup_cv, "cleanup"); 1893 cv_init(&iscsi_event_cv, "iscsievtwait"); 1894 1895 if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, iscsi_cleanup_thread, 1896 NULL, &iscsi_cleanproc, "iscsi_cleanup") != 0) { 1897 panic("Can't create cleanup thread!"); 1898 } 1899 } 1900 1901 int 1902 iscsi_destroy_cleanup(void) 1903 { 1904 1905 iscsi_detaching = true; 1906 mutex_enter(&iscsi_cleanup_mtx); 1907 while (iscsi_cleanproc != NULL) { 1908 iscsi_notify_cleanup(); 1909 kpause("detach_wait", false, hz, &iscsi_cleanup_mtx); 1910 } 1911 mutex_exit(&iscsi_cleanup_mtx); 1912 1913 cv_destroy(&iscsi_event_cv); 1914 cv_destroy(&iscsi_cleanup_cv); 1915 mutex_destroy(&iscsi_cleanup_mtx); 1916 1917 return 0; 1918 } 1919 1920 void 1921 iscsi_notify_cleanup(void) 1922 { 1923 KASSERT(mutex_owned(&iscsi_cleanup_mtx)); 1924 1925 cv_signal(&iscsi_cleanup_cv); 1926 } 1927 1928 1929 /* -------------------------------------------------------------------- */ 1930 1931 /* 1932 * iscsi_ioctl: 1933 * Driver ioctl entry. 1934 * 1935 * Parameter: 1936 * file File structure 1937 * cmd The ioctl Command 1938 * addr IN/OUT: The command parameter 1939 * flag Flags (ignored) 1940 * l IN: The lwp object of the caller 1941 */ 1942 1943 int 1944 iscsiioctl(struct file *fp, u_long cmd, void *addr) 1945 { 1946 struct lwp *l = curlwp; 1947 struct iscsifd *d = fp->f_iscsi; 1948 1949 DEB(1, ("ISCSI Ioctl cmd = %x\n", (int) cmd)); 1950 1951 switch (cmd) { 1952 case ISCSI_GET_VERSION: 1953 get_version((iscsi_get_version_parameters_t *) addr); 1954 break; 1955 1956 case ISCSI_LOGIN: 1957 login((iscsi_login_parameters_t *) addr, l, d->fd_dev); 1958 break; 1959 1960 case ISCSI_ADD_CONNECTION: 1961 add_connection((iscsi_login_parameters_t *) addr, l); 1962 break; 1963 1964 case ISCSI_RESTORE_CONNECTION: 1965 restore_connection((iscsi_login_parameters_t *) addr, l); 1966 break; 1967 1968 case ISCSI_LOGOUT: 1969 logout((iscsi_logout_parameters_t *) addr); 1970 break; 1971 1972 case ISCSI_REMOVE_CONNECTION: 1973 remove_connection((iscsi_remove_parameters_t *) addr); 1974 break; 1975 1976 #ifndef ISCSI_MINIMAL 1977 case ISCSI_IO_COMMAND: 1978 io_command((iscsi_iocommand_parameters_t *) addr, l); 1979 break; 1980 #endif 1981 1982 case ISCSI_SEND_TARGETS: 1983 send_targets((iscsi_send_targets_parameters_t *) addr); 1984 break; 1985 1986 case ISCSI_SET_NODE_NAME: 1987 set_node_name((iscsi_set_node_name_parameters_t *) addr); 1988 break; 1989 1990 case ISCSI_CONNECTION_STATUS: 1991 connection_status((iscsi_conn_status_parameters_t *) addr); 1992 break; 1993 1994 case ISCSI_REGISTER_EVENT: 1995 register_event((iscsi_register_event_parameters_t *) addr); 1996 break; 1997 1998 case ISCSI_DEREGISTER_EVENT: 1999 deregister_event((iscsi_register_event_parameters_t *) addr); 2000 break; 2001 2002 case ISCSI_WAIT_EVENT: 2003 check_event((iscsi_wait_event_parameters_t *) addr, TRUE); 2004 break; 2005 2006 case ISCSI_POLL_EVENT: 2007 check_event((iscsi_wait_event_parameters_t *) addr, FALSE); 2008 break; 2009 2010 default: 2011 DEBOUT(("Invalid IO-Control Code\n")); 2012 return ENOTTY; 2013 } 2014 2015 /* 2016 * NOTE: We return 0 even if the function fails as long as the ioctl code 2017 * is good, so the status code is copied back to the caller. 2018 */ 2019 return 0; 2020 } 2021