From f8e471f9eb9068bf5ac8c6a04da74329a442f75a Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 6 Mar 2015 20:34:32 -0800 Subject: target: Add target_show_dynamic_sessions attribute helper This patch adds a new helper function that can be used by fabric driver TPG attributes for dumping the list of active sessions with a dynamically generated se_node_acl. (generate_node_acl=1). It prints one se_node_acl->initiatorname per line, up to PAGE_SIZE which is due to the current limitiation of single page attribute output within sysfs and configfs code. Note that if a session is referencing a explicit NodeACL, the InitiatorName will not appear within dynamic_sessions output. Reported-by: Andy Grover Signed-off-by: Nicholas Bellinger --- include/target/target_core_fabric.h | 1 + include/target/target_core_fabric_configfs.h | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'include') diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 22a4e98eec80..2f4a2505db4c 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -95,6 +95,7 @@ void transport_register_session(struct se_portal_group *, struct se_node_acl *, struct se_session *, void *); void target_get_session(struct se_session *); void target_put_session(struct se_session *); +ssize_t target_show_dynamic_sessions(struct se_portal_group *, char *); void transport_free_session(struct se_session *); void target_put_nacl(struct se_node_acl *); void transport_deregister_session_configfs(struct se_session *); diff --git a/include/target/target_core_fabric_configfs.h b/include/target/target_core_fabric_configfs.h index b32a14905cfa..7a0649c09e79 100644 --- a/include/target/target_core_fabric_configfs.h +++ b/include/target/target_core_fabric_configfs.h @@ -90,6 +90,11 @@ static struct target_fabric_tpg_attribute _fabric##_tpg_##_name = \ _fabric##_tpg_store_##_name); +#define TF_TPG_BASE_ATTR_RO(_fabric, _name) \ +static struct target_fabric_tpg_attribute _fabric##_tpg_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + _fabric##_tpg_show_##_name); + CONFIGFS_EATTR_STRUCT(target_fabric_wwn, target_fabric_configfs); #define TF_WWN_ATTR(_fabric, _name, _mode) \ static struct target_fabric_wwn_attribute _fabric##_wwn_##_name = \ -- cgit v1.2.3 From 88dcd2dab5c23b1c9cfc396246d8f476c872f0ca Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 26 Feb 2015 22:19:15 -0800 Subject: iscsi-target: Convert iscsi_thread_set usage to kthread.h This patch converts iscsi-target code to use modern kthread.h API callers for creating RX/TX threads for each new iscsi_conn descriptor, and releasing associated RX/TX threads during connection shutdown. This is done using iscsit_start_kthreads() -> kthread_run() to start new kthreads from within iscsi_post_login_handler(), and invoking kthread_stop() from existing iscsit_close_connection() code. Also, convert iscsit_logout_post_handler_closesession() code to use cmpxchg when determing when iscsit_cause_connection_reinstatement() needs to sleep waiting for completion. Reported-by: Sagi Grimberg Tested-by: Sagi Grimberg Cc: Slava Shwartsman Cc: # v3.10+ Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target.c | 104 +++++++++++++----------------- drivers/target/iscsi/iscsi_target_erl0.c | 13 ++-- drivers/target/iscsi/iscsi_target_login.c | 59 +++++++++++++++-- include/target/iscsi/iscsi_target_core.h | 7 ++ 4 files changed, 114 insertions(+), 69 deletions(-) (limited to 'include') diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 47af86167b49..163773fb4f84 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -537,7 +537,7 @@ static struct iscsit_transport iscsi_target_transport = { static int __init iscsi_target_init_module(void) { - int ret = 0; + int ret = 0, size; pr_debug("iSCSI-Target "ISCSIT_VERSION"\n"); @@ -546,6 +546,7 @@ static int __init iscsi_target_init_module(void) pr_err("Unable to allocate memory for iscsit_global\n"); return -1; } + spin_lock_init(&iscsit_global->ts_bitmap_lock); mutex_init(&auth_id_lock); spin_lock_init(&sess_idr_lock); idr_init(&tiqn_idr); @@ -555,15 +556,11 @@ static int __init iscsi_target_init_module(void) if (ret < 0) goto out; - ret = iscsi_thread_set_init(); - if (ret < 0) + size = BITS_TO_LONGS(ISCSIT_BITMAP_BITS) * sizeof(long); + iscsit_global->ts_bitmap = vzalloc(size); + if (!iscsit_global->ts_bitmap) { + pr_err("Unable to allocate iscsit_global->ts_bitmap\n"); goto configfs_out; - - if (iscsi_allocate_thread_sets(TARGET_THREAD_SET_COUNT) != - TARGET_THREAD_SET_COUNT) { - pr_err("iscsi_allocate_thread_sets() returned" - " unexpected value!\n"); - goto ts_out1; } lio_qr_cache = kmem_cache_create("lio_qr_cache", @@ -572,7 +569,7 @@ static int __init iscsi_target_init_module(void) if (!lio_qr_cache) { pr_err("nable to kmem_cache_create() for" " lio_qr_cache\n"); - goto ts_out2; + goto bitmap_out; } lio_dr_cache = kmem_cache_create("lio_dr_cache", @@ -617,10 +614,8 @@ dr_out: kmem_cache_destroy(lio_dr_cache); qr_out: kmem_cache_destroy(lio_qr_cache); -ts_out2: - iscsi_deallocate_thread_sets(); -ts_out1: - iscsi_thread_set_free(); +bitmap_out: + vfree(iscsit_global->ts_bitmap); configfs_out: iscsi_target_deregister_configfs(); out: @@ -630,8 +625,6 @@ out: static void __exit iscsi_target_cleanup_module(void) { - iscsi_deallocate_thread_sets(); - iscsi_thread_set_free(); iscsit_release_discovery_tpg(); iscsit_unregister_transport(&iscsi_target_transport); kmem_cache_destroy(lio_qr_cache); @@ -641,6 +634,7 @@ static void __exit iscsi_target_cleanup_module(void) iscsi_target_deregister_configfs(); + vfree(iscsit_global->ts_bitmap); kfree(iscsit_global); } @@ -3709,17 +3703,16 @@ static int iscsit_send_reject( void iscsit_thread_get_cpumask(struct iscsi_conn *conn) { - struct iscsi_thread_set *ts = conn->thread_set; int ord, cpu; /* - * thread_id is assigned from iscsit_global->ts_bitmap from - * within iscsi_thread_set.c:iscsi_allocate_thread_sets() + * bitmap_id is assigned from iscsit_global->ts_bitmap from + * within iscsit_start_kthreads() * - * Here we use thread_id to determine which CPU that this - * iSCSI connection's iscsi_thread_set will be scheduled to + * Here we use bitmap_id to determine which CPU that this + * iSCSI connection's RX/TX threads will be scheduled to * execute upon. */ - ord = ts->thread_id % cpumask_weight(cpu_online_mask); + ord = conn->bitmap_id % cpumask_weight(cpu_online_mask); for_each_online_cpu(cpu) { if (ord-- == 0) { cpumask_set_cpu(cpu, conn->conn_cpumask); @@ -3908,7 +3901,7 @@ check_rsp_state: switch (state) { case ISTATE_SEND_LOGOUTRSP: if (!iscsit_logout_post_handler(cmd, conn)) - goto restart; + return -ECONNRESET; /* fall through */ case ISTATE_SEND_STATUS: case ISTATE_SEND_ASYNCMSG: @@ -3936,8 +3929,6 @@ check_rsp_state: err: return -1; -restart: - return -EAGAIN; } static int iscsit_handle_response_queue(struct iscsi_conn *conn) @@ -3964,21 +3955,13 @@ static int iscsit_handle_response_queue(struct iscsi_conn *conn) int iscsi_target_tx_thread(void *arg) { int ret = 0; - struct iscsi_conn *conn; - struct iscsi_thread_set *ts = arg; + struct iscsi_conn *conn = arg; /* * Allow ourselves to be interrupted by SIGINT so that a * connection recovery / failure event can be triggered externally. */ allow_signal(SIGINT); -restart: - conn = iscsi_tx_thread_pre_handler(ts); - if (!conn) - goto out; - - ret = 0; - while (!kthread_should_stop()) { /* * Ensure that both TX and RX per connection kthreads @@ -3987,11 +3970,9 @@ restart: iscsit_thread_check_cpumask(conn, current, 1); wait_event_interruptible(conn->queues_wq, - !iscsit_conn_all_queues_empty(conn) || - ts->status == ISCSI_THREAD_SET_RESET); + !iscsit_conn_all_queues_empty(conn)); - if ((ts->status == ISCSI_THREAD_SET_RESET) || - signal_pending(current)) + if (signal_pending(current)) goto transport_err; get_immediate: @@ -4002,15 +3983,14 @@ get_immediate: ret = iscsit_handle_response_queue(conn); if (ret == 1) goto get_immediate; - else if (ret == -EAGAIN) - goto restart; + else if (ret == -ECONNRESET) + goto out; else if (ret < 0) goto transport_err; } transport_err: iscsit_take_action_for_connection_exit(conn); - goto restart; out: return 0; } @@ -4105,8 +4085,7 @@ int iscsi_target_rx_thread(void *arg) int ret; u8 buffer[ISCSI_HDR_LEN], opcode; u32 checksum = 0, digest = 0; - struct iscsi_conn *conn = NULL; - struct iscsi_thread_set *ts = arg; + struct iscsi_conn *conn = arg; struct kvec iov; /* * Allow ourselves to be interrupted by SIGINT so that a @@ -4114,11 +4093,6 @@ int iscsi_target_rx_thread(void *arg) */ allow_signal(SIGINT); -restart: - conn = iscsi_rx_thread_pre_handler(ts); - if (!conn) - goto out; - if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) { struct completion comp; int rc; @@ -4128,7 +4102,7 @@ restart: if (rc < 0) goto transport_err; - goto out; + goto transport_err; } while (!kthread_should_stop()) { @@ -4204,8 +4178,6 @@ transport_err: if (!signal_pending(current)) atomic_set(&conn->transport_failed, 1); iscsit_take_action_for_connection_exit(conn); - goto restart; -out: return 0; } @@ -4261,7 +4233,24 @@ int iscsit_close_connection( */ complete(&conn->conn_logout_comp); - iscsi_release_thread_set(conn); + if (!strcmp(current->comm, ISCSI_RX_THREAD_NAME)) { + if (conn->tx_thread && + cmpxchg(&conn->tx_thread_active, true, false)) { + send_sig(SIGINT, conn->tx_thread, 1); + kthread_stop(conn->tx_thread); + } + } else if (!strcmp(current->comm, ISCSI_TX_THREAD_NAME)) { + if (conn->rx_thread && + cmpxchg(&conn->rx_thread_active, true, false)) { + send_sig(SIGINT, conn->rx_thread, 1); + kthread_stop(conn->rx_thread); + } + } + + spin_lock(&iscsit_global->ts_bitmap_lock); + bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id, + get_order(1)); + spin_unlock(&iscsit_global->ts_bitmap_lock); iscsit_stop_timers_for_cmds(conn); iscsit_stop_nopin_response_timer(conn); @@ -4539,15 +4528,13 @@ static void iscsit_logout_post_handler_closesession( struct iscsi_conn *conn) { struct iscsi_session *sess = conn->sess; - - iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD); - iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD); + int sleep = cmpxchg(&conn->tx_thread_active, true, false); atomic_set(&conn->conn_logout_remove, 0); complete(&conn->conn_logout_comp); iscsit_dec_conn_usage_count(conn); - iscsit_stop_session(sess, 1, 1); + iscsit_stop_session(sess, sleep, sleep); iscsit_dec_session_usage_count(sess); target_put_session(sess->se_sess); } @@ -4555,13 +4542,12 @@ static void iscsit_logout_post_handler_closesession( static void iscsit_logout_post_handler_samecid( struct iscsi_conn *conn) { - iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD); - iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD); + int sleep = cmpxchg(&conn->tx_thread_active, true, false); atomic_set(&conn->conn_logout_remove, 0); complete(&conn->conn_logout_comp); - iscsit_cause_connection_reinstatement(conn, 1); + iscsit_cause_connection_reinstatement(conn, sleep); iscsit_dec_conn_usage_count(conn); } diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index 1c197bad6132..d4e2159f53c2 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -861,7 +861,10 @@ void iscsit_connection_reinstatement_rcfr(struct iscsi_conn *conn) } spin_unlock_bh(&conn->state_lock); - iscsi_thread_set_force_reinstatement(conn); + if (conn->tx_thread && conn->tx_thread_active) + send_sig(SIGINT, conn->tx_thread, 1); + if (conn->rx_thread && conn->rx_thread_active) + send_sig(SIGINT, conn->rx_thread, 1); sleep: wait_for_completion(&conn->conn_wait_rcfr_comp); @@ -886,10 +889,10 @@ void iscsit_cause_connection_reinstatement(struct iscsi_conn *conn, int sleep) return; } - if (iscsi_thread_set_force_reinstatement(conn) < 0) { - spin_unlock_bh(&conn->state_lock); - return; - } + if (conn->tx_thread && conn->tx_thread_active) + send_sig(SIGINT, conn->tx_thread, 1); + if (conn->rx_thread && conn->rx_thread_active) + send_sig(SIGINT, conn->rx_thread, 1); atomic_set(&conn->connection_reinstatement, 1); if (!sleep) { diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 153fb66ac1b8..345f073ff6dc 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -699,6 +699,51 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn) iscsit_start_nopin_timer(conn); } +int iscsit_start_kthreads(struct iscsi_conn *conn) +{ + int ret = 0; + + spin_lock(&iscsit_global->ts_bitmap_lock); + conn->bitmap_id = bitmap_find_free_region(iscsit_global->ts_bitmap, + ISCSIT_BITMAP_BITS, get_order(1)); + spin_unlock(&iscsit_global->ts_bitmap_lock); + + if (conn->bitmap_id < 0) { + pr_err("bitmap_find_free_region() failed for" + " iscsit_start_kthreads()\n"); + return -ENOMEM; + } + + conn->tx_thread = kthread_run(iscsi_target_tx_thread, conn, + "%s", ISCSI_TX_THREAD_NAME); + if (IS_ERR(conn->tx_thread)) { + pr_err("Unable to start iscsi_target_tx_thread\n"); + ret = PTR_ERR(conn->tx_thread); + goto out_bitmap; + } + conn->tx_thread_active = true; + + conn->rx_thread = kthread_run(iscsi_target_rx_thread, conn, + "%s", ISCSI_RX_THREAD_NAME); + if (IS_ERR(conn->rx_thread)) { + pr_err("Unable to start iscsi_target_rx_thread\n"); + ret = PTR_ERR(conn->rx_thread); + goto out_tx; + } + conn->rx_thread_active = true; + + return 0; +out_tx: + kthread_stop(conn->tx_thread); + conn->tx_thread_active = false; +out_bitmap: + spin_lock(&iscsit_global->ts_bitmap_lock); + bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id, + get_order(1)); + spin_unlock(&iscsit_global->ts_bitmap_lock); + return ret; +} + int iscsi_post_login_handler( struct iscsi_np *np, struct iscsi_conn *conn, @@ -709,7 +754,7 @@ int iscsi_post_login_handler( struct se_session *se_sess = sess->se_sess; struct iscsi_portal_group *tpg = sess->tpg; struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; - struct iscsi_thread_set *ts; + int rc; iscsit_inc_conn_usage_count(conn); @@ -724,7 +769,6 @@ int iscsi_post_login_handler( /* * SCSI Initiator -> SCSI Target Port Mapping */ - ts = iscsi_get_thread_set(); if (!zero_tsih) { iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 0); @@ -751,9 +795,11 @@ int iscsi_post_login_handler( sess->sess_ops->InitiatorName); spin_unlock_bh(&sess->conn_lock); - iscsi_post_login_start_timers(conn); + rc = iscsit_start_kthreads(conn); + if (rc) + return rc; - iscsi_activate_thread_set(conn, ts); + iscsi_post_login_start_timers(conn); /* * Determine CPU mask to ensure connection's RX and TX kthreads * are scheduled on the same CPU. @@ -810,8 +856,11 @@ int iscsi_post_login_handler( " iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt); spin_unlock_bh(&se_tpg->session_lock); + rc = iscsit_start_kthreads(conn); + if (rc) + return rc; + iscsi_post_login_start_timers(conn); - iscsi_activate_thread_set(conn, ts); /* * Determine CPU mask to ensure connection's RX and TX kthreads * are scheduled on the same CPU. diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index d3583d3ee193..dd0f3abde75d 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -602,6 +602,11 @@ struct iscsi_conn { struct iscsi_session *sess; /* Pointer to thread_set in use for this conn's threads */ struct iscsi_thread_set *thread_set; + int bitmap_id; + int rx_thread_active; + struct task_struct *rx_thread; + int tx_thread_active; + struct task_struct *tx_thread; /* list_head for session connection list */ struct list_head conn_list; } ____cacheline_aligned; @@ -871,10 +876,12 @@ struct iscsit_global { /* Unique identifier used for the authentication daemon */ u32 auth_id; u32 inactive_ts; +#define ISCSIT_BITMAP_BITS 262144 /* Thread Set bitmap count */ int ts_bitmap_count; /* Thread Set bitmap pointer */ unsigned long *ts_bitmap; + spinlock_t ts_bitmap_lock; /* Used for iSCSI discovery session authentication */ struct iscsi_node_acl discovery_acl; struct iscsi_portal_group *discovery_tpg; -- cgit v1.2.3 From 073900bdb4e34109a647c7cb871856a771634460 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 27 Feb 2015 10:21:06 +0000 Subject: iscsi-target: Drop legacy iscsi_target_tq.c logic Now that iscsi_conn allocates new [rx,tx] threads using kthread.h primitives on the fly, and kthread_stop() is called directly during connection shutdown, it's time to go ahead and drop iscsi_target_tq.c legacy code. The use of multiple struct completion in iscsi_activate_thread_set() has been proven to cause issues during repeated iser login/logout. Tested-by: Sagi Grimberg Cc: Slava Shwartsman Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/Makefile | 1 - drivers/target/iscsi/iscsi_target.c | 3 - drivers/target/iscsi/iscsi_target_erl0.c | 1 - drivers/target/iscsi/iscsi_target_login.c | 1 - drivers/target/iscsi/iscsi_target_tq.c | 495 ------------------------------ drivers/target/iscsi/iscsi_target_tq.h | 84 ----- drivers/target/iscsi/iscsi_target_util.c | 1 - include/target/iscsi/iscsi_target_core.h | 6 +- 8 files changed, 2 insertions(+), 590 deletions(-) delete mode 100644 drivers/target/iscsi/iscsi_target_tq.c delete mode 100644 drivers/target/iscsi/iscsi_target_tq.h (limited to 'include') diff --git a/drivers/target/iscsi/Makefile b/drivers/target/iscsi/Makefile index 13a92403fe3e..0f43be9c3453 100644 --- a/drivers/target/iscsi/Makefile +++ b/drivers/target/iscsi/Makefile @@ -1,6 +1,5 @@ iscsi_target_mod-y += iscsi_target_parameters.o \ iscsi_target_seq_pdu_list.o \ - iscsi_target_tq.o \ iscsi_target_auth.o \ iscsi_target_datain_values.o \ iscsi_target_device.o \ diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 163773fb4f84..cd611e740de7 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -33,7 +33,6 @@ #include #include "iscsi_target_parameters.h" #include "iscsi_target_seq_pdu_list.h" -#include "iscsi_target_tq.h" #include "iscsi_target_configfs.h" #include "iscsi_target_datain_values.h" #include "iscsi_target_erl0.h" @@ -4360,8 +4359,6 @@ int iscsit_close_connection( iscsit_put_transport(conn->conn_transport); - conn->thread_set = NULL; - pr_debug("Moving to TARG_CONN_STATE_FREE.\n"); conn->conn_state = TARG_CONN_STATE_FREE; kfree(conn); diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index d4e2159f53c2..e1f4c7eedb08 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -24,7 +24,6 @@ #include #include #include "iscsi_target_seq_pdu_list.h" -#include "iscsi_target_tq.h" #include "iscsi_target_erl0.h" #include "iscsi_target_erl1.h" #include "iscsi_target_erl2.h" diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 345f073ff6dc..af20ddf2bbb4 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -26,7 +26,6 @@ #include #include -#include "iscsi_target_tq.h" #include "iscsi_target_device.h" #include "iscsi_target_nego.h" #include "iscsi_target_erl0.h" diff --git a/drivers/target/iscsi/iscsi_target_tq.c b/drivers/target/iscsi/iscsi_target_tq.c deleted file mode 100644 index 26aa50996473..000000000000 --- a/drivers/target/iscsi/iscsi_target_tq.c +++ /dev/null @@ -1,495 +0,0 @@ -/******************************************************************************* - * This file contains the iSCSI Login Thread and Thread Queue functions. - * - * (c) Copyright 2007-2013 Datera, Inc. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include -#include - -#include -#include "iscsi_target_tq.h" -#include "iscsi_target.h" - -static LIST_HEAD(inactive_ts_list); -static DEFINE_SPINLOCK(inactive_ts_lock); -static DEFINE_SPINLOCK(ts_bitmap_lock); - -static void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts) -{ - if (!list_empty(&ts->ts_list)) { - WARN_ON(1); - return; - } - spin_lock(&inactive_ts_lock); - list_add_tail(&ts->ts_list, &inactive_ts_list); - iscsit_global->inactive_ts++; - spin_unlock(&inactive_ts_lock); -} - -static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void) -{ - struct iscsi_thread_set *ts; - - spin_lock(&inactive_ts_lock); - if (list_empty(&inactive_ts_list)) { - spin_unlock(&inactive_ts_lock); - return NULL; - } - - ts = list_first_entry(&inactive_ts_list, struct iscsi_thread_set, ts_list); - - list_del_init(&ts->ts_list); - iscsit_global->inactive_ts--; - spin_unlock(&inactive_ts_lock); - - return ts; -} - -int iscsi_allocate_thread_sets(u32 thread_pair_count) -{ - int allocated_thread_pair_count = 0, i, thread_id; - struct iscsi_thread_set *ts = NULL; - - for (i = 0; i < thread_pair_count; i++) { - ts = kzalloc(sizeof(struct iscsi_thread_set), GFP_KERNEL); - if (!ts) { - pr_err("Unable to allocate memory for" - " thread set.\n"); - return allocated_thread_pair_count; - } - /* - * Locate the next available regision in the thread_set_bitmap - */ - spin_lock(&ts_bitmap_lock); - thread_id = bitmap_find_free_region(iscsit_global->ts_bitmap, - iscsit_global->ts_bitmap_count, get_order(1)); - spin_unlock(&ts_bitmap_lock); - if (thread_id < 0) { - pr_err("bitmap_find_free_region() failed for" - " thread_set_bitmap\n"); - kfree(ts); - return allocated_thread_pair_count; - } - - ts->thread_id = thread_id; - ts->status = ISCSI_THREAD_SET_FREE; - INIT_LIST_HEAD(&ts->ts_list); - spin_lock_init(&ts->ts_state_lock); - init_completion(&ts->rx_restart_comp); - init_completion(&ts->tx_restart_comp); - init_completion(&ts->rx_start_comp); - init_completion(&ts->tx_start_comp); - sema_init(&ts->ts_activate_sem, 0); - - ts->create_threads = 1; - ts->tx_thread = kthread_run(iscsi_target_tx_thread, ts, "%s", - ISCSI_TX_THREAD_NAME); - if (IS_ERR(ts->tx_thread)) { - dump_stack(); - pr_err("Unable to start iscsi_target_tx_thread\n"); - break; - } - - ts->rx_thread = kthread_run(iscsi_target_rx_thread, ts, "%s", - ISCSI_RX_THREAD_NAME); - if (IS_ERR(ts->rx_thread)) { - kthread_stop(ts->tx_thread); - pr_err("Unable to start iscsi_target_rx_thread\n"); - break; - } - ts->create_threads = 0; - - iscsi_add_ts_to_inactive_list(ts); - allocated_thread_pair_count++; - } - - pr_debug("Spawned %d thread set(s) (%d total threads).\n", - allocated_thread_pair_count, allocated_thread_pair_count * 2); - return allocated_thread_pair_count; -} - -static void iscsi_deallocate_thread_one(struct iscsi_thread_set *ts) -{ - spin_lock_bh(&ts->ts_state_lock); - ts->status = ISCSI_THREAD_SET_DIE; - - if (ts->rx_thread) { - complete(&ts->rx_start_comp); - spin_unlock_bh(&ts->ts_state_lock); - kthread_stop(ts->rx_thread); - spin_lock_bh(&ts->ts_state_lock); - } - if (ts->tx_thread) { - complete(&ts->tx_start_comp); - spin_unlock_bh(&ts->ts_state_lock); - kthread_stop(ts->tx_thread); - spin_lock_bh(&ts->ts_state_lock); - } - spin_unlock_bh(&ts->ts_state_lock); - /* - * Release this thread_id in the thread_set_bitmap - */ - spin_lock(&ts_bitmap_lock); - bitmap_release_region(iscsit_global->ts_bitmap, - ts->thread_id, get_order(1)); - spin_unlock(&ts_bitmap_lock); - - kfree(ts); -} - -void iscsi_deallocate_thread_sets(void) -{ - struct iscsi_thread_set *ts = NULL; - u32 released_count = 0; - - while ((ts = iscsi_get_ts_from_inactive_list())) { - - iscsi_deallocate_thread_one(ts); - released_count++; - } - - if (released_count) - pr_debug("Stopped %d thread set(s) (%d total threads)." - "\n", released_count, released_count * 2); -} - -static void iscsi_deallocate_extra_thread_sets(void) -{ - u32 orig_count, released_count = 0; - struct iscsi_thread_set *ts = NULL; - - orig_count = TARGET_THREAD_SET_COUNT; - - while ((iscsit_global->inactive_ts + 1) > orig_count) { - ts = iscsi_get_ts_from_inactive_list(); - if (!ts) - break; - - iscsi_deallocate_thread_one(ts); - released_count++; - } - - if (released_count) - pr_debug("Stopped %d thread set(s) (%d total threads)." - "\n", released_count, released_count * 2); -} - -void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts) -{ - spin_lock_bh(&ts->ts_state_lock); - conn->thread_set = ts; - ts->conn = conn; - ts->status = ISCSI_THREAD_SET_ACTIVE; - spin_unlock_bh(&ts->ts_state_lock); - - complete(&ts->rx_start_comp); - complete(&ts->tx_start_comp); - - down(&ts->ts_activate_sem); -} - -struct iscsi_thread_set *iscsi_get_thread_set(void) -{ - struct iscsi_thread_set *ts; - -get_set: - ts = iscsi_get_ts_from_inactive_list(); - if (!ts) { - iscsi_allocate_thread_sets(1); - goto get_set; - } - - ts->delay_inactive = 1; - ts->signal_sent = 0; - ts->thread_count = 2; - init_completion(&ts->rx_restart_comp); - init_completion(&ts->tx_restart_comp); - sema_init(&ts->ts_activate_sem, 0); - - return ts; -} - -void iscsi_set_thread_clear(struct iscsi_conn *conn, u8 thread_clear) -{ - struct iscsi_thread_set *ts = NULL; - - if (!conn->thread_set) { - pr_err("struct iscsi_conn->thread_set is NULL\n"); - return; - } - ts = conn->thread_set; - - spin_lock_bh(&ts->ts_state_lock); - ts->thread_clear &= ~thread_clear; - - if ((thread_clear & ISCSI_CLEAR_RX_THREAD) && - (ts->blocked_threads & ISCSI_BLOCK_RX_THREAD)) - complete(&ts->rx_restart_comp); - else if ((thread_clear & ISCSI_CLEAR_TX_THREAD) && - (ts->blocked_threads & ISCSI_BLOCK_TX_THREAD)) - complete(&ts->tx_restart_comp); - spin_unlock_bh(&ts->ts_state_lock); -} - -void iscsi_set_thread_set_signal(struct iscsi_conn *conn, u8 signal_sent) -{ - struct iscsi_thread_set *ts = NULL; - - if (!conn->thread_set) { - pr_err("struct iscsi_conn->thread_set is NULL\n"); - return; - } - ts = conn->thread_set; - - spin_lock_bh(&ts->ts_state_lock); - ts->signal_sent |= signal_sent; - spin_unlock_bh(&ts->ts_state_lock); -} - -int iscsi_release_thread_set(struct iscsi_conn *conn) -{ - int thread_called = 0; - struct iscsi_thread_set *ts = NULL; - - if (!conn || !conn->thread_set) { - pr_err("connection or thread set pointer is NULL\n"); - BUG(); - } - ts = conn->thread_set; - - spin_lock_bh(&ts->ts_state_lock); - ts->status = ISCSI_THREAD_SET_RESET; - - if (!strncmp(current->comm, ISCSI_RX_THREAD_NAME, - strlen(ISCSI_RX_THREAD_NAME))) - thread_called = ISCSI_RX_THREAD; - else if (!strncmp(current->comm, ISCSI_TX_THREAD_NAME, - strlen(ISCSI_TX_THREAD_NAME))) - thread_called = ISCSI_TX_THREAD; - - if (ts->rx_thread && (thread_called == ISCSI_TX_THREAD) && - (ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) { - - if (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD)) { - send_sig(SIGINT, ts->rx_thread, 1); - ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD; - } - ts->blocked_threads |= ISCSI_BLOCK_RX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); - wait_for_completion(&ts->rx_restart_comp); - spin_lock_bh(&ts->ts_state_lock); - ts->blocked_threads &= ~ISCSI_BLOCK_RX_THREAD; - } - if (ts->tx_thread && (thread_called == ISCSI_RX_THREAD) && - (ts->thread_clear & ISCSI_CLEAR_TX_THREAD)) { - - if (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD)) { - send_sig(SIGINT, ts->tx_thread, 1); - ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD; - } - ts->blocked_threads |= ISCSI_BLOCK_TX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); - wait_for_completion(&ts->tx_restart_comp); - spin_lock_bh(&ts->ts_state_lock); - ts->blocked_threads &= ~ISCSI_BLOCK_TX_THREAD; - } - - ts->conn = NULL; - ts->status = ISCSI_THREAD_SET_FREE; - spin_unlock_bh(&ts->ts_state_lock); - - return 0; -} - -int iscsi_thread_set_force_reinstatement(struct iscsi_conn *conn) -{ - struct iscsi_thread_set *ts; - - if (!conn->thread_set) - return -1; - ts = conn->thread_set; - - spin_lock_bh(&ts->ts_state_lock); - if (ts->status != ISCSI_THREAD_SET_ACTIVE) { - spin_unlock_bh(&ts->ts_state_lock); - return -1; - } - - if (ts->tx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD))) { - send_sig(SIGINT, ts->tx_thread, 1); - ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD; - } - if (ts->rx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD))) { - send_sig(SIGINT, ts->rx_thread, 1); - ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD; - } - spin_unlock_bh(&ts->ts_state_lock); - - return 0; -} - -static void iscsi_check_to_add_additional_sets(void) -{ - int thread_sets_add; - - spin_lock(&inactive_ts_lock); - thread_sets_add = iscsit_global->inactive_ts; - spin_unlock(&inactive_ts_lock); - if (thread_sets_add == 1) - iscsi_allocate_thread_sets(1); -} - -static int iscsi_signal_thread_pre_handler(struct iscsi_thread_set *ts) -{ - spin_lock_bh(&ts->ts_state_lock); - if (ts->status == ISCSI_THREAD_SET_DIE || kthread_should_stop() || - signal_pending(current)) { - spin_unlock_bh(&ts->ts_state_lock); - return -1; - } - spin_unlock_bh(&ts->ts_state_lock); - - return 0; -} - -struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *ts) -{ - int ret; - - spin_lock_bh(&ts->ts_state_lock); - if (ts->create_threads) { - spin_unlock_bh(&ts->ts_state_lock); - goto sleep; - } - - if (ts->status != ISCSI_THREAD_SET_DIE) - flush_signals(current); - - if (ts->delay_inactive && (--ts->thread_count == 0)) { - spin_unlock_bh(&ts->ts_state_lock); - - if (!iscsit_global->in_shutdown) - iscsi_deallocate_extra_thread_sets(); - - iscsi_add_ts_to_inactive_list(ts); - spin_lock_bh(&ts->ts_state_lock); - } - - if ((ts->status == ISCSI_THREAD_SET_RESET) && - (ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) - complete(&ts->rx_restart_comp); - - ts->thread_clear &= ~ISCSI_CLEAR_RX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); -sleep: - ret = wait_for_completion_interruptible(&ts->rx_start_comp); - if (ret != 0) - return NULL; - - if (iscsi_signal_thread_pre_handler(ts) < 0) - return NULL; - - iscsi_check_to_add_additional_sets(); - - spin_lock_bh(&ts->ts_state_lock); - if (!ts->conn) { - pr_err("struct iscsi_thread_set->conn is NULL for" - " RX thread_id: %s/%d\n", current->comm, current->pid); - spin_unlock_bh(&ts->ts_state_lock); - return NULL; - } - ts->thread_clear |= ISCSI_CLEAR_RX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); - - up(&ts->ts_activate_sem); - - return ts->conn; -} - -struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *ts) -{ - int ret; - - spin_lock_bh(&ts->ts_state_lock); - if (ts->create_threads) { - spin_unlock_bh(&ts->ts_state_lock); - goto sleep; - } - - if (ts->status != ISCSI_THREAD_SET_DIE) - flush_signals(current); - - if (ts->delay_inactive && (--ts->thread_count == 0)) { - spin_unlock_bh(&ts->ts_state_lock); - - if (!iscsit_global->in_shutdown) - iscsi_deallocate_extra_thread_sets(); - - iscsi_add_ts_to_inactive_list(ts); - spin_lock_bh(&ts->ts_state_lock); - } - if ((ts->status == ISCSI_THREAD_SET_RESET) && - (ts->thread_clear & ISCSI_CLEAR_TX_THREAD)) - complete(&ts->tx_restart_comp); - - ts->thread_clear &= ~ISCSI_CLEAR_TX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); -sleep: - ret = wait_for_completion_interruptible(&ts->tx_start_comp); - if (ret != 0) - return NULL; - - if (iscsi_signal_thread_pre_handler(ts) < 0) - return NULL; - - iscsi_check_to_add_additional_sets(); - - spin_lock_bh(&ts->ts_state_lock); - if (!ts->conn) { - pr_err("struct iscsi_thread_set->conn is NULL for" - " TX thread_id: %s/%d\n", current->comm, current->pid); - spin_unlock_bh(&ts->ts_state_lock); - return NULL; - } - ts->thread_clear |= ISCSI_CLEAR_TX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); - - up(&ts->ts_activate_sem); - - return ts->conn; -} - -int iscsi_thread_set_init(void) -{ - int size; - - iscsit_global->ts_bitmap_count = ISCSI_TS_BITMAP_BITS; - - size = BITS_TO_LONGS(iscsit_global->ts_bitmap_count) * sizeof(long); - iscsit_global->ts_bitmap = kzalloc(size, GFP_KERNEL); - if (!iscsit_global->ts_bitmap) { - pr_err("Unable to allocate iscsit_global->ts_bitmap\n"); - return -ENOMEM; - } - - return 0; -} - -void iscsi_thread_set_free(void) -{ - kfree(iscsit_global->ts_bitmap); -} diff --git a/drivers/target/iscsi/iscsi_target_tq.h b/drivers/target/iscsi/iscsi_target_tq.h deleted file mode 100644 index cc1eede5ab3a..000000000000 --- a/drivers/target/iscsi/iscsi_target_tq.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef ISCSI_THREAD_QUEUE_H -#define ISCSI_THREAD_QUEUE_H - -/* - * Defines for thread sets. - */ -extern int iscsi_thread_set_force_reinstatement(struct iscsi_conn *); -extern int iscsi_allocate_thread_sets(u32); -extern void iscsi_deallocate_thread_sets(void); -extern void iscsi_activate_thread_set(struct iscsi_conn *, struct iscsi_thread_set *); -extern struct iscsi_thread_set *iscsi_get_thread_set(void); -extern void iscsi_set_thread_clear(struct iscsi_conn *, u8); -extern void iscsi_set_thread_set_signal(struct iscsi_conn *, u8); -extern int iscsi_release_thread_set(struct iscsi_conn *); -extern struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *); -extern struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *); -extern int iscsi_thread_set_init(void); -extern void iscsi_thread_set_free(void); - -extern int iscsi_target_tx_thread(void *); -extern int iscsi_target_rx_thread(void *); - -#define TARGET_THREAD_SET_COUNT 4 - -#define ISCSI_RX_THREAD 1 -#define ISCSI_TX_THREAD 2 -#define ISCSI_RX_THREAD_NAME "iscsi_trx" -#define ISCSI_TX_THREAD_NAME "iscsi_ttx" -#define ISCSI_BLOCK_RX_THREAD 0x1 -#define ISCSI_BLOCK_TX_THREAD 0x2 -#define ISCSI_CLEAR_RX_THREAD 0x1 -#define ISCSI_CLEAR_TX_THREAD 0x2 -#define ISCSI_SIGNAL_RX_THREAD 0x1 -#define ISCSI_SIGNAL_TX_THREAD 0x2 - -/* struct iscsi_thread_set->status */ -#define ISCSI_THREAD_SET_FREE 1 -#define ISCSI_THREAD_SET_ACTIVE 2 -#define ISCSI_THREAD_SET_DIE 3 -#define ISCSI_THREAD_SET_RESET 4 -#define ISCSI_THREAD_SET_DEALLOCATE_THREADS 5 - -/* By default allow a maximum of 32K iSCSI connections */ -#define ISCSI_TS_BITMAP_BITS 32768 - -struct iscsi_thread_set { - /* flags used for blocking and restarting sets */ - int blocked_threads; - /* flag for creating threads */ - int create_threads; - /* flag for delaying readding to inactive list */ - int delay_inactive; - /* status for thread set */ - int status; - /* which threads have had signals sent */ - int signal_sent; - /* flag for which threads exited first */ - int thread_clear; - /* Active threads in the thread set */ - int thread_count; - /* Unique thread ID */ - u32 thread_id; - /* pointer to connection if set is active */ - struct iscsi_conn *conn; - /* used for controlling ts state accesses */ - spinlock_t ts_state_lock; - /* used for restarting thread queue */ - struct completion rx_restart_comp; - /* used for restarting thread queue */ - struct completion tx_restart_comp; - /* used for normal unused blocking */ - struct completion rx_start_comp; - /* used for normal unused blocking */ - struct completion tx_start_comp; - /* OS descriptor for rx thread */ - struct task_struct *rx_thread; - /* OS descriptor for tx thread */ - struct task_struct *tx_thread; - /* struct iscsi_thread_set in list list head*/ - struct list_head ts_list; - struct semaphore ts_activate_sem; -}; - -#endif /*** ISCSI_THREAD_QUEUE_H ***/ diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 390df8ed72b2..b18edda3e8af 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -33,7 +33,6 @@ #include "iscsi_target_erl1.h" #include "iscsi_target_erl2.h" #include "iscsi_target_tpg.h" -#include "iscsi_target_tq.h" #include "iscsi_target_util.h" #include "iscsi_target.h" diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index dd0f3abde75d..0e394a031c28 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -20,6 +20,8 @@ #define ISCSIT_MIN_TAGS 16 #define ISCSIT_EXTRA_TAGS 8 #define ISCSIT_TCP_BACKLOG 256 +#define ISCSI_RX_THREAD_NAME "iscsi_trx" +#define ISCSI_TX_THREAD_NAME "iscsi_ttx" /* struct iscsi_node_attrib sanity values */ #define NA_DATAOUT_TIMEOUT 3 @@ -600,8 +602,6 @@ struct iscsi_conn { struct iscsi_tpg_np *tpg_np; /* Pointer to parent session */ struct iscsi_session *sess; - /* Pointer to thread_set in use for this conn's threads */ - struct iscsi_thread_set *thread_set; int bitmap_id; int rx_thread_active; struct task_struct *rx_thread; @@ -877,8 +877,6 @@ struct iscsit_global { u32 auth_id; u32 inactive_ts; #define ISCSIT_BITMAP_BITS 262144 - /* Thread Set bitmap count */ - int ts_bitmap_count; /* Thread Set bitmap pointer */ unsigned long *ts_bitmap; spinlock_t ts_bitmap_lock; -- cgit v1.2.3 From 38b57f82f66dfb21ebe321d71c84c0e3469980c4 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 27 Feb 2015 22:05:21 -0800 Subject: target: Add protected fabric + unprotected device support This patch adds a new target_core_fabric_ops callback for allowing fabric drivers to expose a TPG attribute for signaling when a T10-PI protected fabric wants to function with an un-protected device without T10-PI. This specifically is to allow LIO to perform WRITE_STRIP + READ_INSERT operations when functioning with non T10-PI enabled devices, seperate from any available hw offloads the fabric supports. This is done using a new se_sess->sess_prot_type that is set at fabric session creation time based upon the TPG attribute. It currently cannot be changed for individual sessions after initial creation. Also, update existing target_core_sbc.c code to honor sess_prot_type when setting up cmd->prot_op + cmd->prot_type assignments. (Add unlikely and !! boolean conversion in sbc_check_prot - Sagi) Cc: Martin Petersen Cc: Sagi Grimberg Cc: Christoph Hellwig Cc: Doug Gilbert Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_sbc.c | 44 +++++++++++++++++++++++++--------- drivers/target/target_core_transport.c | 8 +++++++ include/target/target_core_base.h | 1 + include/target/target_core_fabric.h | 8 +++++++ 4 files changed, 50 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 95a7a7444965..9efd1fd985ee 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -581,12 +581,13 @@ sbc_compare_and_write(struct se_cmd *cmd) } static int -sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type, +sbc_set_prot_op_checks(u8 protect, bool fabric_prot, enum target_prot_type prot_type, bool is_write, struct se_cmd *cmd) { if (is_write) { - cmd->prot_op = protect ? TARGET_PROT_DOUT_PASS : - TARGET_PROT_DOUT_INSERT; + cmd->prot_op = fabric_prot ? TARGET_PROT_DOUT_STRIP : + protect ? TARGET_PROT_DOUT_PASS : + TARGET_PROT_DOUT_INSERT; switch (protect) { case 0x0: case 0x3: @@ -610,8 +611,9 @@ sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type, return -EINVAL; } } else { - cmd->prot_op = protect ? TARGET_PROT_DIN_PASS : - TARGET_PROT_DIN_STRIP; + cmd->prot_op = fabric_prot ? TARGET_PROT_DIN_INSERT : + protect ? TARGET_PROT_DIN_PASS : + TARGET_PROT_DIN_STRIP; switch (protect) { case 0x0: case 0x1: @@ -644,11 +646,15 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, u32 sectors, bool is_write) { u8 protect = cdb[1] >> 5; + int sp_ops = cmd->se_sess->sup_prot_ops; + int pi_prot_type = dev->dev_attrib.pi_prot_type; + bool fabric_prot = false; if (!cmd->t_prot_sg || !cmd->t_prot_nents) { - if (protect && !dev->dev_attrib.pi_prot_type) { - pr_err("CDB contains protect bit, but device does not" - " advertise PROTECT=1 feature bit\n"); + if (unlikely(protect && + !dev->dev_attrib.pi_prot_type && !cmd->se_sess->sess_prot_type)) { + pr_err("CDB contains protect bit, but device + fabric does" + " not advertise PROTECT=1 feature bit\n"); return TCM_INVALID_CDB_FIELD; } if (cmd->prot_pto) @@ -669,15 +675,28 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, cmd->reftag_seed = cmd->t_task_lba; break; case TARGET_DIF_TYPE0_PROT: + /* + * See if the fabric supports T10-PI, and the session has been + * configured to allow export PROTECT=1 feature bit with backend + * devices that don't support T10-PI. + */ + fabric_prot = is_write ? + !!(sp_ops & (TARGET_PROT_DOUT_PASS | TARGET_PROT_DOUT_STRIP)) : + !!(sp_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DIN_INSERT)); + + if (fabric_prot && cmd->se_sess->sess_prot_type) { + pi_prot_type = cmd->se_sess->sess_prot_type; + break; + } + /* Fallthrough */ default: return TCM_NO_SENSE; } - if (sbc_set_prot_op_checks(protect, dev->dev_attrib.pi_prot_type, - is_write, cmd)) + if (sbc_set_prot_op_checks(protect, fabric_prot, pi_prot_type, is_write, cmd)) return TCM_INVALID_CDB_FIELD; - cmd->prot_type = dev->dev_attrib.pi_prot_type; + cmd->prot_type = pi_prot_type; cmd->prot_length = dev->prot_length * sectors; /** @@ -1231,6 +1250,9 @@ sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read, unsigned int i, len, left; unsigned int offset = sg_off; + if (!sg) + return; + left = sectors * dev->prot_length; for_each_sg(cmd->t_prot_sg, psg, cmd->t_prot_nents, i) { diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 4a00ed5c1880..aef989e165ed 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -322,10 +322,18 @@ void __transport_register_session( struct se_session *se_sess, void *fabric_sess_ptr) { + struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo; unsigned char buf[PR_REG_ISID_LEN]; se_sess->se_tpg = se_tpg; se_sess->fabric_sess_ptr = fabric_sess_ptr; + /* + * Determine if fabric allows for T10-PI feature bits to be exposed + * to initiators for device backends with !dev->dev_attrib.pi_prot_type + */ + if (tfo->tpg_check_prot_fabric_only) + se_sess->sess_prot_type = tfo->tpg_check_prot_fabric_only(se_tpg); + /* * Used by struct se_node_acl's under ConfigFS to locate active se_session-t * diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 672150b6aaf5..fe25a78fff46 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -616,6 +616,7 @@ struct se_session { unsigned sess_tearing_down:1; u64 sess_bin_isid; enum target_prot_op sup_prot_ops; + enum target_prot_type sess_prot_type; struct se_node_acl *se_node_acl; struct se_portal_group *se_tpg; void *fabric_sess_ptr; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 2f4a2505db4c..c93cfdf0d8e5 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -27,6 +27,14 @@ struct target_core_fabric_ops { * inquiry response */ int (*tpg_check_demo_mode_login_only)(struct se_portal_group *); + /* + * Optionally used as a configfs tunable to determine when + * target-core should signal the PROTECT=1 feature bit for + * backends that don't support T10-PI, so that either fabric + * HW offload or target-core emulation performs the associated + * WRITE_STRIP and READ_INSERT operations. + */ + int (*tpg_check_prot_fabric_only)(struct se_portal_group *); struct se_node_acl *(*tpg_alloc_fabric_acl)( struct se_portal_group *); void (*tpg_release_fabric_acl)(struct se_portal_group *, -- cgit v1.2.3 From 901c04a33f138e5fb935a1621375a1a0997fe7b1 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 29 Mar 2015 19:36:16 -0700 Subject: iscsi/iser-target: Add fabric_prot_type attribute support This patch updates iscsi/iser-target to add a new fabric_prot_type TPG attribute for iser-target, used for controlling LLD level protection into LIO when the backend device does not support T10-PI. This is required for ib_isert to enable WRITE_STRIP + READ_INSERT hardware offloads. It's disabled by default and controls which se_sesion->sess_prot_type are set at iscsi_target_locate_portal() session registration time. Cc: Sagi Grimberg Cc: Martin Petersen Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target_configfs.c | 22 ++++++++++++++++++++++ drivers/target/iscsi/iscsi_target_tpg.c | 19 +++++++++++++++++++ drivers/target/iscsi/iscsi_target_tpg.h | 1 + include/target/iscsi/iscsi_target_core.h | 2 ++ 4 files changed, 44 insertions(+) (limited to 'include') diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 95a67f604073..9cb5ab472a52 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1052,6 +1052,11 @@ TPG_ATTR(default_erl, S_IRUGO | S_IWUSR); */ DEF_TPG_ATTRIB(t10_pi); TPG_ATTR(t10_pi, S_IRUGO | S_IWUSR); +/* + * Define iscsi_tpg_attrib_s_fabric_prot_type + */ +DEF_TPG_ATTRIB(fabric_prot_type); +TPG_ATTR(fabric_prot_type, S_IRUGO | S_IWUSR); static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = { &iscsi_tpg_attrib_authentication.attr, @@ -1065,6 +1070,7 @@ static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = { &iscsi_tpg_attrib_demo_mode_discovery.attr, &iscsi_tpg_attrib_default_erl.attr, &iscsi_tpg_attrib_t10_pi.attr, + &iscsi_tpg_attrib_fabric_prot_type.attr, NULL, }; @@ -1882,6 +1888,20 @@ static int lio_tpg_check_prod_mode_write_protect( return tpg->tpg_attrib.prod_mode_write_protect; } +static int lio_tpg_check_prot_fabric_only( + struct se_portal_group *se_tpg) +{ + struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; + /* + * Only report fabric_prot_type if t10_pi has also been enabled + * for incoming ib_isert sessions. + */ + if (!tpg->tpg_attrib.t10_pi) + return 0; + + return tpg->tpg_attrib.fabric_prot_type; +} + static void lio_tpg_release_fabric_acl( struct se_portal_group *se_tpg, struct se_node_acl *se_acl) @@ -1997,6 +2017,8 @@ int iscsi_target_register_configfs(void) &lio_tpg_check_demo_mode_write_protect; fabric->tf_ops.tpg_check_prod_mode_write_protect = &lio_tpg_check_prod_mode_write_protect; + fabric->tf_ops.tpg_check_prot_fabric_only = + &lio_tpg_check_prot_fabric_only; fabric->tf_ops.tpg_alloc_fabric_acl = &lio_tpg_alloc_fabric_acl; fabric->tf_ops.tpg_release_fabric_acl = &lio_tpg_release_fabric_acl; fabric->tf_ops.tpg_get_inst_index = &lio_tpg_get_inst_index; diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index bdd127c0e3ae..3076e6f3a831 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -228,6 +228,7 @@ static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *tpg) a->demo_mode_discovery = TA_DEMO_MODE_DISCOVERY; a->default_erl = TA_DEFAULT_ERL; a->t10_pi = TA_DEFAULT_T10_PI; + a->fabric_prot_type = TA_DEFAULT_FABRIC_PROT_TYPE; } int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_group *tpg) @@ -878,3 +879,21 @@ int iscsit_ta_t10_pi( return 0; } + +int iscsit_ta_fabric_prot_type( + struct iscsi_portal_group *tpg, + u32 prot_type) +{ + struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; + + if ((prot_type != 0) && (prot_type != 1) && (prot_type != 3)) { + pr_err("Illegal value for fabric_prot_type: %u\n", prot_type); + return -EINVAL; + } + + a->fabric_prot_type = prot_type; + pr_debug("iSCSI_TPG[%hu] - T10 Fabric Protection Type: %u\n", + tpg->tpgt, prot_type); + + return 0; +} diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h index e7265337bc43..95ff5bdecd71 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.h +++ b/drivers/target/iscsi/iscsi_target_tpg.h @@ -39,5 +39,6 @@ extern int iscsit_ta_prod_mode_write_protect(struct iscsi_portal_group *, u32); extern int iscsit_ta_demo_mode_discovery(struct iscsi_portal_group *, u32); extern int iscsit_ta_default_erl(struct iscsi_portal_group *, u32); extern int iscsit_ta_t10_pi(struct iscsi_portal_group *, u32); +extern int iscsit_ta_fabric_prot_type(struct iscsi_portal_group *, u32); #endif /* ISCSI_TARGET_TPG_H */ diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 0e394a031c28..54e7af301888 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -62,6 +62,7 @@ #define TA_CACHE_CORE_NPS 0 /* T10 protection information disabled by default */ #define TA_DEFAULT_T10_PI 0 +#define TA_DEFAULT_FABRIC_PROT_TYPE 0 #define ISCSI_IOV_DATA_BUFFER 5 @@ -772,6 +773,7 @@ struct iscsi_tpg_attrib { u32 demo_mode_discovery; u32 default_erl; u8 t10_pi; + u32 fabric_prot_type; struct iscsi_portal_group *tpg; }; -- cgit v1.2.3 From c3d0a7c21db219ef87679c2a667aba9f138524db Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 7 Apr 2015 19:11:16 +0200 Subject: target: remove the unused SCF_CMD_XCOPY_PASSTHROUGH flag Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_xcopy.c | 4 ++-- include/target/target_core_base.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 04cad3b36297..b09b40e058a0 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -553,7 +553,7 @@ static int target_xcopy_init_pt_lun( * target_xcopy_setup_pt_port() */ if (!remote_port) { - pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH; + pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; return 0; } @@ -561,7 +561,7 @@ static int target_xcopy_init_pt_lun( pt_cmd->se_dev = se_dev; pr_debug("Setup emulated se_dev: %p from se_dev\n", pt_cmd->se_dev); - pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH; + pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; pr_debug("Setup emulated se_dev: %p to pt_cmd->se_lun->lun_se_dev\n", pt_cmd->se_lun->lun_se_dev); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index fe25a78fff46..71699cf3cc71 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -168,7 +168,6 @@ enum se_cmd_flags_table { SCF_ACK_KREF = 0x00040000, SCF_COMPARE_AND_WRITE = 0x00080000, SCF_COMPARE_AND_WRITE_POST = 0x00100000, - SCF_CMD_XCOPY_PASSTHROUGH = 0x00200000, }; /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */ -- cgit v1.2.3 From 9ac8928e6a3e1ed02e632e45aa766129fe6b1802 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 8 Apr 2015 20:01:35 +0200 Subject: target: simplify the target template registration API Instead of calling target_fabric_configfs_init() + target_fabric_configfs_register() / target_fabric_configfs_deregister() target_fabric_configfs_free() from every target driver, rewrite the API so that we have simple register/unregister functions that operate on a const operations vector. This patch also fixes a memory leak in several target drivers. Several target drivers namely called target_fabric_configfs_deregister() without calling target_fabric_configfs_free(). A large part of this patch is based on earlier changes from Bart Van Assche . (v2: Add a new TF_CIT_SETUP_DRV macro so that the core configfs code can declare attributes as either core only or for drivers) Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 79 ++---------- drivers/infiniband/ulp/srpt/ib_srpt.c | 49 ++------ drivers/scsi/qla2xxx/qla_target.c | 2 +- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 118 ++++-------------- drivers/target/iscsi/iscsi_target.c | 23 ++-- drivers/target/iscsi/iscsi_target.h | 2 +- drivers/target/iscsi/iscsi_target_configfs.c | 180 +++++++++------------------ drivers/target/iscsi/iscsi_target_configfs.h | 7 -- drivers/target/iscsi/iscsi_target_tpg.c | 6 +- drivers/target/loopback/tcm_loop.c | 178 ++++++++------------------ drivers/target/sbp/sbp_target.c | 68 ++-------- drivers/target/target_core_configfs.c | 176 +++++++------------------- drivers/target/target_core_fabric_configfs.c | 38 ++++-- drivers/target/target_core_pr.c | 16 +-- drivers/target/target_core_tpg.c | 2 +- drivers/target/target_core_transport.c | 6 +- drivers/target/target_core_xcopy.c | 2 +- drivers/target/tcm_fc/tcm_fc.h | 1 - drivers/target/tcm_fc/tfc_conf.c | 89 ++++--------- drivers/usb/gadget/legacy/tcm_usb_gadget.c | 57 ++------- drivers/vhost/scsi.c | 76 ++--------- drivers/xen/xen-scsiback.c | 74 ++--------- include/target/target_core_base.h | 4 +- include/target/target_core_configfs.h | 6 - include/target/target_core_fabric.h | 24 +++- 25 files changed, 356 insertions(+), 927 deletions(-) delete mode 100644 drivers/target/iscsi/iscsi_target_configfs.h (limited to 'include') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 2b47704f75cb..27afc033761f 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -237,8 +237,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "#include \"" + fabric_mod_name + "_base.h\"\n" buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n" - buf += "/* Local pointer to allocated TCM configfs fabric module */\n" - buf += "struct target_fabric_configfs *" + fabric_mod_name + "_fabric_configfs;\n\n" + buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops;\n\n" buf += "static struct se_node_acl *" + fabric_mod_name + "_make_nodeacl(\n" buf += " struct se_portal_group *se_tpg,\n" @@ -309,8 +308,8 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " }\n" buf += " tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n" buf += " tpg->" + fabric_mod_port + "_tpgt = tpgt;\n\n" - buf += " ret = core_tpg_register(&" + fabric_mod_name + "_fabric_configfs->tf_ops, wwn,\n" - buf += " &tpg->se_tpg, (void *)tpg,\n" + buf += " ret = core_tpg_register(&" + fabric_mod_name + "_ops, wwn,\n" + buf += " &tpg->se_tpg, tpg,\n" buf += " TRANSPORT_TPG_TYPE_NORMAL);\n" buf += " if (ret < 0) {\n" buf += " kfree(tpg);\n" @@ -370,7 +369,10 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " NULL,\n" buf += "};\n\n" - buf += "static struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n" + buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n" + buf += " .module = THIS_MODULE\n", + buf += " .name = " + fabric_mod_name + ",\n" + buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n" buf += " .get_fabric_name = " + fabric_mod_name + "_get_fabric_name,\n" buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n" buf += " .tpg_get_wwn = " + fabric_mod_name + "_get_fabric_wwn,\n" @@ -413,75 +415,18 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " .fabric_drop_np = NULL,\n" buf += " .fabric_make_nodeacl = " + fabric_mod_name + "_make_nodeacl,\n" buf += " .fabric_drop_nodeacl = " + fabric_mod_name + "_drop_nodeacl,\n" - buf += "};\n\n" - - buf += "static int " + fabric_mod_name + "_register_configfs(void)\n" - buf += "{\n" - buf += " struct target_fabric_configfs *fabric;\n" - buf += " int ret;\n\n" - buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + " fabric module %s on %s/%s\"\n" - buf += " \" on \"UTS_RELEASE\"\\n\"," + fabric_mod_name.upper() + "_VERSION, utsname()->sysname,\n" - buf += " utsname()->machine);\n" - buf += " /*\n" - buf += " * Register the top level struct config_item_type with TCM core\n" - buf += " */\n" - buf += " fabric = target_fabric_configfs_init(THIS_MODULE, \"" + fabric_mod_name + "\");\n" - buf += " if (IS_ERR(fabric)) {\n" - buf += " printk(KERN_ERR \"target_fabric_configfs_init() failed\\n\");\n" - buf += " return PTR_ERR(fabric);\n" - buf += " }\n" - buf += " /*\n" - buf += " * Setup fabric->tf_ops from our local " + fabric_mod_name + "_ops\n" - buf += " */\n" - buf += " fabric->tf_ops = " + fabric_mod_name + "_ops;\n" - buf += " /*\n" - buf += " * Setup default attribute lists for various fabric->tf_cit_tmpl\n" - buf += " */\n" - buf += " fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = " + fabric_mod_name + "_wwn_attrs;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = NULL;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;\n" - buf += " fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;\n" - buf += " /*\n" - buf += " * Register the fabric for use within TCM\n" - buf += " */\n" - buf += " ret = target_fabric_configfs_register(fabric);\n" - buf += " if (ret < 0) {\n" - buf += " printk(KERN_ERR \"target_fabric_configfs_register() failed\"\n" - buf += " \" for " + fabric_mod_name.upper() + "\\n\");\n" - buf += " return ret;\n" - buf += " }\n" - buf += " /*\n" - buf += " * Setup our local pointer to *fabric\n" - buf += " */\n" - buf += " " + fabric_mod_name + "_fabric_configfs = fabric;\n" - buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + "[0] - Set fabric -> " + fabric_mod_name + "_fabric_configfs\\n\");\n" - buf += " return 0;\n" - buf += "};\n\n" - buf += "static void __exit " + fabric_mod_name + "_deregister_configfs(void)\n" - buf += "{\n" - buf += " if (!" + fabric_mod_name + "_fabric_configfs)\n" - buf += " return;\n\n" - buf += " target_fabric_configfs_deregister(" + fabric_mod_name + "_fabric_configfs);\n" - buf += " " + fabric_mod_name + "_fabric_configfs = NULL;\n" - buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + "[0] - Cleared " + fabric_mod_name + "_fabric_configfs\\n\");\n" + buf += "\n" + buf += " .tfc_wwn_attrs = " + fabric_mod_name + "_wwn_attrs;\n" buf += "};\n\n" buf += "static int __init " + fabric_mod_name + "_init(void)\n" buf += "{\n" - buf += " int ret;\n\n" - buf += " ret = " + fabric_mod_name + "_register_configfs();\n" - buf += " if (ret < 0)\n" - buf += " return ret;\n\n" - buf += " return 0;\n" + buf += " return target_register_template(" + fabric_mod_name + "_ops);\n" buf += "};\n\n" + buf += "static void __exit " + fabric_mod_name + "_exit(void)\n" buf += "{\n" - buf += " " + fabric_mod_name + "_deregister_configfs();\n" + buf += " target_unregister_template(" + fabric_mod_name + "_ops);\n" buf += "};\n\n" buf += "MODULE_DESCRIPTION(\"" + fabric_mod_name.upper() + " series fabric driver\");\n" diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 6e0a477681e9..07015389ee5a 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -93,7 +93,7 @@ MODULE_PARM_DESC(srpt_service_guid, " instead of using the node_guid of the first HCA."); static struct ib_client srpt_client; -static struct target_fabric_configfs *srpt_target; +static const struct target_core_fabric_ops srpt_template; static void srpt_release_channel(struct srpt_rdma_ch *ch); static int srpt_queue_status(struct se_cmd *cmd); @@ -3851,7 +3851,7 @@ static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn, int res; /* Initialize sport->port_wwn and sport->port_tpg_1 */ - res = core_tpg_register(&srpt_target->tf_ops, &sport->port_wwn, + res = core_tpg_register(&srpt_template, &sport->port_wwn, &sport->port_tpg_1, sport, TRANSPORT_TPG_TYPE_NORMAL); if (res) return ERR_PTR(res); @@ -3919,7 +3919,9 @@ static struct configfs_attribute *srpt_wwn_attrs[] = { NULL, }; -static struct target_core_fabric_ops srpt_template = { +static const struct target_core_fabric_ops srpt_template = { + .module = THIS_MODULE, + .name = "srpt", .get_fabric_name = srpt_get_fabric_name, .get_fabric_proto_ident = srpt_get_fabric_proto_ident, .tpg_get_wwn = srpt_get_fabric_wwn, @@ -3964,6 +3966,10 @@ static struct target_core_fabric_ops srpt_template = { .fabric_drop_np = NULL, .fabric_make_nodeacl = srpt_make_nodeacl, .fabric_drop_nodeacl = srpt_drop_nodeacl, + + .tfc_wwn_attrs = srpt_wwn_attrs, + .tfc_tpg_base_attrs = srpt_tpg_attrs, + .tfc_tpg_attrib_attrs = srpt_tpg_attrib_attrs, }; /** @@ -3994,33 +4000,9 @@ static int __init srpt_init_module(void) goto out; } - srpt_target = target_fabric_configfs_init(THIS_MODULE, "srpt"); - if (IS_ERR(srpt_target)) { - printk(KERN_ERR "couldn't register\n"); - ret = PTR_ERR(srpt_target); + ret = target_register_template(&srpt_template); + if (ret) goto out; - } - - srpt_target->tf_ops = srpt_template; - - /* - * Set up default attribute lists. - */ - srpt_target->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = srpt_wwn_attrs; - srpt_target->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = srpt_tpg_attrs; - srpt_target->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = srpt_tpg_attrib_attrs; - srpt_target->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - srpt_target->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - srpt_target->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; - srpt_target->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - srpt_target->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - srpt_target->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - - ret = target_fabric_configfs_register(srpt_target); - if (ret < 0) { - printk(KERN_ERR "couldn't register\n"); - goto out_free_target; - } ret = ib_register_client(&srpt_client); if (ret) { @@ -4031,11 +4013,7 @@ static int __init srpt_init_module(void) return 0; out_unregister_target: - target_fabric_configfs_deregister(srpt_target); - srpt_target = NULL; -out_free_target: - if (srpt_target) - target_fabric_configfs_free(srpt_target); + target_unregister_template(&srpt_template); out: return ret; } @@ -4043,8 +4021,7 @@ out: static void __exit srpt_cleanup_module(void) { ib_unregister_client(&srpt_client); - target_fabric_configfs_deregister(srpt_target); - srpt_target = NULL; + target_unregister_template(&srpt_template); } module_init(srpt_init_module); diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 57418258c101..fe8a8d157e22 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -3065,7 +3065,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle, { struct qla_hw_data *ha = vha->hw; struct se_cmd *se_cmd; - struct target_core_fabric_ops *tfo; + const struct target_core_fabric_ops *tfo; struct qla_tgt_cmd *cmd; if (handle & CTIO_INTERMEDIATE_HANDLE_MARK) { diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 843b53b0e9f2..acf54cdbca2c 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -53,9 +53,8 @@ static struct workqueue_struct *tcm_qla2xxx_free_wq; static struct workqueue_struct *tcm_qla2xxx_cmd_wq; -/* Local pointer to allocated TCM configfs fabric module */ -static struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs; -static struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs; +static const struct target_core_fabric_ops tcm_qla2xxx_ops; +static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops; /* * Parse WWN. @@ -1177,7 +1176,7 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg( tpg->tpg_attrib.cache_dynamic_acls = 1; tpg->tpg_attrib.demo_mode_login_only = 1; - ret = core_tpg_register(&tcm_qla2xxx_fabric_configfs->tf_ops, wwn, + ret = core_tpg_register(&tcm_qla2xxx_ops, wwn, &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) { kfree(tpg); @@ -1297,7 +1296,7 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg( tpg->tpg_attrib.cache_dynamic_acls = 1; tpg->tpg_attrib.demo_mode_login_only = 1; - ret = core_tpg_register(&tcm_qla2xxx_npiv_fabric_configfs->tf_ops, wwn, + ret = core_tpg_register(&tcm_qla2xxx_npiv_ops, wwn, &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) { kfree(tpg); @@ -1987,7 +1986,9 @@ static struct configfs_attribute *tcm_qla2xxx_wwn_attrs[] = { NULL, }; -static struct target_core_fabric_ops tcm_qla2xxx_ops = { +static const struct target_core_fabric_ops tcm_qla2xxx_ops = { + .module = THIS_MODULE, + .name = "qla2xxx", .get_fabric_name = tcm_qla2xxx_get_fabric_name, .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, @@ -2037,9 +2038,15 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = { .fabric_drop_np = NULL, .fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl, .fabric_drop_nodeacl = tcm_qla2xxx_drop_nodeacl, + + .tfc_wwn_attrs = tcm_qla2xxx_wwn_attrs, + .tfc_tpg_base_attrs = tcm_qla2xxx_tpg_attrs, + .tfc_tpg_attrib_attrs = tcm_qla2xxx_tpg_attrib_attrs, }; -static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { +static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { + .module = THIS_MODULE, + .name = "qla2xxx_npiv", .get_fabric_name = tcm_qla2xxx_npiv_get_fabric_name, .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, @@ -2087,94 +2094,26 @@ static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .fabric_drop_np = NULL, .fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl, .fabric_drop_nodeacl = tcm_qla2xxx_drop_nodeacl, + + .tfc_wwn_attrs = tcm_qla2xxx_wwn_attrs, + .tfc_tpg_base_attrs = tcm_qla2xxx_npiv_tpg_attrs, }; static int tcm_qla2xxx_register_configfs(void) { - struct target_fabric_configfs *fabric, *npiv_fabric; int ret; pr_debug("TCM QLOGIC QLA2XXX fabric module %s on %s/%s on " UTS_RELEASE"\n", TCM_QLA2XXX_VERSION, utsname()->sysname, utsname()->machine); - /* - * Register the top level struct config_item_type with TCM core - */ - fabric = target_fabric_configfs_init(THIS_MODULE, "qla2xxx"); - if (IS_ERR(fabric)) { - pr_err("target_fabric_configfs_init() failed\n"); - return PTR_ERR(fabric); - } - /* - * Setup fabric->tf_ops from our local tcm_qla2xxx_ops - */ - fabric->tf_ops = tcm_qla2xxx_ops; - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - */ - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = tcm_qla2xxx_tpg_attrs; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = - tcm_qla2xxx_tpg_attrib_attrs; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - /* - * Register the fabric for use within TCM - */ - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - pr_err("target_fabric_configfs_register() failed for TCM_QLA2XXX\n"); + + ret = target_register_template(&tcm_qla2xxx_ops); + if (ret) return ret; - } - /* - * Setup our local pointer to *fabric - */ - tcm_qla2xxx_fabric_configfs = fabric; - pr_debug("TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_fabric_configfs\n"); - /* - * Register the top level struct config_item_type for NPIV with TCM core - */ - npiv_fabric = target_fabric_configfs_init(THIS_MODULE, "qla2xxx_npiv"); - if (IS_ERR(npiv_fabric)) { - pr_err("target_fabric_configfs_init() failed\n"); - ret = PTR_ERR(npiv_fabric); + ret = target_register_template(&tcm_qla2xxx_npiv_ops); + if (ret) goto out_fabric; - } - /* - * Setup fabric->tf_ops from our local tcm_qla2xxx_npiv_ops - */ - npiv_fabric->tf_ops = tcm_qla2xxx_npiv_ops; - /* - * Setup default attribute lists for various npiv_fabric->tf_cit_tmpl - */ - npiv_fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs; - npiv_fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = - tcm_qla2xxx_npiv_tpg_attrs; - npiv_fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL; - npiv_fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - npiv_fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; - npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - npiv_fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - /* - * Register the npiv_fabric for use within TCM - */ - ret = target_fabric_configfs_register(npiv_fabric); - if (ret < 0) { - pr_err("target_fabric_configfs_register() failed for TCM_QLA2XXX\n"); - goto out_fabric; - } - /* - * Setup our local pointer to *npiv_fabric - */ - tcm_qla2xxx_npiv_fabric_configfs = npiv_fabric; - pr_debug("TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_npiv_fabric_configfs\n"); tcm_qla2xxx_free_wq = alloc_workqueue("tcm_qla2xxx_free", WQ_MEM_RECLAIM, 0); @@ -2194,9 +2133,9 @@ static int tcm_qla2xxx_register_configfs(void) out_free_wq: destroy_workqueue(tcm_qla2xxx_free_wq); out_fabric_npiv: - target_fabric_configfs_deregister(tcm_qla2xxx_npiv_fabric_configfs); + target_unregister_template(&tcm_qla2xxx_npiv_ops); out_fabric: - target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs); + target_unregister_template(&tcm_qla2xxx_ops); return ret; } @@ -2205,13 +2144,8 @@ static void tcm_qla2xxx_deregister_configfs(void) destroy_workqueue(tcm_qla2xxx_cmd_wq); destroy_workqueue(tcm_qla2xxx_free_wq); - target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs); - tcm_qla2xxx_fabric_configfs = NULL; - pr_debug("TCM_QLA2XXX[0] - Cleared tcm_qla2xxx_fabric_configfs\n"); - - target_fabric_configfs_deregister(tcm_qla2xxx_npiv_fabric_configfs); - tcm_qla2xxx_npiv_fabric_configfs = NULL; - pr_debug("TCM_QLA2XXX[0] - Cleared tcm_qla2xxx_npiv_fabric_configfs\n"); + target_unregister_template(&tcm_qla2xxx_ops); + target_unregister_template(&tcm_qla2xxx_npiv_ops); } static int __init tcm_qla2xxx_init(void) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index cd611e740de7..5d75bb418696 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -33,7 +33,6 @@ #include #include "iscsi_target_parameters.h" #include "iscsi_target_seq_pdu_list.h" -#include "iscsi_target_configfs.h" #include "iscsi_target_datain_values.h" #include "iscsi_target_erl0.h" #include "iscsi_target_erl1.h" @@ -551,8 +550,8 @@ static int __init iscsi_target_init_module(void) idr_init(&tiqn_idr); idr_init(&sess_idr); - ret = iscsi_target_register_configfs(); - if (ret < 0) + ret = target_register_template(&iscsi_ops); + if (ret) goto out; size = BITS_TO_LONGS(ISCSIT_BITMAP_BITS) * sizeof(long); @@ -616,7 +615,10 @@ qr_out: bitmap_out: vfree(iscsit_global->ts_bitmap); configfs_out: - iscsi_target_deregister_configfs(); + /* XXX: this probably wants it to be it's own unwind step.. */ + if (iscsit_global->discovery_tpg) + iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1); + target_unregister_template(&iscsi_ops); out: kfree(iscsit_global); return -ENOMEM; @@ -631,7 +633,13 @@ static void __exit iscsi_target_cleanup_module(void) kmem_cache_destroy(lio_ooo_cache); kmem_cache_destroy(lio_r2t_cache); - iscsi_target_deregister_configfs(); + /* + * Shutdown discovery sessions and disable discovery TPG + */ + if (iscsit_global->discovery_tpg) + iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1); + + target_unregister_template(&iscsi_ops); vfree(iscsit_global->ts_bitmap); kfree(iscsit_global); @@ -983,7 +991,7 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, /* * Initialize struct se_cmd descriptor from target_core_mod infrastructure */ - transport_init_se_cmd(&cmd->se_cmd, &lio_target_fabric_configfs->tf_ops, + transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops, conn->sess->se_sess, be32_to_cpu(hdr->data_length), cmd->data_direction, sam_task_attr, cmd->sense_buffer + 2); @@ -1798,8 +1806,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, u8 tcm_function; int ret; - transport_init_se_cmd(&cmd->se_cmd, - &lio_target_fabric_configfs->tf_ops, + transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops, conn->sess->se_sess, 0, DMA_NONE, TCM_SIMPLE_TAG, cmd->sense_buffer + 2); diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h index e936d56fb523..7d0f9c00d9c2 100644 --- a/drivers/target/iscsi/iscsi_target.h +++ b/drivers/target/iscsi/iscsi_target.h @@ -35,7 +35,7 @@ extern void iscsit_stop_session(struct iscsi_session *, int, int); extern int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *, int); extern struct iscsit_global *iscsit_global; -extern struct target_fabric_configfs *lio_target_fabric_configfs; +extern const struct target_core_fabric_ops iscsi_ops; extern struct kmem_cache *lio_dr_cache; extern struct kmem_cache *lio_ooo_cache; diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 9cb5ab472a52..469fce44ebad 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -37,9 +37,6 @@ #include "iscsi_target_util.h" #include "iscsi_target.h" #include -#include "iscsi_target_configfs.h" - -struct target_fabric_configfs *lio_target_fabric_configfs; struct lio_target_configfs_attribute { struct configfs_attribute attr; @@ -1466,10 +1463,8 @@ static struct se_portal_group *lio_target_tiqn_addtpg( if (!tpg) return NULL; - ret = core_tpg_register( - &lio_target_fabric_configfs->tf_ops, - wwn, &tpg->tpg_se_tpg, tpg, - TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&iscsi_ops, wwn, &tpg->tpg_se_tpg, + tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) return NULL; @@ -1983,117 +1978,60 @@ static void lio_release_cmd(struct se_cmd *se_cmd) iscsit_release_cmd(cmd); } -/* End functions for target_core_fabric_ops */ - -int iscsi_target_register_configfs(void) -{ - struct target_fabric_configfs *fabric; - int ret; - - lio_target_fabric_configfs = NULL; - fabric = target_fabric_configfs_init(THIS_MODULE, "iscsi"); - if (IS_ERR(fabric)) { - pr_err("target_fabric_configfs_init() for" - " LIO-Target failed!\n"); - return PTR_ERR(fabric); - } - /* - * Setup the fabric API of function pointers used by target_core_mod.. - */ - fabric->tf_ops.get_fabric_name = &iscsi_get_fabric_name; - fabric->tf_ops.get_fabric_proto_ident = &iscsi_get_fabric_proto_ident; - fabric->tf_ops.tpg_get_wwn = &lio_tpg_get_endpoint_wwn; - fabric->tf_ops.tpg_get_tag = &lio_tpg_get_tag; - fabric->tf_ops.tpg_get_default_depth = &lio_tpg_get_default_depth; - fabric->tf_ops.tpg_get_pr_transport_id = &iscsi_get_pr_transport_id; - fabric->tf_ops.tpg_get_pr_transport_id_len = - &iscsi_get_pr_transport_id_len; - fabric->tf_ops.tpg_parse_pr_out_transport_id = - &iscsi_parse_pr_out_transport_id; - fabric->tf_ops.tpg_check_demo_mode = &lio_tpg_check_demo_mode; - fabric->tf_ops.tpg_check_demo_mode_cache = - &lio_tpg_check_demo_mode_cache; - fabric->tf_ops.tpg_check_demo_mode_write_protect = - &lio_tpg_check_demo_mode_write_protect; - fabric->tf_ops.tpg_check_prod_mode_write_protect = - &lio_tpg_check_prod_mode_write_protect; - fabric->tf_ops.tpg_check_prot_fabric_only = - &lio_tpg_check_prot_fabric_only; - fabric->tf_ops.tpg_alloc_fabric_acl = &lio_tpg_alloc_fabric_acl; - fabric->tf_ops.tpg_release_fabric_acl = &lio_tpg_release_fabric_acl; - fabric->tf_ops.tpg_get_inst_index = &lio_tpg_get_inst_index; - fabric->tf_ops.check_stop_free = &lio_check_stop_free, - fabric->tf_ops.release_cmd = &lio_release_cmd; - fabric->tf_ops.shutdown_session = &lio_tpg_shutdown_session; - fabric->tf_ops.close_session = &lio_tpg_close_session; - fabric->tf_ops.sess_get_index = &lio_sess_get_index; - fabric->tf_ops.sess_get_initiator_sid = &lio_sess_get_initiator_sid; - fabric->tf_ops.write_pending = &lio_write_pending; - fabric->tf_ops.write_pending_status = &lio_write_pending_status; - fabric->tf_ops.set_default_node_attributes = - &lio_set_default_node_attributes; - fabric->tf_ops.get_task_tag = &iscsi_get_task_tag; - fabric->tf_ops.get_cmd_state = &iscsi_get_cmd_state; - fabric->tf_ops.queue_data_in = &lio_queue_data_in; - fabric->tf_ops.queue_status = &lio_queue_status; - fabric->tf_ops.queue_tm_rsp = &lio_queue_tm_rsp; - fabric->tf_ops.aborted_task = &lio_aborted_task; - /* - * Setup function pointers for generic logic in target_core_fabric_configfs.c - */ - fabric->tf_ops.fabric_make_wwn = &lio_target_call_coreaddtiqn; - fabric->tf_ops.fabric_drop_wwn = &lio_target_call_coredeltiqn; - fabric->tf_ops.fabric_make_tpg = &lio_target_tiqn_addtpg; - fabric->tf_ops.fabric_drop_tpg = &lio_target_tiqn_deltpg; - fabric->tf_ops.fabric_post_link = NULL; - fabric->tf_ops.fabric_pre_unlink = NULL; - fabric->tf_ops.fabric_make_np = &lio_target_call_addnptotpg; - fabric->tf_ops.fabric_drop_np = &lio_target_call_delnpfromtpg; - fabric->tf_ops.fabric_make_nodeacl = &lio_target_make_nodeacl; - fabric->tf_ops.fabric_drop_nodeacl = &lio_target_drop_nodeacl; - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - * sturct config_item_type's - */ - fabric->tf_cit_tmpl.tfc_discovery_cit.ct_attrs = lio_target_discovery_auth_attrs; - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = lio_target_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = lio_target_tpg_attrs; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = lio_target_tpg_attrib_attrs; - fabric->tf_cit_tmpl.tfc_tpg_auth_cit.ct_attrs = lio_target_tpg_auth_attrs; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = lio_target_tpg_param_attrs; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = lio_target_portal_attrs; - fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = lio_target_initiator_attrs; - fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = lio_target_nacl_attrib_attrs; - fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = lio_target_nacl_auth_attrs; - fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = lio_target_nacl_param_attrs; - - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - pr_err("target_fabric_configfs_register() for" - " LIO-Target failed!\n"); - target_fabric_configfs_free(fabric); - return ret; - } - - lio_target_fabric_configfs = fabric; - pr_debug("LIO_TARGET[0] - Set fabric ->" - " lio_target_fabric_configfs\n"); - return 0; -} - - -void iscsi_target_deregister_configfs(void) -{ - if (!lio_target_fabric_configfs) - return; - /* - * Shutdown discovery sessions and disable discovery TPG - */ - if (iscsit_global->discovery_tpg) - iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1); - - target_fabric_configfs_deregister(lio_target_fabric_configfs); - lio_target_fabric_configfs = NULL; - pr_debug("LIO_TARGET[0] - Cleared" - " lio_target_fabric_configfs\n"); -} +const struct target_core_fabric_ops iscsi_ops = { + .module = THIS_MODULE, + .name = "iscsi", + .get_fabric_name = iscsi_get_fabric_name, + .get_fabric_proto_ident = iscsi_get_fabric_proto_ident, + .tpg_get_wwn = lio_tpg_get_endpoint_wwn, + .tpg_get_tag = lio_tpg_get_tag, + .tpg_get_default_depth = lio_tpg_get_default_depth, + .tpg_get_pr_transport_id = iscsi_get_pr_transport_id, + .tpg_get_pr_transport_id_len = iscsi_get_pr_transport_id_len, + .tpg_parse_pr_out_transport_id = iscsi_parse_pr_out_transport_id, + .tpg_check_demo_mode = lio_tpg_check_demo_mode, + .tpg_check_demo_mode_cache = lio_tpg_check_demo_mode_cache, + .tpg_check_demo_mode_write_protect = + lio_tpg_check_demo_mode_write_protect, + .tpg_check_prod_mode_write_protect = + lio_tpg_check_prod_mode_write_protect, + .tpg_check_prot_fabric_only = &lio_tpg_check_prot_fabric_only, + .tpg_alloc_fabric_acl = lio_tpg_alloc_fabric_acl, + .tpg_release_fabric_acl = lio_tpg_release_fabric_acl, + .tpg_get_inst_index = lio_tpg_get_inst_index, + .check_stop_free = lio_check_stop_free, + .release_cmd = lio_release_cmd, + .shutdown_session = lio_tpg_shutdown_session, + .close_session = lio_tpg_close_session, + .sess_get_index = lio_sess_get_index, + .sess_get_initiator_sid = lio_sess_get_initiator_sid, + .write_pending = lio_write_pending, + .write_pending_status = lio_write_pending_status, + .set_default_node_attributes = lio_set_default_node_attributes, + .get_task_tag = iscsi_get_task_tag, + .get_cmd_state = iscsi_get_cmd_state, + .queue_data_in = lio_queue_data_in, + .queue_status = lio_queue_status, + .queue_tm_rsp = lio_queue_tm_rsp, + .aborted_task = lio_aborted_task, + .fabric_make_wwn = lio_target_call_coreaddtiqn, + .fabric_drop_wwn = lio_target_call_coredeltiqn, + .fabric_make_tpg = lio_target_tiqn_addtpg, + .fabric_drop_tpg = lio_target_tiqn_deltpg, + .fabric_make_np = lio_target_call_addnptotpg, + .fabric_drop_np = lio_target_call_delnpfromtpg, + .fabric_make_nodeacl = lio_target_make_nodeacl, + .fabric_drop_nodeacl = lio_target_drop_nodeacl, + + .tfc_discovery_attrs = lio_target_discovery_auth_attrs, + .tfc_wwn_attrs = lio_target_wwn_attrs, + .tfc_tpg_base_attrs = lio_target_tpg_attrs, + .tfc_tpg_attrib_attrs = lio_target_tpg_attrib_attrs, + .tfc_tpg_auth_attrs = lio_target_tpg_auth_attrs, + .tfc_tpg_param_attrs = lio_target_tpg_param_attrs, + .tfc_tpg_np_base_attrs = lio_target_portal_attrs, + .tfc_tpg_nacl_base_attrs = lio_target_initiator_attrs, + .tfc_tpg_nacl_attrib_attrs = lio_target_nacl_attrib_attrs, + .tfc_tpg_nacl_auth_attrs = lio_target_nacl_auth_attrs, + .tfc_tpg_nacl_param_attrs = lio_target_nacl_param_attrs, +}; diff --git a/drivers/target/iscsi/iscsi_target_configfs.h b/drivers/target/iscsi/iscsi_target_configfs.h deleted file mode 100644 index 8cd5a63c4edc..000000000000 --- a/drivers/target/iscsi/iscsi_target_configfs.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef ISCSI_TARGET_CONFIGFS_H -#define ISCSI_TARGET_CONFIGFS_H - -extern int iscsi_target_register_configfs(void); -extern void iscsi_target_deregister_configfs(void); - -#endif /* ISCSI_TARGET_CONFIGFS_H */ diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 3076e6f3a831..e8a240818353 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -68,10 +68,8 @@ int iscsit_load_discovery_tpg(void) return -1; } - ret = core_tpg_register( - &lio_target_fabric_configfs->tf_ops, - NULL, &tpg->tpg_se_tpg, tpg, - TRANSPORT_TPG_TYPE_DISCOVERY); + ret = core_tpg_register(&iscsi_ops, NULL, &tpg->tpg_se_tpg, + tpg, TRANSPORT_TPG_TYPE_DISCOVERY); if (ret < 0) { kfree(tpg); return -1; diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 2114c1d2c9de..5b143d2c08f7 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -41,8 +41,7 @@ #define to_tcm_loop_hba(hba) container_of(hba, struct tcm_loop_hba, dev) -/* Local pointer to allocated TCM configfs fabric module */ -static struct target_fabric_configfs *tcm_loop_fabric_configfs; +static const struct target_core_fabric_ops loop_ops; static struct workqueue_struct *tcm_loop_workqueue; static struct kmem_cache *tcm_loop_cmd_cache; @@ -1238,8 +1237,7 @@ static struct se_portal_group *tcm_loop_make_naa_tpg( /* * Register the tl_tpg as a emulated SAS TCM Target Endpoint */ - ret = core_tpg_register(&tcm_loop_fabric_configfs->tf_ops, - wwn, &tl_tpg->tl_se_tpg, tl_tpg, + ret = core_tpg_register(&loop_ops, wwn, &tl_tpg->tl_se_tpg, tl_tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) return ERR_PTR(-ENOMEM); @@ -1387,129 +1385,51 @@ static struct configfs_attribute *tcm_loop_wwn_attrs[] = { /* End items for tcm_loop_cit */ -static int tcm_loop_register_configfs(void) -{ - struct target_fabric_configfs *fabric; - int ret; - /* - * Set the TCM Loop HBA counter to zero - */ - tcm_loop_hba_no_cnt = 0; - /* - * Register the top level struct config_item_type with TCM core - */ - fabric = target_fabric_configfs_init(THIS_MODULE, "loopback"); - if (IS_ERR(fabric)) { - pr_err("tcm_loop_register_configfs() failed!\n"); - return PTR_ERR(fabric); - } - /* - * Setup the fabric API of function pointers used by target_core_mod - */ - fabric->tf_ops.get_fabric_name = &tcm_loop_get_fabric_name; - fabric->tf_ops.get_fabric_proto_ident = &tcm_loop_get_fabric_proto_ident; - fabric->tf_ops.tpg_get_wwn = &tcm_loop_get_endpoint_wwn; - fabric->tf_ops.tpg_get_tag = &tcm_loop_get_tag; - fabric->tf_ops.tpg_get_default_depth = &tcm_loop_get_default_depth; - fabric->tf_ops.tpg_get_pr_transport_id = &tcm_loop_get_pr_transport_id; - fabric->tf_ops.tpg_get_pr_transport_id_len = - &tcm_loop_get_pr_transport_id_len; - fabric->tf_ops.tpg_parse_pr_out_transport_id = - &tcm_loop_parse_pr_out_transport_id; - fabric->tf_ops.tpg_check_demo_mode = &tcm_loop_check_demo_mode; - fabric->tf_ops.tpg_check_demo_mode_cache = - &tcm_loop_check_demo_mode_cache; - fabric->tf_ops.tpg_check_demo_mode_write_protect = - &tcm_loop_check_demo_mode_write_protect; - fabric->tf_ops.tpg_check_prod_mode_write_protect = - &tcm_loop_check_prod_mode_write_protect; - fabric->tf_ops.tpg_check_prot_fabric_only = - &tcm_loop_check_prot_fabric_only; - /* - * The TCM loopback fabric module runs in demo-mode to a local - * virtual SCSI device, so fabric dependent initator ACLs are - * not required. - */ - fabric->tf_ops.tpg_alloc_fabric_acl = &tcm_loop_tpg_alloc_fabric_acl; - fabric->tf_ops.tpg_release_fabric_acl = - &tcm_loop_tpg_release_fabric_acl; - fabric->tf_ops.tpg_get_inst_index = &tcm_loop_get_inst_index; - /* - * Used for setting up remaining TCM resources in process context - */ - fabric->tf_ops.check_stop_free = &tcm_loop_check_stop_free; - fabric->tf_ops.release_cmd = &tcm_loop_release_cmd; - fabric->tf_ops.shutdown_session = &tcm_loop_shutdown_session; - fabric->tf_ops.close_session = &tcm_loop_close_session; - fabric->tf_ops.sess_get_index = &tcm_loop_sess_get_index; - fabric->tf_ops.sess_get_initiator_sid = NULL; - fabric->tf_ops.write_pending = &tcm_loop_write_pending; - fabric->tf_ops.write_pending_status = &tcm_loop_write_pending_status; - /* - * Not used for TCM loopback - */ - fabric->tf_ops.set_default_node_attributes = - &tcm_loop_set_default_node_attributes; - fabric->tf_ops.get_task_tag = &tcm_loop_get_task_tag; - fabric->tf_ops.get_cmd_state = &tcm_loop_get_cmd_state; - fabric->tf_ops.queue_data_in = &tcm_loop_queue_data_in; - fabric->tf_ops.queue_status = &tcm_loop_queue_status; - fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp; - fabric->tf_ops.aborted_task = &tcm_loop_aborted_task; - - /* - * Setup function pointers for generic logic in target_core_fabric_configfs.c - */ - fabric->tf_ops.fabric_make_wwn = &tcm_loop_make_scsi_hba; - fabric->tf_ops.fabric_drop_wwn = &tcm_loop_drop_scsi_hba; - fabric->tf_ops.fabric_make_tpg = &tcm_loop_make_naa_tpg; - fabric->tf_ops.fabric_drop_tpg = &tcm_loop_drop_naa_tpg; - /* - * fabric_post_link() and fabric_pre_unlink() are used for - * registration and release of TCM Loop Virtual SCSI LUNs. - */ - fabric->tf_ops.fabric_post_link = &tcm_loop_port_link; - fabric->tf_ops.fabric_pre_unlink = &tcm_loop_port_unlink; - fabric->tf_ops.fabric_make_np = NULL; - fabric->tf_ops.fabric_drop_np = NULL; - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - */ - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_loop_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = tcm_loop_tpg_attrs; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = tcm_loop_tpg_attrib_attrs; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - /* - * Once fabric->tf_ops has been setup, now register the fabric for - * use within TCM - */ - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - pr_err("target_fabric_configfs_register() for" - " TCM_Loop failed!\n"); - target_fabric_configfs_free(fabric); - return -1; - } - /* - * Setup our local pointer to *fabric. - */ - tcm_loop_fabric_configfs = fabric; - pr_debug("TCM_LOOP[0] - Set fabric ->" - " tcm_loop_fabric_configfs\n"); - return 0; -} - -static void tcm_loop_deregister_configfs(void) -{ - if (!tcm_loop_fabric_configfs) - return; - - target_fabric_configfs_deregister(tcm_loop_fabric_configfs); - tcm_loop_fabric_configfs = NULL; - pr_debug("TCM_LOOP[0] - Cleared" - " tcm_loop_fabric_configfs\n"); -} +static const struct target_core_fabric_ops loop_ops = { + .module = THIS_MODULE, + .name = "loopback", + .get_fabric_name = tcm_loop_get_fabric_name, + .get_fabric_proto_ident = tcm_loop_get_fabric_proto_ident, + .tpg_get_wwn = tcm_loop_get_endpoint_wwn, + .tpg_get_tag = tcm_loop_get_tag, + .tpg_get_default_depth = tcm_loop_get_default_depth, + .tpg_get_pr_transport_id = tcm_loop_get_pr_transport_id, + .tpg_get_pr_transport_id_len = tcm_loop_get_pr_transport_id_len, + .tpg_parse_pr_out_transport_id = tcm_loop_parse_pr_out_transport_id, + .tpg_check_demo_mode = tcm_loop_check_demo_mode, + .tpg_check_demo_mode_cache = tcm_loop_check_demo_mode_cache, + .tpg_check_demo_mode_write_protect = + tcm_loop_check_demo_mode_write_protect, + .tpg_check_prod_mode_write_protect = + tcm_loop_check_prod_mode_write_protect, + .tpg_check_prot_fabric_only = tcm_loop_check_prot_fabric_only, + .tpg_alloc_fabric_acl = tcm_loop_tpg_alloc_fabric_acl, + .tpg_release_fabric_acl = tcm_loop_tpg_release_fabric_acl, + .tpg_get_inst_index = tcm_loop_get_inst_index, + .check_stop_free = tcm_loop_check_stop_free, + .release_cmd = tcm_loop_release_cmd, + .shutdown_session = tcm_loop_shutdown_session, + .close_session = tcm_loop_close_session, + .sess_get_index = tcm_loop_sess_get_index, + .write_pending = tcm_loop_write_pending, + .write_pending_status = tcm_loop_write_pending_status, + .set_default_node_attributes = tcm_loop_set_default_node_attributes, + .get_task_tag = tcm_loop_get_task_tag, + .get_cmd_state = tcm_loop_get_cmd_state, + .queue_data_in = tcm_loop_queue_data_in, + .queue_status = tcm_loop_queue_status, + .queue_tm_rsp = tcm_loop_queue_tm_rsp, + .aborted_task = tcm_loop_aborted_task, + .fabric_make_wwn = tcm_loop_make_scsi_hba, + .fabric_drop_wwn = tcm_loop_drop_scsi_hba, + .fabric_make_tpg = tcm_loop_make_naa_tpg, + .fabric_drop_tpg = tcm_loop_drop_naa_tpg, + .fabric_post_link = tcm_loop_port_link, + .fabric_pre_unlink = tcm_loop_port_unlink, + .tfc_wwn_attrs = tcm_loop_wwn_attrs, + .tfc_tpg_base_attrs = tcm_loop_tpg_attrs, + .tfc_tpg_attrib_attrs = tcm_loop_tpg_attrib_attrs, +}; static int __init tcm_loop_fabric_init(void) { @@ -1533,7 +1453,7 @@ static int __init tcm_loop_fabric_init(void) if (ret) goto out_destroy_cache; - ret = tcm_loop_register_configfs(); + ret = target_register_template(&loop_ops); if (ret) goto out_release_core_bus; @@ -1551,7 +1471,7 @@ out: static void __exit tcm_loop_fabric_exit(void) { - tcm_loop_deregister_configfs(); + target_unregister_template(&loop_ops); tcm_loop_release_core_bus(); kmem_cache_destroy(tcm_loop_cmd_cache); destroy_workqueue(tcm_loop_workqueue); diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 9512af6a8114..18b0f9703ff2 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -42,8 +42,7 @@ #include "sbp_target.h" -/* Local pointer to allocated TCM configfs fabric module */ -static struct target_fabric_configfs *sbp_fabric_configfs; +static const struct target_core_fabric_ops sbp_ops; /* FireWire address region for management and command block address handlers */ static const struct fw_address_region sbp_register_region = { @@ -2215,8 +2214,7 @@ static struct se_portal_group *sbp_make_tpg( goto out_free_tpg; } - ret = core_tpg_register(&sbp_fabric_configfs->tf_ops, wwn, - &tpg->se_tpg, (void *)tpg, + ret = core_tpg_register(&sbp_ops, wwn, &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) goto out_unreg_mgt_agt; @@ -2503,7 +2501,9 @@ static struct configfs_attribute *sbp_tpg_attrib_attrs[] = { NULL, }; -static struct target_core_fabric_ops sbp_ops = { +static const struct target_core_fabric_ops sbp_ops = { + .module = THIS_MODULE, + .name = "sbp", .get_fabric_name = sbp_get_fabric_name, .get_fabric_proto_ident = sbp_get_fabric_proto_ident, .tpg_get_wwn = sbp_get_fabric_wwn, @@ -2544,68 +2544,20 @@ static struct target_core_fabric_ops sbp_ops = { .fabric_drop_np = NULL, .fabric_make_nodeacl = sbp_make_nodeacl, .fabric_drop_nodeacl = sbp_drop_nodeacl, -}; - -static int sbp_register_configfs(void) -{ - struct target_fabric_configfs *fabric; - int ret; - - fabric = target_fabric_configfs_init(THIS_MODULE, "sbp"); - if (IS_ERR(fabric)) { - pr_err("target_fabric_configfs_init() failed\n"); - return PTR_ERR(fabric); - } - - fabric->tf_ops = sbp_ops; - - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - */ - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = sbp_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = sbp_tpg_base_attrs; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = sbp_tpg_attrib_attrs; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - pr_err("target_fabric_configfs_register() failed for SBP\n"); - return ret; - } - sbp_fabric_configfs = fabric; - - return 0; -}; - -static void sbp_deregister_configfs(void) -{ - if (!sbp_fabric_configfs) - return; - - target_fabric_configfs_deregister(sbp_fabric_configfs); - sbp_fabric_configfs = NULL; + .tfc_wwn_attrs = sbp_wwn_attrs, + .tfc_tpg_base_attrs = sbp_tpg_base_attrs, + .tfc_tpg_attrib_attrs = sbp_tpg_attrib_attrs, }; static int __init sbp_init(void) { - int ret; - - ret = sbp_register_configfs(); - if (ret < 0) - return ret; - - return 0; + return target_register_template(&sbp_ops); }; static void __exit sbp_exit(void) { - sbp_deregister_configfs(); + target_unregister_template(&sbp_ops); }; MODULE_DESCRIPTION("FireWire SBP fabric driver"); diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 69baf1c53d99..ddaf76a4ac2a 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -300,81 +300,17 @@ struct configfs_subsystem *target_core_subsystem[] = { // Start functions called by external Target Fabrics Modules //############################################################################*/ -/* - * First function called by fabric modules to: - * - * 1) Allocate a struct target_fabric_configfs and save the *fabric_cit pointer. - * 2) Add struct target_fabric_configfs to g_tf_list - * 3) Return struct target_fabric_configfs to fabric module to be passed - * into target_fabric_configfs_register(). - */ -struct target_fabric_configfs *target_fabric_configfs_init( - struct module *fabric_mod, - const char *name) +static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo) { - struct target_fabric_configfs *tf; - - if (!(name)) { - pr_err("Unable to locate passed fabric name\n"); - return ERR_PTR(-EINVAL); + if (!tfo->name) { + pr_err("Missing tfo->name\n"); + return -EINVAL; } - if (strlen(name) >= TARGET_FABRIC_NAME_SIZE) { + if (strlen(tfo->name) >= TARGET_FABRIC_NAME_SIZE) { pr_err("Passed name: %s exceeds TARGET_FABRIC" - "_NAME_SIZE\n", name); - return ERR_PTR(-EINVAL); + "_NAME_SIZE\n", tfo->name); + return -EINVAL; } - - tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL); - if (!tf) - return ERR_PTR(-ENOMEM); - - INIT_LIST_HEAD(&tf->tf_list); - atomic_set(&tf->tf_access_cnt, 0); - /* - * Setup the default generic struct config_item_type's (cits) in - * struct target_fabric_configfs->tf_cit_tmpl - */ - tf->tf_module = fabric_mod; - target_fabric_setup_cits(tf); - - tf->tf_subsys = target_core_subsystem[0]; - snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", name); - - mutex_lock(&g_tf_lock); - list_add_tail(&tf->tf_list, &g_tf_list); - mutex_unlock(&g_tf_lock); - - pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>" - ">>>>>>>>>>>>>>\n"); - pr_debug("Initialized struct target_fabric_configfs: %p for" - " %s\n", tf, tf->tf_name); - return tf; -} -EXPORT_SYMBOL(target_fabric_configfs_init); - -/* - * Called by fabric plugins after FAILED target_fabric_configfs_register() call. - */ -void target_fabric_configfs_free( - struct target_fabric_configfs *tf) -{ - mutex_lock(&g_tf_lock); - list_del(&tf->tf_list); - mutex_unlock(&g_tf_lock); - - kfree(tf); -} -EXPORT_SYMBOL(target_fabric_configfs_free); - -/* - * Perform a sanity check of the passed tf->tf_ops before completing - * TCM fabric module registration. - */ -static int target_fabric_tf_ops_check( - struct target_fabric_configfs *tf) -{ - struct target_core_fabric_ops *tfo = &tf->tf_ops; - if (!tfo->get_fabric_name) { pr_err("Missing tfo->get_fabric_name()\n"); return -EINVAL; @@ -508,77 +444,59 @@ static int target_fabric_tf_ops_check( return 0; } -/* - * Called 2nd from fabric module with returned parameter of - * struct target_fabric_configfs * from target_fabric_configfs_init(). - * - * Upon a successful registration, the new fabric's struct config_item is - * return. Also, a pointer to this struct is set in the passed - * struct target_fabric_configfs. - */ -int target_fabric_configfs_register( - struct target_fabric_configfs *tf) +int target_register_template(const struct target_core_fabric_ops *fo) { + struct target_fabric_configfs *tf; int ret; + ret = target_fabric_tf_ops_check(fo); + if (ret) + return ret; + + tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL); if (!tf) { - pr_err("Unable to locate target_fabric_configfs" - " pointer\n"); - return -EINVAL; - } - if (!tf->tf_subsys) { - pr_err("Unable to target struct config_subsystem" - " pointer\n"); - return -EINVAL; + pr_err("%s: could not allocate memory!\n", __func__); + return -ENOMEM; } - ret = target_fabric_tf_ops_check(tf); - if (ret < 0) - return ret; - pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>" - ">>>>>>>>>>\n"); + INIT_LIST_HEAD(&tf->tf_list); + atomic_set(&tf->tf_access_cnt, 0); + + /* + * Setup the default generic struct config_item_type's (cits) in + * struct target_fabric_configfs->tf_cit_tmpl + */ + tf->tf_module = fo->module; + tf->tf_subsys = target_core_subsystem[0]; + snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", fo->name); + + tf->tf_ops = *fo; + target_fabric_setup_cits(tf); + + mutex_lock(&g_tf_lock); + list_add_tail(&tf->tf_list, &g_tf_list); + mutex_unlock(&g_tf_lock); + return 0; } -EXPORT_SYMBOL(target_fabric_configfs_register); +EXPORT_SYMBOL(target_register_template); -void target_fabric_configfs_deregister( - struct target_fabric_configfs *tf) +void target_unregister_template(const struct target_core_fabric_ops *fo) { - struct configfs_subsystem *su; + struct target_fabric_configfs *t; - if (!tf) { - pr_err("Unable to locate passed target_fabric_" - "configfs\n"); - return; - } - su = tf->tf_subsys; - if (!su) { - pr_err("Unable to locate passed tf->tf_subsys" - " pointer\n"); - return; - } - pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>>>" - ">>>>>>>>>>>>\n"); mutex_lock(&g_tf_lock); - if (atomic_read(&tf->tf_access_cnt)) { - mutex_unlock(&g_tf_lock); - pr_err("Non zero tf->tf_access_cnt for fabric %s\n", - tf->tf_name); - BUG(); + list_for_each_entry(t, &g_tf_list, tf_list) { + if (!strcmp(t->tf_name, fo->name)) { + BUG_ON(atomic_read(&t->tf_access_cnt)); + list_del(&t->tf_list); + kfree(t); + break; + } } - list_del(&tf->tf_list); mutex_unlock(&g_tf_lock); - - pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing tf:" - " %s\n", tf->tf_name); - tf->tf_module = NULL; - tf->tf_subsys = NULL; - kfree(tf); - - pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>>>>>>" - ">>>>>\n"); } -EXPORT_SYMBOL(target_fabric_configfs_deregister); +EXPORT_SYMBOL(target_unregister_template); /*############################################################################## // Stop functions called by external Target Fabrics Modules @@ -945,7 +863,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( struct se_lun *lun; struct se_portal_group *se_tpg; struct t10_pr_registration *pr_reg; - struct target_core_fabric_ops *tfo; + const struct target_core_fabric_ops *tfo; ssize_t len = 0; spin_lock(&dev->dev_reservation_lock); @@ -979,7 +897,7 @@ SE_DEV_PR_ATTR_RO(res_pr_holder_tg_port); static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts( struct se_device *dev, char *page) { - struct target_core_fabric_ops *tfo; + const struct target_core_fabric_ops *tfo; struct t10_pr_registration *pr_reg; unsigned char buf[384]; char i_buf[PR_REG_ISID_ID_LEN]; diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 0c3f90130b7d..1f7886bb16bf 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -56,6 +56,20 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) pr_debug("Setup generic %s\n", __stringify(_name)); \ } +#define TF_CIT_SETUP_DRV(_name, _item_ops, _group_ops) \ +static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ +{ \ + struct target_fabric_configfs_template *tfc = &tf->tf_cit_tmpl; \ + struct config_item_type *cit = &tfc->tfc_##_name##_cit; \ + struct configfs_attribute **attrs = tf->tf_ops.tfc_##_name##_attrs; \ + \ + cit->ct_item_ops = _item_ops; \ + cit->ct_group_ops = _group_ops; \ + cit->ct_attrs = attrs; \ + cit->ct_owner = tf->tf_module; \ + pr_debug("Setup generic %s\n", __stringify(_name)); \ +} + /* Start of tfc_tpg_mappedlun_cit */ static int target_fabric_mappedlun_link( @@ -278,7 +292,7 @@ static struct configfs_item_operations target_fabric_nacl_attrib_item_ops = { .store_attribute = target_fabric_nacl_attrib_attr_store, }; -TF_CIT_SETUP(tpg_nacl_attrib, &target_fabric_nacl_attrib_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_nacl_attrib, &target_fabric_nacl_attrib_item_ops, NULL); /* End of tfc_tpg_nacl_attrib_cit */ @@ -291,7 +305,7 @@ static struct configfs_item_operations target_fabric_nacl_auth_item_ops = { .store_attribute = target_fabric_nacl_auth_attr_store, }; -TF_CIT_SETUP(tpg_nacl_auth, &target_fabric_nacl_auth_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_nacl_auth, &target_fabric_nacl_auth_item_ops, NULL); /* End of tfc_tpg_nacl_auth_cit */ @@ -304,7 +318,7 @@ static struct configfs_item_operations target_fabric_nacl_param_item_ops = { .store_attribute = target_fabric_nacl_param_attr_store, }; -TF_CIT_SETUP(tpg_nacl_param, &target_fabric_nacl_param_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_nacl_param, &target_fabric_nacl_param_item_ops, NULL); /* End of tfc_tpg_nacl_param_cit */ @@ -461,8 +475,8 @@ static struct configfs_group_operations target_fabric_nacl_base_group_ops = { .drop_item = target_fabric_drop_mappedlun, }; -TF_CIT_SETUP(tpg_nacl_base, &target_fabric_nacl_base_item_ops, - &target_fabric_nacl_base_group_ops, NULL); +TF_CIT_SETUP_DRV(tpg_nacl_base, &target_fabric_nacl_base_item_ops, + &target_fabric_nacl_base_group_ops); /* End of tfc_tpg_nacl_base_cit */ @@ -570,7 +584,7 @@ static struct configfs_item_operations target_fabric_np_base_item_ops = { .store_attribute = target_fabric_np_base_attr_store, }; -TF_CIT_SETUP(tpg_np_base, &target_fabric_np_base_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_np_base, &target_fabric_np_base_item_ops, NULL); /* End of tfc_tpg_np_base_cit */ @@ -966,7 +980,7 @@ static struct configfs_item_operations target_fabric_tpg_attrib_item_ops = { .store_attribute = target_fabric_tpg_attrib_attr_store, }; -TF_CIT_SETUP(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL); /* End of tfc_tpg_attrib_cit */ @@ -979,7 +993,7 @@ static struct configfs_item_operations target_fabric_tpg_auth_item_ops = { .store_attribute = target_fabric_tpg_auth_attr_store, }; -TF_CIT_SETUP(tpg_auth, &target_fabric_tpg_auth_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_auth, &target_fabric_tpg_auth_item_ops, NULL); /* End of tfc_tpg_attrib_cit */ @@ -992,7 +1006,7 @@ static struct configfs_item_operations target_fabric_tpg_param_item_ops = { .store_attribute = target_fabric_tpg_param_attr_store, }; -TF_CIT_SETUP(tpg_param, &target_fabric_tpg_param_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_param, &target_fabric_tpg_param_item_ops, NULL); /* End of tfc_tpg_param_cit */ @@ -1018,7 +1032,7 @@ static struct configfs_item_operations target_fabric_tpg_base_item_ops = { .store_attribute = target_fabric_tpg_attr_store, }; -TF_CIT_SETUP(tpg_base, &target_fabric_tpg_base_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(tpg_base, &target_fabric_tpg_base_item_ops, NULL); /* End of tfc_tpg_base_cit */ @@ -1192,7 +1206,7 @@ static struct configfs_item_operations target_fabric_wwn_item_ops = { .store_attribute = target_fabric_wwn_attr_store, }; -TF_CIT_SETUP(wwn, &target_fabric_wwn_item_ops, &target_fabric_wwn_group_ops, NULL); +TF_CIT_SETUP_DRV(wwn, &target_fabric_wwn_item_ops, &target_fabric_wwn_group_ops); /* End of tfc_wwn_cit */ @@ -1206,7 +1220,7 @@ static struct configfs_item_operations target_fabric_discovery_item_ops = { .store_attribute = target_fabric_discovery_attr_store, }; -TF_CIT_SETUP(discovery, &target_fabric_discovery_item_ops, NULL, NULL); +TF_CIT_SETUP_DRV(discovery, &target_fabric_discovery_item_ops, NULL); /* End of tfc_discovery_cit */ diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 7436fdaaad12..963a67729b65 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -680,7 +680,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( struct se_dev_entry *deve_tmp; struct se_node_acl *nacl_tmp; struct se_port *port, *port_tmp; - struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; + const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; struct t10_pr_registration *pr_reg, *pr_reg_atp, *pr_reg_tmp, *pr_reg_tmp_safe; int ret; /* @@ -979,7 +979,7 @@ int core_scsi3_check_aptpl_registration( } static void __core_scsi3_dump_registration( - struct target_core_fabric_ops *tfo, + const struct target_core_fabric_ops *tfo, struct se_device *dev, struct se_node_acl *nacl, struct t10_pr_registration *pr_reg, @@ -1020,7 +1020,7 @@ static void __core_scsi3_add_registration( enum register_type register_type, int register_move) { - struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; + const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; struct t10_reservation *pr_tmpl = &dev->t10_pr; @@ -1237,7 +1237,7 @@ static void __core_scsi3_free_registration( struct list_head *preempt_and_abort_list, int dec_holders) { - struct target_core_fabric_ops *tfo = + const struct target_core_fabric_ops *tfo = pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; struct t10_reservation *pr_tmpl = &dev->t10_pr; char i_buf[PR_REG_ISID_ID_LEN]; @@ -1461,7 +1461,7 @@ core_scsi3_decode_spec_i_port( struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; LIST_HEAD(tid_dest_list); struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp; - struct target_core_fabric_ops *tmp_tf_ops; + const struct target_core_fabric_ops *tmp_tf_ops; unsigned char *buf; unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident; char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN]; @@ -2422,7 +2422,7 @@ static void __core_scsi3_complete_pro_release( int explicit, int unreg) { - struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo; + const struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo; char i_buf[PR_REG_ISID_ID_LEN]; int pr_res_type = 0, pr_res_scope = 0; @@ -2734,7 +2734,7 @@ static void __core_scsi3_complete_pro_preempt( enum preempt_type preempt_type) { struct se_node_acl *nacl = pr_reg->pr_reg_nacl; - struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; + const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; char i_buf[PR_REG_ISID_ID_LEN]; memset(i_buf, 0, PR_REG_ISID_ID_LEN); @@ -3119,7 +3119,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, struct se_node_acl *pr_res_nacl, *pr_reg_nacl, *dest_node_acl = NULL; struct se_port *se_port; struct se_portal_group *se_tpg, *dest_se_tpg = NULL; - struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops; + const struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops; struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg; struct t10_reservation *pr_tmpl = &dev->t10_pr; unsigned char *buf; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 0696de9553d3..47f064415bf6 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -672,7 +672,7 @@ static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) } int core_tpg_register( - struct target_core_fabric_ops *tfo, + const struct target_core_fabric_ops *tfo, struct se_wwn *se_wwn, struct se_portal_group *se_tpg, void *tpg_fabric_ptr, diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index b671ebbe1df6..f884198a8511 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -322,7 +322,7 @@ void __transport_register_session( struct se_session *se_sess, void *fabric_sess_ptr) { - struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo; + const struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo; unsigned char buf[PR_REG_ISID_LEN]; se_sess->se_tpg = se_tpg; @@ -494,7 +494,7 @@ 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; + const struct target_core_fabric_ops *se_tfo; struct se_node_acl *se_nacl; unsigned long flags; bool comp_nacl = true; @@ -1150,7 +1150,7 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size) */ void transport_init_se_cmd( struct se_cmd *cmd, - struct target_core_fabric_ops *tfo, + const struct target_core_fabric_ops *tfo, struct se_session *se_sess, u32 data_length, int data_direction, diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 8585acba6fc9..a600ff15dcfd 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -425,7 +425,7 @@ static int xcopy_pt_queue_status(struct se_cmd *se_cmd) return 0; } -static struct target_core_fabric_ops xcopy_pt_tfo = { +static const struct target_core_fabric_ops xcopy_pt_tfo = { .get_fabric_name = xcopy_pt_get_fabric_name, .get_task_tag = xcopy_pt_get_tag, .get_cmd_state = xcopy_pt_get_cmd_state, diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index a0bcfd3e7e7d..881deb3d499a 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -129,7 +129,6 @@ struct ft_cmd { extern struct mutex ft_lport_lock; extern struct fc4_prov ft_prov; -extern struct target_fabric_configfs *ft_configfs; extern unsigned int ft_debug_logging; /* diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index efdcb9663a1a..65dce1345966 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -48,7 +48,7 @@ #include "tcm_fc.h" -struct target_fabric_configfs *ft_configfs; +static const struct target_core_fabric_ops ft_fabric_ops; static LIST_HEAD(ft_wwn_list); DEFINE_MUTEX(ft_lport_lock); @@ -337,7 +337,7 @@ static struct se_portal_group *ft_add_tpg( return NULL; } - ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg, + ret = core_tpg_register(&ft_fabric_ops, wwn, &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) { destroy_workqueue(wq); @@ -507,7 +507,9 @@ static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg) return tpg->index; } -static struct target_core_fabric_ops ft_fabric_ops = { +static const struct target_core_fabric_ops ft_fabric_ops = { + .module = THIS_MODULE, + .name = "fc", .get_fabric_name = ft_get_fabric_name, .get_fabric_proto_ident = fc_get_fabric_proto_ident, .tpg_get_wwn = ft_get_fabric_wwn, @@ -552,62 +554,10 @@ static struct target_core_fabric_ops ft_fabric_ops = { .fabric_drop_np = NULL, .fabric_make_nodeacl = &ft_add_acl, .fabric_drop_nodeacl = &ft_del_acl, -}; - -static int ft_register_configfs(void) -{ - struct target_fabric_configfs *fabric; - int ret; - - /* - * Register the top level struct config_item_type with TCM core - */ - fabric = target_fabric_configfs_init(THIS_MODULE, "fc"); - if (IS_ERR(fabric)) { - pr_err("%s: target_fabric_configfs_init() failed!\n", - __func__); - return PTR_ERR(fabric); - } - fabric->tf_ops = ft_fabric_ops; - - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - */ - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = ft_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = - ft_nacl_base_attrs; - fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - /* - * register the fabric for use within TCM - */ - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - pr_debug("target_fabric_configfs_register() for" - " FC Target failed!\n"); - target_fabric_configfs_free(fabric); - return -1; - } - - /* - * Setup our local pointer to *fabric. - */ - ft_configfs = fabric; - return 0; -} -static void ft_deregister_configfs(void) -{ - if (!ft_configfs) - return; - target_fabric_configfs_deregister(ft_configfs); - ft_configfs = NULL; -} + .tfc_wwn_attrs = ft_wwn_attrs, + .tfc_tpg_nacl_base_attrs = ft_nacl_base_attrs, +}; static struct notifier_block ft_notifier = { .notifier_call = ft_lport_notify @@ -615,15 +565,24 @@ static struct notifier_block ft_notifier = { static int __init ft_init(void) { - if (ft_register_configfs()) - return -1; - if (fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov)) { - ft_deregister_configfs(); - return -1; - } + int ret; + + ret = target_register_template(&ft_fabric_ops); + if (ret) + goto out; + + ret = fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov); + if (ret) + goto out_unregister_template; + blocking_notifier_chain_register(&fc_lport_notifier_head, &ft_notifier); fc_lport_iterate(ft_lport_add, NULL); return 0; + +out_unregister_template: + target_unregister_template(&ft_fabric_ops); +out: + return ret; } static void __exit ft_exit(void) @@ -632,7 +591,7 @@ static void __exit ft_exit(void) &ft_notifier); fc_fc4_deregister_provider(FC_TYPE_FCP, &ft_prov); fc_lport_iterate(ft_lport_del, NULL); - ft_deregister_configfs(); + target_unregister_template(&ft_fabric_ops); synchronize_rcu(); } diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index 3a494168661e..7ea2a44cb228 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -29,7 +29,7 @@ USB_GADGET_COMPOSITE_OPTIONS(); -static struct target_fabric_configfs *usbg_fabric_configfs; +static const struct target_core_fabric_ops usbg_ops; static inline struct f_uas *to_f_uas(struct usb_function *f) { @@ -1572,8 +1572,7 @@ static struct se_portal_group *usbg_make_tpg( tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn, - &tpg->se_tpg, tpg, + ret = core_tpg_register(&usbg_ops, wwn, &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) { destroy_workqueue(tpg->workqueue); @@ -1865,7 +1864,9 @@ static int usbg_check_stop_free(struct se_cmd *se_cmd) return 1; } -static struct target_core_fabric_ops usbg_ops = { +static const struct target_core_fabric_ops usbg_ops = { + .module = THIS_MODULE, + .name = "usb_gadget", .get_fabric_name = usbg_get_fabric_name, .get_fabric_proto_ident = usbg_get_fabric_proto_ident, .tpg_get_wwn = usbg_get_fabric_wwn, @@ -1907,46 +1908,9 @@ static struct target_core_fabric_ops usbg_ops = { .fabric_drop_np = NULL, .fabric_make_nodeacl = usbg_make_nodeacl, .fabric_drop_nodeacl = usbg_drop_nodeacl, -}; - -static int usbg_register_configfs(void) -{ - struct target_fabric_configfs *fabric; - int ret; - - fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget"); - if (IS_ERR(fabric)) { - printk(KERN_ERR "target_fabric_configfs_init() failed\n"); - return PTR_ERR(fabric); - } - - fabric->tf_ops = usbg_ops; - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = usbg_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = usbg_base_attrs; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - printk(KERN_ERR "target_fabric_configfs_register() failed" - " for usb-gadget\n"); - return ret; - } - usbg_fabric_configfs = fabric; - return 0; -}; -static void usbg_deregister_configfs(void) -{ - if (!(usbg_fabric_configfs)) - return; - - target_fabric_configfs_deregister(usbg_fabric_configfs); - usbg_fabric_configfs = NULL; + .tfc_wwn_attrs = usbg_wwn_attrs, + .tfc_tpg_base_attrs = usbg_base_attrs, }; /* Start gadget.c code */ @@ -2455,16 +2419,13 @@ static void usbg_detach(struct usbg_tpg *tpg) static int __init usb_target_gadget_init(void) { - int ret; - - ret = usbg_register_configfs(); - return ret; + return target_register_template(&usbg_ops); } module_init(usb_target_gadget_init); static void __exit usb_target_gadget_exit(void) { - usbg_deregister_configfs(); + target_unregister_template(&usbg_ops); } module_exit(usb_target_gadget_exit); diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 27ed9642cc21..e8c88b453f79 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -216,9 +216,7 @@ struct vhost_scsi { int vs_events_nr; /* num of pending events, protected by vq->mutex */ }; -/* Local pointer to allocated TCM configfs fabric module */ -static struct target_fabric_configfs *vhost_scsi_fabric_configfs; - +static struct target_core_fabric_ops vhost_scsi_ops; static struct workqueue_struct *vhost_scsi_workqueue; /* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */ @@ -2205,7 +2203,7 @@ vhost_scsi_make_tpg(struct se_wwn *wwn, tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&vhost_scsi_fabric_configfs->tf_ops, wwn, + ret = core_tpg_register(&vhost_scsi_ops, wwn, &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) { kfree(tpg); @@ -2327,6 +2325,8 @@ static struct configfs_attribute *vhost_scsi_wwn_attrs[] = { }; static struct target_core_fabric_ops vhost_scsi_ops = { + .module = THIS_MODULE, + .name = "vhost", .get_fabric_name = vhost_scsi_get_fabric_name, .get_fabric_proto_ident = vhost_scsi_get_fabric_proto_ident, .tpg_get_wwn = vhost_scsi_get_fabric_wwn, @@ -2371,70 +2371,20 @@ static struct target_core_fabric_ops vhost_scsi_ops = { .fabric_drop_np = NULL, .fabric_make_nodeacl = vhost_scsi_make_nodeacl, .fabric_drop_nodeacl = vhost_scsi_drop_nodeacl, + + .tfc_wwn_attrs = vhost_scsi_wwn_attrs, + .tfc_tpg_base_attrs = vhost_scsi_tpg_attrs, + .tfc_tpg_attrib_attrs = vhost_scsi_tpg_attrib_attrs, }; -static int vhost_scsi_register_configfs(void) +static int __init vhost_scsi_init(void) { - struct target_fabric_configfs *fabric; - int ret; + int ret = -ENOMEM; - pr_debug("vhost-scsi fabric module %s on %s/%s" + pr_debug("TCM_VHOST fabric module %s on %s/%s" " on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname, utsname()->machine); - /* - * Register the top level struct config_item_type with TCM core - */ - fabric = target_fabric_configfs_init(THIS_MODULE, "vhost"); - if (IS_ERR(fabric)) { - pr_err("target_fabric_configfs_init() failed\n"); - return PTR_ERR(fabric); - } - /* - * Setup fabric->tf_ops from our local vhost_scsi_ops - */ - fabric->tf_ops = vhost_scsi_ops; - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - */ - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = vhost_scsi_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = vhost_scsi_tpg_attrs; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = vhost_scsi_tpg_attrib_attrs; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - /* - * Register the fabric for use within TCM - */ - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - pr_err("target_fabric_configfs_register() failed" - " for TCM_VHOST\n"); - return ret; - } - /* - * Setup our local pointer to *fabric - */ - vhost_scsi_fabric_configfs = fabric; - pr_debug("TCM_VHOST[0] - Set fabric -> vhost_scsi_fabric_configfs\n"); - return 0; -}; - -static void vhost_scsi_deregister_configfs(void) -{ - if (!vhost_scsi_fabric_configfs) - return; - - target_fabric_configfs_deregister(vhost_scsi_fabric_configfs); - vhost_scsi_fabric_configfs = NULL; - pr_debug("TCM_VHOST[0] - Cleared vhost_scsi_fabric_configfs\n"); -}; -static int __init vhost_scsi_init(void) -{ - int ret = -ENOMEM; /* * Use our own dedicated workqueue for submitting I/O into * target core to avoid contention within system_wq. @@ -2447,7 +2397,7 @@ static int __init vhost_scsi_init(void) if (ret < 0) goto out_destroy_workqueue; - ret = vhost_scsi_register_configfs(); + ret = target_register_template(&vhost_scsi_ops); if (ret < 0) goto out_vhost_scsi_deregister; @@ -2463,7 +2413,7 @@ out: static void vhost_scsi_exit(void) { - vhost_scsi_deregister_configfs(); + target_unregister_template(&vhost_scsi_ops); vhost_scsi_deregister(); destroy_workqueue(vhost_scsi_workqueue); }; diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 61653a03a8f5..f8a1bd741b5d 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -205,8 +205,7 @@ static LIST_HEAD(scsiback_free_pages); static DEFINE_MUTEX(scsiback_mutex); static LIST_HEAD(scsiback_list); -/* Local pointer to allocated TCM configfs fabric module */ -static struct target_fabric_configfs *scsiback_fabric_configfs; +static const struct target_core_fabric_ops scsiback_ops; static void scsiback_get(struct vscsibk_info *info) { @@ -1901,7 +1900,7 @@ scsiback_make_tpg(struct se_wwn *wwn, tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&scsiback_fabric_configfs->tf_ops, wwn, + ret = core_tpg_register(&scsiback_ops, wwn, &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); if (ret < 0) { kfree(tpg); @@ -1943,7 +1942,9 @@ static int scsiback_check_false(struct se_portal_group *se_tpg) return 0; } -static struct target_core_fabric_ops scsiback_ops = { +static const struct target_core_fabric_ops scsiback_ops = { + .module = THIS_MODULE, + .name = "xen-pvscsi", .get_fabric_name = scsiback_get_fabric_name, .get_fabric_proto_ident = scsiback_get_fabric_proto_ident, .tpg_get_wwn = scsiback_get_fabric_wwn, @@ -1990,62 +1991,10 @@ static struct target_core_fabric_ops scsiback_ops = { .fabric_make_nodeacl = scsiback_make_nodeacl, .fabric_drop_nodeacl = scsiback_drop_nodeacl, #endif -}; - -static int scsiback_register_configfs(void) -{ - struct target_fabric_configfs *fabric; - int ret; - pr_debug("xen-pvscsi: fabric module %s on %s/%s on "UTS_RELEASE"\n", - VSCSI_VERSION, utsname()->sysname, utsname()->machine); - /* - * Register the top level struct config_item_type with TCM core - */ - fabric = target_fabric_configfs_init(THIS_MODULE, "xen-pvscsi"); - if (IS_ERR(fabric)) - return PTR_ERR(fabric); - - /* - * Setup fabric->tf_ops from our local scsiback_ops - */ - fabric->tf_ops = scsiback_ops; - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - */ - fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = scsiback_wwn_attrs; - fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = scsiback_tpg_attrs; - fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = scsiback_param_attrs; - fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL; - /* - * Register the fabric for use within TCM - */ - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - target_fabric_configfs_free(fabric); - return ret; - } - /* - * Setup our local pointer to *fabric - */ - scsiback_fabric_configfs = fabric; - pr_debug("xen-pvscsi: Set fabric -> scsiback_fabric_configfs\n"); - return 0; -}; - -static void scsiback_deregister_configfs(void) -{ - if (!scsiback_fabric_configfs) - return; - - target_fabric_configfs_deregister(scsiback_fabric_configfs); - scsiback_fabric_configfs = NULL; - pr_debug("xen-pvscsi: Cleared scsiback_fabric_configfs\n"); + .tfc_wwn_attrs = scsiback_wwn_attrs, + .tfc_tpg_base_attrs = scsiback_tpg_attrs, + .tfc_tpg_param_attrs = scsiback_param_attrs, }; static const struct xenbus_device_id scsiback_ids[] = { @@ -2077,6 +2026,9 @@ static int __init scsiback_init(void) if (!xen_domain()) return -ENODEV; + pr_debug("xen-pvscsi: fabric module %s on %s/%s on "UTS_RELEASE"\n", + VSCSI_VERSION, utsname()->sysname, utsname()->machine); + scsiback_cachep = kmem_cache_create("vscsiif_cache", sizeof(struct vscsibk_pend), 0, 0, scsiback_init_pend); if (!scsiback_cachep) @@ -2086,7 +2038,7 @@ static int __init scsiback_init(void) if (ret) goto out_cache_destroy; - ret = scsiback_register_configfs(); + ret = target_register_template(&scsiback_ops); if (ret) goto out_unregister_xenbus; @@ -2109,7 +2061,7 @@ static void __exit scsiback_exit(void) BUG(); gnttab_free_pages(1, &page); } - scsiback_deregister_configfs(); + target_unregister_template(&scsiback_ops); xenbus_unregister_driver(&scsiback_driver); kmem_cache_destroy(scsiback_cachep); } diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 71699cf3cc71..383110d608a0 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -519,7 +519,7 @@ struct se_cmd { struct list_head se_cmd_list; struct completion cmd_wait_comp; struct kref cmd_kref; - struct target_core_fabric_ops *se_tfo; + const struct target_core_fabric_ops *se_tfo; sense_reason_t (*execute_cmd)(struct se_cmd *); sense_reason_t (*execute_rw)(struct se_cmd *, struct scatterlist *, u32, enum dma_data_direction); @@ -890,7 +890,7 @@ struct se_portal_group { /* List of TCM sessions associated wth this TPG */ struct list_head tpg_sess_list; /* Pointer to $FABRIC_MOD dependent code */ - struct target_core_fabric_ops *se_tpg_tfo; + const struct target_core_fabric_ops *se_tpg_tfo; struct se_wwn *se_tpg_wwn; struct config_group tpg_group; struct config_group *tpg_default_groups[7]; diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h index e0801386e4dc..25bb04c4209e 100644 --- a/include/target/target_core_configfs.h +++ b/include/target/target_core_configfs.h @@ -5,12 +5,6 @@ #define TARGET_CORE_NAME_MAX_LEN 64 #define TARGET_FABRIC_NAME_SIZE 32 -extern struct target_fabric_configfs *target_fabric_configfs_init( - struct module *, const char *); -extern void target_fabric_configfs_free(struct target_fabric_configfs *); -extern int target_fabric_configfs_register(struct target_fabric_configfs *); -extern void target_fabric_configfs_deregister(struct target_fabric_configfs *); - struct target_fabric_configfs_template { struct config_item_type tfc_discovery_cit; struct config_item_type tfc_wwn_cit; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index c93cfdf0d8e5..17c7f5ac7ea0 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -2,6 +2,8 @@ #define TARGET_CORE_FABRIC_H struct target_core_fabric_ops { + struct module *module; + const char *name; struct configfs_subsystem *tf_subsys; char *(*get_fabric_name)(void); u8 (*get_fabric_proto_ident)(struct se_portal_group *); @@ -90,8 +92,23 @@ struct target_core_fabric_ops { struct se_node_acl *(*fabric_make_nodeacl)(struct se_portal_group *, struct config_group *, const char *); void (*fabric_drop_nodeacl)(struct se_node_acl *); + + struct configfs_attribute **tfc_discovery_attrs; + struct configfs_attribute **tfc_wwn_attrs; + struct configfs_attribute **tfc_tpg_base_attrs; + struct configfs_attribute **tfc_tpg_np_base_attrs; + struct configfs_attribute **tfc_tpg_attrib_attrs; + struct configfs_attribute **tfc_tpg_auth_attrs; + struct configfs_attribute **tfc_tpg_param_attrs; + struct configfs_attribute **tfc_tpg_nacl_base_attrs; + struct configfs_attribute **tfc_tpg_nacl_attrib_attrs; + struct configfs_attribute **tfc_tpg_nacl_auth_attrs; + struct configfs_attribute **tfc_tpg_nacl_param_attrs; }; +int target_register_template(const struct target_core_fabric_ops *fo); +void target_unregister_template(const struct target_core_fabric_ops *fo); + struct se_session *transport_init_session(enum target_prot_op); int transport_alloc_session_tags(struct se_session *, unsigned int, unsigned int); @@ -110,7 +127,8 @@ void transport_deregister_session_configfs(struct se_session *); void transport_deregister_session(struct se_session *); -void transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *, +void transport_init_se_cmd(struct se_cmd *, + const struct target_core_fabric_ops *, struct se_session *, u32, int, int, unsigned char *); sense_reason_t transport_lookup_cmd_lun(struct se_cmd *, u32); sense_reason_t target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *); @@ -162,8 +180,8 @@ int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *, unsigned char *, u32, int); int core_tpg_set_initiator_node_tag(struct se_portal_group *, struct se_node_acl *, const char *); -int core_tpg_register(struct target_core_fabric_ops *, struct se_wwn *, - struct se_portal_group *, void *, int); +int core_tpg_register(const struct target_core_fabric_ops *, + struct se_wwn *, struct se_portal_group *, void *, int); int core_tpg_deregister(struct se_portal_group *); /* SAS helpers */ -- cgit v1.2.3 From c8e639852ad720499912acedfd6b072325fd2807 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 7 Apr 2015 21:53:27 +0000 Subject: target: Fix COMPARE_AND_WRITE with SG_TO_MEM_NOALLOC handling This patch fixes a bug for COMPARE_AND_WRITE handling with fabrics using SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC. It adds the missing allocation for cmd->t_bidi_data_sg within transport_generic_new_cmd() that is used by COMPARE_AND_WRITE for the initial READ payload, even if the fabric is already providing a pre-allocated buffer for cmd->t_data_sg. Also, fix zero-length COMPARE_AND_WRITE handling within the compare_and_write_callback() and target_complete_ok_work() to queue the response, skipping the initial READ. This fixes COMPARE_AND_WRITE emulation with loopback, vhost, and xen-backend fabric drivers using SG_TO_MEM_NOALLOC. Reported-by: Christoph Hellwig Cc: Christoph Hellwig Cc: # v3.12+ Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_sbc.c | 15 +++++++++----- drivers/target/target_core_transport.c | 37 ++++++++++++++++++++++++++++++---- include/target/target_core_base.h | 2 +- 3 files changed, 44 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 315ff641408b..0064ffe9a219 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -321,7 +321,7 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o return 0; } -static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd) +static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success) { unsigned char *buf, *addr; struct scatterlist *sg; @@ -385,7 +385,7 @@ sbc_execute_rw(struct se_cmd *cmd) cmd->data_direction); } -static sense_reason_t compare_and_write_post(struct se_cmd *cmd) +static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success) { struct se_device *dev = cmd->se_dev; @@ -408,7 +408,7 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd) return TCM_NO_SENSE; } -static sense_reason_t compare_and_write_callback(struct se_cmd *cmd) +static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success) { struct se_device *dev = cmd->se_dev; struct scatterlist *write_sg = NULL, *sg; @@ -423,10 +423,15 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd) /* * Handle early failure in transport_generic_request_failure(), - * which will not have taken ->caw_mutex yet.. + * which will not have taken ->caw_sem yet.. */ - if (!cmd->t_data_sg || !cmd->t_bidi_data_sg) + if (!success && (!cmd->t_data_sg || !cmd->t_bidi_data_sg)) return TCM_NO_SENSE; + /* + * Handle special case for zero-length COMPARE_AND_WRITE + */ + if (!cmd->data_length) + goto out; /* * Immediately exit + release dev->caw_sem if command has already * been failed with a non-zero SCSI status. diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index f884198a8511..47334e5c47bf 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1647,11 +1647,11 @@ void transport_generic_request_failure(struct se_cmd *cmd, transport_complete_task_attr(cmd); /* * Handle special case for COMPARE_AND_WRITE failure, where the - * callback is expected to drop the per device ->caw_mutex. + * callback is expected to drop the per device ->caw_sem. */ if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && cmd->transport_complete_callback) - cmd->transport_complete_callback(cmd); + cmd->transport_complete_callback(cmd, false); switch (sense_reason) { case TCM_NON_EXISTENT_LUN: @@ -2048,8 +2048,12 @@ static void target_complete_ok_work(struct work_struct *work) if (cmd->transport_complete_callback) { sense_reason_t rc; - rc = cmd->transport_complete_callback(cmd); + rc = cmd->transport_complete_callback(cmd, true); if (!rc && !(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE_POST)) { + if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && + !cmd->data_length) + goto queue_rsp; + return; } else if (rc) { ret = transport_send_check_condition_and_sense(cmd, @@ -2063,6 +2067,7 @@ static void target_complete_ok_work(struct work_struct *work) } } +queue_rsp: switch (cmd->data_direction) { case DMA_FROM_DEVICE: spin_lock(&cmd->se_lun->lun_sep_lock); @@ -2166,6 +2171,16 @@ static inline void transport_reset_sgl_orig(struct se_cmd *cmd) static inline void transport_free_pages(struct se_cmd *cmd) { if (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) { + /* + * Release special case READ buffer payload required for + * SG_TO_MEM_NOALLOC to function with COMPARE_AND_WRITE + */ + if (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) { + transport_free_sgl(cmd->t_bidi_data_sg, + cmd->t_bidi_data_nents); + cmd->t_bidi_data_sg = NULL; + cmd->t_bidi_data_nents = 0; + } transport_reset_sgl_orig(cmd); return; } @@ -2318,6 +2333,7 @@ sense_reason_t transport_generic_new_cmd(struct se_cmd *cmd) { int ret = 0; + bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB); /* * Determine is the TCM fabric module has already allocated physical @@ -2326,7 +2342,6 @@ transport_generic_new_cmd(struct se_cmd *cmd) */ if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) && cmd->data_length) { - bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB); if ((cmd->se_cmd_flags & SCF_BIDI) || (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE)) { @@ -2357,6 +2372,20 @@ transport_generic_new_cmd(struct se_cmd *cmd) cmd->data_length, zero_flag); if (ret < 0) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } else if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && + cmd->data_length) { + /* + * Special case for COMPARE_AND_WRITE with fabrics + * using SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC. + */ + u32 caw_length = cmd->t_task_nolb * + cmd->se_dev->dev_attrib.block_size; + + ret = target_alloc_sgl(&cmd->t_bidi_data_sg, + &cmd->t_bidi_data_nents, + caw_length, zero_flag); + if (ret < 0) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } /* * If this command is not a write we can execute it right here, diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 383110d608a0..dae468903d8b 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -523,7 +523,7 @@ struct se_cmd { sense_reason_t (*execute_cmd)(struct se_cmd *); sense_reason_t (*execute_rw)(struct se_cmd *, struct scatterlist *, u32, enum dma_data_direction); - sense_reason_t (*transport_complete_callback)(struct se_cmd *); + sense_reason_t (*transport_complete_callback)(struct se_cmd *, bool); unsigned char *t_task_cdb; unsigned char __t_task_cdb[TCM_MAX_COMMAND_SIZE]; -- cgit v1.2.3 From 054922bb3549abbea9ed2c1a78a1e331343cc05e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 10 Apr 2015 14:49:44 +0200 Subject: target: Remove the unused flag SCF_ACK_KREF The flag SCF_ACK_KREF is only set but never tested. Hence remove this flag. Signed-off-by: Bart Van Assche Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 4 +--- include/target/target_core_base.h | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 0b8411f8de85..4edb183cf8df 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2479,10 +2479,8 @@ int 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) { + if (ack_kref) kref_get(&se_cmd->cmd_kref); - se_cmd->se_cmd_flags |= SCF_ACK_KREF; - } spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); if (se_sess->sess_tearing_down) { diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index dae468903d8b..e1de142b7b07 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -165,7 +165,6 @@ enum se_cmd_flags_table { SCF_SEND_DELAYED_TAS = 0x00004000, SCF_ALUA_NON_OPTIMIZED = 0x00008000, SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000, - SCF_ACK_KREF = 0x00040000, SCF_COMPARE_AND_WRITE = 0x00080000, SCF_COMPARE_AND_WRITE_POST = 0x00100000, }; -- cgit v1.2.3 From bffb5128f91e820fd8804307a6431607c2c840a4 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 14 Apr 2015 11:52:22 -0700 Subject: target: Ensure sess_prot_type is saved across session restart The following incremental patch saves the current sess_prot_type into se_node_acl, and will always reset sess_prot_type if a previous saved value exists. So the PI setting for the fabric's session with backend devices not supporting PI is persistent across session restart. (Fix se_node_acl dereference for discovery sessions - DanCarpenter) Reviewed-by: Martin Petersen Reviewed-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 22 +++++++++++++++------- include/target/target_core_base.h | 1 + 2 files changed, 16 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 4edb183cf8df..14e324991c34 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -327,13 +327,6 @@ void __transport_register_session( se_sess->se_tpg = se_tpg; se_sess->fabric_sess_ptr = fabric_sess_ptr; - /* - * Determine if fabric allows for T10-PI feature bits to be exposed - * to initiators for device backends with !dev->dev_attrib.pi_prot_type - */ - if (tfo->tpg_check_prot_fabric_only) - se_sess->sess_prot_type = tfo->tpg_check_prot_fabric_only(se_tpg); - /* * Used by struct se_node_acl's under ConfigFS to locate active se_session-t * @@ -341,6 +334,21 @@ void __transport_register_session( * eg: *NOT* discovery sessions. */ if (se_nacl) { + /* + * + * Determine if fabric allows for T10-PI feature bits exposed to + * initiators for device backends with !dev->dev_attrib.pi_prot_type. + * + * If so, then always save prot_type on a per se_node_acl node + * basis and re-instate the previous sess_prot_type to avoid + * disabling PI from below any previously initiator side + * registered LUNs. + */ + if (se_nacl->saved_prot_type) + se_sess->sess_prot_type = se_nacl->saved_prot_type; + else if (tfo->tpg_check_prot_fabric_only) + se_sess->sess_prot_type = se_nacl->saved_prot_type = + tfo->tpg_check_prot_fabric_only(se_tpg); /* * If the fabric module supports an ISID based TransportID, * save this value in binary from the fabric I_T Nexus now. diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index e1de142b7b07..480e9f82dfea 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -589,6 +589,7 @@ struct se_node_acl { bool acl_stop:1; u32 queue_depth; u32 acl_index; + enum target_prot_type saved_prot_type; #define MAX_ACL_TAG_SIZE 64 char acl_tag[MAX_ACL_TAG_SIZE]; /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ -- cgit v1.2.3 From 0ad46af8a618fc38e0cdc3927cfa9f7b42cc9423 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Tue, 14 Apr 2015 17:30:04 -0700 Subject: target: Version 2 of TCMU ABI The initial version of TCMU (in 3.18) does not properly handle bidirectional SCSI commands -- those with both an in and out buffer. In looking to fix this it also became clear that TCMU's support for adding new types of entries (opcodes) to the command ring was broken. We need to fix this now, so that future issues can be handled properly by adding new opcodes. We make the most of this ABI break by enabling bidi cmd handling within TCMP_OP_CMD opcode. Add an iov_bidi_cnt field to tcmu_cmd_entry.req. This enables TCMU to describe bidi commands, but further kernel work is needed for full bidi support. Enlarge tcmu_cmd_entry_hdr by 32 bits by pulling in cmd_id and __pad1. Turn __pad1 into two 8 bit flags fields, for kernel-set and userspace-set flags, "kflags" and "uflags" respectively. Update version fields so userspace can tell the interface is changed. Update tcmu-design.txt with details of how new stuff works: - Specify an additional requirement for userspace to set UNKNOWN_OP (bit 0) in hdr.uflags for unknown/unhandled opcodes. - Define how Data-In and Data-Out fields are described in req.iov[] Changed in v2: - Change name of SKIPPED bit to UNKNOWN bit - PAD op does not set the bit any more - Change len_op helper functions to take just len_op, not the whole struct - Change version to 2 in missed spots, and use defines - Add 16 unused bytes to cmd_entry.req, in case additional SAM cmd parameters need to be included - Add iov_dif_cnt field to specify buffers used for DIF info in iov[] - Rearrange fields to naturally align cdb_off - Handle if userspace sets UNKNOWN_OP by indicating failure of the cmd - Wrap some overly long UPDATE_HEAD lines (Add missing req.iov_bidi_cnt + req.iov_dif_cnt zeroing - Ilias) Signed-off-by: Andy Grover Reviewed-by: Ilias Tsitsimpis Signed-off-by: Nicholas Bellinger --- Documentation/target/tcmu-design.txt | 43 ++++++++++++++++++++------------ drivers/target/target_core_user.c | 46 ++++++++++++++++++++++++++--------- include/uapi/linux/target_core_user.h | 44 ++++++++++++++++++++------------- 3 files changed, 89 insertions(+), 44 deletions(-) (limited to 'include') diff --git a/Documentation/target/tcmu-design.txt b/Documentation/target/tcmu-design.txt index 5518465290bf..43e94ea6d2ca 100644 --- a/Documentation/target/tcmu-design.txt +++ b/Documentation/target/tcmu-design.txt @@ -138,27 +138,40 @@ signals the kernel via a 4-byte write(). When cmd_head equals cmd_tail, the ring is empty -- no commands are currently waiting to be processed by userspace. -TCMU commands start with a common header containing "len_op", a 32-bit -value that stores the length, as well as the opcode in the lowest -unused bits. Currently only two opcodes are defined, TCMU_OP_PAD and -TCMU_OP_CMD. When userspace encounters a command with PAD opcode, it -should skip ahead by the bytes in "length". (The kernel inserts PAD -entries to ensure each CMD entry fits contigously into the circular -buffer.) - -When userspace handles a CMD, it finds the SCSI CDB (Command Data -Block) via tcmu_cmd_entry.req.cdb_off. This is an offset from the -start of the overall shared memory region, not the entry. The data -in/out buffers are accessible via tht req.iov[] array. Note that -each iov.iov_base is also an offset from the start of the region. - -TCMU currently does not support BIDI operations. +TCMU commands are 8-byte aligned. They start with a common header +containing "len_op", a 32-bit value that stores the length, as well as +the opcode in the lowest unused bits. It also contains cmd_id and +flags fields for setting by the kernel (kflags) and userspace +(uflags). + +Currently only two opcodes are defined, TCMU_OP_CMD and TCMU_OP_PAD. + +When the opcode is CMD, the entry in the command ring is a struct +tcmu_cmd_entry. Userspace finds the SCSI CDB (Command Data Block) via +tcmu_cmd_entry.req.cdb_off. This is an offset from the start of the +overall shared memory region, not the entry. The data in/out buffers +are accessible via tht req.iov[] array. iov_cnt contains the number of +entries in iov[] needed to describe either the Data-In or Data-Out +buffers. For bidirectional commands, iov_cnt specifies how many iovec +entries cover the Data-Out area, and iov_bidi_count specifies how many +iovec entries immediately after that in iov[] cover the Data-In +area. Just like other fields, iov.iov_base is an offset from the start +of the region. When completing a command, userspace sets rsp.scsi_status, and rsp.sense_buffer if necessary. Userspace then increments mailbox.cmd_tail by entry.hdr.length (mod cmdr_size) and signals the kernel via the UIO method, a 4-byte write to the file descriptor. +When the opcode is PAD, userspace only updates cmd_tail as above -- +it's a no-op. (The kernel inserts PAD entries to ensure each CMD entry +is contiguous within the command ring.) + +More opcodes may be added in the future. If userspace encounters an +opcode it does not handle, it must set UNKNOWN_OP bit (bit 0) in +hdr.uflags, update cmd_tail, and proceed with processing additional +commands, if any. + The Data Area: This is shared-memory space after the command ring. The organization diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 1fbf304a9491..dbc872a6c981 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -344,8 +344,11 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) entry = (void *) mb + CMDR_OFF + cmd_head; tcmu_flush_dcache_range(entry, sizeof(*entry)); - tcmu_hdr_set_op(&entry->hdr, TCMU_OP_PAD); - tcmu_hdr_set_len(&entry->hdr, pad_size); + tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_PAD); + tcmu_hdr_set_len(&entry->hdr.len_op, pad_size); + entry->hdr.cmd_id = 0; /* not used for PAD */ + entry->hdr.kflags = 0; + entry->hdr.uflags = 0; UPDATE_HEAD(mb->cmd_head, pad_size, udev->cmdr_size); @@ -355,9 +358,11 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) entry = (void *) mb + CMDR_OFF + cmd_head; tcmu_flush_dcache_range(entry, sizeof(*entry)); - tcmu_hdr_set_op(&entry->hdr, TCMU_OP_CMD); - tcmu_hdr_set_len(&entry->hdr, command_size); - entry->cmd_id = tcmu_cmd->cmd_id; + tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_CMD); + tcmu_hdr_set_len(&entry->hdr.len_op, command_size); + entry->hdr.cmd_id = tcmu_cmd->cmd_id; + entry->hdr.kflags = 0; + entry->hdr.uflags = 0; /* * Fix up iovecs, and handle if allocation in data ring wrapped. @@ -407,6 +412,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) kunmap_atomic(from); } entry->req.iov_cnt = iov_cnt; + entry->req.iov_bidi_cnt = 0; + entry->req.iov_dif_cnt = 0; /* All offsets relative to mb_addr, not start of entry! */ cdb_off = CMDR_OFF + cmd_head + base_command_size; @@ -464,6 +471,17 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * return; } + if (entry->hdr.uflags & TCMU_UFLAG_UNKNOWN_OP) { + UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size); + pr_warn("TCMU: Userspace set UNKNOWN_OP flag on se_cmd %p\n", + cmd->se_cmd); + transport_generic_request_failure(cmd->se_cmd, + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE); + cmd->se_cmd = NULL; + kmem_cache_free(tcmu_cmd_cache, cmd); + return; + } + if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) { memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer, se_cmd->scsi_sense_length); @@ -542,14 +560,16 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev) tcmu_flush_dcache_range(entry, sizeof(*entry)); - if (tcmu_hdr_get_op(&entry->hdr) == TCMU_OP_PAD) { - UPDATE_HEAD(udev->cmdr_last_cleaned, tcmu_hdr_get_len(&entry->hdr), udev->cmdr_size); + if (tcmu_hdr_get_op(entry->hdr.len_op) == TCMU_OP_PAD) { + UPDATE_HEAD(udev->cmdr_last_cleaned, + tcmu_hdr_get_len(entry->hdr.len_op), + udev->cmdr_size); continue; } - WARN_ON(tcmu_hdr_get_op(&entry->hdr) != TCMU_OP_CMD); + WARN_ON(tcmu_hdr_get_op(entry->hdr.len_op) != TCMU_OP_CMD); spin_lock(&udev->commands_lock); - cmd = idr_find(&udev->commands, entry->cmd_id); + cmd = idr_find(&udev->commands, entry->hdr.cmd_id); if (cmd) idr_remove(&udev->commands, cmd->cmd_id); spin_unlock(&udev->commands_lock); @@ -562,7 +582,9 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev) tcmu_handle_completion(cmd, entry); - UPDATE_HEAD(udev->cmdr_last_cleaned, tcmu_hdr_get_len(&entry->hdr), udev->cmdr_size); + UPDATE_HEAD(udev->cmdr_last_cleaned, + tcmu_hdr_get_len(entry->hdr.len_op), + udev->cmdr_size); handled++; } @@ -840,14 +862,14 @@ static int tcmu_configure_device(struct se_device *dev) udev->data_size = TCMU_RING_SIZE - CMDR_SIZE; mb = udev->mb_addr; - mb->version = 1; + mb->version = TCMU_MAILBOX_VERSION; mb->cmdr_off = CMDR_OFF; mb->cmdr_size = udev->cmdr_size; WARN_ON(!PAGE_ALIGNED(udev->data_off)); WARN_ON(udev->data_size % PAGE_SIZE); - info->version = "1"; + info->version = xstr(TCMU_MAILBOX_VERSION); info->mem[0].name = "tcm-user command & data buffer"; info->mem[0].addr = (phys_addr_t) udev->mb_addr; diff --git a/include/uapi/linux/target_core_user.h b/include/uapi/linux/target_core_user.h index b483d1909d3e..b67f99d3c520 100644 --- a/include/uapi/linux/target_core_user.h +++ b/include/uapi/linux/target_core_user.h @@ -6,7 +6,7 @@ #include #include -#define TCMU_VERSION "1.0" +#define TCMU_VERSION "2.0" /* * Ring Design @@ -39,9 +39,13 @@ * should process the next packet the same way, and so on. */ -#define TCMU_MAILBOX_VERSION 1 +#define TCMU_MAILBOX_VERSION 2 #define ALIGN_SIZE 64 /* Should be enough for most CPUs */ +/* See https://gcc.gnu.org/onlinedocs/cpp/Stringification.html */ +#define xstr(s) str(s) +#define str(s) #s + struct tcmu_mailbox { __u16 version; __u16 flags; @@ -64,31 +68,36 @@ enum tcmu_opcode { * Only a few opcodes, and length is 8-byte aligned, so use low bits for opcode. */ struct tcmu_cmd_entry_hdr { - __u32 len_op; + __u32 len_op; + __u16 cmd_id; + __u8 kflags; +#define TCMU_UFLAG_UNKNOWN_OP 0x1 + __u8 uflags; + } __packed; #define TCMU_OP_MASK 0x7 -static inline enum tcmu_opcode tcmu_hdr_get_op(struct tcmu_cmd_entry_hdr *hdr) +static inline enum tcmu_opcode tcmu_hdr_get_op(__u32 len_op) { - return hdr->len_op & TCMU_OP_MASK; + return len_op & TCMU_OP_MASK; } -static inline void tcmu_hdr_set_op(struct tcmu_cmd_entry_hdr *hdr, enum tcmu_opcode op) +static inline void tcmu_hdr_set_op(__u32 *len_op, enum tcmu_opcode op) { - hdr->len_op &= ~TCMU_OP_MASK; - hdr->len_op |= (op & TCMU_OP_MASK); + *len_op &= ~TCMU_OP_MASK; + *len_op |= (op & TCMU_OP_MASK); } -static inline __u32 tcmu_hdr_get_len(struct tcmu_cmd_entry_hdr *hdr) +static inline __u32 tcmu_hdr_get_len(__u32 len_op) { - return hdr->len_op & ~TCMU_OP_MASK; + return len_op & ~TCMU_OP_MASK; } -static inline void tcmu_hdr_set_len(struct tcmu_cmd_entry_hdr *hdr, __u32 len) +static inline void tcmu_hdr_set_len(__u32 *len_op, __u32 len) { - hdr->len_op &= TCMU_OP_MASK; - hdr->len_op |= len; + *len_op &= TCMU_OP_MASK; + *len_op |= len; } /* Currently the same as SCSI_SENSE_BUFFERSIZE */ @@ -97,13 +106,14 @@ static inline void tcmu_hdr_set_len(struct tcmu_cmd_entry_hdr *hdr, __u32 len) struct tcmu_cmd_entry { struct tcmu_cmd_entry_hdr hdr; - uint16_t cmd_id; - uint16_t __pad1; - union { struct { + uint32_t iov_cnt; + uint32_t iov_bidi_cnt; + uint32_t iov_dif_cnt; uint64_t cdb_off; - uint64_t iov_cnt; + uint64_t __pad1; + uint64_t __pad2; struct iovec iov[0]; } req; struct { -- cgit v1.2.3