1/*	$NetBSD: iscsi_ioctl.c,v 1.2 2012/01/27 19:48:39 para 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
38#ifndef ISCSI_MINIMAL
39#include <uvm/uvm.h>
40#include <uvm/uvm_pmap.h>
41#endif
42
43static uint16_t current_id = 0;	/* Global session ID counter */
44
45/* list of event handlers */
46static event_handler_list_t event_handlers =
47	TAILQ_HEAD_INITIALIZER(event_handlers);
48
49static uint32_t handler_id = 0;	/* Handler ID counter */
50
51/* -------------------------------------------------------------------------- */
52
53/* Event management functions */
54
55/*
56 * find_handler:
57 *    Search the event handler list for the given ID.
58 *
59 *    Parameter:
60 *          id    The handler ID.
61 *
62 *    Returns:
63 *          Pointer to handler if found, else NULL.
64 */
65
66
67STATIC event_handler_t *
68find_handler(uint32_t id)
69{
70	event_handler_t *curr;
71
72	TAILQ_FOREACH(curr, &event_handlers, link)
73		if (curr->id == id)
74			break;
75
76	return curr;
77}
78
79
80/*
81 * register_event:
82 *    Create event handler entry, return ID.
83 *
84 *    Parameter:
85 *          par   The parameter.
86 */
87
88STATIC void
89register_event(iscsi_register_event_parameters_t *par)
90{
91	event_handler_t *handler;
92	int was_empty;
93
94	handler = malloc(sizeof(event_handler_t), M_DEVBUF, M_WAITOK | M_ZERO);
95	if (handler == NULL) {
96		DEBOUT(("No mem for event handler\n"));
97		par->status = ISCSI_STATUS_NO_RESOURCES;
98		return;
99	}
100
101	TAILQ_INIT(&handler->events);
102
103	/* create a unique ID */
104	CS_BEGIN;
105	do {
106		++handler_id;
107	} while (!handler_id || find_handler(handler_id) != NULL);
108	par->event_id = handler->id = handler_id;
109
110	was_empty = TAILQ_FIRST(&event_handlers) == NULL;
111
112	TAILQ_INSERT_TAIL(&event_handlers, handler, link);
113
114	if (was_empty) {
115		wakeup(&cleanup_list);
116	}
117	CS_END;
118
119	par->status = ISCSI_STATUS_SUCCESS;
120	DEB(5, ("Register Event OK, ID %d\n", par->event_id));
121}
122
123
124/*
125 * deregister_event:
126 *    Destroy handler entry and any waiting events, wake up waiter.
127 *
128 *    Parameter:
129 *          par   The parameter.
130 */
131
132STATIC void
133deregister_event(iscsi_register_event_parameters_t *par)
134{
135	event_handler_t *handler;
136	event_t *evt;
137
138	handler = find_handler(par->event_id);
139	if (handler == NULL) {
140		DEB(1, ("Deregister Event ID %d not found\n", par->event_id));
141		par->status = ISCSI_STATUS_INVALID_EVENT_ID;
142		return;
143	}
144	CS_BEGIN;
145	TAILQ_REMOVE(&event_handlers, handler, link);
146	CS_END;
147	if (handler->waiter != NULL) {
148		handler->waiter->status = ISCSI_STATUS_EVENT_DEREGISTERED;
149		wakeup(handler->waiter);
150	}
151
152	while ((evt = TAILQ_FIRST(&handler->events)) != NULL) {
153		TAILQ_REMOVE(&handler->events, evt, link);
154		free(evt, M_TEMP);
155	}
156
157	free(handler, M_DEVBUF);
158	par->status = ISCSI_STATUS_SUCCESS;
159	DEB(5, ("Deregister Event ID %d complete\n", par->event_id));
160}
161
162
163/*
164 * check_event:
165 *    Return first queued event. Optionally wait for arrival of event.
166 *
167 *    Parameter:
168 *          par   The parameter.
169 *          wait  Wait for event if true
170 */
171
172STATIC void
173check_event(iscsi_wait_event_parameters_t *par, bool wait)
174{
175	event_handler_t *handler;
176	event_t *evt;
177
178	handler = find_handler(par->event_id);
179	if (handler == NULL) {
180		DEBOUT(("Wait Event ID %d not found\n", par->event_id));
181		par->status = ISCSI_STATUS_INVALID_EVENT_ID;
182		return;
183	}
184	if (handler->waiter != NULL) {
185		DEBOUT(("Wait Event ID %d already waiting\n", par->event_id));
186		par->status = ISCSI_STATUS_EVENT_WAITING;
187		return;
188	}
189	par->status = ISCSI_STATUS_SUCCESS;
190	DEB(99, ("Wait Event ID %d\n", par->event_id));
191
192	do {
193		int s = splbio();
194		evt = TAILQ_FIRST(&handler->events);
195		if (evt != NULL) {
196			TAILQ_REMOVE(&handler->events, evt, link);
197			splx(s);
198		} else {
199			if (!wait) {
200				splx(s);
201				par->status = ISCSI_STATUS_LIST_EMPTY;
202				return;
203			}
204			if (par->status != ISCSI_STATUS_SUCCESS) {
205				splx(s);
206				return;
207			}
208			handler->waiter = par;
209			splx(s);
210			if (tsleep(par, PRIBIO | PCATCH, "iscsievtwait", 0))
211				return;
212		}
213	} while (evt == NULL);
214
215	par->connection_id = evt->connection_id;
216	par->session_id = evt->session_id;
217	par->event_kind = evt->event_kind;
218	par->reason = evt->reason;
219
220	free(evt, M_TEMP);
221}
222
223/*
224 * add_event
225 *    Adds an event entry to each registered handler queue.
226 *    Note that events are simply duplicated because we expect the number of
227 *    handlers to be very small, usually 1 (the daemon).
228 *
229 *    Parameters:
230 *       kind     The event kind
231 *       sid      The ID of the affected session
232 *       cid      The ID of the affected connection
233 *       reason   The reason code
234 */
235
236void
237add_event(iscsi_event_t kind, uint32_t sid, uint32_t cid, uint32_t reason)
238{
239	event_handler_t *curr;
240	event_t *evt;
241
242	DEB(9, ("Add_event kind %d, sid %d, cid %d, reason %d\n",
243		kind, sid, cid, reason));
244
245	TAILQ_FOREACH(curr, &event_handlers, link) {
246		evt = malloc(sizeof(*evt), M_TEMP, M_WAITOK);
247		if (evt == NULL) {
248			panic("iSCSI: add_event failed to alloc memory");
249		}
250		evt->event_kind = kind;
251		evt->session_id = sid;
252		evt->connection_id = cid;
253		evt->reason = reason;
254		CS_BEGIN;
255		TAILQ_INSERT_TAIL(&curr->events, evt, link);
256		if (curr->waiter != NULL) {
257			wakeup(curr->waiter);
258			curr->waiter = NULL;
259		}
260		CS_END;
261	}
262}
263
264
265/*
266 * check_event_handlers
267 *    Checks for dead event handlers. A dead event handler would deplete
268 *    memory over time, so we have to make sure someone at the other
269 *    end is actively monitoring events.
270 *    This function is called every 30 seconds or so (less frequent if there
271 *    is other activity for the cleanup thread to deal with) to go through
272 *    the list of handlers and check whether the first element in the event
273 *    list has changed at all. If not, the event is deregistered.
274 *    Note that this will not detect dead handlers if no events are pending,
275 *    but we don't care as long as events don't accumulate in the list.
276 */
277
278STATIC void
279check_event_handlers(void)
280{
281	event_handler_t *curr, *next;
282	event_t *evt;
283
284	for (curr = TAILQ_FIRST(&event_handlers); curr != NULL; curr = next) {
285		next = TAILQ_NEXT(curr, link);
286		evt = TAILQ_FIRST(&curr->events);
287
288		if (evt != NULL && evt == curr->first_in_list) {
289			DEBOUT(("Found Dead Event Handler %d, removing\n", curr->id));
290
291			TAILQ_REMOVE(&event_handlers, curr, link);
292			while ((evt = TAILQ_FIRST(&curr->events)) != NULL) {
293				TAILQ_REMOVE(&curr->events, evt, link);
294				free(evt, M_TEMP);
295			}
296			free(curr, M_DEVBUF);
297		} else
298			curr->first_in_list = evt;
299	}
300}
301
302
303/* -------------------------------------------------------------------------- */
304
305/*
306 * get_socket:
307 *    Get the file pointer from the socket handle passed into login.
308 *
309 *    Parameter:
310 *          fdes     IN: The socket handle
311 *          fpp      OUT: The pointer to the resulting file pointer
312 *
313 *    Returns:    0 on success, else an error code.
314 *
315 */
316
317STATIC int
318get_socket(int fdes, struct file **fpp)
319{
320	struct file *fp;
321
322	if ((fp = fd_getfile(fdes)) == NULL) {
323		return EBADF;
324	}
325	if (fp->f_type != DTYPE_SOCKET) {
326		return ENOTSOCK;
327	}
328
329	/* Add the reference */
330	mutex_enter(&fp->f_lock);
331	fp->f_count++;
332	mutex_exit(&fp->f_lock);
333
334	*fpp = fp;
335	return 0;
336}
337
338/*
339 * release_socket:
340 *    Release the file pointer from the socket handle passed into login.
341 *
342 *    Parameter:
343 *          fp       IN: The pointer to the resulting file pointer
344 *
345 */
346
347STATIC void
348release_socket(struct file *fp)
349{
350	/* Add the reference */
351	mutex_enter(&fp->f_lock);
352	fp->f_count--;
353	mutex_exit(&fp->f_lock);
354}
355
356
357/*
358 * find_session:
359 *    Find a session by ID.
360 *
361 *    Parameter:  the session ID
362 *
363 *    Returns:    The pointer to the session (or NULL if not found)
364 */
365
366session_t *
367find_session(uint32_t id)
368{
369	session_t *curr;
370
371	TAILQ_FOREACH(curr, &sessions, sessions)
372		if (curr->id == id) {
373			break;
374		}
375	return curr;
376}
377
378
379/*
380 * find_connection:
381 *    Find a connection by ID.
382 *
383 *    Parameter:  the session pointer and the connection ID
384 *
385 *    Returns:    The pointer to the connection (or NULL if not found)
386 */
387
388connection_t *
389find_connection(session_t *session, uint32_t id)
390{
391	connection_t *curr;
392
393	TAILQ_FOREACH(curr, &session->conn_list, connections)
394		if (curr->id == id) {
395			break;
396		}
397	return curr;
398}
399
400
401/*
402 * kill_connection:
403 *    Terminate the connection as gracefully as possible.
404 *
405 *    Parameter:
406 *		conn		The connection to terminate
407 *		status		The status code for the connection's "terminating" field
408 *		logout		The logout reason code
409 *		recover	Attempt to recover connection
410 */
411
412void
413kill_connection(connection_t *conn, uint32_t status, int logout, bool recover)
414{
415	session_t *sess = conn->session;
416
417	DEBC(conn, 1, ("Kill_connection: terminating=%d, status=%d, logout=%d, "
418			   "state=%d\n",
419			   conn->terminating, status, logout, conn->state));
420
421	if (recover &&
422	    !conn->destroy &&
423	    conn->recover > MAX_RECOVERY_ATTEMPTS) {
424		DEBC(conn, 1,
425			  ("Kill_connection: Too many recovery attempts, destroying\n"));
426		conn->destroy = TRUE;
427	}
428
429	if (!recover || conn->destroy) {
430		CS_BEGIN;
431		if (conn->in_session) {
432			conn->in_session = FALSE;
433			TAILQ_REMOVE(&sess->conn_list, conn, connections);
434			sess->mru_connection = TAILQ_FIRST(&sess->conn_list);
435		}
436		CS_END;
437		if (!conn->destroy) {
438			DEBC(conn, 1, ("Kill_connection setting destroy flag\n"));
439			conn->destroy = TRUE;
440		}
441		/* in case it was already terminated earlier and rcv/send-threads */
442		/* are waiting */
443		wakeup(conn);
444	}
445
446	/* Don't recurse */
447	if (conn->terminating) {
448		DEBC(conn, 1, ("Kill_connection exiting (already terminating)\n"));
449		return;
450	}
451
452	if (conn->state == ST_FULL_FEATURE) {
453		sess->active_connections--;
454
455		/* If this is the last connection and ERL < 2, reset TSIH */
456		if (!sess->active_connections && sess->ErrorRecoveryLevel < 2)
457			sess->TSIH = 0;
458
459		/* Don't try to log out if the socket is broken or we're in the middle */
460		/* of logging in */
461		if (logout >= 0) {
462			conn->state = ST_WINDING_DOWN;
463			SET_CONN_TIMEOUT(conn, CONNECTION_TIMEOUT);
464
465			if (sess->ErrorRecoveryLevel < 2 &&
466			    logout == RECOVER_CONNECTION) {
467				logout = LOGOUT_CONNECTION;
468			}
469			if (!sess->active_connections &&
470			    logout == LOGOUT_CONNECTION) {
471				logout = LOGOUT_SESSION;
472			}
473			if (!send_logout(conn, conn, logout, FALSE)) {
474				return;
475			}
476			/*
477			 * if the logout request was successfully sent, the logout response
478			 * handler will do the rest of the termination processing. If the
479			 * logout doesn't get a response, we'll get back in here once
480			 * the timeout hits.
481			 */
482		}
483	}
484
485#ifdef ISCSI_TEST_MODE
486	test_remove_connection(conn);
487#endif
488
489	conn->terminating = status;
490	conn->state = ST_SETTLING;
491
492	/* let send thread take over next step of cleanup */
493	wakeup(&conn->pdus_to_send);
494
495	DEBC(conn, 5, ("kill_connection returns\n"));
496}
497
498
499/*
500 * kill_session:
501 *    Terminate the session as gracefully as possible.
502 *
503 *    Parameter:
504 *		session		Session to terminate
505 *		status		The status code for the termination
506 *		logout		The logout reason code
507
508 */
509
510void
511kill_session(session_t *session, uint32_t status, int logout, bool recover)
512{
513	connection_t *curr;
514	ccb_t *ccb;
515
516	DEB(1, ("ISCSI: kill_session %d, status %d, logout %d, recover %d\n",
517			session->id, status, logout, recover));
518
519	/*
520	 * don't do anything if session isn't established yet, termination will be
521	 * handled elsewhere
522	 */
523	if (session->sessions.tqe_next == NULL &&
524	    session->sessions.tqe_prev == NULL) {
525		return;
526	}
527
528	if (recover) {
529		/*
530		 * Only recover when there's just one active connection left.
531		 * Otherwise we get in all sorts of timing problems, and it doesn't
532		 * make much sense anyway to recover when the other side has
533		 * requested that we kill a multipathed session.
534		 */
535		if (session->active_connections == 1) {
536			curr = assign_connection(session, FALSE);
537			if (curr != NULL)
538				kill_connection(curr, status, logout, TRUE);
539		}
540		/* don't allow the session to disappear when the target */
541		/* requested the logout */
542		return;
543	}
544
545	/* remove from session list */
546	TAILQ_REMOVE(&sessions, session, sessions);
547	session->sessions.tqe_next = NULL;
548	session->sessions.tqe_prev = NULL;
549
550	/* complete any throttled CCBs */
551	while ((ccb = TAILQ_FIRST(&session->ccbs_throttled)) != NULL) {
552		ccb->status = ISCSI_STATUS_LOGOUT;
553		TAILQ_REMOVE(&session->ccbs_throttled, ccb, chain);
554		complete_ccb(ccb);
555	}
556
557	/*
558	 * unmap first to give the system an opportunity to flush its buffers,
559	 * but don't try to unmap if it's a forced termination (connection is dead)
560	 * to avoid waiting for pending commands that can't complete anyway.
561	 */
562	if (logout >= 0) {
563		unmap_session(session);
564		DEB(5, ("Unmap Returns\n"));
565	}
566
567	/* kill all connections */
568	while ((curr = TAILQ_FIRST(&session->conn_list)) != NULL) {
569		kill_connection(curr, status, logout, FALSE);
570		logout = NO_LOGOUT;
571	}
572}
573
574
575/*
576 * create_connection:
577 *    Create and init the necessary framework for a connection:
578 *       Alloc the connection structure itself
579 *       Copy connection parameters
580 *       Create the send and receive threads
581 *       And finally, log in.
582 *
583 *    Parameter:
584 *          par      IN/OUT: The login parameters
585 *          session  IN: The owning session
586 *          p        IN: The proc pointer of the caller
587 *
588 *    Returns:    0 on success
589 *                >0 on failure, connection structure deleted
590 *                <0 on failure, connection is still terminating
591 */
592
593STATIC int
594create_connection(iscsi_login_parameters_t *par, session_t *session,
595				  PTHREADOBJ p)
596{
597	connection_t *connection;
598	int rc;
599
600	DEB(1, ("Create Connection for Session %d\n", session->id));
601
602	if (session->MaxConnections &&
603	    session->active_connections >= session->MaxConnections) {
604		DEBOUT(("Too many connections (max = %d, curr = %d)\n",
605				session->MaxConnections, session->active_connections));
606		par->status = ISCSI_STATUS_MAXED_CONNECTIONS;
607		return EIO;
608	}
609
610	connection = malloc(sizeof(*connection), M_DEVBUF, M_WAITOK | M_ZERO);
611	if (connection == NULL) {
612		DEBOUT(("No mem for connection\n"));
613		par->status = ISCSI_STATUS_NO_RESOURCES;
614		return EIO;
615	}
616
617	/* create a unique ID */
618	do {
619		++session->conn_id;
620	} while (!session->conn_id ||
621		 find_connection(session, session->conn_id) != NULL);
622
623	par->connection_id = connection->id = session->conn_id;
624	DEB(99, ("Connection ID = %d\n", connection->id));
625
626	connection->session = session;
627
628	TAILQ_INIT(&connection->ccbs_waiting);
629	TAILQ_INIT(&connection->pdus_to_send);
630	TAILQ_INIT(&connection->pdu_pool);
631
632	callout_init(&connection->timeout, 0);
633	callout_setfunc(&connection->timeout, connection_timeout, connection);
634	connection->idle_timeout_val = CONNECTION_IDLE_TIMEOUT;
635
636	init_sernum(&connection->StatSN_buf);
637	create_pdus(connection);
638
639	if ((rc = get_socket(par->socket, &connection->sock)) != 0) {
640		DEBOUT(("Invalid socket %d\n", par->socket));
641
642		free(connection, M_DEVBUF);
643		par->status = ISCSI_STATUS_INVALID_SOCKET;
644		return rc;
645	}
646	DEBC(connection, 1, ("get_socket: par_sock=%d, fdesc=%p\n",
647			par->socket, connection->sock));
648
649	/* close the file descriptor */
650	fd_close(par->socket);
651
652	connection->threadobj = p;
653	connection->login_par = par;
654
655	/*DEBOUT (("Creating receive thread\n")); */
656	if ((rc = kthread_create(PRI_NONE, 0, NULL, iscsi_rcv_thread,
657				connection, &connection->rcvproc,
658				"ConnRcv")) != 0) {
659		DEBOUT(("Can't create rcv thread (rc %d)\n", rc));
660
661		release_socket(connection->sock);
662		free(connection, M_DEVBUF);
663		par->status = ISCSI_STATUS_NO_RESOURCES;
664		return rc;
665	}
666	/*DEBOUT (("Creating send thread\n")); */
667	if ((rc = kthread_create(PRI_NONE, 0, NULL, iscsi_send_thread,
668				connection, &connection->sendproc,
669				"ConnSend")) != 0) {
670		DEBOUT(("Can't create send thread (rc %d)\n", rc));
671
672		connection->terminating = ISCSI_STATUS_NO_RESOURCES;
673
674		/*
675		 * We must close the socket here to force the receive
676		 * thread to wake up
677		 */
678		DEBC(connection, 1,
679			("Closing Socket %p\n", connection->sock));
680		mutex_enter(&connection->sock->f_lock);
681		connection->sock->f_count += 1;
682		mutex_exit(&connection->sock->f_lock);
683		closef(connection->sock);
684
685		/* give receive thread time to exit */
686		tsleep(connection, PWAIT, "settle", 20);
687
688		release_socket(connection->sock);
689		free(connection, M_DEVBUF);
690		par->status = ISCSI_STATUS_NO_RESOURCES;
691		return rc;
692	}
693
694	/*
695	 * At this point, each thread will tie 'sock' into its own file descriptor
696	 * tables w/o increasing the use count - they will inherit the use
697	 * increments performed in get_socket().
698	 */
699
700#ifdef ISCSI_TEST_MODE
701	test_assign_connection(connection);
702#endif
703
704	if ((rc = send_login(connection)) != 0) {
705		DEBC(connection, 0, ("Login failed (rc %d)\n", rc));
706		/* Don't attempt to recover, there seems to be something amiss */
707		kill_connection(connection, rc, NO_LOGOUT, FALSE);
708		par->status = rc;
709		return -1;
710	}
711
712	CS_BEGIN;
713	connection->state = ST_FULL_FEATURE;
714
715	TAILQ_INSERT_TAIL(&session->conn_list, connection, connections);
716	connection->in_session = TRUE;
717	session->total_connections++;
718	session->active_connections++;
719	session->mru_connection = connection;
720	CS_END;
721
722	DEBC(connection, 5, ("Connection created successfully!\n"));
723	return 0;
724}
725
726
727/*
728 * recreate_connection:
729 *    Revive dead connection
730 *
731 *    Parameter:
732 *          par      IN/OUT: The login parameters
733 *          conn     IN: The connection
734 *          p        IN: The proc pointer of the caller
735 *
736 *    Returns:    0 on success
737 *                >0 on failure, connection structure deleted
738 *                <0 on failure, connection is still terminating
739 */
740
741STATIC int
742recreate_connection(iscsi_login_parameters_t *par, session_t *session,
743					connection_t *connection, PTHREADOBJ p)
744{
745	int rc;
746	ccb_t *ccb;
747	ccb_list_t old_waiting;
748
749	DEB(1, ("ReCreate Connection %d for Session %d, ERL=%d\n",
750		connection->id, connection->session->id,
751		connection->session->ErrorRecoveryLevel));
752
753	if (session->MaxConnections &&
754	    session->active_connections >= session->MaxConnections) {
755		DEBOUT(("Too many connections (max = %d, curr = %d)\n",
756			session->MaxConnections, session->active_connections));
757		par->status = ISCSI_STATUS_MAXED_CONNECTIONS;
758		return EIO;
759	}
760
761	if ((rc = get_socket(par->socket, &connection->sock)) != 0) {
762		DEBOUT(("Invalid socket %d\n", par->socket));
763		par->status = ISCSI_STATUS_INVALID_SOCKET;
764		return rc;
765	}
766
767	/* close the file descriptor */
768	fd_close(par->socket);
769
770	connection->threadobj = p;
771	connection->login_par = par;
772	connection->terminating = ISCSI_STATUS_SUCCESS;
773	connection->recover++;
774	connection->num_timeouts = 0;
775	connection->state = ST_SEC_NEG;
776
777	session->active_connections++;
778
779	TAILQ_INIT(&old_waiting);
780	while ((ccb = TAILQ_FIRST(&connection->ccbs_waiting)) != NULL) {
781		TAILQ_REMOVE(&connection->ccbs_waiting, ccb, chain);
782		TAILQ_INSERT_TAIL(&old_waiting, ccb, chain);
783	}
784
785	init_sernum(&connection->StatSN_buf);
786	wakeup(connection);
787
788	if ((rc = send_login(connection)) != 0) {
789		DEBOUT(("Login failed (rc %d)\n", rc));
790		while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) {
791			TAILQ_REMOVE(&old_waiting, ccb, chain);
792			ccb->status = rc;
793			complete_ccb(ccb);
794		}
795		/* Don't attempt to recover, there seems to be something amiss */
796		kill_connection(connection, rc, NO_LOGOUT, FALSE);
797		par->status = rc;
798		return -1;
799	}
800
801	DEBC(connection, 9, ("Re-Login successful\n"));
802	par->status = ISCSI_STATUS_SUCCESS;
803	CS_BEGIN;
804	connection->state = ST_FULL_FEATURE;
805	session->mru_connection = connection;
806	CS_END;
807
808	while ((ccb = TAILQ_FIRST(&old_waiting)) != NULL) {
809		TAILQ_REMOVE(&old_waiting, ccb, chain);
810		TAILQ_INSERT_TAIL(&connection->ccbs_waiting, ccb, chain);
811
812		rc = send_task_management(connection, ccb, NULL, TASK_REASSIGN);
813		/* if we get an error on reassign, restart the original request */
814		if (rc && ccb->pdu_waiting != NULL) {
815			if (ccb->CmdSN < session->ExpCmdSN) {
816				pdu_t *pdu = ccb->pdu_waiting;
817
818				/* update CmdSN */
819				DEBC(connection, 1, ("Resend Updating CmdSN - old %d, new %d\n",
820					   ccb->CmdSN, session->CmdSN));
821				ccb->CmdSN = session->CmdSN;
822				if (!(pdu->pdu.Opcode & OP_IMMEDIATE))
823					session->CmdSN++;
824				pdu->pdu.p.command.CmdSN = htonl(ccb->CmdSN);
825			}
826			resend_pdu(ccb);
827		} else {
828			SET_CCB_TIMEOUT(connection, ccb, COMMAND_TIMEOUT);
829		}
830	}
831
832	wakeup(session);
833
834	DEBC(connection, 5, ("Connection ReCreated successfully - status %d\n",
835						 par->status));
836
837	return 0;
838}
839
840/* -------------------------------------------------------------------------- */
841
842/*
843 * check_login_pars:
844 *    Check the parameters passed into login/add_connection
845 *    for validity and consistency.
846 *
847 *    Parameter:
848 *          par      The login parameters
849 *
850 *    Returns:    0 on success, else an error code.
851 */
852
853STATIC int
854check_login_pars(iscsi_login_parameters_t *par)
855{
856	int i, n;
857
858	if (par->is_present.auth_info) {
859		/* check consistency of authentication parameters */
860
861		if (par->auth_info.auth_number > ISCSI_AUTH_OPTIONS) {
862			DEBOUT(("Auth number invalid: %d\n", par->auth_info.auth_number));
863			return ISCSI_STATUS_PARAMETER_INVALID;
864		}
865
866		if (par->auth_info.auth_number > 2) {
867			DEBOUT(("Auth number invalid: %d\n", par->auth_info.auth_number));
868			return ISCSI_STATUS_NOTIMPL;
869		}
870
871		for (i = 0, n = 0; i < par->auth_info.auth_number; i++) {
872#if 0
873			if (par->auth_info.auth_type[i] < ISCSI_AUTH_None) {
874				DEBOUT(("Auth type invalid: %d\n",
875						par->auth_info.auth_type[i]));
876				return ISCSI_STATUS_PARAMETER_INVALID;
877			}
878#endif
879			if (par->auth_info.auth_type[i] > ISCSI_AUTH_CHAP) {
880				DEBOUT(("Auth type invalid: %d\n",
881						par->auth_info.auth_type[i]));
882				return ISCSI_STATUS_NOTIMPL;
883			}
884			n = max(n, par->auth_info.auth_type[i]);
885		}
886		if (n) {
887			if (!par->is_present.password ||
888				(par->auth_info.mutual_auth &&
889				 !par->is_present.target_password)) {
890				DEBOUT(("Password missing\n"));
891				return ISCSI_STATUS_PARAMETER_MISSING;
892			}
893			/* Note: Default for user-name is initiator name */
894		}
895	}
896	if (par->login_type != ISCSI_LOGINTYPE_DISCOVERY &&
897	    !par->is_present.TargetName) {
898		DEBOUT(("Target name missing, login type %d\n", par->login_type));
899		return ISCSI_STATUS_PARAMETER_MISSING;
900	}
901	if (par->is_present.MaxRecvDataSegmentLength) {
902		if (par->MaxRecvDataSegmentLength < 512 ||
903			par->MaxRecvDataSegmentLength > 0xffffff) {
904			DEBOUT(("MaxRecvDataSegmentLength invalid: %d\n",
905					par->MaxRecvDataSegmentLength));
906			return ISCSI_STATUS_PARAMETER_INVALID;
907		}
908	}
909	return 0;
910}
911
912
913/*
914 * login:
915 *    Handle the login ioctl - Create a session:
916 *       Alloc the session structure
917 *       Copy session parameters
918 *       And call create_connection to establish the connection.
919 *
920 *    Parameter:
921 *          par      IN/OUT: The login parameters
922 *          p        IN: The proc pointer of the caller
923 */
924
925STATIC void
926login(iscsi_login_parameters_t *par, PTHREADOBJ p)
927{
928	session_t *session;
929	int rc;
930
931	DEB(99, ("ISCSI: login\n"));
932
933	if (!InitiatorName[0]) {
934		DEB(1, ("No Initiator Name\n"));
935		par->status = ISCSI_STATUS_NO_INITIATOR_NAME;
936		return;
937	}
938
939	if ((par->status = check_login_pars(par)) != 0)
940		return;
941
942	/* alloc the session */
943	session = malloc(sizeof(*session), M_DEVBUF, M_WAITOK | M_ZERO);
944	if (session == NULL) {
945		DEBOUT(("No mem for session\n"));
946		par->status = ISCSI_STATUS_NO_RESOURCES;
947		return;
948	}
949	TAILQ_INIT(&session->conn_list);
950	TAILQ_INIT(&session->ccb_pool);
951	TAILQ_INIT(&session->ccbs_throttled);
952
953	/* create a unique ID */
954	do {
955		++current_id;
956	} while (!current_id || find_session(current_id) != NULL);
957	par->session_id = session->id = current_id;
958
959	create_ccbs(session);
960	session->login_type = par->login_type;
961	session->CmdSN = 1;
962
963	if ((rc = create_connection(par, session, p)) != 0) {
964		if (rc > 0) {
965			free(session, M_DEVBUF);
966		}
967		return;
968	}
969
970	CS_BEGIN;
971	TAILQ_INSERT_HEAD(&sessions, session, sessions);
972	CS_END;
973
974	/* Session established, map LUNs? */
975	if (par->login_type == ISCSI_LOGINTYPE_MAP) {
976		copyinstr(par->TargetName, session->tgtname,
977		    sizeof(session->tgtname), NULL);
978		if (!map_session(session)) {
979			kill_session(session, ISCSI_STATUS_MAP_FAILED,
980					LOGOUT_SESSION, FALSE);
981			par->status = ISCSI_STATUS_MAP_FAILED;
982			return;
983		}
984	}
985}
986
987
988/*
989 * logout:
990 *    Handle the logout ioctl - Kill a session.
991 *
992 *    Parameter:
993 *          par      IN/OUT: The login parameters
994 */
995
996STATIC void
997logout(iscsi_logout_parameters_t *par)
998{
999	session_t *session;
1000
1001	DEB(5, ("ISCSI: logout session %d\n", par->session_id));
1002
1003	if ((session = find_session(par->session_id)) == NULL) {
1004		DEBOUT(("Session %d not found\n", par->session_id));
1005		par->status = ISCSI_STATUS_INVALID_SESSION_ID;
1006		return;
1007	}
1008	/* If the session exists, this always succeeds */
1009	par->status = ISCSI_STATUS_SUCCESS;
1010
1011	kill_session(session, ISCSI_STATUS_LOGOUT, LOGOUT_SESSION, FALSE);
1012}
1013
1014
1015/*
1016 * add_connection:
1017 *    Handle the add_connection ioctl.
1018 *
1019 *    Parameter:
1020 *          par      IN/OUT: The login parameters
1021 *          p        IN: The proc pointer of the caller
1022 */
1023
1024STATIC void
1025add_connection(iscsi_login_parameters_t *par, PTHREADOBJ p)
1026{
1027	session_t *session;
1028
1029	DEB(5, ("ISCSI: add_connection to session %d\n", par->session_id));
1030
1031	if ((session = find_session(par->session_id)) == NULL) {
1032		DEBOUT(("Session %d not found\n", par->session_id));
1033		par->status = ISCSI_STATUS_INVALID_SESSION_ID;
1034		return;
1035	}
1036	if ((par->status = check_login_pars(par)) == 0) {
1037		create_connection(par, session, p);
1038	}
1039}
1040
1041
1042/*
1043 * remove_connection:
1044 *    Handle the remove_connection ioctl.
1045 *
1046 *    Parameter:
1047 *          par      IN/OUT: The remove parameters
1048 */
1049
1050STATIC void
1051remove_connection(iscsi_remove_parameters_t *par)
1052{
1053	connection_t *conn;
1054	session_t *session;
1055
1056	DEB(5, ("ISCSI: remove_connection %d from session %d\n",
1057			par->connection_id, par->session_id));
1058
1059	if ((session = find_session(par->session_id)) == NULL) {
1060		DEBOUT(("Session %d not found\n", par->session_id));
1061		par->status = ISCSI_STATUS_INVALID_SESSION_ID;
1062		return;
1063	}
1064
1065	if ((conn = find_connection(session, par->connection_id)) == NULL) {
1066		DEBOUT(("Connection %d not found in session %d\n",
1067				par->connection_id, par->session_id));
1068
1069		par->status = ISCSI_STATUS_INVALID_CONNECTION_ID;
1070	} else {
1071		kill_connection(conn, ISCSI_STATUS_LOGOUT, LOGOUT_CONNECTION,
1072					FALSE);
1073		par->status = ISCSI_STATUS_SUCCESS;
1074	}
1075}
1076
1077
1078/*
1079 * restore_connection:
1080 *    Handle the restore_connection ioctl.
1081 *
1082 *    Parameter:
1083 *          par      IN/OUT: The login parameters
1084 *          p        IN: The proc pointer of the caller
1085 */
1086
1087STATIC void
1088restore_connection(iscsi_login_parameters_t *par, PTHREADOBJ p)
1089{
1090	session_t *session;
1091	connection_t *connection;
1092
1093	DEB(5, ("ISCSI: restore_connection %d of session %d\n",
1094			par->connection_id, par->session_id));
1095
1096	if ((session = find_session(par->session_id)) == NULL) {
1097		DEBOUT(("Session %d not found\n", par->session_id));
1098		par->status = ISCSI_STATUS_INVALID_SESSION_ID;
1099		return;
1100	}
1101
1102	if ((connection = find_connection(session, par->connection_id)) == NULL) {
1103		DEBOUT(("Connection %d not found in session %d\n",
1104				par->connection_id, par->session_id));
1105		par->status = ISCSI_STATUS_INVALID_CONNECTION_ID;
1106		return;
1107	}
1108
1109	if ((par->status = check_login_pars(par)) == 0) {
1110		recreate_connection(par, session, connection, p);
1111	}
1112}
1113
1114
1115#ifndef ISCSI_MINIMAL
1116
1117/*
1118 * map_databuf:
1119 *    Map user-supplied data buffer into kernel space.
1120 *
1121 *    Parameter:
1122 *          p        IN: The proc pointer of the caller
1123 *          buf      IN/OUT: The virtual address of the buffer, modified
1124 *                   on exit to reflect kernel VA.
1125 *          datalen  IN: The size of the data buffer
1126 *
1127 *    Returns:
1128 *          An ISCSI status code on error, else 0.
1129 */
1130
1131uint32_t
1132map_databuf(struct proc *p, void **buf, uint32_t datalen)
1133{
1134	vaddr_t kva, databuf, offs;
1135	int error;
1136
1137	/* page align address */
1138	databuf = (vaddr_t) * buf & ~PAGE_MASK;
1139	/* offset of VA into page */
1140	offs = (vaddr_t) * buf & PAGE_MASK;
1141	/* round to full page including offset */
1142	datalen = (datalen + offs + PAGE_MASK) & ~PAGE_MASK;
1143
1144	/* Do some magic to the vm space reference count (copied from "copyin_proc") */
1145	if ((p->p_sflag & PS_WEXIT) || (p->p_vmspace->vm_refcnt < 1)) {
1146		return ISCSI_STATUS_NO_RESOURCES;
1147	}
1148	p->p_vmspace->vm_refcnt++;
1149
1150	/* this is lifted from uvm_io */
1151	error = uvm_map_extract(&p->p_vmspace->vm_map, databuf, datalen,
1152			kernel_map, &kva,
1153			UVM_EXTRACT_QREF | UVM_EXTRACT_CONTIG |
1154				UVM_EXTRACT_FIXPROT);
1155	if (error) {
1156		DEBOUT(("uvm_map_extract failed, error = %d\n", error));
1157		return ISCSI_STATUS_NO_RESOURCES;
1158	}
1159	/* add offset back into kernel VA */
1160	*buf = (void *) (kva + offs);
1161
1162	return 0;
1163}
1164
1165
1166/*
1167 * unmap_databuf:
1168 *    Remove kernel space mapping of data buffer.
1169 *
1170 *    Parameter:
1171 *          p        IN: The proc pointer of the caller
1172 *          buf      IN: The kernel virtual address of the buffer
1173 *          datalen  IN: The size of the data buffer
1174 *
1175 *    Returns:
1176 *          An ISCSI status code on error, else 0.
1177 */
1178
1179void
1180unmap_databuf(struct proc *p, void *buf, uint32_t datalen)
1181{
1182	struct vm_map_entry *dead_entries;
1183	vaddr_t databuf;
1184
1185	/* round to full page */
1186	datalen = (datalen + ((uintptr_t) buf & PAGE_MASK) + PAGE_MASK) & ~PAGE_MASK;
1187	/* page align address */
1188	databuf = (vaddr_t) buf & ~PAGE_MASK;
1189
1190	/* following code lifted almost verbatim from uvm_io.c */
1191	vm_map_lock(kernel_map);
1192	uvm_unmap_remove(kernel_map, databuf, databuf + datalen, &dead_entries
1193#if (__NetBSD_Version__ >= 399000500)
1194					 , 0
1195#elif   (__NetBSD_Version__ >= 300000000)
1196					 , NULL
1197#endif
1198		);
1199	vm_map_unlock(kernel_map);
1200	if (dead_entries != NULL) {
1201		uvm_unmap_detach(dead_entries, AMAP_REFALL);
1202	}
1203	/* this apparently reverses the magic to the vm ref count, from copyin_proc */
1204	uvmspace_free(p->p_vmspace);
1205}
1206
1207
1208/*
1209 * io_command:
1210 *    Handle the io_command ioctl.
1211 *
1212 *    Parameter:
1213 *          par      IN/OUT: The iocommand parameters
1214 *          p        IN: The proc pointer of the caller
1215 */
1216
1217STATIC void
1218io_command(iscsi_iocommand_parameters_t *par, PTHREADOBJ p)
1219{
1220	uint32_t datalen = par->req.datalen;
1221	void *databuf = par->req.databuf;
1222	session_t *session;
1223
1224	DEB(9, ("ISCSI: io_command, SID=%d, lun=%" PRIu64 "\n", par->session_id, par->lun));
1225	if ((session = find_session(par->session_id)) == NULL) {
1226		DEBOUT(("Session %d not found\n", par->session_id));
1227		par->status = ISCSI_STATUS_INVALID_SESSION_ID;
1228		return;
1229	}
1230
1231	par->req.senselen_used = 0;
1232	par->req.datalen_used = 0;
1233	par->req.error = 0;
1234	par->req.status = 0;
1235	par->req.retsts = SCCMD_UNKNOWN;	/* init to failure code */
1236
1237	if (par->req.cmdlen > 16 || par->req.senselen > sizeof(par->req.sense)) {
1238		par->status = ISCSI_STATUS_PARAMETER_INVALID;
1239		return;
1240	}
1241
1242	if (datalen && (par->status = map_databuf(PROCP(p),
1243			&par->req.databuf, datalen)) != 0) {
1244		return;
1245	}
1246	par->status = send_io_command(session, par->lun, &par->req,
1247								  par->options.immediate, par->connection_id);
1248
1249	if (datalen) {
1250		unmap_databuf(PROCP(p), par->req.databuf, datalen);
1251		par->req.databuf = databuf;	/* restore original addr */
1252	}
1253
1254	switch (par->status) {
1255	case ISCSI_STATUS_SUCCESS:
1256		par->req.retsts = SCCMD_OK;
1257		break;
1258
1259	case ISCSI_STATUS_TARGET_BUSY:
1260		par->req.retsts = SCCMD_BUSY;
1261		break;
1262
1263	case ISCSI_STATUS_TIMEOUT:
1264	case ISCSI_STATUS_SOCKET_ERROR:
1265		par->req.retsts = SCCMD_TIMEOUT;
1266		break;
1267
1268	default:
1269		par->req.retsts = (par->req.senselen_used) ? SCCMD_SENSE
1270												   : SCCMD_UNKNOWN;
1271		break;
1272	}
1273}
1274#endif
1275
1276/*
1277 * send_targets:
1278 *    Handle the send_targets ioctl.
1279 *    Note: If the passed buffer is too small to hold the complete response,
1280 *    the response is kept in the session structure so it can be
1281 *    retrieved with the next call to this function without having to go to
1282 *    the target again. Once the complete response has been retrieved, it
1283 *    is discarded.
1284 *
1285 *    Parameter:
1286 *          par      IN/OUT: The send_targets parameters
1287 */
1288
1289STATIC void
1290send_targets(iscsi_send_targets_parameters_t *par)
1291{
1292	int rc;
1293	uint32_t rlen, cplen;
1294	session_t *session;
1295
1296	if ((session = find_session(par->session_id)) == NULL) {
1297		DEBOUT(("Session %d not found\n", par->session_id));
1298		par->status = ISCSI_STATUS_INVALID_SESSION_ID;
1299		return;
1300	}
1301
1302	DEB(9, ("ISCSI: send_targets, rsp_size=%d; Saved list: %p\n",
1303			par->response_size, session->target_list));
1304
1305	if (session->target_list == NULL) {
1306		rc = send_send_targets(session, par->key);
1307		if (rc) {
1308			par->status = rc;
1309			return;
1310		}
1311	}
1312	rlen = session->target_list_len;
1313	par->response_total = rlen;
1314	cplen = min(par->response_size, rlen);
1315	if (cplen) {
1316		copyout(session->target_list, par->response_buffer, cplen);
1317	}
1318	par->response_used = cplen;
1319
1320	/* If all of the response was copied, don't keep it around */
1321	if (rlen && par->response_used == rlen) {
1322		free(session->target_list, M_TEMP);
1323		session->target_list = NULL;
1324	}
1325
1326	par->status = ISCSI_STATUS_SUCCESS;
1327}
1328
1329
1330/*
1331 * set_node_name:
1332 *    Handle the set_node_name ioctl.
1333 *
1334 *    Parameter:
1335 *          par      IN/OUT: The set_node_name parameters
1336 */
1337
1338STATIC void
1339set_node_name(iscsi_set_node_name_parameters_t *par)
1340{
1341
1342	if (strlen(par->InitiatorName) >= ISCSI_STRING_LENGTH ||
1343		strlen(par->InitiatorAlias) >= ISCSI_STRING_LENGTH) {
1344		DEBOUT(("*** set_node_name string too long!\n"));
1345		par->status = ISCSI_STATUS_PARAMETER_INVALID;
1346		return;
1347	}
1348	strlcpy(InitiatorName, par->InitiatorName, sizeof(InitiatorName));
1349	strlcpy(InitiatorAlias, par->InitiatorAlias, sizeof(InitiatorAlias));
1350	memcpy(&InitiatorISID, par->ISID, 6);
1351	DEB(5, ("ISCSI: set_node_name, ISID A=%x, B=%x, C=%x, D=%x\n",
1352			InitiatorISID.ISID_A, InitiatorISID.ISID_B,
1353			InitiatorISID.ISID_C, InitiatorISID.ISID_D));
1354
1355	if (!InitiatorISID.ISID_A && !InitiatorISID.ISID_B &&
1356		!InitiatorISID.ISID_C && !InitiatorISID.ISID_D) {
1357		InitiatorISID.ISID_A = T_FORMAT_EN;
1358		InitiatorISID.ISID_B = htons(0x1);
1359		InitiatorISID.ISID_C = 0x37;
1360		InitiatorISID.ISID_D = 0;
1361	}
1362
1363	par->status = ISCSI_STATUS_SUCCESS;
1364}
1365
1366
1367/*
1368 * connection_status:
1369 *    Handle the connection_status ioctl.
1370 *
1371 *    Parameter:
1372 *          par      IN/OUT: The status parameters
1373 */
1374
1375STATIC void
1376connection_status(iscsi_conn_status_parameters_t *par)
1377{
1378	connection_t *conn;
1379	session_t *session;
1380
1381	if ((session = find_session(par->session_id)) == NULL) {
1382		par->status = ISCSI_STATUS_INVALID_SESSION_ID;
1383		return;
1384	}
1385
1386	if (par->connection_id) {
1387		conn = find_connection(session, par->connection_id);
1388	} else {
1389		conn = TAILQ_FIRST(&session->conn_list);
1390	}
1391	par->status = (conn == NULL) ? ISCSI_STATUS_INVALID_CONNECTION_ID :
1392					ISCSI_STATUS_SUCCESS;
1393	DEB(9, ("ISCSI: connection_status, session %d connection %d --> %d\n",
1394			par->session_id, par->connection_id, par->status));
1395}
1396
1397
1398/*
1399 * get_version:
1400 *    Handle the get_version ioctl.
1401 *
1402 *    Parameter:
1403 *          par      IN/OUT: The version parameters
1404 */
1405
1406STATIC void
1407get_version(iscsi_get_version_parameters_t *par)
1408{
1409	par->status = ISCSI_STATUS_SUCCESS;
1410	par->interface_version = INTERFACE_VERSION;
1411	par->major = VERSION_MAJOR;
1412	par->minor = VERSION_MINOR;
1413	strlcpy(par->version_string, VERSION_STRING,
1414		sizeof(par->version_string));
1415}
1416
1417
1418/* -------------------------------------------------------------------- */
1419
1420/*
1421 * kill_all_sessions:
1422 *    Terminate all sessions (called when the driver unloads).
1423 */
1424
1425void
1426kill_all_sessions(void)
1427{
1428	session_t *sess;
1429
1430	while ((sess = TAILQ_FIRST(&sessions)) != NULL) {
1431		kill_session(sess, ISCSI_STATUS_DRIVER_UNLOAD, LOGOUT_SESSION,
1432				FALSE);
1433	}
1434}
1435
1436/*
1437 * handle_connection_error:
1438 *    Deal with a problem during send or receive.
1439 *
1440 *    Parameter:
1441 *       conn        The connection the problem is associated with
1442 *       status      The status code to insert into any unfinished CCBs
1443 *       dologout    Whether Logout should be attempted
1444 */
1445
1446void
1447handle_connection_error(connection_t *conn, uint32_t status, int dologout)
1448{
1449
1450	DEBC(conn, 0, ("*** Connection Error, status=%d, logout=%d, state=%d\n",
1451				   status, dologout, conn->state));
1452
1453	if (!conn->terminating && conn->state <= ST_LOGOUT_SENT) {
1454		/* if we get an error while winding down, escalate it */
1455		if (dologout >= 0 && conn->state >= ST_WINDING_DOWN) {
1456			dologout = NO_LOGOUT;
1457		}
1458		kill_connection(conn, status, dologout, TRUE);
1459	}
1460}
1461
1462
1463/*
1464 * iscsi_cleanup_thread
1465 *    Global thread to handle connection and session cleanup after termination.
1466 */
1467
1468void
1469iscsi_cleanup_thread(void *par)
1470{
1471	int s, rc;
1472	connection_t *conn;
1473	session_t *sess;
1474	uint32_t status;
1475
1476	s = splbio();
1477	while ((conn = TAILQ_FIRST(&cleanup_list)) != NULL ||
1478		num_send_threads ||
1479		!detaching) {
1480		if (conn != NULL) {
1481			TAILQ_REMOVE(&cleanup_list, conn, connections);
1482			splx(s);
1483
1484			sess = conn->session;
1485			status = conn->terminating;
1486
1487			DEBC(conn, 5, ("Cleanup: Waiting for threads to exit\n"));
1488			while (conn->sendproc || conn->rcvproc)
1489				tsleep(conn, PWAIT, "termwait", 20);
1490
1491			while (conn->usecount > 0)
1492				tsleep(conn, PWAIT, "finalwait", 20);
1493
1494			callout_stop(&conn->timeout);
1495			closef(conn->sock);
1496			free(conn, M_DEVBUF);
1497
1498			if (!(--sess->total_connections)) {
1499				/* just in case */
1500				unmap_session(sess);
1501
1502				/* unlink and free the session */
1503				if (sess->sessions.tqe_next != NULL ||
1504					sess->sessions.tqe_prev != NULL)
1505					TAILQ_REMOVE(&sessions, sess, sessions);
1506
1507				if (sess->target_list != NULL)
1508					free(sess->target_list, M_TEMP);
1509
1510				/* notify event handlers of session shutdown */
1511				add_event(ISCSI_SESSION_TERMINATED, sess->id, 0, status);
1512
1513				free(sess, M_DEVBUF);
1514			}
1515
1516			DEB(5, ("Cleanup: Done\n"));
1517
1518			s = splbio();
1519		} else {
1520			/* Go to sleep, but wake up every 30 seconds to check for */
1521			/* dead event handlers */
1522			splx(s);
1523			rc = tsleep(&cleanup_list, PWAIT, "cleanup",
1524				(TAILQ_FIRST(&event_handlers)) ? 30 * hz : 0);
1525			s = splbio();
1526			/* if timed out, not woken up */
1527			if (rc == EWOULDBLOCK)
1528				check_event_handlers();
1529		}
1530	}
1531	splx(s);
1532
1533	add_event(ISCSI_DRIVER_TERMINATING, 0, 0, ISCSI_STATUS_DRIVER_UNLOAD);
1534
1535	/*
1536     * Wait for all event handlers to deregister, but don't wait more
1537     * than 1 minute (assume registering app has died if it takes longer).
1538	 */
1539	for (s = 0; TAILQ_FIRST(&event_handlers) != NULL && s < 60; s++)
1540		tsleep(&s, PWAIT, "waiteventclr", hz);
1541
1542	cleanproc = NULL;
1543	DEB(5, ("Cleanup thread exits\n"));
1544	kthread_exit(0);
1545}
1546
1547
1548/* -------------------------------------------------------------------- */
1549
1550/*
1551 * iscsi_ioctl:
1552 *    Driver ioctl entry.
1553 *
1554 *    Parameter:
1555 *       dev      The device (ignored)
1556 *       cmd      The ioctl Command
1557 *       addr     IN/OUT: The command parameter
1558 *       flag     Flags (ignored)
1559 *       p        IN: The thread object of the caller
1560 */
1561
1562int
1563iscsiioctl(dev_t dev, u_long cmd, void *addr, int flag, PTHREADOBJ p)
1564{
1565
1566	DEB(99, ("ISCSI Ioctl cmd = %x\n", (int) cmd));
1567
1568	switch (cmd) {
1569	case ISCSI_GET_VERSION:
1570		get_version((iscsi_get_version_parameters_t *) addr);
1571		break;
1572
1573	case ISCSI_LOGIN:
1574		login((iscsi_login_parameters_t *) addr, p);
1575		break;
1576
1577	case ISCSI_ADD_CONNECTION:
1578		add_connection((iscsi_login_parameters_t *) addr, p);
1579		break;
1580
1581	case ISCSI_RESTORE_CONNECTION:
1582		restore_connection((iscsi_login_parameters_t *) addr, p);
1583		break;
1584
1585	case ISCSI_LOGOUT:
1586		logout((iscsi_logout_parameters_t *) addr);
1587		break;
1588
1589	case ISCSI_REMOVE_CONNECTION:
1590		remove_connection((iscsi_remove_parameters_t *) addr);
1591		break;
1592
1593#ifndef ISCSI_MINIMAL
1594	case ISCSI_IO_COMMAND:
1595		io_command((iscsi_iocommand_parameters_t *) addr, p);
1596		break;
1597#endif
1598
1599	case ISCSI_SEND_TARGETS:
1600		send_targets((iscsi_send_targets_parameters_t *) addr);
1601		break;
1602
1603	case ISCSI_SET_NODE_NAME:
1604		set_node_name((iscsi_set_node_name_parameters_t *) addr);
1605		break;
1606
1607	case ISCSI_CONNECTION_STATUS:
1608		connection_status((iscsi_conn_status_parameters_t *) addr);
1609		break;
1610
1611	case ISCSI_REGISTER_EVENT:
1612		register_event((iscsi_register_event_parameters_t *) addr);
1613		break;
1614
1615	case ISCSI_DEREGISTER_EVENT:
1616		deregister_event((iscsi_register_event_parameters_t *) addr);
1617		break;
1618
1619	case ISCSI_WAIT_EVENT:
1620		check_event((iscsi_wait_event_parameters_t *) addr, TRUE);
1621		break;
1622
1623	case ISCSI_POLL_EVENT:
1624		check_event((iscsi_wait_event_parameters_t *) addr, FALSE);
1625		break;
1626
1627#ifdef ISCSI_PERFTEST
1628	case ISCSI_PERFDATA_START:
1629		perf_start((iscsi_perf_startstop_parameters_t *) addr);
1630		break;
1631
1632	case ISCSI_PERFDATA_STOP:
1633		perf_stop((iscsi_perf_startstop_parameters_t *) addr);
1634		break;
1635
1636	case ISCSI_PERFDATA_GET:
1637		perf_get((iscsi_perf_get_parameters_t *) addr);
1638		break;
1639#endif
1640
1641#ifdef ISCSI_TEST_MODE
1642	case ISCSI_TEST_DEFINE:
1643		test_define((iscsi_test_define_parameters_t *) addr);
1644		break;
1645
1646	case ISCSI_TEST_ADD_NEGOTIATION:
1647		test_add_neg((iscsi_test_add_negotiation_parameters_t *) addr);
1648		break;
1649
1650	case ISCSI_TEST_ADD_MODIFICATION:
1651		test_add_mod(PROCP(p), (iscsi_test_add_modification_parameters_t *) addr);
1652		break;
1653
1654	case ISCSI_TEST_SEND_PDU:
1655		test_send_pdu(PROCP(p), (iscsi_test_send_pdu_parameters_t *) addr);
1656		break;
1657
1658	case ISCSI_TEST_CANCEL:
1659		test_cancel((iscsi_test_cancel_parameters_t *) addr);
1660		break;
1661#endif
1662
1663	default:
1664		DEBOUT(("Invalid IO-Control Code\n"));
1665		return ENOTTY;
1666	}
1667
1668    /*
1669     * NOTE: We return 0 even if the function fails as long as the ioctl code
1670     * is good, so the status code is copied back to the caller.
1671	 */
1672	return 0;
1673}
1674