Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tfc_conf.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Filename: tcm_fc.c
3  *
4  * This file contains the configfs implementation for TCM_fc fabric node.
5  * Based on tcm_loop_configfs.c
6  *
7  * Copyright (c) 2010 Cisco Systems, Inc.
8  * Copyright (c) 2009,2010 Rising Tide, Inc.
9  * Copyright (c) 2009,2010 Linux-iSCSI.org
10  *
11  * Copyright (c) 2009,2010 Nicholas A. Bellinger <[email protected]>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  ****************************************************************************/
23 
24 #include <linux/module.h>
25 #include <linux/moduleparam.h>
26 #include <generated/utsrelease.h>
27 #include <linux/utsname.h>
28 #include <linux/init.h>
29 #include <linux/slab.h>
30 #include <linux/kthread.h>
31 #include <linux/types.h>
32 #include <linux/string.h>
33 #include <linux/configfs.h>
34 #include <linux/kernel.h>
35 #include <linux/ctype.h>
36 #include <asm/unaligned.h>
37 #include <scsi/scsi.h>
38 #include <scsi/scsi_host.h>
39 #include <scsi/scsi_device.h>
40 #include <scsi/scsi_cmnd.h>
41 #include <scsi/libfc.h>
42 
47 #include <target/configfs_macros.h>
48 
49 #include "tcm_fc.h"
50 
52 
53 LIST_HEAD(ft_lport_list);
54 DEFINE_MUTEX(ft_lport_lock);
55 
56 unsigned int ft_debug_logging;
58 MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
59 
60 /*
61  * Parse WWN.
62  * If strict, we require lower-case hex and colon separators to be sure
63  * the name is the same as what would be generated by ft_format_wwn()
64  * so the name and wwn are mapped one-to-one.
65  */
66 static ssize_t ft_parse_wwn(const char *name, u64 *wwn, int strict)
67 {
68  const char *cp;
69  char c;
70  u32 byte = 0;
71  u32 pos = 0;
72  u32 err;
73  int val;
74 
75  *wwn = 0;
76  for (cp = name; cp < &name[FT_NAMELEN - 1]; cp++) {
77  c = *cp;
78  if (c == '\n' && cp[1] == '\0')
79  continue;
80  if (strict && pos++ == 2 && byte++ < 7) {
81  pos = 0;
82  if (c == ':')
83  continue;
84  err = 1;
85  goto fail;
86  }
87  if (c == '\0') {
88  err = 2;
89  if (strict && byte != 8)
90  goto fail;
91  return cp - name;
92  }
93  err = 3;
94  val = hex_to_bin(c);
95  if (val < 0 || (strict && isupper(c)))
96  goto fail;
97  *wwn = (*wwn << 4) | val;
98  }
99  err = 4;
100 fail:
101  pr_debug("err %u len %zu pos %u byte %u\n",
102  err, cp - name, pos, byte);
103  return -1;
104 }
105 
106 ssize_t ft_format_wwn(char *buf, size_t len, u64 wwn)
107 {
108  u8 b[8];
109 
110  put_unaligned_be64(wwn, b);
111  return snprintf(buf, len,
112  "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
113  b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
114 }
115 
116 static ssize_t ft_wwn_show(void *arg, char *buf)
117 {
118  u64 *wwn = arg;
119  ssize_t len;
120 
121  len = ft_format_wwn(buf, PAGE_SIZE - 2, *wwn);
122  buf[len++] = '\n';
123  return len;
124 }
125 
126 static ssize_t ft_wwn_store(void *arg, const char *buf, size_t len)
127 {
128  ssize_t ret;
129  u64 wwn;
130 
131  ret = ft_parse_wwn(buf, &wwn, 0);
132  if (ret > 0)
133  *(u64 *)arg = wwn;
134  return ret;
135 }
136 
137 /*
138  * ACL auth ops.
139  */
140 
141 static ssize_t ft_nacl_show_port_name(
142  struct se_node_acl *se_nacl,
143  char *page)
144 {
145  struct ft_node_acl *acl = container_of(se_nacl,
146  struct ft_node_acl, se_node_acl);
147 
148  return ft_wwn_show(&acl->node_auth.port_name, page);
149 }
150 
151 static ssize_t ft_nacl_store_port_name(
152  struct se_node_acl *se_nacl,
153  const char *page,
154  size_t count)
155 {
156  struct ft_node_acl *acl = container_of(se_nacl,
157  struct ft_node_acl, se_node_acl);
158 
159  return ft_wwn_store(&acl->node_auth.port_name, page, count);
160 }
161 
163 
164 static ssize_t ft_nacl_show_node_name(
165  struct se_node_acl *se_nacl,
166  char *page)
167 {
168  struct ft_node_acl *acl = container_of(se_nacl,
169  struct ft_node_acl, se_node_acl);
170 
171  return ft_wwn_show(&acl->node_auth.node_name, page);
172 }
173 
174 static ssize_t ft_nacl_store_node_name(
175  struct se_node_acl *se_nacl,
176  const char *page,
177  size_t count)
178 {
179  struct ft_node_acl *acl = container_of(se_nacl,
180  struct ft_node_acl, se_node_acl);
181 
182  return ft_wwn_store(&acl->node_auth.node_name, page, count);
183 }
184 
186 
187 static struct configfs_attribute *ft_nacl_base_attrs[] = {
188  &ft_nacl_port_name.attr,
189  &ft_nacl_node_name.attr,
190  NULL,
191 };
192 
193 /*
194  * ACL ops.
195  */
196 
197 /*
198  * Add ACL for an initiator. The ACL is named arbitrarily.
199  * The port_name and/or node_name are attributes.
200  */
201 static struct se_node_acl *ft_add_acl(
202  struct se_portal_group *se_tpg,
203  struct config_group *group,
204  const char *name)
205 {
206  struct ft_node_acl *acl;
207  struct ft_tpg *tpg;
208  u64 wwpn;
209  u32 q_depth;
210 
211  pr_debug("add acl %s\n", name);
212  tpg = container_of(se_tpg, struct ft_tpg, se_tpg);
213 
214  if (ft_parse_wwn(name, &wwpn, 1) < 0)
215  return ERR_PTR(-EINVAL);
216 
217  acl = kzalloc(sizeof(struct ft_node_acl), GFP_KERNEL);
218  if (!acl)
219  return ERR_PTR(-ENOMEM);
220  acl->node_auth.port_name = wwpn;
221 
222  q_depth = 32; /* XXX bogus default - get from tpg? */
224  &acl->se_node_acl, name, q_depth);
225 }
226 
227 static void ft_del_acl(struct se_node_acl *se_acl)
228 {
229  struct se_portal_group *se_tpg = se_acl->se_tpg;
230  struct ft_tpg *tpg;
231  struct ft_node_acl *acl = container_of(se_acl,
232  struct ft_node_acl, se_node_acl);
233 
234  pr_debug("del acl %s\n",
235  config_item_name(&se_acl->acl_group.cg_item));
236 
237  tpg = container_of(se_tpg, struct ft_tpg, se_tpg);
238  pr_debug("del acl %p se_acl %p tpg %p se_tpg %p\n",
239  acl, se_acl, tpg, &tpg->se_tpg);
240 
241  core_tpg_del_initiator_node_acl(&tpg->se_tpg, se_acl, 1);
242  kfree(acl);
243 }
244 
245 struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata)
246 {
247  struct ft_node_acl *found = NULL;
248  struct ft_node_acl *acl;
249  struct se_portal_group *se_tpg = &tpg->se_tpg;
250  struct se_node_acl *se_acl;
251 
252  spin_lock_irq(&se_tpg->acl_node_lock);
253  list_for_each_entry(se_acl, &se_tpg->acl_node_list, acl_list) {
254  acl = container_of(se_acl, struct ft_node_acl, se_node_acl);
255  pr_debug("acl %p port_name %llx\n",
256  acl, (unsigned long long)acl->node_auth.port_name);
257  if (acl->node_auth.port_name == rdata->ids.port_name ||
258  acl->node_auth.node_name == rdata->ids.node_name) {
259  pr_debug("acl %p port_name %llx matched\n", acl,
260  (unsigned long long)rdata->ids.port_name);
261  found = acl;
262  /* XXX need to hold onto ACL */
263  break;
264  }
265  }
266  spin_unlock_irq(&se_tpg->acl_node_lock);
267  return found;
268 }
269 
271 {
272  struct ft_node_acl *acl;
273 
274  acl = kzalloc(sizeof(*acl), GFP_KERNEL);
275  if (!acl) {
276  pr_err("Unable to allocate struct ft_node_acl\n");
277  return NULL;
278  }
279  pr_debug("acl %p\n", acl);
280  return &acl->se_node_acl;
281 }
282 
283 static void ft_tpg_release_fabric_acl(struct se_portal_group *se_tpg,
284  struct se_node_acl *se_acl)
285 {
286  struct ft_node_acl *acl = container_of(se_acl,
287  struct ft_node_acl, se_node_acl);
288 
289  pr_debug("acl %p\n", acl);
290  kfree(acl);
291 }
292 
293 /*
294  * local_port port_group (tpg) ops.
295  */
296 static struct se_portal_group *ft_add_tpg(
297  struct se_wwn *wwn,
298  struct config_group *group,
299  const char *name)
300 {
301  struct ft_lport_acl *lacl;
302  struct ft_tpg *tpg;
303  struct workqueue_struct *wq;
304  unsigned long index;
305  int ret;
306 
307  pr_debug("tcm_fc: add tpg %s\n", name);
308 
309  /*
310  * Name must be "tpgt_" followed by the index.
311  */
312  if (strstr(name, "tpgt_") != name)
313  return NULL;
314  if (strict_strtoul(name + 5, 10, &index) || index > UINT_MAX)
315  return NULL;
316 
317  lacl = container_of(wwn, struct ft_lport_acl, fc_lport_wwn);
318  tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
319  if (!tpg)
320  return NULL;
321  tpg->index = index;
322  tpg->lport_acl = lacl;
323  INIT_LIST_HEAD(&tpg->lun_list);
324 
325  wq = alloc_workqueue("tcm_fc", 0, 1);
326  if (!wq) {
327  kfree(tpg);
328  return NULL;
329  }
330 
331  ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg,
333  if (ret < 0) {
334  destroy_workqueue(wq);
335  kfree(tpg);
336  return NULL;
337  }
338  tpg->workqueue = wq;
339 
340  mutex_lock(&ft_lport_lock);
341  list_add_tail(&tpg->list, &lacl->tpg_list);
342  mutex_unlock(&ft_lport_lock);
343 
344  return &tpg->se_tpg;
345 }
346 
347 static void ft_del_tpg(struct se_portal_group *se_tpg)
348 {
349  struct ft_tpg *tpg = container_of(se_tpg, struct ft_tpg, se_tpg);
350 
351  pr_debug("del tpg %s\n",
352  config_item_name(&tpg->se_tpg.tpg_group.cg_item));
353 
355 
356  /* Wait for sessions to be freed thru RCU, for BUG_ON below */
357  synchronize_rcu();
358 
359  mutex_lock(&ft_lport_lock);
360  list_del(&tpg->list);
361  if (tpg->tport) {
362  tpg->tport->tpg = NULL;
363  tpg->tport = NULL;
364  }
365  mutex_unlock(&ft_lport_lock);
366 
367  core_tpg_deregister(se_tpg);
368  kfree(tpg);
369 }
370 
371 /*
372  * Verify that an lport is configured to use the tcm_fc module, and return
373  * the target port group that should be used.
374  *
375  * The caller holds ft_lport_lock.
376  */
378 {
379  struct ft_lport_acl *lacl;
380  struct ft_tpg *tpg;
381 
383  if (lacl->wwpn == lport->wwpn) {
384  list_for_each_entry(tpg, &lacl->tpg_list, list)
385  return tpg; /* XXX for now return first entry */
386  return NULL;
387  }
388  }
389  return NULL;
390 }
391 
392 /*
393  * target config instance ops.
394  */
395 
396 /*
397  * Add lport to allowed config.
398  * The name is the WWPN in lower-case ASCII, colon-separated bytes.
399  */
400 static struct se_wwn *ft_add_lport(
401  struct target_fabric_configfs *tf,
402  struct config_group *group,
403  const char *name)
404 {
405  struct ft_lport_acl *lacl;
406  struct ft_lport_acl *old_lacl;
407  u64 wwpn;
408 
409  pr_debug("add lport %s\n", name);
410  if (ft_parse_wwn(name, &wwpn, 1) < 0)
411  return NULL;
412  lacl = kzalloc(sizeof(*lacl), GFP_KERNEL);
413  if (!lacl)
414  return NULL;
415  lacl->wwpn = wwpn;
416  INIT_LIST_HEAD(&lacl->tpg_list);
417 
418  mutex_lock(&ft_lport_lock);
419  list_for_each_entry(old_lacl, &ft_lport_list, list) {
420  if (old_lacl->wwpn == wwpn) {
421  mutex_unlock(&ft_lport_lock);
422  kfree(lacl);
423  return NULL;
424  }
425  }
426  list_add_tail(&lacl->list, &ft_lport_list);
427  ft_format_wwn(lacl->name, sizeof(lacl->name), wwpn);
428  mutex_unlock(&ft_lport_lock);
429 
430  return &lacl->fc_lport_wwn;
431 }
432 
433 static void ft_del_lport(struct se_wwn *wwn)
434 {
435  struct ft_lport_acl *lacl = container_of(wwn,
436  struct ft_lport_acl, fc_lport_wwn);
437 
438  pr_debug("del lport %s\n", lacl->name);
439  mutex_lock(&ft_lport_lock);
440  list_del(&lacl->list);
441  mutex_unlock(&ft_lport_lock);
442 
443  kfree(lacl);
444 }
445 
446 static ssize_t ft_wwn_show_attr_version(
447  struct target_fabric_configfs *tf,
448  char *page)
449 {
450  return sprintf(page, "TCM FC " FT_VERSION " on %s/%s on "
451  ""UTS_RELEASE"\n", utsname()->sysname, utsname()->machine);
452 }
453 
455 
456 static struct configfs_attribute *ft_wwn_attrs[] = {
457  &ft_wwn_version.attr,
458  NULL,
459 };
460 
461 static char *ft_get_fabric_name(void)
462 {
463  return "fc";
464 }
465 
466 static char *ft_get_fabric_wwn(struct se_portal_group *se_tpg)
467 {
468  struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr;
469 
470  return tpg->lport_acl->name;
471 }
472 
473 static u16 ft_get_tag(struct se_portal_group *se_tpg)
474 {
475  struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr;
476 
477  /*
478  * This tag is used when forming SCSI Name identifier in EVPD=1 0x83
479  * to represent the SCSI Target Port.
480  */
481  return tpg->index;
482 }
483 
484 static u32 ft_get_default_depth(struct se_portal_group *se_tpg)
485 {
486  return 1;
487 }
488 
489 static int ft_check_false(struct se_portal_group *se_tpg)
490 {
491  return 0;
492 }
493 
494 static void ft_set_default_node_attr(struct se_node_acl *se_nacl)
495 {
496 }
497 
498 static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg)
499 {
500  struct ft_tpg *tpg = se_tpg->se_tpg_fabric_ptr;
501 
502  return tpg->index;
503 }
504 
505 static struct target_core_fabric_ops ft_fabric_ops = {
506  .get_fabric_name = ft_get_fabric_name,
507  .get_fabric_proto_ident = fc_get_fabric_proto_ident,
508  .tpg_get_wwn = ft_get_fabric_wwn,
509  .tpg_get_tag = ft_get_tag,
510  .tpg_get_default_depth = ft_get_default_depth,
511  .tpg_get_pr_transport_id = fc_get_pr_transport_id,
512  .tpg_get_pr_transport_id_len = fc_get_pr_transport_id_len,
513  .tpg_parse_pr_out_transport_id = fc_parse_pr_out_transport_id,
514  .tpg_check_demo_mode = ft_check_false,
515  .tpg_check_demo_mode_cache = ft_check_false,
516  .tpg_check_demo_mode_write_protect = ft_check_false,
517  .tpg_check_prod_mode_write_protect = ft_check_false,
518  .tpg_alloc_fabric_acl = ft_tpg_alloc_fabric_acl,
519  .tpg_release_fabric_acl = ft_tpg_release_fabric_acl,
520  .tpg_get_inst_index = ft_tpg_get_inst_index,
521  .check_stop_free = ft_check_stop_free,
522  .release_cmd = ft_release_cmd,
523  .shutdown_session = ft_sess_shutdown,
524  .close_session = ft_sess_close,
525  .sess_get_index = ft_sess_get_index,
526  .sess_get_initiator_sid = NULL,
527  .write_pending = ft_write_pending,
528  .write_pending_status = ft_write_pending_status,
529  .set_default_node_attributes = ft_set_default_node_attr,
530  .get_task_tag = ft_get_task_tag,
531  .get_cmd_state = ft_get_cmd_state,
532  .queue_data_in = ft_queue_data_in,
533  .queue_status = ft_queue_status,
534  .queue_tm_rsp = ft_queue_tm_resp,
535  /*
536  * Setup function pointers for generic logic in
537  * target_core_fabric_configfs.c
538  */
539  .fabric_make_wwn = &ft_add_lport,
540  .fabric_drop_wwn = &ft_del_lport,
541  .fabric_make_tpg = &ft_add_tpg,
542  .fabric_drop_tpg = &ft_del_tpg,
543  .fabric_post_link = NULL,
544  .fabric_pre_unlink = NULL,
545  .fabric_make_np = NULL,
546  .fabric_drop_np = NULL,
547  .fabric_make_nodeacl = &ft_add_acl,
548  .fabric_drop_nodeacl = &ft_del_acl,
549 };
550 
552 {
553  struct target_fabric_configfs *fabric;
554  int ret;
555 
556  /*
557  * Register the top level struct config_item_type with TCM core
558  */
560  if (IS_ERR(fabric)) {
561  pr_err("%s: target_fabric_configfs_init() failed!\n",
562  __func__);
563  return PTR_ERR(fabric);
564  }
565  fabric->tf_ops = ft_fabric_ops;
566 
567  /*
568  * Setup default attribute lists for various fabric->tf_cit_tmpl
569  */
570  TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = ft_wwn_attrs;
571  TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = NULL;
572  TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
573  TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
574  TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
575  TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs =
576  ft_nacl_base_attrs;
577  TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
578  TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
579  TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
580  /*
581  * register the fabric for use within TCM
582  */
583  ret = target_fabric_configfs_register(fabric);
584  if (ret < 0) {
585  pr_debug("target_fabric_configfs_register() for"
586  " FC Target failed!\n");
588  return -1;
589  }
590 
591  /*
592  * Setup our local pointer to *fabric.
593  */
594  ft_configfs = fabric;
595  return 0;
596 }
597 
599 {
600  if (!ft_configfs)
601  return;
603  ft_configfs = NULL;
604 }
605 
606 static struct notifier_block ft_notifier = {
607  .notifier_call = ft_lport_notify
608 };
609 
610 static int __init ft_init(void)
611 {
612  if (ft_register_configfs())
613  return -1;
616  return -1;
617  }
620  return 0;
621 }
622 
623 static void __exit ft_exit(void)
624 {
626  &ft_notifier);
630  synchronize_rcu();
631 }
632 
633 MODULE_DESCRIPTION("FC TCM fabric driver " FT_VERSION);
634 MODULE_LICENSE("GPL");
635 module_init(ft_init);
636 module_exit(ft_exit);