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