Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending

Pull SCSI target updates from Nicholas Bellinger:
 "Lots of activity in target land the last months.

  The highlights include:

   - Convert fabric drivers tree-wide to target_register_template() (hch
     + bart)

   - iser-target hardening fixes + v1.0 improvements (sagi)

   - Convert iscsi_thread_set usage to kthread.h + kill
     iscsi_target_tq.c (sagi + nab)

   - Add support for T10-PI WRITE_STRIP + READ_INSERT operation (mkp +
     sagi + nab)

   - DIF fixes for CONFIG_DEBUG_SG=y + UNMAP file emulation (akinobu +
     sagi + mkp)

   - Extended TCMU ABI v2 for future BIDI + DIF support (andy + ilias)

   - Fix COMPARE_AND_WRITE handling for NO_ALLLOC drivers (hch + nab)

  Thanks to everyone who contributed this round with new features,
  bug-reports, fixes, cleanups and improvements.

  Looking forward, it's currently shaping up to be a busy v4.2 as well"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (69 commits)
  target: Put TCMU under a new config option
  target: Version 2 of TCMU ABI
  target: fix tcm_mod_builder.py
  target/file: Fix UNMAP with DIF protection support
  target/file: Fix SG table for prot_buf initialization
  target/file: Fix BUG() when CONFIG_DEBUG_SG=y and DIF protection enabled
  target: Make core_tmr_abort_task() skip TMFs
  target/sbc: Update sbc_dif_generate pr_debug output
  target/sbc: Make internal DIF emulation honor ->prot_checks
  target/sbc: Return INVALID_CDB_FIELD if DIF + sess_prot_type disabled
  target: Ensure sess_prot_type is saved across session restart
  target/rd: Don't pass incomplete scatterlist entries to sbc_dif_verify_*
  target: Remove the unused flag SCF_ACK_KREF
  target: Fix two sparse warnings
  target: Fix COMPARE_AND_WRITE with SG_TO_MEM_NOALLOC handling
  target: simplify the target template registration API
  target: simplify target_xcopy_init_pt_lun
  target: remove the unused SCF_CMD_XCOPY_PASSTHROUGH flag
  target/rd: reduce code duplication in rd_execute_rw()
  tcm_loop: fixup tpgt string to integer conversion
  ...
This commit is contained in:
Linus Torvalds 2015-04-24 10:22:09 -07:00
commit c6668726d2
50 changed files with 1687 additions and 2273 deletions

View file

@ -31,12 +31,13 @@ config TCM_PSCSI
Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered
passthrough access to Linux/SCSI device
config TCM_USER
config TCM_USER2
tristate "TCM/USER Subsystem Plugin for Linux"
depends on UIO && NET
help
Say Y here to enable the TCM/USER subsystem plugin for a userspace
process to handle requests
process to handle requests. This is version 2 of the ABI; version 1
is obsolete.
source "drivers/target/loopback/Kconfig"
source "drivers/target/tcm_fc/Kconfig"

View file

@ -22,7 +22,7 @@ obj-$(CONFIG_TARGET_CORE) += target_core_mod.o
obj-$(CONFIG_TCM_IBLOCK) += target_core_iblock.o
obj-$(CONFIG_TCM_FILEIO) += target_core_file.o
obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o
obj-$(CONFIG_TCM_USER) += target_core_user.o
obj-$(CONFIG_TCM_USER2) += target_core_user.o
# Fabric modules
obj-$(CONFIG_LOOPBACK_TARGET) += loopback/

View file

@ -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 \

View file

@ -33,8 +33,6 @@
#include <target/iscsi/iscsi_target_core.h>
#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"
#include "iscsi_target_erl1.h"
@ -537,7 +535,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,24 +544,21 @@ 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);
idr_init(&sess_idr);
ret = iscsi_target_register_configfs();
if (ret < 0)
ret = target_register_template(&iscsi_ops);
if (ret)
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 +567,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,12 +612,13 @@ 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();
/* 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;
@ -630,8 +626,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);
@ -639,8 +633,15 @@ 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);
}
@ -990,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);
@ -1805,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);
@ -2155,7 +2155,6 @@ reject:
cmd->text_in_ptr = NULL;
return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
}
EXPORT_SYMBOL(iscsit_handle_text_cmd);
int iscsit_logout_closesession(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
{
@ -3715,17 +3714,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);
@ -3914,7 +3912,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:
@ -3942,8 +3940,6 @@ check_rsp_state:
err:
return -1;
restart:
return -EAGAIN;
}
static int iscsit_handle_response_queue(struct iscsi_conn *conn)
@ -3970,21 +3966,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
@ -3993,11 +3981,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:
@ -4008,15 +3994,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;
}
@ -4111,8 +4096,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
@ -4120,11 +4104,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;
@ -4134,7 +4113,7 @@ restart:
if (rc < 0)
goto transport_err;
goto out;
goto transport_err;
}
while (!kthread_should_stop()) {
@ -4210,8 +4189,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;
}
@ -4273,7 +4250,24 @@ int iscsit_close_connection(
if (conn->conn_transport->transport_type == ISCSI_TCP)
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);
@ -4383,8 +4377,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);
@ -4551,15 +4543,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);
}
@ -4567,13 +4557,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);
}

View file

@ -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;

View file

@ -37,9 +37,6 @@
#include "iscsi_target_util.h"
#include "iscsi_target.h"
#include <target/iscsi/iscsi_target_stat.h>
#include "iscsi_target_configfs.h"
struct target_fabric_configfs *lio_target_fabric_configfs;
struct lio_target_configfs_attribute {
struct configfs_attribute attr;
@ -1052,6 +1049,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 +1067,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,
};
@ -1410,8 +1413,18 @@ out:
TF_TPG_BASE_ATTR(lio_target, enable, S_IRUGO | S_IWUSR);
static ssize_t lio_target_tpg_show_dynamic_sessions(
struct se_portal_group *se_tpg,
char *page)
{
return target_show_dynamic_sessions(se_tpg, page);
}
TF_TPG_BASE_ATTR_RO(lio_target, dynamic_sessions);
static struct configfs_attribute *lio_target_tpg_attrs[] = {
&lio_target_tpg_enable.attr,
&lio_target_tpg_dynamic_sessions.attr,
NULL,
};
@ -1450,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;
@ -1872,6 +1883,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)
@ -1953,115 +1978,60 @@ static void lio_release_cmd(struct se_cmd *se_cmd)
iscsit_release_cmd(cmd);
}
/* End functions for target_core_fabric_ops */
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,
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_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");
}
.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,
};

View file

@ -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 */

View file

@ -23,7 +23,6 @@
#include <target/iscsi/iscsi_target_core.h>
#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"
@ -860,7 +859,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);
@ -885,10 +887,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) {

View file

@ -26,7 +26,6 @@
#include <target/iscsi/iscsi_target_core.h>
#include <target/iscsi/iscsi_target_stat.h>
#include "iscsi_target_tq.h"
#include "iscsi_target_device.h"
#include "iscsi_target_nego.h"
#include "iscsi_target_erl0.h"
@ -699,6 +698,51 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn)
iscsit_start_nopin_timer(conn);
}
static 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 +753,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 +768,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 +794,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 +855,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.

