1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte /*
22fcf3ce44SJohn Forte  * Copyright 2000 by Cisco Systems, Inc.  All rights reserved.
2330e7468fSPeter Dunlap  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24fcf3ce44SJohn Forte  * Use is subject to license terms.
25fcf3ce44SJohn Forte  *
26fcf3ce44SJohn Forte  * iSCSI Software Initiator
27fcf3ce44SJohn Forte  */
28fcf3ce44SJohn Forte 
29fcf3ce44SJohn Forte #include "iscsi.h"		/* main header */
30fcf3ce44SJohn Forte 
31fcf3ce44SJohn Forte static void iscsi_enqueue_cmd_tail(iscsi_cmd_t **head, iscsi_cmd_t **tail,
32fcf3ce44SJohn Forte     iscsi_cmd_t *icmdp);
33fcf3ce44SJohn Forte 
34fcf3ce44SJohn Forte 
35fcf3ce44SJohn Forte /*
36fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
37fcf3ce44SJohn Forte  * | public queue functions						|
38fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
39fcf3ce44SJohn Forte  *
40fcf3ce44SJohn Forte  * Public queue locking rules.  When acquiring multiple queue locks
41fcf3ce44SJohn Forte  * they MUST always be acquired in a forward order.  If a lock is
42fcf3ce44SJohn Forte  * aquire in a reverese order it could lead to a deadlock panic.
43fcf3ce44SJohn Forte  * The forward order of locking is described as shown below.
44fcf3ce44SJohn Forte  *
45fcf3ce44SJohn Forte  *		 pending -> cmdsn -> active -> completion
46fcf3ce44SJohn Forte  *
47fcf3ce44SJohn Forte  * If a cmd_mutex is held, it is either held after the pending queue
48fcf3ce44SJohn Forte  * mutex or after the active queue mutex.
49fcf3ce44SJohn Forte  */
50fcf3ce44SJohn Forte 
51fcf3ce44SJohn Forte /*
52fcf3ce44SJohn Forte  * iscsi_init_queue - used to initialize iscsi queue
53fcf3ce44SJohn Forte  */
54fcf3ce44SJohn Forte void
iscsi_init_queue(iscsi_queue_t * queue)55fcf3ce44SJohn Forte iscsi_init_queue(iscsi_queue_t *queue)
56fcf3ce44SJohn Forte {
57fcf3ce44SJohn Forte 	ASSERT(queue != NULL);
58fcf3ce44SJohn Forte 
59fcf3ce44SJohn Forte 	queue->head = NULL;
60fcf3ce44SJohn Forte 	queue->tail = NULL;
61fcf3ce44SJohn Forte 	queue->count = 0;
62fcf3ce44SJohn Forte 	mutex_init(&queue->mutex, NULL, MUTEX_DRIVER, NULL);
63fcf3ce44SJohn Forte }
64fcf3ce44SJohn Forte 
65fcf3ce44SJohn Forte /*
66fcf3ce44SJohn Forte  * iscsi_destroy_queue - used to terminate iscsi queue
67fcf3ce44SJohn Forte  */
68fcf3ce44SJohn Forte void
iscsi_destroy_queue(iscsi_queue_t * queue)69fcf3ce44SJohn Forte iscsi_destroy_queue(iscsi_queue_t *queue)
70fcf3ce44SJohn Forte {
71fcf3ce44SJohn Forte 	ASSERT(queue != NULL);
72fcf3ce44SJohn Forte 	ASSERT(queue->count == 0);
73fcf3ce44SJohn Forte 
74fcf3ce44SJohn Forte 	mutex_destroy(&queue->mutex);
75fcf3ce44SJohn Forte }
76fcf3ce44SJohn Forte 
77fcf3ce44SJohn Forte /*
78fcf3ce44SJohn Forte  * iscsi_enqueue_pending_cmd - used to add a command in a pending queue
79fcf3ce44SJohn Forte  */
80fcf3ce44SJohn Forte void
iscsi_enqueue_pending_cmd(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)81fcf3ce44SJohn Forte iscsi_enqueue_pending_cmd(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
82fcf3ce44SJohn Forte {
83fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
84fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
85fcf3ce44SJohn Forte 	ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
86fcf3ce44SJohn Forte 
87fcf3ce44SJohn Forte 	icmdp->cmd_state = ISCSI_CMD_STATE_PENDING;
88fcf3ce44SJohn Forte 	if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
89fcf3ce44SJohn Forte 		iscsi_enqueue_cmd_tail(&isp->sess_queue_pending.head,
90fcf3ce44SJohn Forte 		    &isp->sess_queue_pending.tail, icmdp);
91fcf3ce44SJohn Forte 		isp->sess_queue_pending.count++;
92fcf3ce44SJohn Forte 		KSTAT_WAITQ_ENTER(isp);
93fcf3ce44SJohn Forte 	} else {
94fcf3ce44SJohn Forte 		iscsi_enqueue_cmd_head(&isp->sess_queue_pending.head,
95fcf3ce44SJohn Forte 		    &isp->sess_queue_pending.tail, icmdp);
96fcf3ce44SJohn Forte 		isp->sess_queue_pending.count++;
97fcf3ce44SJohn Forte 		KSTAT_WAITQ_ENTER(isp);
98fcf3ce44SJohn Forte 	}
99fcf3ce44SJohn Forte 	iscsi_sess_redrive_io(isp);
100fcf3ce44SJohn Forte }
101fcf3ce44SJohn Forte 
102fcf3ce44SJohn Forte 
103fcf3ce44SJohn Forte /*
104fcf3ce44SJohn Forte  * iscsi_dequeue_pending_cmd - used to remove a command from a pending queue
105fcf3ce44SJohn Forte  */
106fcf3ce44SJohn Forte void
iscsi_dequeue_pending_cmd(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)107fcf3ce44SJohn Forte iscsi_dequeue_pending_cmd(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
108fcf3ce44SJohn Forte {
109fcf3ce44SJohn Forte 	iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
110fcf3ce44SJohn Forte 
111fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
112fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
113fcf3ce44SJohn Forte 	ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
114fcf3ce44SJohn Forte 
115fcf3ce44SJohn Forte 	rval = iscsi_dequeue_cmd(&isp->sess_queue_pending.head,
116fcf3ce44SJohn Forte 	    &isp->sess_queue_pending.tail, icmdp);
117fcf3ce44SJohn Forte 	if (ISCSI_SUCCESS(rval)) {
118fcf3ce44SJohn Forte 		isp->sess_queue_pending.count--;
119fcf3ce44SJohn Forte 		if (((kstat_io_t *)(&isp->stats.ks_io_data))->wcnt) {
120fcf3ce44SJohn Forte 			KSTAT_WAITQ_EXIT(isp);
121fcf3ce44SJohn Forte 		} else {
122fcf3ce44SJohn Forte 			cmn_err(CE_WARN,
123fcf3ce44SJohn Forte 			    "kstat wcnt == 0 when exiting waitq,"
124fcf3ce44SJohn Forte 			    " please check\n");
125fcf3ce44SJohn Forte 		}
126fcf3ce44SJohn Forte 	} else {
127fcf3ce44SJohn Forte 		ASSERT(FALSE);
128fcf3ce44SJohn Forte 	}
129fcf3ce44SJohn Forte }
130fcf3ce44SJohn Forte 
131fcf3ce44SJohn Forte /*
132fcf3ce44SJohn Forte  * iscsi_enqueue_active_cmd - used to add a command in a active queue
133fcf3ce44SJohn Forte  *
134fcf3ce44SJohn Forte  * This interface attempts to keep newer items are on the tail,
135fcf3ce44SJohn Forte  * older items are on the head.  But, Do not assume that the list
136fcf3ce44SJohn Forte  * is completely sorted.  If someone attempts to enqueue an item
137fcf3ce44SJohn Forte  * that already has cmd_lbolt_active assigned and is older than
138fcf3ce44SJohn Forte  * the current head, otherwise add to the tail.
139fcf3ce44SJohn Forte  */
140fcf3ce44SJohn Forte void
iscsi_enqueue_active_cmd(iscsi_conn_t * icp,iscsi_cmd_t * icmdp)141fcf3ce44SJohn Forte iscsi_enqueue_active_cmd(iscsi_conn_t *icp, iscsi_cmd_t *icmdp)
142fcf3ce44SJohn Forte {
143fcf3ce44SJohn Forte 	iscsi_sess_t		*isp    = NULL;
144fcf3ce44SJohn Forte 
145fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
146fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
147fcf3ce44SJohn Forte 	isp = icp->conn_sess;
148fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
149fcf3ce44SJohn Forte 
150fcf3ce44SJohn Forte 	/*
151fcf3ce44SJohn Forte 	 * When receiving data associated to a command it
152fcf3ce44SJohn Forte 	 * is temporarily removed from the active queue.
153fcf3ce44SJohn Forte 	 * Then once the data receive is completed it may
154fcf3ce44SJohn Forte 	 * be returned to the active queue.  If this was
155fcf3ce44SJohn Forte 	 * an aborting command we need to preserve its
156fcf3ce44SJohn Forte 	 * state.
157fcf3ce44SJohn Forte 	 */
158fcf3ce44SJohn Forte 	if (icmdp->cmd_state != ISCSI_CMD_STATE_ABORTING) {
159fcf3ce44SJohn Forte 		icmdp->cmd_state = ISCSI_CMD_STATE_ACTIVE;
160fcf3ce44SJohn Forte 	}
161fcf3ce44SJohn Forte 
162fcf3ce44SJohn Forte 	/*
163fcf3ce44SJohn Forte 	 * It's possible that this is not a newly issued icmdp - we may
164fcf3ce44SJohn Forte 	 * have tried to abort it but the abort failed or was rejected
165fcf3ce44SJohn Forte 	 * and we are putting it back on the active list. So if it is older
166fcf3ce44SJohn Forte 	 * than the head of the active queue, put it at the head to keep
167fcf3ce44SJohn Forte 	 * the CommandTimeout valid.
168fcf3ce44SJohn Forte 	 */
169fcf3ce44SJohn Forte 	if (icmdp->cmd_lbolt_active == 0) {
170fcf3ce44SJohn Forte 		icmdp->cmd_lbolt_active = ddi_get_lbolt();
171fcf3ce44SJohn Forte 		iscsi_enqueue_cmd_tail(&icp->conn_queue_active.head,
172fcf3ce44SJohn Forte 		    &icp->conn_queue_active.tail, icmdp);
173fcf3ce44SJohn Forte 	} else if ((icp->conn_queue_active.head != NULL) &&
174fcf3ce44SJohn Forte 	    (icmdp->cmd_lbolt_active <
175fcf3ce44SJohn Forte 	    icp->conn_queue_active.head->cmd_lbolt_active)) {
176fcf3ce44SJohn Forte 		iscsi_enqueue_cmd_head(&icp->conn_queue_active.head,
177fcf3ce44SJohn Forte 		    &icp->conn_queue_active.tail, icmdp);
178fcf3ce44SJohn Forte 	} else {
179fcf3ce44SJohn Forte 		iscsi_enqueue_cmd_tail(&icp->conn_queue_active.head,
180fcf3ce44SJohn Forte 		    &icp->conn_queue_active.tail, icmdp);
181fcf3ce44SJohn Forte 	}
182fcf3ce44SJohn Forte 	icp->conn_queue_active.count++;
183fcf3ce44SJohn Forte 
184fcf3ce44SJohn Forte 	if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
185fcf3ce44SJohn Forte 		KSTAT_RUNQ_ENTER(isp);
186fcf3ce44SJohn Forte 	}
187fcf3ce44SJohn Forte }
188fcf3ce44SJohn Forte 
189fcf3ce44SJohn Forte /*
190fcf3ce44SJohn Forte  * iscsi_dequeue_active_cmd - used to remove a command from a active queue
191fcf3ce44SJohn Forte  */
192fcf3ce44SJohn Forte void
iscsi_dequeue_active_cmd(iscsi_conn_t * icp,iscsi_cmd_t * icmdp)193fcf3ce44SJohn Forte iscsi_dequeue_active_cmd(iscsi_conn_t *icp, iscsi_cmd_t *icmdp)
194fcf3ce44SJohn Forte {
195fcf3ce44SJohn Forte 	iscsi_status_t	rval	= ISCSI_STATUS_SUCCESS;
196fcf3ce44SJohn Forte 	iscsi_sess_t	*isp	= NULL;
197fcf3ce44SJohn Forte 
198fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
199fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
200fcf3ce44SJohn Forte 	isp = icp->conn_sess;
201fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
202fcf3ce44SJohn Forte 	ASSERT(mutex_owned(&icp->conn_queue_active.mutex));
203fcf3ce44SJohn Forte 
204fcf3ce44SJohn Forte 	rval = iscsi_dequeue_cmd(&icp->conn_queue_active.head,
205fcf3ce44SJohn Forte 	    &icp->conn_queue_active.tail, icmdp);
206fcf3ce44SJohn Forte 
207fcf3ce44SJohn Forte 	if (ISCSI_SUCCESS(rval)) {
208fcf3ce44SJohn Forte 		icp->conn_queue_active.count--;
209fcf3ce44SJohn Forte 
210fcf3ce44SJohn Forte 		if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
211fcf3ce44SJohn Forte 			if (((kstat_io_t *)(&isp->stats.ks_io_data))->rcnt) {
212fcf3ce44SJohn Forte 				KSTAT_RUNQ_EXIT(isp);
213fcf3ce44SJohn Forte 			} else {
214fcf3ce44SJohn Forte 				cmn_err(CE_WARN,
215fcf3ce44SJohn Forte 				    "kstat rcnt == 0 when exiting runq,"
216fcf3ce44SJohn Forte 				    " please check\n");
217fcf3ce44SJohn Forte 			}
218fcf3ce44SJohn Forte 		}
219fcf3ce44SJohn Forte 	} else {
220fcf3ce44SJohn Forte 		ASSERT(FALSE);
221fcf3ce44SJohn Forte 	}
222fcf3ce44SJohn Forte }
223fcf3ce44SJohn Forte 
22430e7468fSPeter Dunlap /*
22530e7468fSPeter Dunlap  * iscsi_enqueue_idm_aborting_cmd - used to add a command to the queue
22630e7468fSPeter Dunlap  * representing command waiting for a callback from IDM for aborting
22730e7468fSPeter Dunlap  *
22830e7468fSPeter Dunlap  * Not sorted
22930e7468fSPeter Dunlap  */
23030e7468fSPeter Dunlap void
iscsi_enqueue_idm_aborting_cmd(iscsi_conn_t * icp,iscsi_cmd_t * icmdp)23130e7468fSPeter Dunlap iscsi_enqueue_idm_aborting_cmd(iscsi_conn_t *icp, iscsi_cmd_t *icmdp)
23230e7468fSPeter Dunlap {
23330e7468fSPeter Dunlap 	iscsi_sess_t		*isp    = NULL;
23430e7468fSPeter Dunlap 
23530e7468fSPeter Dunlap 	ASSERT(icp != NULL);
23630e7468fSPeter Dunlap 	ASSERT(icmdp != NULL);
23730e7468fSPeter Dunlap 	isp = icp->conn_sess;
23830e7468fSPeter Dunlap 	ASSERT(isp != NULL);
23930e7468fSPeter Dunlap 	ASSERT(icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI);
24030e7468fSPeter Dunlap 	ASSERT(mutex_owned(&icp->conn_queue_idm_aborting.mutex));
24130e7468fSPeter Dunlap 
24230e7468fSPeter Dunlap 	icmdp->cmd_state = ISCSI_CMD_STATE_IDM_ABORTING;
24330e7468fSPeter Dunlap 	icmdp->cmd_lbolt_idm_aborting = ddi_get_lbolt();
24430e7468fSPeter Dunlap 	iscsi_enqueue_cmd_tail(&icp->conn_queue_idm_aborting.head,
24530e7468fSPeter Dunlap 	    &icp->conn_queue_idm_aborting.tail, icmdp);
24630e7468fSPeter Dunlap 	icp->conn_queue_idm_aborting.count++;
24730e7468fSPeter Dunlap }
24830e7468fSPeter Dunlap 
24930e7468fSPeter Dunlap /*
25030e7468fSPeter Dunlap  * iscsi_dequeue_idm_aborting_cmd - used to remove a command from the queue
25130e7468fSPeter Dunlap  * representing commands waiting for a callback from IDM for aborting.
25230e7468fSPeter Dunlap  */
25330e7468fSPeter Dunlap void
iscsi_dequeue_idm_aborting_cmd(iscsi_conn_t * icp,iscsi_cmd_t * icmdp)25430e7468fSPeter Dunlap iscsi_dequeue_idm_aborting_cmd(iscsi_conn_t *icp, iscsi_cmd_t *icmdp)
25530e7468fSPeter Dunlap {
25630e7468fSPeter Dunlap 	iscsi_sess_t	*isp	= NULL;
25730e7468fSPeter Dunlap 
25830e7468fSPeter Dunlap 	ASSERT(icp != NULL);
25930e7468fSPeter Dunlap 	ASSERT(icmdp != NULL);
26030e7468fSPeter Dunlap 	isp = icp->conn_sess;
26130e7468fSPeter Dunlap 	ASSERT(isp != NULL);
26230e7468fSPeter Dunlap 	ASSERT(mutex_owned(&icp->conn_queue_idm_aborting.mutex));
26330e7468fSPeter Dunlap 
26430e7468fSPeter Dunlap 	(void) iscsi_dequeue_cmd(&icp->conn_queue_idm_aborting.head,
26530e7468fSPeter Dunlap 	    &icp->conn_queue_idm_aborting.tail, icmdp);
26630e7468fSPeter Dunlap 	icp->conn_queue_idm_aborting.count--;
26730e7468fSPeter Dunlap }
26830e7468fSPeter Dunlap 
269fcf3ce44SJohn Forte /*
270fcf3ce44SJohn Forte  * iscsi_enqueue_completed_cmd - used to add a command in completion queue
271fcf3ce44SJohn Forte  */
272fcf3ce44SJohn Forte void
iscsi_enqueue_completed_cmd(iscsi_sess_t * isp,iscsi_cmd_t * icmdp)273fcf3ce44SJohn Forte iscsi_enqueue_completed_cmd(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
274fcf3ce44SJohn Forte {
275fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
276fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
277fcf3ce44SJohn Forte 
278fcf3ce44SJohn Forte 	mutex_enter(&isp->sess_queue_completion.mutex);
279fcf3ce44SJohn Forte 	if (icmdp->cmd_state != ISCSI_CMD_STATE_COMPLETED) {
280fcf3ce44SJohn Forte 		icmdp->cmd_state = ISCSI_CMD_STATE_COMPLETED;
281fcf3ce44SJohn Forte 	} else {
282fcf3ce44SJohn Forte 		/*
283fcf3ce44SJohn Forte 		 * This command has already been completed, probably
284fcf3ce44SJohn Forte 		 * through the abort code path. It should  be in
285fcf3ce44SJohn Forte 		 * the process of being returned to to the upper
286fcf3ce44SJohn Forte 		 * layers, so do nothing.
287fcf3ce44SJohn Forte 		 */
288fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_queue_completion.mutex);
289fcf3ce44SJohn Forte 		return;
290fcf3ce44SJohn Forte 	}
291fcf3ce44SJohn Forte 	iscsi_enqueue_cmd_tail(&isp->sess_queue_completion.head,
292fcf3ce44SJohn Forte 	    &isp->sess_queue_completion.tail, icmdp);
293fcf3ce44SJohn Forte 	++isp->sess_queue_completion.count;
294fcf3ce44SJohn Forte 	mutex_exit(&isp->sess_queue_completion.mutex);
295fcf3ce44SJohn Forte 
296*49311b35SJack Meng 	(void) iscsi_thread_send_wakeup(isp->sess_ic_thread);
297fcf3ce44SJohn Forte }
298fcf3ce44SJohn Forte 
299fcf3ce44SJohn Forte /*
300fcf3ce44SJohn Forte  * iscsi_move_queue - used to move the whole contents of a queue
301fcf3ce44SJohn Forte  *
302fcf3ce44SJohn Forte  *   The source queue has to be initialized.  Its mutex is entered before
303fcf3ce44SJohn Forte  * doing the actual move.  The destination queue should be initialized.
304fcf3ce44SJohn Forte  * This function is intended to move a queue located in a shared location
305fcf3ce44SJohn Forte  * into local space.  No mutex is needed for the destination queue.
306fcf3ce44SJohn Forte  */
307fcf3ce44SJohn Forte void
iscsi_move_queue(iscsi_queue_t * src_queue,iscsi_queue_t * dst_queue)308fcf3ce44SJohn Forte iscsi_move_queue(
309fcf3ce44SJohn Forte 	iscsi_queue_t	*src_queue,
310fcf3ce44SJohn Forte 	iscsi_queue_t	*dst_queue
311fcf3ce44SJohn Forte )
312fcf3ce44SJohn Forte {
313fcf3ce44SJohn Forte 	ASSERT(src_queue != NULL);
314fcf3ce44SJohn Forte 	ASSERT(dst_queue != NULL);
315fcf3ce44SJohn Forte 	mutex_enter(&src_queue->mutex);
316fcf3ce44SJohn Forte 	dst_queue->count = src_queue->count;
317fcf3ce44SJohn Forte 	dst_queue->head  = src_queue->head;
318fcf3ce44SJohn Forte 	dst_queue->tail  = src_queue->tail;
319fcf3ce44SJohn Forte 	src_queue->count = 0;
320fcf3ce44SJohn Forte 	src_queue->head  = NULL;
321fcf3ce44SJohn Forte 	src_queue->tail  = NULL;
322fcf3ce44SJohn Forte 	mutex_exit(&src_queue->mutex);
323fcf3ce44SJohn Forte }
324fcf3ce44SJohn Forte 
325fcf3ce44SJohn Forte /*
326fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
327fcf3ce44SJohn Forte  * | private functions							|
328fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
329fcf3ce44SJohn Forte  */
330fcf3ce44SJohn Forte 
331fcf3ce44SJohn Forte /*
332fcf3ce44SJohn Forte  * iscsi_dequeue_cmd - used to remove a command from a queue
333fcf3ce44SJohn Forte  */
334fcf3ce44SJohn Forte iscsi_status_t
iscsi_dequeue_cmd(iscsi_cmd_t ** head,iscsi_cmd_t ** tail,iscsi_cmd_t * icmdp)335fcf3ce44SJohn Forte iscsi_dequeue_cmd(iscsi_cmd_t **head, iscsi_cmd_t **tail, iscsi_cmd_t *icmdp)
336fcf3ce44SJohn Forte {
337fcf3ce44SJohn Forte #ifdef DEBUG
338fcf3ce44SJohn Forte 	iscsi_cmd_t	*tp	= NULL;
339fcf3ce44SJohn Forte #endif
340fcf3ce44SJohn Forte 
341fcf3ce44SJohn Forte 	ASSERT(head != NULL);
342fcf3ce44SJohn Forte 	ASSERT(tail != NULL);
343fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
344fcf3ce44SJohn Forte 
345fcf3ce44SJohn Forte 	if (*head == NULL) {
346fcf3ce44SJohn Forte 		/* empty queue, error */
347fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
348fcf3ce44SJohn Forte 	} else if (*head == *tail) {
349fcf3ce44SJohn Forte 		/* one element queue */
350fcf3ce44SJohn Forte 		if (*head == icmdp) {
351fcf3ce44SJohn Forte 			*head = NULL;
352fcf3ce44SJohn Forte 			*tail = NULL;
353fcf3ce44SJohn Forte 		} else {
354fcf3ce44SJohn Forte 			return (ISCSI_STATUS_INTERNAL_ERROR);
355fcf3ce44SJohn Forte 		}
356fcf3ce44SJohn Forte 	} else {
357fcf3ce44SJohn Forte 		/* multi-element queue */
358fcf3ce44SJohn Forte 		if (*head == icmdp) {
359fcf3ce44SJohn Forte 			/* at the head */
360fcf3ce44SJohn Forte 			*head = icmdp->cmd_next;
361fcf3ce44SJohn Forte 			(*head)->cmd_prev = NULL;
362fcf3ce44SJohn Forte 		} else if (*tail == icmdp) {
363fcf3ce44SJohn Forte 			*tail = icmdp->cmd_prev;
364fcf3ce44SJohn Forte 			(*tail)->cmd_next = NULL;
365fcf3ce44SJohn Forte 		} else {
366fcf3ce44SJohn Forte #ifdef DEBUG
367fcf3ce44SJohn Forte 			/* in the middle? */
368fcf3ce44SJohn Forte 			for (tp = (*head)->cmd_next; (tp != NULL) &&
369fcf3ce44SJohn Forte 			    (tp != icmdp); tp = tp->cmd_next)
370fcf3ce44SJohn Forte 				;
371fcf3ce44SJohn Forte 			if (tp == NULL) {
372fcf3ce44SJohn Forte 				/* not found */
373fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
374fcf3ce44SJohn Forte 			}
375fcf3ce44SJohn Forte #endif
376fcf3ce44SJohn Forte 			if (icmdp->cmd_prev == NULL) {
377fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
378fcf3ce44SJohn Forte 			}
379fcf3ce44SJohn Forte 			icmdp->cmd_prev->cmd_next = icmdp->cmd_next;
380fcf3ce44SJohn Forte 			if (icmdp->cmd_next == NULL) {
381fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
382fcf3ce44SJohn Forte 			}
383fcf3ce44SJohn Forte 			icmdp->cmd_next->cmd_prev = icmdp->cmd_prev;
384fcf3ce44SJohn Forte 		}
385fcf3ce44SJohn Forte 	}
386fcf3ce44SJohn Forte 
387fcf3ce44SJohn Forte 	/* icmdp no longer in the queue */
388fcf3ce44SJohn Forte 	icmdp->cmd_prev = NULL;
389fcf3ce44SJohn Forte 	icmdp->cmd_next = NULL;
390fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
391fcf3ce44SJohn Forte }
392fcf3ce44SJohn Forte 
393fcf3ce44SJohn Forte /*
394fcf3ce44SJohn Forte  * iscsi_enqueue_cmd_head - used to add a command to the head of a queue
395fcf3ce44SJohn Forte  */
396fcf3ce44SJohn Forte void
iscsi_enqueue_cmd_head(iscsi_cmd_t ** head,iscsi_cmd_t ** tail,iscsi_cmd_t * icmdp)397fcf3ce44SJohn Forte iscsi_enqueue_cmd_head(iscsi_cmd_t **head, iscsi_cmd_t **tail,
398fcf3ce44SJohn Forte     iscsi_cmd_t *icmdp)
399fcf3ce44SJohn Forte {
400fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
401fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_next == NULL);
402fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_prev == NULL);
403fcf3ce44SJohn Forte 	ASSERT(icmdp != *head);
404fcf3ce44SJohn Forte 	ASSERT(icmdp != *tail);
405fcf3ce44SJohn Forte 
406fcf3ce44SJohn Forte 	if (*head == NULL) {
407fcf3ce44SJohn Forte 		/* empty queue */
408fcf3ce44SJohn Forte 		*head = *tail = icmdp;
409fcf3ce44SJohn Forte 		icmdp->cmd_prev = NULL;
410fcf3ce44SJohn Forte 		icmdp->cmd_next = NULL;
411fcf3ce44SJohn Forte 	} else {
412fcf3ce44SJohn Forte 		/* non-empty queue */
413fcf3ce44SJohn Forte 		icmdp->cmd_next = *head;
414fcf3ce44SJohn Forte 		icmdp->cmd_prev = NULL;
415fcf3ce44SJohn Forte 		(*head)->cmd_prev = icmdp;
416fcf3ce44SJohn Forte 		*head = icmdp;
417fcf3ce44SJohn Forte 	}
418fcf3ce44SJohn Forte }
419fcf3ce44SJohn Forte 
420fcf3ce44SJohn Forte /*
421fcf3ce44SJohn Forte  * iscsi_enqueue_cmd_tail - used to add a command to the tail of a queue
422fcf3ce44SJohn Forte  */
423fcf3ce44SJohn Forte static void
iscsi_enqueue_cmd_tail(iscsi_cmd_t ** head,iscsi_cmd_t ** tail,iscsi_cmd_t * icmdp)424fcf3ce44SJohn Forte iscsi_enqueue_cmd_tail(iscsi_cmd_t **head, iscsi_cmd_t **tail,
425fcf3ce44SJohn Forte     iscsi_cmd_t *icmdp)
426fcf3ce44SJohn Forte {
427fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
428fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_next == NULL);
429fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_prev == NULL);
430fcf3ce44SJohn Forte 	ASSERT(icmdp != *head);
431fcf3ce44SJohn Forte 	ASSERT(icmdp != *tail);
432fcf3ce44SJohn Forte 
433fcf3ce44SJohn Forte 	if (*head == NULL) {
434fcf3ce44SJohn Forte 		/* empty queue */
435fcf3ce44SJohn Forte 		*head = *tail = icmdp;
436fcf3ce44SJohn Forte 		icmdp->cmd_prev = NULL;
437fcf3ce44SJohn Forte 		icmdp->cmd_next = NULL;
438fcf3ce44SJohn Forte 	} else {
439fcf3ce44SJohn Forte 		/* non-empty queue */
440fcf3ce44SJohn Forte 		icmdp->cmd_next = NULL;
441fcf3ce44SJohn Forte 		icmdp->cmd_prev = *tail;
442fcf3ce44SJohn Forte 		(*tail)->cmd_next = icmdp;
443fcf3ce44SJohn Forte 		*tail = icmdp;
444fcf3ce44SJohn Forte 	}
445fcf3ce44SJohn Forte }
446