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