View file

@ -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;
@ -228,6 +226,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 +877,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;
}

View file

@ -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 */

View file

@ -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 <nab@linux-iscsi.org>
*
* 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 <linux/kthread.h>
#include <linux/list.h>
#include <linux/bitmap.h>
#include <target/iscsi/iscsi_target_core.h>
#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);
}

View file

@ -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 ***/

View file

@ -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"

View file

@ -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;
@ -108,7 +107,7 @@ static struct device_driver tcm_loop_driverfs = {
/*
* Used with root_device_register() in tcm_loop_alloc_core_bus() below
*/
struct device *tcm_loop_primary;
static struct device *tcm_loop_primary;
static void tcm_loop_submission_work(struct work_struct *work)
{
@ -697,6 +696,13 @@ static int tcm_loop_check_prod_mode_write_protect(struct se_portal_group *se_tpg
return 0;
}
static int tcm_loop_check_prot_fabric_only(struct se_portal_group *se_tpg)
{
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg,
tl_se_tpg);
return tl_tpg->tl_fabric_prot_type;
}
static struct se_node_acl *tcm_loop_tpg_alloc_fabric_acl(
struct se_portal_group *se_tpg)
{
@ -912,6 +918,46 @@ static void tcm_loop_port_unlink(
/* End items for tcm_loop_port_cit */
static ssize_t tcm_loop_tpg_attrib_show_fabric_prot_type(
struct se_portal_group *se_tpg,
char *page)
{
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg,
tl_se_tpg);
return sprintf(page, "%d\n", tl_tpg->tl_fabric_prot_type);
}
static ssize_t tcm_loop_tpg_attrib_store_fabric_prot_type(
struct se_portal_group *se_tpg,
const char *page,
size_t count)
{
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg,
tl_se_tpg);
unsigned long val;
int ret = kstrtoul(page, 0, &val);
if (ret) {
pr_err("kstrtoul() returned %d for fabric_prot_type\n", ret);
return ret;
}
if (val != 0 && val != 1 && val != 3) {
pr_err("Invalid qla2xxx fabric_prot_type: %lu\n", val);
return -EINVAL;
}
tl_tpg->tl_fabric_prot_type = val;
return count;
}
TF_TPG_ATTRIB_ATTR(tcm_loop, fabric_prot_type, S_IRUGO | S_IWUSR);
static struct configfs_attribute *tcm_loop_tpg_attrib_attrs[] = {
&tcm_loop_tpg_attrib_fabric_prot_type.attr,
NULL,
};
/* Start items for tcm_loop_nexus_cit */
static int tcm_loop_make_nexus(
@ -937,7 +983,8 @@ static int tcm_loop_make_nexus(
/*
* Initialize the struct se_session pointer
*/
tl_nexus->se_sess = transport_init_session(TARGET_PROT_ALL);
tl_nexus->se_sess = transport_init_session(
TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS);
if (IS_ERR(tl_nexus->se_sess)) {
ret = PTR_ERR(tl_nexus->se_sess);
goto out;
@ -1165,21 +1212,19 @@ static struct se_portal_group *tcm_loop_make_naa_tpg(
struct tcm_loop_hba *tl_hba = container_of(wwn,
struct tcm_loop_hba, tl_hba_wwn);
struct tcm_loop_tpg *tl_tpg;
char *tpgt_str, *end_ptr;
int ret;
unsigned short int tpgt;
unsigned long tpgt;
tpgt_str = strstr(name, "tpgt_");
if (!tpgt_str) {
if (strstr(name, "tpgt_") != name) {
pr_err("Unable to locate \"tpgt_#\" directory"
" group\n");
return ERR_PTR(-EINVAL);
}
tpgt_str += 5; /* Skip ahead of "tpgt_" */
tpgt = (unsigned short int) simple_strtoul(tpgt_str, &end_ptr, 0);
if (kstrtoul(name+5, 10, &tpgt))
return ERR_PTR(-EINVAL);
if (tpgt >= TL_TPGS_PER_HBA) {
pr_err("Passed tpgt: %hu exceeds TL_TPGS_PER_HBA:"
pr_err("Passed tpgt: %lu exceeds TL_TPGS_PER_HBA:"
" %u\n", tpgt, TL_TPGS_PER_HBA);
return ERR_PTR(-EINVAL);
}
@ -1189,14 +1234,13 @@ 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);
pr_debug("TCM_Loop_ConfigFS: Allocated Emulated %s"
" Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba),
" Target Port %s,t,0x%04lx\n", tcm_loop_dump_proto_id(tl_hba),
config_item_name(&wwn->wwn_group.cg_item), tpgt);
return &tl_tpg->tl_se_tpg;
@ -1338,127 +1382,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;
/*
* 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 = NULL;
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)
{
@ -1482,7 +1450,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;
@ -1500,7 +1468,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);

View file

@ -43,6 +43,7 @@ struct tcm_loop_nacl {
struct tcm_loop_tpg {
unsigned short tl_tpgt;
unsigned short tl_transport_status;
enum target_prot_type tl_fabric_prot_type;
atomic_t tl_tpg_port_count;
struct se_portal_group tl_se_tpg;
struct tcm_loop_hba *tl_hba;

View file

@ -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");

View file

@ -142,8 +142,8 @@ static struct config_group *target_core_register_fabric(
tf = target_core_get_fabric(name);
if (!tf) {
pr_err("target_core_register_fabric() trying autoload for %s\n",
name);
pr_debug("target_core_register_fabric() trying autoload for %s\n",
name);
/*
* Below are some hardcoded request_module() calls to automatically
@ -165,8 +165,8 @@ static struct config_group *target_core_register_fabric(
*/
ret = request_module("iscsi_target_mod");
if (ret < 0) {
pr_err("request_module() failed for"
" iscsi_target_mod.ko: %d\n", ret);
pr_debug("request_module() failed for"
" iscsi_target_mod.ko: %d\n", ret);
return ERR_PTR(-EINVAL);
}
} else if (!strncmp(name, "loopback", 8)) {
@ -178,8 +178,8 @@ static struct config_group *target_core_register_fabric(
*/
ret = request_module("tcm_loop");
if (ret < 0) {
pr_err("request_module() failed for"
" tcm_loop.ko: %d\n", ret);
pr_debug("request_module() failed for"
" tcm_loop.ko: %d\n", ret);
return ERR_PTR(-EINVAL);
}
}
@ -188,8 +188,8 @@ static struct config_group *target_core_register_fabric(
}
if (!tf) {
pr_err("target_core_get_fabric() failed for %s\n",
name);
pr_debug("target_core_get_fabric() failed for %s\n",
name);
return ERR_PTR(-EINVAL);
}
pr_debug("Target_Core_ConfigFS: REGISTER -> Located fabric:"
@ -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;
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;
}
ret = target_fabric_tf_ops_check(tf);
if (ret < 0)
ret = target_fabric_tf_ops_check(fo);
if (ret)
return ret;
pr_debug("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>"
">>>>>>>>>>\n");
return 0;
}
EXPORT_SYMBOL(target_fabric_configfs_register);
void target_fabric_configfs_deregister(
struct target_fabric_configfs *tf)
{
struct configfs_subsystem *su;
tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL);
if (!tf) {
pr_err("Unable to locate passed target_fabric_"
"configfs\n");
return;
pr_err("%s: could not allocate memory!\n", __func__);
return -ENOMEM;
}
su = tf->tf_subsys;
if (!su) {
pr_err("Unable to locate passed tf->tf_subsys"
" pointer\n");
return;
}
pr_debug("<<<<<<<<<<<<<<<<<<<<<< BEGIN 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);
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_del(&tf->tf_list);
list_add_tail(&tf->tf_list, &g_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");
return 0;
}
EXPORT_SYMBOL(target_fabric_configfs_deregister);
EXPORT_SYMBOL(target_register_template);
void target_unregister_template(const struct target_core_fabric_ops *fo)
{
struct target_fabric_configfs *t;
mutex_lock(&g_tf_lock);
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;
}
}
mutex_unlock(&g_tf_lock);
}
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];

View file

@ -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 */

View file

@ -264,40 +264,32 @@ static int fd_do_prot_rw(struct se_cmd *cmd, struct fd_prot *fd_prot,
struct se_device *se_dev = cmd->se_dev;
struct fd_dev *dev = FD_DEV(se_dev);
struct file *prot_fd = dev->fd_prot_file;
struct scatterlist *sg;
loff_t pos = (cmd->t_task_lba * se_dev->prot_length);
unsigned char *buf;
u32 prot_size, len, size;
int rc, ret = 1, i;
u32 prot_size;
int rc, ret = 1;
prot_size = (cmd->data_length / se_dev->dev_attrib.block_size) *
se_dev->prot_length;
if (!is_write) {
fd_prot->prot_buf = vzalloc(prot_size);
fd_prot->prot_buf = kzalloc(prot_size, GFP_KERNEL);
if (!fd_prot->prot_buf) {
pr_err("Unable to allocate fd_prot->prot_buf\n");
return -ENOMEM;
}
buf = fd_prot->prot_buf;
fd_prot->prot_sg_nents = cmd->t_prot_nents;
fd_prot->prot_sg = kzalloc(sizeof(struct scatterlist) *
fd_prot->prot_sg_nents, GFP_KERNEL);
fd_prot->prot_sg_nents = 1;
fd_prot->prot_sg = kzalloc(sizeof(struct scatterlist),
GFP_KERNEL);
if (!fd_prot->prot_sg) {
pr_err("Unable to allocate fd_prot->prot_sg\n");
vfree(fd_prot->prot_buf);
kfree(fd_prot->prot_buf);
return -ENOMEM;
}
size = prot_size;
for_each_sg(fd_prot->prot_sg, sg, fd_prot->prot_sg_nents, i) {
len = min_t(u32, PAGE_SIZE, size);
sg_set_buf(sg, buf, len);
size -= len;
buf += len;
}
sg_init_table(fd_prot->prot_sg, fd_prot->prot_sg_nents);
sg_set_buf(fd_prot->prot_sg, buf, prot_size);
}
if (is_write) {
@ -318,7 +310,7 @@ static int fd_do_prot_rw(struct se_cmd *cmd, struct fd_prot *fd_prot,
if (is_write || ret < 0) {
kfree(fd_prot->prot_sg);
vfree(fd_prot->prot_buf);
kfree(fd_prot->prot_buf);
}
return ret;
@ -331,36 +323,33 @@ static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl,
struct fd_dev *dev = FD_DEV(se_dev);
struct file *fd = dev->fd_file;
struct scatterlist *sg;
struct iovec *iov;
mm_segment_t old_fs;
struct iov_iter iter;
struct bio_vec *bvec;
ssize_t len = 0;
loff_t pos = (cmd->t_task_lba * se_dev->dev_attrib.block_size);
int ret = 0, i;
iov = kzalloc(sizeof(struct iovec) * sgl_nents, GFP_KERNEL);
if (!iov) {
bvec = kcalloc(sgl_nents, sizeof(struct bio_vec), GFP_KERNEL);
if (!bvec) {
pr_err("Unable to allocate fd_do_readv iov[]\n");
return -ENOMEM;
}
for_each_sg(sgl, sg, sgl_nents, i) {
iov[i].iov_len = sg->length;
iov[i].iov_base = kmap(sg_page(sg)) + sg->offset;
bvec[i].bv_page = sg_page(sg);
bvec[i].bv_len = sg->length;
bvec[i].bv_offset = sg->offset;
len += sg->length;
}
old_fs = get_fs();
set_fs(get_ds());
iov_iter_bvec(&iter, ITER_BVEC, bvec, sgl_nents, len);
if (is_write)
ret = vfs_writev(fd, &iov[0], sgl_nents, &pos);
ret = vfs_iter_write(fd, &iter, &pos);
else
ret = vfs_readv(fd, &iov[0], sgl_nents, &pos);
ret = vfs_iter_read(fd, &iter, &pos);
set_fs(old_fs);
for_each_sg(sgl, sg, sgl_nents, i)
kunmap(sg_page(sg));
kfree(iov);
kfree(bvec);
if (is_write) {
if (ret < 0 || ret != cmd->data_length) {
@ -436,59 +425,17 @@ fd_execute_sync_cache(struct se_cmd *cmd)
return 0;
}
static unsigned char *
fd_setup_write_same_buf(struct se_cmd *cmd, struct scatterlist *sg,
unsigned int len)
{
struct se_device *se_dev = cmd->se_dev;
unsigned int block_size = se_dev->dev_attrib.block_size;
unsigned int i = 0, end;
unsigned char *buf, *p, *kmap_buf;
buf = kzalloc(min_t(unsigned int, len, PAGE_SIZE), GFP_KERNEL);
if (!buf) {
pr_err("Unable to allocate fd_execute_write_same buf\n");
return NULL;
}
kmap_buf = kmap(sg_page(sg)) + sg->offset;
if (!kmap_buf) {
pr_err("kmap() failed in fd_setup_write_same\n");
kfree(buf);
return NULL;
}
/*
* Fill local *buf to contain multiple WRITE_SAME blocks up to
* min(len, PAGE_SIZE)
*/
p = buf;
end = min_t(unsigned int, len, PAGE_SIZE);
while (i < end) {
memcpy(p, kmap_buf, block_size);
i += block_size;
p += block_size;
}
kunmap(sg_page(sg));
return buf;
}
static sense_reason_t
fd_execute_write_same(struct se_cmd *cmd)
{
struct se_device *se_dev = cmd->se_dev;
struct fd_dev *fd_dev = FD_DEV(se_dev);
struct file *f = fd_dev->fd_file;
struct scatterlist *sg;
struct iovec *iov;
mm_segment_t old_fs;
sector_t nolb = sbc_get_write_same_sectors(cmd);
loff_t pos = cmd->t_task_lba * se_dev->dev_attrib.block_size;
unsigned int len, len_tmp, iov_num;
int i, rc;
unsigned char *buf;
sector_t nolb = sbc_get_write_same_sectors(cmd);
struct iov_iter iter;
struct bio_vec *bvec;
unsigned int len = 0, i;
ssize_t ret;
if (!nolb) {
target_complete_cmd(cmd, SAM_STAT_GOOD);
@ -499,49 +446,35 @@ fd_execute_write_same(struct se_cmd *cmd)
" backends not supported\n");
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
sg = &cmd->t_data_sg[0];
if (cmd->t_data_nents > 1 ||
sg->length != cmd->se_dev->dev_attrib.block_size) {
cmd->t_data_sg[0].length != cmd->se_dev->dev_attrib.block_size) {
pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u"
" block_size: %u\n", cmd->t_data_nents, sg->length,
" block_size: %u\n",
cmd->t_data_nents,
cmd->t_data_sg[0].length,
cmd->se_dev->dev_attrib.block_size);
return TCM_INVALID_CDB_FIELD;
}
len = len_tmp = nolb * se_dev->dev_attrib.block_size;
iov_num = DIV_ROUND_UP(len, PAGE_SIZE);
buf = fd_setup_write_same_buf(cmd, sg, len);
if (!buf)
bvec = kcalloc(nolb, sizeof(struct bio_vec), GFP_KERNEL);
if (!bvec)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
iov = vzalloc(sizeof(struct iovec) * iov_num);
if (!iov) {
pr_err("Unable to allocate fd_execute_write_same iovecs\n");
kfree(buf);
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
/*
* Map the single fabric received scatterlist block now populated
* in *buf into each iovec for I/O submission.
*/
for (i = 0; i < iov_num; i++) {
iov[i].iov_base = buf;
iov[i].iov_len = min_t(unsigned int, len_tmp, PAGE_SIZE);
len_tmp -= iov[i].iov_len;
for (i = 0; i < nolb; i++) {
bvec[i].bv_page = sg_page(&cmd->t_data_sg[0]);
bvec[i].bv_len = cmd->t_data_sg[0].length;
bvec[i].bv_offset = cmd->t_data_sg[0].offset;
len += se_dev->dev_attrib.block_size;
}
old_fs = get_fs();
set_fs(get_ds());
rc = vfs_writev(f, &iov[0], iov_num, &pos);
set_fs(old_fs);
iov_iter_bvec(&iter, ITER_BVEC, bvec, nolb, len);
ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos);
vfree(iov);
kfree(buf);
if (rc < 0 || rc != len) {
pr_err("vfs_writev() returned %d for write same\n", rc);
kfree(bvec);
if (ret < 0 || ret != len) {
pr_err("vfs_iter_write() returned %zd for write same\n", ret);
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
@ -549,6 +482,56 @@ fd_execute_write_same(struct se_cmd *cmd)
return 0;
}
static int
fd_do_prot_fill(struct se_device *se_dev, sector_t lba, sector_t nolb,
void *buf, size_t bufsize)
{
struct fd_dev *fd_dev = FD_DEV(se_dev);
struct file *prot_fd = fd_dev->fd_prot_file;
sector_t prot_length, prot;
loff_t pos = lba * se_dev->prot_length;
if (!prot_fd) {
pr_err("Unable to locate fd_dev->fd_prot_file\n");
return -ENODEV;
}
prot_length = nolb * se_dev->prot_length;
for (prot = 0; prot < prot_length;) {
sector_t len = min_t(sector_t, bufsize, prot_length - prot);
ssize_t ret = kernel_write(prot_fd, buf, len, pos + prot);
if (ret != len) {
pr_err("vfs_write to prot file failed: %zd\n", ret);
return ret < 0 ? ret : -ENODEV;
}
prot += ret;
}
return 0;
}
static int
fd_do_prot_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb)
{
void *buf;
int rc;
buf = (void *)__get_free_page(GFP_KERNEL);
if (!buf) {
pr_err("Unable to allocate FILEIO prot buf\n");
return -ENOMEM;
}
memset(buf, 0xff, PAGE_SIZE);
rc = fd_do_prot_fill(cmd->se_dev, lba, nolb, buf, PAGE_SIZE);
free_page((unsigned long)buf);
return rc;
}
static sense_reason_t
fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb)
{
@ -556,6 +539,12 @@ fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb)
struct inode *inode = file->f_mapping->host;
int ret;
if (cmd->se_dev->dev_attrib.pi_prot_type) {
ret = fd_do_prot_unmap(cmd, lba, nolb);
if (ret)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
if (S_ISBLK(inode->i_mode)) {
/* The backend is block device, use discard */
struct block_device *bdev = inode->i_bdev;
@ -595,7 +584,7 @@ fd_execute_write_same_unmap(struct se_cmd *cmd)
struct file *file = fd_dev->fd_file;
sector_t lba = cmd->t_task_lba;
sector_t nolb = sbc_get_write_same_sectors(cmd);
int ret;
sense_reason_t ret;
if (!nolb) {
target_complete_cmd(cmd, SAM_STAT_GOOD);
@ -643,7 +632,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
if (data_direction == DMA_FROM_DEVICE) {
memset(&fd_prot, 0, sizeof(struct fd_prot));
if (cmd->prot_type) {
if (cmd->prot_type && dev->dev_attrib.pi_prot_type) {
ret = fd_do_prot_rw(cmd, &fd_prot, false);
if (ret < 0)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@ -651,23 +640,23 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
ret = fd_do_rw(cmd, sgl, sgl_nents, 0);
if (ret > 0 && cmd->prot_type) {
if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type) {
u32 sectors = cmd->data_length / dev->dev_attrib.block_size;
rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors,
0, fd_prot.prot_sg, 0);
if (rc) {
kfree(fd_prot.prot_sg);
vfree(fd_prot.prot_buf);
kfree(fd_prot.prot_buf);
return rc;
}
kfree(fd_prot.prot_sg);
vfree(fd_prot.prot_buf);
kfree(fd_prot.prot_buf);
}
} else {
memset(&fd_prot, 0, sizeof(struct fd_prot));
if (cmd->prot_type) {
if (cmd->prot_type && dev->dev_attrib.pi_prot_type) {
u32 sectors = cmd->data_length / dev->dev_attrib.block_size;
ret = fd_do_prot_rw(cmd, &fd_prot, false);
@ -678,7 +667,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
0, fd_prot.prot_sg, 0);
if (rc) {
kfree(fd_prot.prot_sg);
vfree(fd_prot.prot_buf);
kfree(fd_prot.prot_buf);
return rc;
}
}
@ -705,7 +694,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
vfs_fsync_range(fd_dev->fd_file, start, end, 1);
}
if (ret > 0 && cmd->prot_type) {
if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type) {
ret = fd_do_prot_rw(cmd, &fd_prot, true);
if (ret < 0)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@ -714,7 +703,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
if (ret < 0) {
kfree(fd_prot.prot_sg);
vfree(fd_prot.prot_buf);
kfree(fd_prot.prot_buf);
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
@ -878,48 +867,28 @@ static int fd_init_prot(struct se_device *dev)
static int fd_format_prot(struct se_device *dev)
{
struct fd_dev *fd_dev = FD_DEV(dev);
struct file *prot_fd = fd_dev->fd_prot_file;
sector_t prot_length, prot;
unsigned char *buf;
loff_t pos = 0;
int unit_size = FDBD_FORMAT_UNIT_SIZE * dev->dev_attrib.block_size;
int rc, ret = 0, size, len;
int ret;
if (!dev->dev_attrib.pi_prot_type) {
pr_err("Unable to format_prot while pi_prot_type == 0\n");
return -ENODEV;
}
if (!prot_fd) {
pr_err("Unable to locate fd_dev->fd_prot_file\n");
return -ENODEV;
}
buf = vzalloc(unit_size);
if (!buf) {
pr_err("Unable to allocate FILEIO prot buf\n");
return -ENOMEM;
}
prot_length = (dev->transport->get_blocks(dev) + 1) * dev->prot_length;
size = prot_length;
pr_debug("Using FILEIO prot_length: %llu\n",
(unsigned long long)prot_length);
(unsigned long long)(dev->transport->get_blocks(dev) + 1) *
dev->prot_length);
memset(buf, 0xff, unit_size);
for (prot = 0; prot < prot_length; prot += unit_size) {
len = min(unit_size, size);
rc = kernel_write(prot_fd, buf, len, pos);
if (rc != len) {
pr_err("vfs_write to prot file failed: %d\n", rc);
ret = -ENODEV;
goto out;
}
pos += len;
size -= len;
}
out:
ret = fd_do_prot_fill(dev, 0, dev->transport->get_blocks(dev) + 1,
buf, unit_size);
vfree(buf);
return ret;
}

View file

@ -444,7 +444,7 @@ iblock_execute_write_same_unmap(struct se_cmd *cmd)
struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd;
sector_t lba = cmd->t_task_lba;
sector_t nolb = sbc_get_write_same_sectors(cmd);
int ret;
sense_reason_t ret;
ret = iblock_do_unmap(cmd, bdev, lba, nolb);
if (ret)
@ -774,7 +774,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
sg_num--;
}
if (cmd->prot_type) {
if (cmd->prot_type && dev->dev_attrib.pi_prot_type) {
int rc = iblock_alloc_bip(cmd, bio_start);
if (rc)
goto fail_put_bios;

View file

@ -4,7 +4,13 @@
/* target_core_alua.c */
extern struct t10_alua_lu_gp *default_lu_gp;
/* target_core_configfs.c */
extern struct configfs_subsystem *target_core_subsystem[];
/* target_core_device.c */
extern struct mutex g_device_mutex;
extern struct list_head g_device_list;
struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16);
int core_free_device_list_for_node(struct se_node_acl *,
struct se_portal_group *);

View file

@ -78,6 +78,22 @@ enum preempt_type {
static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *,
struct t10_pr_registration *, int, int);
static int is_reservation_holder(
struct t10_pr_registration *pr_res_holder,
struct t10_pr_registration *pr_reg)
{
int pr_res_type;
if (pr_res_holder) {
pr_res_type = pr_res_holder->pr_res_type;
return pr_res_holder == pr_reg ||
pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG ||
pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG;
}
return 0;
}
static sense_reason_t
target_scsi2_reservation_check(struct se_cmd *cmd)
{
@ -664,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;
/*
@ -963,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,
@ -1004,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;
@ -1220,8 +1236,10 @@ static void __core_scsi3_free_registration(
struct t10_pr_registration *pr_reg,
struct list_head *preempt_and_abort_list,
int dec_holders)
__releases(&pr_tmpl->registration_lock)
__acquires(&pr_tmpl->registration_lock)
{
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];
@ -1445,7 +1463,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];
@ -2287,7 +2305,6 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)
spin_lock(&dev->dev_reservation_lock);
pr_res_holder = dev->dev_pr_res_holder;
if (pr_res_holder) {
int pr_res_type = pr_res_holder->pr_res_type;
/*
* From spc4r17 Section 5.7.9: Reserving:
*
@ -2298,9 +2315,7 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)
* the logical unit, then the command shall be completed with
* RESERVATION CONFLICT status.
*/
if ((pr_res_holder != pr_reg) &&
(pr_res_type != PR_TYPE_WRITE_EXCLUSIVE_ALLREG) &&
(pr_res_type != PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
if (!is_reservation_holder(pr_res_holder, pr_reg)) {
struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
pr_err("SPC-3 PR: Attempted RESERVE from"
" [%s]: %s while reservation already held by"
@ -2409,7 +2424,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;
@ -2477,7 +2492,6 @@ core_scsi3_emulate_pro_release(struct se_cmd *cmd, int type, int scope,
struct se_lun *se_lun = cmd->se_lun;
struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_res_holder;
struct t10_reservation *pr_tmpl = &dev->t10_pr;
int all_reg = 0;
sense_reason_t ret = 0;
if (!se_sess || !se_lun) {
@ -2514,13 +2528,9 @@ core_scsi3_emulate_pro_release(struct se_cmd *cmd, int type, int scope,
spin_unlock(&dev->dev_reservation_lock);
goto out_put_pr_reg;
}
if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
(pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG))
all_reg = 1;
if ((all_reg == 0) && (pr_res_holder != pr_reg)) {
if (!is_reservation_holder(pr_res_holder, pr_reg)) {
/*
* Non 'All Registrants' PR Type cases..
* Release request from a registered I_T nexus that is not a
* persistent reservation holder. return GOOD status.
*/
@ -2726,7 +2736,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);
@ -3111,7 +3121,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;
@ -3375,7 +3385,7 @@ after_iport_check:
* From spc4r17 section 5.7.8 Table 50 --
* Register behaviors for a REGISTER AND MOVE service action
*/
if (pr_res_holder != pr_reg) {
if (!is_reservation_holder(pr_res_holder, pr_reg)) {
pr_warn("SPC-3 PR REGISTER_AND_MOVE: Calling I_T"
" Nexus is not reservation holder\n");
spin_unlock(&dev->dev_reservation_lock);

View file

@ -139,10 +139,22 @@ static int rd_allocate_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *
unsigned char *p;
while (total_sg_needed) {
unsigned int chain_entry = 0;
sg_per_table = (total_sg_needed > max_sg_per_table) ?
max_sg_per_table : total_sg_needed;
sg = kzalloc(sg_per_table * sizeof(struct scatterlist),
#ifdef CONFIG_ARCH_HAS_SG_CHAIN
/*
* Reserve extra element for chain entry
*/
if (sg_per_table < total_sg_needed)
chain_entry = 1;
#endif /* CONFIG_ARCH_HAS_SG_CHAIN */
sg = kcalloc(sg_per_table + chain_entry, sizeof(*sg),
GFP_KERNEL);
if (!sg) {
pr_err("Unable to allocate scatterlist array"
@ -150,7 +162,16 @@ static int rd_allocate_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *
return -ENOMEM;
}
sg_init_table(sg, sg_per_table);
sg_init_table(sg, sg_per_table + chain_entry);
#ifdef CONFIG_ARCH_HAS_SG_CHAIN
if (i > 0) {
sg_chain(sg_table[i - 1].sg_table,
max_sg_per_table + 1, sg);
}
#endif /* CONFIG_ARCH_HAS_SG_CHAIN */
sg_table[i].sg_table = sg;
sg_table[i].rd_sg_count = sg_per_table;
@ -382,6 +403,76 @@ static struct rd_dev_sg_table *rd_get_prot_table(struct rd_dev *rd_dev, u32 page
return NULL;
}
typedef sense_reason_t (*dif_verify)(struct se_cmd *, sector_t, unsigned int,
unsigned int, struct scatterlist *, int);
static sense_reason_t rd_do_prot_rw(struct se_cmd *cmd, dif_verify dif_verify)
{
struct se_device *se_dev = cmd->se_dev;
struct rd_dev *dev = RD_DEV(se_dev);
struct rd_dev_sg_table *prot_table;
bool need_to_release = false;
struct scatterlist *prot_sg;
u32 sectors = cmd->data_length / se_dev->dev_attrib.block_size;
u32 prot_offset, prot_page;
u32 prot_npages __maybe_unused;
u64 tmp;
sense_reason_t rc = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
tmp = cmd->t_task_lba * se_dev->prot_length;
prot_offset = do_div(tmp, PAGE_SIZE);
prot_page = tmp;
prot_table = rd_get_prot_table(dev, prot_page);
if (!prot_table)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
prot_sg = &prot_table->sg_table[prot_page -
prot_table->page_start_offset];
#ifndef CONFIG_ARCH_HAS_SG_CHAIN
prot_npages = DIV_ROUND_UP(prot_offset + sectors * se_dev->prot_length,
PAGE_SIZE);
/*
* Allocate temporaly contiguous scatterlist entries if prot pages
* straddles multiple scatterlist tables.
*/
if (prot_table->page_end_offset < prot_page + prot_npages - 1) {
int i;
prot_sg = kcalloc(prot_npages, sizeof(*prot_sg), GFP_KERNEL);
if (!prot_sg)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
need_to_release = true;
sg_init_table(prot_sg, prot_npages);
for (i = 0; i < prot_npages; i++) {
if (prot_page + i > prot_table->page_end_offset) {
prot_table = rd_get_prot_table(dev,
prot_page + i);
if (!prot_table) {
kfree(prot_sg);
return rc;
}
sg_unmark_end(&prot_sg[i - 1]);
}
prot_sg[i] = prot_table->sg_table[prot_page + i -
prot_table->page_start_offset];
}
}
#endif /* !CONFIG_ARCH_HAS_SG_CHAIN */
rc = dif_verify(cmd, cmd->t_task_lba, sectors, 0, prot_sg, prot_offset);
if (need_to_release)
kfree(prot_sg);
return rc;
}
static sense_reason_t
rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
enum dma_data_direction data_direction)
@ -419,24 +510,9 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
data_direction == DMA_FROM_DEVICE ? "Read" : "Write",
cmd->t_task_lba, rd_size, rd_page, rd_offset);
if (cmd->prot_type && data_direction == DMA_TO_DEVICE) {
struct rd_dev_sg_table *prot_table;
struct scatterlist *prot_sg;
u32 sectors = cmd->data_length / se_dev->dev_attrib.block_size;
u32 prot_offset, prot_page;
tmp = cmd->t_task_lba * se_dev->prot_length;
prot_offset = do_div(tmp, PAGE_SIZE);
prot_page = tmp;
prot_table = rd_get_prot_table(dev, prot_page);
if (!prot_table)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
prot_sg = &prot_table->sg_table[prot_page - prot_table->page_start_offset];
rc = sbc_dif_verify_write(cmd, cmd->t_task_lba, sectors, 0,
prot_sg, prot_offset);
if (cmd->prot_type && se_dev->dev_attrib.pi_prot_type &&
data_direction == DMA_TO_DEVICE) {
rc = rd_do_prot_rw(cmd, sbc_dif_verify_write);
if (rc)
return rc;
}
@ -502,24 +578,9 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
}
sg_miter_stop(&m);
if (cmd->prot_type && data_direction == DMA_FROM_DEVICE) {
struct rd_dev_sg_table *prot_table;
struct scatterlist *prot_sg;
u32 sectors = cmd->data_length / se_dev->dev_attrib.block_size;
u32 prot_offset, prot_page;
tmp = cmd->t_task_lba * se_dev->prot_length;
prot_offset = do_div(tmp, PAGE_SIZE);
prot_page = tmp;
prot_table = rd_get_prot_table(dev, prot_page);
if (!prot_table)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
prot_sg = &prot_table->sg_table[prot_page - prot_table->page_start_offset];
rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, 0,
prot_sg, prot_offset);
if (cmd->prot_type && se_dev->dev_attrib.pi_prot_type &&
data_direction == DMA_FROM_DEVICE) {
rc = rd_do_prot_rw(cmd, sbc_dif_verify_read);
if (rc)
return rc;
}

View file

@ -93,6 +93,8 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
struct se_session *sess = cmd->se_sess;
int pi_prot_type = dev->dev_attrib.pi_prot_type;
unsigned char *rbuf;
unsigned char buf[32];
unsigned long long blocks = dev->transport->get_blocks(dev);
@ -114,8 +116,15 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
* Set P_TYPE and PROT_EN bits for DIF support
*/
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
if (dev->dev_attrib.pi_prot_type)
buf[12] = (dev->dev_attrib.pi_prot_type - 1) << 1 | 0x1;
/*
* Only override a device's pi_prot_type if no T10-PI is
* available, and sess_prot_type has been explicitly enabled.
*/
if (!pi_prot_type)
pi_prot_type = sess->sess_prot_type;
if (pi_prot_type)
buf[12] = (pi_prot_type - 1) << 1 | 0x1;
}
if (dev->transport->get_lbppbe)
@ -312,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;
@ -376,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;
@ -399,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;
@ -414,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.
@ -581,12 +595,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 +625,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 +660,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 +689,32 @@ 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;
}
if (!protect)
return TCM_NO_SENSE;
/* Fallthrough */
default:
return TCM_NO_SENSE;
pr_err("Unable to determine pi_prot_type for CDB: 0x%02x "
"PROTECT: 0x%02x\n", cdb[0], protect);
return TCM_INVALID_CDB_FIELD;
}
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;
/**
@ -1166,14 +1203,16 @@ sbc_dif_generate(struct se_cmd *cmd)
sdt = paddr + offset;
sdt->guard_tag = cpu_to_be16(crc_t10dif(daddr + j,
dev->dev_attrib.block_size));
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT)
if (cmd->prot_type == TARGET_DIF_TYPE1_PROT)
sdt->ref_tag = cpu_to_be32(sector & 0xffffffff);
sdt->app_tag = 0;
pr_debug("DIF WRITE INSERT sector: %llu guard_tag: 0x%04x"
pr_debug("DIF %s INSERT sector: %llu guard_tag: 0x%04x"
" app_tag: 0x%04x ref_tag: %u\n",
(unsigned long long)sector, sdt->guard_tag,
sdt->app_tag, be32_to_cpu(sdt->ref_tag));
(cmd->data_direction == DMA_TO_DEVICE) ?
"WRITE" : "READ", (unsigned long long)sector,
sdt->guard_tag, sdt->app_tag,
be32_to_cpu(sdt->ref_tag));
sector++;
offset += sizeof(struct se_dif_v1_tuple);
@ -1185,12 +1224,16 @@ sbc_dif_generate(struct se_cmd *cmd)
}
static sense_reason_t
sbc_dif_v1_verify(struct se_device *dev, struct se_dif_v1_tuple *sdt,
sbc_dif_v1_verify(struct se_cmd *cmd, struct se_dif_v1_tuple *sdt,
const void *p, sector_t sector, unsigned int ei_lba)
{
struct se_device *dev = cmd->se_dev;
int block_size = dev->dev_attrib.block_size;
__be16 csum;
if (!(cmd->prot_checks & TARGET_DIF_CHECK_GUARD))
goto check_ref;
csum = cpu_to_be16(crc_t10dif(p, block_size));
if (sdt->guard_tag != csum) {
@ -1200,7 +1243,11 @@ sbc_dif_v1_verify(struct se_device *dev, struct se_dif_v1_tuple *sdt,
return TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED;
}
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT &&
check_ref:
if (!(cmd->prot_checks & TARGET_DIF_CHECK_REFTAG))
return 0;
if (cmd->prot_type == TARGET_DIF_TYPE1_PROT &&
be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
pr_err("DIFv1 Type 1 reference failed on sector: %llu tag: 0x%08x"
" sector MSB: 0x%08x\n", (unsigned long long)sector,
@ -1208,7 +1255,7 @@ sbc_dif_v1_verify(struct se_device *dev, struct se_dif_v1_tuple *sdt,
return TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED;
}
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE2_PROT &&
if (cmd->prot_type == TARGET_DIF_TYPE2_PROT &&
be32_to_cpu(sdt->ref_tag) != ei_lba) {
pr_err("DIFv1 Type 2 reference failed on sector: %llu tag: 0x%08x"
" ei_lba: 0x%08x\n", (unsigned long long)sector,
@ -1229,6 +1276,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) {
@ -1292,7 +1342,7 @@ sbc_dif_verify_write(struct se_cmd *cmd, sector_t start, unsigned int sectors,
(unsigned long long)sector, sdt->guard_tag,
sdt->app_tag, be32_to_cpu(sdt->ref_tag));
rc = sbc_dif_v1_verify(dev, sdt, daddr + j, sector,
rc = sbc_dif_v1_verify(cmd, sdt, daddr + j, sector,
ei_lba);
if (rc) {
kunmap_atomic(paddr);
@ -1309,6 +1359,9 @@ sbc_dif_verify_write(struct se_cmd *cmd, sector_t start, unsigned int sectors,
kunmap_atomic(paddr);
kunmap_atomic(daddr);
}
if (!sg)
return 0;
sbc_dif_copy_prot(cmd, sectors, false, sg, sg_off);
return 0;
@ -1353,7 +1406,7 @@ __sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
continue;
}
rc = sbc_dif_v1_verify(dev, sdt, daddr + j, sector,
rc = sbc_dif_v1_verify(cmd, sdt, daddr + j, sector,
ei_lba);
if (rc) {
kunmap_atomic(paddr);

View file

@ -103,10 +103,12 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
buf[5] |= 0x8;
/*
* Set Protection (PROTECT) bit when DIF has been enabled on the
* device, and the transport supports VERIFY + PASS.
* device, and the fabric supports VERIFY + PASS. Also report
* PROTECT=1 if sess_prot_type has been configured to allow T10-PI
* to unprotected devices.
*/
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
if (dev->dev_attrib.pi_prot_type)
if (dev->dev_attrib.pi_prot_type || cmd->se_sess->sess_prot_type)
buf[5] |= 0x1;
}
@ -467,9 +469,11 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
* only for TYPE3 protection.
*/
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT)
if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT ||
cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE1_PROT)
buf[4] = 0x5;
else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT)
else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT ||
cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE3_PROT)
buf[4] = 0x4;
}
@ -861,7 +865,7 @@ static int spc_modesense_control(struct se_cmd *cmd, u8 pc, u8 *p)
* TAG field.
*/
if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
if (dev->dev_attrib.pi_prot_type)
if (dev->dev_attrib.pi_prot_type || sess->sess_prot_type)
p[5] |= 0x80;
}
@ -1099,7 +1103,7 @@ static sense_reason_t spc_emulate_modeselect(struct se_cmd *cmd)
unsigned char *buf;
unsigned char tbuf[SE_MODE_PAGE_BUF];
int length;
int ret = 0;
sense_reason_t ret = 0;
int i;
if (!cmd->data_length) {

View file

@ -125,8 +125,8 @@ void core_tmr_abort_task(
if (dev != se_cmd->se_dev)
continue;
/* skip se_cmd associated with tmr */
if (tmr->task_cmd == se_cmd)
/* skip task management functions, including tmr->task_cmd */
if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
continue;
ref_tag = se_cmd->se_tfo->get_task_tag(se_cmd);

View file

@ -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,

View file

@ -322,6 +322,7 @@ void __transport_register_session(
struct se_session *se_sess,
void *fabric_sess_ptr)
{
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;
@ -333,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.
@ -404,6 +420,30 @@ void target_put_session(struct se_session *se_sess)
}
EXPORT_SYMBOL(target_put_session);
ssize_t target_show_dynamic_sessions(struct se_portal_group *se_tpg, char *page)
{
struct se_session *se_sess;
ssize_t len = 0;
spin_lock_bh(&se_tpg->session_lock);
list_for_each_entry(se_sess, &se_tpg->tpg_sess_list, sess_list) {
if (!se_sess->se_node_acl)
continue;
if (!se_sess->se_node_acl->dynamic_node_acl)
continue;
if (strlen(se_sess->se_node_acl->initiatorname) + 1 + len > PAGE_SIZE)
break;
len += snprintf(page + len, PAGE_SIZE - len, "%s\n",
se_sess->se_node_acl->initiatorname);
len += 1; /* Include NULL terminator */
}
spin_unlock_bh(&se_tpg->session_lock);
return len;
}
EXPORT_SYMBOL(target_show_dynamic_sessions);
static void target_complete_nacl(struct kref *kref)
{
struct se_node_acl *nacl = container_of(kref,
@ -462,7 +502,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;
@ -1118,7 +1158,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,
@ -1570,6 +1610,8 @@ EXPORT_SYMBOL(target_submit_tmr);
* has completed.
*/
bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags)
__releases(&cmd->t_state_lock)
__acquires(&cmd->t_state_lock)
{
bool was_active = false;
@ -1615,11 +1657,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:
@ -1706,6 +1748,41 @@ void __target_execute_cmd(struct se_cmd *cmd)
}
}
static int target_write_prot_action(struct se_cmd *cmd)
{
u32 sectors;
/*
* Perform WRITE_INSERT of PI using software emulation when backend
* device has PI enabled, if the transport has not already generated
* PI using hardware WRITE_INSERT offload.
*/
switch (cmd->prot_op) {
case TARGET_PROT_DOUT_INSERT:
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DOUT_INSERT))
sbc_dif_generate(cmd);
break;
case TARGET_PROT_DOUT_STRIP:
if (cmd->se_sess->sup_prot_ops & TARGET_PROT_DOUT_STRIP)
break;
sectors = cmd->data_length >> ilog2(cmd->se_dev->dev_attrib.block_size);
cmd->pi_err = sbc_dif_verify_write(cmd, cmd->t_task_lba,
sectors, 0, NULL, 0);
if (unlikely(cmd->pi_err)) {
spin_lock_irq(&cmd->t_state_lock);
cmd->transport_state &= ~CMD_T_BUSY|CMD_T_SENT;
spin_unlock_irq(&cmd->t_state_lock);
transport_generic_request_failure(cmd, cmd->pi_err);
return -1;
}
break;
default:
break;
}
return 0;
}
static bool target_handle_task_attr(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
@ -1785,15 +1862,9 @@ void target_execute_cmd(struct se_cmd *cmd)
cmd->t_state = TRANSPORT_PROCESSING;
cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
spin_unlock_irq(&cmd->t_state_lock);
/*
* Perform WRITE_INSERT of PI using software emulation when backend
* device has PI enabled, if the transport has not already generated
* PI using hardware WRITE_INSERT offload.
*/
if (cmd->prot_op == TARGET_PROT_DOUT_INSERT) {
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DOUT_INSERT))
sbc_dif_generate(cmd);
}
if (target_write_prot_action(cmd))
return;
if (target_handle_task_attr(cmd)) {
spin_lock_irq(&cmd->t_state_lock);
@ -1919,16 +1990,28 @@ static void transport_handle_queue_full(
schedule_work(&cmd->se_dev->qf_work_queue);
}
static bool target_check_read_strip(struct se_cmd *cmd)
static bool target_read_prot_action(struct se_cmd *cmd)
{
sense_reason_t rc;
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DIN_STRIP)) {
rc = sbc_dif_read_strip(cmd);
if (rc) {
cmd->pi_err = rc;
return true;
switch (cmd->prot_op) {
case TARGET_PROT_DIN_STRIP:
if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DIN_STRIP)) {
rc = sbc_dif_read_strip(cmd);
if (rc) {
cmd->pi_err = rc;
return true;
}
}
break;
case TARGET_PROT_DIN_INSERT:
if (cmd->se_sess->sup_prot_ops & TARGET_PROT_DIN_INSERT)
break;
sbc_dif_generate(cmd);
break;
default:
break;
}
return false;
@ -1975,8 +2058,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,
@ -1990,6 +2077,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);
@ -2003,8 +2091,7 @@ static void target_complete_ok_work(struct work_struct *work)
* backend had PI enabled, if the transport will not be
* performing hardware READ_STRIP offload.
*/
if (cmd->prot_op == TARGET_PROT_DIN_STRIP &&
target_check_read_strip(cmd)) {
if (target_read_prot_action(cmd)) {
ret = transport_send_check_condition_and_sense(cmd,
cmd->pi_err, 0);
if (ret == -EAGAIN || ret == -ENOMEM)
@ -2094,6 +2181,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;
}
@ -2246,6 +2343,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
@ -2254,7 +2352,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)) {
@ -2285,6 +2382,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,
@ -2376,10 +2487,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) {
@ -2398,6 +2507,7 @@ out:
EXPORT_SYMBOL(target_get_sess_cmd);
static void target_release_cmd_kref(struct kref *kref)
__releases(&se_cmd->se_sess->sess_cmd_lock)
{
struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
struct se_session *se_sess = se_cmd->se_sess;

View file

@ -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.
@ -376,7 +381,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
/* Even iov_base is relative to mb_addr */
iov->iov_len = copy_bytes;
iov->iov_base = (void *) udev->data_off + udev->data_head;
iov->iov_base = (void __user *) udev->data_off +
udev->data_head;
iov_cnt++;
iov++;
@ -388,7 +394,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
copy_bytes = sg->length - copy_bytes;
iov->iov_len = copy_bytes;
iov->iov_base = (void *) udev->data_off + udev->data_head;
iov->iov_base = (void __user *) udev->data_off +
udev->data_head;
if (se_cmd->data_direction == DMA_TO_DEVICE) {
to = (void *) mb + udev->data_off + udev->data_head;
@ -405,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;
@ -462,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);
@ -540,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);
@ -560,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++;
}
@ -838,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;

View file

@ -34,20 +34,12 @@
#include <target/target_core_fabric.h>
#include <target/target_core_configfs.h>
#include "target_core_internal.h"
#include "target_core_pr.h"
#include "target_core_ua.h"
#include "target_core_xcopy.h"
static struct workqueue_struct *xcopy_wq = NULL;
/*
* From target_core_device.c
*/
extern struct mutex g_device_mutex;
extern struct list_head g_device_list;
/*
* From target_core_configfs.c
*/
extern struct configfs_subsystem *target_core_subsystem[];
static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
{
@ -433,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,
@ -548,33 +540,22 @@ static void target_xcopy_setup_pt_port(
}
}
static int target_xcopy_init_pt_lun(
struct xcopy_pt_cmd *xpt_cmd,
struct xcopy_op *xop,
struct se_device *se_dev,
struct se_cmd *pt_cmd,
bool remote_port)
static void target_xcopy_init_pt_lun(struct se_device *se_dev,
struct se_cmd *pt_cmd, bool remote_port)
{
/*
* Don't allocate + init an pt_cmd->se_lun if honoring local port for
* reservations. The pt_cmd->se_lun pointer will be setup from within
* target_xcopy_setup_pt_port()
*/
if (!remote_port) {
pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH;
return 0;
if (remote_port) {
pr_debug("Setup emulated se_dev: %p from se_dev\n",
pt_cmd->se_dev);
pt_cmd->se_lun = &se_dev->xcopy_lun;
pt_cmd->se_dev = se_dev;
}
pt_cmd->se_lun = &se_dev->xcopy_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;
pr_debug("Setup emulated se_dev: %p to pt_cmd->se_lun->lun_se_dev\n",
pt_cmd->se_lun->lun_se_dev);
return 0;
pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
}
static int target_xcopy_setup_pt_cmd(
@ -592,11 +573,8 @@ static int target_xcopy_setup_pt_cmd(
* Setup LUN+port to honor reservations based upon xop->op_origin for
* X-COPY PUSH or X-COPY PULL based upon where the CDB was received.
*/
rc = target_xcopy_init_pt_lun(xpt_cmd, xop, se_dev, cmd, remote_port);
if (rc < 0) {
ret = rc;
goto out;
}
target_xcopy_init_pt_lun(se_dev, cmd, remote_port);
xpt_cmd->xcopy_op = xop;
target_xcopy_setup_pt_port(xpt_cmd, xop, remote_port);

View file

@ -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;
/*

View file

@ -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,78 +554,35 @@ 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,
.tfc_wwn_attrs = ft_wwn_attrs,
.tfc_tpg_nacl_base_attrs = ft_nacl_base_attrs,
};
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;
}
static struct notifier_block ft_notifier = {
.notifier_call = ft_lport_notify
};
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();
}