13699d92aSKiran Patil /******************************************************************************* 23699d92aSKiran Patil * Filename: tcm_fc.c 33699d92aSKiran Patil * 43699d92aSKiran Patil * This file contains the configfs implementation for TCM_fc fabric node. 53699d92aSKiran Patil * Based on tcm_loop_configfs.c 63699d92aSKiran Patil * 73699d92aSKiran Patil * Copyright (c) 2010 Cisco Systems, Inc. 83699d92aSKiran Patil * Copyright (c) 2009,2010 Rising Tide, Inc. 93699d92aSKiran Patil * Copyright (c) 2009,2010 Linux-iSCSI.org 103699d92aSKiran Patil * 113699d92aSKiran Patil * Copyright (c) 2009,2010 Nicholas A. Bellinger <nab@linux-iscsi.org> 123699d92aSKiran Patil * 133699d92aSKiran Patil * This program is free software; you can redistribute it and/or modify 143699d92aSKiran Patil * it under the terms of the GNU General Public License as published by 153699d92aSKiran Patil * the Free Software Foundation; either version 2 of the License, or 163699d92aSKiran Patil * (at your option) any later version. 173699d92aSKiran Patil * 183699d92aSKiran Patil * This program is distributed in the hope that it will be useful, 193699d92aSKiran Patil * but WITHOUT ANY WARRANTY; without even the implied warranty of 203699d92aSKiran Patil * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 213699d92aSKiran Patil * GNU General Public License for more details. 223699d92aSKiran Patil ****************************************************************************/ 233699d92aSKiran Patil 243699d92aSKiran Patil #include <linux/module.h> 253699d92aSKiran Patil #include <linux/moduleparam.h> 263699d92aSKiran Patil #include <linux/version.h> 273699d92aSKiran Patil #include <generated/utsrelease.h> 283699d92aSKiran Patil #include <linux/utsname.h> 293699d92aSKiran Patil #include <linux/init.h> 303699d92aSKiran Patil #include <linux/slab.h> 313699d92aSKiran Patil #include <linux/kthread.h> 323699d92aSKiran Patil #include <linux/types.h> 333699d92aSKiran Patil #include <linux/string.h> 343699d92aSKiran Patil #include <linux/configfs.h> 353699d92aSKiran Patil #include <linux/ctype.h> 363699d92aSKiran Patil #include <asm/unaligned.h> 373699d92aSKiran Patil #include <scsi/scsi.h> 383699d92aSKiran Patil #include <scsi/scsi_host.h> 393699d92aSKiran Patil #include <scsi/scsi_device.h> 403699d92aSKiran Patil #include <scsi/scsi_cmnd.h> 413699d92aSKiran Patil #include <scsi/libfc.h> 423699d92aSKiran Patil 433699d92aSKiran Patil #include <target/target_core_base.h> 443699d92aSKiran Patil #include <target/target_core_transport.h> 453699d92aSKiran Patil #include <target/target_core_fabric_ops.h> 463699d92aSKiran Patil #include <target/target_core_fabric_configfs.h> 473699d92aSKiran Patil #include <target/target_core_fabric_lib.h> 483699d92aSKiran Patil #include <target/target_core_device.h> 493699d92aSKiran Patil #include <target/target_core_tpg.h> 503699d92aSKiran Patil #include <target/target_core_configfs.h> 513699d92aSKiran Patil #include <target/target_core_base.h> 523699d92aSKiran Patil #include <target/configfs_macros.h> 533699d92aSKiran Patil 543699d92aSKiran Patil #include "tcm_fc.h" 553699d92aSKiran Patil 563699d92aSKiran Patil struct target_fabric_configfs *ft_configfs; 573699d92aSKiran Patil 583699d92aSKiran Patil LIST_HEAD(ft_lport_list); 593699d92aSKiran Patil DEFINE_MUTEX(ft_lport_lock); 603699d92aSKiran Patil 613699d92aSKiran Patil unsigned int ft_debug_logging; 623699d92aSKiran Patil module_param_named(debug_logging, ft_debug_logging, int, S_IRUGO|S_IWUSR); 633699d92aSKiran Patil MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); 643699d92aSKiran Patil 653699d92aSKiran Patil /* 663699d92aSKiran Patil * Parse WWN. 673699d92aSKiran Patil * If strict, we require lower-case hex and colon separators to be sure 683699d92aSKiran Patil * the name is the same as what would be generated by ft_format_wwn() 693699d92aSKiran Patil * so the name and wwn are mapped one-to-one. 703699d92aSKiran Patil */ 713699d92aSKiran Patil static ssize_t ft_parse_wwn(const char *name, u64 *wwn, int strict) 723699d92aSKiran Patil { 733699d92aSKiran Patil const char *cp; 743699d92aSKiran Patil char c; 753699d92aSKiran Patil u32 nibble; 763699d92aSKiran Patil u32 byte = 0; 773699d92aSKiran Patil u32 pos = 0; 783699d92aSKiran Patil u32 err; 793699d92aSKiran Patil 803699d92aSKiran Patil *wwn = 0; 813699d92aSKiran Patil for (cp = name; cp < &name[FT_NAMELEN - 1]; cp++) { 823699d92aSKiran Patil c = *cp; 833699d92aSKiran Patil if (c == '\n' && cp[1] == '\0') 843699d92aSKiran Patil continue; 853699d92aSKiran Patil if (strict && pos++ == 2 && byte++ < 7) { 863699d92aSKiran Patil pos = 0; 873699d92aSKiran Patil if (c == ':') 883699d92aSKiran Patil continue; 893699d92aSKiran Patil err = 1; 903699d92aSKiran Patil goto fail; 913699d92aSKiran Patil } 923699d92aSKiran Patil if (c == '\0') { 933699d92aSKiran Patil err = 2; 943699d92aSKiran Patil if (strict && byte != 8) 953699d92aSKiran Patil goto fail; 963699d92aSKiran Patil return cp - name; 973699d92aSKiran Patil } 983699d92aSKiran Patil err = 3; 993699d92aSKiran Patil if (isdigit(c)) 1003699d92aSKiran Patil nibble = c - '0'; 1013699d92aSKiran Patil else if (isxdigit(c) && (islower(c) || !strict)) 1023699d92aSKiran Patil nibble = tolower(c) - 'a' + 10; 1033699d92aSKiran Patil else 1043699d92aSKiran Patil goto fail; 1053699d92aSKiran Patil *wwn = (*wwn << 4) | nibble; 1063699d92aSKiran Patil } 1073699d92aSKiran Patil err = 4; 1083699d92aSKiran Patil fail: 1093699d92aSKiran Patil FT_CONF_DBG("err %u len %zu pos %u byte %u\n", 1103699d92aSKiran Patil err, cp - name, pos, byte); 1113699d92aSKiran Patil return -1; 1123699d92aSKiran Patil } 1133699d92aSKiran Patil 1143699d92aSKiran Patil ssize_t ft_format_wwn(char *buf, size_t len, u64 wwn) 1153699d92aSKiran Patil { 1163699d92aSKiran Patil u8 b[8]; 1173699d92aSKiran Patil 1183699d92aSKiran Patil put_unaligned_be64(wwn, b); 1193699d92aSKiran Patil return snprintf(buf, len, 1203699d92aSKiran Patil "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", 1213699d92aSKiran Patil b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); 1223699d92aSKiran Patil } 1233699d92aSKiran Patil 1243699d92aSKiran Patil static ssize_t ft_wwn_show(void *arg, char *buf) 1253699d92aSKiran Patil { 1263699d92aSKiran Patil u64 *wwn = arg; 1273699d92aSKiran Patil ssize_t len; 1283699d92aSKiran Patil 1293699d92aSKiran Patil len = ft_format_wwn(buf, PAGE_SIZE - 2, *wwn); 1303699d92aSKiran Patil buf[len++] = '\n'; 1313699d92aSKiran Patil return len; 1323699d92aSKiran Patil } 1333699d92aSKiran Patil 1343699d92aSKiran Patil static ssize_t ft_wwn_store(void *arg, const char *buf, size_t len) 1353699d92aSKiran Patil { 1363699d92aSKiran Patil ssize_t ret; 1373699d92aSKiran Patil u64 wwn; 1383699d92aSKiran Patil 1393699d92aSKiran Patil ret = ft_parse_wwn(buf, &wwn, 0); 1403699d92aSKiran Patil if (ret > 0) 1413699d92aSKiran Patil *(u64 *)arg = wwn; 1423699d92aSKiran Patil return ret; 1433699d92aSKiran Patil } 1443699d92aSKiran Patil 1453699d92aSKiran Patil /* 1463699d92aSKiran Patil * ACL auth ops. 1473699d92aSKiran Patil */ 1483699d92aSKiran Patil 1493699d92aSKiran Patil static ssize_t ft_nacl_show_port_name( 1503699d92aSKiran Patil struct se_node_acl *se_nacl, 1513699d92aSKiran Patil char *page) 1523699d92aSKiran Patil { 1533699d92aSKiran Patil struct ft_node_acl *acl = container_of(se_nacl, 1543699d92aSKiran Patil struct ft_node_acl, se_node_acl); 1553699d92aSKiran Patil 1563699d92aSKiran Patil return ft_wwn_show(&acl->node_auth.port_name, page); 1573699d92aSKiran Patil } 1583699d92aSKiran Patil 1593699d92aSKiran Patil static ssize_t ft_nacl_store_port_name( 1603699d92aSKiran Patil struct se_node_acl *se_nacl, 1613699d92aSKiran Patil const char *page, 1623699d92aSKiran Patil size_t count) 1633699d92aSKiran Patil { 1643699d92aSKiran Patil struct ft_node_acl *acl = container_of(se_nacl, 1653699d92aSKiran Patil struct ft_node_acl, se_node_acl); 1663699d92aSKiran Patil 1673699d92aSKiran Patil return ft_wwn_store(&acl->node_auth.port_name, page, count); 1683699d92aSKiran Patil } 1693699d92aSKiran Patil 1703699d92aSKiran Patil TF_NACL_BASE_ATTR(ft, port_name, S_IRUGO | S_IWUSR); 1713699d92aSKiran Patil 1723699d92aSKiran Patil static ssize_t ft_nacl_show_node_name( 1733699d92aSKiran Patil struct se_node_acl *se_nacl, 1743699d92aSKiran Patil char *page) 1753699d92aSKiran Patil { 1763699d92aSKiran Patil struct ft_node_acl *acl = container_of(se_nacl, 1773699d92aSKiran Patil struct ft_node_acl, se_node_acl); 1783699d92aSKiran Patil 1793699d92aSKiran Patil return ft_wwn_show(&acl->node_auth.node_name, page); 1803699d92aSKiran Patil } 1813699d92aSKiran Patil 1823699d92aSKiran Patil static ssize_t ft_nacl_store_node_name( 1833699d92aSKiran Patil struct se_node_acl *se_nacl, 1843699d92aSKiran Patil const char *page, 1853699d92aSKiran Patil size_t count) 1863699d92aSKiran Patil { 1873699d92aSKiran Patil struct ft_node_acl *acl = container_of(se_nacl, 1883699d92aSKiran Patil struct ft_node_acl, se_node_acl); 1893699d92aSKiran Patil 1903699d92aSKiran Patil return ft_wwn_store(&acl->node_auth.node_name, page, count); 1913699d92aSKiran Patil } 1923699d92aSKiran Patil 1933699d92aSKiran Patil TF_NACL_BASE_ATTR(ft, node_name, S_IRUGO | S_IWUSR); 1943699d92aSKiran Patil 1953699d92aSKiran Patil static struct configfs_attribute *ft_nacl_base_attrs[] = { 1963699d92aSKiran Patil &ft_nacl_port_name.attr, 1973699d92aSKiran Patil &ft_nacl_node_name.attr, 1983699d92aSKiran Patil NULL, 1993699d92aSKiran Patil }; 2003699d92aSKiran Patil 2013699d92aSKiran Patil /* 2023699d92aSKiran Patil * ACL ops. 2033699d92aSKiran Patil */ 2043699d92aSKiran Patil 2053699d92aSKiran Patil /* 2063699d92aSKiran Patil * Add ACL for an initiator. The ACL is named arbitrarily. 2073699d92aSKiran Patil * The port_name and/or node_name are attributes. 2083699d92aSKiran Patil */ 2093699d92aSKiran Patil static struct se_node_acl *ft_add_acl( 2103699d92aSKiran Patil struct se_portal_group *se_tpg, 2113699d92aSKiran Patil struct config_group *group, 2123699d92aSKiran Patil const char *name) 2133699d92aSKiran Patil { 2143699d92aSKiran Patil struct ft_node_acl *acl; 2153699d92aSKiran Patil struct ft_tpg *tpg; 2163699d92aSKiran Patil u64 wwpn; 2173699d92aSKiran Patil u32 q_depth; 2183699d92aSKiran Patil 2193699d92aSKiran Patil FT_CONF_DBG("add acl %s\n", name); 2203699d92aSKiran Patil tpg = container_of(se_tpg, struct ft_tpg, se_tpg); 2213699d92aSKiran Patil 2223699d92aSKiran Patil if (ft_parse_wwn(name, &wwpn, 1) < 0) 2233699d92aSKiran Patil return ERR_PTR(-EINVAL); 2243699d92aSKiran Patil 2253699d92aSKiran Patil acl = kzalloc(sizeof(struct ft_node_acl), GFP_KERNEL); 2263699d92aSKiran Patil if (!(acl)) 2273699d92aSKiran Patil return ERR_PTR(-ENOMEM); 2283699d92aSKiran Patil acl->node_auth.port_name = wwpn; 2293699d92aSKiran Patil 2303699d92aSKiran Patil q_depth = 32; /* XXX bogus default - get from tpg? */ 2313699d92aSKiran Patil return core_tpg_add_initiator_node_acl(&tpg->se_tpg, 2323699d92aSKiran Patil &acl->se_node_acl, name, q_depth); 2333699d92aSKiran Patil } 2343699d92aSKiran Patil 2353699d92aSKiran Patil static void ft_del_acl(struct se_node_acl *se_acl) 2363699d92aSKiran Patil { 2373699d92aSKiran Patil struct se_portal_group *se_tpg = se_acl->se_tpg; 2383699d92aSKiran Patil struct ft_tpg *tpg; 2393699d92aSKiran Patil struct ft_node_acl *acl = container_of(se_acl, 2403699d92aSKiran Patil struct ft_node_acl, se_node_acl); 2413699d92aSKiran Patil 2423699d92aSKiran Patil FT_CONF_DBG("del acl %s\n", 2433699d92aSKiran Patil config_item_name(&se_acl->acl_group.cg_item)); 2443699d92aSKiran Patil 2453699d92aSKiran Patil tpg = container_of(se_tpg, struct ft_tpg, se_tpg); 2463699d92aSKiran Patil FT_CONF_DBG("del acl %p se_acl %p tpg %p se_tpg %p\n", 2473699d92aSKiran Patil acl, se_acl, tpg, &tpg->se_tpg); 2483699d92aSKiran Patil 2493699d92aSKiran Patil core_tpg_del_initiator_node_acl(&tpg->se_tpg, se_acl, 1); 2503699d92aSKiran Patil kfree(acl); 2513699d92aSKiran Patil } 2523699d92aSKiran Patil 2533699d92aSKiran Patil struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata) 2543699d92aSKiran Patil { 2553699d92aSKiran Patil struct ft_node_acl *found = NULL; 2563699d92aSKiran Patil struct ft_node_acl *acl; 2573699d92aSKiran Patil struct se_portal_group *se_tpg = &tpg->se_tpg; 2583699d92aSKiran Patil struct se_node_acl *se_acl; 2593699d92aSKiran Patil 2603699d92aSKiran Patil spin_lock_bh(&se_tpg->acl_node_lock); 2613699d92aSKiran Patil list_for_each_entry(se_acl, &se_tpg->acl_node_list, acl_list) { 2623699d92aSKiran Patil acl = container_of(se_acl, struct ft_node_acl, se_node_acl); 2633699d92aSKiran Patil FT_CONF_DBG("acl %p port_name %llx\n", 2643699d92aSKiran Patil acl, (unsigned long long)acl->node_auth.port_name); 2653699d92aSKiran Patil if (acl->node_auth.port_name == rdata->ids.port_name || 2663699d92aSKiran Patil acl->node_auth.node_name == rdata->ids.node_name) { 2673699d92aSKiran Patil FT_CONF_DBG("acl %p port_name %llx matched\n", acl, 2683699d92aSKiran Patil (unsigned long long)rdata->ids.port_name); 2693699d92aSKiran Patil found = acl; 2703699d92aSKiran Patil /* XXX need to hold onto ACL */ 2713699d92aSKiran Patil break; 2723699d92aSKiran Patil } 2733699d92aSKiran Patil } 2743699d92aSKiran Patil spin_unlock_bh(&se_tpg->acl_node_lock); 2753699d92aSKiran Patil return found; 2763699d92aSKiran Patil } 2773699d92aSKiran Patil 2783699d92aSKiran Patil struct se_node_acl *ft_tpg_alloc_fabric_acl(struct se_portal_group *se_tpg) 2793699d92aSKiran Patil { 2803699d92aSKiran Patil struct ft_node_acl *acl; 2813699d92aSKiran Patil 2823699d92aSKiran Patil acl = kzalloc(sizeof(*acl), GFP_KERNEL); 2833699d92aSKiran Patil if (!(acl)) { 2843699d92aSKiran Patil printk(KERN_ERR "Unable to allocate struct ft_node_acl\n"); 2853699d92aSKiran Patil return NULL; 2863699d92aSKiran Patil } 2873699d92aSKiran Patil FT_CONF_DBG("acl %p\n", acl); 2883699d92aSKiran Patil return &acl->se_node_acl; 2893699d92aSKiran Patil } 2903699d92aSKiran Patil 2913699d92aSKiran Patil static void ft_tpg_release_fabric_acl(struct se_portal_group *se_tpg, 2923699d92aSKiran Patil struct se_node_acl *se_acl) 2933699d92aSKiran Patil { 2943699d92aSKiran Patil struct ft_node_acl *acl = container_of(se_acl, 2953699d92aSKiran Patil struct ft_node_acl, se_node_acl); 2963699d92aSKiran Patil 2973699d92aSKiran Patil FT_CONF_DBG(KERN_INFO "acl %p\n", acl); 2983699d92aSKiran Patil kfree(acl); 2993699d92aSKiran Patil } 3003699d92aSKiran Patil 3013699d92aSKiran Patil /* 3023699d92aSKiran Patil * local_port port_group (tpg) ops. 3033699d92aSKiran Patil */ 3043699d92aSKiran Patil static struct se_portal_group *ft_add_tpg( 3053699d92aSKiran Patil struct se_wwn *wwn, 3063699d92aSKiran Patil struct config_group *group, 3073699d92aSKiran Patil const char *name) 3083699d92aSKiran Patil { 3093699d92aSKiran Patil struct ft_lport_acl *lacl; 3103699d92aSKiran Patil struct ft_tpg *tpg; 3113699d92aSKiran Patil unsigned long index; 3123699d92aSKiran Patil int ret; 3133699d92aSKiran Patil 3143699d92aSKiran Patil FT_CONF_DBG("tcm_fc: add tpg %s\n", name); 3153699d92aSKiran Patil 3163699d92aSKiran Patil /* 3173699d92aSKiran Patil * Name must be "tpgt_" followed by the index. 3183699d92aSKiran Patil */ 3193699d92aSKiran Patil if (strstr(name, "tpgt_") != name) 3203699d92aSKiran Patil return NULL; 3213699d92aSKiran Patil if (strict_strtoul(name + 5, 10, &index) || index > UINT_MAX) 3223699d92aSKiran Patil return NULL; 3233699d92aSKiran Patil 3243699d92aSKiran Patil lacl = container_of(wwn, struct ft_lport_acl, fc_lport_wwn); 3253699d92aSKiran Patil tpg = kzalloc(sizeof(*tpg), GFP_KERNEL); 3263699d92aSKiran Patil if (!tpg) 3273699d92aSKiran Patil return NULL; 3283699d92aSKiran Patil tpg->index = index; 3293699d92aSKiran Patil tpg->lport_acl = lacl; 3303699d92aSKiran Patil INIT_LIST_HEAD(&tpg->lun_list); 3313699d92aSKiran Patil transport_init_queue_obj(&tpg->qobj); 3323699d92aSKiran Patil 3333699d92aSKiran Patil ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg, 3345951146dSAndy Grover tpg, TRANSPORT_TPG_TYPE_NORMAL); 3353699d92aSKiran Patil if (ret < 0) { 3363699d92aSKiran Patil kfree(tpg); 3373699d92aSKiran Patil return NULL; 3383699d92aSKiran Patil } 3393699d92aSKiran Patil 3403699d92aSKiran Patil tpg->thread = kthread_run(ft_thread, tpg, "ft_tpg%lu", index); 3413699d92aSKiran Patil if (IS_ERR(tpg->thread)) { 3423699d92aSKiran Patil kfree(tpg); 3433699d92aSKiran Patil return NULL; 3443699d92aSKiran Patil } 3453699d92aSKiran Patil 3463699d92aSKiran Patil mutex_lock(&ft_lport_lock); 3473699d92aSKiran Patil list_add_tail(&tpg->list, &lacl->tpg_list); 3483699d92aSKiran Patil mutex_unlock(&ft_lport_lock); 3493699d92aSKiran Patil 3503699d92aSKiran Patil return &tpg->se_tpg; 3513699d92aSKiran Patil } 3523699d92aSKiran Patil 3533699d92aSKiran Patil static void ft_del_tpg(struct se_portal_group *se_tpg) 3543699d92aSKiran Patil { 3553699d92aSKiran Patil struct ft_tpg *tpg = container_of(se_tpg, struct ft_tpg, se_tpg); 3563699d92aSKiran Patil 3573699d92aSKiran Patil FT_CONF_DBG("del tpg %s\n", 3583699d92aSKiran Patil config_item_name(&tpg->se_tpg.tpg_group.cg_item)); 3593699d92aSKiran Patil 3603699d92aSKiran Patil kthread_stop(tpg->thread); 3613699d92aSKiran Patil 3623699d92aSKiran Patil /* Wait for sessions to be freed thru RCU, for BUG_ON below */ 3633699d92aSKiran Patil synchronize_rcu(); 3643699d92aSKiran Patil 3653699d92aSKiran Patil mutex_lock(&ft_lport_lock); 3663699d92aSKiran Patil list_del(&tpg->list); 3673699d92aSKiran Patil if (tpg->tport) { 3683699d92aSKiran Patil tpg->tport->tpg = NULL; 3693699d92aSKiran Patil tpg->tport = NULL; 3703699d92aSKiran Patil } 3713699d92aSKiran Patil mutex_unlock(&ft_lport_lock); 3723699d92aSKiran Patil 3733699d92aSKiran Patil core_tpg_deregister(se_tpg); 3743699d92aSKiran Patil kfree(tpg); 3753699d92aSKiran Patil } 3763699d92aSKiran Patil 3773699d92aSKiran Patil /* 3783699d92aSKiran Patil * Verify that an lport is configured to use the tcm_fc module, and return 3793699d92aSKiran Patil * the target port group that should be used. 3803699d92aSKiran Patil * 3813699d92aSKiran Patil * The caller holds ft_lport_lock. 3823699d92aSKiran Patil */ 3833699d92aSKiran Patil struct ft_tpg *ft_lport_find_tpg(struct fc_lport *lport) 3843699d92aSKiran Patil { 3853699d92aSKiran Patil struct ft_lport_acl *lacl; 3863699d92aSKiran Patil struct ft_tpg *tpg; 3873699d92aSKiran Patil 3883699d92aSKiran Patil list_for_each_entry(lacl, &ft_lport_list, list) { 3893699d92aSKiran Patil if (lacl->wwpn == lport->wwpn) { 3903699d92aSKiran Patil list_for_each_entry(tpg, &lacl->tpg_list, list) 3913699d92aSKiran Patil return tpg; /* XXX for now return first entry */ 3923699d92aSKiran Patil return NULL; 3933699d92aSKiran Patil } 3943699d92aSKiran Patil } 3953699d92aSKiran Patil return NULL; 3963699d92aSKiran Patil } 3973699d92aSKiran Patil 3983699d92aSKiran Patil /* 3993699d92aSKiran Patil * target config instance ops. 4003699d92aSKiran Patil */ 4013699d92aSKiran Patil 4023699d92aSKiran Patil /* 4033699d92aSKiran Patil * Add lport to allowed config. 4043699d92aSKiran Patil * The name is the WWPN in lower-case ASCII, colon-separated bytes. 4053699d92aSKiran Patil */ 4063699d92aSKiran Patil static struct se_wwn *ft_add_lport( 4073699d92aSKiran Patil struct target_fabric_configfs *tf, 4083699d92aSKiran Patil struct config_group *group, 4093699d92aSKiran Patil const char *name) 4103699d92aSKiran Patil { 4113699d92aSKiran Patil struct ft_lport_acl *lacl; 4123699d92aSKiran Patil struct ft_lport_acl *old_lacl; 4133699d92aSKiran Patil u64 wwpn; 4143699d92aSKiran Patil 4153699d92aSKiran Patil FT_CONF_DBG("add lport %s\n", name); 4163699d92aSKiran Patil if (ft_parse_wwn(name, &wwpn, 1) < 0) 4173699d92aSKiran Patil return NULL; 4183699d92aSKiran Patil lacl = kzalloc(sizeof(*lacl), GFP_KERNEL); 4193699d92aSKiran Patil if (!lacl) 4203699d92aSKiran Patil return NULL; 4213699d92aSKiran Patil lacl->wwpn = wwpn; 4223699d92aSKiran Patil INIT_LIST_HEAD(&lacl->tpg_list); 4233699d92aSKiran Patil 4243699d92aSKiran Patil mutex_lock(&ft_lport_lock); 4253699d92aSKiran Patil list_for_each_entry(old_lacl, &ft_lport_list, list) { 4263699d92aSKiran Patil if (old_lacl->wwpn == wwpn) { 4273699d92aSKiran Patil mutex_unlock(&ft_lport_lock); 4283699d92aSKiran Patil kfree(lacl); 4293699d92aSKiran Patil return NULL; 4303699d92aSKiran Patil } 4313699d92aSKiran Patil } 4323699d92aSKiran Patil list_add_tail(&lacl->list, &ft_lport_list); 4333699d92aSKiran Patil ft_format_wwn(lacl->name, sizeof(lacl->name), wwpn); 4343699d92aSKiran Patil mutex_unlock(&ft_lport_lock); 4353699d92aSKiran Patil 4363699d92aSKiran Patil return &lacl->fc_lport_wwn; 4373699d92aSKiran Patil } 4383699d92aSKiran Patil 4393699d92aSKiran Patil static void ft_del_lport(struct se_wwn *wwn) 4403699d92aSKiran Patil { 4413699d92aSKiran Patil struct ft_lport_acl *lacl = container_of(wwn, 4423699d92aSKiran Patil struct ft_lport_acl, fc_lport_wwn); 4433699d92aSKiran Patil 4443699d92aSKiran Patil FT_CONF_DBG("del lport %s\n", 4453699d92aSKiran Patil config_item_name(&wwn->wwn_group.cg_item)); 4463699d92aSKiran Patil mutex_lock(&ft_lport_lock); 4473699d92aSKiran Patil list_del(&lacl->list); 4483699d92aSKiran Patil mutex_unlock(&ft_lport_lock); 4493699d92aSKiran Patil 4503699d92aSKiran Patil kfree(lacl); 4513699d92aSKiran Patil } 4523699d92aSKiran Patil 4533699d92aSKiran Patil static ssize_t ft_wwn_show_attr_version( 4543699d92aSKiran Patil struct target_fabric_configfs *tf, 4553699d92aSKiran Patil char *page) 4563699d92aSKiran Patil { 4573699d92aSKiran Patil return sprintf(page, "TCM FC " FT_VERSION " on %s/%s on " 4583699d92aSKiran Patil ""UTS_RELEASE"\n", utsname()->sysname, utsname()->machine); 4593699d92aSKiran Patil } 4603699d92aSKiran Patil 4613699d92aSKiran Patil TF_WWN_ATTR_RO(ft, version); 4623699d92aSKiran Patil 4633699d92aSKiran Patil static struct configfs_attribute *ft_wwn_attrs[] = { 4643699d92aSKiran Patil &ft_wwn_version.attr, 4653699d92aSKiran Patil NULL, 4663699d92aSKiran Patil }; 4673699d92aSKiran Patil 4683699d92aSKiran Patil static char *ft_get_fabric_name(void) 4693699d92aSKiran Patil { 4703699d92aSKiran Patil return "fc"; 4713699d92aSKiran Patil } 4723699d92aSKiran Patil 4733699d92aSKiran Patil static char *ft_get_fabric_wwn(struct se_portal_group *se_tpg) 4743699d92aSKiran Patil { 4753699d92aSKiran Patil struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr; 4763699d92aSKiran Patil 4773699d92aSKiran Patil return tpg->lport_acl->name; 4783699d92aSKiran Patil } 4793699d92aSKiran Patil 4803699d92aSKiran Patil static u16 ft_get_tag(struct se_portal_group *se_tpg) 4813699d92aSKiran Patil { 4823699d92aSKiran Patil struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr; 4833699d92aSKiran Patil 4843699d92aSKiran Patil /* 4853699d92aSKiran Patil * This tag is used when forming SCSI Name identifier in EVPD=1 0x83 4863699d92aSKiran Patil * to represent the SCSI Target Port. 4873699d92aSKiran Patil */ 4883699d92aSKiran Patil return tpg->index; 4893699d92aSKiran Patil } 4903699d92aSKiran Patil 4913699d92aSKiran Patil static u32 ft_get_default_depth(struct se_portal_group *se_tpg) 4923699d92aSKiran Patil { 4933699d92aSKiran Patil return 1; 4943699d92aSKiran Patil } 4953699d92aSKiran Patil 4963699d92aSKiran Patil static int ft_check_false(struct se_portal_group *se_tpg) 4973699d92aSKiran Patil { 4983699d92aSKiran Patil return 0; 4993699d92aSKiran Patil } 5003699d92aSKiran Patil 5013699d92aSKiran Patil static void ft_set_default_node_attr(struct se_node_acl *se_nacl) 5023699d92aSKiran Patil { 5033699d92aSKiran Patil } 5043699d92aSKiran Patil 5053699d92aSKiran Patil static u16 ft_get_fabric_sense_len(void) 5063699d92aSKiran Patil { 5073699d92aSKiran Patil return 0; 5083699d92aSKiran Patil } 5093699d92aSKiran Patil 5103699d92aSKiran Patil static u16 ft_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_len) 5113699d92aSKiran Patil { 5123699d92aSKiran Patil return 0; 5133699d92aSKiran Patil } 5143699d92aSKiran Patil 5153699d92aSKiran Patil static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg) 5163699d92aSKiran Patil { 5173699d92aSKiran Patil struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr; 5183699d92aSKiran Patil 5193699d92aSKiran Patil return tpg->index; 5203699d92aSKiran Patil } 5213699d92aSKiran Patil 5223699d92aSKiran Patil static struct target_core_fabric_ops ft_fabric_ops = { 5233699d92aSKiran Patil .get_fabric_name = ft_get_fabric_name, 5243699d92aSKiran Patil .get_fabric_proto_ident = fc_get_fabric_proto_ident, 5253699d92aSKiran Patil .tpg_get_wwn = ft_get_fabric_wwn, 5263699d92aSKiran Patil .tpg_get_tag = ft_get_tag, 5273699d92aSKiran Patil .tpg_get_default_depth = ft_get_default_depth, 5283699d92aSKiran Patil .tpg_get_pr_transport_id = fc_get_pr_transport_id, 5293699d92aSKiran Patil .tpg_get_pr_transport_id_len = fc_get_pr_transport_id_len, 5303699d92aSKiran Patil .tpg_parse_pr_out_transport_id = fc_parse_pr_out_transport_id, 5313699d92aSKiran Patil .tpg_check_demo_mode = ft_check_false, 5323699d92aSKiran Patil .tpg_check_demo_mode_cache = ft_check_false, 5333699d92aSKiran Patil .tpg_check_demo_mode_write_protect = ft_check_false, 5343699d92aSKiran Patil .tpg_check_prod_mode_write_protect = ft_check_false, 5353699d92aSKiran Patil .tpg_alloc_fabric_acl = ft_tpg_alloc_fabric_acl, 5363699d92aSKiran Patil .tpg_release_fabric_acl = ft_tpg_release_fabric_acl, 5373699d92aSKiran Patil .tpg_get_inst_index = ft_tpg_get_inst_index, 5383699d92aSKiran Patil .check_stop_free = ft_check_stop_free, 539*35462975SChristoph Hellwig .release_cmd = ft_release_cmd, 5403699d92aSKiran Patil .shutdown_session = ft_sess_shutdown, 5413699d92aSKiran Patil .close_session = ft_sess_close, 5423699d92aSKiran Patil .stop_session = ft_sess_stop, 5433699d92aSKiran Patil .fall_back_to_erl0 = ft_sess_set_erl0, 5443699d92aSKiran Patil .sess_logged_in = ft_sess_logged_in, 5453699d92aSKiran Patil .sess_get_index = ft_sess_get_index, 5463699d92aSKiran Patil .sess_get_initiator_sid = NULL, 5473699d92aSKiran Patil .write_pending = ft_write_pending, 5483699d92aSKiran Patil .write_pending_status = ft_write_pending_status, 5493699d92aSKiran Patil .set_default_node_attributes = ft_set_default_node_attr, 5503699d92aSKiran Patil .get_task_tag = ft_get_task_tag, 5513699d92aSKiran Patil .get_cmd_state = ft_get_cmd_state, 5523699d92aSKiran Patil .queue_data_in = ft_queue_data_in, 5533699d92aSKiran Patil .queue_status = ft_queue_status, 5543699d92aSKiran Patil .queue_tm_rsp = ft_queue_tm_resp, 5553699d92aSKiran Patil .get_fabric_sense_len = ft_get_fabric_sense_len, 5563699d92aSKiran Patil .set_fabric_sense_len = ft_set_fabric_sense_len, 5573699d92aSKiran Patil .is_state_remove = ft_is_state_remove, 5583699d92aSKiran Patil /* 5593699d92aSKiran Patil * Setup function pointers for generic logic in 5603699d92aSKiran Patil * target_core_fabric_configfs.c 5613699d92aSKiran Patil */ 5623699d92aSKiran Patil .fabric_make_wwn = &ft_add_lport, 5633699d92aSKiran Patil .fabric_drop_wwn = &ft_del_lport, 5643699d92aSKiran Patil .fabric_make_tpg = &ft_add_tpg, 5653699d92aSKiran Patil .fabric_drop_tpg = &ft_del_tpg, 5663699d92aSKiran Patil .fabric_post_link = NULL, 5673699d92aSKiran Patil .fabric_pre_unlink = NULL, 5683699d92aSKiran Patil .fabric_make_np = NULL, 5693699d92aSKiran Patil .fabric_drop_np = NULL, 5703699d92aSKiran Patil .fabric_make_nodeacl = &ft_add_acl, 5713699d92aSKiran Patil .fabric_drop_nodeacl = &ft_del_acl, 5723699d92aSKiran Patil }; 5733699d92aSKiran Patil 5743699d92aSKiran Patil int ft_register_configfs(void) 5753699d92aSKiran Patil { 5763699d92aSKiran Patil struct target_fabric_configfs *fabric; 5773699d92aSKiran Patil int ret; 5783699d92aSKiran Patil 5793699d92aSKiran Patil /* 5803699d92aSKiran Patil * Register the top level struct config_item_type with TCM core 5813699d92aSKiran Patil */ 5823699d92aSKiran Patil fabric = target_fabric_configfs_init(THIS_MODULE, "fc"); 583e3d6f909SAndy Grover if (IS_ERR(fabric)) { 5843699d92aSKiran Patil printk(KERN_INFO "%s: target_fabric_configfs_init() failed!\n", 5853699d92aSKiran Patil __func__); 586e3d6f909SAndy Grover return PTR_ERR(fabric); 5873699d92aSKiran Patil } 5883699d92aSKiran Patil fabric->tf_ops = ft_fabric_ops; 5893699d92aSKiran Patil 5903699d92aSKiran Patil /* Allowing support for task_sg_chaining */ 5913699d92aSKiran Patil fabric->tf_ops.task_sg_chaining = 1; 5923699d92aSKiran Patil 5933699d92aSKiran Patil /* 5943699d92aSKiran Patil * Setup default attribute lists for various fabric->tf_cit_tmpl 5953699d92aSKiran Patil */ 5963699d92aSKiran Patil TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = ft_wwn_attrs; 5973699d92aSKiran Patil TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = NULL; 5983699d92aSKiran Patil TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL; 5993699d92aSKiran Patil TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL; 6003699d92aSKiran Patil TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL; 6013699d92aSKiran Patil TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = 6023699d92aSKiran Patil ft_nacl_base_attrs; 6033699d92aSKiran Patil TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; 6043699d92aSKiran Patil TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL; 6053699d92aSKiran Patil TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL; 6063699d92aSKiran Patil /* 6073699d92aSKiran Patil * register the fabric for use within TCM 6083699d92aSKiran Patil */ 6093699d92aSKiran Patil ret = target_fabric_configfs_register(fabric); 6103699d92aSKiran Patil if (ret < 0) { 6113699d92aSKiran Patil FT_CONF_DBG("target_fabric_configfs_register() for" 6123699d92aSKiran Patil " FC Target failed!\n"); 6133699d92aSKiran Patil printk(KERN_INFO 6143699d92aSKiran Patil "%s: target_fabric_configfs_register() failed!\n", 6153699d92aSKiran Patil __func__); 6163699d92aSKiran Patil target_fabric_configfs_free(fabric); 6173699d92aSKiran Patil return -1; 6183699d92aSKiran Patil } 6193699d92aSKiran Patil 6203699d92aSKiran Patil /* 6213699d92aSKiran Patil * Setup our local pointer to *fabric. 6223699d92aSKiran Patil */ 6233699d92aSKiran Patil ft_configfs = fabric; 6243699d92aSKiran Patil return 0; 6253699d92aSKiran Patil } 6263699d92aSKiran Patil 6273699d92aSKiran Patil void ft_deregister_configfs(void) 6283699d92aSKiran Patil { 6293699d92aSKiran Patil if (!ft_configfs) 6303699d92aSKiran Patil return; 6313699d92aSKiran Patil target_fabric_configfs_deregister(ft_configfs); 6323699d92aSKiran Patil ft_configfs = NULL; 6333699d92aSKiran Patil } 6343699d92aSKiran Patil 6353699d92aSKiran Patil static struct notifier_block ft_notifier = { 6363699d92aSKiran Patil .notifier_call = ft_lport_notify 6373699d92aSKiran Patil }; 6383699d92aSKiran Patil 6393699d92aSKiran Patil static int __init ft_init(void) 6403699d92aSKiran Patil { 6413699d92aSKiran Patil if (ft_register_configfs()) 6423699d92aSKiran Patil return -1; 6433699d92aSKiran Patil if (fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov)) { 6443699d92aSKiran Patil ft_deregister_configfs(); 6453699d92aSKiran Patil return -1; 6463699d92aSKiran Patil } 6473699d92aSKiran Patil blocking_notifier_chain_register(&fc_lport_notifier_head, &ft_notifier); 6483699d92aSKiran Patil fc_lport_iterate(ft_lport_add, NULL); 6493699d92aSKiran Patil return 0; 6503699d92aSKiran Patil } 6513699d92aSKiran Patil 6523699d92aSKiran Patil static void __exit ft_exit(void) 6533699d92aSKiran Patil { 6543699d92aSKiran Patil blocking_notifier_chain_unregister(&fc_lport_notifier_head, 6553699d92aSKiran Patil &ft_notifier); 6563699d92aSKiran Patil fc_fc4_deregister_provider(FC_TYPE_FCP, &ft_prov); 6573699d92aSKiran Patil fc_lport_iterate(ft_lport_del, NULL); 6583699d92aSKiran Patil ft_deregister_configfs(); 6593699d92aSKiran Patil synchronize_rcu(); 6603699d92aSKiran Patil } 6613699d92aSKiran Patil 6623699d92aSKiran Patil #ifdef MODULE 6633699d92aSKiran Patil MODULE_DESCRIPTION("FC TCM fabric driver " FT_VERSION); 6643699d92aSKiran Patil MODULE_LICENSE("GPL"); 6653699d92aSKiran Patil module_init(ft_init); 6663699d92aSKiran Patil module_exit(ft_exit); 6673699d92aSKiran Patil #endif /* MODULE */ 668