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