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 /*
2230e7468fSPeter Dunlap  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23fcf3ce44SJohn Forte  * Use is subject to license terms.
24fcf3ce44SJohn Forte  *
25*61dfa509SRick McNeal  * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
26fcf3ce44SJohn Forte  * iSCSI command interfaces
27fcf3ce44SJohn Forte  */
28fcf3ce44SJohn Forte 
29fcf3ce44SJohn Forte #include "iscsi.h"
30fcf3ce44SJohn Forte 
31fcf3ce44SJohn Forte /* internal interfaces */
32fcf3ce44SJohn Forte static void iscsi_cmd_state_free(iscsi_cmd_t *icmdp,
33fcf3ce44SJohn Forte     iscsi_cmd_event_t event, void *arg);
34fcf3ce44SJohn Forte static void iscsi_cmd_state_pending(iscsi_cmd_t *icmdp,
35fcf3ce44SJohn Forte     iscsi_cmd_event_t event, void *arg);
36fcf3ce44SJohn Forte static void iscsi_cmd_state_active(iscsi_cmd_t *icmdp,
37fcf3ce44SJohn Forte     iscsi_cmd_event_t event, void *arg);
38fcf3ce44SJohn Forte static void iscsi_cmd_state_aborting(iscsi_cmd_t *icmdp,
39fcf3ce44SJohn Forte     iscsi_cmd_event_t event, void *arg);
4030e7468fSPeter Dunlap static void iscsi_cmd_state_idm_aborting(iscsi_cmd_t *icmdp,
4130e7468fSPeter Dunlap     iscsi_cmd_event_t event, void *arg);
42fcf3ce44SJohn Forte static void iscsi_cmd_state_completed(iscsi_cmd_t *icmdp,
43fcf3ce44SJohn Forte     iscsi_cmd_event_t event, void *arg);
44fcf3ce44SJohn Forte static char *iscsi_cmd_state_str(iscsi_cmd_state_t state);
45fcf3ce44SJohn Forte static char *iscsi_cmd_event_str(iscsi_cmd_event_t event);
46fcf3ce44SJohn Forte /* LINTED E_STATIC_UNUSED */
47fcf3ce44SJohn Forte static char *iscsi_cmd_type_str(iscsi_cmd_type_t type);
48fcf3ce44SJohn Forte 
49fcf3ce44SJohn Forte #define	ISCSI_INTERNAL_CMD_TIMEOUT	60
50fcf3ce44SJohn Forte 
51fcf3ce44SJohn Forte #define	ISCSI_CMD_ISSUE_CALLBACK(icmdp, status)	\
52fcf3ce44SJohn Forte 	icmdp->cmd_completed = B_TRUE;		\
53fcf3ce44SJohn Forte 	icmdp->cmd_result = status;		\
54fcf3ce44SJohn Forte 	cv_broadcast(&icmdp->cmd_completion);
55fcf3ce44SJohn Forte 
56fcf3ce44SJohn Forte #define	ISCSI_CMD_SET_REASON_STAT(icmdp, reason, stat)	\
57fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.pkt->pkt_reason = reason;	\
58fcf3ce44SJohn Forte 	icmdp->cmd_un.scsi.pkt->pkt_statistics = stat;
59fcf3ce44SJohn Forte 
60fcf3ce44SJohn Forte /*
61fcf3ce44SJohn Forte  * The following private tunable, settable via
62fcf3ce44SJohn Forte  *	set iscsi:iscsi_cmd_timeout_factor = 2
63fcf3ce44SJohn Forte  * in /etc/system, provides customer relief for configurations experiencing
64fcf3ce44SJohn Forte  * SCSI command timeouts due to high-latency/high-loss network connections
65fcf3ce44SJohn Forte  * or slow target response (possibly due to backing store issues). If frequent
66fcf3ce44SJohn Forte  * use of this tunable is necessary, a beter mechanism must be provided.
67fcf3ce44SJohn Forte  */
68fcf3ce44SJohn Forte int	iscsi_cmd_timeout_factor = 1;
69fcf3ce44SJohn Forte 
70fcf3ce44SJohn Forte /*
71fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
72fcf3ce44SJohn Forte  * | External Command Interfaces					|
73fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
74fcf3ce44SJohn Forte  */
75fcf3ce44SJohn Forte 
76fcf3ce44SJohn Forte /*
77fcf3ce44SJohn Forte  * iscsi_cmd_state_machine - This function is used to drive the
78fcf3ce44SJohn Forte  * state machine of the internal iscsi commands.  It takes in a command
79fcf3ce44SJohn Forte  * and the associated event affecting the command.
80fcf3ce44SJohn Forte  *
81fcf3ce44SJohn Forte  * 7.1.3  Command State Diagram for an Initiator
82fcf3ce44SJohn Forte  *      Symbolic Names for States:
83fcf3ce44SJohn Forte  *      C1: FREE        - State on instantiation, or after successful
84fcf3ce44SJohn Forte  *                        completion.
85fcf3ce44SJohn Forte  *      C2: PENDING     - Command is in the session's pending queue awaiting
86fcf3ce44SJohn Forte  *                        its turn to be sent on the wire.
87fcf3ce44SJohn Forte  *      C3: ACTIVE      - Command has been sent on the wire and is
88fcf3ce44SJohn Forte  *                        awaiting completion.
89fcf3ce44SJohn Forte  *      C4: ABORTING    - Command which was sent on the wire has not timed
90fcf3ce44SJohn Forte  *                        out or been requested to abort by an upper layer
91fcf3ce44SJohn Forte  *                        driver.  At this point there is a task management
92fcf3ce44SJohn Forte  *                        command in the active queue trying to abort the task.
9330e7468fSPeter Dunlap  *	C4': IDM ABORTING - SCSI command is owned by IDM and idm_task_abort
9430e7468fSPeter Dunlap  *                          has been called for this command.
95fcf3ce44SJohn Forte  *      C5: COMPLETED	- Command which is ready to complete via pkt callback.
96fcf3ce44SJohn Forte  *
97fcf3ce44SJohn Forte  *      The state diagram is as follows:
98fcf3ce44SJohn Forte  *               -------
99fcf3ce44SJohn Forte  *              / C1    \
100fcf3ce44SJohn Forte  *    I-------->\       /<------------
101fcf3ce44SJohn Forte  *    N|         ---+---             |
102fcf3ce44SJohn Forte  *    T|            |E1              |
103fcf3ce44SJohn Forte  *    E|            V                |
104fcf3ce44SJohn Forte  *    R|         -------             |
105fcf3ce44SJohn Forte  *    N+--------/ C2    \            |
106fcf3ce44SJohn Forte  *    A|  E4/6/7\       /--------    |
107fcf3ce44SJohn Forte  *    L|         ---+---  E4/6/7|    |
10830e7468fSPeter Dunlap  *     |            |E2    E10  |    |
109fcf3ce44SJohn Forte  *    C|            V           | S  |
110fcf3ce44SJohn Forte  *    M|         _______        | C  |
111fcf3ce44SJohn Forte  *    D+--------/ C3    \       | S  |
112fcf3ce44SJohn Forte  *    S E3/4/6/7\       /-------+ I  |
11330e7468fSPeter Dunlap  *              /---+---E3/4/6/7|    |
11430e7468fSPeter Dunlap  *             /    |      E9/10|    |
11530e7468fSPeter Dunlap  *      ------/ E4/6|           | C  |
11630e7468fSPeter Dunlap  *      |           V           | M  |
11730e7468fSPeter Dunlap  *    E7|        -------        | D  |
11830e7468fSPeter Dunlap  *  SCSI|    - >/ C4    \       | S  |
11930e7468fSPeter Dunlap  *      |   /   \       /-------+    |
12030e7468fSPeter Dunlap  *      |   |    ---+---E3/6/7/9|    |
12130e7468fSPeter Dunlap  *      |   |  E4|  |           V   /E8
12230e7468fSPeter Dunlap  *      |   ------  |        -------
12330e7468fSPeter Dunlap  *      +-\         /       / C5    \
12430e7468fSPeter Dunlap  *      V  \-------/  /---->\       /
12530e7468fSPeter Dunlap  *   -------    E7   /       ---+---
12630e7468fSPeter Dunlap  *  / C4'   \       /
12730e7468fSPeter Dunlap  *  \       /------/ E9
12830e7468fSPeter Dunlap  *   -------
129fcf3ce44SJohn Forte  *
130fcf3ce44SJohn Forte  * The state transition table is as follows:
131fcf3ce44SJohn Forte  *
13230e7468fSPeter Dunlap  *         +---------+---+---+-----+----+--------------+
13330e7468fSPeter Dunlap  *         |C1       |C2 |C3 |C4   |C4' |C5            |
13430e7468fSPeter Dunlap  *      ---+---------+---+---+-----+----+--------------+
13530e7468fSPeter Dunlap  *       C1| -       |E1 | - | -   | -  |              |
13630e7468fSPeter Dunlap  *      ---+---------+---+---+-----+----+--------------+
13730e7468fSPeter Dunlap  *       C2|E4/6/7   |-  |E2 | -   | -  |E4/6/7/10     |
13830e7468fSPeter Dunlap  *      ---+---------+---+---+-----+----+--------------+
13930e7468fSPeter Dunlap  *       C3|E3/4/6/7 |-  |-  |E4/6 |E7  |E3/4/6/7/9/10 |
14030e7468fSPeter Dunlap  *      ---+---------+---+---+-----+----+--------------+
14130e7468fSPeter Dunlap  *       C4|         |-  |-  |E4   |E7  |E3/6/7/9      |
14230e7468fSPeter Dunlap  *      ---+---------+---+---+-----+----+--------------+
14330e7468fSPeter Dunlap  *      C4'|         |-  |-  |-    |-   |E9            |
14430e7468fSPeter Dunlap  *      ---+---------+---+---+-----+----+--------------+
14530e7468fSPeter Dunlap  *       C5|E8       |   |   |     |    |              |
14630e7468fSPeter Dunlap  *      ---+---------+---+---+-----+----+--------------+
147fcf3ce44SJohn Forte  *
148fcf3ce44SJohn Forte  * Event definitions:
149fcf3ce44SJohn Forte  *
150fcf3ce44SJohn Forte  * -E1: Command was requested to be sent on wire
151fcf3ce44SJohn Forte  * -E2: Command was submitted and now active on wire
152fcf3ce44SJohn Forte  * -E3: Command was successfully completed
153fcf3ce44SJohn Forte  *	- SCSI command is move to completion queue
154fcf3ce44SJohn Forte  *	- ABORT/RESET/etc are completed.
155fcf3ce44SJohn Forte  * -E4: Command has been requested to abort
156fcf3ce44SJohn Forte  *	- SCSI command in pending queue will be returned
157fcf3ce44SJohn Forte  *		to caller with aborted status.
158fcf3ce44SJohn Forte  *	- SCSI command state updated and iscsi_handle_abort()
159fcf3ce44SJohn Forte  *		will be called.
160fcf3ce44SJohn Forte  *	- SCSI command with ABORTING state has already
161fcf3ce44SJohn Forte  *		been requested to abort ignore request.
162fcf3ce44SJohn Forte  *	- ABORT/RESET commands will be destroyed and the
163fcf3ce44SJohn Forte  *		caller will be notify of the failure.
164fcf3ce44SJohn Forte  *	- All other commands will just be destroyed.
165fcf3ce44SJohn Forte  * -E6: Command has timed out
166fcf3ce44SJohn Forte  *	- SCSI commands in pending queue will be returned up the
167fcf3ce44SJohn Forte  *		stack with TIMEOUT errors.
168fcf3ce44SJohn Forte  *	- SCSI commands in the active queue and timed out
169fcf3ce44SJohn Forte  *		will be moved to the aborting queue.
170fcf3ce44SJohn Forte  *	- SCSI commands in ABORTING state will be returned up
171fcf3ce44SJohn Forte  *		up the stack with TIMEOUT errors.
172fcf3ce44SJohn Forte  *	- ABORT/RESET commands will be destroyed and the caller
173fcf3ce44SJohn Forte  *		notified of the failure.
174fcf3ce44SJohn Forte  *	- All other commands will just be detroyed.
175fcf3ce44SJohn Forte  * -E7: Connection has encountered a problem
176fcf3ce44SJohn Forte  * -E8:	Command has completed
177fcf3ce44SJohn Forte  *	- Only SCSI cmds should receive these events
178fcf3ce44SJohn Forte  *		and reach the command state.
17930e7468fSPeter Dunlap  * -E9: Callback received for previous idm_task_abort request
18030e7468fSPeter Dunlap  * -E10: The command this abort was associated with has terminated on its own
181fcf3ce44SJohn Forte  */
182fcf3ce44SJohn Forte void
iscsi_cmd_state_machine(iscsi_cmd_t * icmdp,iscsi_cmd_event_t event,void * arg)183fcf3ce44SJohn Forte iscsi_cmd_state_machine(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
184fcf3ce44SJohn Forte {
185fcf3ce44SJohn Forte 	boolean_t	release_lock = B_TRUE;
186fcf3ce44SJohn Forte 
187fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
188fcf3ce44SJohn Forte 	ASSERT(arg != NULL);
189fcf3ce44SJohn Forte 
190fcf3ce44SJohn Forte 	DTRACE_PROBE3(event, iscsi_cmd_t *, icmdp, char *,
191fcf3ce44SJohn Forte 	    iscsi_cmd_state_str(icmdp->cmd_state),
192fcf3ce44SJohn Forte 	    char *, iscsi_cmd_event_str(event));
193fcf3ce44SJohn Forte 
194fcf3ce44SJohn Forte 	mutex_enter(&icmdp->cmd_mutex);
19530e7468fSPeter Dunlap 
19630e7468fSPeter Dunlap 	/* Audit event */
19730e7468fSPeter Dunlap 	idm_sm_audit_event(&icmdp->cmd_state_audit,
19830e7468fSPeter Dunlap 	    SAS_ISCSI_CMD, icmdp->cmd_state, event, (uintptr_t)arg);
19930e7468fSPeter Dunlap 
200fcf3ce44SJohn Forte 	icmdp->cmd_prev_state = icmdp->cmd_state;
201fcf3ce44SJohn Forte 	switch (icmdp->cmd_state) {
202fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_FREE:
203fcf3ce44SJohn Forte 		iscsi_cmd_state_free(icmdp, event, arg);
204fcf3ce44SJohn Forte 		break;
205fcf3ce44SJohn Forte 
206fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_PENDING:
207fcf3ce44SJohn Forte 		iscsi_cmd_state_pending(icmdp, event, arg);
208fcf3ce44SJohn Forte 		break;
209fcf3ce44SJohn Forte 
210fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_ACTIVE:
211fcf3ce44SJohn Forte 		iscsi_cmd_state_active(icmdp, event, arg);
212fcf3ce44SJohn Forte 		break;
213fcf3ce44SJohn Forte 
214fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_ABORTING:
215fcf3ce44SJohn Forte 		iscsi_cmd_state_aborting(icmdp, event, arg);
216fcf3ce44SJohn Forte 		break;
217fcf3ce44SJohn Forte 
21830e7468fSPeter Dunlap 	case ISCSI_CMD_STATE_IDM_ABORTING:
21930e7468fSPeter Dunlap 		iscsi_cmd_state_idm_aborting(icmdp, event, arg);
22030e7468fSPeter Dunlap 		break;
22130e7468fSPeter Dunlap 
222fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_COMPLETED:
223fcf3ce44SJohn Forte 		iscsi_cmd_state_completed(icmdp, event, arg);
224fcf3ce44SJohn Forte 
225fcf3ce44SJohn Forte 		/*
226fcf3ce44SJohn Forte 		 * Once completed event is processed we DO NOT
227fcf3ce44SJohn Forte 		 * want to touch it again because the caller
228fcf3ce44SJohn Forte 		 * (sd, st, etc) may have freed the command.
229fcf3ce44SJohn Forte 		 */
230fcf3ce44SJohn Forte 		release_lock = B_FALSE;
231fcf3ce44SJohn Forte 		break;
232fcf3ce44SJohn Forte 
233fcf3ce44SJohn Forte 	default:
234fcf3ce44SJohn Forte 		ASSERT(FALSE);
235fcf3ce44SJohn Forte 	}
236fcf3ce44SJohn Forte 
237fcf3ce44SJohn Forte 	if (release_lock == B_TRUE) {
23830e7468fSPeter Dunlap 		/* Audit state if not completed */
23930e7468fSPeter Dunlap 		idm_sm_audit_state_change(&icmdp->cmd_state_audit,
24030e7468fSPeter Dunlap 		    SAS_ISCSI_CMD, icmdp->cmd_prev_state, icmdp->cmd_state);
24130e7468fSPeter Dunlap 
242d233de7eSJack Meng 		if (!(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_FREE) ||
243d233de7eSJack Meng 		    !(icmdp->cmd_misc_flags &
244d233de7eSJack Meng 		    ISCSI_CMD_MISCFLAG_INTERNAL)) {
245fcf3ce44SJohn Forte 			mutex_exit(&icmdp->cmd_mutex);
246fcf3ce44SJohn Forte 			return;
247fcf3ce44SJohn Forte 		}
248fcf3ce44SJohn Forte 		mutex_exit(&icmdp->cmd_mutex);
249fcf3ce44SJohn Forte 		iscsi_cmd_free(icmdp);
250fcf3ce44SJohn Forte 	}
251fcf3ce44SJohn Forte }
252fcf3ce44SJohn Forte 
253fcf3ce44SJohn Forte /*
254fcf3ce44SJohn Forte  * iscsi_cmd_alloc -
255fcf3ce44SJohn Forte  *
256fcf3ce44SJohn Forte  */
257fcf3ce44SJohn Forte iscsi_cmd_t *
iscsi_cmd_alloc(iscsi_conn_t * icp,int km_flags)258fcf3ce44SJohn Forte iscsi_cmd_alloc(iscsi_conn_t *icp, int km_flags)
259fcf3ce44SJohn Forte {
260fcf3ce44SJohn Forte 	iscsi_cmd_t	*icmdp;
261fcf3ce44SJohn Forte 
262fcf3ce44SJohn Forte 	icmdp = kmem_zalloc(sizeof (iscsi_cmd_t), km_flags);
263fcf3ce44SJohn Forte 	if (icmdp) {
264fcf3ce44SJohn Forte 		icmdp->cmd_sig		= ISCSI_SIG_CMD;
265fcf3ce44SJohn Forte 		icmdp->cmd_state	= ISCSI_CMD_STATE_FREE;
266fcf3ce44SJohn Forte 		icmdp->cmd_conn		= icp;
267d233de7eSJack Meng 		icmdp->cmd_misc_flags	|= ISCSI_CMD_MISCFLAG_INTERNAL;
26830e7468fSPeter Dunlap 		idm_sm_audit_init(&icmdp->cmd_state_audit);
269fcf3ce44SJohn Forte 		mutex_init(&icmdp->cmd_mutex, NULL, MUTEX_DRIVER, NULL);
270fcf3ce44SJohn Forte 		cv_init(&icmdp->cmd_completion, NULL, CV_DRIVER, NULL);
271fcf3ce44SJohn Forte 	}
272fcf3ce44SJohn Forte 	return (icmdp);
273fcf3ce44SJohn Forte }
274fcf3ce44SJohn Forte 
275fcf3ce44SJohn Forte /*
276fcf3ce44SJohn Forte  * iscsi_cmd_free -
277fcf3ce44SJohn Forte  *
278fcf3ce44SJohn Forte  */
279fcf3ce44SJohn Forte void
iscsi_cmd_free(iscsi_cmd_t * icmdp)280fcf3ce44SJohn Forte iscsi_cmd_free(iscsi_cmd_t *icmdp)
281fcf3ce44SJohn Forte {
282fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
283fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_sig == ISCSI_SIG_CMD);
284fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_FREE);
285fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_next == NULL);
286fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_prev == NULL);
287d233de7eSJack Meng 	ASSERT(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_INTERNAL);
28830e7468fSPeter Dunlap 	if (icmdp->cmd_type == ISCSI_CMD_TYPE_ABORT)
289fcf3ce44SJohn Forte 		ASSERT(icmdp->cmd_un.abort.icmdp == NULL);
290fcf3ce44SJohn Forte 	else if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
291fcf3ce44SJohn Forte 		ASSERT(icmdp->cmd_un.scsi.r2t_icmdp == NULL);
292fcf3ce44SJohn Forte 		ASSERT(icmdp->cmd_un.scsi.abort_icmdp == NULL);
293fcf3ce44SJohn Forte 	}
294fcf3ce44SJohn Forte 	mutex_destroy(&icmdp->cmd_mutex);
295fcf3ce44SJohn Forte 	cv_destroy(&icmdp->cmd_completion);
296fcf3ce44SJohn Forte 	kmem_free(icmdp, sizeof (iscsi_cmd_t));
297fcf3ce44SJohn Forte }
298fcf3ce44SJohn Forte 
299fcf3ce44SJohn Forte /*
300fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
301fcf3ce44SJohn Forte  * | Internal Command Interfaces					|
302fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
303fcf3ce44SJohn Forte  */
304fcf3ce44SJohn Forte /*
305fcf3ce44SJohn Forte  * iscsi_cmd_state_free -
306fcf3ce44SJohn Forte  *
307fcf3ce44SJohn Forte  */
308fcf3ce44SJohn Forte static void
iscsi_cmd_state_free(iscsi_cmd_t * icmdp,iscsi_cmd_event_t event,void * arg)309fcf3ce44SJohn Forte iscsi_cmd_state_free(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
310fcf3ce44SJohn Forte {
311fcf3ce44SJohn Forte 	iscsi_sess_t	*isp		= (iscsi_sess_t *)arg;
312fcf3ce44SJohn Forte 
313fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
314fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_FREE);
315fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
316fcf3ce44SJohn Forte 
317fcf3ce44SJohn Forte 	/* switch on event change */
318fcf3ce44SJohn Forte 	switch (event) {
319fcf3ce44SJohn Forte 	/* -E1: Command was requested to be sent on wire */
320fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E1:
321fcf3ce44SJohn Forte 
322fcf3ce44SJohn Forte 		/* setup timestamps and timeouts for this command */
323fcf3ce44SJohn Forte 		icmdp->cmd_lbolt_pending = ddi_get_lbolt();
324fcf3ce44SJohn Forte 		if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
325fcf3ce44SJohn Forte 			/*
326fcf3ce44SJohn Forte 			 * Establish absolute time when command should timeout.
32730e7468fSPeter Dunlap 			 * For commands that depend on cmdsn window to go
328fcf3ce44SJohn Forte 			 * active, the timeout will be ignored while on
329fcf3ce44SJohn Forte 			 * the pending queue and a new timeout will be
330fcf3ce44SJohn Forte 			 * established when the command goes active.
331fcf3ce44SJohn Forte 			 */
332fcf3ce44SJohn Forte 			if (icmdp->cmd_un.scsi.pkt &&
333fcf3ce44SJohn Forte 			    icmdp->cmd_un.scsi.pkt->pkt_time)
334fcf3ce44SJohn Forte 				icmdp->cmd_lbolt_timeout =
335fcf3ce44SJohn Forte 				    icmdp->cmd_lbolt_pending + SEC_TO_TICK(
336fcf3ce44SJohn Forte 				    icmdp->cmd_un.scsi.pkt->pkt_time *
337fcf3ce44SJohn Forte 				    iscsi_cmd_timeout_factor);
338fcf3ce44SJohn Forte 			else
339fcf3ce44SJohn Forte 				icmdp->cmd_lbolt_timeout = 0;
3402b79d384Sbing zhao - Sun Microsystems - Beijing China 
3412b79d384Sbing zhao - Sun Microsystems - Beijing China 			icmdp->cmd_un.scsi.pkt_stat &=
3422b79d384Sbing zhao - Sun Microsystems - Beijing China 			    ISCSI_CMD_PKT_STAT_INIT;
343fcf3ce44SJohn Forte 		} else {
344fcf3ce44SJohn Forte 			icmdp->cmd_lbolt_timeout = icmdp->cmd_lbolt_pending +
345fcf3ce44SJohn Forte 			    SEC_TO_TICK(ISCSI_INTERNAL_CMD_TIMEOUT *
346fcf3ce44SJohn Forte 			    iscsi_cmd_timeout_factor);
347fcf3ce44SJohn Forte 		}
348fcf3ce44SJohn Forte 
349fcf3ce44SJohn Forte 		/* place into pending queue */
350fcf3ce44SJohn Forte 		iscsi_enqueue_pending_cmd(isp, icmdp);
351fcf3ce44SJohn Forte 
352fcf3ce44SJohn Forte 		break;
353fcf3ce44SJohn Forte 
354fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
355fcf3ce44SJohn Forte 	default:
356fcf3ce44SJohn Forte 		ASSERT(FALSE);
357fcf3ce44SJohn Forte 	}
358fcf3ce44SJohn Forte }
359fcf3ce44SJohn Forte 
360fcf3ce44SJohn Forte /*
361fcf3ce44SJohn Forte  * iscsi_cmd_state_pending -
362fcf3ce44SJohn Forte  *
363fcf3ce44SJohn Forte  */
364fcf3ce44SJohn Forte static void
iscsi_cmd_state_pending(iscsi_cmd_t * icmdp,iscsi_cmd_event_t event,void * arg)365fcf3ce44SJohn Forte iscsi_cmd_state_pending(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
366fcf3ce44SJohn Forte {
367fcf3ce44SJohn Forte 	iscsi_status_t	status;
368fcf3ce44SJohn Forte 	iscsi_sess_t	*isp		= (iscsi_sess_t *)arg;
369fcf3ce44SJohn Forte 	boolean_t	free_icmdp	= B_FALSE;
370fcf3ce44SJohn Forte 	int		rval;
371fcf3ce44SJohn Forte 
372fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
373fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_PENDING);
374fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
375fcf3ce44SJohn Forte 
376fcf3ce44SJohn Forte 	/* switch on event change */
377fcf3ce44SJohn Forte 	switch (event) {
378fcf3ce44SJohn Forte 	/* -E2: Command was submitted and now active on wire */
379fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E2:
380fcf3ce44SJohn Forte 
381fcf3ce44SJohn Forte 		/* A connection should have already been assigned */
38230e7468fSPeter Dunlap 		ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
383fcf3ce44SJohn Forte 		ASSERT(icmdp->cmd_conn != NULL);
384fcf3ce44SJohn Forte 
385fcf3ce44SJohn Forte 		/*
386fcf3ce44SJohn Forte 		 * RESERVE RESOURSES
387fcf3ce44SJohn Forte 		 */
388fcf3ce44SJohn Forte 		switch (icmdp->cmd_type) {
389fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_SCSI:
390fcf3ce44SJohn Forte 			/* check cmdsn window */
391fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
392fcf3ce44SJohn Forte 			if (!iscsi_sna_lte(isp->sess_cmdsn,
393fcf3ce44SJohn Forte 			    isp->sess_maxcmdsn)) {
394fcf3ce44SJohn Forte 				/* cmdsn window closed */
395fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_cmdsn_mutex);
396fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_queue_pending.mutex);
397fcf3ce44SJohn Forte 				isp->sess_window_open = B_FALSE;
398d233de7eSJack Meng 				icmdp->cmd_misc_flags |=
399d233de7eSJack Meng 				    ISCSI_CMD_MISCFLAG_STUCK;
400fcf3ce44SJohn Forte 				return;
401fcf3ce44SJohn Forte 			}
402fcf3ce44SJohn Forte 
403fcf3ce44SJohn Forte 			/* assign itt */
40430e7468fSPeter Dunlap 			status = iscsi_sess_reserve_scsi_itt(icmdp);
405fcf3ce44SJohn Forte 			if (!ISCSI_SUCCESS(status)) {
406fcf3ce44SJohn Forte 				/* no available itt slots */
407fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_cmdsn_mutex);
408fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_queue_pending.mutex);
409fcf3ce44SJohn Forte 				isp->sess_window_open = B_FALSE;
410d233de7eSJack Meng 				icmdp->cmd_misc_flags |=
411d233de7eSJack Meng 				    ISCSI_CMD_MISCFLAG_STUCK;
412fcf3ce44SJohn Forte 				return;
413fcf3ce44SJohn Forte 			}
414fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
415fcf3ce44SJohn Forte 			break;
416fcf3ce44SJohn Forte 
417fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_ABORT:
418fcf3ce44SJohn Forte 			/*
419fcf3ce44SJohn Forte 			 * Verify ABORT's parent SCSI command is still
420fcf3ce44SJohn Forte 			 * there.  If parent SCSI command is completed
421fcf3ce44SJohn Forte 			 * then there is no longer any reason to abort
422fcf3ce44SJohn Forte 			 * the parent command.  This could occur due
423fcf3ce44SJohn Forte 			 * to a connection or target reset.
424fcf3ce44SJohn Forte 			 */
425fcf3ce44SJohn Forte 			ASSERT(icmdp->cmd_un.abort.icmdp != NULL);
426fcf3ce44SJohn Forte 			if (icmdp->cmd_un.abort.icmdp->cmd_state ==
427fcf3ce44SJohn Forte 			    ISCSI_CMD_STATE_COMPLETED) {
428fcf3ce44SJohn Forte 				iscsi_dequeue_pending_cmd(isp, icmdp);
429fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_queue_pending.mutex);
430fcf3ce44SJohn Forte 
431fcf3ce44SJohn Forte 				mutex_enter(&icmdp->cmd_un.abort.icmdp->
432fcf3ce44SJohn Forte 				    cmd_mutex);
433fcf3ce44SJohn Forte 				icmdp->cmd_un.abort.icmdp->
434fcf3ce44SJohn Forte 				    cmd_un.scsi.abort_icmdp = NULL;
435fcf3ce44SJohn Forte 				cv_broadcast(&icmdp->cmd_un.abort.icmdp->
436fcf3ce44SJohn Forte 				    cmd_completion);
437fcf3ce44SJohn Forte 				mutex_exit(&icmdp->cmd_un.abort.icmdp->
438fcf3ce44SJohn Forte 				    cmd_mutex);
439fcf3ce44SJohn Forte 				icmdp->cmd_un.abort.icmdp = NULL;
440fcf3ce44SJohn Forte 
441fcf3ce44SJohn Forte 				icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
442d233de7eSJack Meng 				icmdp->cmd_misc_flags |=
443d233de7eSJack Meng 				    ISCSI_CMD_MISCFLAG_FREE;
444fcf3ce44SJohn Forte 				return;
445fcf3ce44SJohn Forte 			}
446fcf3ce44SJohn Forte 			/* FALLTHRU */
447fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_RESET:
448fcf3ce44SJohn Forte 			/* FALLTHRU */
449fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_LOGOUT:
450fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
451fcf3ce44SJohn Forte 			/* assign itt */
452fcf3ce44SJohn Forte 			status = iscsi_sess_reserve_itt(isp, icmdp);
453fcf3ce44SJohn Forte 			if (!ISCSI_SUCCESS(status)) {
454fcf3ce44SJohn Forte 				/* no available itt slots */
455fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_cmdsn_mutex);
456fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_queue_pending.mutex);
457fcf3ce44SJohn Forte 				isp->sess_window_open = B_FALSE;
458fcf3ce44SJohn Forte 				return;
459fcf3ce44SJohn Forte 			}
460fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
461fcf3ce44SJohn Forte 			break;
462fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_NOP:
463fcf3ce44SJohn Forte 			/* assign itt, if needed */
464fcf3ce44SJohn Forte 			if (icmdp->cmd_itt == ISCSI_RSVD_TASK_TAG) {
465fcf3ce44SJohn Forte 				/* not expecting a response */
466fcf3ce44SJohn Forte 				free_icmdp = B_TRUE;
467fcf3ce44SJohn Forte 			} else {
468fcf3ce44SJohn Forte 				/* expecting response, assign an itt */
469fcf3ce44SJohn Forte 				mutex_enter(&isp->sess_cmdsn_mutex);
470fcf3ce44SJohn Forte 				/* assign itt */
471fcf3ce44SJohn Forte 				status = iscsi_sess_reserve_itt(isp, icmdp);
472fcf3ce44SJohn Forte 				if (!ISCSI_SUCCESS(status)) {
473fcf3ce44SJohn Forte 					/* no available itt slots */
474fcf3ce44SJohn Forte 					mutex_exit(&isp->sess_cmdsn_mutex);
475fcf3ce44SJohn Forte 					mutex_exit(&isp->sess_queue_pending.
476fcf3ce44SJohn Forte 					    mutex);
477fcf3ce44SJohn Forte 					isp->sess_window_open = B_FALSE;
478fcf3ce44SJohn Forte 					return;
479fcf3ce44SJohn Forte 				}
480fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_cmdsn_mutex);
481fcf3ce44SJohn Forte 			}
482fcf3ce44SJohn Forte 			break;
483fcf3ce44SJohn Forte 
484fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_TEXT:
485fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
486fcf3ce44SJohn Forte 			/* check cmdsn window */
487fcf3ce44SJohn Forte 			if (!iscsi_sna_lte(isp->sess_cmdsn,
488fcf3ce44SJohn Forte 			    isp->sess_maxcmdsn)) {
489fcf3ce44SJohn Forte 				/* cmdsn window closed */
490fcf3ce44SJohn Forte 				isp->sess_window_open = B_FALSE;
491fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_cmdsn_mutex);
492fcf3ce44SJohn Forte 				mutex_exit(&isp->sess_queue_pending.mutex);
493d233de7eSJack Meng 				icmdp->cmd_misc_flags |=
494d233de7eSJack Meng 				    ISCSI_CMD_MISCFLAG_STUCK;
495fcf3ce44SJohn Forte 				return;
496fcf3ce44SJohn Forte 			}
497fcf3ce44SJohn Forte 			if (icmdp->cmd_un.text.stage ==
498fcf3ce44SJohn Forte 			    ISCSI_CMD_TEXT_INITIAL_REQ) {
499fcf3ce44SJohn Forte 				/* assign itt */
500fcf3ce44SJohn Forte 				status = iscsi_sess_reserve_itt(isp, icmdp);
501fcf3ce44SJohn Forte 				if (!ISCSI_SUCCESS(status)) {
502fcf3ce44SJohn Forte 					/* no available itt slots */
503fcf3ce44SJohn Forte 					mutex_exit(&isp->sess_cmdsn_mutex);
504fcf3ce44SJohn Forte 					mutex_exit(&isp->sess_queue_pending.
505fcf3ce44SJohn Forte 					    mutex);
506fcf3ce44SJohn Forte 					isp->sess_window_open = B_FALSE;
507d233de7eSJack Meng 					icmdp->cmd_misc_flags |=
508d233de7eSJack Meng 					    ISCSI_CMD_MISCFLAG_STUCK;
509fcf3ce44SJohn Forte 					return;
510fcf3ce44SJohn Forte 				}
511fcf3ce44SJohn Forte 			}
512fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
513fcf3ce44SJohn Forte 			break;
514fcf3ce44SJohn Forte 
515fcf3ce44SJohn Forte 		default:
516fcf3ce44SJohn Forte 			ASSERT(FALSE);
517fcf3ce44SJohn Forte 		}
518fcf3ce44SJohn Forte 
519fcf3ce44SJohn Forte 		/*
520fcf3ce44SJohn Forte 		 * RESOURCES RESERVED
521fcf3ce44SJohn Forte 		 *
522fcf3ce44SJohn Forte 		 * Now that we have the resources reserved, establish timeout
523fcf3ce44SJohn Forte 		 * for cmd_type values that depend on having an open cmdsn
524fcf3ce44SJohn Forte 		 * window (i.e. cmd_type that called iscsi_sna_lte() above).
525fcf3ce44SJohn Forte 		 */
526fcf3ce44SJohn Forte 		if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
527fcf3ce44SJohn Forte 			if (icmdp->cmd_un.scsi.pkt &&
528fcf3ce44SJohn Forte 			    icmdp->cmd_un.scsi.pkt->pkt_time)
529fcf3ce44SJohn Forte 				icmdp->cmd_lbolt_timeout =
530fcf3ce44SJohn Forte 				    ddi_get_lbolt() + SEC_TO_TICK(
531fcf3ce44SJohn Forte 				    icmdp->cmd_un.scsi.pkt->pkt_time *
532fcf3ce44SJohn Forte 				    iscsi_cmd_timeout_factor);
533fcf3ce44SJohn Forte 			else
534fcf3ce44SJohn Forte 				icmdp->cmd_lbolt_timeout = 0;
535fcf3ce44SJohn Forte 		} else if (icmdp->cmd_type == ISCSI_CMD_TYPE_TEXT) {
536fcf3ce44SJohn Forte 			icmdp->cmd_lbolt_timeout = ddi_get_lbolt() +
537fcf3ce44SJohn Forte 			    SEC_TO_TICK(ISCSI_INTERNAL_CMD_TIMEOUT *
538fcf3ce44SJohn Forte 			    iscsi_cmd_timeout_factor);
539fcf3ce44SJohn Forte 		}
540fcf3ce44SJohn Forte 
541fcf3ce44SJohn Forte 		/* remove command from pending queue */
542fcf3ce44SJohn Forte 		iscsi_dequeue_pending_cmd(isp, icmdp);
543fcf3ce44SJohn Forte 		/* check if expecting a response */
544fcf3ce44SJohn Forte 		if (free_icmdp == B_FALSE) {
545fcf3ce44SJohn Forte 			/* response expected, move to active queue */
546fcf3ce44SJohn Forte 			mutex_enter(&icmdp->cmd_conn->conn_queue_active.mutex);
547fcf3ce44SJohn Forte 			iscsi_enqueue_active_cmd(icmdp->cmd_conn, icmdp);
548fcf3ce44SJohn Forte 			mutex_exit(&icmdp->cmd_conn->conn_queue_active.mutex);
549fcf3ce44SJohn Forte 		}
550fcf3ce44SJohn Forte 
551fcf3ce44SJohn Forte 		/*
552fcf3ce44SJohn Forte 		 * TRANSFER COMMAND
553fcf3ce44SJohn Forte 		 */
554fcf3ce44SJohn Forte 		rval = iscsi_tx_cmd(isp, icmdp);
555fcf3ce44SJohn Forte 
556fcf3ce44SJohn Forte 		ASSERT(!mutex_owned(&isp->sess_queue_pending.mutex));
557fcf3ce44SJohn Forte 
558fcf3ce44SJohn Forte 		/*
559fcf3ce44SJohn Forte 		 * CHECK SUCCESS/FAILURE
560fcf3ce44SJohn Forte 		 */
561fcf3ce44SJohn Forte 		if (!ISCSI_SUCCESS(rval)) {
562fcf3ce44SJohn Forte 			/*
563fcf3ce44SJohn Forte 			 * iscsi_tx_cmd failed.  No cleanup is required
564fcf3ce44SJohn Forte 			 * of commands that were put in the active queue.
565fcf3ce44SJohn Forte 			 * If the tx failed then rx will also fail and cleanup
566fcf3ce44SJohn Forte 			 * all items in the active/aborted queue in a common.
567fcf3ce44SJohn Forte 			 */
568fcf3ce44SJohn Forte 
569fcf3ce44SJohn Forte 			/* EMPTY */
570fcf3ce44SJohn Forte 		}
571fcf3ce44SJohn Forte 
572fcf3ce44SJohn Forte 		/* free temporary commands */
573fcf3ce44SJohn Forte 		if (free_icmdp == B_TRUE) {
574fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
575d233de7eSJack Meng 			icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_FREE;
576fcf3ce44SJohn Forte 		}
577fcf3ce44SJohn Forte 		break;
578fcf3ce44SJohn Forte 
57930e7468fSPeter Dunlap 	/* -E10: Abort is no longer required for this command */
58030e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E10:
58130e7468fSPeter Dunlap 		/*
58230e7468fSPeter Dunlap 		 * Acquiring the sess_queue_pending lock while the
58330e7468fSPeter Dunlap 		 * conn_queue_active lock is held conflicts with the
58430e7468fSPeter Dunlap 		 * locking order in iscsi_cmd_state_pending where
58530e7468fSPeter Dunlap 		 * conn_queue_active is acquired while sess_queue_pending
58630e7468fSPeter Dunlap 		 * is held.  Normally this would be a dangerous lock
58730e7468fSPeter Dunlap 		 * order conflict, except that we know that if we are
58830e7468fSPeter Dunlap 		 * seeing ISCSI_CMD_EVENT_E10 then the command being
58930e7468fSPeter Dunlap 		 * aborted is in "aborting" state and by extension
59030e7468fSPeter Dunlap 		 * is not in "pending" state.  Therefore the code
59130e7468fSPeter Dunlap 		 * path with that alternate lock order will not execute.
59230e7468fSPeter Dunlap 		 * That's good because we can't drop the lock here without
59330e7468fSPeter Dunlap 		 * risking a deadlock.
59430e7468fSPeter Dunlap 		 */
59530e7468fSPeter Dunlap 		ASSERT(mutex_owned(&icmdp->cmd_conn->conn_queue_active.mutex));
59630e7468fSPeter Dunlap 		mutex_enter(&isp->sess_queue_pending.mutex);
59730e7468fSPeter Dunlap 
59830e7468fSPeter Dunlap 		icmdp->cmd_lbolt_aborting = ddi_get_lbolt();
59930e7468fSPeter Dunlap 
60030e7468fSPeter Dunlap 		iscsi_dequeue_pending_cmd(isp, icmdp);
60130e7468fSPeter Dunlap 
60230e7468fSPeter Dunlap 		icmdp->cmd_un.abort.icmdp->cmd_un.scsi.abort_icmdp = NULL;
60330e7468fSPeter Dunlap 		icmdp->cmd_un.abort.icmdp = NULL;
60430e7468fSPeter Dunlap 		icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_FREE;
60530e7468fSPeter Dunlap 		icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
60630e7468fSPeter Dunlap 
60730e7468fSPeter Dunlap 		mutex_exit(&isp->sess_queue_pending.mutex);
60830e7468fSPeter Dunlap 		break;
60930e7468fSPeter Dunlap 
610fcf3ce44SJohn Forte 	/* -E4: Command has been requested to abort */
611fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E4:
61230e7468fSPeter Dunlap 		ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
613fcf3ce44SJohn Forte 
614fcf3ce44SJohn Forte 		icmdp->cmd_lbolt_aborting = ddi_get_lbolt();
615fcf3ce44SJohn Forte 		ISCSI_CMD_SET_REASON_STAT(icmdp,
616fcf3ce44SJohn Forte 		    CMD_ABORTED, STAT_ABORTED);
617fcf3ce44SJohn Forte 
618fcf3ce44SJohn Forte 		iscsi_dequeue_pending_cmd(isp, icmdp);
619fcf3ce44SJohn Forte 		iscsi_enqueue_completed_cmd(isp, icmdp);
620fcf3ce44SJohn Forte 
621fcf3ce44SJohn Forte 		icmdp->cmd_lbolt_aborting = ddi_get_lbolt();
622fcf3ce44SJohn Forte 
623fcf3ce44SJohn Forte 		break;
624fcf3ce44SJohn Forte 
625fcf3ce44SJohn Forte 	/* -E7: Command has been reset */
626fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E7:
627fcf3ce44SJohn Forte 
628fcf3ce44SJohn Forte 		/* FALLTHRU */
629fcf3ce44SJohn Forte 
630fcf3ce44SJohn Forte 	/* -E6: Command has timed out */
631fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E6:
63230e7468fSPeter Dunlap 		ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
633fcf3ce44SJohn Forte 		iscsi_dequeue_pending_cmd(isp, icmdp);
634fcf3ce44SJohn Forte 
635fcf3ce44SJohn Forte 		switch (icmdp->cmd_type) {
636fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_SCSI:
637fcf3ce44SJohn Forte 			/* Complete to caller as TIMEOUT */
638fcf3ce44SJohn Forte 			if (event == ISCSI_CMD_EVENT_E6) {
639fcf3ce44SJohn Forte 				ISCSI_CMD_SET_REASON_STAT(icmdp,
640fcf3ce44SJohn Forte 				    CMD_TIMEOUT, STAT_TIMEOUT);
641fcf3ce44SJohn Forte 			} else {
642fcf3ce44SJohn Forte 				ISCSI_CMD_SET_REASON_STAT(icmdp,
6432b79d384Sbing zhao - Sun Microsystems - Beijing China 				    CMD_TRAN_ERR, icmdp->cmd_un.scsi.pkt_stat);
644fcf3ce44SJohn Forte 			}
645fcf3ce44SJohn Forte 			iscsi_enqueue_completed_cmd(isp, icmdp);
646fcf3ce44SJohn Forte 			break;
647fcf3ce44SJohn Forte 
648fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_NOP:
649fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
650fcf3ce44SJohn Forte 			/*
651fcf3ce44SJohn Forte 			 * Timeout occured.  Just free NOP.  Another
652fcf3ce44SJohn Forte 			 * NOP request will be spawned to replace
653fcf3ce44SJohn Forte 			 * this one.
654fcf3ce44SJohn Forte 			 */
655d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
656d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
657d233de7eSJack Meng 
658fcf3ce44SJohn Forte 			break;
659fcf3ce44SJohn Forte 
660fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_ABORT:
661fcf3ce44SJohn Forte 			mutex_enter(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
662fcf3ce44SJohn Forte 			icmdp->cmd_un.abort.icmdp->
663fcf3ce44SJohn Forte 			    cmd_un.scsi.abort_icmdp = NULL;
664fcf3ce44SJohn Forte 			cv_broadcast(&icmdp->cmd_un.abort.icmdp->
665fcf3ce44SJohn Forte 			    cmd_completion);
666fcf3ce44SJohn Forte 			mutex_exit(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
667fcf3ce44SJohn Forte 			icmdp->cmd_un.abort.icmdp = NULL;
668fcf3ce44SJohn Forte 
669fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
670d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
671d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
672fcf3ce44SJohn Forte 			break;
673fcf3ce44SJohn Forte 
674fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_RESET:
675fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
676fcf3ce44SJohn Forte 			/*
677fcf3ce44SJohn Forte 			 * If we are failing a RESET we need
678fcf3ce44SJohn Forte 			 * to notify the tran_reset caller.
679fcf3ce44SJohn Forte 			 * with the cmd and notify caller.
680fcf3ce44SJohn Forte 			 */
681fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
682fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
683fcf3ce44SJohn Forte 			break;
684fcf3ce44SJohn Forte 
685fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_LOGOUT:
686fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
687fcf3ce44SJohn Forte 			/* notify requester of failure */
688fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
689fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
690fcf3ce44SJohn Forte 			break;
691fcf3ce44SJohn Forte 
692fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_TEXT:
693fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
694fcf3ce44SJohn Forte 			icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
695fcf3ce44SJohn Forte 			/*
696fcf3ce44SJohn Forte 			 * If a TEXT command fails, notify the owner.
697fcf3ce44SJohn Forte 			 */
698fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
699fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
700fcf3ce44SJohn Forte 			break;
701fcf3ce44SJohn Forte 
702fcf3ce44SJohn Forte 		default:
703fcf3ce44SJohn Forte 			ASSERT(FALSE);
704fcf3ce44SJohn Forte 			break;
705fcf3ce44SJohn Forte 		}
706fcf3ce44SJohn Forte 		break;
707fcf3ce44SJohn Forte 
708fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
709fcf3ce44SJohn Forte 	default:
710fcf3ce44SJohn Forte 		ASSERT(FALSE);
711fcf3ce44SJohn Forte 	}
712fcf3ce44SJohn Forte }
713fcf3ce44SJohn Forte 
714fcf3ce44SJohn Forte 
715fcf3ce44SJohn Forte /*
716fcf3ce44SJohn Forte  * iscsi_cmd_state_active -
717fcf3ce44SJohn Forte  *
718fcf3ce44SJohn Forte  */
719fcf3ce44SJohn Forte static void
iscsi_cmd_state_active(iscsi_cmd_t * icmdp,iscsi_cmd_event_t event,void * arg)720fcf3ce44SJohn Forte iscsi_cmd_state_active(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
721fcf3ce44SJohn Forte {
722fcf3ce44SJohn Forte 	iscsi_sess_t	*isp		= (iscsi_sess_t *)arg;
723fcf3ce44SJohn Forte 	iscsi_hba_t	*ihp;
724fcf3ce44SJohn Forte 	iscsi_cmd_t	*t_icmdp	= NULL;
725fcf3ce44SJohn Forte 	iscsi_conn_t	*icp		= NULL;
726fcf3ce44SJohn Forte 
727fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
728fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_ACTIVE);
729fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
730fcf3ce44SJohn Forte 
731fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
732fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
733fcf3ce44SJohn Forte 
734fcf3ce44SJohn Forte 	icp = icmdp->cmd_conn;
735fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
736fcf3ce44SJohn Forte 	ASSERT(mutex_owned(&icp->conn_queue_active.mutex));
737fcf3ce44SJohn Forte 
738fcf3ce44SJohn Forte 	/* switch on event change */
739fcf3ce44SJohn Forte 	switch (event) {
740fcf3ce44SJohn Forte 	/* -E3: Command was successfully completed */
741fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E3:
742fcf3ce44SJohn Forte 		/*
743fcf3ce44SJohn Forte 		 * Remove command from the active list.  We need to protect
744fcf3ce44SJohn Forte 		 * someone from looking up this command ITT until it's
745fcf3ce44SJohn Forte 		 * freed of the command is moved to a new queue location.
746fcf3ce44SJohn Forte 		 */
747fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_cmdsn_mutex);
748fcf3ce44SJohn Forte 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
749fcf3ce44SJohn Forte 
750fcf3ce44SJohn Forte 		switch (icmdp->cmd_type) {
751fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_SCSI:
75230e7468fSPeter Dunlap 			iscsi_sess_release_scsi_itt(icmdp);
753fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
754fcf3ce44SJohn Forte 			iscsi_enqueue_completed_cmd(isp, icmdp);
755fcf3ce44SJohn Forte 			break;
756fcf3ce44SJohn Forte 
757fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_NOP:
758fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
759fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
760fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
761fcf3ce44SJohn Forte 
762fcf3ce44SJohn Forte 			/* free alloc */
763d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
764d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
765d233de7eSJack Meng 
766fcf3ce44SJohn Forte 			break;
767fcf3ce44SJohn Forte 
768fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_ABORT:
769fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
770fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
771fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
772fcf3ce44SJohn Forte 
773fcf3ce44SJohn Forte 			/*
774fcf3ce44SJohn Forte 			 * Abort was completed successfully.  We should
775fcf3ce44SJohn Forte 			 * complete the parent scsi command if it still
776fcf3ce44SJohn Forte 			 * exists as timed out, and the state is not
777fcf3ce44SJohn Forte 			 * COMPLETED
778fcf3ce44SJohn Forte 			 */
779fcf3ce44SJohn Forte 			t_icmdp = icmdp->cmd_un.abort.icmdp;
780fcf3ce44SJohn Forte 			ASSERT(t_icmdp != NULL);
781fcf3ce44SJohn Forte 			mutex_enter(&t_icmdp->cmd_mutex);
78230e7468fSPeter Dunlap 			t_icmdp->cmd_un.scsi.abort_icmdp = NULL;
783fcf3ce44SJohn Forte 			if (t_icmdp->cmd_state != ISCSI_CMD_STATE_COMPLETED) {
784fcf3ce44SJohn Forte 				iscsi_dequeue_active_cmd(
785fcf3ce44SJohn Forte 				    t_icmdp->cmd_conn, t_icmdp);
78630e7468fSPeter Dunlap 				mutex_enter(
78730e7468fSPeter Dunlap 				    &icp->conn_queue_idm_aborting.mutex);
78830e7468fSPeter Dunlap 				iscsi_enqueue_idm_aborting_cmd(
78930e7468fSPeter Dunlap 				    t_icmdp->cmd_conn,
79030e7468fSPeter Dunlap 				    t_icmdp);
79130e7468fSPeter Dunlap 				mutex_exit(&icp->conn_queue_idm_aborting.mutex);
792fcf3ce44SJohn Forte 
79330e7468fSPeter Dunlap 				/*
79430e7468fSPeter Dunlap 				 * Complete abort processing after IDM
79530e7468fSPeter Dunlap 				 * calls us back.  Set the status to use
79630e7468fSPeter Dunlap 				 * when we complete the command.
79730e7468fSPeter Dunlap 				 */
798fcf3ce44SJohn Forte 				ISCSI_CMD_SET_REASON_STAT(
7992b79d384Sbing zhao - Sun Microsystems - Beijing China 				    t_icmdp, CMD_TIMEOUT, STAT_ABORTED);
800*61dfa509SRick McNeal 				(void) idm_task_abort(icp->conn_ic,
801*61dfa509SRick McNeal 				    t_icmdp->cmd_itp, AT_TASK_MGMT_ABORT);
80230e7468fSPeter Dunlap 			} else {
80330e7468fSPeter Dunlap 				cv_broadcast(&t_icmdp->cmd_completion);
804fcf3ce44SJohn Forte 			}
805fcf3ce44SJohn Forte 			mutex_exit(&t_icmdp->cmd_mutex);
806fcf3ce44SJohn Forte 			icmdp->cmd_un.abort.icmdp = NULL;
807fcf3ce44SJohn Forte 
808d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
809d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
810d233de7eSJack Meng 
811fcf3ce44SJohn Forte 			break;
812fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_RESET:
813fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
814fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
815fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
816fcf3ce44SJohn Forte 
817fcf3ce44SJohn Forte 			/*
8182b79d384Sbing zhao - Sun Microsystems - Beijing China 			 * Complete the abort/reset command.
819fcf3ce44SJohn Forte 			 */
8202b79d384Sbing zhao - Sun Microsystems - Beijing China 			if (icmdp->cmd_un.reset.response !=
8212b79d384Sbing zhao - Sun Microsystems - Beijing China 			    SCSI_TCP_TM_RESP_COMPLETE) {
8222b79d384Sbing zhao - Sun Microsystems - Beijing China 				ISCSI_CMD_ISSUE_CALLBACK(icmdp,
8232b79d384Sbing zhao - Sun Microsystems - Beijing China 				    ISCSI_STATUS_CMD_FAILED);
8242b79d384Sbing zhao - Sun Microsystems - Beijing China 			} else {
8252b79d384Sbing zhao - Sun Microsystems - Beijing China 				ISCSI_CMD_ISSUE_CALLBACK(icmdp,
8262b79d384Sbing zhao - Sun Microsystems - Beijing China 				    ISCSI_STATUS_SUCCESS);
8272b79d384Sbing zhao - Sun Microsystems - Beijing China 			}
8282b79d384Sbing zhao - Sun Microsystems - Beijing China 
829fcf3ce44SJohn Forte 			break;
830fcf3ce44SJohn Forte 
831fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_LOGOUT:
832fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
833fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
834fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
835fcf3ce44SJohn Forte 
836fcf3ce44SJohn Forte 			/*
837fcf3ce44SJohn Forte 			 * Complete the logout successfully.
838fcf3ce44SJohn Forte 			 */
839fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp, ISCSI_STATUS_SUCCESS);
840fcf3ce44SJohn Forte 			break;
841fcf3ce44SJohn Forte 
842fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_TEXT:
843fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
844fcf3ce44SJohn Forte 			if (icmdp->cmd_un.text.stage ==
845fcf3ce44SJohn Forte 			    ISCSI_CMD_TEXT_FINAL_RSP) {
846fcf3ce44SJohn Forte 				iscsi_sess_release_itt(isp, icmdp);
847fcf3ce44SJohn Forte 			}
848fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
849fcf3ce44SJohn Forte 
850fcf3ce44SJohn Forte 			/*
851fcf3ce44SJohn Forte 			 * Complete the text command successfully.
852fcf3ce44SJohn Forte 			 */
853fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp, icmdp->cmd_result);
854fcf3ce44SJohn Forte 			break;
855fcf3ce44SJohn Forte 
856fcf3ce44SJohn Forte 		default:
857fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
858fcf3ce44SJohn Forte 			ASSERT(FALSE);
859fcf3ce44SJohn Forte 		}
860fcf3ce44SJohn Forte 
861fcf3ce44SJohn Forte 		ASSERT(!mutex_owned(&isp->sess_cmdsn_mutex));
862fcf3ce44SJohn Forte 		break;
863fcf3ce44SJohn Forte 
86430e7468fSPeter Dunlap 	/* -E10,E4: Command has been requested to abort */
86530e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E10:
86630e7468fSPeter Dunlap 		/* FALLTHRU */
867fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E4:
868fcf3ce44SJohn Forte 
869fcf3ce44SJohn Forte 		/* E4 is only for resets and aborts */
870fcf3ce44SJohn Forte 		ASSERT((icmdp->cmd_type == ISCSI_CMD_TYPE_ABORT) ||
871fcf3ce44SJohn Forte 		    (icmdp->cmd_type == ISCSI_CMD_TYPE_RESET));
872fcf3ce44SJohn Forte 		/* FALLTHRU */
873fcf3ce44SJohn Forte 
874fcf3ce44SJohn Forte 	/* -E6: Command has timed out */
875fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E6:
876fcf3ce44SJohn Forte 
877fcf3ce44SJohn Forte 		switch (icmdp->cmd_type) {
878fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_SCSI:
879fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_ABORTING;
880fcf3ce44SJohn Forte 			iscsi_handle_abort(icmdp);
881fcf3ce44SJohn Forte 			break;
882fcf3ce44SJohn Forte 
883fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_NOP:
884fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
885fcf3ce44SJohn Forte 
886fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
887fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
888fcf3ce44SJohn Forte 			iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
889fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
890fcf3ce44SJohn Forte 
891d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
892d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
893d233de7eSJack Meng 
894fcf3ce44SJohn Forte 			break;
895fcf3ce44SJohn Forte 
896fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_ABORT:
897fcf3ce44SJohn Forte 			icmdp->cmd_state =
898fcf3ce44SJohn Forte 			    ISCSI_CMD_STATE_FREE;
899fcf3ce44SJohn Forte 
900fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
901fcf3ce44SJohn Forte 			iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
902fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
903fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
904fcf3ce44SJohn Forte 
905fcf3ce44SJohn Forte 			/*
90630e7468fSPeter Dunlap 			 * If this is an E4 then we may need to deal with
90730e7468fSPeter Dunlap 			 * the abort's associated SCSI command.  If this
90830e7468fSPeter Dunlap 			 * is an E10 then IDM is already cleaning up the
90930e7468fSPeter Dunlap 			 * SCSI command and all we need to do is break the
91030e7468fSPeter Dunlap 			 * linkage between them and free the abort command.
911fcf3ce44SJohn Forte 			 */
91230e7468fSPeter Dunlap 			t_icmdp = icmdp->cmd_un.abort.icmdp;
91330e7468fSPeter Dunlap 			ASSERT(t_icmdp != NULL);
91430e7468fSPeter Dunlap 			if (event != ISCSI_CMD_EVENT_E10) {
91530e7468fSPeter Dunlap 
91630e7468fSPeter Dunlap 				mutex_enter(&t_icmdp->cmd_mutex);
91730e7468fSPeter Dunlap 				t_icmdp->cmd_un.scsi.abort_icmdp = NULL;
91830e7468fSPeter Dunlap 				/*
91930e7468fSPeter Dunlap 				 * If abort command is aborted then we should
92030e7468fSPeter Dunlap 				 * not act on the parent scsi command.  If the
92130e7468fSPeter Dunlap 				 * abort command timed out then we need to
92230e7468fSPeter Dunlap 				 * complete the parent command if it still
92330e7468fSPeter Dunlap 				 * exists with a timeout failure.
92430e7468fSPeter Dunlap 				 */
92530e7468fSPeter Dunlap 				if ((event == ISCSI_CMD_EVENT_E6) &&
92630e7468fSPeter Dunlap 				    (t_icmdp->cmd_state !=
92730e7468fSPeter Dunlap 				    ISCSI_CMD_STATE_IDM_ABORTING) &&
92830e7468fSPeter Dunlap 				    (t_icmdp->cmd_state !=
92930e7468fSPeter Dunlap 				    ISCSI_CMD_STATE_COMPLETED)) {
93030e7468fSPeter Dunlap 
93130e7468fSPeter Dunlap 					iscsi_dequeue_active_cmd(
93230e7468fSPeter Dunlap 					    t_icmdp->cmd_conn, t_icmdp);
93330e7468fSPeter Dunlap 					mutex_enter(&icp->
93430e7468fSPeter Dunlap 					    conn_queue_idm_aborting.mutex);
93530e7468fSPeter Dunlap 					iscsi_enqueue_idm_aborting_cmd(
93630e7468fSPeter Dunlap 					    t_icmdp->cmd_conn,  t_icmdp);
93730e7468fSPeter Dunlap 					mutex_exit(&icp->
93830e7468fSPeter Dunlap 					    conn_queue_idm_aborting.mutex);
93930e7468fSPeter Dunlap 					/*
94030e7468fSPeter Dunlap 					 * Complete abort processing after IDM
94130e7468fSPeter Dunlap 					 * calls us back.  Set the status to use
94230e7468fSPeter Dunlap 					 * when we complete the command.
94330e7468fSPeter Dunlap 					 */
94430e7468fSPeter Dunlap 					ISCSI_CMD_SET_REASON_STAT(t_icmdp,
94530e7468fSPeter Dunlap 					    CMD_TIMEOUT, STAT_TIMEOUT);
946*61dfa509SRick McNeal 					(void) idm_task_abort(icp->conn_ic,
94730e7468fSPeter Dunlap 					    t_icmdp->cmd_itp,
94830e7468fSPeter Dunlap 					    AT_TASK_MGMT_ABORT);
94930e7468fSPeter Dunlap 				} else {
95030e7468fSPeter Dunlap 					cv_broadcast(&t_icmdp->cmd_completion);
95130e7468fSPeter Dunlap 				}
95230e7468fSPeter Dunlap 				mutex_exit(&t_icmdp->cmd_mutex);
95330e7468fSPeter Dunlap 			} else {
95430e7468fSPeter Dunlap 				t_icmdp->cmd_un.scsi.abort_icmdp = NULL;
955fcf3ce44SJohn Forte 			}
956fcf3ce44SJohn Forte 			icmdp->cmd_un.abort.icmdp = NULL;
957d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
958d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
959fcf3ce44SJohn Forte 			break;
960fcf3ce44SJohn Forte 
961fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_RESET:
962fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
963fcf3ce44SJohn Forte 
964fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
965fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
966fcf3ce44SJohn Forte 			iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
967fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
968fcf3ce44SJohn Forte 
969fcf3ce44SJohn Forte 			/*
970fcf3ce44SJohn Forte 			 * If we are failing a RESET we need
971fcf3ce44SJohn Forte 			 * to notify the tran_reset caller.
972fcf3ce44SJohn Forte 			 * It will free the memory associated
973fcf3ce44SJohn Forte 			 * with the cmd and notify caller.
974fcf3ce44SJohn Forte 			 */
975fcf3ce44SJohn Forte 
976fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
977fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
978fcf3ce44SJohn Forte 			break;
979fcf3ce44SJohn Forte 
980fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_LOGOUT:
981fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
982fcf3ce44SJohn Forte 
983fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
984fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
985fcf3ce44SJohn Forte 			iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
986fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
987fcf3ce44SJohn Forte 
988fcf3ce44SJohn Forte 			/*
989fcf3ce44SJohn Forte 			 * Notify caller of failure.
990fcf3ce44SJohn Forte 			 */
991fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
992fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
993fcf3ce44SJohn Forte 			break;
994fcf3ce44SJohn Forte 
995fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_TEXT:
996fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
997fcf3ce44SJohn Forte 			icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
998fcf3ce44SJohn Forte 			mutex_enter(&isp->sess_cmdsn_mutex);
999fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
1000fcf3ce44SJohn Forte 			iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
1001fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1002fcf3ce44SJohn Forte 
1003fcf3ce44SJohn Forte 			/*
1004fcf3ce44SJohn Forte 			 * If a TEXT command fails, notify caller so
1005fcf3ce44SJohn Forte 			 * it can free assocated command
1006fcf3ce44SJohn Forte 			 */
1007fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
1008fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
1009fcf3ce44SJohn Forte 			break;
1010fcf3ce44SJohn Forte 
1011fcf3ce44SJohn Forte 		default:
1012fcf3ce44SJohn Forte 			ASSERT(FALSE);
1013fcf3ce44SJohn Forte 		}
1014fcf3ce44SJohn Forte 
1015fcf3ce44SJohn Forte 		ASSERT(!mutex_owned(&isp->sess_cmdsn_mutex));
1016fcf3ce44SJohn Forte 		break;
1017fcf3ce44SJohn Forte 
1018fcf3ce44SJohn Forte 	/* -E7: Connection has encountered a problem */
1019fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E7:
1020fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_cmdsn_mutex);
1021fcf3ce44SJohn Forte 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
1022fcf3ce44SJohn Forte 
1023fcf3ce44SJohn Forte 		switch (icmdp->cmd_type) {
1024fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_SCSI:
1025fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
102630e7468fSPeter Dunlap 			mutex_enter(&icp->conn_queue_idm_aborting.mutex);
102730e7468fSPeter Dunlap 			iscsi_enqueue_idm_aborting_cmd(icmdp->cmd_conn, icmdp);
102830e7468fSPeter Dunlap 			mutex_exit(&icp->conn_queue_idm_aborting.mutex);
10292b79d384Sbing zhao - Sun Microsystems - Beijing China 			ISCSI_CMD_SET_REASON_STAT(icmdp,
10302b79d384Sbing zhao - Sun Microsystems - Beijing China 			    CMD_TRAN_ERR, icmdp->cmd_un.scsi.pkt_stat);
1031*61dfa509SRick McNeal 			(void) idm_task_abort(icp->conn_ic, icmdp->cmd_itp,
103230e7468fSPeter Dunlap 			    AT_TASK_MGMT_ABORT);
1033fcf3ce44SJohn Forte 			break;
1034fcf3ce44SJohn Forte 
1035fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_NOP:
1036fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1037fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
1038fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1039fcf3ce44SJohn Forte 
1040d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
1041d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
1042fcf3ce44SJohn Forte 			break;
1043fcf3ce44SJohn Forte 
1044fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_ABORT:
1045fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1046fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
1047fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1048fcf3ce44SJohn Forte 
1049fcf3ce44SJohn Forte 			mutex_enter(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
1050fcf3ce44SJohn Forte 			icmdp->cmd_un.abort.icmdp->
1051fcf3ce44SJohn Forte 			    cmd_un.scsi.abort_icmdp = NULL;
1052fcf3ce44SJohn Forte 			cv_broadcast(&icmdp->cmd_un.abort.icmdp->
1053fcf3ce44SJohn Forte 			    cmd_completion);
1054fcf3ce44SJohn Forte 			mutex_exit(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
1055fcf3ce44SJohn Forte 			/*
1056fcf3ce44SJohn Forte 			 * Nullify the abort command's pointer to its
1057fcf3ce44SJohn Forte 			 * parent command. It does not have to complete its
1058fcf3ce44SJohn Forte 			 * parent command because the parent command will
1059fcf3ce44SJohn Forte 			 * also get an E7.
1060fcf3ce44SJohn Forte 			 */
1061fcf3ce44SJohn Forte 			icmdp->cmd_un.abort.icmdp = NULL;
1062fcf3ce44SJohn Forte 
1063d233de7eSJack Meng 			icmdp->cmd_misc_flags |=
1064d233de7eSJack Meng 			    ISCSI_CMD_MISCFLAG_FREE;
1065fcf3ce44SJohn Forte 			break;
1066fcf3ce44SJohn Forte 
1067fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_RESET:
1068fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1069fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
1070fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1071fcf3ce44SJohn Forte 			/*
1072fcf3ce44SJohn Forte 			 * If we are failing a ABORT we need
1073fcf3ce44SJohn Forte 			 * to notify the tran_abort caller.
1074fcf3ce44SJohn Forte 			 * It will free the memory associated
1075fcf3ce44SJohn Forte 			 * with the cmd and notify caller.
1076fcf3ce44SJohn Forte 			 */
1077fcf3ce44SJohn Forte 
1078fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
1079fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
1080fcf3ce44SJohn Forte 			break;
1081fcf3ce44SJohn Forte 
1082fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_LOGOUT:
1083fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1084fcf3ce44SJohn Forte 			/*
1085fcf3ce44SJohn Forte 			 * A connection problem and we attempted to
1086fcf3ce44SJohn Forte 			 * logout?  I guess we can just free the
1087fcf3ce44SJohn Forte 			 * request.  Someone has already pushed the
1088fcf3ce44SJohn Forte 			 * connection state.
1089fcf3ce44SJohn Forte 			 */
1090fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
1091fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1092fcf3ce44SJohn Forte 
1093fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp, ISCSI_STATUS_SUCCESS);
1094fcf3ce44SJohn Forte 			break;
1095fcf3ce44SJohn Forte 
1096fcf3ce44SJohn Forte 		case ISCSI_CMD_TYPE_TEXT:
1097fcf3ce44SJohn Forte 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1098fcf3ce44SJohn Forte 			icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
1099fcf3ce44SJohn Forte 			iscsi_sess_release_itt(isp, icmdp);
1100fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1101fcf3ce44SJohn Forte 
1102fcf3ce44SJohn Forte 			/*
1103fcf3ce44SJohn Forte 			 * If a TEXT command fails, notify caller so
1104fcf3ce44SJohn Forte 			 * it can free assocated command
1105fcf3ce44SJohn Forte 			 */
1106fcf3ce44SJohn Forte 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
1107fcf3ce44SJohn Forte 			    ISCSI_STATUS_CMD_FAILED);
1108fcf3ce44SJohn Forte 			break;
1109fcf3ce44SJohn Forte 
1110fcf3ce44SJohn Forte 		default:
1111fcf3ce44SJohn Forte 			mutex_exit(&isp->sess_cmdsn_mutex);
1112fcf3ce44SJohn Forte 			ASSERT(FALSE);
1113fcf3ce44SJohn Forte 			break;
1114fcf3ce44SJohn Forte 		}
1115fcf3ce44SJohn Forte 
1116fcf3ce44SJohn Forte 		ASSERT(!mutex_owned(&isp->sess_cmdsn_mutex));
1117fcf3ce44SJohn Forte 		break;
1118fcf3ce44SJohn Forte 
111930e7468fSPeter Dunlap 	/* -E9: IDM is no longer processing this command */
112030e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E9:
112130e7468fSPeter Dunlap 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
112230e7468fSPeter Dunlap 
112330e7468fSPeter Dunlap 		iscsi_task_cleanup(ISCSI_OP_SCSI_RSP, icmdp);
112430e7468fSPeter Dunlap 		iscsi_sess_release_scsi_itt(icmdp);
112530e7468fSPeter Dunlap 
11262b79d384Sbing zhao - Sun Microsystems - Beijing China 		ISCSI_CMD_SET_REASON_STAT(icmdp, CMD_TRAN_ERR,
11272b79d384Sbing zhao - Sun Microsystems - Beijing China 		    icmdp->cmd_un.scsi.pkt_stat);
112830e7468fSPeter Dunlap 		iscsi_enqueue_completed_cmd(isp, icmdp);
112930e7468fSPeter Dunlap 		break;
113030e7468fSPeter Dunlap 
1131fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
1132fcf3ce44SJohn Forte 	default:
1133fcf3ce44SJohn Forte 		ASSERT(FALSE);
1134fcf3ce44SJohn Forte 	}
1135fcf3ce44SJohn Forte }
1136fcf3ce44SJohn Forte 
1137fcf3ce44SJohn Forte 
1138fcf3ce44SJohn Forte /*
1139fcf3ce44SJohn Forte  * iscsi_cmd_state_aborting -
1140fcf3ce44SJohn Forte  *
1141fcf3ce44SJohn Forte  */
1142fcf3ce44SJohn Forte static void
iscsi_cmd_state_aborting(iscsi_cmd_t * icmdp,iscsi_cmd_event_t event,void * arg)1143fcf3ce44SJohn Forte iscsi_cmd_state_aborting(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
1144fcf3ce44SJohn Forte {
1145fcf3ce44SJohn Forte 	iscsi_sess_t	*isp	= (iscsi_sess_t *)arg;
114630e7468fSPeter Dunlap 	iscsi_cmd_t	*a_icmdp;
1147fcf3ce44SJohn Forte 
1148fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
1149fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI);
1150fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_ABORTING);
1151fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1152fcf3ce44SJohn Forte 	ASSERT(mutex_owned(&icmdp->cmd_conn->conn_queue_active.mutex));
1153fcf3ce44SJohn Forte 
1154fcf3ce44SJohn Forte 	/* switch on event change */
1155fcf3ce44SJohn Forte 	switch (event) {
1156fcf3ce44SJohn Forte 	/* -E3: Command was successfully completed */
1157fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E3:
1158fcf3ce44SJohn Forte 		/*
1159fcf3ce44SJohn Forte 		 * Remove command from the aborting list
1160fcf3ce44SJohn Forte 		 */
1161fcf3ce44SJohn Forte 		mutex_enter(&isp->sess_cmdsn_mutex);
1162fcf3ce44SJohn Forte 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
116330e7468fSPeter Dunlap 		iscsi_sess_release_scsi_itt(icmdp);
1164fcf3ce44SJohn Forte 		mutex_exit(&isp->sess_cmdsn_mutex);
1165fcf3ce44SJohn Forte 
1166fcf3ce44SJohn Forte 		iscsi_enqueue_completed_cmd(isp, icmdp);
1167fcf3ce44SJohn Forte 		break;
1168fcf3ce44SJohn Forte 
1169fcf3ce44SJohn Forte 	/* -E4: Command has been requested to abort */
1170fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E4:
1171fcf3ce44SJohn Forte 		/*
1172fcf3ce44SJohn Forte 		 * An upper level driver might attempt to
1173fcf3ce44SJohn Forte 		 * abort a command that we are already
1174fcf3ce44SJohn Forte 		 * aborting due to a nop.  Since we are
1175fcf3ce44SJohn Forte 		 * already in the process of aborting
1176fcf3ce44SJohn Forte 		 * ignore the request.
1177fcf3ce44SJohn Forte 		 */
1178fcf3ce44SJohn Forte 		break;
1179fcf3ce44SJohn Forte 
1180fcf3ce44SJohn Forte 	/* -E6: Command has timed out */
1181fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E6:
1182fcf3ce44SJohn Forte 		ASSERT(FALSE);
1183fcf3ce44SJohn Forte 		/*
1184fcf3ce44SJohn Forte 		 * Timeouts should not occur on command in abort queue
1185fcf3ce44SJohn Forte 		 * they are already be processed due to a timeout.
1186fcf3ce44SJohn Forte 		 */
1187fcf3ce44SJohn Forte 		break;
1188fcf3ce44SJohn Forte 
1189fcf3ce44SJohn Forte 	/* -E7: Connection has encountered a problem */
1190fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E7:
1191fcf3ce44SJohn Forte 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
119230e7468fSPeter Dunlap 		mutex_enter(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
119330e7468fSPeter Dunlap 		iscsi_enqueue_idm_aborting_cmd(icmdp->cmd_conn, icmdp);
119430e7468fSPeter Dunlap 		mutex_exit(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
1195fcf3ce44SJohn Forte 
119630e7468fSPeter Dunlap 		/*
119730e7468fSPeter Dunlap 		 * Since we are in "aborting" state there is another command
119830e7468fSPeter Dunlap 		 * representing the abort of this command.  This command
119930e7468fSPeter Dunlap 		 * will cleanup at some indeterminate time after the call
120030e7468fSPeter Dunlap 		 * to idm_task_abort so we can't leave the abort request
120130e7468fSPeter Dunlap 		 * active.  An E10 event to the abort command will cause
120230e7468fSPeter Dunlap 		 * it to complete immediately.
120330e7468fSPeter Dunlap 		 */
120430e7468fSPeter Dunlap 		if ((a_icmdp = icmdp->cmd_un.scsi.abort_icmdp) != NULL) {
120530e7468fSPeter Dunlap 			iscsi_cmd_state_machine(a_icmdp,
120630e7468fSPeter Dunlap 			    ISCSI_CMD_EVENT_E10, arg);
120730e7468fSPeter Dunlap 		}
120830e7468fSPeter Dunlap 
12092b79d384Sbing zhao - Sun Microsystems - Beijing China 		ISCSI_CMD_SET_REASON_STAT(icmdp,
12102b79d384Sbing zhao - Sun Microsystems - Beijing China 		    CMD_TRAN_ERR, icmdp->cmd_un.scsi.pkt_stat);
12112b79d384Sbing zhao - Sun Microsystems - Beijing China 
1212*61dfa509SRick McNeal 		(void) idm_task_abort(icmdp->cmd_conn->conn_ic, icmdp->cmd_itp,
121330e7468fSPeter Dunlap 		    AT_TASK_MGMT_ABORT);
121430e7468fSPeter Dunlap 		break;
121530e7468fSPeter Dunlap 
121630e7468fSPeter Dunlap 	/* -E9: IDM is no longer processing this command */
121730e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E9:
121830e7468fSPeter Dunlap 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
121930e7468fSPeter Dunlap 
122030e7468fSPeter Dunlap 		iscsi_task_cleanup(ISCSI_OP_SCSI_RSP, icmdp);
122130e7468fSPeter Dunlap 		iscsi_sess_release_scsi_itt(icmdp);
122230e7468fSPeter Dunlap 
12232b79d384Sbing zhao - Sun Microsystems - Beijing China 		ISCSI_CMD_SET_REASON_STAT(icmdp, CMD_TRAN_ERR,
12242b79d384Sbing zhao - Sun Microsystems - Beijing China 		    icmdp->cmd_un.scsi.pkt_stat);
122530e7468fSPeter Dunlap 		iscsi_enqueue_completed_cmd(isp, icmdp);
122630e7468fSPeter Dunlap 		break;
122730e7468fSPeter Dunlap 
122830e7468fSPeter Dunlap 	/* All other events are invalid for this state */
122930e7468fSPeter Dunlap 	default:
123030e7468fSPeter Dunlap 		ASSERT(FALSE);
123130e7468fSPeter Dunlap 	}
123230e7468fSPeter Dunlap }
123330e7468fSPeter Dunlap 
123430e7468fSPeter Dunlap static void
iscsi_cmd_state_idm_aborting(iscsi_cmd_t * icmdp,iscsi_cmd_event_t event,void * arg)123530e7468fSPeter Dunlap iscsi_cmd_state_idm_aborting(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event,
123630e7468fSPeter Dunlap     void *arg)
123730e7468fSPeter Dunlap {
123830e7468fSPeter Dunlap 	iscsi_sess_t	*isp	= (iscsi_sess_t *)arg;
123930e7468fSPeter Dunlap 
124030e7468fSPeter Dunlap 	ASSERT(icmdp != NULL);
124130e7468fSPeter Dunlap 	ASSERT(icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI);
124230e7468fSPeter Dunlap 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_IDM_ABORTING);
124330e7468fSPeter Dunlap 	ASSERT(isp != NULL);
124430e7468fSPeter Dunlap 
124530e7468fSPeter Dunlap 	/* switch on event change */
124630e7468fSPeter Dunlap 	switch (event) {
124730e7468fSPeter Dunlap 	/* -E3: Command was successfully completed */
124830e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E3:
124930e7468fSPeter Dunlap 		/*
125030e7468fSPeter Dunlap 		 * iscsi_rx_process_cmd_rsp() and iscsi_rx_process_data_rsp()
125130e7468fSPeter Dunlap 		 * are supposed to confirm the cmd state is appropriate before
125230e7468fSPeter Dunlap 		 * generating an E3 event.  E3 is not allowed in this state.
125330e7468fSPeter Dunlap 		 */
125430e7468fSPeter Dunlap 		ASSERT(0);
125530e7468fSPeter Dunlap 		break;
125630e7468fSPeter Dunlap 
125730e7468fSPeter Dunlap 	/* -E4: Command has been requested to abort */
125830e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E4:
125930e7468fSPeter Dunlap 		/*
126030e7468fSPeter Dunlap 		 * An upper level driver might attempt to
126130e7468fSPeter Dunlap 		 * abort a command that we are already
126230e7468fSPeter Dunlap 		 * aborting due to a nop.  Since we are
126330e7468fSPeter Dunlap 		 * already in the process of aborting
126430e7468fSPeter Dunlap 		 * ignore the request.
126530e7468fSPeter Dunlap 		 */
126630e7468fSPeter Dunlap 		break;
126730e7468fSPeter Dunlap 
126830e7468fSPeter Dunlap 	/* -E6: Command has timed out */
126930e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E6:
127030e7468fSPeter Dunlap 		ASSERT(FALSE);
127130e7468fSPeter Dunlap 		/*
127230e7468fSPeter Dunlap 		 * Timeouts should not occur on aborting commands
127330e7468fSPeter Dunlap 		 */
127430e7468fSPeter Dunlap 		break;
127530e7468fSPeter Dunlap 
127630e7468fSPeter Dunlap 	/* -E7: Connection has encountered a problem */
127730e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E7:
127830e7468fSPeter Dunlap 		/*
127930e7468fSPeter Dunlap 		 * We have already requested IDM to stop processing this
12802b79d384Sbing zhao - Sun Microsystems - Beijing China 		 * command so just update the pkt_statistics.
128130e7468fSPeter Dunlap 		 */
12822b79d384Sbing zhao - Sun Microsystems - Beijing China 		ISCSI_CMD_SET_REASON_STAT(icmdp,
12832b79d384Sbing zhao - Sun Microsystems - Beijing China 		    CMD_TRAN_ERR, icmdp->cmd_un.scsi.pkt_stat);
128430e7468fSPeter Dunlap 		break;
128530e7468fSPeter Dunlap 
128630e7468fSPeter Dunlap 	/* -E9: IDM is no longer processing this command */
128730e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E9:
128830e7468fSPeter Dunlap 		mutex_enter(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
128930e7468fSPeter Dunlap 		iscsi_dequeue_idm_aborting_cmd(icmdp->cmd_conn, icmdp);
129030e7468fSPeter Dunlap 		mutex_exit(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
129130e7468fSPeter Dunlap 
129230e7468fSPeter Dunlap 		/* This is always an error so make sure an error has been set */
129330e7468fSPeter Dunlap 		ASSERT(icmdp->cmd_un.scsi.pkt->pkt_reason != CMD_CMPLT);
129430e7468fSPeter Dunlap 		iscsi_task_cleanup(ISCSI_OP_SCSI_RSP, icmdp);
129530e7468fSPeter Dunlap 		iscsi_sess_release_scsi_itt(icmdp);
129630e7468fSPeter Dunlap 
129730e7468fSPeter Dunlap 		/*
129830e7468fSPeter Dunlap 		 * Whoever called idm_task_abort should have set the completion
129930e7468fSPeter Dunlap 		 * status beforehand.
130030e7468fSPeter Dunlap 		 */
1301fcf3ce44SJohn Forte 		iscsi_enqueue_completed_cmd(isp, icmdp);
130230e7468fSPeter Dunlap 		cv_broadcast(&icmdp->cmd_completion);
1303fcf3ce44SJohn Forte 		break;
1304fcf3ce44SJohn Forte 
1305fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
1306fcf3ce44SJohn Forte 	default:
1307fcf3ce44SJohn Forte 		ASSERT(FALSE);
1308fcf3ce44SJohn Forte 	}
1309fcf3ce44SJohn Forte }
1310fcf3ce44SJohn Forte 
1311fcf3ce44SJohn Forte 
1312fcf3ce44SJohn Forte /*
1313fcf3ce44SJohn Forte  * iscsi_cmd_state_completed -
1314fcf3ce44SJohn Forte  *
1315fcf3ce44SJohn Forte  */
1316fcf3ce44SJohn Forte static void
iscsi_cmd_state_completed(iscsi_cmd_t * icmdp,iscsi_cmd_event_t event,void * arg)1317fcf3ce44SJohn Forte iscsi_cmd_state_completed(iscsi_cmd_t *icmdp,
1318fcf3ce44SJohn Forte     iscsi_cmd_event_t event, void *arg)
1319fcf3ce44SJohn Forte {
1320fcf3ce44SJohn Forte 	iscsi_sess_t	*isp	= (iscsi_sess_t *)arg;
1321fcf3ce44SJohn Forte 
1322fcf3ce44SJohn Forte 	ASSERT(icmdp != NULL);
1323fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI);
1324fcf3ce44SJohn Forte 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_COMPLETED);
1325fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1326fcf3ce44SJohn Forte 
1327fcf3ce44SJohn Forte 	/* switch on event change */
1328fcf3ce44SJohn Forte 	switch (event) {
1329fcf3ce44SJohn Forte 	/* -E8: */
1330fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E8:
1331fcf3ce44SJohn Forte 		icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1332fcf3ce44SJohn Forte 
1333fcf3ce44SJohn Forte 		/* the caller has already remove cmd from queue */
1334fcf3ce44SJohn Forte 
1335fcf3ce44SJohn Forte 		icmdp->cmd_next = NULL;
1336fcf3ce44SJohn Forte 		icmdp->cmd_prev = NULL;
1337fcf3ce44SJohn Forte 		iscsi_iodone(isp, icmdp);
1338fcf3ce44SJohn Forte 		break;
1339fcf3ce44SJohn Forte 	/* All other events are invalid for this state */
1340fcf3ce44SJohn Forte 	default:
1341fcf3ce44SJohn Forte 		ASSERT(FALSE);
1342fcf3ce44SJohn Forte 	}
1343fcf3ce44SJohn Forte }
1344fcf3ce44SJohn Forte 
1345fcf3ce44SJohn Forte 
1346fcf3ce44SJohn Forte /*
1347fcf3ce44SJohn Forte  * iscsi_cmd_state_str -
1348fcf3ce44SJohn Forte  *
1349fcf3ce44SJohn Forte  */
1350fcf3ce44SJohn Forte static char *
iscsi_cmd_state_str(iscsi_cmd_state_t state)1351fcf3ce44SJohn Forte iscsi_cmd_state_str(iscsi_cmd_state_t state)
1352fcf3ce44SJohn Forte {
1353fcf3ce44SJohn Forte 	switch (state) {
1354fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_FREE:
1355fcf3ce44SJohn Forte 		return ("free");
1356fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_PENDING:
1357fcf3ce44SJohn Forte 		return ("pending");
1358fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_ACTIVE:
1359fcf3ce44SJohn Forte 		return ("active");
1360fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_ABORTING:
1361fcf3ce44SJohn Forte 		return ("aborting");
136230e7468fSPeter Dunlap 	case ISCSI_CMD_STATE_IDM_ABORTING:
136330e7468fSPeter Dunlap 		return ("idm-aborting");
1364fcf3ce44SJohn Forte 	case ISCSI_CMD_STATE_COMPLETED:
1365fcf3ce44SJohn Forte 		return ("completed");
1366fcf3ce44SJohn Forte 	default:
1367fcf3ce44SJohn Forte 		return ("unknown");
1368fcf3ce44SJohn Forte 	}
1369fcf3ce44SJohn Forte }
1370fcf3ce44SJohn Forte 
1371fcf3ce44SJohn Forte 
1372fcf3ce44SJohn Forte /*
1373fcf3ce44SJohn Forte  * iscsi_cmd_event_str -
1374fcf3ce44SJohn Forte  *
1375fcf3ce44SJohn Forte  */
1376fcf3ce44SJohn Forte static char *
iscsi_cmd_event_str(iscsi_cmd_event_t event)1377fcf3ce44SJohn Forte iscsi_cmd_event_str(iscsi_cmd_event_t event)
1378fcf3ce44SJohn Forte {
1379fcf3ce44SJohn Forte 	switch (event) {
1380fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E1:
1381fcf3ce44SJohn Forte 		return ("E1");
1382fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E2:
1383fcf3ce44SJohn Forte 		return ("E2");
1384fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E3:
1385fcf3ce44SJohn Forte 		return ("E3");
1386fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E4:
1387fcf3ce44SJohn Forte 		return ("E4");
1388fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E6:
1389fcf3ce44SJohn Forte 		return ("E6");
1390fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E7:
1391fcf3ce44SJohn Forte 		return ("E7");
1392fcf3ce44SJohn Forte 	case ISCSI_CMD_EVENT_E8:
1393fcf3ce44SJohn Forte 		return ("E8");
139430e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E9:
139530e7468fSPeter Dunlap 		return ("E9");
139630e7468fSPeter Dunlap 	case ISCSI_CMD_EVENT_E10:
139730e7468fSPeter Dunlap 		return ("E10");
1398fcf3ce44SJohn Forte 	default:
1399fcf3ce44SJohn Forte 		return ("unknown");
1400fcf3ce44SJohn Forte 	}
1401fcf3ce44SJohn Forte }
1402fcf3ce44SJohn Forte 
1403fcf3ce44SJohn Forte 
1404fcf3ce44SJohn Forte /*
1405fcf3ce44SJohn Forte  * iscsi_cmd_event_str -
1406fcf3ce44SJohn Forte  *
1407fcf3ce44SJohn Forte  */
1408fcf3ce44SJohn Forte static char *
iscsi_cmd_type_str(iscsi_cmd_type_t type)1409fcf3ce44SJohn Forte iscsi_cmd_type_str(iscsi_cmd_type_t type)
1410fcf3ce44SJohn Forte {
1411fcf3ce44SJohn Forte 	switch (type) {
1412fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_SCSI:
1413fcf3ce44SJohn Forte 		return ("scsi");
1414fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_NOP:
1415fcf3ce44SJohn Forte 		return ("nop");
1416fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_ABORT:
1417fcf3ce44SJohn Forte 		return ("abort");
1418fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_RESET:
1419fcf3ce44SJohn Forte 		return ("reset");
1420fcf3ce44SJohn Forte 	case ISCSI_CMD_TYPE_LOGOUT:
1421fcf3ce44SJohn Forte 		return ("logout");
1422fcf3ce44SJohn Forte 	default:
1423fcf3ce44SJohn Forte 		return ("unknown");
1424fcf3ce44SJohn Forte 	}
1425fcf3ce44SJohn Forte }
1426