From 7d680f3b74dd6f0f57569eeeee8c257790ceaa96 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 21 Dec 2011 14:13:47 -0500 Subject: target: replace various cmd flags with a transport state Replace various atomic_ts used as flags in struct se_cmd with a single transport_state bitmap that requires t_state_lock to be held for modifications. In the target core that assumption generally is true, but some recently added code in the SRP target had to grow new lock calls. I can't say I like the way how it messes with the command state directly, but let's leave that for later. (Re-add missing ib_srpt.c changes that nab dropped..) Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 130 ++++++++++++++++----------------- 1 file changed, 61 insertions(+), 69 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 58cea07b12f..f704123752c 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -437,7 +437,7 @@ static void transport_all_task_dev_remove_state(struct se_cmd *cmd) /* transport_cmd_check_stop(): * - * 'transport_off = 1' determines if t_transport_active should be cleared. + * 'transport_off = 1' determines if CMD_T_ACTIVE should be cleared. * 'transport_off = 2' determines if task_dev_state should be removed. * * A non-zero u8 t_state sets cmd->t_state. @@ -455,12 +455,11 @@ static int transport_cmd_check_stop( * Determine if IOCTL context caller in requesting the stopping of this * command for LUN shutdown purposes. */ - if (atomic_read(&cmd->transport_lun_stop)) { - pr_debug("%s:%d atomic_read(&cmd->transport_lun_stop)" - " == TRUE for ITT: 0x%08x\n", __func__, __LINE__, - cmd->se_tfo->get_task_tag(cmd)); + if (cmd->transport_state & CMD_T_LUN_STOP) { + pr_debug("%s:%d CMD_T_LUN_STOP for ITT: 0x%08x\n", + __func__, __LINE__, cmd->se_tfo->get_task_tag(cmd)); - atomic_set(&cmd->t_transport_active, 0); + cmd->transport_state &= ~CMD_T_ACTIVE; if (transport_off == 2) transport_all_task_dev_remove_state(cmd); spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -472,9 +471,9 @@ static int transport_cmd_check_stop( * Determine if frontend context caller is requesting the stopping of * this command for frontend exceptions. */ - if (atomic_read(&cmd->t_transport_stop)) { - pr_debug("%s:%d atomic_read(&cmd->t_transport_stop) ==" - " TRUE for ITT: 0x%08x\n", __func__, __LINE__, + if (cmd->transport_state & CMD_T_STOP) { + pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08x\n", + __func__, __LINE__, cmd->se_tfo->get_task_tag(cmd)); if (transport_off == 2) @@ -492,7 +491,7 @@ static int transport_cmd_check_stop( return 1; } if (transport_off) { - atomic_set(&cmd->t_transport_active, 0); + cmd->transport_state &= ~CMD_T_ACTIVE; if (transport_off == 2) { transport_all_task_dev_remove_state(cmd); /* @@ -540,16 +539,12 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd) return; spin_lock_irqsave(&cmd->t_state_lock, flags); - if (!atomic_read(&cmd->transport_dev_active)) { - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - goto check_lun; + if (cmd->transport_state & CMD_T_DEV_ACTIVE) { + cmd->transport_state &= ~CMD_T_DEV_ACTIVE; + transport_all_task_dev_remove_state(cmd); } - atomic_set(&cmd->transport_dev_active, 0); - transport_all_task_dev_remove_state(cmd); spin_unlock_irqrestore(&cmd->t_state_lock, flags); - -check_lun: spin_lock_irqsave(&lun->lun_cmd_lock, flags); if (atomic_read(&cmd->transport_lun_active)) { list_del(&cmd->se_lun_node); @@ -585,7 +580,7 @@ static void transport_add_cmd_to_queue(struct se_cmd *cmd, int t_state, if (t_state) { spin_lock_irqsave(&cmd->t_state_lock, flags); cmd->t_state = t_state; - atomic_set(&cmd->t_transport_active, 1); + cmd->transport_state |= CMD_T_ACTIVE; spin_unlock_irqrestore(&cmd->t_state_lock, flags); } @@ -601,7 +596,7 @@ static void transport_add_cmd_to_queue(struct se_cmd *cmd, int t_state, list_add(&cmd->se_queue_node, &qobj->qobj_list); else list_add_tail(&cmd->se_queue_node, &qobj->qobj_list); - atomic_set(&cmd->t_transport_queue_active, 1); + cmd->transport_state |= CMD_T_QUEUED; spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); wake_up_interruptible(&qobj->thread_wq); @@ -620,8 +615,7 @@ transport_get_cmd_from_queue(struct se_queue_obj *qobj) } cmd = list_first_entry(&qobj->qobj_list, struct se_cmd, se_queue_node); - atomic_set(&cmd->t_transport_queue_active, 0); - + cmd->transport_state &= ~CMD_T_QUEUED; list_del_init(&cmd->se_queue_node); atomic_dec(&qobj->queue_cnt); spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); @@ -635,20 +629,14 @@ static void transport_remove_cmd_from_queue(struct se_cmd *cmd) unsigned long flags; spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - if (!atomic_read(&cmd->t_transport_queue_active)) { + if (!(cmd->transport_state & CMD_T_QUEUED)) { spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); return; } - atomic_set(&cmd->t_transport_queue_active, 0); + cmd->transport_state &= ~CMD_T_QUEUED; atomic_dec(&qobj->queue_cnt); list_del_init(&cmd->se_queue_node); spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - - if (atomic_read(&cmd->t_transport_queue_active)) { - pr_err("ITT: 0x%08x t_transport_queue_active: %d\n", - cmd->se_tfo->get_task_tag(cmd), - atomic_read(&cmd->t_transport_queue_active)); - } } /* @@ -719,7 +707,7 @@ void transport_complete_task(struct se_task *task, int success) } if (!success) - cmd->t_tasks_failed = 1; + cmd->transport_state |= CMD_T_FAILED; /* * Decrement the outstanding t_task_cdbs_left count. The last @@ -731,16 +719,16 @@ void transport_complete_task(struct se_task *task, int success) return; } - if (cmd->t_tasks_failed) { + if (cmd->transport_state & CMD_T_FAILED) { cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; INIT_WORK(&cmd->work, target_complete_failure_work); } else { - atomic_set(&cmd->t_transport_complete, 1); + cmd->transport_state |= CMD_T_COMPLETE; INIT_WORK(&cmd->work, target_complete_ok_work); } cmd->t_state = TRANSPORT_COMPLETE; - atomic_set(&cmd->t_transport_active, 1); + cmd->transport_state |= CMD_T_ACTIVE; spin_unlock_irqrestore(&cmd->t_state_lock, flags); queue_work(target_completion_wq, &cmd->work); @@ -1488,7 +1476,7 @@ void transport_init_se_cmd( init_completion(&cmd->t_transport_stop_comp); init_completion(&cmd->cmd_wait_comp); spin_lock_init(&cmd->t_state_lock); - atomic_set(&cmd->transport_dev_active, 1); + cmd->transport_state = CMD_T_DEV_ACTIVE; cmd->se_tfo = tfo; cmd->se_sess = se_sess; @@ -1618,7 +1606,7 @@ int transport_handle_cdb_direct( return -EINVAL; } /* - * Set TRANSPORT_NEW_CMD state and cmd->t_transport_active=1 following + * Set TRANSPORT_NEW_CMD state and CMD_T_ACTIVE following * transport_generic_handle_cdb*() -> transport_add_cmd_to_queue() * in existing usage to ensure that outstanding descriptors are handled * correctly during shutdown via transport_wait_for_tasks() @@ -1627,7 +1615,8 @@ int transport_handle_cdb_direct( * this to be called for initial descriptor submission. */ cmd->t_state = TRANSPORT_NEW_CMD; - atomic_set(&cmd->t_transport_active, 1); + cmd->transport_state |= CMD_T_ACTIVE; + /* * transport_generic_new_cmd() is already handling QUEUE_FULL, * so follow TRANSPORT_NEW_CMD processing thread context usage @@ -1859,14 +1848,14 @@ static void transport_generic_request_failure(struct se_cmd *cmd) cmd->t_state, cmd->scsi_sense_reason); pr_debug("-----[ t_tasks: %d t_task_cdbs_left: %d" " t_task_cdbs_sent: %d t_task_cdbs_ex_left: %d --" - " t_transport_active: %d t_transport_stop: %d" - " t_transport_sent: %d\n", cmd->t_task_list_num, + " CMD_T_ACTIVE: %d CMD_T_STOP: %d CMD_T_SENT: %d\n", + cmd->t_task_list_num, atomic_read(&cmd->t_task_cdbs_left), atomic_read(&cmd->t_task_cdbs_sent), atomic_read(&cmd->t_task_cdbs_ex_left), - atomic_read(&cmd->t_transport_active), - atomic_read(&cmd->t_transport_stop), - atomic_read(&cmd->t_transport_sent)); + (cmd->transport_state & CMD_T_ACTIVE) != 0, + (cmd->transport_state & CMD_T_STOP) != 0, + (cmd->transport_state & CMD_T_SENT) != 0); /* * For SAM Task Attribute emulation for failed struct se_cmd @@ -2125,7 +2114,7 @@ check_depth: if (atomic_read(&cmd->t_task_cdbs_sent) == cmd->t_task_list_num) - atomic_set(&cmd->t_transport_sent, 1); + cmd->transport_state |= CMD_T_SENT; spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -2136,8 +2125,9 @@ check_depth: if (error != 0) { spin_lock_irqsave(&cmd->t_state_lock, flags); task->task_flags &= ~TF_ACTIVE; + cmd->transport_state &= ~CMD_T_SENT; spin_unlock_irqrestore(&cmd->t_state_lock, flags); - atomic_set(&cmd->t_transport_sent, 0); + transport_stop_tasks_for_cmd(cmd); transport_generic_request_failure(cmd); } @@ -3420,8 +3410,8 @@ static void transport_put_cmd(struct se_cmd *cmd) goto out_busy; } - if (atomic_read(&cmd->transport_dev_active)) { - atomic_set(&cmd->transport_dev_active, 0); + if (cmd->transport_state & CMD_T_DEV_ACTIVE) { + cmd->transport_state &= ~CMD_T_DEV_ACTIVE; transport_all_task_dev_remove_state(cmd); free_tasks = 1; } @@ -3859,8 +3849,10 @@ int transport_generic_new_cmd(struct se_cmd *cmd) if (task_cdbs < 0) goto out_fail; else if (!task_cdbs && (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)) { + spin_lock_irq(&cmd->t_state_lock); cmd->t_state = TRANSPORT_COMPLETE; - atomic_set(&cmd->t_transport_active, 1); + cmd->transport_state |= CMD_T_ACTIVE; + spin_unlock_irq(&cmd->t_state_lock); if (cmd->t_task_cdb[0] == REQUEST_SENSE) { u8 ua_asc = 0, ua_ascq = 0; @@ -3941,9 +3933,9 @@ static int transport_generic_write_pending(struct se_cmd *cmd) /* * Clear the se_cmd for WRITE_PENDING status in order to set - * cmd->t_transport_active=0 so that transport_generic_handle_data - * can be called from HW target mode interrupt code. This is safe - * to be called with transport_off=1 before the cmd->se_tfo->write_pending + * 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 transport_off=1 before the cmd->se_tfo->write_pending * because the se_cmd->se_lun pointer is not being cleared. */ transport_cmd_check_stop(cmd, 1, 0); @@ -4129,15 +4121,16 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun) * be stopped, we can safely ignore this struct se_cmd. */ spin_lock_irqsave(&cmd->t_state_lock, flags); - if (atomic_read(&cmd->t_transport_stop)) { - atomic_set(&cmd->transport_lun_stop, 0); - pr_debug("ConfigFS ITT[0x%08x] - t_transport_stop ==" - " TRUE, skipping\n", cmd->se_tfo->get_task_tag(cmd)); + if (cmd->transport_state & CMD_T_STOP) { + cmd->transport_state &= ~CMD_T_LUN_STOP; + + pr_debug("ConfigFS ITT[0x%08x] - CMD_T_STOP, skipping\n", + cmd->se_tfo->get_task_tag(cmd)); spin_unlock_irqrestore(&cmd->t_state_lock, flags); transport_cmd_check_stop(cmd, 1, 0); return -EPERM; } - atomic_set(&cmd->transport_lun_fe_stop, 1); + cmd->transport_state |= CMD_T_LUN_FE_STOP; spin_unlock_irqrestore(&cmd->t_state_lock, flags); wake_up_interruptible(&cmd->se_dev->dev_queue_obj.thread_wq); @@ -4183,7 +4176,7 @@ static void __transport_clear_lun_from_sessions(struct se_lun *lun) "_lun_stop for ITT: 0x%08x\n", cmd->se_lun->unpacked_lun, cmd->se_tfo->get_task_tag(cmd)); - atomic_set(&cmd->transport_lun_stop, 1); + cmd->transport_state |= CMD_T_LUN_STOP; spin_unlock(&cmd->t_state_lock); spin_unlock_irqrestore(&lun->lun_cmd_lock, lun_flags); @@ -4213,11 +4206,11 @@ static void __transport_clear_lun_from_sessions(struct se_lun *lun) cmd->se_tfo->get_task_tag(cmd)); spin_lock_irqsave(&cmd->t_state_lock, cmd_flags); - if (!atomic_read(&cmd->transport_dev_active)) { + if (!(cmd->transport_state & CMD_T_DEV_ACTIVE)) { spin_unlock_irqrestore(&cmd->t_state_lock, cmd_flags); goto check_cond; } - atomic_set(&cmd->transport_dev_active, 0); + cmd->transport_state &= ~CMD_T_DEV_ACTIVE; transport_all_task_dev_remove_state(cmd); spin_unlock_irqrestore(&cmd->t_state_lock, cmd_flags); @@ -4237,7 +4230,7 @@ check_cond: * finished accessing it. */ spin_lock_irqsave(&cmd->t_state_lock, cmd_flags); - if (atomic_read(&cmd->transport_lun_fe_stop)) { + if (cmd->transport_state & CMD_T_LUN_FE_STOP) { pr_debug("SE_LUN[%d] - Detected FE stop for" " struct se_cmd: %p ITT: 0x%08x\n", lun->unpacked_lun, @@ -4315,8 +4308,7 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) * transport_clear_lun_from_sessions() once the ConfigFS context caller * has completed its operation on the struct se_cmd. */ - if (atomic_read(&cmd->transport_lun_stop)) { - + if (cmd->transport_state & CMD_T_LUN_STOP) { pr_debug("wait_for_tasks: Stopping" " wait_for_completion(&cmd->t_tasktransport_lun_fe" "_stop_comp); for ITT: 0x%08x\n", @@ -4344,18 +4336,19 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) "stop_comp); for ITT: 0x%08x\n", cmd->se_tfo->get_task_tag(cmd)); - atomic_set(&cmd->transport_lun_stop, 0); + cmd->transport_state &= ~CMD_T_LUN_STOP; } - if (!atomic_read(&cmd->t_transport_active) || - atomic_read(&cmd->t_transport_aborted)) { + + if (!(cmd->transport_state & CMD_T_ACTIVE) || + (cmd->transport_state & CMD_T_ABORTED)) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); return false; } - atomic_set(&cmd->t_transport_stop, 1); + cmd->transport_state |= CMD_T_STOP; pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08x" - " i_state: %d, t_state: %d, t_transport_stop = TRUE\n", + " i_state: %d, t_state: %d, CMD_T_STOP\n", cmd, cmd->se_tfo->get_task_tag(cmd), cmd->se_tfo->get_cmd_state(cmd), cmd->t_state); @@ -4366,8 +4359,7 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) wait_for_completion(&cmd->t_transport_stop_comp); spin_lock_irqsave(&cmd->t_state_lock, flags); - atomic_set(&cmd->t_transport_active, 0); - atomic_set(&cmd->t_transport_stop, 0); + cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP); pr_debug("wait_for_tasks: Stopped wait_for_compltion(" "&cmd->t_transport_stop_comp) for ITT: 0x%08x\n", @@ -4596,7 +4588,7 @@ int transport_check_aborted_status(struct se_cmd *cmd, int send_status) { int ret = 0; - if (atomic_read(&cmd->t_transport_aborted) != 0) { + if (cmd->transport_state & CMD_T_ABORTED) { if (!send_status || (cmd->se_cmd_flags & SCF_SENT_DELAYED_TAS)) return 1; @@ -4633,7 +4625,7 @@ void transport_send_task_abort(struct se_cmd *cmd) */ if (cmd->data_direction == DMA_TO_DEVICE) { if (cmd->se_tfo->write_pending_status(cmd) != 0) { - atomic_inc(&cmd->t_transport_aborted); + cmd->transport_state |= CMD_T_ABORTED; smp_mb__after_atomic_inc(); } } -- cgit v1.2.3 From 3d26fea01d5f80e3e585d69d8d73a60e1ca563a0 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 21 Dec 2011 14:14:05 -0500 Subject: target: remove the transport_lun_active field in struct se_cmd There is no reason to have a flag telling if a command is on the per-lun list, we can simply do a list_empty check before removing it as long as we're careful to always use list_del_init. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index f704123752c..78ea638aa3b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -546,14 +546,8 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd) spin_unlock_irqrestore(&cmd->t_state_lock, flags); spin_lock_irqsave(&lun->lun_cmd_lock, flags); - if (atomic_read(&cmd->transport_lun_active)) { - list_del(&cmd->se_lun_node); - atomic_set(&cmd->transport_lun_active, 0); -#if 0 - pr_debug("Removed ITT: 0x%08x from LUN LIST[%d]\n" - cmd->se_tfo->get_task_tag(cmd), lun->unpacked_lun); -#endif - } + if (!list_empty(&cmd->se_lun_node)) + list_del_init(&cmd->se_lun_node); spin_unlock_irqrestore(&lun->lun_cmd_lock, flags); } @@ -4163,9 +4157,8 @@ static void __transport_clear_lun_from_sessions(struct se_lun *lun) while (!list_empty(&lun->lun_cmd_list)) { cmd = list_first_entry(&lun->lun_cmd_list, struct se_cmd, se_lun_node); - list_del(&cmd->se_lun_node); + list_del_init(&cmd->se_lun_node); - atomic_set(&cmd->transport_lun_active, 0); /* * This will notify iscsi_target_transport.c: * transport_cmd_check_stop() that a LUN shutdown is in -- cgit v1.2.3 From 8e94b8db6121570f5ceb1aede9b28db93461cb86 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Mon, 16 Jan 2012 16:57:07 -0800 Subject: target: Use #define for SYNCHRONIZE_CACHE_16 Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 78ea638aa3b..affbd4d1446 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2912,7 +2912,7 @@ static int transport_generic_cmd_sequencer( cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB; break; case SYNCHRONIZE_CACHE: - case 0x91: /* SYNCHRONIZE_CACHE_16: */ + case SYNCHRONIZE_CACHE_16: /* * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE */ -- cgit v1.2.3 From c8e31f26feeb03dc6f51bff68135cc58431e099b Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 19 Jan 2012 13:39:17 -0800 Subject: target: Add SCF_SCSI_TMR_CDB usage and drop se_tmr_req_cache Change the test for if a cmd is a tmr request to checking if SCF_SCSI_TMR_CDB (a new flag) is set in cmd->se_cmd_flags. Also remove se_tmr_req_cache usage in favor of kzalloc usage, and make core_tmr_alloc_req() return int + setup se_cmd->se_tmr_req directly and fix up various fabric module usages Cc: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index affbd4d1446..c10c3653eab 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -58,7 +58,6 @@ static int sub_api_initialized; static struct workqueue_struct *target_completion_wq; static struct kmem_cache *se_sess_cache; -struct kmem_cache *se_tmr_req_cache; struct kmem_cache *se_ua_cache; struct kmem_cache *t10_pr_reg_cache; struct kmem_cache *t10_alua_lu_gp_cache; @@ -82,21 +81,13 @@ static void target_complete_ok_work(struct work_struct *work); int init_se_kmem_caches(void) { - se_tmr_req_cache = kmem_cache_create("se_tmr_cache", - sizeof(struct se_tmr_req), __alignof__(struct se_tmr_req), - 0, NULL); - if (!se_tmr_req_cache) { - pr_err("kmem_cache_create() for struct se_tmr_req" - " failed\n"); - goto out; - } se_sess_cache = kmem_cache_create("se_sess_cache", sizeof(struct se_session), __alignof__(struct se_session), 0, NULL); if (!se_sess_cache) { pr_err("kmem_cache_create() for struct se_session" " failed\n"); - goto out_free_tmr_req_cache; + goto out; } se_ua_cache = kmem_cache_create("se_ua_cache", sizeof(struct se_ua), __alignof__(struct se_ua), @@ -169,8 +160,6 @@ out_free_ua_cache: kmem_cache_destroy(se_ua_cache); out_free_sess_cache: kmem_cache_destroy(se_sess_cache); -out_free_tmr_req_cache: - kmem_cache_destroy(se_tmr_req_cache); out: return -ENOMEM; } @@ -178,7 +167,6 @@ out: void release_se_kmem_caches(void) { destroy_workqueue(target_completion_wq); - kmem_cache_destroy(se_tmr_req_cache); kmem_cache_destroy(se_sess_cache); kmem_cache_destroy(se_ua_cache); kmem_cache_destroy(t10_pr_reg_cache); @@ -553,7 +541,7 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd) void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) { - if (!cmd->se_tmr_req) + if (!(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) transport_lun_remove_cmd(cmd); if (transport_cmd_check_stop_to_fabric(cmd)) @@ -3367,7 +3355,7 @@ static void transport_release_cmd(struct se_cmd *cmd) { BUG_ON(!cmd->se_tfo); - if (cmd->se_tmr_req) + if (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) core_tmr_release_req(cmd->se_tmr_req); if (cmd->t_task_cdb != cmd->__t_task_cdb) kfree(cmd->t_task_cdb); @@ -3956,7 +3944,7 @@ queue_full: void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) { if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) { - if (wait_for_tasks && cmd->se_tmr_req) + if (wait_for_tasks && (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) transport_wait_for_tasks(cmd); transport_release_cmd(cmd); @@ -4282,7 +4270,8 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) unsigned long flags; spin_lock_irqsave(&cmd->t_state_lock, flags); - if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && !(cmd->se_tmr_req)) { + if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && + !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); return false; } @@ -4290,7 +4279,8 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) * Only perform a possible wait_for_tasks if SCF_SUPPORTED_SAM_OPCODE * has been set in transport_set_supported_SAM_opcode(). */ - if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) && !cmd->se_tmr_req) { + if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) && + !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); return false; } -- cgit v1.2.3 From ea98d7f9c7cc38de55f81a1c249112442b93c7c9 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 19 Jan 2012 13:39:21 -0800 Subject: target: Add target_submit_tmr helper function Similar to target_submit_cmd, this function lets fabrics call one function (albeit with a lot of parameters) instead of 3 or more. (nab: Add missing return for transport_lookup_tmr_lun failure) Signed-off-by: Andy Grover Cc: Kiran Patil Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index c10c3653eab..42da7a30072 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1687,6 +1687,54 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, } EXPORT_SYMBOL(target_submit_cmd); +/** + * target_submit_tmr - lookup unpacked lun and submit uninitialized se_cmd + * for TMR CDBs + * + * @se_cmd: command descriptor to submit + * @se_sess: associated se_sess for endpoint + * @sense: pointer to SCSI sense buffer + * @unpacked_lun: unpacked LUN to reference for struct se_lun + * @fabric_context: fabric context for TMR req + * @tm_type: Type of TM request + * + * Callable from all contexts. + **/ + +void target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, + unsigned char *sense, u32 unpacked_lun, + void *fabric_tmr_ptr, unsigned char tm_type, int flags) +{ + struct se_portal_group *se_tpg; + int ret; + + se_tpg = se_sess->se_tpg; + BUG_ON(!se_tpg); + + transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, + 0, DMA_NONE, MSG_SIMPLE_TAG, sense); + + /* See target_submit_cmd for commentary */ + target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + + ret = core_tmr_alloc_req(se_cmd, fabric_tmr_ptr, tm_type, GFP_KERNEL); + if (ret < 0) { + dump_stack(); + /* FIXME XXX */ + return; + } + + ret = transport_lookup_tmr_lun(se_cmd, unpacked_lun); + if (ret) { + transport_send_check_condition_and_sense(se_cmd, + se_cmd->scsi_sense_reason, 0); + transport_generic_free_cmd(se_cmd, 0); + return; + } + transport_generic_handle_tmr(se_cmd); +} +EXPORT_SYMBOL(target_submit_tmr); + /* * Used by fabric module frontends defining a TFO->new_cmd_map() caller * to queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD_MAP in order to -- cgit v1.2.3 From a1edf9cf6d1efed2981fcf6e4caa704fbb1bd093 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 9 Feb 2012 12:18:06 -0800 Subject: target: Cleanup transport_kunmap_data_sg() This code isn't broken per se, but it's scary to look at! It looks like in the t_data_nents==1 case we're doing both a kunmap and a vunmap, what's saving us is that t_data_vmap in this case is 0, so vunmap doesn't do anything. Return after kunmap, so the handling of the three cases does not overlap. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 42da7a30072..1520dd2dd71 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -3546,10 +3546,12 @@ EXPORT_SYMBOL(transport_kmap_data_sg); void transport_kunmap_data_sg(struct se_cmd *cmd) { - if (!cmd->t_data_nents) + if (!cmd->t_data_nents) { return; - else if (cmd->t_data_nents == 1) + } else if (cmd->t_data_nents == 1) { kunmap(sg_page(cmd->t_data_sg)); + return; + } vunmap(cmd->t_data_vmap); cmd->t_data_vmap = NULL; -- cgit v1.2.3 From 2fbff1276bb635294b3384b6c167f72d0acdab95 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 10 Feb 2012 16:18:11 -0800 Subject: target: Export transport_generic_request_failure symbol transport_generic_request_failure() is a wrapper around calling transport_send_check_condition_and_sense() that is required once an se_cmd->cmd_kref has been obtained via target_submit_cmd() -> target_get_sess_cmd(). tcm_qla2xxx currently requires this, and since it's necessary for other callers using target_submit_cmd() make it exportable now. Reported-by: Roland Dreier Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 1520dd2dd71..35bae7dd670 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -76,7 +76,6 @@ static int transport_generic_get_mem(struct se_cmd *cmd); static void transport_put_cmd(struct se_cmd *cmd); static void transport_remove_cmd_from_queue(struct se_cmd *cmd); static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); -static void transport_generic_request_failure(struct se_cmd *); static void target_complete_ok_work(struct work_struct *work); int init_se_kmem_caches(void) @@ -1866,7 +1865,7 @@ static int transport_stop_tasks_for_cmd(struct se_cmd *cmd) /* * Handle SAM-esque emulation for generic transport request failures. */ -static void transport_generic_request_failure(struct se_cmd *cmd) +void transport_generic_request_failure(struct se_cmd *cmd) { int ret = 0; @@ -1958,6 +1957,7 @@ queue_full: cmd->t_state = TRANSPORT_COMPLETE_QF_OK; transport_handle_queue_full(cmd, cmd->se_dev); } +EXPORT_SYMBOL(transport_generic_request_failure); static inline u32 transport_lba_21(unsigned char *cdb) { -- cgit v1.2.3 From 86715569d085addc635c2b55ee8acb79d3a7fbbf Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 13 Feb 2012 01:07:22 -0800 Subject: target: Add SCF_ACK_KREF flag for acknowledgement kref When TARGET_SCF_ACK_KREF is in use with target_submit_cmd() for setting the extra acknowledgement reference to se_cmd->cmd_kref, go ahead and set SCF_ACK_KREF in order to be used later by abort task. Reported-by: Roland Dreier Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 35bae7dd670..c6b8b823339 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -4030,8 +4030,10 @@ void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, * fabric acknowledgement that requires two target_put_sess_cmd() * invocations before se_cmd descriptor release. */ - if (ack_kref == true) + if (ack_kref == true) { kref_get(&se_cmd->cmd_kref); + se_cmd->se_cmd_flags |= SCF_ACK_KREF; + } spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); -- cgit v1.2.3 From ffc32d5259d107a3aa1b822e22f20b69cb9ec0a5 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 13 Feb 2012 02:35:01 -0800 Subject: target: Make target_release_cmd_kref release on empty list This patch changes target_release_cmd_kref() to make TFO->release_cmd() call when list_empty(&se_cmd->se_cmd_list) is TRUE. This is required for TMR_ABORT_TASK operation where the referenced tag descriptor may have already been pulled of the session command list. Reported-by: Roland Dreier Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index c6b8b823339..52a66710a29 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -4051,7 +4051,7 @@ static void target_release_cmd_kref(struct kref *kref) spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); if (list_empty(&se_cmd->se_cmd_list)) { spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); - WARN_ON(1); + se_cmd->se_tfo->release_cmd(se_cmd); return; } if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) { -- cgit v1.2.3 From 3d28934aaae5e924afedf0f5cb42e1316514da6b Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 13 Feb 2012 02:38:14 -0800 Subject: target: Add TMR_ABORT_TASK task management support This patch adds initial support for TMR_ABORT_TASK ops for se_cmd descriptors using se_sess->sess_cmd_list and se_cmd->cmd_kref counting. It will perform an explict abort for all outstanding se_cmd ops based upon tmr->ref_task_tag that have not been set CMD_T_COMPLETE. It will cancel se_cmd->work and wait for backing I/O to complete before attempting to send SAM_STAT_TASK_ABORTED and perform target_put_sess_cmd() to release the referenced descriptor. It also adds a CMD_T_ABORTED check into transport_complete_task() to catch the completion from backend I/O that has been aborted, and updates transport_wait_for_tasks() to allow CMD_T_ABORTED usage with core_tmr_abort_task() context. Reported-by: Roland Dreier Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 52a66710a29..19804b6fdba 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -699,17 +699,24 @@ void transport_complete_task(struct se_task *task, int success) spin_unlock_irqrestore(&cmd->t_state_lock, flags); return; } - - if (cmd->transport_state & CMD_T_FAILED) { + /* + * Check for case where an explict ABORT_TASK has been received + * and transport_wait_for_tasks() will be waiting for completion.. + */ + if (cmd->transport_state & CMD_T_ABORTED && + cmd->transport_state & CMD_T_STOP) { + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + complete(&cmd->t_transport_stop_comp); + return; + } else if (cmd->transport_state & CMD_T_FAILED) { cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; INIT_WORK(&cmd->work, target_complete_failure_work); } else { - cmd->transport_state |= CMD_T_COMPLETE; INIT_WORK(&cmd->work, target_complete_ok_work); } cmd->t_state = TRANSPORT_COMPLETE; - cmd->transport_state |= CMD_T_ACTIVE; + cmd->transport_state |= (CMD_T_COMPLETE | CMD_T_ACTIVE); spin_unlock_irqrestore(&cmd->t_state_lock, flags); queue_work(target_completion_wq, &cmd->work); @@ -4374,8 +4381,7 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) cmd->transport_state &= ~CMD_T_LUN_STOP; } - if (!(cmd->transport_state & CMD_T_ACTIVE) || - (cmd->transport_state & CMD_T_ABORTED)) { + if (!(cmd->transport_state & CMD_T_ACTIVE)) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); return false; } @@ -4681,7 +4687,7 @@ static int transport_generic_do_tmr(struct se_cmd *cmd) switch (tmr->function) { case TMR_ABORT_TASK: - tmr->response = TMR_FUNCTION_REJECTED; + core_tmr_abort_task(dev, tmr, cmd->se_sess); break; case TMR_ABORT_TASK_SET: case TMR_CLEAR_ACA: -- cgit v1.2.3 From 015487b89f27d91d95a056cdc3c85e6c729bff12 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 13 Feb 2012 16:18:17 -0800 Subject: target: Untangle front-end and back-end meanings of max_sectors attribute se_dev_attrib.max_sectors currently has two independent meanings: - It is reported in the block limits VPD page as the maximum transfer length, ie the largest IO that the front-end (fabric) can handle. Also the target core doesn't enforce this maximum transfer length. - It is used to hold the size of the largest IO that the back-end can handle, so we know when to split SCSI commands into multiple tasks. Fix this by adding a new se_dev_attrib.fabric_max_sectors to hold the maximum transfer length, and checking incoming IOs against that limit. Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 19804b6fdba..b79c6a2824e 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -3107,6 +3108,13 @@ static int transport_generic_cmd_sequencer( cmd->data_length = size; } + if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB && + sectors > dev->se_sub_dev->se_dev_attrib.fabric_max_sectors) { + printk_ratelimited(KERN_ERR "SCSI OP %02xh with too big sectors %u\n", + cdb[0], sectors); + goto out_invalid_cdb_field; + } + /* reject any command that we don't have a handler for */ if (!(passthrough || cmd->execute_task || (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB))) -- cgit v1.2.3 From 3de55ec74aa803d7aa1e581700086d755c2599d2 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sat, 25 Feb 2012 01:30:55 -0800 Subject: target: Fix target_submit_tmr LUN lookup failures This patch changes target_submit_tmr() LUN lookup failures to set response status TMR_LUN_DOES_NOT_EXIST and invoke TFO->queue_tm_rsp(), instead of sending CHECK_CONDITION status that can cause problems with Linux FCoE clients. Tested with tcm_fc ports and explict LUN_RESET lookup failures. Cc: Andy Grover Cc: Kiran Patil Cc: Arun Easi Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index b79c6a2824e..d44cbc2113e 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1733,8 +1733,8 @@ void target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, ret = transport_lookup_tmr_lun(se_cmd, unpacked_lun); if (ret) { - transport_send_check_condition_and_sense(se_cmd, - se_cmd->scsi_sense_reason, 0); + se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST; + se_cmd->se_tfo->queue_tm_rsp(se_cmd); transport_generic_free_cmd(se_cmd, 0); return; } -- cgit v1.2.3 From c7042cae58c13970f39c0820a3aab2a13dda9fe1 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sat, 25 Feb 2012 01:40:24 -0800 Subject: target: Fix target_submit_tmr se_tmr_req allocation failures This patch makes target_submit_tmr() se_tmr_req allocation occur before target_get_sess_cmd(), and changes target_submit_tmr() to return a failure w/ non zero status to the fabric caller upon core_tmr_alloc_req() failure. Cc: Andy Grover Cc: Kiran Patil Cc: Arun Easi Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index d44cbc2113e..96e78f3f461 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1704,11 +1704,12 @@ EXPORT_SYMBOL(target_submit_cmd); * @unpacked_lun: unpacked LUN to reference for struct se_lun * @fabric_context: fabric context for TMR req * @tm_type: Type of TM request + * @flags: submit cmd flags * * Callable from all contexts. **/ -void target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, +int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, unsigned char *sense, u32 unpacked_lun, void *fabric_tmr_ptr, unsigned char tm_type, int flags) { @@ -1720,25 +1721,26 @@ void target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, 0, DMA_NONE, MSG_SIMPLE_TAG, sense); + /* + * FIXME: Currently expect caller to handle se_cmd->se_tmr_req + * allocation failure. + */ + ret = core_tmr_alloc_req(se_cmd, fabric_tmr_ptr, tm_type, GFP_KERNEL); + if (ret < 0) + return -ENOMEM; /* See target_submit_cmd for commentary */ target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); - ret = core_tmr_alloc_req(se_cmd, fabric_tmr_ptr, tm_type, GFP_KERNEL); - if (ret < 0) { - dump_stack(); - /* FIXME XXX */ - return; - } - ret = transport_lookup_tmr_lun(se_cmd, unpacked_lun); if (ret) { se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST; se_cmd->se_tfo->queue_tm_rsp(se_cmd); transport_generic_free_cmd(se_cmd, 0); - return; + return 0; } transport_generic_handle_tmr(se_cmd); + return 0; } EXPORT_SYMBOL(target_submit_tmr); -- cgit v1.2.3 From 9f0d05c2c6185d7b5ba08a6c052e90837101031f Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sat, 25 Feb 2012 05:02:48 -0800 Subject: target: Push target_submit_tmr LUN lookup failure to system_wq context In order to handle incoming target_submit_tmr() callers using interrupt context, use system_wq process context for transport_lookup_tmr_lun() failures to return TMR_LUN_DOES_NOT_EXIST status for fabric TM response. Cc: Andy Grover Cc: Kiran Patil Cc: Arun Easi Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 96e78f3f461..ca1a40dc488 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1694,6 +1694,15 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, } EXPORT_SYMBOL(target_submit_cmd); +static void target_complete_tmr_failure(struct work_struct *work) +{ + struct se_cmd *se_cmd = container_of(work, struct se_cmd, work); + + se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST; + se_cmd->se_tfo->queue_tm_rsp(se_cmd); + transport_generic_free_cmd(se_cmd, 0); +} + /** * target_submit_tmr - lookup unpacked lun and submit uninitialized se_cmd * for TMR CDBs @@ -1734,9 +1743,12 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, ret = transport_lookup_tmr_lun(se_cmd, unpacked_lun); if (ret) { - se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST; - se_cmd->se_tfo->queue_tm_rsp(se_cmd); - transport_generic_free_cmd(se_cmd, 0); + /* + * For callback during failure handling, push this work off + * to process context with TMR_LUN_DOES_NOT_EXIST status. + */ + INIT_WORK(&se_cmd->work, target_complete_tmr_failure); + schedule_work(&se_cmd->work); return 0; } transport_generic_handle_tmr(se_cmd); -- cgit v1.2.3 From c0974f89385970455a60a999ae4fc0a783cf458d Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sat, 25 Feb 2012 05:10:04 -0800 Subject: target: Allow target_submit_tmr interrupt context + pass ABORT_TASK tag This patch allows target_submit_tmr() to pass gfp_t for se_cmd->se_tmr_req allocation, and also set up se_cmd->se_tmr_req->ref_task_tag for passed tag with TMR_ABORT_TASK. Also update tcm_fc(fcoe) parameter usgae and add ref_task_tag FIXME for TMR_ABORT_TASK usage, Cc: Andy Grover Cc: Kiran Patil Cc: Arun Easi Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index ca1a40dc488..3533ad64428 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1713,6 +1713,8 @@ static void target_complete_tmr_failure(struct work_struct *work) * @unpacked_lun: unpacked LUN to reference for struct se_lun * @fabric_context: fabric context for TMR req * @tm_type: Type of TM request + * @gfp: gfp type for caller + * @tag: referenced task tag for TMR_ABORT_TASK * @flags: submit cmd flags * * Callable from all contexts. @@ -1720,7 +1722,8 @@ static void target_complete_tmr_failure(struct work_struct *work) int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, unsigned char *sense, u32 unpacked_lun, - void *fabric_tmr_ptr, unsigned char tm_type, int flags) + void *fabric_tmr_ptr, unsigned char tm_type, + gfp_t gfp, unsigned int tag, int flags) { struct se_portal_group *se_tpg; int ret; @@ -1734,10 +1737,13 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, * FIXME: Currently expect caller to handle se_cmd->se_tmr_req * allocation failure. */ - ret = core_tmr_alloc_req(se_cmd, fabric_tmr_ptr, tm_type, GFP_KERNEL); + ret = core_tmr_alloc_req(se_cmd, fabric_tmr_ptr, tm_type, gfp); if (ret < 0) return -ENOMEM; + if (tm_type == TMR_ABORT_TASK) + se_cmd->se_tmr_req->ref_task_tag = tag; + /* See target_submit_cmd for commentary */ target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); -- cgit v1.2.3 From 140854cb72525246745b67300d35101ad2875a39 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 31 Aug 2011 12:34:39 -0700 Subject: target: Convert session_lock to irqsave This patch converts the remaining struct se_portal_group->session_lock usage to use irqsave+irqrestore to address the following warnings for hardware target mode interrupt context usage. This change generate other warnings for current iscsi-target mode still using ->session_lock with spin_lock_bh, which will need to be converted in a seperate patch. [ 492.480728] [ INFO: HARDIRQ-safe -> HARDIRQ-unsafe lock order detected ] [ 492.488194] 3.0.0+ #23 [ 492.490820] ------------------------------------------------------ [ 492.497704] sh/7162 [HC0[0]:SC0[2]:HE0:SE0] is trying to acquire: [ 492.504493] (&(&se_tpg->session_lock)->rlock){+.....}, at: [] transport_deregister_session+0x2d/0x163 [target_core_mod] 492.518390] [ 492.518390] and this task is already holding: [ 492.524897] (&(&ha->hardware_lock)->rlock){-.-...}, at: [] qla_tgt_stop_phase1+0x5e/0x27e [qla2xxx] [ 492.536856] which would create a new lock dependency: [ 492.542481] (&(&ha->hardware_lock)->rlock){-.-...} -> (&(&se_tpg->session_lock)->rlock){+.....} [ 492.552321] [ 492.552321] but this new dependency connects a HARDIRQ-irq-safe lock: [ 492.561149] (&(&ha->hardware_lock)->rlock){-.-...} [ 492.566400] ... which became HARDIRQ-irq-safe at: [ 492.571841] [] __lock_acquire+0x68f/0x921 [ 492.578247] [] lock_acquire+0xe0/0x10d [ 492.584367] [] _raw_spin_lock_irqsave+0x44/0x56 [ 492.591358] [] qla24xx_msix_default+0x5c/0x2aa [qla2xxx] [ 492.599227] [] handle_irq_event_percpu+0x5a/0x197 [ 492.606413] [] handle_irq_event+0x3c/0x5c [ 492.612822] [] handle_edge_irq+0xcc/0xf1 [ 492.619138] [] handle_irq+0x83/0x8e [ 492.624971] [] do_IRQ+0x48/0xaf [ 492.630413] [] ret_from_intr+0x0/0x1a [ 492.636437] [] cpu_idle+0x5b/0x8d [ 492.642073] [] rest_init+0xad/0xb4 [ 492.647809] [] start_kernel+0x366/0x371 [ 492.654030] [] x86_64_start_reservations+0xb8/0xbc [ 492.661311] [] x86_64_start_kernel+0x101/0x110 [ 492.668204] [ 492.668205] to a HARDIRQ-irq-unsafe lock: [ 492.674324] (&(&se_tpg->session_lock)->rlock){+.....} [ 492.679862] ... which became HARDIRQ-irq-unsafe at: [ 492.685497] ... [] __lock_acquire+0x709/0x921 [ 492.692209] [] lock_acquire+0xe0/0x10d [ 492.698330] [] _raw_spin_lock_bh+0x31/0x40 [ 492.704836] [] core_tpg_del_initiator_node_acl+0x89/0x336 [target_core_mod] [ 492.714546] [] tcm_qla2xxx_drop_nodeacl+0x20/0x2d [tcm_qla2xxx] [ 492.723087] [] target_fabric_nacl_base_release+0x22/0x24 [target_core_mod] [ 492.732698] [] config_item_release+0x7d/0xa3 [configfs] [ 492.740465] [] kref_put+0x43/0x4d [ 492.746101] [] config_item_put+0x19/0x1b [configfs] [ 492.753481] [] configfs_rmdir+0x1eb/0x258 [configfs] [ 492.760957] [] vfs_rmdir+0x79/0xd0 [ 492.766690] [] do_rmdir+0xc2/0x111 [ 492.772423] [] sys_rmdir+0x11/0x13 [ 492.778156] [] system_call_fastpath+0x16/0x1b [ 492.784953] Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 3533ad64428..d931edf11c2 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -252,7 +252,7 @@ struct se_session *transport_init_session(void) EXPORT_SYMBOL(transport_init_session); /* - * Called with spin_lock_bh(&struct se_portal_group->session_lock called. + * Called with spin_lock_irqsave(&struct se_portal_group->session_lock called. */ void __transport_register_session( struct se_portal_group *se_tpg, @@ -305,9 +305,11 @@ void transport_register_session( struct se_session *se_sess, void *fabric_sess_ptr) { - spin_lock_bh(&se_tpg->session_lock); + unsigned long flags; + + spin_lock_irqsave(&se_tpg->session_lock, flags); __transport_register_session(se_tpg, se_nacl, se_sess, fabric_sess_ptr); - spin_unlock_bh(&se_tpg->session_lock); + spin_unlock_irqrestore(&se_tpg->session_lock, flags); } EXPORT_SYMBOL(transport_register_session); -- cgit v1.2.3 From 41ac82b668177876d5965d5f60956fb0fbcdb514 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 26 Feb 2012 22:22:10 -0800 Subject: target: Add se_sess->sess_kref + get/put helpers This patch adds basic se_session->sess_kref and get/put helpers for fabric session reference counting. It sets the initial kref in transport_init_session() and adds a target_release_session() callback to invoke TFO->close_session() for final session shutdown. Cc: Roland Dreier Cc: Christoph Hellwig Cc: Joern Engel Cc: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index d931edf11c2..7badc87e4bb 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -246,6 +246,7 @@ struct se_session *transport_init_session(void) INIT_LIST_HEAD(&se_sess->sess_cmd_list); INIT_LIST_HEAD(&se_sess->sess_wait_list); spin_lock_init(&se_sess->sess_cmd_lock); + kref_init(&se_sess->sess_kref); return se_sess; } @@ -313,6 +314,27 @@ void transport_register_session( } EXPORT_SYMBOL(transport_register_session); +static void target_release_session(struct kref *kref) +{ + struct se_session *se_sess = container_of(kref, + struct se_session, sess_kref); + struct se_portal_group *se_tpg = se_sess->se_tpg; + + se_tpg->se_tpg_tfo->close_session(se_sess); +} + +void target_get_session(struct se_session *se_sess) +{ + kref_get(&se_sess->sess_kref); +} +EXPORT_SYMBOL(target_get_session); + +int target_put_session(struct se_session *se_sess) +{ + return kref_put(&se_sess->sess_kref, target_release_session); +} +EXPORT_SYMBOL(target_put_session); + void transport_deregister_session_configfs(struct se_session *se_sess) { struct se_node_acl *se_nacl; -- cgit v1.2.3 From 01468346546a9bcc09035a7e8b71f78af5b7133a Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sat, 10 Mar 2012 14:32:52 -0800 Subject: target: Add se_node_acl->acl_free_comp for NodeACL release path Add se_node_acl->acl_free_comp for NodeACL release path to wait for outstanding fabric session shutdown to complete in transport_deregister_session() before finishing NodeACL release from configfs process context. Also make transport_deregister_session() clear the comp_nacl bit to skip se_node_acl->acl_free_comp completion for dynamically generated NodeACL during fabric session shutdown. Cc: Roland Dreier Cc: Christoph Hellwig Cc: Joern Engel Cc: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 40 ++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 16 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 7badc87e4bb..9e61abc5d9d 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -372,13 +372,16 @@ EXPORT_SYMBOL(transport_free_session); void transport_deregister_session(struct se_session *se_sess) { struct se_portal_group *se_tpg = se_sess->se_tpg; + struct target_core_fabric_ops *se_tfo; struct se_node_acl *se_nacl; unsigned long flags; + bool comp_nacl = true; if (!se_tpg) { transport_free_session(se_sess); return; } + se_tfo = se_tpg->se_tpg_tfo; spin_lock_irqsave(&se_tpg->session_lock, flags); list_del(&se_sess->sess_list); @@ -391,29 +394,34 @@ void transport_deregister_session(struct se_session *se_sess) * struct se_node_acl if it had been previously dynamically generated. */ se_nacl = se_sess->se_node_acl; - if (se_nacl) { - spin_lock_irqsave(&se_tpg->acl_node_lock, flags); - if (se_nacl->dynamic_node_acl) { - if (!se_tpg->se_tpg_tfo->tpg_check_demo_mode_cache( - se_tpg)) { - list_del(&se_nacl->acl_list); - se_tpg->num_node_acls--; - spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags); - - core_tpg_wait_for_nacl_pr_ref(se_nacl); - core_free_device_list_for_node(se_nacl, se_tpg); - se_tpg->se_tpg_tfo->tpg_release_fabric_acl(se_tpg, - se_nacl); - spin_lock_irqsave(&se_tpg->acl_node_lock, flags); - } + + spin_lock_irqsave(&se_tpg->acl_node_lock, flags); + if (se_nacl && se_nacl->dynamic_node_acl) { + if (!se_tfo->tpg_check_demo_mode_cache(se_tpg)) { + list_del(&se_nacl->acl_list); + se_tpg->num_node_acls--; + spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags); + core_tpg_wait_for_nacl_pr_ref(se_nacl); + core_free_device_list_for_node(se_nacl, se_tpg); + se_tfo->tpg_release_fabric_acl(se_tpg, se_nacl); + + comp_nacl = false; + spin_lock_irqsave(&se_tpg->acl_node_lock, flags); } - spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags); } + spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags); transport_free_session(se_sess); pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n", se_tpg->se_tpg_tfo->get_fabric_name()); + /* + * Awake sleeping ->acl_free_comp caller from configfs se_node_acl + * removal context + */ + if (se_nacl && comp_nacl == true) + complete(&se_nacl->acl_free_comp); + } EXPORT_SYMBOL(transport_deregister_session); -- cgit v1.2.3 From afb999ffc48f5e7ec18e6f8f9e68aa3d0085862d Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 8 Mar 2012 23:45:02 -0800 Subject: target: Add se_node_acl->acl_kref for ->acl_free_comp usage This patch adds se_node_acl->acl_kref for use with ->acl_free_comp during explict se_node_acl release. It adds kref_init() during se_node_acl setup, kref_get() during __transport_register_session() -> target_put_nacl() with existing transport_deregister_session() fabric callback usage. It also moves transport_free_session() to release *se_sess memory after target_put_nacl() execution in transport_deregister_session() Cc: Roland Dreier Cc: Christoph Hellwig Cc: Joern Engel Cc: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 9e61abc5d9d..efefbec286f 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -282,6 +282,8 @@ void __transport_register_session( &buf[0], PR_REG_ISID_LEN); se_sess->sess_bin_isid = get_unaligned_be64(&buf[0]); } + kref_get(&se_nacl->acl_kref); + spin_lock_irq(&se_nacl->nacl_sess_lock); /* * The se_nacl->nacl_sess pointer will be set to the @@ -335,6 +337,19 @@ int target_put_session(struct se_session *se_sess) } EXPORT_SYMBOL(target_put_session); +static void target_complete_nacl(struct kref *kref) +{ + struct se_node_acl *nacl = container_of(kref, + struct se_node_acl, acl_kref); + + complete(&nacl->acl_free_comp); +} + +void target_put_nacl(struct se_node_acl *nacl) +{ + kref_put(&nacl->acl_kref, target_complete_nacl); +} + void transport_deregister_session_configfs(struct se_session *se_sess) { struct se_node_acl *se_nacl; @@ -411,17 +426,17 @@ void transport_deregister_session(struct se_session *se_sess) } spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags); - transport_free_session(se_sess); - pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n", se_tpg->se_tpg_tfo->get_fabric_name()); /* - * Awake sleeping ->acl_free_comp caller from configfs se_node_acl - * removal context + * If last kref is dropping now for an explict NodeACL, awake sleeping + * ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group + * removal context. */ if (se_nacl && comp_nacl == true) - complete(&se_nacl->acl_free_comp); + target_put_nacl(se_nacl); + transport_free_session(se_sess); } EXPORT_SYMBOL(transport_deregister_session); -- cgit v1.2.3 From 337c060701fb3d27d9945bf7af7ba194ae2153a8 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sat, 10 Mar 2012 14:36:21 -0800 Subject: target: Convert se_node_acl->acl_group removal to use ->acl_kref This patch converts core_tpg_del_initiator_node_acl() shutdown from configfs context to use se_node_acl->acl_kref and ->acl_free_comp in order to wait for outstanding fabric callbacks to complete via transport_deregister_session() callbacks before waking ->acl_free_comp from the last ->acl_kref put. It also changes core_tpg_del_initiator_node_acl() to setup a local sess_list with target_get_session() + acl->acl_stop = 1 for active sessions that will be shutdown, and changes transport_deregister_session_configfs() to check for ->acl_stop usage. Cc: Roland Dreier Cc: Christoph Hellwig Cc: Joern Engel Cc: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index efefbec286f..ba8eb837303 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -360,7 +360,8 @@ void transport_deregister_session_configfs(struct se_session *se_sess) se_nacl = se_sess->se_node_acl; if (se_nacl) { spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags); - list_del(&se_sess->sess_acl_list); + if (se_nacl->acl_stop == 0) + list_del(&se_sess->sess_acl_list); /* * If the session list is empty, then clear the pointer. * Otherwise, set the struct se_session pointer from the tail -- cgit v1.2.3 From b168fe8cfe530daabbdf632af4554600006a81a9 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 14 Mar 2012 10:40:43 -0700 Subject: target: Fix sense code for unsupported SERVICE ACTION IN If we don't handle a given service action, we're supposed to return INVALID FIELD IN CDB, since we do handle the SERVICE ACTION IN opcode. Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index ba8eb837303..4a112b6c7f2 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2942,7 +2942,7 @@ static int transport_generic_cmd_sequencer( pr_err("Unsupported SA: 0x%02x\n", cmd->t_task_cdb[1] & 0x1f); - goto out_unsupported_cdb; + goto out_invalid_cdb_field; } /*FALLTHROUGH*/ case ACCESS_CONTROL_IN: -- cgit v1.2.3