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