diff options
-rw-r--r-- | drivers/target/target_core_transport.c | 74 |
1 files changed, 26 insertions, 48 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index dd9c87f62d76..db139133f708 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -66,7 +66,6 @@ struct kmem_cache *t10_alua_lu_gp_mem_cache; struct kmem_cache *t10_alua_tg_pt_gp_cache; struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; -static int transport_generic_write_pending(struct se_cmd *); static int transport_processing_thread(void *param); static void transport_complete_task_attr(struct se_cmd *cmd); static void transport_handle_queue_full(struct se_cmd *cmd, @@ -2487,23 +2486,39 @@ int transport_generic_new_cmd(struct se_cmd *cmd) atomic_inc(&cmd->t_fe_count); /* - * For WRITEs, let the fabric know its buffer is ready. - * - * The command will be added to the execution queue after its write - * data has arrived. - * - * Everything else but a WRITE, add the command to the execution queue. + * If this command is not a write we can execute it right here, + * for write buffers we need to notify the fabric driver first + * and let it call back once the write buffers are ready. */ target_add_to_state_list(cmd); - if (cmd->data_direction == DMA_TO_DEVICE) - return transport_generic_write_pending(cmd); - target_execute_cmd(cmd); - return 0; + if (cmd->data_direction != DMA_TO_DEVICE) { + target_execute_cmd(cmd); + return 0; + } + + spin_lock_irq(&cmd->t_state_lock); + cmd->t_state = TRANSPORT_WRITE_PENDING; + spin_unlock_irq(&cmd->t_state_lock); + + transport_cmd_check_stop(cmd, false); + + ret = cmd->se_tfo->write_pending(cmd); + if (ret == -EAGAIN || ret == -ENOMEM) + goto queue_full; + + if (ret < 0) + return ret; + return 1; out_fail: cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; return -EINVAL; +queue_full: + pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd); + cmd->t_state = TRANSPORT_COMPLETE_QF_WP; + transport_handle_queue_full(cmd, cmd->se_dev); + return 0; } EXPORT_SYMBOL(transport_generic_new_cmd); @@ -2519,43 +2534,6 @@ static void transport_write_pending_qf(struct se_cmd *cmd) } } -static int transport_generic_write_pending(struct se_cmd *cmd) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&cmd->t_state_lock, flags); - cmd->t_state = TRANSPORT_WRITE_PENDING; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - - /* - * Clear the se_cmd for WRITE_PENDING status in order to set - * CMD_T_ACTIVE so that transport_generic_handle_data can be called - * from HW target mode interrupt code. This is safe to be called - * with remove_from_lists false before the cmd->se_tfo->write_pending - * because the se_cmd->se_lun pointer is not being cleared. - */ - transport_cmd_check_stop(cmd, false); - - /* - * Call the fabric write_pending function here to let the - * frontend know that WRITE buffers are ready. - */ - ret = cmd->se_tfo->write_pending(cmd); - if (ret == -EAGAIN || ret == -ENOMEM) - goto queue_full; - else if (ret < 0) - return ret; - - return 1; - -queue_full: - pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd); - cmd->t_state = TRANSPORT_COMPLETE_QF_WP; - transport_handle_queue_full(cmd, cmd->se_dev); - return 0; -} - void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) { if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) { |