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