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