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 /*
22*30e7468fSPeter Dunlap  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23fcf3ce44SJohn Forte  * Use is subject to license terms.
24fcf3ce44SJohn Forte  *
25fcf3ce44SJohn Forte  * iSCSI command interfaces
26fcf3ce44SJohn Forte  */
27fcf3ce44SJohn Forte 
28fcf3ce44SJohn Forte #include "iscsi.h"
29fcf3ce44SJohn Forte 
30fcf3ce44SJohn Forte /* internal interfaces */
31fcf3ce44SJohn Forte static void iscsi_cmd_state_free(iscsi_cmd_t *icmdp,
32fcf3ce44SJohn Forte     iscsi_cmd_event_t event, void *arg);
33fcf3ce44SJohn Forte static void iscsi_cmd_state_pending(iscsi_cmd_t *icmdp,
34fcf3ce44SJohn Forte     iscsi_cmd_event_t event, void *arg);
35fcf3ce44SJohn Forte static void iscsi_cmd_state_active(iscsi_cmd_t *icmdp,
36fcf3ce44SJohn Forte     iscsi_cmd_event_t event, void *arg);
37fcf3ce44SJohn Forte static void iscsi_cmd_state_aborting(iscsi_cmd_t *icmdp,
38fcf3ce44SJohn Forte     iscsi_cmd_event_t event, void *arg);
39*30e7468fSPeter Dunlap static void iscsi_cmd_state_idm_aborting(iscsi_cmd_t *icmdp,
40*30e7468fSPeter Dunlap     iscsi_cmd_event_t event, void *arg);
41fcf3ce44SJohn Forte static void iscsi_cmd_state_completed(iscsi_cmd_t *icmdp,
42fcf3ce44SJohn Forte     iscsi_cmd_event_t event, void *arg);
43fcf3ce44SJohn Forte static char *iscsi_cmd_state_str(iscsi_cmd_state_t state);
44fcf3ce44SJohn Forte static char *iscsi_cmd_event_str(iscsi_cmd_event_t event);
45fcf3ce44SJohn Forte /* LINTED E_STATIC_UNUSED */
46fcf3ce44SJohn Forte static char *iscsi_cmd_type_str(iscsi_cmd_type_t type);
47fcf3ce44SJohn Forte 
48fcf3ce44SJohn Forte #define	ISCSI_INTERNAL_CMD_TIMEOUT	60
49fcf3ce44SJohn Forte 
50fcf3ce44SJohn Forte #define	ISCSI_CMD_ISSUE_CALLBACK(icmdp, status)	\
51fcf3ce44SJohn Forte 	icmdp->cmd_completed = B_TRUE;		\
52fcf3ce44SJohn Forte 	icmdp->cmd_result = status;		\
53fcf3ce44SJohn Forte 	cv_broadcast(&icmdp->cmd_completion);
54fcf3ce44SJohn Forte 
55fcf3ce44SJohn Forte #define	ISCSI_CMD_SET_REASON_STAT(icmdp, reason, stat)	\
56fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.pkt->pkt_reason = reason;	\
57fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.pkt->pkt_statistics = stat;
58fcf3ce44SJohn Forte 
59fcf3ce44SJohn Forte /*
60fcf3ce44SJohn Forte  * The following private tunable, settable via
61fcf3ce44SJohn Forte  *	set iscsi:iscsi_cmd_timeout_factor = 2
62fcf3ce44SJohn Forte  * in /etc/system, provides customer relief for configurations experiencing
63fcf3ce44SJohn Forte  * SCSI command timeouts due to high-latency/high-loss network connections
64fcf3ce44SJohn Forte  * or slow target response (possibly due to backing store issues). If frequent
65fcf3ce44SJohn Forte  * use of this tunable is necessary, a beter mechanism must be provided.
66fcf3ce44SJohn Forte  */
67fcf3ce44SJohn Forte int	iscsi_cmd_timeout_factor = 1;
68fcf3ce44SJohn Forte 
69fcf3ce44SJohn Forte /*
70fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
71fcf3ce44SJohn Forte  * | External Command Interfaces					|
72fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
73fcf3ce44SJohn Forte  */
74fcf3ce44SJohn Forte 
75fcf3ce44SJohn Forte /*
76fcf3ce44SJohn Forte  * iscsi_cmd_state_machine - This function is used to drive the
77fcf3ce44SJohn Forte  * state machine of the internal iscsi commands.  It takes in a command
78fcf3ce44SJohn Forte  * and the associated event affecting the command.
79fcf3ce44SJohn Forte  *
80fcf3ce44SJohn Forte  * 7.1.3  Command State Diagram for an Initiator
81fcf3ce44SJohn Forte  *      Symbolic Names for States:
82fcf3ce44SJohn Forte  *      C1: FREE        - State on instantiation, or after successful
83fcf3ce44SJohn Forte  *                        completion.
84fcf3ce44SJohn Forte  *      C2: PENDING     - Command is in the session's pending queue awaiting
85fcf3ce44SJohn Forte  *                        its turn to be sent on the wire.
86fcf3ce44SJohn Forte  *      C3: ACTIVE      - Command has been sent on the wire and is
87fcf3ce44SJohn Forte  *                        awaiting completion.
88fcf3ce44SJohn Forte  *      C4: ABORTING    - Command which was sent on the wire has not timed
89fcf3ce44SJohn Forte  *                        out or been requested to abort by an upper layer
90fcf3ce44SJohn Forte  *                        driver.  At this point there is a task management
91fcf3ce44SJohn Forte  *                        command in the active queue trying to abort the task.
92*30e7468fSPeter Dunlap  *	C4': IDM ABORTING - SCSI command is owned by IDM and idm_task_abort
93*30e7468fSPeter Dunlap  *                          has been called for this command.
94fcf3ce44SJohn Forte  *      C5: COMPLETED	- Command which is ready to complete via pkt callback.
95fcf3ce44SJohn Forte  *
96fcf3ce44SJohn Forte  *      The state diagram is as follows:
97fcf3ce44SJohn Forte  *               -------
98fcf3ce44SJohn Forte  *              / C1    \
99fcf3ce44SJohn Forte  *    I-------->\       /<------------
100fcf3ce44SJohn Forte  *    N|         ---+---             |
101fcf3ce44SJohn Forte  *    T|            |E1              |
102fcf3ce44SJohn Forte  *    E|            V                |
103fcf3ce44SJohn Forte  *    R|         -------             |
104fcf3ce44SJohn Forte  *    N+--------/ C2    \            |
105fcf3ce44SJohn Forte  *    A|  E4/6/7\       /--------    |
106fcf3ce44SJohn Forte  *    L|         ---+---  E4/6/7|    |
107*30e7468fSPeter Dunlap  *     |            |E2    E10  |    |
108fcf3ce44SJohn Forte  *    C|            V           | S  |
109fcf3ce44SJohn Forte  *    M|         _______        | C  |
110fcf3ce44SJohn Forte  *    D+--------/ C3    \       | S  |
111fcf3ce44SJohn Forte  *    S E3/4/6/7\       /-------+ I  |
112*30e7468fSPeter Dunlap  *              /---+---E3/4/6/7|    |
113*30e7468fSPeter Dunlap  *             /    |      E9/10|    |
114*30e7468fSPeter Dunlap  *      ------/ E4/6|           | C  |
115*30e7468fSPeter Dunlap  *      |           V           | M  |
116*30e7468fSPeter Dunlap  *    E7|        -------        | D  |
117*30e7468fSPeter Dunlap  *  SCSI|    - >/ C4    \       | S  |
118*30e7468fSPeter Dunlap  *      |   /   \       /-------+    |
119*30e7468fSPeter Dunlap  *      |   |    ---+---E3/6/7/9|    |
120*30e7468fSPeter Dunlap  *      |   |  E4|  |           V   /E8
121*30e7468fSPeter Dunlap  *      |   ------  |        -------
122*30e7468fSPeter Dunlap  *      +-\         /       / C5    \
123*30e7468fSPeter Dunlap  *      V  \-------/  /---->\       /
124*30e7468fSPeter Dunlap  *   -------    E7   /       ---+---
125*30e7468fSPeter Dunlap  *  / C4'   \       /
126*30e7468fSPeter Dunlap  *  \       /------/ E9
127*30e7468fSPeter Dunlap  *   -------
128fcf3ce44SJohn Forte  *
129fcf3ce44SJohn Forte  * The state transition table is as follows:
130fcf3ce44SJohn Forte  *
131*30e7468fSPeter Dunlap  *         +---------+---+---+-----+----+--------------+
132*30e7468fSPeter Dunlap  *         |C1       |C2 |C3 |C4   |C4' |C5            |
133*30e7468fSPeter Dunlap  *      ---+---------+---+---+-----+----+--------------+
134*30e7468fSPeter Dunlap  *       C1| -       |E1 | - | -   | -  |              |
135*30e7468fSPeter Dunlap  *      ---+---------+---+---+-----+----+--------------+
136*30e7468fSPeter Dunlap  *       C2|E4/6/7   |-  |E2 | -   | -  |E4/6/7/10     |
137*30e7468fSPeter Dunlap  *      ---+---------+---+---+-----+----+--------------+
138*30e7468fSPeter Dunlap  *       C3|E3/4/6/7 |-  |-  |E4/6 |E7  |E3/4/6/7/9/10 |
139*30e7468fSPeter Dunlap  *      ---+---------+---+---+-----+----+--------------+
140*30e7468fSPeter Dunlap  *       C4|         |-  |-  |E4   |E7  |E3/6/7/9      |
141*30e7468fSPeter Dunlap  *      ---+---------+---+---+-----+----+--------------+
142*30e7468fSPeter Dunlap  *      C4'|         |-  |-  |-    |-   |E9            |
143*30e7468fSPeter Dunlap  *      ---+---------+---+---+-----+----+--------------+
144*30e7468fSPeter Dunlap  *       C5|E8       |   |   |     |    |              |
145*30e7468fSPeter Dunlap  *      ---+---------+---+---+-----+----+--------------+
146fcf3ce44SJohn Forte  *
147fcf3ce44SJohn Forte  * Event definitions:
148fcf3ce44SJohn Forte  *
149fcf3ce44SJohn Forte  * -E1: Command was requested to be sent on wire
150fcf3ce44SJohn Forte  * -E2: Command was submitted and now active on wire
151fcf3ce44SJohn Forte  * -E3: Command was successfully completed
152fcf3ce44SJohn Forte  *	- SCSI command is move to completion queue
153fcf3ce44SJohn Forte  *	- ABORT/RESET/etc are completed.
154fcf3ce44SJohn Forte  * -E4: Command has been requested to abort
155fcf3ce44SJohn Forte  *	- SCSI command in pending queue will be returned
156fcf3ce44SJohn Forte  *		to caller with aborted status.
157fcf3ce44SJohn Forte  *	- SCSI command state updated and iscsi_handle_abort()
158fcf3ce44SJohn Forte  *		will be called.
159fcf3ce44SJohn Forte  *	- SCSI command with ABORTING state has already
160fcf3ce44SJohn Forte  *		been requested to abort ignore request.
161fcf3ce44SJohn Forte  *	- ABORT/RESET commands will be destroyed and the
162fcf3ce44SJohn Forte  *		caller will be notify of the failure.
163fcf3ce44SJohn Forte  *	- All other commands will just be destroyed.
164fcf3ce44SJohn Forte  * -E6: Command has timed out
165fcf3ce44SJohn Forte  *	- SCSI commands in pending queue will be returned up the
166fcf3ce44SJohn Forte  *		stack with TIMEOUT errors.
167fcf3ce44SJohn Forte  *	- SCSI commands in the active queue and timed out
168fcf3ce44SJohn Forte  *		will be moved to the aborting queue.
169fcf3ce44SJohn Forte  *	- SCSI commands in ABORTING state will be returned up
170fcf3ce44SJohn Forte  *		up the stack with TIMEOUT errors.
171fcf3ce44SJohn Forte  *	- ABORT/RESET commands will be destroyed and the caller
172fcf3ce44SJohn Forte  *		notified of the failure.
173fcf3ce44SJohn Forte  *	- All other commands will just be detroyed.
174fcf3ce44SJohn Forte  * -E7: Connection has encountered a problem
175fcf3ce44SJohn Forte  * -E8:	Command has completed
176fcf3ce44SJohn Forte  *	- Only SCSI cmds should receive these events
177fcf3ce44SJohn Forte  *		and reach the command state.
178*30e7468fSPeter Dunlap  * -E9: Callback received for previous idm_task_abort request
179*30e7468fSPeter Dunlap  * -E10: The command this abort was associated with has terminated on its own
180fcf3ce44SJohn Forte  */
181fcf3ce44SJohn Forte void
182fcf3ce44SJohn Forte iscsi_cmd_state_machine(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
183fcf3ce44SJohn Forte {
184fcf3ce44SJohn Forte 	boolean_t	release_lock = B_TRUE;
185fcf3ce44SJohn Forte 
186fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
187fcf3ce44SJohn Forte 	ASSERT(arg != NULL);
188fcf3ce44SJohn Forte 
189fcf3ce44SJohn Forte 	DTRACE_PROBE3(event, iscsi_cmd_t *, icmdp, char *,
190fcf3ce44SJohn Forte 	    iscsi_cmd_state_str(icmdp->cmd_state),
191fcf3ce44SJohn Forte 	    char *, iscsi_cmd_event_str(event));
192fcf3ce44SJohn Forte 
193fcf3ce44SJohn Forte 	mutex_enter(&icmdp->cmd_mutex);
194*30e7468fSPeter Dunlap 
195*30e7468fSPeter Dunlap 	/* Audit event */
196*30e7468fSPeter Dunlap 	idm_sm_audit_event(&icmdp->cmd_state_audit,
197*30e7468fSPeter Dunlap 	    SAS_ISCSI_CMD, icmdp->cmd_state, event, (uintptr_t)arg);
198*30e7468fSPeter Dunlap 
199fcf3ce44SJohn Forte 	icmdp->cmd_prev_state = icmdp->cmd_state;
200fcf3ce44SJohn Forte 	switch (icmdp->cmd_state) {
201fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_FREE:
202fcf3ce44SJohn Forte 		iscsi_cmd_state_free(icmdp, event, arg);
203fcf3ce44SJohn Forte 		break;
204fcf3ce44SJohn Forte 
205fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_PENDING:
206fcf3ce44SJohn Forte 		iscsi_cmd_state_pending(icmdp, event, arg);
207fcf3ce44SJohn Forte 		break;
208fcf3ce44SJohn Forte 
209fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_ACTIVE:
210fcf3ce44SJohn Forte 		iscsi_cmd_state_active(icmdp, event, arg);
211fcf3ce44SJohn Forte 		break;
212fcf3ce44SJohn Forte 
213fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_ABORTING:
214fcf3ce44SJohn Forte 		iscsi_cmd_state_aborting(icmdp, event, arg);
215fcf3ce44SJohn Forte 		break;
216fcf3ce44SJohn Forte 
217*30e7468fSPeter Dunlap 	case ISCSI_CMD_STATE_IDM_ABORTING:
218*30e7468fSPeter Dunlap 		iscsi_cmd_state_idm_aborting(icmdp, event, arg);
219*30e7468fSPeter Dunlap 		break;
220*30e7468fSPeter Dunlap 
221fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_COMPLETED:
222fcf3ce44SJohn Forte 		iscsi_cmd_state_completed(icmdp, event, arg);
223fcf3ce44SJohn Forte 
224fcf3ce44SJohn Forte 		/*
225fcf3ce44SJohn Forte 		 * Once completed event is processed we DO NOT
226fcf3ce44SJohn Forte 		 * want to touch it again because the caller
227fcf3ce44SJohn Forte 		 * (sd, st, etc) may have freed the command.
228fcf3ce44SJohn Forte 		 */
229fcf3ce44SJohn Forte 		release_lock = B_FALSE;
230fcf3ce44SJohn Forte 		break;
231fcf3ce44SJohn Forte 
232fcf3ce44SJohn Forte 	default:
233fcf3ce44SJohn Forte 		ASSERT(FALSE);
234fcf3ce44SJohn Forte 	}
235fcf3ce44SJohn Forte 
236fcf3ce44SJohn Forte 	if (release_lock == B_TRUE) {
237*30e7468fSPeter Dunlap 		/* Audit state if not completed */
238*30e7468fSPeter Dunlap 		idm_sm_audit_state_change(&icmdp->cmd_state_audit,
239*30e7468fSPeter Dunlap 		    SAS_ISCSI_CMD, icmdp->cmd_prev_state, icmdp->cmd_state);
240*30e7468fSPeter Dunlap 
241d233de7eSJack Meng 		if (!(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_FREE) ||
242d233de7eSJack Meng 		    !(icmdp->cmd_misc_flags &
243d233de7eSJack Meng 		    ISCSI_CMD_MISCFLAG_INTERNAL)) {
244fcf3ce44SJohn Forte 			mutex_exit(&icmdp->cmd_mutex);
245fcf3ce44SJohn Forte 			return;
246fcf3ce44SJohn Forte 		}
247fcf3ce44SJohn Forte 		mutex_exit(&icmdp->cmd_mutex);
248fcf3ce44SJohn Forte 		iscsi_cmd_free(icmdp);
249fcf3ce44SJohn Forte 	}
250fcf3ce44SJohn Forte }
251fcf3ce44SJohn Forte 
252fcf3ce44SJohn Forte /*
253fcf3ce44SJohn Forte  * iscsi_cmd_alloc -
254fcf3ce44SJohn Forte  *
255fcf3ce44SJohn Forte  */
256fcf3ce44SJohn Forte iscsi_cmd_t *
257fcf3ce44SJohn Forte iscsi_cmd_alloc(iscsi_conn_t *icp, int km_flags)
258fcf3ce44SJohn Forte {
259fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp;
260fcf3ce44SJohn Forte 
261fcf3ce44SJohn Forte 	icmdp = kmem_zalloc(sizeof (iscsi_cmd_t), km_flags);
262fcf3ce44SJohn Forte 	if (icmdp) {
263fcf3ce44SJohn Forte 		icmdp->cmd_sig		= ISCSI_SIG_CMD;
264fcf3ce44SJohn Forte 		icmdp->cmd_state	= ISCSI_CMD_STATE_FREE;
265fcf3ce44SJohn Forte 		icmdp->cmd_conn		= icp;
266d233de7eSJack Meng 		icmdp->cmd_misc_flags	|= ISCSI_CMD_MISCFLAG_INTERNAL;
267*30e7468fSPeter Dunlap 		idm_sm_audit_init(&icmdp->cmd_state_audit);
268fcf3ce44SJohn Forte 		mutex_init(&icmdp->cmd_mutex, NULL, MUTEX_DRIVER, NULL);
269fcf3ce44SJohn Forte 		cv_init(&icmdp->cmd_completion, NULL, CV_DRIVER, NULL);
270fcf3ce44SJohn Forte 	}
271fcf3ce44SJohn Forte 	return (icmdp);
272fcf3ce44SJohn Forte }
273fcf3ce44SJohn Forte 
274fcf3ce44SJohn Forte /*
275fcf3ce44SJohn Forte  * iscsi_cmd_free -
276fcf3ce44SJohn Forte  *
277fcf3ce44SJohn Forte  */
278fcf3ce44SJohn Forte void
279fcf3ce44SJohn Forte iscsi_cmd_free(iscsi_cmd_t *icmdp)
280fcf3ce44SJohn Forte {
281fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
282fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_sig == ISCSI_SIG_CMD);
283fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_FREE);
284fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_next == NULL);
285fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_prev == NULL);
286d233de7eSJack Meng 	ASSERT(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_INTERNAL);
287*30e7468fSPeter Dunlap 	if (icmdp->cmd_type == ISCSI_CMD_TYPE_ABORT)
288fcf3ce44SJohn Forte 		ASSERT(icmdp->cmd_un.abort.icmdp == NULL);
289fcf3ce44SJohn Forte 	else if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
290fcf3ce44SJohn Forte 		ASSERT(icmdp->cmd_un.scsi.r2t_icmdp == NULL);
291fcf3ce44SJohn Forte 		ASSERT(icmdp->cmd_un.scsi.abort_icmdp == NULL);
292fcf3ce44SJohn Forte 	}
293fcf3ce44SJohn Forte 	mutex_destroy(&icmdp->cmd_mutex);
294fcf3ce44SJohn Forte 	cv_destroy(&icmdp->cmd_completion);
295fcf3ce44SJohn Forte 	kmem_free(icmdp, sizeof (iscsi_cmd_t));
296fcf3ce44SJohn Forte }
297fcf3ce44SJohn Forte 
298fcf3ce44SJohn Forte /*
299fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
300fcf3ce44SJohn Forte  * | Internal Command Interfaces					|
301fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
302fcf3ce44SJohn Forte  */
303fcf3ce44SJohn Forte /*
304fcf3ce44SJohn Forte  * iscsi_cmd_state_free -
305fcf3ce44SJohn Forte  *
306fcf3ce44SJohn Forte  */
307fcf3ce44SJohn Forte static void
308fcf3ce44SJohn Forte iscsi_cmd_state_free(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
309fcf3ce44SJohn Forte {
310fcf3ce44SJohn Forte 	iscsi_sess_t	*isp		= (iscsi_sess_t *)arg;
311fcf3ce44SJohn Forte 
312fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
313fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_FREE);
314fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
315fcf3ce44SJohn Forte 
316fcf3ce44SJohn Forte 	/* switch on event change */
317fcf3ce44SJohn Forte 	switch (event) {
318fcf3ce44SJohn Forte 	/* -E1: Command was requested to be sent on wire */
319fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E1:
320fcf3ce44SJohn Forte 
321fcf3ce44SJohn Forte 		/* setup timestamps and timeouts for this command */
322fcf3ce44SJohn Forte 		icmdp->cmd_lbolt_pending = ddi_get_lbolt();
323fcf3ce44SJohn Forte 		if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
324fcf3ce44SJohn Forte 			/*
325fcf3ce44SJohn Forte 			 * Establish absolute time when command should timeout.
326*30e7468fSPeter Dunlap 			 * For commands that depend on cmdsn window to go
327fcf3ce44SJohn Forte 			 * active, the timeout will be ignored while on
328fcf3ce44SJohn Forte 			 * the pending queue and a new timeout will be
329fcf3ce44SJohn Forte 			 * established when the command goes active.
330fcf3ce44SJohn Forte 			 */
331fcf3ce44SJohn Forte 			if (icmdp->cmd_un.scsi.pkt &&
332fcf3ce44SJohn Forte 			    icmdp->cmd_un.scsi.pkt->pkt_time)
333fcf3ce44SJohn Forte 				icmdp->cmd_lbolt_timeout =
334fcf3ce44SJohn Forte 				    icmdp->cmd_lbolt_pending + SEC_TO_TICK(
335fcf3ce44SJohn Forte 				    icmdp->cmd_un.scsi.pkt->pkt_time *
336fcf3ce44SJohn Forte 				    iscsi_cmd_timeout_factor);
337fcf3ce44SJohn Forte 			else
338fcf3ce44SJohn Forte 				icmdp->cmd_lbolt_timeout = 0;
339fcf3ce44SJohn Forte 		} else {
340fcf3ce44SJohn Forte 			icmdp->cmd_lbolt_timeout = icmdp->cmd_lbolt_pending +
341fcf3ce44SJohn Forte 			    SEC_TO_TICK(ISCSI_INTERNAL_CMD_TIMEOUT *
342fcf3ce44SJohn Forte 			    iscsi_cmd_timeout_factor);
343fcf3ce44SJohn Forte 		}
344fcf3ce44SJohn Forte 
345fcf3ce44SJohn Forte 		/* place into pending queue */
346fcf3ce44SJohn Forte 		iscsi_enqueue_pending_cmd(isp, icmdp);
347fcf3ce44SJohn Forte 
348fcf3ce44SJohn Forte 		break;
349fcf3ce44SJohn Forte 
350fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
351fcf3ce44SJohn Forte 	default:
352fcf3ce44SJohn Forte 		ASSERT(FALSE);
353fcf3ce44SJohn Forte 	}
354fcf3ce44SJohn Forte }
355fcf3ce44SJohn Forte 
356fcf3ce44SJohn Forte /*
357fcf3ce44SJohn Forte  * iscsi_cmd_state_pending -
358fcf3ce44SJohn Forte  *
359fcf3ce44SJohn Forte  */
360fcf3ce44SJohn Forte static void
361fcf3ce44SJohn Forte iscsi_cmd_state_pending(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
362fcf3ce44SJohn Forte {
363fcf3ce44SJohn Forte 	iscsi_status_t	status;
364fcf3ce44SJohn Forte 	iscsi_sess_t	*isp		= (iscsi_sess_t *)arg;
365fcf3ce44SJohn Forte 	boolean_t	free_icmdp	= B_FALSE;
366fcf3ce44SJohn Forte 	int		rval;
367fcf3ce44SJohn Forte 
368fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
369fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_PENDING);
370fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
371fcf3ce44SJohn Forte 
372fcf3ce44SJohn Forte 	/* switch on event change */
373fcf3ce44SJohn Forte 	switch (event) {
374fcf3ce44SJohn Forte 	/* -E2: Command was submitted and now active on wire */
375fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E2:
376fcf3ce44SJohn Forte 
377fcf3ce44SJohn Forte 		/* A connection should have already been assigned */
378*30e7468fSPeter Dunlap 		ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
379fcf3ce44SJohn Forte 		ASSERT(icmdp->cmd_conn != NULL);
380fcf3ce44SJohn Forte 
381fcf3ce44SJohn Forte 		/*
382fcf3ce44SJohn Forte 		 * RESERVE RESOURSES
383fcf3ce44SJohn Forte 		 */
384fcf3ce44SJohn Forte 		switch (icmdp->cmd_type) {
385fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_SCSI:
386fcf3ce44SJohn Forte 			/* check cmdsn window */
387fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
388fcf3ce44SJohn Forte 			if (!iscsi_sna_lte(isp->sess_cmdsn,
389fcf3ce44SJohn Forte 			    isp->sess_maxcmdsn)) {
390fcf3ce44SJohn Forte 				/* cmdsn window closed */
391fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_cmdsn_mutex);
392fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_queue_pending.mutex);
393fcf3ce44SJohn Forte 				isp->sess_window_open = B_FALSE;
394d233de7eSJack Meng 				icmdp->cmd_misc_flags |=
395d233de7eSJack Meng 				    ISCSI_CMD_MISCFLAG_STUCK;
396fcf3ce44SJohn Forte 				return;
397fcf3ce44SJohn Forte 			}
398fcf3ce44SJohn Forte 
399fcf3ce44SJohn Forte 			/* assign itt */
400*30e7468fSPeter Dunlap 			status = iscsi_sess_reserve_scsi_itt(icmdp);
401fcf3ce44SJohn Forte 			if (!ISCSI_SUCCESS(status)) {
402fcf3ce44SJohn Forte 				/* no available itt slots */
403fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_cmdsn_mutex);
404fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_queue_pending.mutex);
405fcf3ce44SJohn Forte 				isp->sess_window_open = B_FALSE;
406d233de7eSJack Meng 				icmdp->cmd_misc_flags |=
407d233de7eSJack Meng 				    ISCSI_CMD_MISCFLAG_STUCK;
408fcf3ce44SJohn Forte 				return;
409fcf3ce44SJohn Forte 			}
410fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
411fcf3ce44SJohn Forte 			break;
412fcf3ce44SJohn Forte 
413fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_ABORT:
414fcf3ce44SJohn Forte 			/*
415fcf3ce44SJohn Forte 			 * Verify ABORT's parent SCSI command is still
416fcf3ce44SJohn Forte 			 * there.  If parent SCSI command is completed
417fcf3ce44SJohn Forte 			 * then there is no longer any reason to abort
418fcf3ce44SJohn Forte 			 * the parent command.  This could occur due
419fcf3ce44SJohn Forte 			 * to a connection or target reset.
420fcf3ce44SJohn Forte 			 */
421fcf3ce44SJohn Forte 			ASSERT(icmdp->cmd_un.abort.icmdp != NULL);
422fcf3ce44SJohn Forte 			if (icmdp->cmd_un.abort.icmdp->cmd_state ==
423fcf3ce44SJohn Forte 			    ISCSI_CMD_STATE_COMPLETED) {
424fcf3ce44SJohn Forte 				iscsi_dequeue_pending_cmd(isp, icmdp);
425fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_queue_pending.mutex);
426fcf3ce44SJohn Forte 
427fcf3ce44SJohn Forte 				mutex_enter(&icmdp->cmd_un.abort.icmdp->
428fcf3ce44SJohn Forte 				    cmd_mutex);
429fcf3ce44SJohn Forte 				icmdp->cmd_un.abort.icmdp->
430fcf3ce44SJohn Forte 				    cmd_un.scsi.abort_icmdp = NULL;
431fcf3ce44SJohn Forte 				cv_broadcast(&icmdp->cmd_un.abort.icmdp->
432fcf3ce44SJohn Forte 				    cmd_completion);
433fcf3ce44SJohn Forte 				mutex_exit(&icmdp->cmd_un.abort.icmdp->
434fcf3ce44SJohn Forte 				    cmd_mutex);
435fcf3ce44SJohn Forte 				icmdp->cmd_un.abort.icmdp = NULL;
436fcf3ce44SJohn Forte 
437fcf3ce44SJohn Forte 				icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
438d233de7eSJack Meng 				icmdp->cmd_misc_flags |=
439d233de7eSJack Meng 				    ISCSI_CMD_MISCFLAG_FREE;
440fcf3ce44SJohn Forte 				return;
441fcf3ce44SJohn Forte 			}
442fcf3ce44SJohn Forte 			/* FALLTHRU */
443fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_RESET:
444fcf3ce44SJohn Forte 			/* FALLTHRU */
445fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_LOGOUT:
446fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
447fcf3ce44SJohn Forte 			/* assign itt */
448fcf3ce44SJohn Forte 			status = iscsi_sess_reserve_itt(isp, icmdp);
449fcf3ce44SJohn Forte 			if (!ISCSI_SUCCESS(status)) {
450fcf3ce44SJohn Forte 				/* no available itt slots */
451fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_cmdsn_mutex);
452fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_queue_pending.mutex);
453fcf3ce44SJohn Forte 				isp->sess_window_open = B_FALSE;
454fcf3ce44SJohn Forte 				return;
455fcf3ce44SJohn Forte 			}
456fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
457fcf3ce44SJohn Forte 			break;
458fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_NOP:
459fcf3ce44SJohn Forte 			/* assign itt, if needed */
460fcf3ce44SJohn Forte 			if (icmdp->cmd_itt == ISCSI_RSVD_TASK_TAG) {
461fcf3ce44SJohn Forte 				/* not expecting a response */
462fcf3ce44SJohn Forte 				free_icmdp = B_TRUE;
463fcf3ce44SJohn Forte 			} else {
464fcf3ce44SJohn Forte 				/* expecting response, assign an itt */
465fcf3ce44SJohn Forte 				mutex_enter(&isp->sess_cmdsn_mutex);
466fcf3ce44SJohn Forte 				/* assign itt */
467fcf3ce44SJohn Forte 				status = iscsi_sess_reserve_itt(isp, icmdp);
468fcf3ce44SJohn Forte 				if (!ISCSI_SUCCESS(status)) {
469fcf3ce44SJohn Forte 					/* no available itt slots */
470fcf3ce44SJohn Forte 					mutex_exit(&isp->sess_cmdsn_mutex);
471fcf3ce44SJohn Forte 					mutex_exit(&isp->sess_queue_pending.
472fcf3ce44SJohn Forte 					    mutex);
473fcf3ce44SJohn Forte 					isp->sess_window_open = B_FALSE;
474fcf3ce44SJohn Forte 					return;
475fcf3ce44SJohn Forte 				}
476fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_cmdsn_mutex);
477fcf3ce44SJohn Forte 			}
478fcf3ce44SJohn Forte 			break;
479fcf3ce44SJohn Forte 
480fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_TEXT:
481fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
482fcf3ce44SJohn Forte 			/* check cmdsn window */
483fcf3ce44SJohn Forte 			if (!iscsi_sna_lte(isp->sess_cmdsn,
484fcf3ce44SJohn Forte 			    isp->sess_maxcmdsn)) {
485fcf3ce44SJohn Forte 				/* cmdsn window closed */
486fcf3ce44SJohn Forte 				isp->sess_window_open = B_FALSE;
487fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_cmdsn_mutex);
488fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_queue_pending.mutex);
489d233de7eSJack Meng 				icmdp->cmd_misc_flags |=
490d233de7eSJack Meng 				    ISCSI_CMD_MISCFLAG_STUCK;
491fcf3ce44SJohn Forte 				return;
492fcf3ce44SJohn Forte 			}
493fcf3ce44SJohn Forte 			if (icmdp->cmd_un.text.stage ==
494fcf3ce44SJohn Forte 			    ISCSI_CMD_TEXT_INITIAL_REQ) {
495fcf3ce44SJohn Forte 				/* assign itt */
496fcf3ce44SJohn Forte 				status = iscsi_sess_reserve_itt(isp, icmdp);
497fcf3ce44SJohn Forte 				if (!ISCSI_SUCCESS(status)) {
498fcf3ce44SJohn Forte 					/* no available itt slots */
499fcf3ce44SJohn Forte 					mutex_exit(&isp->sess_cmdsn_mutex);
500fcf3ce44SJohn Forte 					mutex_exit(&isp->sess_queue_pending.
501fcf3ce44SJohn Forte 					    mutex);
502fcf3ce44SJohn Forte 					isp->sess_window_open = B_FALSE;
503d233de7eSJack Meng 					icmdp->cmd_misc_flags |=
504d233de7eSJack Meng 					    ISCSI_CMD_MISCFLAG_STUCK;
505fcf3ce44SJohn Forte 					return;
506fcf3ce44SJohn Forte 				}
507fcf3ce44SJohn Forte 			}
508fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
509fcf3ce44SJohn Forte 			break;
510fcf3ce44SJohn Forte 
511fcf3ce44SJohn Forte 		default:
512fcf3ce44SJohn Forte 			ASSERT(FALSE);
513fcf3ce44SJohn Forte 		}
514fcf3ce44SJohn Forte 
515fcf3ce44SJohn Forte 		/*
516fcf3ce44SJohn Forte 		 * RESOURCES RESERVED
517fcf3ce44SJohn Forte 		 *
518fcf3ce44SJohn Forte 		 * Now that we have the resources reserved, establish timeout
519fcf3ce44SJohn Forte 		 * for cmd_type values that depend on having an open cmdsn
520fcf3ce44SJohn Forte 		 * window (i.e. cmd_type that called iscsi_sna_lte() above).
521fcf3ce44SJohn Forte 		 */
522fcf3ce44SJohn Forte 		if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
523fcf3ce44SJohn Forte 			if (icmdp->cmd_un.scsi.pkt &&
524fcf3ce44SJohn Forte 			    icmdp->cmd_un.scsi.pkt->pkt_time)
525fcf3ce44SJohn Forte 				icmdp->cmd_lbolt_timeout =
526fcf3ce44SJohn Forte 				    ddi_get_lbolt() + SEC_TO_TICK(
527fcf3ce44SJohn Forte 				    icmdp->cmd_un.scsi.pkt->pkt_time *
528fcf3ce44SJohn Forte 				    iscsi_cmd_timeout_factor);
529fcf3ce44SJohn Forte 			else
530fcf3ce44SJohn Forte 				icmdp->cmd_lbolt_timeout = 0;
531fcf3ce44SJohn Forte 		} else if (icmdp->cmd_type == ISCSI_CMD_TYPE_TEXT) {
532fcf3ce44SJohn Forte 			icmdp->cmd_lbolt_timeout = ddi_get_lbolt() +
533fcf3ce44SJohn Forte 			    SEC_TO_TICK(ISCSI_INTERNAL_CMD_TIMEOUT *
534fcf3ce44SJohn Forte 			    iscsi_cmd_timeout_factor);
535fcf3ce44SJohn Forte 		}
536fcf3ce44SJohn Forte 
537fcf3ce44SJohn Forte 		/* remove command from pending queue */
538fcf3ce44SJohn Forte 		iscsi_dequeue_pending_cmd(isp, icmdp);
539fcf3ce44SJohn Forte 		/* check if expecting a response */
540fcf3ce44SJohn Forte 		if (free_icmdp == B_FALSE) {
541fcf3ce44SJohn Forte 			/* response expected, move to active queue */
542fcf3ce44SJohn Forte 			mutex_enter(&icmdp->cmd_conn->conn_queue_active.mutex);
543fcf3ce44SJohn Forte 			iscsi_enqueue_active_cmd(icmdp->cmd_conn, icmdp);
544fcf3ce44SJohn Forte 			mutex_exit(&icmdp->cmd_conn->conn_queue_active.mutex);
545fcf3ce44SJohn Forte 		}
546fcf3ce44SJohn Forte 
547fcf3ce44SJohn Forte 		/*
548fcf3ce44SJohn Forte 		 * TRANSFER COMMAND
549fcf3ce44SJohn Forte 		 */
550fcf3ce44SJohn Forte 		rval = iscsi_tx_cmd(isp, icmdp);
551fcf3ce44SJohn Forte 
552fcf3ce44SJohn Forte 		ASSERT(!mutex_owned(&isp->sess_queue_pending.mutex));
553fcf3ce44SJohn Forte 
554fcf3ce44SJohn Forte 		/*
555fcf3ce44SJohn Forte 		 * CHECK SUCCESS/FAILURE
556fcf3ce44SJohn Forte 		 */
557fcf3ce44SJohn Forte 		if (!ISCSI_SUCCESS(rval)) {
558fcf3ce44SJohn Forte 			/*
559fcf3ce44SJohn Forte 			 * iscsi_tx_cmd failed.  No cleanup is required
560fcf3ce44SJohn Forte 			 * of commands that were put in the active queue.
561fcf3ce44SJohn Forte 			 * If the tx failed then rx will also fail and cleanup
562fcf3ce44SJohn Forte 			 * all items in the active/aborted queue in a common.
563fcf3ce44SJohn Forte 			 */
564fcf3ce44SJohn Forte 
565fcf3ce44SJohn Forte 			/* EMPTY */
566fcf3ce44SJohn Forte 		}
567fcf3ce44SJohn Forte 
568fcf3ce44SJohn Forte 		/* free temporary commands */
569fcf3ce44SJohn Forte 		if (free_icmdp == B_TRUE) {
570fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
571d233de7eSJack Meng 			icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_FREE;
572fcf3ce44SJohn Forte 		}
573fcf3ce44SJohn Forte 		break;
574fcf3ce44SJohn Forte 
575*30e7468fSPeter Dunlap 	/* -E10: Abort is no longer required for this command */
576*30e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E10:
577*30e7468fSPeter Dunlap 		/*
578*30e7468fSPeter Dunlap 		 * Acquiring the sess_queue_pending lock while the
579*30e7468fSPeter Dunlap 		 * conn_queue_active lock is held conflicts with the
580*30e7468fSPeter Dunlap 		 * locking order in iscsi_cmd_state_pending where
581*30e7468fSPeter Dunlap 		 * conn_queue_active is acquired while sess_queue_pending
582*30e7468fSPeter Dunlap 		 * is held.  Normally this would be a dangerous lock
583*30e7468fSPeter Dunlap 		 * order conflict, except that we know that if we are
584*30e7468fSPeter Dunlap 		 * seeing ISCSI_CMD_EVENT_E10 then the command being
585*30e7468fSPeter Dunlap 		 * aborted is in "aborting" state and by extension
586*30e7468fSPeter Dunlap 		 * is not in "pending" state.  Therefore the code
587*30e7468fSPeter Dunlap 		 * path with that alternate lock order will not execute.
588*30e7468fSPeter Dunlap 		 * That's good because we can't drop the lock here without
589*30e7468fSPeter Dunlap 		 * risking a deadlock.
590*30e7468fSPeter Dunlap 		 */
591*30e7468fSPeter Dunlap 		ASSERT(mutex_owned(&icmdp->cmd_conn->conn_queue_active.mutex));
592*30e7468fSPeter Dunlap 		mutex_enter(&isp->sess_queue_pending.mutex);
593*30e7468fSPeter Dunlap 
594*30e7468fSPeter Dunlap 		icmdp->cmd_lbolt_aborting = ddi_get_lbolt();
595*30e7468fSPeter Dunlap 
596*30e7468fSPeter Dunlap 		iscsi_dequeue_pending_cmd(isp, icmdp);
597*30e7468fSPeter Dunlap 
598*30e7468fSPeter Dunlap 		icmdp->cmd_un.abort.icmdp->cmd_un.scsi.abort_icmdp = NULL;
599*30e7468fSPeter Dunlap 		icmdp->cmd_un.abort.icmdp = NULL;
600*30e7468fSPeter Dunlap 		icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_FREE;
601*30e7468fSPeter Dunlap 		icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
602*30e7468fSPeter Dunlap 
603*30e7468fSPeter Dunlap 		mutex_exit(&isp->sess_queue_pending.mutex);
604*30e7468fSPeter Dunlap 		break;
605*30e7468fSPeter Dunlap 
606fcf3ce44SJohn Forte 	/* -E4: Command has been requested to abort */
607fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E4:
608*30e7468fSPeter Dunlap 		ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
609fcf3ce44SJohn Forte 
610fcf3ce44SJohn Forte 		icmdp->cmd_lbolt_aborting = ddi_get_lbolt();
611fcf3ce44SJohn Forte 		ISCSI_CMD_SET_REASON_STAT(icmdp,
612fcf3ce44SJohn Forte 		    CMD_ABORTED, STAT_ABORTED);
613fcf3ce44SJohn Forte 
614fcf3ce44SJohn Forte 		iscsi_dequeue_pending_cmd(isp, icmdp);
615fcf3ce44SJohn Forte 		iscsi_enqueue_completed_cmd(isp, icmdp);
616fcf3ce44SJohn Forte 
617fcf3ce44SJohn Forte 		icmdp->cmd_lbolt_aborting = ddi_get_lbolt();
618fcf3ce44SJohn Forte 
619fcf3ce44SJohn Forte 		break;
620fcf3ce44SJohn Forte 
621fcf3ce44SJohn Forte 	/* -E7: Command has been reset */
622fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E7:
623fcf3ce44SJohn Forte 
624fcf3ce44SJohn Forte 		/* FALLTHRU */
625fcf3ce44SJohn Forte 
626fcf3ce44SJohn Forte 	/* -E6: Command has timed out */
627fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E6:
628*30e7468fSPeter Dunlap 		ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
629fcf3ce44SJohn Forte 		iscsi_dequeue_pending_cmd(isp, icmdp);
630fcf3ce44SJohn Forte 
631fcf3ce44SJohn Forte 		switch (icmdp->cmd_type) {
632fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_SCSI:
633fcf3ce44SJohn Forte 			/* Complete to caller as TIMEOUT */
634fcf3ce44SJohn Forte 			if (event == ISCSI_CMD_EVENT_E6) {
635fcf3ce44SJohn Forte 				ISCSI_CMD_SET_REASON_STAT(icmdp,
636fcf3ce44SJohn Forte 				    CMD_TIMEOUT, STAT_TIMEOUT);
637fcf3ce44SJohn Forte 			} else {
638fcf3ce44SJohn Forte 				ISCSI_CMD_SET_REASON_STAT(icmdp,
639fcf3ce44SJohn Forte 				    CMD_TRAN_ERR, 0);
640fcf3ce44SJohn Forte 			}
641fcf3ce44SJohn Forte 			iscsi_enqueue_completed_cmd(isp, icmdp);
642fcf3ce44SJohn Forte 			break;
643fcf3ce44SJohn Forte 
644fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_NOP:
645fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
646fcf3ce44SJohn Forte 			/*
647fcf3ce44SJohn Forte 			 * Timeout occured.  Just free NOP.  Another
648fcf3ce44SJohn Forte 			 * NOP request will be spawned to replace
649fcf3ce44SJohn Forte 			 * this one.
650fcf3ce44SJohn Forte 			 */
651d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
652d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
653d233de7eSJack Meng 
654fcf3ce44SJohn Forte 			break;
655fcf3ce44SJohn Forte 
656fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_ABORT:
657fcf3ce44SJohn Forte 			mutex_enter(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
658fcf3ce44SJohn Forte 			icmdp->cmd_un.abort.icmdp->
659fcf3ce44SJohn Forte 			    cmd_un.scsi.abort_icmdp = NULL;
660fcf3ce44SJohn Forte 			cv_broadcast(&icmdp->cmd_un.abort.icmdp->
661fcf3ce44SJohn Forte 			    cmd_completion);
662fcf3ce44SJohn Forte 			mutex_exit(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
663fcf3ce44SJohn Forte 			icmdp->cmd_un.abort.icmdp = NULL;
664fcf3ce44SJohn Forte 
665fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
666d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
667d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
668fcf3ce44SJohn Forte 			break;
669fcf3ce44SJohn Forte 
670fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_RESET:
671fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
672fcf3ce44SJohn Forte 			/*
673fcf3ce44SJohn Forte 			 * If we are failing a RESET we need
674fcf3ce44SJohn Forte 			 * to notify the tran_reset caller.
675fcf3ce44SJohn Forte 			 * with the cmd and notify caller.
676fcf3ce44SJohn Forte 			 */
677fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
678fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
679fcf3ce44SJohn Forte 			break;
680fcf3ce44SJohn Forte 
681fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_LOGOUT:
682fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
683fcf3ce44SJohn Forte 			/* notify requester of failure */
684fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
685fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
686fcf3ce44SJohn Forte 			break;
687fcf3ce44SJohn Forte 
688fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_TEXT:
689fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
690fcf3ce44SJohn Forte 			icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
691fcf3ce44SJohn Forte 			/*
692fcf3ce44SJohn Forte 			 * If a TEXT command fails, notify the owner.
693fcf3ce44SJohn Forte 			 */
694fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
695fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
696fcf3ce44SJohn Forte 			break;
697fcf3ce44SJohn Forte 
698fcf3ce44SJohn Forte 		default:
699fcf3ce44SJohn Forte 			ASSERT(FALSE);
700fcf3ce44SJohn Forte 			break;
701fcf3ce44SJohn Forte 		}
702fcf3ce44SJohn Forte 		break;
703fcf3ce44SJohn Forte 
704fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
705fcf3ce44SJohn Forte 	default:
706fcf3ce44SJohn Forte 		ASSERT(FALSE);
707fcf3ce44SJohn Forte 	}
708fcf3ce44SJohn Forte }
709fcf3ce44SJohn Forte 
710fcf3ce44SJohn Forte 
711fcf3ce44SJohn Forte /*
712fcf3ce44SJohn Forte  * iscsi_cmd_state_active -
713fcf3ce44SJohn Forte  *
714fcf3ce44SJohn Forte  */
715fcf3ce44SJohn Forte static void
716fcf3ce44SJohn Forte iscsi_cmd_state_active(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
717fcf3ce44SJohn Forte {
718fcf3ce44SJohn Forte 	iscsi_sess_t	*isp		= (iscsi_sess_t *)arg;
719fcf3ce44SJohn Forte 	iscsi_hba_t	*ihp;
720fcf3ce44SJohn Forte 	iscsi_cmd_t	*t_icmdp	= NULL;
721fcf3ce44SJohn Forte 	iscsi_conn_t	*icp		= NULL;
722fcf3ce44SJohn Forte 
723fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
724fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_ACTIVE);
725fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
726fcf3ce44SJohn Forte 
727fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
728fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
729fcf3ce44SJohn Forte 
730fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
731fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
732fcf3ce44SJohn Forte 	ASSERT(mutex_owned(&icp->conn_queue_active.mutex));
733fcf3ce44SJohn Forte 
734fcf3ce44SJohn Forte 	/* switch on event change */
735fcf3ce44SJohn Forte 	switch (event) {
736fcf3ce44SJohn Forte 	/* -E3: Command was successfully completed */
737fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E3:
738fcf3ce44SJohn Forte 		/*
739fcf3ce44SJohn Forte 		 * Remove command from the active list.  We need to protect
740fcf3ce44SJohn Forte 		 * someone from looking up this command ITT until it's
741fcf3ce44SJohn Forte 		 * freed of the command is moved to a new queue location.
742fcf3ce44SJohn Forte 		 */
743fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_cmdsn_mutex);
744fcf3ce44SJohn Forte 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
745fcf3ce44SJohn Forte 
746fcf3ce44SJohn Forte 		switch (icmdp->cmd_type) {
747fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_SCSI:
748*30e7468fSPeter Dunlap 			iscsi_sess_release_scsi_itt(icmdp);
749fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
750fcf3ce44SJohn Forte 			iscsi_enqueue_completed_cmd(isp, icmdp);
751fcf3ce44SJohn Forte 			break;
752fcf3ce44SJohn Forte 
753fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_NOP:
754fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
755fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
756fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
757fcf3ce44SJohn Forte 
758fcf3ce44SJohn Forte 			/* free alloc */
759d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
760d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
761d233de7eSJack Meng 
762fcf3ce44SJohn Forte 			break;
763fcf3ce44SJohn Forte 
764fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_ABORT:
765fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
766fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
767fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
768fcf3ce44SJohn Forte 
769fcf3ce44SJohn Forte 			/*
770fcf3ce44SJohn Forte 			 * Abort was completed successfully.  We should
771fcf3ce44SJohn Forte 			 * complete the parent scsi command if it still
772fcf3ce44SJohn Forte 			 * exists as timed out, and the state is not
773fcf3ce44SJohn Forte 			 * COMPLETED
774fcf3ce44SJohn Forte 			 */
775fcf3ce44SJohn Forte 			t_icmdp = icmdp->cmd_un.abort.icmdp;
776fcf3ce44SJohn Forte 			ASSERT(t_icmdp != NULL);
777fcf3ce44SJohn Forte 			mutex_enter(&t_icmdp->cmd_mutex);
778*30e7468fSPeter Dunlap 			t_icmdp->cmd_un.scsi.abort_icmdp = NULL;
779fcf3ce44SJohn Forte 			if (t_icmdp->cmd_state != ISCSI_CMD_STATE_COMPLETED) {
780fcf3ce44SJohn Forte 				iscsi_dequeue_active_cmd(
781fcf3ce44SJohn Forte 				    t_icmdp->cmd_conn, t_icmdp);
782*30e7468fSPeter Dunlap 				mutex_enter(
783*30e7468fSPeter Dunlap 				    &icp->conn_queue_idm_aborting.mutex);
784*30e7468fSPeter Dunlap 				iscsi_enqueue_idm_aborting_cmd(
785*30e7468fSPeter Dunlap 				    t_icmdp->cmd_conn,
786*30e7468fSPeter Dunlap 				    t_icmdp);
787*30e7468fSPeter Dunlap 				mutex_exit(&icp->conn_queue_idm_aborting.mutex);
788fcf3ce44SJohn Forte 
789*30e7468fSPeter Dunlap 				/*
790*30e7468fSPeter Dunlap 				 * Complete abort processing after IDM
791*30e7468fSPeter Dunlap 				 * calls us back.  Set the status to use
792*30e7468fSPeter Dunlap 				 * when we complete the command.
793*30e7468fSPeter Dunlap 				 */
794fcf3ce44SJohn Forte 				ISCSI_CMD_SET_REASON_STAT(
795fcf3ce44SJohn Forte 				    t_icmdp, CMD_TIMEOUT, STAT_TIMEOUT);
796*30e7468fSPeter Dunlap 				idm_task_abort(icp->conn_ic, t_icmdp->cmd_itp,
797*30e7468fSPeter Dunlap 				    AT_TASK_MGMT_ABORT);
798*30e7468fSPeter Dunlap 			} else {
799*30e7468fSPeter Dunlap 				cv_broadcast(&t_icmdp->cmd_completion);
800fcf3ce44SJohn Forte 			}
801fcf3ce44SJohn Forte 			mutex_exit(&t_icmdp->cmd_mutex);
802fcf3ce44SJohn Forte 			icmdp->cmd_un.abort.icmdp = NULL;
803fcf3ce44SJohn Forte 
804d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
805d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
806d233de7eSJack Meng 
807fcf3ce44SJohn Forte 			break;
808fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_RESET:
809fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
810fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
811fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
812fcf3ce44SJohn Forte 
813fcf3ce44SJohn Forte 			/*
814fcf3ce44SJohn Forte 			 * Complete the abort/reset successfully.
815fcf3ce44SJohn Forte 			 */
816fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp, ISCSI_STATUS_SUCCESS);
817fcf3ce44SJohn Forte 			break;
818fcf3ce44SJohn Forte 
819fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_LOGOUT:
820fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
821fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
822fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
823fcf3ce44SJohn Forte 
824fcf3ce44SJohn Forte 			/*
825fcf3ce44SJohn Forte 			 * Complete the logout successfully.
826fcf3ce44SJohn Forte 			 */
827fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp, ISCSI_STATUS_SUCCESS);
828fcf3ce44SJohn Forte 			break;
829fcf3ce44SJohn Forte 
830fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_TEXT:
831fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
832fcf3ce44SJohn Forte 			if (icmdp->cmd_un.text.stage ==
833fcf3ce44SJohn Forte 			    ISCSI_CMD_TEXT_FINAL_RSP) {
834fcf3ce44SJohn Forte 				iscsi_sess_release_itt(isp, icmdp);
835fcf3ce44SJohn Forte 			}
836fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
837fcf3ce44SJohn Forte 
838fcf3ce44SJohn Forte 			/*
839fcf3ce44SJohn Forte 			 * Complete the text command successfully.
840fcf3ce44SJohn Forte 			 */
841fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp, icmdp->cmd_result);
842fcf3ce44SJohn Forte 			break;
843fcf3ce44SJohn Forte 
844fcf3ce44SJohn Forte 		default:
845fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
846fcf3ce44SJohn Forte 			ASSERT(FALSE);
847fcf3ce44SJohn Forte 		}
848fcf3ce44SJohn Forte 
849fcf3ce44SJohn Forte 		ASSERT(!mutex_owned(&isp->sess_cmdsn_mutex));
850fcf3ce44SJohn Forte 		break;
851fcf3ce44SJohn Forte 
852*30e7468fSPeter Dunlap 	/* -E10,E4: Command has been requested to abort */
853*30e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E10:
854*30e7468fSPeter Dunlap 		/* FALLTHRU */
855fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E4:
856fcf3ce44SJohn Forte 
857fcf3ce44SJohn Forte 		/* E4 is only for resets and aborts */
858fcf3ce44SJohn Forte 		ASSERT((icmdp->cmd_type == ISCSI_CMD_TYPE_ABORT) ||
859fcf3ce44SJohn Forte 		    (icmdp->cmd_type == ISCSI_CMD_TYPE_RESET));
860fcf3ce44SJohn Forte 		/* FALLTHRU */
861fcf3ce44SJohn Forte 
862fcf3ce44SJohn Forte 	/* -E6: Command has timed out */
863fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E6:
864fcf3ce44SJohn Forte 
865fcf3ce44SJohn Forte 		switch (icmdp->cmd_type) {
866fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_SCSI:
867fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_ABORTING;
868fcf3ce44SJohn Forte 			iscsi_handle_abort(icmdp);
869fcf3ce44SJohn Forte 			break;
870fcf3ce44SJohn Forte 
871fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_NOP:
872fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
873fcf3ce44SJohn Forte 
874fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
875fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
876fcf3ce44SJohn Forte 			iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
877fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
878fcf3ce44SJohn Forte 
879d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
880d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
881d233de7eSJack Meng 
882fcf3ce44SJohn Forte 			break;
883fcf3ce44SJohn Forte 
884fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_ABORT:
885fcf3ce44SJohn Forte 			icmdp->cmd_state =
886fcf3ce44SJohn Forte 			    ISCSI_CMD_STATE_FREE;
887fcf3ce44SJohn Forte 
888fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
889fcf3ce44SJohn Forte 			iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
890fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
891fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
892fcf3ce44SJohn Forte 
893fcf3ce44SJohn Forte 			/*
894*30e7468fSPeter Dunlap 			 * If this is an E4 then we may need to deal with
895*30e7468fSPeter Dunlap 			 * the abort's associated SCSI command.  If this
896*30e7468fSPeter Dunlap 			 * is an E10 then IDM is already cleaning up the
897*30e7468fSPeter Dunlap 			 * SCSI command and all we need to do is break the
898*30e7468fSPeter Dunlap 			 * linkage between them and free the abort command.
899fcf3ce44SJohn Forte 			 */
900*30e7468fSPeter Dunlap 			t_icmdp = icmdp->cmd_un.abort.icmdp;
901*30e7468fSPeter Dunlap 			ASSERT(t_icmdp != NULL);
902*30e7468fSPeter Dunlap 			if (event != ISCSI_CMD_EVENT_E10) {
903*30e7468fSPeter Dunlap 
904*30e7468fSPeter Dunlap 				mutex_enter(&t_icmdp->cmd_mutex);
905*30e7468fSPeter Dunlap 				t_icmdp->cmd_un.scsi.abort_icmdp = NULL;
906*30e7468fSPeter Dunlap 				/*
907*30e7468fSPeter Dunlap 				 * If abort command is aborted then we should
908*30e7468fSPeter Dunlap 				 * not act on the parent scsi command.  If the
909*30e7468fSPeter Dunlap 				 * abort command timed out then we need to
910*30e7468fSPeter Dunlap 				 * complete the parent command if it still
911*30e7468fSPeter Dunlap 				 * exists with a timeout failure.
912*30e7468fSPeter Dunlap 				 */
913*30e7468fSPeter Dunlap 				if ((event == ISCSI_CMD_EVENT_E6) &&
914*30e7468fSPeter Dunlap 				    (t_icmdp->cmd_state !=
915*30e7468fSPeter Dunlap 				    ISCSI_CMD_STATE_IDM_ABORTING) &&
916*30e7468fSPeter Dunlap 				    (t_icmdp->cmd_state !=
917*30e7468fSPeter Dunlap 				    ISCSI_CMD_STATE_COMPLETED)) {
918*30e7468fSPeter Dunlap 
919*30e7468fSPeter Dunlap 					iscsi_dequeue_active_cmd(
920*30e7468fSPeter Dunlap 					    t_icmdp->cmd_conn, t_icmdp);
921*30e7468fSPeter Dunlap 					mutex_enter(&icp->
922*30e7468fSPeter Dunlap 					    conn_queue_idm_aborting.mutex);
923*30e7468fSPeter Dunlap 					iscsi_enqueue_idm_aborting_cmd(
924*30e7468fSPeter Dunlap 					    t_icmdp->cmd_conn,  t_icmdp);
925*30e7468fSPeter Dunlap 					mutex_exit(&icp->
926*30e7468fSPeter Dunlap 					    conn_queue_idm_aborting.mutex);
927*30e7468fSPeter Dunlap 					/*
928*30e7468fSPeter Dunlap 					 * Complete abort processing after IDM
929*30e7468fSPeter Dunlap 					 * calls us back.  Set the status to use
930*30e7468fSPeter Dunlap 					 * when we complete the command.
931*30e7468fSPeter Dunlap 					 */
932*30e7468fSPeter Dunlap 					ISCSI_CMD_SET_REASON_STAT(t_icmdp,
933*30e7468fSPeter Dunlap 					    CMD_TIMEOUT, STAT_TIMEOUT);
934*30e7468fSPeter Dunlap 					idm_task_abort(icp->conn_ic,
935*30e7468fSPeter Dunlap 					    t_icmdp->cmd_itp,
936*30e7468fSPeter Dunlap 					    AT_TASK_MGMT_ABORT);
937*30e7468fSPeter Dunlap 				} else {
938*30e7468fSPeter Dunlap 					cv_broadcast(&t_icmdp->cmd_completion);
939*30e7468fSPeter Dunlap 				}
940*30e7468fSPeter Dunlap 				mutex_exit(&t_icmdp->cmd_mutex);
941*30e7468fSPeter Dunlap 			} else {
942*30e7468fSPeter Dunlap 				t_icmdp->cmd_un.scsi.abort_icmdp = NULL;
943fcf3ce44SJohn Forte 			}
944fcf3ce44SJohn Forte 			icmdp->cmd_un.abort.icmdp = NULL;
945d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
946d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
947fcf3ce44SJohn Forte 			break;
948fcf3ce44SJohn Forte 
949fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_RESET:
950fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
951fcf3ce44SJohn Forte 
952fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
953fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
954fcf3ce44SJohn Forte 			iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
955fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
956fcf3ce44SJohn Forte 
957fcf3ce44SJohn Forte 			/*
958fcf3ce44SJohn Forte 			 * If we are failing a RESET we need
959fcf3ce44SJohn Forte 			 * to notify the tran_reset caller.
960fcf3ce44SJohn Forte 			 * It will free the memory associated
961fcf3ce44SJohn Forte 			 * with the cmd and notify caller.
962fcf3ce44SJohn Forte 			 */
963fcf3ce44SJohn Forte 
964fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
965fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
966fcf3ce44SJohn Forte 			break;
967fcf3ce44SJohn Forte 
968fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_LOGOUT:
969fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
970fcf3ce44SJohn Forte 
971fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
972fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
973fcf3ce44SJohn Forte 			iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
974fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
975fcf3ce44SJohn Forte 
976fcf3ce44SJohn Forte 			/*
977fcf3ce44SJohn Forte 			 * Notify caller of failure.
978fcf3ce44SJohn Forte 			 */
979fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
980fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
981fcf3ce44SJohn Forte 			break;
982fcf3ce44SJohn Forte 
983fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_TEXT:
984fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
985fcf3ce44SJohn Forte 			icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
986fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
987fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
988fcf3ce44SJohn Forte 			iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
989fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
990fcf3ce44SJohn Forte 
991fcf3ce44SJohn Forte 			/*
992fcf3ce44SJohn Forte 			 * If a TEXT command fails, notify caller so
993fcf3ce44SJohn Forte 			 * it can free assocated command
994fcf3ce44SJohn Forte 			 */
995fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
996fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
997fcf3ce44SJohn Forte 			break;
998fcf3ce44SJohn Forte 
999fcf3ce44SJohn Forte 		default:
1000fcf3ce44SJohn Forte 			ASSERT(FALSE);
1001fcf3ce44SJohn Forte 		}
1002fcf3ce44SJohn Forte 
1003fcf3ce44SJohn Forte 		ASSERT(!mutex_owned(&isp->sess_cmdsn_mutex));
1004fcf3ce44SJohn Forte 		break;
1005fcf3ce44SJohn Forte 
1006fcf3ce44SJohn Forte 	/* -E7: Connection has encountered a problem */
1007fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E7:
1008fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_cmdsn_mutex);
1009fcf3ce44SJohn Forte 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
1010fcf3ce44SJohn Forte 
1011fcf3ce44SJohn Forte 		switch (icmdp->cmd_type) {
1012fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_SCSI:
1013fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1014*30e7468fSPeter Dunlap 			mutex_enter(&icp->conn_queue_idm_aborting.mutex);
1015*30e7468fSPeter Dunlap 			iscsi_enqueue_idm_aborting_cmd(icmdp->cmd_conn, icmdp);
1016*30e7468fSPeter Dunlap 			mutex_exit(&icp->conn_queue_idm_aborting.mutex);
1017fcf3ce44SJohn Forte 
1018*30e7468fSPeter Dunlap 			ISCSI_CMD_SET_REASON_STAT(icmdp, CMD_TRAN_ERR, 0);
1019*30e7468fSPeter Dunlap 			idm_task_abort(icp->conn_ic, icmdp->cmd_itp,
1020*30e7468fSPeter Dunlap 			    AT_TASK_MGMT_ABORT);
1021fcf3ce44SJohn Forte 			break;
1022fcf3ce44SJohn Forte 
1023fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_NOP:
1024fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1025fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
1026fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1027fcf3ce44SJohn Forte 
1028d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
1029d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
1030fcf3ce44SJohn Forte 			break;
1031fcf3ce44SJohn Forte 
1032fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_ABORT:
1033fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1034fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
1035fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1036fcf3ce44SJohn Forte 
1037fcf3ce44SJohn Forte 			mutex_enter(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
1038fcf3ce44SJohn Forte 			icmdp->cmd_un.abort.icmdp->
1039fcf3ce44SJohn Forte 			    cmd_un.scsi.abort_icmdp = NULL;
1040fcf3ce44SJohn Forte 			cv_broadcast(&icmdp->cmd_un.abort.icmdp->
1041fcf3ce44SJohn Forte 			    cmd_completion);
1042fcf3ce44SJohn Forte 			mutex_exit(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
1043fcf3ce44SJohn Forte 			/*
1044fcf3ce44SJohn Forte 			 * Nullify the abort command's pointer to its
1045fcf3ce44SJohn Forte 			 * parent command. It does not have to complete its
1046fcf3ce44SJohn Forte 			 * parent command because the parent command will
1047fcf3ce44SJohn Forte 			 * also get an E7.
1048fcf3ce44SJohn Forte 			 */
1049fcf3ce44SJohn Forte 			icmdp->cmd_un.abort.icmdp = NULL;
1050fcf3ce44SJohn Forte 
1051d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
1052d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
1053fcf3ce44SJohn Forte 			break;
1054fcf3ce44SJohn Forte 
1055fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_RESET:
1056fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1057fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
1058fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1059fcf3ce44SJohn Forte 			/*
1060fcf3ce44SJohn Forte 			 * If we are failing a ABORT we need
1061fcf3ce44SJohn Forte 			 * to notify the tran_abort caller.
1062fcf3ce44SJohn Forte 			 * It will free the memory associated
1063fcf3ce44SJohn Forte 			 * with the cmd and notify caller.
1064fcf3ce44SJohn Forte 			 */
1065fcf3ce44SJohn Forte 
1066fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
1067fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
1068fcf3ce44SJohn Forte 			break;
1069fcf3ce44SJohn Forte 
1070fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_LOGOUT:
1071fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1072fcf3ce44SJohn Forte 			/*
1073fcf3ce44SJohn Forte 			 * A connection problem and we attempted to
1074fcf3ce44SJohn Forte 			 * logout?  I guess we can just free the
1075fcf3ce44SJohn Forte 			 * request.  Someone has already pushed the
1076fcf3ce44SJohn Forte 			 * connection state.
1077fcf3ce44SJohn Forte 			 */
1078fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
1079fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1080fcf3ce44SJohn Forte 
1081fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp, ISCSI_STATUS_SUCCESS);
1082fcf3ce44SJohn Forte 			break;
1083fcf3ce44SJohn Forte 
1084fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_TEXT:
1085fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1086fcf3ce44SJohn Forte 			icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
1087fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
1088fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1089fcf3ce44SJohn Forte 
1090fcf3ce44SJohn Forte 			/*
1091fcf3ce44SJohn Forte 			 * If a TEXT command fails, notify caller so
1092fcf3ce44SJohn Forte 			 * it can free assocated command
1093fcf3ce44SJohn Forte 			 */
1094fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
1095fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
1096fcf3ce44SJohn Forte 			break;
1097fcf3ce44SJohn Forte 
1098fcf3ce44SJohn Forte 		default:
1099fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1100fcf3ce44SJohn Forte 			ASSERT(FALSE);
1101fcf3ce44SJohn Forte 			break;
1102fcf3ce44SJohn Forte 		}
1103fcf3ce44SJohn Forte 
1104fcf3ce44SJohn Forte 		ASSERT(!mutex_owned(&isp->sess_cmdsn_mutex));
1105fcf3ce44SJohn Forte 		break;
1106fcf3ce44SJohn Forte 
1107*30e7468fSPeter Dunlap 	/* -E9: IDM is no longer processing this command */
1108*30e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E9:
1109*30e7468fSPeter Dunlap 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
1110*30e7468fSPeter Dunlap 
1111*30e7468fSPeter Dunlap 		iscsi_task_cleanup(ISCSI_OP_SCSI_RSP, icmdp);
1112*30e7468fSPeter Dunlap 		iscsi_sess_release_scsi_itt(icmdp);
1113*30e7468fSPeter Dunlap 
1114*30e7468fSPeter Dunlap 		ISCSI_CMD_SET_REASON_STAT(icmdp, CMD_TRAN_ERR, 0);
1115*30e7468fSPeter Dunlap 		iscsi_enqueue_completed_cmd(isp, icmdp);
1116*30e7468fSPeter Dunlap 		break;
1117*30e7468fSPeter Dunlap 
1118fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
1119fcf3ce44SJohn Forte 	default:
1120fcf3ce44SJohn Forte 		ASSERT(FALSE);
1121fcf3ce44SJohn Forte 	}
1122fcf3ce44SJohn Forte }
1123fcf3ce44SJohn Forte 
1124fcf3ce44SJohn Forte 
1125fcf3ce44SJohn Forte /*
1126fcf3ce44SJohn Forte  * iscsi_cmd_state_aborting -
1127fcf3ce44SJohn Forte  *
1128fcf3ce44SJohn Forte  */
1129fcf3ce44SJohn Forte static void
1130fcf3ce44SJohn Forte iscsi_cmd_state_aborting(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
1131fcf3ce44SJohn Forte {
1132fcf3ce44SJohn Forte 	iscsi_sess_t	*isp	= (iscsi_sess_t *)arg;
1133*30e7468fSPeter Dunlap 	iscsi_cmd_t	*a_icmdp;
1134fcf3ce44SJohn Forte 
1135fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
1136fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI);
1137fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_ABORTING);
1138fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1139fcf3ce44SJohn Forte 	ASSERT(mutex_owned(&icmdp->cmd_conn->conn_queue_active.mutex));
1140fcf3ce44SJohn Forte 
1141fcf3ce44SJohn Forte 	/* switch on event change */
1142fcf3ce44SJohn Forte 	switch (event) {
1143fcf3ce44SJohn Forte 	/* -E3: Command was successfully completed */
1144fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E3:
1145fcf3ce44SJohn Forte 		/*
1146fcf3ce44SJohn Forte 		 * Remove command from the aborting list
1147fcf3ce44SJohn Forte 		 */
1148fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_cmdsn_mutex);
1149fcf3ce44SJohn Forte 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
1150*30e7468fSPeter Dunlap 		iscsi_sess_release_scsi_itt(icmdp);
1151fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_cmdsn_mutex);
1152fcf3ce44SJohn Forte 
1153fcf3ce44SJohn Forte 		iscsi_enqueue_completed_cmd(isp, icmdp);
1154fcf3ce44SJohn Forte 		break;
1155fcf3ce44SJohn Forte 
1156fcf3ce44SJohn Forte 	/* -E4: Command has been requested to abort */
1157fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E4:
1158fcf3ce44SJohn Forte 		/*
1159fcf3ce44SJohn Forte 		 * An upper level driver might attempt to
1160fcf3ce44SJohn Forte 		 * abort a command that we are already
1161fcf3ce44SJohn Forte 		 * aborting due to a nop.  Since we are
1162fcf3ce44SJohn Forte 		 * already in the process of aborting
1163fcf3ce44SJohn Forte 		 * ignore the request.
1164fcf3ce44SJohn Forte 		 */
1165fcf3ce44SJohn Forte 		break;
1166fcf3ce44SJohn Forte 
1167fcf3ce44SJohn Forte 	/* -E6: Command has timed out */
1168fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E6:
1169fcf3ce44SJohn Forte 		ASSERT(FALSE);
1170fcf3ce44SJohn Forte 		/*
1171fcf3ce44SJohn Forte 		 * Timeouts should not occur on command in abort queue
1172fcf3ce44SJohn Forte 		 * they are already be processed due to a timeout.
1173fcf3ce44SJohn Forte 		 */
1174fcf3ce44SJohn Forte 		break;
1175fcf3ce44SJohn Forte 
1176fcf3ce44SJohn Forte 	/* -E7: Connection has encountered a problem */
1177fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E7:
1178fcf3ce44SJohn Forte 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
1179*30e7468fSPeter Dunlap 		mutex_enter(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
1180*30e7468fSPeter Dunlap 		iscsi_enqueue_idm_aborting_cmd(icmdp->cmd_conn, icmdp);
1181*30e7468fSPeter Dunlap 		mutex_exit(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
1182fcf3ce44SJohn Forte 
1183*30e7468fSPeter Dunlap 		/*
1184*30e7468fSPeter Dunlap 		 * Since we are in "aborting" state there is another command
1185*30e7468fSPeter Dunlap 		 * representing the abort of this command.  This command
1186*30e7468fSPeter Dunlap 		 * will cleanup at some indeterminate time after the call
1187*30e7468fSPeter Dunlap 		 * to idm_task_abort so we can't leave the abort request
1188*30e7468fSPeter Dunlap 		 * active.  An E10 event to the abort command will cause
1189*30e7468fSPeter Dunlap 		 * it to complete immediately.
1190*30e7468fSPeter Dunlap 		 */
1191*30e7468fSPeter Dunlap 		if ((a_icmdp = icmdp->cmd_un.scsi.abort_icmdp) != NULL) {
1192*30e7468fSPeter Dunlap 			iscsi_cmd_state_machine(a_icmdp,
1193*30e7468fSPeter Dunlap 			    ISCSI_CMD_EVENT_E10, arg);
1194*30e7468fSPeter Dunlap 		}
1195*30e7468fSPeter Dunlap 
1196*30e7468fSPeter Dunlap 		ISCSI_CMD_SET_REASON_STAT(icmdp, CMD_TRAN_ERR, 0);
1197*30e7468fSPeter Dunlap 		idm_task_abort(icmdp->cmd_conn->conn_ic, icmdp->cmd_itp,
1198*30e7468fSPeter Dunlap 		    AT_TASK_MGMT_ABORT);
1199*30e7468fSPeter Dunlap 		break;
1200*30e7468fSPeter Dunlap 
1201*30e7468fSPeter Dunlap 	/* -E9: IDM is no longer processing this command */
1202*30e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E9:
1203*30e7468fSPeter Dunlap 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
1204*30e7468fSPeter Dunlap 
1205*30e7468fSPeter Dunlap 		iscsi_task_cleanup(ISCSI_OP_SCSI_RSP, icmdp);
1206*30e7468fSPeter Dunlap 		iscsi_sess_release_scsi_itt(icmdp);
1207*30e7468fSPeter Dunlap 
1208*30e7468fSPeter Dunlap 		ISCSI_CMD_SET_REASON_STAT(icmdp, CMD_TRAN_ERR, 0);
1209*30e7468fSPeter Dunlap 		iscsi_enqueue_completed_cmd(isp, icmdp);
1210*30e7468fSPeter Dunlap 		break;
1211*30e7468fSPeter Dunlap 
1212*30e7468fSPeter Dunlap 	/* All other events are invalid for this state */
1213*30e7468fSPeter Dunlap 	default:
1214*30e7468fSPeter Dunlap 		ASSERT(FALSE);
1215*30e7468fSPeter Dunlap 	}
1216*30e7468fSPeter Dunlap }
1217*30e7468fSPeter Dunlap 
1218*30e7468fSPeter Dunlap static void
1219*30e7468fSPeter Dunlap iscsi_cmd_state_idm_aborting(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event,
1220*30e7468fSPeter Dunlap     void *arg)
1221*30e7468fSPeter Dunlap {
1222*30e7468fSPeter Dunlap 	iscsi_sess_t	*isp	= (iscsi_sess_t *)arg;
1223*30e7468fSPeter Dunlap 
1224*30e7468fSPeter Dunlap 	ASSERT(icmdp != NULL);
1225*30e7468fSPeter Dunlap 	ASSERT(icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI);
1226*30e7468fSPeter Dunlap 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_IDM_ABORTING);
1227*30e7468fSPeter Dunlap 	ASSERT(isp != NULL);
1228*30e7468fSPeter Dunlap 
1229*30e7468fSPeter Dunlap 	/* switch on event change */
1230*30e7468fSPeter Dunlap 	switch (event) {
1231*30e7468fSPeter Dunlap 	/* -E3: Command was successfully completed */
1232*30e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E3:
1233*30e7468fSPeter Dunlap 		/*
1234*30e7468fSPeter Dunlap 		 * iscsi_rx_process_cmd_rsp() and iscsi_rx_process_data_rsp()
1235*30e7468fSPeter Dunlap 		 * are supposed to confirm the cmd state is appropriate before
1236*30e7468fSPeter Dunlap 		 * generating an E3 event.  E3 is not allowed in this state.
1237*30e7468fSPeter Dunlap 		 */
1238*30e7468fSPeter Dunlap 		ASSERT(0);
1239*30e7468fSPeter Dunlap 		break;
1240*30e7468fSPeter Dunlap 
1241*30e7468fSPeter Dunlap 	/* -E4: Command has been requested to abort */
1242*30e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E4:
1243*30e7468fSPeter Dunlap 		/*
1244*30e7468fSPeter Dunlap 		 * An upper level driver might attempt to
1245*30e7468fSPeter Dunlap 		 * abort a command that we are already
1246*30e7468fSPeter Dunlap 		 * aborting due to a nop.  Since we are
1247*30e7468fSPeter Dunlap 		 * already in the process of aborting
1248*30e7468fSPeter Dunlap 		 * ignore the request.
1249*30e7468fSPeter Dunlap 		 */
1250*30e7468fSPeter Dunlap 		break;
1251*30e7468fSPeter Dunlap 
1252*30e7468fSPeter Dunlap 	/* -E6: Command has timed out */
1253*30e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E6:
1254*30e7468fSPeter Dunlap 		ASSERT(FALSE);
1255*30e7468fSPeter Dunlap 		/*
1256*30e7468fSPeter Dunlap 		 * Timeouts should not occur on aborting commands
1257*30e7468fSPeter Dunlap 		 */
1258*30e7468fSPeter Dunlap 		break;
1259*30e7468fSPeter Dunlap 
1260*30e7468fSPeter Dunlap 	/* -E7: Connection has encountered a problem */
1261*30e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E7:
1262*30e7468fSPeter Dunlap 		/*
1263*30e7468fSPeter Dunlap 		 * We have already requested IDM to stop processing this
1264*30e7468fSPeter Dunlap 		 * command so ignore this request.
1265*30e7468fSPeter Dunlap 		 */
1266*30e7468fSPeter Dunlap 		break;
1267*30e7468fSPeter Dunlap 
1268*30e7468fSPeter Dunlap 	/* -E9: IDM is no longer processing this command */
1269*30e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E9:
1270*30e7468fSPeter Dunlap 		mutex_enter(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
1271*30e7468fSPeter Dunlap 		iscsi_dequeue_idm_aborting_cmd(icmdp->cmd_conn, icmdp);
1272*30e7468fSPeter Dunlap 		mutex_exit(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
1273*30e7468fSPeter Dunlap 
1274*30e7468fSPeter Dunlap 		/* This is always an error so make sure an error has been set */
1275*30e7468fSPeter Dunlap 		ASSERT(icmdp->cmd_un.scsi.pkt->pkt_reason != CMD_CMPLT);
1276*30e7468fSPeter Dunlap 		iscsi_task_cleanup(ISCSI_OP_SCSI_RSP, icmdp);
1277*30e7468fSPeter Dunlap 		iscsi_sess_release_scsi_itt(icmdp);
1278*30e7468fSPeter Dunlap 
1279*30e7468fSPeter Dunlap 		/*
1280*30e7468fSPeter Dunlap 		 * Whoever called idm_task_abort should have set the completion
1281*30e7468fSPeter Dunlap 		 * status beforehand.
1282*30e7468fSPeter Dunlap 		 */
1283fcf3ce44SJohn Forte 		iscsi_enqueue_completed_cmd(isp, icmdp);
1284*30e7468fSPeter Dunlap 		cv_broadcast(&icmdp->cmd_completion);
1285fcf3ce44SJohn Forte 		break;
1286fcf3ce44SJohn Forte 
1287fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
1288fcf3ce44SJohn Forte 	default:
1289fcf3ce44SJohn Forte 		ASSERT(FALSE);
1290fcf3ce44SJohn Forte 	}
1291fcf3ce44SJohn Forte }
1292fcf3ce44SJohn Forte 
1293fcf3ce44SJohn Forte 
1294fcf3ce44SJohn Forte /*
1295fcf3ce44SJohn Forte  * iscsi_cmd_state_completed -
1296fcf3ce44SJohn Forte  *
1297fcf3ce44SJohn Forte  */
1298fcf3ce44SJohn Forte static void
1299fcf3ce44SJohn Forte iscsi_cmd_state_completed(iscsi_cmd_t *icmdp,
1300fcf3ce44SJohn Forte     iscsi_cmd_event_t event, void *arg)
1301fcf3ce44SJohn Forte {
1302fcf3ce44SJohn Forte 	iscsi_sess_t	*isp	= (iscsi_sess_t *)arg;
1303fcf3ce44SJohn Forte 
1304fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
1305fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI);
1306fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_COMPLETED);
1307fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1308fcf3ce44SJohn Forte 
1309fcf3ce44SJohn Forte 	/* switch on event change */
1310fcf3ce44SJohn Forte 	switch (event) {
1311fcf3ce44SJohn Forte 	/* -E8: */
1312fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E8:
1313fcf3ce44SJohn Forte 		icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1314fcf3ce44SJohn Forte 
1315fcf3ce44SJohn Forte 		/* the caller has already remove cmd from queue */
1316fcf3ce44SJohn Forte 
1317fcf3ce44SJohn Forte 		icmdp->cmd_next = NULL;
1318fcf3ce44SJohn Forte 		icmdp->cmd_prev = NULL;
1319fcf3ce44SJohn Forte 		iscsi_iodone(isp, icmdp);
1320fcf3ce44SJohn Forte 		break;
1321fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
1322fcf3ce44SJohn Forte 	default:
1323fcf3ce44SJohn Forte 		ASSERT(FALSE);
1324fcf3ce44SJohn Forte 	}
1325fcf3ce44SJohn Forte }
1326fcf3ce44SJohn Forte 
1327fcf3ce44SJohn Forte 
1328fcf3ce44SJohn Forte /*
1329fcf3ce44SJohn Forte  * iscsi_cmd_state_str -
1330fcf3ce44SJohn Forte  *
1331fcf3ce44SJohn Forte  */
1332fcf3ce44SJohn Forte static char *
1333fcf3ce44SJohn Forte iscsi_cmd_state_str(iscsi_cmd_state_t state)
1334fcf3ce44SJohn Forte {
1335fcf3ce44SJohn Forte 	switch (state) {
1336fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_FREE:
1337fcf3ce44SJohn Forte 		return ("free");
1338fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_PENDING:
1339fcf3ce44SJohn Forte 		return ("pending");
1340fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_ACTIVE:
1341fcf3ce44SJohn Forte 		return ("active");
1342fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_ABORTING:
1343fcf3ce44SJohn Forte 		return ("aborting");
1344*30e7468fSPeter Dunlap 	case ISCSI_CMD_STATE_IDM_ABORTING:
1345*30e7468fSPeter Dunlap 		return ("idm-aborting");
1346fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_COMPLETED:
1347fcf3ce44SJohn Forte 		return ("completed");
1348fcf3ce44SJohn Forte 	default:
1349fcf3ce44SJohn Forte 		return ("unknown");
1350fcf3ce44SJohn Forte 	}
1351fcf3ce44SJohn Forte }
1352fcf3ce44SJohn Forte 
1353fcf3ce44SJohn Forte 
1354fcf3ce44SJohn Forte /*
1355fcf3ce44SJohn Forte  * iscsi_cmd_event_str -
1356fcf3ce44SJohn Forte  *
1357fcf3ce44SJohn Forte  */
1358fcf3ce44SJohn Forte static char *
1359fcf3ce44SJohn Forte iscsi_cmd_event_str(iscsi_cmd_event_t event)
1360fcf3ce44SJohn Forte {
1361fcf3ce44SJohn Forte 	switch (event) {
1362fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E1:
1363fcf3ce44SJohn Forte 		return ("E1");
1364fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E2:
1365fcf3ce44SJohn Forte 		return ("E2");
1366fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E3:
1367fcf3ce44SJohn Forte 		return ("E3");
1368fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E4:
1369fcf3ce44SJohn Forte 		return ("E4");
1370fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E6:
1371fcf3ce44SJohn Forte 		return ("E6");
1372fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E7:
1373fcf3ce44SJohn Forte 		return ("E7");
1374fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E8:
1375fcf3ce44SJohn Forte 		return ("E8");
1376*30e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E9:
1377*30e7468fSPeter Dunlap 		return ("E9");
1378*30e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E10:
1379*30e7468fSPeter Dunlap 		return ("E10");
1380fcf3ce44SJohn Forte 	default:
1381fcf3ce44SJohn Forte 		return ("unknown");
1382fcf3ce44SJohn Forte 	}
1383fcf3ce44SJohn Forte }
1384fcf3ce44SJohn Forte 
1385fcf3ce44SJohn Forte 
1386fcf3ce44SJohn Forte /*
1387fcf3ce44SJohn Forte  * iscsi_cmd_event_str -
1388fcf3ce44SJohn Forte  *
1389fcf3ce44SJohn Forte  */
1390fcf3ce44SJohn Forte static char *
1391fcf3ce44SJohn Forte iscsi_cmd_type_str(iscsi_cmd_type_t type)
1392fcf3ce44SJohn Forte {
1393fcf3ce44SJohn Forte 	switch (type) {
1394fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_SCSI:
1395fcf3ce44SJohn Forte 		return ("scsi");
1396fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_NOP:
1397fcf3ce44SJohn Forte 		return ("nop");
1398fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_ABORT:
1399fcf3ce44SJohn Forte 		return ("abort");
1400fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_RESET:
1401fcf3ce44SJohn Forte 		return ("reset");
1402fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_LOGOUT:
1403fcf3ce44SJohn Forte 		return ("logout");
1404fcf3ce44SJohn Forte 	default:
1405fcf3ce44SJohn Forte 		return ("unknown");
1406fcf3ce44SJohn Forte 	}
1407fcf3ce44SJohn Forte }
1408