6ac3fc1a7d39bba8478bbdb1e00a27dafb44c46f
[linux-2.6-microblaze.git] / drivers / target / tcm_fc / tfc_conf.c
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 u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg)
402 {
403         return ft_tpg(se_tpg)->index;
404 }
405
406 static const struct target_core_fabric_ops ft_fabric_ops = {
407         .module =                       THIS_MODULE,
408         .fabric_name =                  "fc",
409         .node_acl_size =                sizeof(struct ft_node_acl),
410         .tpg_get_wwn =                  ft_get_fabric_wwn,
411         .tpg_get_tag =                  ft_get_tag,
412         .tpg_get_inst_index =           ft_tpg_get_inst_index,
413         .check_stop_free =              ft_check_stop_free,
414         .release_cmd =                  ft_release_cmd,
415         .close_session =                ft_sess_close,
416         .sess_get_index =               ft_sess_get_index,
417         .sess_get_initiator_sid =       NULL,
418         .write_pending =                ft_write_pending,
419         .queue_data_in =                ft_queue_data_in,
420         .queue_status =                 ft_queue_status,
421         .queue_tm_rsp =                 ft_queue_tm_resp,
422         .aborted_task =                 ft_aborted_task,
423         /*
424          * Setup function pointers for generic logic in
425          * target_core_fabric_configfs.c
426          */
427         .fabric_make_wwn =              &ft_add_wwn,
428         .fabric_drop_wwn =              &ft_del_wwn,
429         .fabric_make_tpg =              &ft_add_tpg,
430         .fabric_drop_tpg =              &ft_del_tpg,
431         .fabric_init_nodeacl =          &ft_init_nodeacl,
432
433         .tfc_wwn_attrs                  = ft_wwn_attrs,
434         .tfc_tpg_nacl_base_attrs        = ft_nacl_base_attrs,
435 };
436
437 static struct notifier_block ft_notifier = {
438         .notifier_call = ft_lport_notify
439 };
440
441 static int __init ft_init(void)
442 {
443         int ret;
444
445         ret = target_register_template(&ft_fabric_ops);
446         if (ret)
447                 goto out;
448
449         ret = fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov);
450         if (ret)
451                 goto out_unregister_template;
452
453         blocking_notifier_chain_register(&fc_lport_notifier_head, &ft_notifier);
454         fc_lport_iterate(ft_lport_add, NULL);
455         return 0;
456
457 out_unregister_template:
458         target_unregister_template(&ft_fabric_ops);
459 out:
460         return ret;
461 }
462
463 static void __exit ft_exit(void)
464 {
465         blocking_notifier_chain_unregister(&fc_lport_notifier_head,
466                                            &ft_notifier);
467         fc_fc4_deregister_provider(FC_TYPE_FCP, &ft_prov);
468         fc_lport_iterate(ft_lport_del, NULL);
469         target_unregister_template(&ft_fabric_ops);
470         synchronize_rcu();
471 }
472
473 MODULE_DESCRIPTION("FC TCM fabric driver " FT_VERSION);
474 MODULE_LICENSE("GPL");
475 module_init(ft_init);
476 module_exit(ft_exit);