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 37 static LIST_HEAD(ft_wwn_list); 38 DEFINE_MUTEX(ft_lport_lock); 39 40 unsigned int ft_debug_logging; 41 module_param_named(debug_logging, ft_debug_logging, int, S_IRUGO|S_IWUSR); 42 MODULE_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 */ 50 static 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; 84 fail: 85 pr_debug("err %u len %zu pos %u byte %u\n", 86 err, cp - name, pos, byte); 87 return -1; 88 } 89 90 ssize_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 100 static 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 110 static 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 125 static 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 134 static 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 144 static 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 154 static 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 164 CONFIGFS_ATTR(ft_nacl_, node_name); 165 CONFIGFS_ATTR(ft_nacl_, port_name); 166 167 static 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 173 static 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 186 CONFIGFS_ATTR(ft_nacl_, tag); 187 188 static 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 */ 203 static 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 */ 219 static 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(sizeof(*tpg), GFP_KERNEL); 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 275 static 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 */ 306 struct 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 */ 325 static 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(sizeof(*ft_wwn), GFP_KERNEL); 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 357 static 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 370 static 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 376 CONFIGFS_ATTR_RO(ft_wwn_, version); 377 378 static struct configfs_attribute *ft_wwn_attrs[] = { 379 &ft_wwn_attr_version, 380 NULL, 381 }; 382 383 static 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 388 static char *ft_get_fabric_wwn(struct se_portal_group *se_tpg) 389 { 390 return ft_tpg(se_tpg)->lport_wwn->name; 391 } 392 393 static 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 402 static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg) 403 { 404 return ft_tpg(se_tpg)->index; 405 } 406 407 static 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_submit_type = TARGET_DIRECT_SUBMIT, 438 .direct_submit_supp = 1, 439 }; 440 441 static struct notifier_block ft_notifier = { 442 .notifier_call = ft_lport_notify 443 }; 444 445 static int __init ft_init(void) 446 { 447 int ret; 448 449 ret = target_register_template(&ft_fabric_ops); 450 if (ret) 451 goto out; 452 453 ret = fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov); 454 if (ret) 455 goto out_unregister_template; 456 457 blocking_notifier_chain_register(&fc_lport_notifier_head, &ft_notifier); 458 fc_lport_iterate(ft_lport_add, NULL); 459 return 0; 460 461 out_unregister_template: 462 target_unregister_template(&ft_fabric_ops); 463 out: 464 return ret; 465 } 466 467 static void __exit ft_exit(void) 468 { 469 blocking_notifier_chain_unregister(&fc_lport_notifier_head, 470 &ft_notifier); 471 fc_fc4_deregister_provider(FC_TYPE_FCP, &ft_prov); 472 fc_lport_iterate(ft_lport_del, NULL); 473 target_unregister_template(&ft_fabric_ops); 474 synchronize_rcu(); 475 } 476 477 MODULE_DESCRIPTION("FC TCM fabric driver " FT_VERSION); 478 MODULE_LICENSE("GPL"); 479 module_init(ft_init); 480 module_exit(ft_exit); 481