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 
340 			icmdp->cmd_un.scsi.pkt_stat &=
341 			    ISCSI_CMD_PKT_STAT_INIT;
342 		} else {
343 			icmdp->cmd_lbolt_timeout = icmdp->cmd_lbolt_pending +
344 			    SEC_TO_TICK(ISCSI_INTERNAL_CMD_TIMEOUT *
345 			    iscsi_cmd_timeout_factor);
346 		}
347 
348 		/* place into pending queue */
349 		iscsi_enqueue_pending_cmd(isp, icmdp);
350 
351 		break;
352 
353 	/* All other events are invalid for this state */
354 	default:
355 		ASSERT(FALSE);
356 	}
357 }
358 
359 /*
360  * iscsi_cmd_state_pending -
361  *
362  */
363 static void
364 iscsi_cmd_state_pending(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
365 {
366 	iscsi_status_t	status;
367 	iscsi_sess_t	*isp		= (iscsi_sess_t *)arg;
368 	boolean_t	free_icmdp	= B_FALSE;
369 	int		rval;
370 
371 	ASSERT(icmdp != NULL);
372 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_PENDING);
373 	ASSERT(isp != NULL);
374 
375 	/* switch on event change */
376 	switch (event) {
377 	/* -E2: Command was submitted and now active on wire */
378 	case ISCSI_CMD_EVENT_E2:
379 
380 		/* A connection should have already been assigned */
381 		ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
382 		ASSERT(icmdp->cmd_conn != NULL);
383 
384 		/*
385 		 * RESERVE RESOURSES
386 		 */
387 		switch (icmdp->cmd_type) {
388 		case ISCSI_CMD_TYPE_SCSI:
389 			/* check cmdsn window */
390 			mutex_enter(&isp->sess_cmdsn_mutex);
391 			if (!iscsi_sna_lte(isp->sess_cmdsn,
392 			    isp->sess_maxcmdsn)) {
393 				/* cmdsn window closed */
394 				mutex_exit(&isp->sess_cmdsn_mutex);
395 				mutex_exit(&isp->sess_queue_pending.mutex);
396 				isp->sess_window_open = B_FALSE;
397 				icmdp->cmd_misc_flags |=
398 				    ISCSI_CMD_MISCFLAG_STUCK;
399 				return;
400 			}
401 
402 			/* assign itt */
403 			status = iscsi_sess_reserve_scsi_itt(icmdp);
404 			if (!ISCSI_SUCCESS(status)) {
405 				/* no available itt slots */
406 				mutex_exit(&isp->sess_cmdsn_mutex);
407 				mutex_exit(&isp->sess_queue_pending.mutex);
408 				isp->sess_window_open = B_FALSE;
409 				icmdp->cmd_misc_flags |=
410 				    ISCSI_CMD_MISCFLAG_STUCK;
411 				return;
412 			}
413 			mutex_exit(&isp->sess_cmdsn_mutex);
414 			break;
415 
416 		case ISCSI_CMD_TYPE_ABORT:
417 			/*
418 			 * Verify ABORT's parent SCSI command is still
419 			 * there.  If parent SCSI command is completed
420 			 * then there is no longer any reason to abort
421 			 * the parent command.  This could occur due
422 			 * to a connection or target reset.
423 			 */
424 			ASSERT(icmdp->cmd_un.abort.icmdp != NULL);
425 			if (icmdp->cmd_un.abort.icmdp->cmd_state ==
426 			    ISCSI_CMD_STATE_COMPLETED) {
427 				iscsi_dequeue_pending_cmd(isp, icmdp);
428 				mutex_exit(&isp->sess_queue_pending.mutex);
429 
430 				mutex_enter(&icmdp->cmd_un.abort.icmdp->
431 				    cmd_mutex);
432 				icmdp->cmd_un.abort.icmdp->
433 				    cmd_un.scsi.abort_icmdp = NULL;
434 				cv_broadcast(&icmdp->cmd_un.abort.icmdp->
435 				    cmd_completion);
436 				mutex_exit(&icmdp->cmd_un.abort.icmdp->
437 				    cmd_mutex);
438 				icmdp->cmd_un.abort.icmdp = NULL;
439 
440 				icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
441 				icmdp->cmd_misc_flags |=
442 				    ISCSI_CMD_MISCFLAG_FREE;
443 				return;
444 			}
445 			/* FALLTHRU */
446 		case ISCSI_CMD_TYPE_RESET:
447 			/* FALLTHRU */
448 		case ISCSI_CMD_TYPE_LOGOUT:
449 			mutex_enter(&isp->sess_cmdsn_mutex);
450 			/* assign itt */
451 			status = iscsi_sess_reserve_itt(isp, icmdp);
452 			if (!ISCSI_SUCCESS(status)) {
453 				/* no available itt slots */
454 				mutex_exit(&isp->sess_cmdsn_mutex);
455 				mutex_exit(&isp->sess_queue_pending.mutex);
456 				isp->sess_window_open = B_FALSE;
457 				return;
458 			}
459 			mutex_exit(&isp->sess_cmdsn_mutex);
460 			break;
461 		case ISCSI_CMD_TYPE_NOP:
462 			/* assign itt, if needed */
463 			if (icmdp->cmd_itt == ISCSI_RSVD_TASK_TAG) {
464 				/* not expecting a response */
465 				free_icmdp = B_TRUE;
466 			} else {
467 				/* expecting response, assign an itt */
468 				mutex_enter(&isp->sess_cmdsn_mutex);
469 				/* assign itt */
470 				status = iscsi_sess_reserve_itt(isp, icmdp);
471 				if (!ISCSI_SUCCESS(status)) {
472 					/* no available itt slots */
473 					mutex_exit(&isp->sess_cmdsn_mutex);
474 					mutex_exit(&isp->sess_queue_pending.
475 					    mutex);
476 					isp->sess_window_open = B_FALSE;
477 					return;
478 				}
479 				mutex_exit(&isp->sess_cmdsn_mutex);
480 			}
481 			break;
482 
483 		case ISCSI_CMD_TYPE_TEXT:
484 			mutex_enter(&isp->sess_cmdsn_mutex);
485 			/* check cmdsn window */
486 			if (!iscsi_sna_lte(isp->sess_cmdsn,
487 			    isp->sess_maxcmdsn)) {
488 				/* cmdsn window closed */
489 				isp->sess_window_open = B_FALSE;
490 				mutex_exit(&isp->sess_cmdsn_mutex);
491 				mutex_exit(&isp->sess_queue_pending.mutex);
492 				icmdp->cmd_misc_flags |=
493 				    ISCSI_CMD_MISCFLAG_STUCK;
494 				return;
495 			}
496 			if (icmdp->cmd_un.text.stage ==
497 			    ISCSI_CMD_TEXT_INITIAL_REQ) {
498 				/* assign itt */
499 				status = iscsi_sess_reserve_itt(isp, icmdp);
500 				if (!ISCSI_SUCCESS(status)) {
501 					/* no available itt slots */
502 					mutex_exit(&isp->sess_cmdsn_mutex);
503 					mutex_exit(&isp->sess_queue_pending.
504 					    mutex);
505 					isp->sess_window_open = B_FALSE;
506 					icmdp->cmd_misc_flags |=
507 					    ISCSI_CMD_MISCFLAG_STUCK;
508 					return;
509 				}
510 			}
511 			mutex_exit(&isp->sess_cmdsn_mutex);
512 			break;
513 
514 		default:
515 			ASSERT(FALSE);
516 		}
517 
518 		/*
519 		 * RESOURCES RESERVED
520 		 *
521 		 * Now that we have the resources reserved, establish timeout
522 		 * for cmd_type values that depend on having an open cmdsn
523 		 * window (i.e. cmd_type that called iscsi_sna_lte() above).
524 		 */
525 		if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
526 			if (icmdp->cmd_un.scsi.pkt &&
527 			    icmdp->cmd_un.scsi.pkt->pkt_time)
528 				icmdp->cmd_lbolt_timeout =
529 				    ddi_get_lbolt() + SEC_TO_TICK(
530 				    icmdp->cmd_un.scsi.pkt->pkt_time *
531 				    iscsi_cmd_timeout_factor);
532 			else
533 				icmdp->cmd_lbolt_timeout = 0;
534 		} else if (icmdp->cmd_type == ISCSI_CMD_TYPE_TEXT) {
535 			icmdp->cmd_lbolt_timeout = ddi_get_lbolt() +
536 			    SEC_TO_TICK(ISCSI_INTERNAL_CMD_TIMEOUT *
537 			    iscsi_cmd_timeout_factor);
538 		}
539 
540 		/* remove command from pending queue */
541 		iscsi_dequeue_pending_cmd(isp, icmdp);
542 		/* check if expecting a response */
543 		if (free_icmdp == B_FALSE) {
544 			/* response expected, move to active queue */
545 			mutex_enter(&icmdp->cmd_conn->conn_queue_active.mutex);
546 			iscsi_enqueue_active_cmd(icmdp->cmd_conn, icmdp);
547 			mutex_exit(&icmdp->cmd_conn->conn_queue_active.mutex);
548 		}
549 
550 		/*
551 		 * TRANSFER COMMAND
552 		 */
553 		rval = iscsi_tx_cmd(isp, icmdp);
554 
555 		ASSERT(!mutex_owned(&isp->sess_queue_pending.mutex));
556 
557 		/*
558 		 * CHECK SUCCESS/FAILURE
559 		 */
560 		if (!ISCSI_SUCCESS(rval)) {
561 			/*
562 			 * iscsi_tx_cmd failed.  No cleanup is required
563 			 * of commands that were put in the active queue.
564 			 * If the tx failed then rx will also fail and cleanup
565 			 * all items in the active/aborted queue in a common.
566 			 */
567 
568 			/* EMPTY */
569 		}
570 
571 		/* free temporary commands */
572 		if (free_icmdp == B_TRUE) {
573 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
574 			icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_FREE;
575 		}
576 		break;
577 
578 	/* -E10: Abort is no longer required for this command */
579 	case ISCSI_CMD_EVENT_E10:
580 		/*
581 		 * Acquiring the sess_queue_pending lock while the
582 		 * conn_queue_active lock is held conflicts with the
583 		 * locking order in iscsi_cmd_state_pending where
584 		 * conn_queue_active is acquired while sess_queue_pending
585 		 * is held.  Normally this would be a dangerous lock
586 		 * order conflict, except that we know that if we are
587 		 * seeing ISCSI_CMD_EVENT_E10 then the command being
588 		 * aborted is in "aborting" state and by extension
589 		 * is not in "pending" state.  Therefore the code
590 		 * path with that alternate lock order will not execute.
591 		 * That's good because we can't drop the lock here without
592 		 * risking a deadlock.
593 		 */
594 		ASSERT(mutex_owned(&icmdp->cmd_conn->conn_queue_active.mutex));
595 		mutex_enter(&isp->sess_queue_pending.mutex);
596 
597 		icmdp->cmd_lbolt_aborting = ddi_get_lbolt();
598 
599 		iscsi_dequeue_pending_cmd(isp, icmdp);
600 
601 		icmdp->cmd_un.abort.icmdp->cmd_un.scsi.abort_icmdp = NULL;
602 		icmdp->cmd_un.abort.icmdp = NULL;
603 		icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_FREE;
604 		icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
605 
606 		mutex_exit(&isp->sess_queue_pending.mutex);
607 		break;
608 
609 	/* -E4: Command has been requested to abort */
610 	case ISCSI_CMD_EVENT_E4:
611 		ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
612 
613 		icmdp->cmd_lbolt_aborting = ddi_get_lbolt();
614 		ISCSI_CMD_SET_REASON_STAT(icmdp,
615 		    CMD_ABORTED, STAT_ABORTED);
616 
617 		iscsi_dequeue_pending_cmd(isp, icmdp);
618 		iscsi_enqueue_completed_cmd(isp, icmdp);
619 
620 		icmdp->cmd_lbolt_aborting = ddi_get_lbolt();
621 
622 		break;
623 
624 	/* -E7: Command has been reset */
625 	case ISCSI_CMD_EVENT_E7:
626 
627 		/* FALLTHRU */
628 
629 	/* -E6: Command has timed out */
630 	case ISCSI_CMD_EVENT_E6:
631 		ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
632 		iscsi_dequeue_pending_cmd(isp, icmdp);
633 
634 		switch (icmdp->cmd_type) {
635 		case ISCSI_CMD_TYPE_SCSI:
636 			/* Complete to caller as TIMEOUT */
637 			if (event == ISCSI_CMD_EVENT_E6) {
638 				ISCSI_CMD_SET_REASON_STAT(icmdp,
639 				    CMD_TIMEOUT, STAT_TIMEOUT);
640 			} else {
641 				ISCSI_CMD_SET_REASON_STAT(icmdp,
642 				    CMD_TRAN_ERR, icmdp->cmd_un.scsi.pkt_stat);
643 			}
644 			iscsi_enqueue_completed_cmd(isp, icmdp);
645 			break;
646 
647 		case ISCSI_CMD_TYPE_NOP:
648 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
649 			/*
650 			 * Timeout occured.  Just free NOP.  Another
651 			 * NOP request will be spawned to replace
652 			 * this one.
653 			 */
654 			icmdp->cmd_misc_flags |=
655 			    ISCSI_CMD_MISCFLAG_FREE;
656 
657 			break;
658 
659 		case ISCSI_CMD_TYPE_ABORT:
660 			mutex_enter(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
661 			icmdp->cmd_un.abort.icmdp->
662 			    cmd_un.scsi.abort_icmdp = NULL;
663 			cv_broadcast(&icmdp->cmd_un.abort.icmdp->
664 			    cmd_completion);
665 			mutex_exit(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
666 			icmdp->cmd_un.abort.icmdp = NULL;
667 
668 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
669 			icmdp->cmd_misc_flags |=
670 			    ISCSI_CMD_MISCFLAG_FREE;
671 			break;
672 
673 		case ISCSI_CMD_TYPE_RESET:
674 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
675 			/*
676 			 * If we are failing a RESET we need
677 			 * to notify the tran_reset caller.
678 			 * with the cmd and notify caller.
679 			 */
680 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
681 			    ISCSI_STATUS_CMD_FAILED);
682 			break;
683 
684 		case ISCSI_CMD_TYPE_LOGOUT:
685 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
686 			/* notify requester of failure */
687 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
688 			    ISCSI_STATUS_CMD_FAILED);
689 			break;
690 
691 		case ISCSI_CMD_TYPE_TEXT:
692 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
693 			icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
694 			/*
695 			 * If a TEXT command fails, notify the owner.
696 			 */
697 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
698 			    ISCSI_STATUS_CMD_FAILED);
699 			break;
700 
701 		default:
702 			ASSERT(FALSE);
703 			break;
704 		}
705 		break;
706 
707 	/* All other events are invalid for this state */
708 	default:
709 		ASSERT(FALSE);
710 	}
711 }
712 
713 
714 /*
715  * iscsi_cmd_state_active -
716  *
717  */
718 static void
719 iscsi_cmd_state_active(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
720 {
721 	iscsi_sess_t	*isp		= (iscsi_sess_t *)arg;
722 	iscsi_hba_t	*ihp;
723 	iscsi_cmd_t	*t_icmdp	= NULL;
724 	iscsi_conn_t	*icp		= NULL;
725 
726 	ASSERT(icmdp != NULL);
727 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_ACTIVE);
728 	ASSERT(isp != NULL);
729 
730 	ihp = isp->sess_hba;
731 	ASSERT(ihp != NULL);
732 
733 	icp = icmdp->cmd_conn;
734 	ASSERT(icp != NULL);
735 	ASSERT(mutex_owned(&icp->conn_queue_active.mutex));
736 
737 	/* switch on event change */
738 	switch (event) {
739 	/* -E3: Command was successfully completed */
740 	case ISCSI_CMD_EVENT_E3:
741 		/*
742 		 * Remove command from the active list.  We need to protect
743 		 * someone from looking up this command ITT until it's
744 		 * freed of the command is moved to a new queue location.
745 		 */
746 		mutex_enter(&isp->sess_cmdsn_mutex);
747 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
748 
749 		switch (icmdp->cmd_type) {
750 		case ISCSI_CMD_TYPE_SCSI:
751 			iscsi_sess_release_scsi_itt(icmdp);
752 			mutex_exit(&isp->sess_cmdsn_mutex);
753 			iscsi_enqueue_completed_cmd(isp, icmdp);
754 			break;
755 
756 		case ISCSI_CMD_TYPE_NOP:
757 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
758 			iscsi_sess_release_itt(isp, icmdp);
759 			mutex_exit(&isp->sess_cmdsn_mutex);
760 
761 			/* free alloc */
762 			icmdp->cmd_misc_flags |=
763 			    ISCSI_CMD_MISCFLAG_FREE;
764 
765 			break;
766 
767 		case ISCSI_CMD_TYPE_ABORT:
768 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
769 			iscsi_sess_release_itt(isp, icmdp);
770 			mutex_exit(&isp->sess_cmdsn_mutex);
771 
772 			/*
773 			 * Abort was completed successfully.  We should
774 			 * complete the parent scsi command if it still
775 			 * exists as timed out, and the state is not
776 			 * COMPLETED
777 			 */
778 			t_icmdp = icmdp->cmd_un.abort.icmdp;
779 			ASSERT(t_icmdp != NULL);
780 			mutex_enter(&t_icmdp->cmd_mutex);
781 			t_icmdp->cmd_un.scsi.abort_icmdp = NULL;
782 			if (t_icmdp->cmd_state != ISCSI_CMD_STATE_COMPLETED) {
783 				iscsi_dequeue_active_cmd(
784 				    t_icmdp->cmd_conn, t_icmdp);
785 				mutex_enter(
786 				    &icp->conn_queue_idm_aborting.mutex);
787 				iscsi_enqueue_idm_aborting_cmd(
788 				    t_icmdp->cmd_conn,
789 				    t_icmdp);
790 				mutex_exit(&icp->conn_queue_idm_aborting.mutex);
791 
792 				/*
793 				 * Complete abort processing after IDM
794 				 * calls us back.  Set the status to use
795 				 * when we complete the command.
796 				 */
797 				ISCSI_CMD_SET_REASON_STAT(
798 				    t_icmdp, CMD_TIMEOUT, STAT_ABORTED);
799 				idm_task_abort(icp->conn_ic, t_icmdp->cmd_itp,
800 				    AT_TASK_MGMT_ABORT);
801 			} else {
802 				cv_broadcast(&t_icmdp->cmd_completion);
803 			}
804 			mutex_exit(&t_icmdp->cmd_mutex);
805 			icmdp->cmd_un.abort.icmdp = NULL;
806 
807 			icmdp->cmd_misc_flags |=
808 			    ISCSI_CMD_MISCFLAG_FREE;
809 
810 			break;
811 		case ISCSI_CMD_TYPE_RESET:
812 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
813 			iscsi_sess_release_itt(isp, icmdp);
814 			mutex_exit(&isp->sess_cmdsn_mutex);
815 
816 			/*
817 			 * Complete the abort/reset command.
818 			 */
819 			if (icmdp->cmd_un.reset.response !=
820 			    SCSI_TCP_TM_RESP_COMPLETE) {
821 				ISCSI_CMD_ISSUE_CALLBACK(icmdp,
822 				    ISCSI_STATUS_CMD_FAILED);
823 			} else {
824 				ISCSI_CMD_ISSUE_CALLBACK(icmdp,
825 				    ISCSI_STATUS_SUCCESS);
826 			}
827 
828 			break;
829 
830 		case ISCSI_CMD_TYPE_LOGOUT:
831 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
832 			iscsi_sess_release_itt(isp, icmdp);
833 			mutex_exit(&isp->sess_cmdsn_mutex);
834 
835 			/*
836 			 * Complete the logout successfully.
837 			 */
838 			ISCSI_CMD_ISSUE_CALLBACK(icmdp, ISCSI_STATUS_SUCCESS);
839 			break;
840 
841 		case ISCSI_CMD_TYPE_TEXT:
842 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
843 			if (icmdp->cmd_un.text.stage ==
844 			    ISCSI_CMD_TEXT_FINAL_RSP) {
845 				iscsi_sess_release_itt(isp, icmdp);
846 			}
847 			mutex_exit(&isp->sess_cmdsn_mutex);
848 
849 			/*
850 			 * Complete the text command successfully.
851 			 */
852 			ISCSI_CMD_ISSUE_CALLBACK(icmdp, icmdp->cmd_result);
853 			break;
854 
855 		default:
856 			mutex_exit(&isp->sess_cmdsn_mutex);
857 			ASSERT(FALSE);
858 		}
859 
860 		ASSERT(!mutex_owned(&isp->sess_cmdsn_mutex));
861 		break;
862 
863 	/* -E10,E4: Command has been requested to abort */
864 	case ISCSI_CMD_EVENT_E10:
865 		/* FALLTHRU */
866 	case ISCSI_CMD_EVENT_E4:
867 
868 		/* E4 is only for resets and aborts */
869 		ASSERT((icmdp->cmd_type == ISCSI_CMD_TYPE_ABORT) ||
870 		    (icmdp->cmd_type == ISCSI_CMD_TYPE_RESET));
871 		/* FALLTHRU */
872 
873 	/* -E6: Command has timed out */
874 	case ISCSI_CMD_EVENT_E6:
875 
876 		switch (icmdp->cmd_type) {
877 		case ISCSI_CMD_TYPE_SCSI:
878 			icmdp->cmd_state = ISCSI_CMD_STATE_ABORTING;
879 			iscsi_handle_abort(icmdp);
880 			break;
881 
882 		case ISCSI_CMD_TYPE_NOP:
883 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
884 
885 			mutex_enter(&isp->sess_cmdsn_mutex);
886 			iscsi_sess_release_itt(isp, icmdp);
887 			iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
888 			mutex_exit(&isp->sess_cmdsn_mutex);
889 
890 			icmdp->cmd_misc_flags |=
891 			    ISCSI_CMD_MISCFLAG_FREE;
892 
893 			break;
894 
895 		case ISCSI_CMD_TYPE_ABORT:
896 			icmdp->cmd_state =
897 			    ISCSI_CMD_STATE_FREE;
898 
899 			mutex_enter(&isp->sess_cmdsn_mutex);
900 			iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
901 			iscsi_sess_release_itt(isp, icmdp);
902 			mutex_exit(&isp->sess_cmdsn_mutex);
903 
904 			/*
905 			 * If this is an E4 then we may need to deal with
906 			 * the abort's associated SCSI command.  If this
907 			 * is an E10 then IDM is already cleaning up the
908 			 * SCSI command and all we need to do is break the
909 			 * linkage between them and free the abort command.
910 			 */
911 			t_icmdp = icmdp->cmd_un.abort.icmdp;
912 			ASSERT(t_icmdp != NULL);
913 			if (event != ISCSI_CMD_EVENT_E10) {
914 
915 				mutex_enter(&t_icmdp->cmd_mutex);
916 				t_icmdp->cmd_un.scsi.abort_icmdp = NULL;
917 				/*
918 				 * If abort command is aborted then we should
919 				 * not act on the parent scsi command.  If the
920 				 * abort command timed out then we need to
921 				 * complete the parent command if it still
922 				 * exists with a timeout failure.
923 				 */
924 				if ((event == ISCSI_CMD_EVENT_E6) &&
925 				    (t_icmdp->cmd_state !=
926 				    ISCSI_CMD_STATE_IDM_ABORTING) &&
927 				    (t_icmdp->cmd_state !=
928 				    ISCSI_CMD_STATE_COMPLETED)) {
929 
930 					iscsi_dequeue_active_cmd(
931 					    t_icmdp->cmd_conn, t_icmdp);
932 					mutex_enter(&icp->
933 					    conn_queue_idm_aborting.mutex);
934 					iscsi_enqueue_idm_aborting_cmd(
935 					    t_icmdp->cmd_conn,  t_icmdp);
936 					mutex_exit(&icp->
937 					    conn_queue_idm_aborting.mutex);
938 					/*
939 					 * Complete abort processing after IDM
940 					 * calls us back.  Set the status to use
941 					 * when we complete the command.
942 					 */
943 					ISCSI_CMD_SET_REASON_STAT(t_icmdp,
944 					    CMD_TIMEOUT, STAT_TIMEOUT);
945 					idm_task_abort(icp->conn_ic,
946 					    t_icmdp->cmd_itp,
947 					    AT_TASK_MGMT_ABORT);
948 				} else {
949 					cv_broadcast(&t_icmdp->cmd_completion);
950 				}
951 				mutex_exit(&t_icmdp->cmd_mutex);
952 			} else {
953 				t_icmdp->cmd_un.scsi.abort_icmdp = NULL;
954 			}
955 			icmdp->cmd_un.abort.icmdp = NULL;
956 			icmdp->cmd_misc_flags |=
957 			    ISCSI_CMD_MISCFLAG_FREE;
958 			break;
959 
960 		case ISCSI_CMD_TYPE_RESET:
961 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
962 
963 			mutex_enter(&isp->sess_cmdsn_mutex);
964 			iscsi_sess_release_itt(isp, icmdp);
965 			iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
966 			mutex_exit(&isp->sess_cmdsn_mutex);
967 
968 			/*
969 			 * If we are failing a RESET we need
970 			 * to notify the tran_reset caller.
971 			 * It will free the memory associated
972 			 * with the cmd and notify caller.
973 			 */
974 
975 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
976 			    ISCSI_STATUS_CMD_FAILED);
977 			break;
978 
979 		case ISCSI_CMD_TYPE_LOGOUT:
980 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
981 
982 			mutex_enter(&isp->sess_cmdsn_mutex);
983 			iscsi_sess_release_itt(isp, icmdp);
984 			iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
985 			mutex_exit(&isp->sess_cmdsn_mutex);
986 
987 			/*
988 			 * Notify caller of failure.
989 			 */
990 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
991 			    ISCSI_STATUS_CMD_FAILED);
992 			break;
993 
994 		case ISCSI_CMD_TYPE_TEXT:
995 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
996 			icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
997 			mutex_enter(&isp->sess_cmdsn_mutex);
998 			iscsi_sess_release_itt(isp, icmdp);
999 			iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
1000 			mutex_exit(&isp->sess_cmdsn_mutex);
1001 
1002 			/*
1003 			 * If a TEXT command fails, notify caller so
1004 			 * it can free assocated command
1005 			 */
1006 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
1007 			    ISCSI_STATUS_CMD_FAILED);
1008 			break;
1009 
1010 		default:
1011 			ASSERT(FALSE);
1012 		}
1013 
1014 		ASSERT(!mutex_owned(&isp->sess_cmdsn_mutex));
1015 		break;
1016 
1017 	/* -E7: Connection has encountered a problem */
1018 	case ISCSI_CMD_EVENT_E7:
1019 		mutex_enter(&isp->sess_cmdsn_mutex);
1020 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
1021 
1022 		switch (icmdp->cmd_type) {
1023 		case ISCSI_CMD_TYPE_SCSI:
1024 			mutex_exit(&isp->sess_cmdsn_mutex);
1025 			mutex_enter(&icp->conn_queue_idm_aborting.mutex);
1026 			iscsi_enqueue_idm_aborting_cmd(icmdp->cmd_conn, icmdp);
1027 			mutex_exit(&icp->conn_queue_idm_aborting.mutex);
1028 			ISCSI_CMD_SET_REASON_STAT(icmdp,
1029 			    CMD_TRAN_ERR, icmdp->cmd_un.scsi.pkt_stat);
1030 			idm_task_abort(icp->conn_ic, icmdp->cmd_itp,
1031 			    AT_TASK_MGMT_ABORT);
1032 			break;
1033 
1034 		case ISCSI_CMD_TYPE_NOP:
1035 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1036 			iscsi_sess_release_itt(isp, icmdp);
1037 			mutex_exit(&isp->sess_cmdsn_mutex);
1038 
1039 			icmdp->cmd_misc_flags |=
1040 			    ISCSI_CMD_MISCFLAG_FREE;
1041 			break;
1042 
1043 		case ISCSI_CMD_TYPE_ABORT:
1044 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1045 			iscsi_sess_release_itt(isp, icmdp);
1046 			mutex_exit(&isp->sess_cmdsn_mutex);
1047 
1048 			mutex_enter(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
1049 			icmdp->cmd_un.abort.icmdp->
1050 			    cmd_un.scsi.abort_icmdp = NULL;
1051 			cv_broadcast(&icmdp->cmd_un.abort.icmdp->
1052 			    cmd_completion);
1053 			mutex_exit(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
1054 			/*
1055 			 * Nullify the abort command's pointer to its
1056 			 * parent command. It does not have to complete its
1057 			 * parent command because the parent command will
1058 			 * also get an E7.
1059 			 */
1060 			icmdp->cmd_un.abort.icmdp = NULL;
1061 
1062 			icmdp->cmd_misc_flags |=
1063 			    ISCSI_CMD_MISCFLAG_FREE;
1064 			break;
1065 
1066 		case ISCSI_CMD_TYPE_RESET:
1067 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1068 			iscsi_sess_release_itt(isp, icmdp);
1069 			mutex_exit(&isp->sess_cmdsn_mutex);
1070 			/*
1071 			 * If we are failing a ABORT we need
1072 			 * to notify the tran_abort caller.
1073 			 * It will free the memory associated
1074 			 * with the cmd and notify caller.
1075 			 */
1076 
1077 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
1078 			    ISCSI_STATUS_CMD_FAILED);
1079 			break;
1080 
1081 		case ISCSI_CMD_TYPE_LOGOUT:
1082 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1083 			/*
1084 			 * A connection problem and we attempted to
1085 			 * logout?  I guess we can just free the
1086 			 * request.  Someone has already pushed the
1087 			 * connection state.
1088 			 */
1089 			iscsi_sess_release_itt(isp, icmdp);
1090 			mutex_exit(&isp->sess_cmdsn_mutex);
1091 
1092 			ISCSI_CMD_ISSUE_CALLBACK(icmdp, ISCSI_STATUS_SUCCESS);
1093 			break;
1094 
1095 		case ISCSI_CMD_TYPE_TEXT:
1096 			icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1097 			icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
1098 			iscsi_sess_release_itt(isp, icmdp);
1099 			mutex_exit(&isp->sess_cmdsn_mutex);
1100 
1101 			/*
1102 			 * If a TEXT command fails, notify caller so
1103 			 * it can free assocated command
1104 			 */
1105 			ISCSI_CMD_ISSUE_CALLBACK(icmdp,
1106 			    ISCSI_STATUS_CMD_FAILED);
1107 			break;
1108 
1109 		default:
1110 			mutex_exit(&isp->sess_cmdsn_mutex);
1111 			ASSERT(FALSE);
1112 			break;
1113 		}
1114 
1115 		ASSERT(!mutex_owned(&isp->sess_cmdsn_mutex));
1116 		break;
1117 
1118 	/* -E9: IDM is no longer processing this command */
1119 	case ISCSI_CMD_EVENT_E9:
1120 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
1121 
1122 		iscsi_task_cleanup(ISCSI_OP_SCSI_RSP, icmdp);
1123 		iscsi_sess_release_scsi_itt(icmdp);
1124 
1125 		ISCSI_CMD_SET_REASON_STAT(icmdp, CMD_TRAN_ERR,
1126 		    icmdp->cmd_un.scsi.pkt_stat);
1127 		iscsi_enqueue_completed_cmd(isp, icmdp);
1128 		break;
1129 
1130 	/* All other events are invalid for this state */
1131 	default:
1132 		ASSERT(FALSE);
1133 	}
1134 }
1135 
1136 
1137 /*
1138  * iscsi_cmd_state_aborting -
1139  *
1140  */
1141 static void
1142 iscsi_cmd_state_aborting(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
1143 {
1144 	iscsi_sess_t	*isp	= (iscsi_sess_t *)arg;
1145 	iscsi_cmd_t	*a_icmdp;
1146 
1147 	ASSERT(icmdp != NULL);
1148 	ASSERT(icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI);
1149 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_ABORTING);
1150 	ASSERT(isp != NULL);
1151 	ASSERT(mutex_owned(&icmdp->cmd_conn->conn_queue_active.mutex));
1152 
1153 	/* switch on event change */
1154 	switch (event) {
1155 	/* -E3: Command was successfully completed */
1156 	case ISCSI_CMD_EVENT_E3:
1157 		/*
1158 		 * Remove command from the aborting list
1159 		 */
1160 		mutex_enter(&isp->sess_cmdsn_mutex);
1161 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
1162 		iscsi_sess_release_scsi_itt(icmdp);
1163 		mutex_exit(&isp->sess_cmdsn_mutex);
1164 
1165 		iscsi_enqueue_completed_cmd(isp, icmdp);
1166 		break;
1167 
1168 	/* -E4: Command has been requested to abort */
1169 	case ISCSI_CMD_EVENT_E4:
1170 		/*
1171 		 * An upper level driver might attempt to
1172 		 * abort a command that we are already
1173 		 * aborting due to a nop.  Since we are
1174 		 * already in the process of aborting
1175 		 * ignore the request.
1176 		 */
1177 		break;
1178 
1179 	/* -E6: Command has timed out */
1180 	case ISCSI_CMD_EVENT_E6:
1181 		ASSERT(FALSE);
1182 		/*
1183 		 * Timeouts should not occur on command in abort queue
1184 		 * they are already be processed due to a timeout.
1185 		 */
1186 		break;
1187 
1188 	/* -E7: Connection has encountered a problem */
1189 	case ISCSI_CMD_EVENT_E7:
1190 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
1191 		mutex_enter(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
1192 		iscsi_enqueue_idm_aborting_cmd(icmdp->cmd_conn, icmdp);
1193 		mutex_exit(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
1194 
1195 		/*
1196 		 * Since we are in "aborting" state there is another command
1197 		 * representing the abort of this command.  This command
1198 		 * will cleanup at some indeterminate time after the call
1199 		 * to idm_task_abort so we can't leave the abort request
1200 		 * active.  An E10 event to the abort command will cause
1201 		 * it to complete immediately.
1202 		 */
1203 		if ((a_icmdp = icmdp->cmd_un.scsi.abort_icmdp) != NULL) {
1204 			iscsi_cmd_state_machine(a_icmdp,
1205 			    ISCSI_CMD_EVENT_E10, arg);
1206 		}
1207 
1208 		ISCSI_CMD_SET_REASON_STAT(icmdp,
1209 		    CMD_TRAN_ERR, icmdp->cmd_un.scsi.pkt_stat);
1210 
1211 		idm_task_abort(icmdp->cmd_conn->conn_ic, icmdp->cmd_itp,
1212 		    AT_TASK_MGMT_ABORT);
1213 		break;
1214 
1215 	/* -E9: IDM is no longer processing this command */
1216 	case ISCSI_CMD_EVENT_E9:
1217 		iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
1218 
1219 		iscsi_task_cleanup(ISCSI_OP_SCSI_RSP, icmdp);
1220 		iscsi_sess_release_scsi_itt(icmdp);
1221 
1222 		ISCSI_CMD_SET_REASON_STAT(icmdp, CMD_TRAN_ERR,
1223 		    icmdp->cmd_un.scsi.pkt_stat);
1224 		iscsi_enqueue_completed_cmd(isp, icmdp);
1225 		break;
1226 
1227 	/* All other events are invalid for this state */
1228 	default:
1229 		ASSERT(FALSE);
1230 	}
1231 }
1232 
1233 static void
1234 iscsi_cmd_state_idm_aborting(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event,
1235     void *arg)
1236 {
1237 	iscsi_sess_t	*isp	= (iscsi_sess_t *)arg;
1238 
1239 	ASSERT(icmdp != NULL);
1240 	ASSERT(icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI);
1241 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_IDM_ABORTING);
1242 	ASSERT(isp != NULL);
1243 
1244 	/* switch on event change */
1245 	switch (event) {
1246 	/* -E3: Command was successfully completed */
1247 	case ISCSI_CMD_EVENT_E3:
1248 		/*
1249 		 * iscsi_rx_process_cmd_rsp() and iscsi_rx_process_data_rsp()
1250 		 * are supposed to confirm the cmd state is appropriate before
1251 		 * generating an E3 event.  E3 is not allowed in this state.
1252 		 */
1253 		ASSERT(0);
1254 		break;
1255 
1256 	/* -E4: Command has been requested to abort */
1257 	case ISCSI_CMD_EVENT_E4:
1258 		/*
1259 		 * An upper level driver might attempt to
1260 		 * abort a command that we are already
1261 		 * aborting due to a nop.  Since we are
1262 		 * already in the process of aborting
1263 		 * ignore the request.
1264 		 */
1265 		break;
1266 
1267 	/* -E6: Command has timed out */
1268 	case ISCSI_CMD_EVENT_E6:
1269 		ASSERT(FALSE);
1270 		/*
1271 		 * Timeouts should not occur on aborting commands
1272 		 */
1273 		break;
1274 
1275 	/* -E7: Connection has encountered a problem */
1276 	case ISCSI_CMD_EVENT_E7:
1277 		/*
1278 		 * We have already requested IDM to stop processing this
1279 		 * command so just update the pkt_statistics.
1280 		 */
1281 		ISCSI_CMD_SET_REASON_STAT(icmdp,
1282 		    CMD_TRAN_ERR, icmdp->cmd_un.scsi.pkt_stat);
1283 		break;
1284 
1285 	/* -E9: IDM is no longer processing this command */
1286 	case ISCSI_CMD_EVENT_E9:
1287 		mutex_enter(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
1288 		iscsi_dequeue_idm_aborting_cmd(icmdp->cmd_conn, icmdp);
1289 		mutex_exit(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
1290 
1291 		/* This is always an error so make sure an error has been set */
1292 		ASSERT(icmdp->cmd_un.scsi.pkt->pkt_reason != CMD_CMPLT);
1293 		iscsi_task_cleanup(ISCSI_OP_SCSI_RSP, icmdp);
1294 		iscsi_sess_release_scsi_itt(icmdp);
1295 
1296 		/*
1297 		 * Whoever called idm_task_abort should have set the completion
1298 		 * status beforehand.
1299 		 */
1300 		iscsi_enqueue_completed_cmd(isp, icmdp);
1301 		cv_broadcast(&icmdp->cmd_completion);
1302 		break;
1303 
1304 	/* All other events are invalid for this state */
1305 	default:
1306 		ASSERT(FALSE);
1307 	}
1308 }
1309 
1310 
1311 /*
1312  * iscsi_cmd_state_completed -
1313  *
1314  */
1315 static void
1316 iscsi_cmd_state_completed(iscsi_cmd_t *icmdp,
1317     iscsi_cmd_event_t event, void *arg)
1318 {
1319 	iscsi_sess_t	*isp	= (iscsi_sess_t *)arg;
1320 
1321 	ASSERT(icmdp != NULL);
1322 	ASSERT(icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI);
1323 	ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_COMPLETED);
1324 	ASSERT(isp != NULL);
1325 
1326 	/* switch on event change */
1327 	switch (event) {
1328 	/* -E8: */
1329 	case ISCSI_CMD_EVENT_E8:
1330 		icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
1331 
1332 		/* the caller has already remove cmd from queue */
1333 
1334 		icmdp->cmd_next = NULL;
1335 		icmdp->cmd_prev = NULL;
1336 		iscsi_iodone(isp, icmdp);
1337 		break;
1338 	/* All other events are invalid for this state */
1339 	default:
1340 		ASSERT(FALSE);
1341 	}
1342 }
1343 
1344 
1345 /*
1346  * iscsi_cmd_state_str -
1347  *
1348  */
1349 static char *
1350 iscsi_cmd_state_str(iscsi_cmd_state_t state)
1351 {
1352 	switch (state) {
1353 	case ISCSI_CMD_STATE_FREE:
1354 		return ("free");
1355 	case ISCSI_CMD_STATE_PENDING:
1356 		return ("pending");
1357 	case ISCSI_CMD_STATE_ACTIVE:
1358 		return ("active");
1359 	case ISCSI_CMD_STATE_ABORTING:
1360 		return ("aborting");
1361 	case ISCSI_CMD_STATE_IDM_ABORTING:
1362 		return ("idm-aborting");
1363 	case ISCSI_CMD_STATE_COMPLETED:
1364 		return ("completed");
1365 	default:
1366 		return ("unknown");
1367 	}
1368 }
1369 
1370 
1371 /*
1372  * iscsi_cmd_event_str -
1373  *
1374  */
1375 static char *
1376 iscsi_cmd_event_str(iscsi_cmd_event_t event)
1377 {
1378 	switch (event) {
1379 	case ISCSI_CMD_EVENT_E1:
1380 		return ("E1");
1381 	case ISCSI_CMD_EVENT_E2:
1382 		return ("E2");
1383 	case ISCSI_CMD_EVENT_E3:
1384 		return ("E3");
1385 	case ISCSI_CMD_EVENT_E4:
1386 		return ("E4");
1387 	case ISCSI_CMD_EVENT_E6:
1388 		return ("E6");
1389 	case ISCSI_CMD_EVENT_E7:
1390 		return ("E7");
1391 	case ISCSI_CMD_EVENT_E8:
1392 		return ("E8");
1393 	case ISCSI_CMD_EVENT_E9:
1394 		return ("E9");
1395 	case ISCSI_CMD_EVENT_E10:
1396 		return ("E10");
1397 	default:
1398 		return ("unknown");
1399 	}
1400 }
1401 
1402 
1403 /*
1404  * iscsi_cmd_event_str -
1405  *
1406  */
1407 static char *
1408 iscsi_cmd_type_str(iscsi_cmd_type_t type)
1409 {
1410 	switch (type) {
1411 	case ISCSI_CMD_TYPE_SCSI:
1412 		return ("scsi");
1413 	case ISCSI_CMD_TYPE_NOP:
1414 		return ("nop");
1415 	case ISCSI_CMD_TYPE_ABORT:
1416 		return ("abort");
1417 	case ISCSI_CMD_TYPE_RESET:
1418 		return ("reset");
1419 	case ISCSI_CMD_TYPE_LOGOUT:
1420 		return ("logout");
1421 	default:
1422 		return ("unknown");
1423 	}
1424 }
1425