root/drivers/target/tcm_fc/tfc_conf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ft_parse_wwn
  2. ft_format_wwn
  3. ft_wwn_show
  4. ft_wwn_store
  5. ft_nacl_port_name_show
  6. ft_nacl_port_name_store
  7. ft_nacl_node_name_show
  8. ft_nacl_node_name_store
  9. ft_nacl_tag_show
  10. ft_nacl_tag_store
  11. ft_init_nodeacl
  12. ft_add_tpg
  13. ft_del_tpg
  14. ft_lport_find_tpg
  15. ft_add_wwn
  16. ft_del_wwn
  17. ft_wwn_version_show
  18. ft_get_fabric_wwn
  19. ft_get_tag
  20. ft_check_false
  21. ft_set_default_node_attr
  22. ft_tpg_get_inst_index
  23. ft_init
  24. ft_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*******************************************************************************
   3  * Filename:  tcm_fc.c
   4  *
   5  * This file contains the configfs implementation for TCM_fc fabric node.
   6  * Based on tcm_loop_configfs.c
   7  *
   8  * Copyright (c) 2010 Cisco Systems, Inc.
   9  * Copyright (c) 2009,2010 Rising Tide, Inc.
  10  * Copyright (c) 2009,2010 Linux-iSCSI.org
  11  *
  12  * Copyright (c) 2009,2010 Nicholas A. Bellinger <nab@linux-iscsi.org>
  13  *
  14  ****************************************************************************/
  15 
  16 #include <linux/module.h>
  17 #include <linux/moduleparam.h>
  18 #include <generated/utsrelease.h>
  19 #include <linux/utsname.h>
  20 #include <linux/init.h>
  21 #include <linux/slab.h>
  22 #include <linux/kthread.h>
  23 #include <linux/types.h>
  24 #include <linux/string.h>
  25 #include <linux/configfs.h>
  26 #include <linux/kernel.h>
  27 #include <linux/ctype.h>
  28 #include <asm/unaligned.h>
  29 #include <scsi/libfc.h>
  30 
  31 #include <target/target_core_base.h>
  32 #include <target/target_core_fabric.h>
  33 
  34 #include "tcm_fc.h"
  35 
  36 static LIST_HEAD(ft_wwn_list);
  37 DEFINE_MUTEX(ft_lport_lock);
  38 
  39 unsigned int ft_debug_logging;
  40 module_param_named(debug_logging, ft_debug_logging, int, S_IRUGO|S_IWUSR);
  41 MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
  42 
  43 /*
  44  * Parse WWN.
  45  * If strict, we require lower-case hex and colon separators to be sure
  46  * the name is the same as what would be generated by ft_format_wwn()
  47  * so the name and wwn are mapped one-to-one.
  48  */
  49 static ssize_t ft_parse_wwn(const char *name, u64 *wwn, int strict)
  50 {
  51         const char *cp;
  52         char c;
  53         u32 byte = 0;
  54         u32 pos = 0;
  55         u32 err;
  56         int val;
  57 
  58         *wwn = 0;
  59         for (cp = name; cp < &name[FT_NAMELEN - 1]; cp++) {
  60                 c = *cp;
  61                 if (c == '\n' && cp[1] == '\0')
  62                         continue;
  63                 if (strict && pos++ == 2 && byte++ < 7) {
  64                         pos = 0;
  65                         if (c == ':')
  66                                 continue;
  67                         err = 1;
  68                         goto fail;
  69                 }
  70                 if (c == '\0') {
  71                         err = 2;
  72                         if (strict && byte != 8)
  73                                 goto fail;
  74                         return cp - name;
  75                 }
  76                 err = 3;
  77                 val = hex_to_bin(c);
  78                 if (val < 0 || (strict && isupper(c)))
  79                         goto fail;
  80                 *wwn = (*wwn << 4) | val;
  81         }
  82         err = 4;
  83 fail:
  84         pr_debug("err %u len %zu pos %u byte %u\n",
  85                     err, cp - name, pos, byte);
  86         return -1;
  87 }
  88 
  89 ssize_t ft_format_wwn(char *buf, size_t len, u64 wwn)
  90 {
  91         u8 b[8];
  92 
  93         put_unaligned_be64(wwn, b);
  94         return snprintf(buf, len,
  95                  "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
  96                  b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
  97 }
  98 
  99 static ssize_t ft_wwn_show(void *arg, char *buf)
 100 {
 101         u64 *wwn = arg;
 102         ssize_t len;
 103 
 104         len = ft_format_wwn(buf, PAGE_SIZE - 2, *wwn);
 105         buf[len++] = '\n';
 106         return len;
 107 }
 108 
 109 static ssize_t ft_wwn_store(void *arg, const char *buf, size_t len)
 110 {
 111         ssize_t ret;
 112         u64 wwn;
 113 
 114         ret = ft_parse_wwn(buf, &wwn, 0);
 115         if (ret > 0)
 116                 *(u64 *)arg = wwn;
 117         return ret;
 118 }
 119 
 120 /*
 121  * ACL auth ops.
 122  */
 123 
 124 static ssize_t ft_nacl_port_name_show(struct config_item *item, char *page)
 125 {
 126         struct se_node_acl *se_nacl = acl_to_nacl(item);
 127         struct ft_node_acl *acl = container_of(se_nacl,
 128                         struct ft_node_acl, se_node_acl);
 129 
 130         return ft_wwn_show(&acl->node_auth.port_name, page);
 131 }
 132 
 133 static ssize_t ft_nacl_port_name_store(struct config_item *item,
 134                 const char *page, size_t count)
 135 {
 136         struct se_node_acl *se_nacl = acl_to_nacl(item);
 137         struct ft_node_acl *acl = container_of(se_nacl,
 138                         struct ft_node_acl, se_node_acl);
 139 
 140         return ft_wwn_store(&acl->node_auth.port_name, page, count);
 141 }
 142 
 143 static ssize_t ft_nacl_node_name_show(struct config_item *item,
 144                 char *page)
 145 {
 146         struct se_node_acl *se_nacl = acl_to_nacl(item);
 147         struct ft_node_acl *acl = container_of(se_nacl,
 148                         struct ft_node_acl, se_node_acl);
 149 
 150         return ft_wwn_show(&acl->node_auth.node_name, page);
 151 }
 152 
 153 static ssize_t ft_nacl_node_name_store(struct config_item *item,
 154                 const char *page, size_t count)
 155 {
 156         struct se_node_acl *se_nacl = acl_to_nacl(item);
 157         struct ft_node_acl *acl = container_of(se_nacl,
 158                         struct ft_node_acl, se_node_acl);
 159 
 160         return ft_wwn_store(&acl->node_auth.node_name, page, count);
 161 }
 162 
 163 CONFIGFS_ATTR(ft_nacl_, node_name);
 164 CONFIGFS_ATTR(ft_nacl_, port_name);
 165 
 166 static ssize_t ft_nacl_tag_show(struct config_item *item,
 167                 char *page)
 168 {
 169         return snprintf(page, PAGE_SIZE, "%s", acl_to_nacl(item)->acl_tag);
 170 }
 171 
 172 static ssize_t ft_nacl_tag_store(struct config_item *item,
 173                 const char *page, size_t count)
 174 {
 175         struct se_node_acl *se_nacl = acl_to_nacl(item);
 176         int ret;
 177 
 178         ret = core_tpg_set_initiator_node_tag(se_nacl->se_tpg, se_nacl, page);
 179 
 180         if (ret < 0)
 181                 return ret;
 182         return count;
 183 }
 184 
 185 CONFIGFS_ATTR(ft_nacl_, tag);
 186 
 187 static struct configfs_attribute *ft_nacl_base_attrs[] = {
 188         &ft_nacl_attr_port_name,
 189         &ft_nacl_attr_node_name,
 190         &ft_nacl_attr_tag,
 191         NULL,
 192 };
 193 
 194 /*
 195  * ACL ops.
 196  */
 197 
 198 /*
 199  * Add ACL for an initiator.  The ACL is named arbitrarily.
 200  * The port_name and/or node_name are attributes.
 201  */
 202 static int ft_init_nodeacl(struct se_node_acl *nacl, const char *name)
 203 {
 204         struct ft_node_acl *acl =
 205                 container_of(nacl, struct ft_node_acl, se_node_acl);
 206         u64 wwpn;
 207 
 208         if (ft_parse_wwn(name, &wwpn, 1) < 0)
 209                 return -EINVAL;
 210 
 211         acl->node_auth.port_name = wwpn;
 212         return 0;
 213 }
 214 
 215 /*
 216  * local_port port_group (tpg) ops.
 217  */
 218 static struct se_portal_group *ft_add_tpg(struct se_wwn *wwn, const char *name)
 219 {
 220         struct ft_lport_wwn *ft_wwn;
 221         struct ft_tpg *tpg;
 222         struct workqueue_struct *wq;
 223         unsigned long index;
 224         int ret;
 225 
 226         pr_debug("tcm_fc: add tpg %s\n", name);
 227 
 228         /*
 229          * Name must be "tpgt_" followed by the index.
 230          */
 231         if (strstr(name, "tpgt_") != name)
 232                 return NULL;
 233 
 234         ret = kstrtoul(name + 5, 10, &index);
 235         if (ret)
 236                 return NULL;
 237         if (index > UINT_MAX)
 238                 return NULL;
 239 
 240         if ((index != 1)) {
 241                 pr_err("Error, a single TPG=1 is used for HW port mappings\n");
 242                 return ERR_PTR(-ENOSYS);
 243         }
 244 
 245         ft_wwn = container_of(wwn, struct ft_lport_wwn, se_wwn);
 246         tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
 247         if (!tpg)
 248                 return NULL;
 249         tpg->index = index;
 250         tpg->lport_wwn = ft_wwn;
 251         INIT_LIST_HEAD(&tpg->lun_list);
 252 
 253         wq = alloc_workqueue("tcm_fc", 0, 1);
 254         if (!wq) {
 255                 kfree(tpg);
 256                 return NULL;
 257         }
 258 
 259         ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_FCP);
 260         if (ret < 0) {
 261                 destroy_workqueue(wq);
 262                 kfree(tpg);
 263                 return NULL;
 264         }
 265         tpg->workqueue = wq;
 266 
 267         mutex_lock(&ft_lport_lock);
 268         ft_wwn->tpg = tpg;
 269         mutex_unlock(&ft_lport_lock);
 270 
 271         return &tpg->se_tpg;
 272 }
 273 
 274 static void ft_del_tpg(struct se_portal_group *se_tpg)
 275 {
 276         struct ft_tpg *tpg = container_of(se_tpg, struct ft_tpg, se_tpg);
 277         struct ft_lport_wwn *ft_wwn = tpg->lport_wwn;
 278 
 279         pr_debug("del tpg %s\n",
 280                     config_item_name(&tpg->se_tpg.tpg_group.cg_item));
 281 
 282         destroy_workqueue(tpg->workqueue);
 283 
 284         /* Wait for sessions to be freed thru RCU, for BUG_ON below */
 285         synchronize_rcu();
 286 
 287         mutex_lock(&ft_lport_lock);
 288         ft_wwn->tpg = NULL;
 289         if (tpg->tport) {
 290                 tpg->tport->tpg = NULL;
 291                 tpg->tport = NULL;
 292         }
 293         mutex_unlock(&ft_lport_lock);
 294 
 295         core_tpg_deregister(se_tpg);
 296         kfree(tpg);
 297 }
 298 
 299 /*
 300  * Verify that an lport is configured to use the tcm_fc module, and return
 301  * the target port group that should be used.
 302  *
 303  * The caller holds ft_lport_lock.
 304  */
 305 struct ft_tpg *ft_lport_find_tpg(struct fc_lport *lport)
 306 {
 307         struct ft_lport_wwn *ft_wwn;
 308 
 309         list_for_each_entry(ft_wwn, &ft_wwn_list, ft_wwn_node) {
 310                 if (ft_wwn->wwpn == lport->wwpn)
 311                         return ft_wwn->tpg;
 312         }
 313         return NULL;
 314 }
 315 
 316 /*
 317  * target config instance ops.
 318  */
 319 
 320 /*
 321  * Add lport to allowed config.
 322  * The name is the WWPN in lower-case ASCII, colon-separated bytes.
 323  */
 324 static struct se_wwn *ft_add_wwn(
 325         struct target_fabric_configfs *tf,
 326         struct config_group *group,
 327         const char *name)
 328 {
 329         struct ft_lport_wwn *ft_wwn;
 330         struct ft_lport_wwn *old_ft_wwn;
 331         u64 wwpn;
 332 
 333         pr_debug("add wwn %s\n", name);
 334         if (ft_parse_wwn(name, &wwpn, 1) < 0)
 335                 return NULL;
 336         ft_wwn = kzalloc(sizeof(*ft_wwn), GFP_KERNEL);
 337         if (!ft_wwn)
 338                 return NULL;
 339         ft_wwn->wwpn = wwpn;
 340 
 341         mutex_lock(&ft_lport_lock);
 342         list_for_each_entry(old_ft_wwn, &ft_wwn_list, ft_wwn_node) {
 343                 if (old_ft_wwn->wwpn == wwpn) {
 344                         mutex_unlock(&ft_lport_lock);
 345                         kfree(ft_wwn);
 346                         return NULL;
 347                 }
 348         }
 349         list_add_tail(&ft_wwn->ft_wwn_node, &ft_wwn_list);
 350         ft_format_wwn(ft_wwn->name, sizeof(ft_wwn->name), wwpn);
 351         mutex_unlock(&ft_lport_lock);
 352 
 353         return &ft_wwn->se_wwn;
 354 }
 355 
 356 static void ft_del_wwn(struct se_wwn *wwn)
 357 {
 358         struct ft_lport_wwn *ft_wwn = container_of(wwn,
 359                                 struct ft_lport_wwn, se_wwn);
 360 
 361         pr_debug("del wwn %s\n", ft_wwn->name);
 362         mutex_lock(&ft_lport_lock);
 363         list_del(&ft_wwn->ft_wwn_node);
 364         mutex_unlock(&ft_lport_lock);
 365 
 366         kfree(ft_wwn);
 367 }
 368 
 369 static ssize_t ft_wwn_version_show(struct config_item *item, char *page)
 370 {
 371         return sprintf(page, "TCM FC " FT_VERSION " on %s/%s on "
 372                 ""UTS_RELEASE"\n",  utsname()->sysname, utsname()->machine);
 373 }
 374 
 375 CONFIGFS_ATTR_RO(ft_wwn_, version);
 376 
 377 static struct configfs_attribute *ft_wwn_attrs[] = {
 378         &ft_wwn_attr_version,
 379         NULL,
 380 };
 381 
 382 static inline struct ft_tpg *ft_tpg(struct se_portal_group *se_tpg)
 383 {
 384         return container_of(se_tpg, struct ft_tpg, se_tpg);
 385 }
 386 
 387 static char *ft_get_fabric_wwn(struct se_portal_group *se_tpg)
 388 {
 389         return ft_tpg(se_tpg)->lport_wwn->name;
 390 }
 391 
 392 static u16 ft_get_tag(struct se_portal_group *se_tpg)
 393 {
 394         /*
 395          * This tag is used when forming SCSI Name identifier in EVPD=1 0x83
 396          * to represent the SCSI Target Port.
 397          */
 398         return ft_tpg(se_tpg)->index;
 399 }
 400 
 401 static int ft_check_false(struct se_portal_group *se_tpg)
 402 {
 403         return 0;
 404 }
 405 
 406 static void ft_set_default_node_attr(struct se_node_acl *se_nacl)
 407 {
 408 }
 409 
 410 static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg)
 411 {
 412         return ft_tpg(se_tpg)->index;
 413 }
 414 
 415 static const struct target_core_fabric_ops ft_fabric_ops = {
 416         .module =                       THIS_MODULE,
 417         .fabric_name =                  "fc",
 418         .node_acl_size =                sizeof(struct ft_node_acl),
 419         .tpg_get_wwn =                  ft_get_fabric_wwn,
 420         .tpg_get_tag =                  ft_get_tag,
 421         .tpg_check_demo_mode =          ft_check_false,
 422         .tpg_check_demo_mode_cache =    ft_check_false,
 423         .tpg_check_demo_mode_write_protect = ft_check_false,
 424         .tpg_check_prod_mode_write_protect = ft_check_false,
 425         .tpg_get_inst_index =           ft_tpg_get_inst_index,
 426         .check_stop_free =              ft_check_stop_free,
 427         .release_cmd =                  ft_release_cmd,
 428         .close_session =                ft_sess_close,
 429         .sess_get_index =               ft_sess_get_index,
 430         .sess_get_initiator_sid =       NULL,
 431         .write_pending =                ft_write_pending,
 432         .set_default_node_attributes =  ft_set_default_node_attr,
 433         .get_cmd_state =                ft_get_cmd_state,
 434         .queue_data_in =                ft_queue_data_in,
 435         .queue_status =                 ft_queue_status,
 436         .queue_tm_rsp =                 ft_queue_tm_resp,
 437         .aborted_task =                 ft_aborted_task,
 438         /*
 439          * Setup function pointers for generic logic in
 440          * target_core_fabric_configfs.c
 441          */
 442         .fabric_make_wwn =              &ft_add_wwn,
 443         .fabric_drop_wwn =              &ft_del_wwn,
 444         .fabric_make_tpg =              &ft_add_tpg,
 445         .fabric_drop_tpg =              &ft_del_tpg,
 446         .fabric_init_nodeacl =          &ft_init_nodeacl,
 447 
 448         .tfc_wwn_attrs                  = ft_wwn_attrs,
 449         .tfc_tpg_nacl_base_attrs        = ft_nacl_base_attrs,
 450 };
 451 
 452 static struct notifier_block ft_notifier = {
 453         .notifier_call = ft_lport_notify
 454 };
 455 
 456 static int __init ft_init(void)
 457 {
 458         int ret;
 459 
 460         ret = target_register_template(&ft_fabric_ops);
 461         if (ret)
 462                 goto out;
 463 
 464         ret = fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov);
 465         if (ret)
 466                 goto out_unregister_template;
 467 
 468         blocking_notifier_chain_register(&fc_lport_notifier_head, &ft_notifier);
 469         fc_lport_iterate(ft_lport_add, NULL);
 470         return 0;
 471 
 472 out_unregister_template:
 473         target_unregister_template(&ft_fabric_ops);
 474 out:
 475         return ret;
 476 }
 477 
 478 static void __exit ft_exit(void)
 479 {
 480         blocking_notifier_chain_unregister(&fc_lport_notifier_head,
 481                                            &ft_notifier);
 482         fc_fc4_deregister_provider(FC_TYPE_FCP, &ft_prov);
 483         fc_lport_iterate(ft_lport_del, NULL);
 484         target_unregister_template(&ft_fabric_ops);
 485         synchronize_rcu();
 486 }
 487 
 488 MODULE_DESCRIPTION("FC TCM fabric driver " FT_VERSION);
 489 MODULE_LICENSE("GPL");
 490 module_init(ft_init);
 491 module_exit(ft_exit);

/* [<][>][^][v][top][bottom][index][help] */