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