Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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