diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2016-01-19 18:23:02 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2016-02-05 18:40:34 -0500 |
commit | 0f4a943168f31d29a1701908931acaba518b131a (patch) | |
tree | 00f4e66a05f284df16775d392ae8e8084cfa4953 | |
parent | ebde1ca5a908b10312db4ecd7553e3ba039319ab (diff) |
target: Fix remote-port TMR ABORT + se_cmd fabric stop
To address the bug where fabric driver level shutdown
of se_cmd occurs at the same time when TMR CMD_T_ABORTED
is happening resulting in a -1 ->cmd_kref, this patch
adds a CMD_T_FABRIC_STOP bit that is used to determine
when TMR + driver I_T nexus shutdown is happening
concurrently.
It changes target_sess_cmd_list_set_waiting() to obtain
se_cmd->cmd_kref + set CMD_T_FABRIC_STOP, and drop local
reference in target_wait_for_sess_cmds() and invoke extra
target_put_sess_cmd() during Task Aborted Status (TAS)
when necessary.
Also, it adds a new target_wait_free_cmd() wrapper around
transport_wait_for_tasks() for the special case within
transport_generic_free_cmd() to set CMD_T_FABRIC_STOP,
and is now aware of CMD_T_ABORTED + CMD_T_TAS status
bits to know when an extra transport_put_cmd() during
TAS is required.
Note transport_generic_free_cmd() is expected to block on
cmd->cmd_wait_comp in order to follow what iscsi-target
expects during iscsi_conn context se_cmd shutdown.
Cc: Quinn Tran <quinn.tran@qlogic.com>
Cc: Himanshu Madhani <himanshu.madhani@qlogic.com>
Cc: Sagi Grimberg <sagig@mellanox.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Hannes Reinecke <hare@suse.de>
Cc: Andy Grover <agrover@redhat.com>
Cc: Mike Christie <mchristi@redhat.com>
Cc: stable@vger.kernel.org # 3.10+
Signed-off-by: Nicholas Bellinger <nab@daterainc.com>
-rw-r--r-- | drivers/target/target_core_tmr.c | 54 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 145 | ||||
-rw-r--r-- | include/target/target_core_base.h | 2 |
3 files changed, 150 insertions, 51 deletions
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 3e0d77a4c7b6..82a663ba9800 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c | |||
@@ -75,16 +75,18 @@ void core_tmr_release_req(struct se_tmr_req *tmr) | |||
75 | kfree(tmr); | 75 | kfree(tmr); |
76 | } | 76 | } |
77 | 77 | ||
78 | static void core_tmr_handle_tas_abort( | 78 | static void core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas) |
79 | struct se_session *tmr_sess, | ||
80 | struct se_cmd *cmd, | ||
81 | int tas) | ||
82 | { | 79 | { |
83 | bool remove = true; | 80 | unsigned long flags; |
81 | bool remove = true, send_tas; | ||
84 | /* | 82 | /* |
85 | * TASK ABORTED status (TAS) bit support | 83 | * TASK ABORTED status (TAS) bit support |
86 | */ | 84 | */ |
87 | if (tmr_sess && tmr_sess != cmd->se_sess && tas) { | 85 | spin_lock_irqsave(&cmd->t_state_lock, flags); |
86 | send_tas = (cmd->transport_state & CMD_T_TAS); | ||
87 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
88 | |||
89 | if (send_tas) { | ||
88 | remove = false; | 90 | remove = false; |
89 | transport_send_task_abort(cmd); | 91 | transport_send_task_abort(cmd); |
90 | } | 92 | } |
@@ -107,7 +109,8 @@ static int target_check_cdb_and_preempt(struct list_head *list, | |||
107 | return 1; | 109 | return 1; |
108 | } | 110 | } |
109 | 111 | ||
110 | static bool __target_check_io_state(struct se_cmd *se_cmd) | 112 | static bool __target_check_io_state(struct se_cmd *se_cmd, |
113 | struct se_session *tmr_sess, int tas) | ||
111 | { | 114 | { |
112 | struct se_session *sess = se_cmd->se_sess; | 115 | struct se_session *sess = se_cmd->se_sess; |
113 | 116 | ||
@@ -115,21 +118,32 @@ static bool __target_check_io_state(struct se_cmd *se_cmd) | |||
115 | WARN_ON_ONCE(!irqs_disabled()); | 118 | WARN_ON_ONCE(!irqs_disabled()); |
116 | /* | 119 | /* |
117 | * If command already reached CMD_T_COMPLETE state within | 120 | * If command already reached CMD_T_COMPLETE state within |
118 | * target_complete_cmd(), this se_cmd has been passed to | 121 | * target_complete_cmd() or CMD_T_FABRIC_STOP due to shutdown, |
119 | * fabric driver and will not be aborted. | 122 | * this se_cmd has been passed to fabric driver and will |
123 | * not be aborted. | ||
120 | * | 124 | * |
121 | * Otherwise, obtain a local se_cmd->cmd_kref now for TMR | 125 | * Otherwise, obtain a local se_cmd->cmd_kref now for TMR |
122 | * ABORT_TASK + LUN_RESET for CMD_T_ABORTED processing as | 126 | * ABORT_TASK + LUN_RESET for CMD_T_ABORTED processing as |
123 | * long as se_cmd->cmd_kref is still active unless zero. | 127 | * long as se_cmd->cmd_kref is still active unless zero. |
124 | */ | 128 | */ |
125 | spin_lock(&se_cmd->t_state_lock); | 129 | spin_lock(&se_cmd->t_state_lock); |
126 | if (se_cmd->transport_state & CMD_T_COMPLETE) { | 130 | if (se_cmd->transport_state & (CMD_T_COMPLETE | CMD_T_FABRIC_STOP)) { |
127 | pr_debug("Attempted to abort io tag: %llu already complete," | 131 | pr_debug("Attempted to abort io tag: %llu already complete or" |
132 | " fabric stop, skipping\n", se_cmd->tag); | ||
133 | spin_unlock(&se_cmd->t_state_lock); | ||
134 | return false; | ||
135 | } | ||
136 | if (sess->sess_tearing_down || se_cmd->cmd_wait_set) { | ||
137 | pr_debug("Attempted to abort io tag: %llu already shutdown," | ||
128 | " skipping\n", se_cmd->tag); | 138 | " skipping\n", se_cmd->tag); |
129 | spin_unlock(&se_cmd->t_state_lock); | 139 | spin_unlock(&se_cmd->t_state_lock); |
130 | return false; | 140 | return false; |
131 | } | 141 | } |
132 | se_cmd->transport_state |= CMD_T_ABORTED; | 142 | se_cmd->transport_state |= CMD_T_ABORTED; |
143 | |||
144 | if ((tmr_sess != se_cmd->se_sess) && tas) | ||
145 | se_cmd->transport_state |= CMD_T_TAS; | ||
146 | |||
133 | spin_unlock(&se_cmd->t_state_lock); | 147 | spin_unlock(&se_cmd->t_state_lock); |
134 | 148 | ||
135 | return kref_get_unless_zero(&se_cmd->cmd_kref); | 149 | return kref_get_unless_zero(&se_cmd->cmd_kref); |
@@ -161,7 +175,7 @@ void core_tmr_abort_task( | |||
161 | printk("ABORT_TASK: Found referenced %s task_tag: %llu\n", | 175 | printk("ABORT_TASK: Found referenced %s task_tag: %llu\n", |
162 | se_cmd->se_tfo->get_fabric_name(), ref_tag); | 176 | se_cmd->se_tfo->get_fabric_name(), ref_tag); |
163 | 177 | ||
164 | if (!__target_check_io_state(se_cmd)) { | 178 | if (!__target_check_io_state(se_cmd, se_sess, 0)) { |
165 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); | 179 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); |
166 | target_put_sess_cmd(se_cmd); | 180 | target_put_sess_cmd(se_cmd); |
167 | goto out; | 181 | goto out; |
@@ -230,7 +244,8 @@ static void core_tmr_drain_tmr_list( | |||
230 | 244 | ||
231 | spin_lock(&sess->sess_cmd_lock); | 245 | spin_lock(&sess->sess_cmd_lock); |
232 | spin_lock(&cmd->t_state_lock); | 246 | spin_lock(&cmd->t_state_lock); |
233 | if (!(cmd->transport_state & CMD_T_ACTIVE)) { | 247 | if (!(cmd->transport_state & CMD_T_ACTIVE) || |
248 | (cmd->transport_state & CMD_T_FABRIC_STOP)) { | ||
234 | spin_unlock(&cmd->t_state_lock); | 249 | spin_unlock(&cmd->t_state_lock); |
235 | spin_unlock(&sess->sess_cmd_lock); | 250 | spin_unlock(&sess->sess_cmd_lock); |
236 | continue; | 251 | continue; |
@@ -240,15 +255,22 @@ static void core_tmr_drain_tmr_list( | |||
240 | spin_unlock(&sess->sess_cmd_lock); | 255 | spin_unlock(&sess->sess_cmd_lock); |
241 | continue; | 256 | continue; |
242 | } | 257 | } |
258 | if (sess->sess_tearing_down || cmd->cmd_wait_set) { | ||
259 | spin_unlock(&cmd->t_state_lock); | ||
260 | spin_unlock(&sess->sess_cmd_lock); | ||
261 | continue; | ||
262 | } | ||
243 | cmd->transport_state |= CMD_T_ABORTED; | 263 | cmd->transport_state |= CMD_T_ABORTED; |
244 | spin_unlock(&cmd->t_state_lock); | 264 | spin_unlock(&cmd->t_state_lock); |
245 | 265 | ||
246 | rc = kref_get_unless_zero(&cmd->cmd_kref); | 266 | rc = kref_get_unless_zero(&cmd->cmd_kref); |
247 | spin_unlock(&sess->sess_cmd_lock); | ||
248 | if (!rc) { | 267 | if (!rc) { |
249 | printk("LUN_RESET TMR: non-zero kref_get_unless_zero\n"); | 268 | printk("LUN_RESET TMR: non-zero kref_get_unless_zero\n"); |
269 | spin_unlock(&sess->sess_cmd_lock); | ||
250 | continue; | 270 | continue; |
251 | } | 271 | } |
272 | spin_unlock(&sess->sess_cmd_lock); | ||
273 | |||
252 | list_move_tail(&tmr_p->tmr_list, &drain_tmr_list); | 274 | list_move_tail(&tmr_p->tmr_list, &drain_tmr_list); |
253 | } | 275 | } |
254 | spin_unlock_irqrestore(&dev->se_tmr_lock, flags); | 276 | spin_unlock_irqrestore(&dev->se_tmr_lock, flags); |
@@ -325,7 +347,7 @@ static void core_tmr_drain_state_list( | |||
325 | continue; | 347 | continue; |
326 | 348 | ||
327 | spin_lock(&sess->sess_cmd_lock); | 349 | spin_lock(&sess->sess_cmd_lock); |
328 | rc = __target_check_io_state(cmd); | 350 | rc = __target_check_io_state(cmd, tmr_sess, tas); |
329 | spin_unlock(&sess->sess_cmd_lock); | 351 | spin_unlock(&sess->sess_cmd_lock); |
330 | if (!rc) | 352 | if (!rc) |
331 | continue; | 353 | continue; |
@@ -364,7 +386,7 @@ static void core_tmr_drain_state_list( | |||
364 | cancel_work_sync(&cmd->work); | 386 | cancel_work_sync(&cmd->work); |
365 | transport_wait_for_tasks(cmd); | 387 | transport_wait_for_tasks(cmd); |
366 | 388 | ||
367 | core_tmr_handle_tas_abort(tmr_sess, cmd, tas); | 389 | core_tmr_handle_tas_abort(cmd, tas); |
368 | target_put_sess_cmd(cmd); | 390 | target_put_sess_cmd(cmd); |
369 | } | 391 | } |
370 | } | 392 | } |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 94e372af9e28..3441b159e306 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -2431,18 +2431,33 @@ static void transport_write_pending_qf(struct se_cmd *cmd) | |||
2431 | } | 2431 | } |
2432 | } | 2432 | } |
2433 | 2433 | ||
2434 | static bool | ||
2435 | __transport_wait_for_tasks(struct se_cmd *, bool, bool *, bool *, | ||
2436 | unsigned long *flags); | ||
2437 | |||
2438 | static void target_wait_free_cmd(struct se_cmd *cmd, bool *aborted, bool *tas) | ||
2439 | { | ||
2440 | unsigned long flags; | ||
2441 | |||
2442 | spin_lock_irqsave(&cmd->t_state_lock, flags); | ||
2443 | __transport_wait_for_tasks(cmd, true, aborted, tas, &flags); | ||
2444 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
2445 | } | ||
2446 | |||
2434 | int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) | 2447 | int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) |
2435 | { | 2448 | { |
2436 | int ret = 0; | 2449 | int ret = 0; |
2450 | bool aborted = false, tas = false; | ||
2437 | 2451 | ||
2438 | if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) { | 2452 | if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) { |
2439 | if (wait_for_tasks && (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) | 2453 | if (wait_for_tasks && (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) |
2440 | transport_wait_for_tasks(cmd); | 2454 | target_wait_free_cmd(cmd, &aborted, &tas); |
2441 | 2455 | ||
2442 | ret = transport_put_cmd(cmd); | 2456 | if (!aborted || tas) |
2457 | ret = transport_put_cmd(cmd); | ||
2443 | } else { | 2458 | } else { |
2444 | if (wait_for_tasks) | 2459 | if (wait_for_tasks) |
2445 | transport_wait_for_tasks(cmd); | 2460 | target_wait_free_cmd(cmd, &aborted, &tas); |
2446 | /* | 2461 | /* |
2447 | * Handle WRITE failure case where transport_generic_new_cmd() | 2462 | * Handle WRITE failure case where transport_generic_new_cmd() |
2448 | * has already added se_cmd to state_list, but fabric has | 2463 | * has already added se_cmd to state_list, but fabric has |
@@ -2454,7 +2469,20 @@ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) | |||
2454 | if (cmd->se_lun) | 2469 | if (cmd->se_lun) |
2455 | transport_lun_remove_cmd(cmd); | 2470 | transport_lun_remove_cmd(cmd); |
2456 | 2471 | ||
2457 | ret = transport_put_cmd(cmd); | 2472 | if (!aborted || tas) |
2473 | ret = transport_put_cmd(cmd); | ||
2474 | } | ||
2475 | /* | ||
2476 | * If the task has been internally aborted due to TMR ABORT_TASK | ||
2477 | * or LUN_RESET, target_core_tmr.c is responsible for performing | ||
2478 | * the remaining calls to target_put_sess_cmd(), and not the | ||
2479 | * callers of this function. | ||
2480 | */ | ||
2481 | if (aborted) { | ||
2482 | pr_debug("Detected CMD_T_ABORTED for ITT: %llu\n", cmd->tag); | ||
2483 | wait_for_completion(&cmd->cmd_wait_comp); | ||
2484 | cmd->se_tfo->release_cmd(cmd); | ||
2485 | ret = 1; | ||
2458 | } | 2486 | } |
2459 | return ret; | 2487 | return ret; |
2460 | } | 2488 | } |
@@ -2509,6 +2537,7 @@ static void target_release_cmd_kref(struct kref *kref) | |||
2509 | struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref); | 2537 | struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref); |
2510 | struct se_session *se_sess = se_cmd->se_sess; | 2538 | struct se_session *se_sess = se_cmd->se_sess; |
2511 | unsigned long flags; | 2539 | unsigned long flags; |
2540 | bool fabric_stop; | ||
2512 | 2541 | ||
2513 | spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); | 2542 | spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); |
2514 | if (list_empty(&se_cmd->se_cmd_list)) { | 2543 | if (list_empty(&se_cmd->se_cmd_list)) { |
@@ -2517,13 +2546,19 @@ static void target_release_cmd_kref(struct kref *kref) | |||
2517 | se_cmd->se_tfo->release_cmd(se_cmd); | 2546 | se_cmd->se_tfo->release_cmd(se_cmd); |
2518 | return; | 2547 | return; |
2519 | } | 2548 | } |
2520 | if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) { | 2549 | |
2550 | spin_lock(&se_cmd->t_state_lock); | ||
2551 | fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP); | ||
2552 | spin_unlock(&se_cmd->t_state_lock); | ||
2553 | |||
2554 | if (se_cmd->cmd_wait_set || fabric_stop) { | ||
2555 | list_del_init(&se_cmd->se_cmd_list); | ||
2521 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); | 2556 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); |
2522 | target_free_cmd_mem(se_cmd); | 2557 | target_free_cmd_mem(se_cmd); |
2523 | complete(&se_cmd->cmd_wait_comp); | 2558 | complete(&se_cmd->cmd_wait_comp); |
2524 | return; | 2559 | return; |
2525 | } | 2560 | } |
2526 | list_del(&se_cmd->se_cmd_list); | 2561 | list_del_init(&se_cmd->se_cmd_list); |
2527 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); | 2562 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); |
2528 | 2563 | ||
2529 | target_free_cmd_mem(se_cmd); | 2564 | target_free_cmd_mem(se_cmd); |
@@ -2555,6 +2590,7 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess) | |||
2555 | { | 2590 | { |
2556 | struct se_cmd *se_cmd; | 2591 | struct se_cmd *se_cmd; |
2557 | unsigned long flags; | 2592 | unsigned long flags; |
2593 | int rc; | ||
2558 | 2594 | ||
2559 | spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); | 2595 | spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); |
2560 | if (se_sess->sess_tearing_down) { | 2596 | if (se_sess->sess_tearing_down) { |
@@ -2564,8 +2600,15 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess) | |||
2564 | se_sess->sess_tearing_down = 1; | 2600 | se_sess->sess_tearing_down = 1; |
2565 | list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list); | 2601 | list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list); |
2566 | 2602 | ||
2567 | list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) | 2603 | list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) { |
2568 | se_cmd->cmd_wait_set = 1; | 2604 | rc = kref_get_unless_zero(&se_cmd->cmd_kref); |
2605 | if (rc) { | ||
2606 | se_cmd->cmd_wait_set = 1; | ||
2607 | spin_lock(&se_cmd->t_state_lock); | ||
2608 | se_cmd->transport_state |= CMD_T_FABRIC_STOP; | ||
2609 | spin_unlock(&se_cmd->t_state_lock); | ||
2610 | } | ||
2611 | } | ||
2569 | 2612 | ||
2570 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); | 2613 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); |
2571 | } | 2614 | } |
@@ -2578,15 +2621,25 @@ void target_wait_for_sess_cmds(struct se_session *se_sess) | |||
2578 | { | 2621 | { |
2579 | struct se_cmd *se_cmd, *tmp_cmd; | 2622 | struct se_cmd *se_cmd, *tmp_cmd; |
2580 | unsigned long flags; | 2623 | unsigned long flags; |
2624 | bool tas; | ||
2581 | 2625 | ||
2582 | list_for_each_entry_safe(se_cmd, tmp_cmd, | 2626 | list_for_each_entry_safe(se_cmd, tmp_cmd, |
2583 | &se_sess->sess_wait_list, se_cmd_list) { | 2627 | &se_sess->sess_wait_list, se_cmd_list) { |
2584 | list_del(&se_cmd->se_cmd_list); | 2628 | list_del_init(&se_cmd->se_cmd_list); |
2585 | 2629 | ||
2586 | pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:" | 2630 | pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:" |
2587 | " %d\n", se_cmd, se_cmd->t_state, | 2631 | " %d\n", se_cmd, se_cmd->t_state, |
2588 | se_cmd->se_tfo->get_cmd_state(se_cmd)); | 2632 | se_cmd->se_tfo->get_cmd_state(se_cmd)); |
2589 | 2633 | ||
2634 | spin_lock_irqsave(&se_cmd->t_state_lock, flags); | ||
2635 | tas = (se_cmd->transport_state & CMD_T_TAS); | ||
2636 | spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); | ||
2637 | |||
2638 | if (!target_put_sess_cmd(se_cmd)) { | ||
2639 | if (tas) | ||
2640 | target_put_sess_cmd(se_cmd); | ||
2641 | } | ||
2642 | |||
2590 | wait_for_completion(&se_cmd->cmd_wait_comp); | 2643 | wait_for_completion(&se_cmd->cmd_wait_comp); |
2591 | pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d" | 2644 | pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d" |
2592 | " fabric state: %d\n", se_cmd, se_cmd->t_state, | 2645 | " fabric state: %d\n", se_cmd, se_cmd->t_state, |
@@ -2608,53 +2661,75 @@ void transport_clear_lun_ref(struct se_lun *lun) | |||
2608 | wait_for_completion(&lun->lun_ref_comp); | 2661 | wait_for_completion(&lun->lun_ref_comp); |
2609 | } | 2662 | } |
2610 | 2663 | ||
2611 | /** | 2664 | static bool |
2612 | * transport_wait_for_tasks - wait for completion to occur | 2665 | __transport_wait_for_tasks(struct se_cmd *cmd, bool fabric_stop, |
2613 | * @cmd: command to wait | 2666 | bool *aborted, bool *tas, unsigned long *flags) |
2614 | * | 2667 | __releases(&cmd->t_state_lock) |
2615 | * Called from frontend fabric context to wait for storage engine | 2668 | __acquires(&cmd->t_state_lock) |
2616 | * to pause and/or release frontend generated struct se_cmd. | ||
2617 | */ | ||
2618 | bool transport_wait_for_tasks(struct se_cmd *cmd) | ||
2619 | { | 2669 | { |
2620 | unsigned long flags; | ||
2621 | 2670 | ||
2622 | spin_lock_irqsave(&cmd->t_state_lock, flags); | 2671 | assert_spin_locked(&cmd->t_state_lock); |
2672 | WARN_ON_ONCE(!irqs_disabled()); | ||
2673 | |||
2674 | if (fabric_stop) | ||
2675 | cmd->transport_state |= CMD_T_FABRIC_STOP; | ||
2676 | |||
2677 | if (cmd->transport_state & CMD_T_ABORTED) | ||
2678 | *aborted = true; | ||
2679 | |||
2680 | if (cmd->transport_state & CMD_T_TAS) | ||
2681 | *tas = true; | ||
2682 | |||
2623 | if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && | 2683 | if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && |
2624 | !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) { | 2684 | !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) |
2625 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
2626 | return false; | 2685 | return false; |
2627 | } | ||
2628 | 2686 | ||
2629 | if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) && | 2687 | if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) && |
2630 | !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) { | 2688 | !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) |
2631 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
2632 | return false; | 2689 | return false; |
2633 | } | ||
2634 | 2690 | ||
2635 | if (!(cmd->transport_state & CMD_T_ACTIVE)) { | 2691 | if (!(cmd->transport_state & CMD_T_ACTIVE)) |
2636 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | 2692 | return false; |
2693 | |||
2694 | if (fabric_stop && *aborted) | ||
2637 | return false; | 2695 | return false; |
2638 | } | ||
2639 | 2696 | ||
2640 | cmd->transport_state |= CMD_T_STOP; | 2697 | cmd->transport_state |= CMD_T_STOP; |
2641 | 2698 | ||
2642 | pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d, t_state: %d, CMD_T_STOP\n", | 2699 | pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d," |
2643 | cmd, cmd->tag, cmd->se_tfo->get_cmd_state(cmd), cmd->t_state); | 2700 | " t_state: %d, CMD_T_STOP\n", cmd, cmd->tag, |
2701 | cmd->se_tfo->get_cmd_state(cmd), cmd->t_state); | ||
2644 | 2702 | ||
2645 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | 2703 | spin_unlock_irqrestore(&cmd->t_state_lock, *flags); |
2646 | 2704 | ||
2647 | wait_for_completion(&cmd->t_transport_stop_comp); | 2705 | wait_for_completion(&cmd->t_transport_stop_comp); |
2648 | 2706 | ||
2649 | spin_lock_irqsave(&cmd->t_state_lock, flags); | 2707 | spin_lock_irqsave(&cmd->t_state_lock, *flags); |
2650 | cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP); | 2708 | cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP); |
2651 | 2709 | ||
2652 | pr_debug("wait_for_tasks: Stopped wait_for_completion(&cmd->t_transport_stop_comp) for ITT: 0x%08llx\n", | 2710 | pr_debug("wait_for_tasks: Stopped wait_for_completion(&cmd->" |
2653 | cmd->tag); | 2711 | "t_transport_stop_comp) for ITT: 0x%08llx\n", cmd->tag); |
2654 | 2712 | ||
2713 | return true; | ||
2714 | } | ||
2715 | |||
2716 | /** | ||
2717 | * transport_wait_for_tasks - wait for completion to occur | ||
2718 | * @cmd: command to wait | ||
2719 | * | ||
2720 | * Called from frontend fabric context to wait for storage engine | ||
2721 | * to pause and/or release frontend generated struct se_cmd. | ||
2722 | */ | ||
2723 | bool transport_wait_for_tasks(struct se_cmd *cmd) | ||
2724 | { | ||
2725 | unsigned long flags; | ||
2726 | bool ret, aborted = false, tas = false; | ||
2727 | |||
2728 | spin_lock_irqsave(&cmd->t_state_lock, flags); | ||
2729 | ret = __transport_wait_for_tasks(cmd, false, &aborted, &tas, &flags); | ||
2655 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | 2730 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); |
2656 | 2731 | ||
2657 | return true; | 2732 | return ret; |
2658 | } | 2733 | } |
2659 | EXPORT_SYMBOL(transport_wait_for_tasks); | 2734 | EXPORT_SYMBOL(transport_wait_for_tasks); |
2660 | 2735 | ||
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 1a76726c45a2..1579539e5669 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h | |||
@@ -493,6 +493,8 @@ struct se_cmd { | |||
493 | #define CMD_T_DEV_ACTIVE (1 << 7) | 493 | #define CMD_T_DEV_ACTIVE (1 << 7) |
494 | #define CMD_T_REQUEST_STOP (1 << 8) | 494 | #define CMD_T_REQUEST_STOP (1 << 8) |
495 | #define CMD_T_BUSY (1 << 9) | 495 | #define CMD_T_BUSY (1 << 9) |
496 | #define CMD_T_TAS (1 << 10) | ||
497 | #define CMD_T_FABRIC_STOP (1 << 11) | ||
496 | spinlock_t t_state_lock; | 498 | spinlock_t t_state_lock; |
497 | struct kref cmd_kref; | 499 | struct kref cmd_kref; |
498 | struct completion t_transport_stop_comp; | 500 | struct completion t_transport_stop_comp; |