diff options
Diffstat (limited to 'drivers/target/iscsi/iscsi_target_tpg.c')
| -rw-r--r-- | drivers/target/iscsi/iscsi_target_tpg.c | 180 |
1 files changed, 152 insertions, 28 deletions
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 879d8d0fa3f..c3cb5c15efd 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -1,9 +1,7 @@ /******************************************************************************* * This file contains iSCSI Target Portal Group related functions. * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. + * (c) Copyright 2007-2013 Datera, Inc. * * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> * @@ -31,6 +29,8 @@ #include "iscsi_target.h" #include "iscsi_target_parameters.h" +#include <target/iscsi/iscsi_transport.h> + struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *tiqn, u16 tpgt) { struct iscsi_portal_group *tpg; @@ -47,7 +47,7 @@ struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *tiqn, u1 INIT_LIST_HEAD(&tpg->tpg_gnp_list); INIT_LIST_HEAD(&tpg->tpg_list); mutex_init(&tpg->tpg_access_lock); - mutex_init(&tpg->np_login_lock); + sema_init(&tpg->np_login_sem, 1); spin_lock_init(&tpg->tpg_state_lock); spin_lock_init(&tpg->tpg_np_lock); @@ -127,7 +127,8 @@ void iscsit_release_discovery_tpg(void) struct iscsi_portal_group *iscsit_get_tpg_from_np( struct iscsi_tiqn *tiqn, - struct iscsi_np *np) + struct iscsi_np *np, + struct iscsi_tpg_np **tpg_np_out) { struct iscsi_portal_group *tpg = NULL; struct iscsi_tpg_np *tpg_np; @@ -136,7 +137,7 @@ struct iscsi_portal_group *iscsit_get_tpg_from_np( list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) { spin_lock(&tpg->tpg_state_lock); - if (tpg->tpg_state == TPG_STATE_FREE) { + if (tpg->tpg_state != TPG_STATE_ACTIVE) { spin_unlock(&tpg->tpg_state_lock); continue; } @@ -145,6 +146,8 @@ struct iscsi_portal_group *iscsit_get_tpg_from_np( spin_lock(&tpg->tpg_np_lock); list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) { if (tpg_np->tpg_np == np) { + *tpg_np_out = tpg_np; + kref_get(&tpg_np->tpg_np_kref); spin_unlock(&tpg->tpg_np_lock); spin_unlock(&tiqn->tiqn_tpg_lock); return tpg; @@ -173,18 +176,22 @@ void iscsit_put_tpg(struct iscsi_portal_group *tpg) static void iscsit_clear_tpg_np_login_thread( struct iscsi_tpg_np *tpg_np, - struct iscsi_portal_group *tpg) + struct iscsi_portal_group *tpg, + bool shutdown) { if (!tpg_np->tpg_np) { pr_err("struct iscsi_tpg_np->tpg_np is NULL!\n"); return; } - iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg); + if (shutdown) + tpg_np->tpg_np->enabled = false; + iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg, shutdown); } -void iscsit_clear_tpg_np_login_threads( - struct iscsi_portal_group *tpg) +static void iscsit_clear_tpg_np_login_threads( + struct iscsi_portal_group *tpg, + bool shutdown) { struct iscsi_tpg_np *tpg_np; @@ -195,7 +202,7 @@ void iscsit_clear_tpg_np_login_threads( continue; } spin_unlock(&tpg->tpg_np_lock); - iscsit_clear_tpg_np_login_thread(tpg_np, tpg); + iscsit_clear_tpg_np_login_thread(tpg_np, tpg, shutdown); spin_lock(&tpg->tpg_np_lock); } spin_unlock(&tpg->tpg_np_lock); @@ -218,6 +225,9 @@ static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *tpg) a->cache_dynamic_acls = TA_CACHE_DYNAMIC_ACLS; a->demo_mode_write_protect = TA_DEMO_MODE_WRITE_PROTECT; a->prod_mode_write_protect = TA_PROD_MODE_WRITE_PROTECT; + a->demo_mode_discovery = TA_DEMO_MODE_DISCOVERY; + a->default_erl = TA_DEFAULT_ERL; + a->t10_pi = TA_DEFAULT_T10_PI; } int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_group *tpg) @@ -232,7 +242,7 @@ int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_gro if (iscsi_create_default_params(&tpg->param_list) < 0) goto err_out; - ISCSI_TPG_ATTRIB(tpg)->tpg = tpg; + tpg->tpg_attrib.tpg = tpg; spin_lock(&tpg->tpg_state_lock); tpg->tpg_state = TPG_STATE_INACTIVE; @@ -303,6 +313,7 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg) { struct iscsi_param *param; struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; + int ret; spin_lock(&tpg->tpg_state_lock); if (tpg->tpg_state == TPG_STATE_ACTIVE) { @@ -319,19 +330,19 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg) param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list); if (!param) { spin_unlock(&tpg->tpg_state_lock); - return -ENOMEM; + return -EINVAL; } - if (ISCSI_TPG_ATTRIB(tpg)->authentication) { - if (!strcmp(param->value, NONE)) - if (iscsi_update_param_value(param, CHAP) < 0) { - spin_unlock(&tpg->tpg_state_lock); - return -ENOMEM; - } - if (iscsit_ta_authentication(tpg, 1) < 0) { - spin_unlock(&tpg->tpg_state_lock); - return -ENOMEM; + if (tpg->tpg_attrib.authentication) { + if (!strcmp(param->value, NONE)) { + ret = iscsi_update_param_value(param, CHAP); + if (ret) + goto err; } + + ret = iscsit_ta_authentication(tpg, 1); + if (ret < 0) + goto err; } tpg->tpg_state = TPG_STATE_ACTIVE; @@ -344,6 +355,10 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg) spin_unlock(&tiqn->tiqn_tpg_lock); return 0; + +err: + spin_unlock(&tpg->tpg_state_lock); + return ret; } int iscsit_tpg_disable_portal_group(struct iscsi_portal_group *tpg, int force) @@ -361,7 +376,7 @@ int iscsit_tpg_disable_portal_group(struct iscsi_portal_group *tpg, int force) tpg->tpg_state = TPG_STATE_INACTIVE; spin_unlock(&tpg->tpg_state_lock); - iscsit_clear_tpg_np_login_threads(tpg); + iscsit_clear_tpg_np_login_threads(tpg, false); if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { spin_lock(&tpg->tpg_state_lock); @@ -417,6 +432,35 @@ struct iscsi_tpg_np *iscsit_tpg_locate_child_np( return NULL; } +static bool iscsit_tpg_check_network_portal( + struct iscsi_tiqn *tiqn, + struct __kernel_sockaddr_storage *sockaddr, + int network_transport) +{ + struct iscsi_portal_group *tpg; + struct iscsi_tpg_np *tpg_np; + struct iscsi_np *np; + bool match = false; + + spin_lock(&tiqn->tiqn_tpg_lock); + list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) { + + spin_lock(&tpg->tpg_np_lock); + list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) { + np = tpg_np->tpg_np; + + match = iscsit_check_np_match(sockaddr, np, + network_transport); + if (match) + break; + } + spin_unlock(&tpg->tpg_np_lock); + } + spin_unlock(&tiqn->tiqn_tpg_lock); + + return match; +} + struct iscsi_tpg_np *iscsit_tpg_add_network_portal( struct iscsi_portal_group *tpg, struct __kernel_sockaddr_storage *sockaddr, @@ -427,6 +471,16 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal( struct iscsi_np *np; struct iscsi_tpg_np *tpg_np; + if (!tpg_np_parent) { + if (iscsit_tpg_check_network_portal(tpg->tpg_tiqn, sockaddr, + network_transport)) { + pr_err("Network Portal: %s already exists on a" + " different TPG on %s\n", ip_str, + tpg->tpg_tiqn->tiqn); + return ERR_PTR(-EEXIST); + } + } + tpg_np = kzalloc(sizeof(struct iscsi_tpg_np), GFP_KERNEL); if (!tpg_np) { pr_err("Unable to allocate memory for" @@ -444,7 +498,10 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal( INIT_LIST_HEAD(&tpg_np->tpg_np_child_list); INIT_LIST_HEAD(&tpg_np->tpg_np_parent_list); spin_lock_init(&tpg_np->tpg_np_parent_lock); + init_completion(&tpg_np->tpg_np_comp); + kref_init(&tpg_np->tpg_np_kref); tpg_np->tpg_np = np; + np->tpg_np = tpg_np; tpg_np->tpg = tpg; spin_lock(&tpg->tpg_np_lock); @@ -464,7 +521,7 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal( pr_debug("CORE[%s] - Added Network Portal: %s:%hu,%hu on %s\n", tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, - (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP"); + np->np_transport->name); return tpg_np; } @@ -474,11 +531,11 @@ static int iscsit_tpg_release_np( struct iscsi_portal_group *tpg, struct iscsi_np *np) { - iscsit_clear_tpg_np_login_thread(tpg_np, tpg); + iscsit_clear_tpg_np_login_thread(tpg_np, tpg, true); pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n", tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, - (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP"); + np->np_transport->name); tpg_np->tpg_np = NULL; tpg_np->tpg = NULL; @@ -558,7 +615,7 @@ int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication) if ((authentication != 1) && (authentication != 0)) { pr_err("Illegal value for authentication parameter:" " %u, ignoring request.\n", authentication); - return -1; + return -EINVAL; } memset(buf1, 0, sizeof(buf1)); @@ -593,7 +650,7 @@ int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication) } else { snprintf(buf1, sizeof(buf1), "%s", param->value); none = strstr(buf1, NONE); - if ((none)) + if (none) goto out; strncat(buf1, ",", strlen(",")); strncat(buf1, NONE, strlen(NONE)); @@ -672,6 +729,12 @@ int iscsit_ta_generate_node_acls( pr_debug("iSCSI_TPG[%hu] - Generate Initiator Portal Group ACLs: %s\n", tpg->tpgt, (a->generate_node_acls) ? "Enabled" : "Disabled"); + if (flag == 1 && a->cache_dynamic_acls == 0) { + pr_debug("Explicitly setting cache_dynamic_acls=1 when " + "generate_node_acls=1\n"); + a->cache_dynamic_acls = 1; + } + return 0; } @@ -711,6 +774,12 @@ int iscsit_ta_cache_dynamic_acls( return -EINVAL; } + if (a->generate_node_acls == 1 && flag == 0) { + pr_debug("Skipping cache_dynamic_acls=0 when" + " generate_node_acls=1\n"); + return 0; + } + a->cache_dynamic_acls = flag; pr_debug("iSCSI_TPG[%hu] - Cache Dynamic Initiator Portal Group" " ACLs %s\n", tpg->tpgt, (a->cache_dynamic_acls) ? @@ -755,3 +824,58 @@ int iscsit_ta_prod_mode_write_protect( return 0; } + +int iscsit_ta_demo_mode_discovery( + struct iscsi_portal_group *tpg, + u32 flag) +{ + struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; + + if ((flag != 0) && (flag != 1)) { + pr_err("Illegal value %d\n", flag); + return -EINVAL; + } + + a->demo_mode_discovery = flag; + pr_debug("iSCSI_TPG[%hu] - Demo Mode Discovery bit:" + " %s\n", tpg->tpgt, (a->demo_mode_discovery) ? + "ON" : "OFF"); + + return 0; +} + +int iscsit_ta_default_erl( + struct iscsi_portal_group *tpg, + u32 default_erl) +{ + struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; + + if ((default_erl != 0) && (default_erl != 1) && (default_erl != 2)) { + pr_err("Illegal value for default_erl: %u\n", default_erl); + return -EINVAL; + } + + a->default_erl = default_erl; + pr_debug("iSCSI_TPG[%hu] - DefaultERL: %u\n", tpg->tpgt, a->default_erl); + + return 0; +} + +int iscsit_ta_t10_pi( + struct iscsi_portal_group *tpg, + u32 flag) +{ + struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; + + if ((flag != 0) && (flag != 1)) { + pr_err("Illegal value %d\n", flag); + return -EINVAL; + } + + a->t10_pi = flag; + pr_debug("iSCSI_TPG[%hu] - T10 Protection information bit:" + " %s\n", tpg->tpgt, (a->t10_pi) ? + "ON" : "OFF"); + + return 0; +} |
