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