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 */
31 static void iscsi_cmd_state_free(iscsi_cmd_t *icmdp,
32     iscsi_cmd_event_t event, void *arg);
33 static void iscsi_cmd_state_pending(iscsi_cmd_t *icmdp,
34     iscsi_cmd_event_t event, void *arg);
35 static void iscsi_cmd_state_active(iscsi_cmd_t *icmdp,
36     iscsi_cmd_event_t event, void *arg);
37 static void iscsi_cmd_state_aborting(iscsi_cmd_t *icmdp,
38     iscsi_cmd_event_t event, void *arg);
39 static void iscsi_cmd_state_idm_aborting(iscsi_cmd_t *icmdp,
40     iscsi_cmd_event_t event, void *arg);
41 static void iscsi_cmd_state_completed(iscsi_cmd_t *icmdp,
42     iscsi_cmd_event_t event, void *arg);
43 static char *iscsi_cmd_state_str(iscsi_cmd_state_t state);
44 static char *iscsi_cmd_event_str(iscsi_cmd_event_t event);
45 /* LINTED E_STATIC_UNUSED */
46 static 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  */
67 int	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  */
181 void
182 iscsi_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  */
256 iscsi_cmd_t *
257 iscsi_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  */
278 void
279 iscsi_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  */
307 static void
308 iscsi_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  */
360 static void
361 iscsi_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  */
715 static void
716 iscsi_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  */
1129 static void
1130 iscsi_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 
1218 static void
1219 iscsi_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  */
1298 static void
1299 iscsi_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  */
1332 static char *
1333 iscsi_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  */
1358 static char *
1359 iscsi_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  */
1390 static char *
1391 iscsi_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