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