]>
Commit | Line | Data |
---|---|---|
c66ac9db NB |
1 | /******************************************************************************* |
2 | * Filename: target_core_fabric_configfs.c | |
3 | * | |
4 | * This file contains generic fabric module configfs infrastructure for | |
5 | * TCM v4.x code | |
6 | * | |
4c76251e | 7 | * (c) Copyright 2010-2013 Datera, Inc. |
c66ac9db | 8 | * |
fd9a11d7 | 9 | * Nicholas A. Bellinger <nab@linux-iscsi.org> |
c66ac9db NB |
10 | * |
11 | * This program is free software; you can redistribute it and/or modify | |
12 | * it under the terms of the GNU General Public License as published by | |
13 | * the Free Software Foundation; either version 2 of the License, or | |
14 | * (at your option) any later version. | |
15 | * | |
16 | * This program is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | * GNU General Public License for more details. | |
20 | ****************************************************************************/ | |
21 | ||
22 | #include <linux/module.h> | |
23 | #include <linux/moduleparam.h> | |
c66ac9db NB |
24 | #include <linux/utsname.h> |
25 | #include <linux/init.h> | |
26 | #include <linux/fs.h> | |
27 | #include <linux/namei.h> | |
28 | #include <linux/slab.h> | |
29 | #include <linux/types.h> | |
30 | #include <linux/delay.h> | |
31 | #include <linux/unistd.h> | |
32 | #include <linux/string.h> | |
33 | #include <linux/syscalls.h> | |
34 | #include <linux/configfs.h> | |
35 | ||
36 | #include <target/target_core_base.h> | |
c4795fb2 | 37 | #include <target/target_core_fabric.h> |
c66ac9db | 38 | |
e26d99ae | 39 | #include "target_core_internal.h" |
c66ac9db | 40 | #include "target_core_alua.h" |
c66ac9db NB |
41 | #include "target_core_pr.h" |
42 | ||
43 | #define TF_CIT_SETUP(_name, _item_ops, _group_ops, _attrs) \ | |
44 | static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ | |
45 | { \ | |
968ebe75 | 46 | struct config_item_type *cit = &tf->tf_##_name##_cit; \ |
c66ac9db NB |
47 | \ |
48 | cit->ct_item_ops = _item_ops; \ | |
49 | cit->ct_group_ops = _group_ops; \ | |
50 | cit->ct_attrs = _attrs; \ | |
0dc2e8d1 | 51 | cit->ct_owner = tf->tf_ops->module; \ |
6708bb27 | 52 | pr_debug("Setup generic %s\n", __stringify(_name)); \ |
c66ac9db NB |
53 | } |
54 | ||
9ac8928e CH |
55 | #define TF_CIT_SETUP_DRV(_name, _item_ops, _group_ops) \ |
56 | static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ | |
57 | { \ | |
968ebe75 | 58 | struct config_item_type *cit = &tf->tf_##_name##_cit; \ |
ef0caf8d | 59 | struct configfs_attribute **attrs = tf->tf_ops->tfc_##_name##_attrs; \ |
9ac8928e CH |
60 | \ |
61 | cit->ct_item_ops = _item_ops; \ | |
62 | cit->ct_group_ops = _group_ops; \ | |
63 | cit->ct_attrs = attrs; \ | |
0dc2e8d1 | 64 | cit->ct_owner = tf->tf_ops->module; \ |
9ac8928e CH |
65 | pr_debug("Setup generic %s\n", __stringify(_name)); \ |
66 | } | |
67 | ||
c66ac9db NB |
68 | /* Start of tfc_tpg_mappedlun_cit */ |
69 | ||
70 | static int target_fabric_mappedlun_link( | |
71 | struct config_item *lun_acl_ci, | |
72 | struct config_item *lun_ci) | |
73 | { | |
74 | struct se_dev_entry *deve; | |
75 | struct se_lun *lun = container_of(to_config_group(lun_ci), | |
76 | struct se_lun, lun_group); | |
77 | struct se_lun_acl *lacl = container_of(to_config_group(lun_acl_ci), | |
78 | struct se_lun_acl, se_lun_group); | |
79 | struct se_portal_group *se_tpg; | |
80 | struct config_item *nacl_ci, *tpg_ci, *tpg_ci_s, *wwn_ci, *wwn_ci_s; | |
03a68b44 | 81 | bool lun_access_ro; |
0ff87549 NB |
82 | |
83 | if (lun->lun_link_magic != SE_LUN_LINK_MAGIC) { | |
84 | pr_err("Bad lun->lun_link_magic, not a valid lun_ci pointer:" | |
85 | " %p to struct lun: %p\n", lun_ci, lun); | |
86 | return -EFAULT; | |
87 | } | |
c66ac9db NB |
88 | /* |
89 | * Ensure that the source port exists | |
90 | */ | |
adf653f9 CH |
91 | if (!lun->lun_se_dev) { |
92 | pr_err("Source se_lun->lun_se_dev does not exist\n"); | |
c66ac9db NB |
93 | return -EINVAL; |
94 | } | |
6630f11d NB |
95 | if (lun->lun_shutdown) { |
96 | pr_err("Unable to create mappedlun symlink because" | |
97 | " lun->lun_shutdown=true\n"); | |
98 | return -EINVAL; | |
99 | } | |
adf653f9 | 100 | se_tpg = lun->lun_tpg; |
c66ac9db NB |
101 | |
102 | nacl_ci = &lun_acl_ci->ci_parent->ci_group->cg_item; | |
103 | tpg_ci = &nacl_ci->ci_group->cg_item; | |
104 | wwn_ci = &tpg_ci->ci_group->cg_item; | |
105 | tpg_ci_s = &lun_ci->ci_parent->ci_group->cg_item; | |
106 | wwn_ci_s = &tpg_ci_s->ci_group->cg_item; | |
107 | /* | |
108 | * Make sure the SymLink is going to the same $FABRIC/$WWN/tpgt_$TPGT | |
109 | */ | |
110 | if (strcmp(config_item_name(wwn_ci), config_item_name(wwn_ci_s))) { | |
6708bb27 | 111 | pr_err("Illegal Initiator ACL SymLink outside of %s\n", |
c66ac9db NB |
112 | config_item_name(wwn_ci)); |
113 | return -EINVAL; | |
114 | } | |
115 | if (strcmp(config_item_name(tpg_ci), config_item_name(tpg_ci_s))) { | |
6708bb27 | 116 | pr_err("Illegal Initiator ACL Symlink outside of %s" |
c66ac9db NB |
117 | " TPGT: %s\n", config_item_name(wwn_ci), |
118 | config_item_name(tpg_ci)); | |
119 | return -EINVAL; | |
120 | } | |
121 | /* | |
122 | * If this struct se_node_acl was dynamically generated with | |
03a68b44 AG |
123 | * tpg_1/attrib/generate_node_acls=1, use the existing |
124 | * deve->lun_access_ro value, which will be true when | |
c66ac9db NB |
125 | * tpg_1/attrib/demo_mode_write_protect=1 |
126 | */ | |
29a05dee NB |
127 | rcu_read_lock(); |
128 | deve = target_nacl_find_deve(lacl->se_lun_nacl, lacl->mapped_lun); | |
129 | if (deve) | |
03a68b44 | 130 | lun_access_ro = deve->lun_access_ro; |
c66ac9db | 131 | else |
03a68b44 | 132 | lun_access_ro = |
e3d6f909 | 133 | (se_tpg->se_tpg_tfo->tpg_check_prod_mode_write_protect( |
03a68b44 | 134 | se_tpg)) ? true : false; |
29a05dee | 135 | rcu_read_unlock(); |
c66ac9db NB |
136 | /* |
137 | * Determine the actual mapped LUN value user wants.. | |
138 | * | |
139 | * This value is what the SCSI Initiator actually sees the | |
6bb82612 | 140 | * $FABRIC/$WWPN/$TPGT/lun/lun_* as on their SCSI Initiator Ports. |
c66ac9db | 141 | */ |
03a68b44 | 142 | return core_dev_add_initiator_node_lun_acl(se_tpg, lacl, lun, lun_access_ro); |
c66ac9db NB |
143 | } |
144 | ||
e16769d4 | 145 | static void target_fabric_mappedlun_unlink( |
c66ac9db NB |
146 | struct config_item *lun_acl_ci, |
147 | struct config_item *lun_ci) | |
148 | { | |
c66ac9db NB |
149 | struct se_lun_acl *lacl = container_of(to_config_group(lun_acl_ci), |
150 | struct se_lun_acl, se_lun_group); | |
29a05dee NB |
151 | struct se_lun *lun = container_of(to_config_group(lun_ci), |
152 | struct se_lun, lun_group); | |
c66ac9db | 153 | |
e16769d4 | 154 | core_dev_del_initiator_node_lun_acl(lun, lacl); |
c66ac9db NB |
155 | } |
156 | ||
2eafd729 CH |
157 | static struct se_lun_acl *item_to_lun_acl(struct config_item *item) |
158 | { | |
159 | return container_of(to_config_group(item), struct se_lun_acl, | |
160 | se_lun_group); | |
161 | } | |
c66ac9db | 162 | |
2eafd729 CH |
163 | static ssize_t target_fabric_mappedlun_write_protect_show( |
164 | struct config_item *item, char *page) | |
c66ac9db | 165 | { |
2eafd729 | 166 | struct se_lun_acl *lacl = item_to_lun_acl(item); |
c66ac9db NB |
167 | struct se_node_acl *se_nacl = lacl->se_lun_nacl; |
168 | struct se_dev_entry *deve; | |
29a05dee NB |
169 | ssize_t len = 0; |
170 | ||
171 | rcu_read_lock(); | |
172 | deve = target_nacl_find_deve(se_nacl, lacl->mapped_lun); | |
173 | if (deve) { | |
03a68b44 | 174 | len = sprintf(page, "%d\n", deve->lun_access_ro); |
29a05dee NB |
175 | } |
176 | rcu_read_unlock(); | |
c66ac9db NB |
177 | |
178 | return len; | |
179 | } | |
180 | ||
2eafd729 CH |
181 | static ssize_t target_fabric_mappedlun_write_protect_store( |
182 | struct config_item *item, const char *page, size_t count) | |
c66ac9db | 183 | { |
2eafd729 | 184 | struct se_lun_acl *lacl = item_to_lun_acl(item); |
c66ac9db NB |
185 | struct se_node_acl *se_nacl = lacl->se_lun_nacl; |
186 | struct se_portal_group *se_tpg = se_nacl->se_tpg; | |
03a68b44 | 187 | unsigned long wp; |
57103d7f | 188 | int ret; |
c66ac9db | 189 | |
03a68b44 | 190 | ret = kstrtoul(page, 0, &wp); |
57103d7f JH |
191 | if (ret) |
192 | return ret; | |
c66ac9db | 193 | |
03a68b44 | 194 | if ((wp != 1) && (wp != 0)) |
c66ac9db NB |
195 | return -EINVAL; |
196 | ||
03a68b44 AG |
197 | /* wp=1 means lun_access_ro=true */ |
198 | core_update_device_list_access(lacl->mapped_lun, wp, lacl->se_lun_nacl); | |
c66ac9db | 199 | |
6708bb27 | 200 | pr_debug("%s_ConfigFS: Changed Initiator ACL: %s" |
f2d30680 | 201 | " Mapped LUN: %llu Write Protect bit to %s\n", |
e3d6f909 | 202 | se_tpg->se_tpg_tfo->get_fabric_name(), |
03a68b44 | 203 | se_nacl->initiatorname, lacl->mapped_lun, (wp) ? "ON" : "OFF"); |
c66ac9db NB |
204 | |
205 | return count; | |
206 | ||
207 | } | |
208 | ||
2eafd729 | 209 | CONFIGFS_ATTR(target_fabric_mappedlun_, write_protect); |
c66ac9db | 210 | |
2eafd729 CH |
211 | static struct configfs_attribute *target_fabric_mappedlun_attrs[] = { |
212 | &target_fabric_mappedlun_attr_write_protect, | |
213 | NULL, | |
214 | }; | |
c66ac9db | 215 | |
1f6fe7cb NB |
216 | static void target_fabric_mappedlun_release(struct config_item *item) |
217 | { | |
218 | struct se_lun_acl *lacl = container_of(to_config_group(item), | |
219 | struct se_lun_acl, se_lun_group); | |
220 | struct se_portal_group *se_tpg = lacl->se_lun_nacl->se_tpg; | |
221 | ||
222 | core_dev_free_initiator_node_lun_acl(se_tpg, lacl); | |
223 | } | |
224 | ||
c66ac9db | 225 | static struct configfs_item_operations target_fabric_mappedlun_item_ops = { |
1f6fe7cb | 226 | .release = target_fabric_mappedlun_release, |
c66ac9db NB |
227 | .allow_link = target_fabric_mappedlun_link, |
228 | .drop_link = target_fabric_mappedlun_unlink, | |
229 | }; | |
230 | ||
231 | TF_CIT_SETUP(tpg_mappedlun, &target_fabric_mappedlun_item_ops, NULL, | |
232 | target_fabric_mappedlun_attrs); | |
233 | ||
234 | /* End of tfc_tpg_mappedlun_cit */ | |
235 | ||
12d23384 NB |
236 | /* Start of tfc_tpg_mappedlun_port_cit */ |
237 | ||
238 | static struct config_group *target_core_mappedlun_stat_mkdir( | |
239 | struct config_group *group, | |
240 | const char *name) | |
241 | { | |
242 | return ERR_PTR(-ENOSYS); | |
243 | } | |
244 | ||
245 | static void target_core_mappedlun_stat_rmdir( | |
246 | struct config_group *group, | |
247 | struct config_item *item) | |
248 | { | |
249 | return; | |
250 | } | |
251 | ||
252 | static struct configfs_group_operations target_fabric_mappedlun_stat_group_ops = { | |
253 | .make_group = target_core_mappedlun_stat_mkdir, | |
254 | .drop_item = target_core_mappedlun_stat_rmdir, | |
255 | }; | |
256 | ||
257 | TF_CIT_SETUP(tpg_mappedlun_stat, NULL, &target_fabric_mappedlun_stat_group_ops, | |
258 | NULL); | |
259 | ||
260 | /* End of tfc_tpg_mappedlun_port_cit */ | |
261 | ||
2eafd729 CH |
262 | TF_CIT_SETUP_DRV(tpg_nacl_attrib, NULL, NULL); |
263 | TF_CIT_SETUP_DRV(tpg_nacl_auth, NULL, NULL); | |
264 | TF_CIT_SETUP_DRV(tpg_nacl_param, NULL, NULL); | |
c66ac9db NB |
265 | |
266 | /* Start of tfc_tpg_nacl_base_cit */ | |
267 | ||
c66ac9db NB |
268 | static struct config_group *target_fabric_make_mappedlun( |
269 | struct config_group *group, | |
270 | const char *name) | |
271 | { | |
272 | struct se_node_acl *se_nacl = container_of(group, | |
273 | struct se_node_acl, acl_group); | |
274 | struct se_portal_group *se_tpg = se_nacl->se_tpg; | |
275 | struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; | |
da0abaee | 276 | struct se_lun_acl *lacl = NULL; |
c66ac9db | 277 | char *buf; |
f2d30680 | 278 | unsigned long long mapped_lun; |
c66ac9db NB |
279 | int ret = 0; |
280 | ||
c66ac9db | 281 | buf = kzalloc(strlen(name) + 1, GFP_KERNEL); |
6708bb27 AG |
282 | if (!buf) { |
283 | pr_err("Unable to allocate memory for name buf\n"); | |
c66ac9db NB |
284 | return ERR_PTR(-ENOMEM); |
285 | } | |
286 | snprintf(buf, strlen(name) + 1, "%s", name); | |
287 | /* | |
288 | * Make sure user is creating iscsi/$IQN/$TPGT/acls/$INITIATOR/lun_$ID. | |
289 | */ | |
290 | if (strstr(buf, "lun_") != buf) { | |
6708bb27 | 291 | pr_err("Unable to locate \"lun_\" from buf: %s" |
c66ac9db NB |
292 | " name: %s\n", buf, name); |
293 | ret = -EINVAL; | |
294 | goto out; | |
295 | } | |
296 | /* | |
297 | * Determine the Mapped LUN value. This is what the SCSI Initiator | |
298 | * Port will actually see. | |
299 | */ | |
f2d30680 | 300 | ret = kstrtoull(buf + 4, 0, &mapped_lun); |
57103d7f JH |
301 | if (ret) |
302 | goto out; | |
c66ac9db | 303 | |
fcf29481 NB |
304 | lacl = core_dev_init_initiator_node_lun_acl(se_tpg, se_nacl, |
305 | mapped_lun, &ret); | |
6708bb27 | 306 | if (!lacl) { |
12d23384 | 307 | ret = -EINVAL; |
c66ac9db | 308 | goto out; |
12d23384 NB |
309 | } |
310 | ||
c66ac9db | 311 | config_group_init_type_name(&lacl->se_lun_group, name, |
968ebe75 | 312 | &tf->tf_tpg_mappedlun_cit); |
1ae1602d | 313 | |
12d23384 | 314 | config_group_init_type_name(&lacl->ml_stat_grps.stat_group, |
968ebe75 | 315 | "statistics", &tf->tf_tpg_mappedlun_stat_cit); |
1ae1602d CH |
316 | configfs_add_default_group(&lacl->ml_stat_grps.stat_group, |
317 | &lacl->se_lun_group); | |
318 | ||
12d23384 | 319 | target_stat_setup_mappedlun_default_groups(lacl); |
c66ac9db NB |
320 | |
321 | kfree(buf); | |
322 | return &lacl->se_lun_group; | |
323 | out: | |
da0abaee | 324 | kfree(lacl); |
c66ac9db NB |
325 | kfree(buf); |
326 | return ERR_PTR(ret); | |
327 | } | |
328 | ||
329 | static void target_fabric_drop_mappedlun( | |
330 | struct config_group *group, | |
331 | struct config_item *item) | |
332 | { | |
12d23384 NB |
333 | struct se_lun_acl *lacl = container_of(to_config_group(item), |
334 | struct se_lun_acl, se_lun_group); | |
12d23384 | 335 | |
1ae1602d CH |
336 | configfs_remove_default_groups(&lacl->ml_stat_grps.stat_group); |
337 | configfs_remove_default_groups(&lacl->se_lun_group); | |
12d23384 | 338 | |
c66ac9db | 339 | config_item_put(item); |
1f6fe7cb NB |
340 | } |
341 | ||
342 | static void target_fabric_nacl_base_release(struct config_item *item) | |
343 | { | |
344 | struct se_node_acl *se_nacl = container_of(to_config_group(item), | |
345 | struct se_node_acl, acl_group); | |
1f6fe7cb | 346 | |
ce7043fd | 347 | configfs_remove_default_groups(&se_nacl->acl_fabric_stat_group); |
c7d6a803 | 348 | core_tpg_del_initiator_node_acl(se_nacl); |
c66ac9db NB |
349 | } |
350 | ||
351 | static struct configfs_item_operations target_fabric_nacl_base_item_ops = { | |
1f6fe7cb | 352 | .release = target_fabric_nacl_base_release, |
c66ac9db NB |
353 | }; |
354 | ||
355 | static struct configfs_group_operations target_fabric_nacl_base_group_ops = { | |
356 | .make_group = target_fabric_make_mappedlun, | |
357 | .drop_item = target_fabric_drop_mappedlun, | |
358 | }; | |
359 | ||
9ac8928e CH |
360 | TF_CIT_SETUP_DRV(tpg_nacl_base, &target_fabric_nacl_base_item_ops, |
361 | &target_fabric_nacl_base_group_ops); | |
c66ac9db NB |
362 | |
363 | /* End of tfc_tpg_nacl_base_cit */ | |
364 | ||
12d23384 NB |
365 | /* Start of tfc_node_fabric_stats_cit */ |
366 | /* | |
367 | * This is used as a placeholder for struct se_node_acl->acl_fabric_stat_group | |
368 | * to allow fabrics access to ->acl_fabric_stat_group->default_groups[] | |
369 | */ | |
370 | TF_CIT_SETUP(tpg_nacl_stat, NULL, NULL, NULL); | |
371 | ||
372 | /* End of tfc_wwn_fabric_stats_cit */ | |
373 | ||
c66ac9db NB |
374 | /* Start of tfc_tpg_nacl_cit */ |
375 | ||
376 | static struct config_group *target_fabric_make_nodeacl( | |
377 | struct config_group *group, | |
378 | const char *name) | |
379 | { | |
380 | struct se_portal_group *se_tpg = container_of(group, | |
381 | struct se_portal_group, tpg_acl_group); | |
382 | struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; | |
383 | struct se_node_acl *se_nacl; | |
c66ac9db | 384 | |
c7d6a803 | 385 | se_nacl = core_tpg_add_initiator_node_acl(se_tpg, name); |
c66ac9db | 386 | if (IS_ERR(se_nacl)) |
e1750ba2 | 387 | return ERR_CAST(se_nacl); |
c66ac9db | 388 | |
c66ac9db | 389 | config_group_init_type_name(&se_nacl->acl_group, name, |
968ebe75 | 390 | &tf->tf_tpg_nacl_base_cit); |
1ae1602d | 391 | |
c66ac9db | 392 | config_group_init_type_name(&se_nacl->acl_attrib_group, "attrib", |
968ebe75 | 393 | &tf->tf_tpg_nacl_attrib_cit); |
1ae1602d CH |
394 | configfs_add_default_group(&se_nacl->acl_attrib_group, |
395 | &se_nacl->acl_group); | |
396 | ||
c66ac9db | 397 | config_group_init_type_name(&se_nacl->acl_auth_group, "auth", |
968ebe75 | 398 | &tf->tf_tpg_nacl_auth_cit); |
1ae1602d CH |
399 | configfs_add_default_group(&se_nacl->acl_auth_group, |
400 | &se_nacl->acl_group); | |
401 | ||
c66ac9db | 402 | config_group_init_type_name(&se_nacl->acl_param_group, "param", |
968ebe75 | 403 | &tf->tf_tpg_nacl_param_cit); |
1ae1602d CH |
404 | configfs_add_default_group(&se_nacl->acl_param_group, |
405 | &se_nacl->acl_group); | |
406 | ||
12d23384 | 407 | config_group_init_type_name(&se_nacl->acl_fabric_stat_group, |
968ebe75 | 408 | "fabric_statistics", &tf->tf_tpg_nacl_stat_cit); |
1ae1602d CH |
409 | configfs_add_default_group(&se_nacl->acl_fabric_stat_group, |
410 | &se_nacl->acl_group); | |
c66ac9db | 411 | |
e6e202ed CH |
412 | if (tf->tf_ops->fabric_init_nodeacl) { |
413 | int ret = tf->tf_ops->fabric_init_nodeacl(se_nacl, name); | |
414 | if (ret) { | |
415 | configfs_remove_default_groups(&se_nacl->acl_fabric_stat_group); | |
416 | core_tpg_del_initiator_node_acl(se_nacl); | |
417 | return ERR_PTR(ret); | |
418 | } | |
419 | } | |
420 | ||
c66ac9db NB |
421 | return &se_nacl->acl_group; |
422 | } | |
423 | ||
424 | static void target_fabric_drop_nodeacl( | |
425 | struct config_group *group, | |
426 | struct config_item *item) | |
427 | { | |
c66ac9db NB |
428 | struct se_node_acl *se_nacl = container_of(to_config_group(item), |
429 | struct se_node_acl, acl_group); | |
1ae1602d CH |
430 | |
431 | configfs_remove_default_groups(&se_nacl->acl_group); | |
432 | ||
1f6fe7cb NB |
433 | /* |
434 | * struct se_node_acl free is done in target_fabric_nacl_base_release() | |
435 | */ | |
c66ac9db | 436 | config_item_put(item); |
c66ac9db NB |
437 | } |
438 | ||
439 | static struct configfs_group_operations target_fabric_nacl_group_ops = { | |
440 | .make_group = target_fabric_make_nodeacl, | |
441 | .drop_item = target_fabric_drop_nodeacl, | |
442 | }; | |
443 | ||
444 | TF_CIT_SETUP(tpg_nacl, NULL, &target_fabric_nacl_group_ops, NULL); | |
445 | ||
446 | /* End of tfc_tpg_nacl_cit */ | |
447 | ||
448 | /* Start of tfc_tpg_np_base_cit */ | |
449 | ||
1f6fe7cb NB |
450 | static void target_fabric_np_base_release(struct config_item *item) |
451 | { | |
452 | struct se_tpg_np *se_tpg_np = container_of(to_config_group(item), | |
453 | struct se_tpg_np, tpg_np_group); | |
454 | struct se_portal_group *se_tpg = se_tpg_np->tpg_np_parent; | |
455 | struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; | |
456 | ||
ef0caf8d | 457 | tf->tf_ops->fabric_drop_np(se_tpg_np); |
1f6fe7cb NB |
458 | } |
459 | ||
c66ac9db | 460 | static struct configfs_item_operations target_fabric_np_base_item_ops = { |
1f6fe7cb | 461 | .release = target_fabric_np_base_release, |
c66ac9db NB |
462 | }; |
463 | ||
9ac8928e | 464 | TF_CIT_SETUP_DRV(tpg_np_base, &target_fabric_np_base_item_ops, NULL); |
c66ac9db NB |
465 | |
466 | /* End of tfc_tpg_np_base_cit */ | |
467 | ||
468 | /* Start of tfc_tpg_np_cit */ | |
469 | ||
470 | static struct config_group *target_fabric_make_np( | |
471 | struct config_group *group, | |
472 | const char *name) | |
473 | { | |
474 | struct se_portal_group *se_tpg = container_of(group, | |
475 | struct se_portal_group, tpg_np_group); | |
476 | struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; | |
477 | struct se_tpg_np *se_tpg_np; | |
478 | ||
ef0caf8d | 479 | if (!tf->tf_ops->fabric_make_np) { |
6708bb27 | 480 | pr_err("tf->tf_ops.fabric_make_np is NULL\n"); |
c66ac9db NB |
481 | return ERR_PTR(-ENOSYS); |
482 | } | |
483 | ||
ef0caf8d | 484 | se_tpg_np = tf->tf_ops->fabric_make_np(se_tpg, group, name); |
6708bb27 | 485 | if (!se_tpg_np || IS_ERR(se_tpg_np)) |
c66ac9db NB |
486 | return ERR_PTR(-EINVAL); |
487 | ||
1f6fe7cb | 488 | se_tpg_np->tpg_np_parent = se_tpg; |
c66ac9db | 489 | config_group_init_type_name(&se_tpg_np->tpg_np_group, name, |
968ebe75 | 490 | &tf->tf_tpg_np_base_cit); |
c66ac9db NB |
491 | |
492 | return &se_tpg_np->tpg_np_group; | |
493 | } | |
494 | ||
495 | static void target_fabric_drop_np( | |
496 | struct config_group *group, | |
497 | struct config_item *item) | |
498 | { | |
1f6fe7cb NB |
499 | /* |
500 | * struct se_tpg_np is released via target_fabric_np_base_release() | |
501 | */ | |
c66ac9db | 502 | config_item_put(item); |
c66ac9db NB |
503 | } |
504 | ||
505 | static struct configfs_group_operations target_fabric_np_group_ops = { | |
506 | .make_group = &target_fabric_make_np, | |
507 | .drop_item = &target_fabric_drop_np, | |
508 | }; | |
509 | ||
510 | TF_CIT_SETUP(tpg_np, NULL, &target_fabric_np_group_ops, NULL); | |
511 | ||
512 | /* End of tfc_tpg_np_cit */ | |
513 | ||
514 | /* Start of tfc_tpg_port_cit */ | |
515 | ||
2eafd729 CH |
516 | static struct se_lun *item_to_lun(struct config_item *item) |
517 | { | |
518 | return container_of(to_config_group(item), struct se_lun, | |
519 | lun_group); | |
520 | } | |
c66ac9db | 521 | |
2eafd729 CH |
522 | static ssize_t target_fabric_port_alua_tg_pt_gp_show(struct config_item *item, |
523 | char *page) | |
c66ac9db | 524 | { |
2eafd729 CH |
525 | struct se_lun *lun = item_to_lun(item); |
526 | ||
adf653f9 | 527 | if (!lun || !lun->lun_se_dev) |
c66ac9db NB |
528 | return -ENODEV; |
529 | ||
adf653f9 | 530 | return core_alua_show_tg_pt_gp_info(lun, page); |
c66ac9db NB |
531 | } |
532 | ||
2eafd729 CH |
533 | static ssize_t target_fabric_port_alua_tg_pt_gp_store(struct config_item *item, |
534 | const char *page, size_t count) | |
c66ac9db | 535 | { |
2eafd729 CH |
536 | struct se_lun *lun = item_to_lun(item); |
537 | ||
adf653f9 | 538 | if (!lun || !lun->lun_se_dev) |
c66ac9db NB |
539 | return -ENODEV; |
540 | ||
adf653f9 | 541 | return core_alua_store_tg_pt_gp_info(lun, page, count); |
c66ac9db NB |
542 | } |
543 | ||
2eafd729 CH |
544 | static ssize_t target_fabric_port_alua_tg_pt_offline_show( |
545 | struct config_item *item, char *page) | |
c66ac9db | 546 | { |
2eafd729 CH |
547 | struct se_lun *lun = item_to_lun(item); |
548 | ||
adf653f9 | 549 | if (!lun || !lun->lun_se_dev) |
c66ac9db NB |
550 | return -ENODEV; |
551 | ||
552 | return core_alua_show_offline_bit(lun, page); | |
553 | } | |
554 | ||
2eafd729 CH |
555 | static ssize_t target_fabric_port_alua_tg_pt_offline_store( |
556 | struct config_item *item, const char *page, size_t count) | |
c66ac9db | 557 | { |
2eafd729 CH |
558 | struct se_lun *lun = item_to_lun(item); |
559 | ||
adf653f9 | 560 | if (!lun || !lun->lun_se_dev) |
c66ac9db NB |
561 | return -ENODEV; |
562 | ||
563 | return core_alua_store_offline_bit(lun, page, count); | |
564 | } | |
565 | ||
2eafd729 CH |
566 | static ssize_t target_fabric_port_alua_tg_pt_status_show( |
567 | struct config_item *item, char *page) | |
c66ac9db | 568 | { |
2eafd729 CH |
569 | struct se_lun *lun = item_to_lun(item); |
570 | ||
adf653f9 | 571 | if (!lun || !lun->lun_se_dev) |
c66ac9db NB |
572 | return -ENODEV; |
573 | ||
574 | return core_alua_show_secondary_status(lun, page); | |
575 | } | |
576 | ||
2eafd729 CH |
577 | static ssize_t target_fabric_port_alua_tg_pt_status_store( |
578 | struct config_item *item, const char *page, size_t count) | |
c66ac9db | 579 | { |
2eafd729 CH |
580 | struct se_lun *lun = item_to_lun(item); |
581 | ||
adf653f9 | 582 | if (!lun || !lun->lun_se_dev) |
c66ac9db NB |
583 | return -ENODEV; |
584 | ||
585 | return core_alua_store_secondary_status(lun, page, count); | |
586 | } | |
587 | ||
2eafd729 CH |
588 | static ssize_t target_fabric_port_alua_tg_pt_write_md_show( |
589 | struct config_item *item, char *page) | |
c66ac9db | 590 | { |
2eafd729 CH |
591 | struct se_lun *lun = item_to_lun(item); |
592 | ||
adf653f9 | 593 | if (!lun || !lun->lun_se_dev) |
c66ac9db NB |
594 | return -ENODEV; |
595 | ||
596 | return core_alua_show_secondary_write_metadata(lun, page); | |
597 | } | |
598 | ||
2eafd729 CH |
599 | static ssize_t target_fabric_port_alua_tg_pt_write_md_store( |
600 | struct config_item *item, const char *page, size_t count) | |
c66ac9db | 601 | { |
2eafd729 CH |
602 | struct se_lun *lun = item_to_lun(item); |
603 | ||
adf653f9 | 604 | if (!lun || !lun->lun_se_dev) |
c66ac9db NB |
605 | return -ENODEV; |
606 | ||
607 | return core_alua_store_secondary_write_metadata(lun, page, count); | |
608 | } | |
609 | ||
2eafd729 CH |
610 | CONFIGFS_ATTR(target_fabric_port_, alua_tg_pt_gp); |
611 | CONFIGFS_ATTR(target_fabric_port_, alua_tg_pt_offline); | |
612 | CONFIGFS_ATTR(target_fabric_port_, alua_tg_pt_status); | |
613 | CONFIGFS_ATTR(target_fabric_port_, alua_tg_pt_write_md); | |
c66ac9db NB |
614 | |
615 | static struct configfs_attribute *target_fabric_port_attrs[] = { | |
2eafd729 CH |
616 | &target_fabric_port_attr_alua_tg_pt_gp, |
617 | &target_fabric_port_attr_alua_tg_pt_offline, | |
618 | &target_fabric_port_attr_alua_tg_pt_status, | |
619 | &target_fabric_port_attr_alua_tg_pt_write_md, | |
c66ac9db NB |
620 | NULL, |
621 | }; | |
622 | ||
c66ac9db NB |
623 | static int target_fabric_port_link( |
624 | struct config_item *lun_ci, | |
625 | struct config_item *se_dev_ci) | |
626 | { | |
627 | struct config_item *tpg_ci; | |
c66ac9db NB |
628 | struct se_lun *lun = container_of(to_config_group(lun_ci), |
629 | struct se_lun, lun_group); | |
c66ac9db | 630 | struct se_portal_group *se_tpg; |
0fd97ccf CH |
631 | struct se_device *dev = |
632 | container_of(to_config_group(se_dev_ci), struct se_device, dev_group); | |
c66ac9db NB |
633 | struct target_fabric_configfs *tf; |
634 | int ret; | |
635 | ||
0ff87549 NB |
636 | if (dev->dev_link_magic != SE_DEV_LINK_MAGIC) { |
637 | pr_err("Bad dev->dev_link_magic, not a valid se_dev_ci pointer:" | |
638 | " %p to struct se_device: %p\n", se_dev_ci, dev); | |
639 | return -EFAULT; | |
640 | } | |
641 | ||
faa06ab9 NB |
642 | if (!(dev->dev_flags & DF_CONFIGURED)) { |
643 | pr_err("se_device not configured yet, cannot port link\n"); | |
644 | return -ENODEV; | |
645 | } | |
646 | ||
c66ac9db NB |
647 | tpg_ci = &lun_ci->ci_parent->ci_group->cg_item; |
648 | se_tpg = container_of(to_config_group(tpg_ci), | |
649 | struct se_portal_group, tpg_group); | |
650 | tf = se_tpg->se_tpg_wwn->wwn_tf; | |
651 | ||
652 | if (lun->lun_se_dev != NULL) { | |
6708bb27 | 653 | pr_err("Port Symlink already exists\n"); |
c66ac9db NB |
654 | return -EEXIST; |
655 | } | |
656 | ||
6bb82612 NB |
657 | ret = core_dev_add_lun(se_tpg, dev, lun); |
658 | if (ret) { | |
659 | pr_err("core_dev_add_lun() failed: %d\n", ret); | |
c66ac9db NB |
660 | goto out; |
661 | } | |
662 | ||
ef0caf8d | 663 | if (tf->tf_ops->fabric_post_link) { |
c66ac9db NB |
664 | /* |
665 | * Call the optional fabric_post_link() to allow a | |
666 | * fabric module to setup any additional state once | |
667 | * core_dev_add_lun() has been called.. | |
668 | */ | |
ef0caf8d | 669 | tf->tf_ops->fabric_post_link(se_tpg, lun); |
c66ac9db NB |
670 | } |
671 | ||
672 | return 0; | |
673 | out: | |
674 | return ret; | |
675 | } | |
676 | ||
e16769d4 | 677 | static void target_fabric_port_unlink( |
c66ac9db NB |
678 | struct config_item *lun_ci, |
679 | struct config_item *se_dev_ci) | |
680 | { | |
681 | struct se_lun *lun = container_of(to_config_group(lun_ci), | |
682 | struct se_lun, lun_group); | |
adf653f9 | 683 | struct se_portal_group *se_tpg = lun->lun_tpg; |
c66ac9db NB |
684 | struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; |
685 | ||
ef0caf8d | 686 | if (tf->tf_ops->fabric_pre_unlink) { |
c66ac9db NB |
687 | /* |
688 | * Call the optional fabric_pre_unlink() to allow a | |
689 | * fabric module to release any additional stat before | |
690 | * core_dev_del_lun() is called. | |
691 | */ | |
ef0caf8d | 692 | tf->tf_ops->fabric_pre_unlink(se_tpg, lun); |
c66ac9db NB |
693 | } |
694 | ||
cd9d7cba | 695 | core_dev_del_lun(se_tpg, lun); |
c66ac9db NB |
696 | } |
697 | ||
6bb82612 NB |
698 | static void target_fabric_port_release(struct config_item *item) |
699 | { | |
700 | struct se_lun *lun = container_of(to_config_group(item), | |
701 | struct se_lun, lun_group); | |
702 | ||
703 | kfree_rcu(lun, rcu_head); | |
704 | } | |
705 | ||
c66ac9db | 706 | static struct configfs_item_operations target_fabric_port_item_ops = { |
6bb82612 | 707 | .release = target_fabric_port_release, |
c66ac9db NB |
708 | .allow_link = target_fabric_port_link, |
709 | .drop_link = target_fabric_port_unlink, | |
710 | }; | |
711 | ||
712 | TF_CIT_SETUP(tpg_port, &target_fabric_port_item_ops, NULL, target_fabric_port_attrs); | |
713 | ||
714 | /* End of tfc_tpg_port_cit */ | |
715 | ||
12d23384 NB |
716 | /* Start of tfc_tpg_port_stat_cit */ |
717 | ||
718 | static struct config_group *target_core_port_stat_mkdir( | |
719 | struct config_group *group, | |
720 | const char *name) | |
721 | { | |
722 | return ERR_PTR(-ENOSYS); | |
723 | } | |
724 | ||
725 | static void target_core_port_stat_rmdir( | |
726 | struct config_group *group, | |
727 | struct config_item *item) | |
728 | { | |
729 | return; | |
730 | } | |
731 | ||
732 | static struct configfs_group_operations target_fabric_port_stat_group_ops = { | |
733 | .make_group = target_core_port_stat_mkdir, | |
734 | .drop_item = target_core_port_stat_rmdir, | |
735 | }; | |
736 | ||
737 | TF_CIT_SETUP(tpg_port_stat, NULL, &target_fabric_port_stat_group_ops, NULL); | |
738 | ||
739 | /* End of tfc_tpg_port_stat_cit */ | |
740 | ||
c66ac9db NB |
741 | /* Start of tfc_tpg_lun_cit */ |
742 | ||
743 | static struct config_group *target_fabric_make_lun( | |
744 | struct config_group *group, | |
745 | const char *name) | |
746 | { | |
747 | struct se_lun *lun; | |
748 | struct se_portal_group *se_tpg = container_of(group, | |
749 | struct se_portal_group, tpg_lun_group); | |
750 | struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; | |
f2d30680 | 751 | unsigned long long unpacked_lun; |
12d23384 | 752 | int errno; |
c66ac9db NB |
753 | |
754 | if (strstr(name, "lun_") != name) { | |
6708bb27 | 755 | pr_err("Unable to locate \'_\" in" |
c66ac9db NB |
756 | " \"lun_$LUN_NUMBER\"\n"); |
757 | return ERR_PTR(-EINVAL); | |
758 | } | |
f2d30680 | 759 | errno = kstrtoull(name + 4, 0, &unpacked_lun); |
57103d7f JH |
760 | if (errno) |
761 | return ERR_PTR(errno); | |
c66ac9db | 762 | |
6bb82612 NB |
763 | lun = core_tpg_alloc_lun(se_tpg, unpacked_lun); |
764 | if (IS_ERR(lun)) | |
765 | return ERR_CAST(lun); | |
c66ac9db NB |
766 | |
767 | config_group_init_type_name(&lun->lun_group, name, | |
968ebe75 | 768 | &tf->tf_tpg_port_cit); |
1ae1602d | 769 | |
12d23384 | 770 | config_group_init_type_name(&lun->port_stat_grps.stat_group, |
968ebe75 | 771 | "statistics", &tf->tf_tpg_port_stat_cit); |
1ae1602d CH |
772 | configfs_add_default_group(&lun->port_stat_grps.stat_group, |
773 | &lun->lun_group); | |
774 | ||
12d23384 | 775 | target_stat_setup_port_default_groups(lun); |
c66ac9db NB |
776 | |
777 | return &lun->lun_group; | |
778 | } | |
779 | ||
780 | static void target_fabric_drop_lun( | |
781 | struct config_group *group, | |
782 | struct config_item *item) | |
783 | { | |
12d23384 NB |
784 | struct se_lun *lun = container_of(to_config_group(item), |
785 | struct se_lun, lun_group); | |
12d23384 | 786 | |
1ae1602d CH |
787 | configfs_remove_default_groups(&lun->port_stat_grps.stat_group); |
788 | configfs_remove_default_groups(&lun->lun_group); | |
12d23384 | 789 | |
c66ac9db NB |
790 | config_item_put(item); |
791 | } | |
792 | ||
793 | static struct configfs_group_operations target_fabric_lun_group_ops = { | |
794 | .make_group = &target_fabric_make_lun, | |
795 | .drop_item = &target_fabric_drop_lun, | |
796 | }; | |
797 | ||
798 | TF_CIT_SETUP(tpg_lun, NULL, &target_fabric_lun_group_ops, NULL); | |
799 | ||
800 | /* End of tfc_tpg_lun_cit */ | |
801 | ||
2eafd729 CH |
802 | TF_CIT_SETUP_DRV(tpg_attrib, NULL, NULL); |
803 | TF_CIT_SETUP_DRV(tpg_auth, NULL, NULL); | |
804 | TF_CIT_SETUP_DRV(tpg_param, NULL, NULL); | |
c66ac9db NB |
805 | |
806 | /* Start of tfc_tpg_base_cit */ | |
c66ac9db | 807 | |
1f6fe7cb NB |
808 | static void target_fabric_tpg_release(struct config_item *item) |
809 | { | |
810 | struct se_portal_group *se_tpg = container_of(to_config_group(item), | |
811 | struct se_portal_group, tpg_group); | |
812 | struct se_wwn *wwn = se_tpg->se_tpg_wwn; | |
813 | struct target_fabric_configfs *tf = wwn->wwn_tf; | |
814 | ||
ef0caf8d | 815 | tf->tf_ops->fabric_drop_tpg(se_tpg); |
1f6fe7cb NB |
816 | } |
817 | ||
c66ac9db | 818 | static struct configfs_item_operations target_fabric_tpg_base_item_ops = { |
1f6fe7cb | 819 | .release = target_fabric_tpg_release, |
c66ac9db NB |
820 | }; |
821 | ||
9ac8928e | 822 | TF_CIT_SETUP_DRV(tpg_base, &target_fabric_tpg_base_item_ops, NULL); |
c66ac9db NB |
823 | |
824 | /* End of tfc_tpg_base_cit */ | |
825 | ||
826 | /* Start of tfc_tpg_cit */ | |
827 | ||
828 | static struct config_group *target_fabric_make_tpg( | |
829 | struct config_group *group, | |
830 | const char *name) | |
831 | { | |
832 | struct se_wwn *wwn = container_of(group, struct se_wwn, wwn_group); | |
833 | struct target_fabric_configfs *tf = wwn->wwn_tf; | |
834 | struct se_portal_group *se_tpg; | |
835 | ||
ef0caf8d CH |
836 | if (!tf->tf_ops->fabric_make_tpg) { |
837 | pr_err("tf->tf_ops->fabric_make_tpg is NULL\n"); | |
c66ac9db NB |
838 | return ERR_PTR(-ENOSYS); |
839 | } | |
840 | ||
ef0caf8d | 841 | se_tpg = tf->tf_ops->fabric_make_tpg(wwn, group, name); |
6708bb27 | 842 | if (!se_tpg || IS_ERR(se_tpg)) |
c66ac9db | 843 | return ERR_PTR(-EINVAL); |
c66ac9db NB |
844 | |
845 | config_group_init_type_name(&se_tpg->tpg_group, name, | |
968ebe75 | 846 | &tf->tf_tpg_base_cit); |
1ae1602d | 847 | |
c66ac9db | 848 | config_group_init_type_name(&se_tpg->tpg_lun_group, "lun", |
968ebe75 | 849 | &tf->tf_tpg_lun_cit); |
1ae1602d CH |
850 | configfs_add_default_group(&se_tpg->tpg_lun_group, |
851 | &se_tpg->tpg_group); | |
852 | ||
c66ac9db | 853 | config_group_init_type_name(&se_tpg->tpg_np_group, "np", |
968ebe75 | 854 | &tf->tf_tpg_np_cit); |
1ae1602d CH |
855 | configfs_add_default_group(&se_tpg->tpg_np_group, |
856 | &se_tpg->tpg_group); | |
857 | ||
c66ac9db | 858 | config_group_init_type_name(&se_tpg->tpg_acl_group, "acls", |
968ebe75 | 859 | &tf->tf_tpg_nacl_cit); |
1ae1602d CH |
860 | configfs_add_default_group(&se_tpg->tpg_acl_group, |
861 | &se_tpg->tpg_group); | |
862 | ||
c66ac9db | 863 | config_group_init_type_name(&se_tpg->tpg_attrib_group, "attrib", |
968ebe75 | 864 | &tf->tf_tpg_attrib_cit); |
1ae1602d CH |
865 | configfs_add_default_group(&se_tpg->tpg_attrib_group, |
866 | &se_tpg->tpg_group); | |
867 | ||
e4b512e7 | 868 | config_group_init_type_name(&se_tpg->tpg_auth_group, "auth", |
968ebe75 | 869 | &tf->tf_tpg_auth_cit); |
1ae1602d CH |
870 | configfs_add_default_group(&se_tpg->tpg_auth_group, |
871 | &se_tpg->tpg_group); | |
872 | ||
c66ac9db | 873 | config_group_init_type_name(&se_tpg->tpg_param_group, "param", |
968ebe75 | 874 | &tf->tf_tpg_param_cit); |
1ae1602d CH |
875 | configfs_add_default_group(&se_tpg->tpg_param_group, |
876 | &se_tpg->tpg_group); | |
c66ac9db NB |
877 | |
878 | return &se_tpg->tpg_group; | |
879 | } | |
880 | ||
881 | static void target_fabric_drop_tpg( | |
882 | struct config_group *group, | |
883 | struct config_item *item) | |
884 | { | |
c66ac9db NB |
885 | struct se_portal_group *se_tpg = container_of(to_config_group(item), |
886 | struct se_portal_group, tpg_group); | |
c66ac9db | 887 | |
1ae1602d | 888 | configfs_remove_default_groups(&se_tpg->tpg_group); |
c66ac9db | 889 | config_item_put(item); |
c66ac9db NB |
890 | } |
891 | ||
1f6fe7cb NB |
892 | static void target_fabric_release_wwn(struct config_item *item) |
893 | { | |
894 | struct se_wwn *wwn = container_of(to_config_group(item), | |
895 | struct se_wwn, wwn_group); | |
896 | struct target_fabric_configfs *tf = wwn->wwn_tf; | |
897 | ||
839559e1 | 898 | configfs_remove_default_groups(&wwn->fabric_stat_group); |
ef0caf8d | 899 | tf->tf_ops->fabric_drop_wwn(wwn); |
1f6fe7cb NB |
900 | } |
901 | ||
902 | static struct configfs_item_operations target_fabric_tpg_item_ops = { | |
903 | .release = target_fabric_release_wwn, | |
904 | }; | |
905 | ||
c66ac9db NB |
906 | static struct configfs_group_operations target_fabric_tpg_group_ops = { |
907 | .make_group = target_fabric_make_tpg, | |
908 | .drop_item = target_fabric_drop_tpg, | |
909 | }; | |
910 | ||
1f6fe7cb NB |
911 | TF_CIT_SETUP(tpg, &target_fabric_tpg_item_ops, &target_fabric_tpg_group_ops, |
912 | NULL); | |
c66ac9db NB |
913 | |
914 | /* End of tfc_tpg_cit */ | |
915 | ||
12d23384 NB |
916 | /* Start of tfc_wwn_fabric_stats_cit */ |
917 | /* | |
918 | * This is used as a placeholder for struct se_wwn->fabric_stat_group | |
919 | * to allow fabrics access to ->fabric_stat_group->default_groups[] | |
920 | */ | |
921 | TF_CIT_SETUP(wwn_fabric_stats, NULL, NULL, NULL); | |
922 | ||
923 | /* End of tfc_wwn_fabric_stats_cit */ | |
924 | ||
c66ac9db NB |
925 | /* Start of tfc_wwn_cit */ |
926 | ||
927 | static struct config_group *target_fabric_make_wwn( | |
928 | struct config_group *group, | |
929 | const char *name) | |
930 | { | |
931 | struct target_fabric_configfs *tf = container_of(group, | |
932 | struct target_fabric_configfs, tf_group); | |
933 | struct se_wwn *wwn; | |
934 | ||
ef0caf8d | 935 | if (!tf->tf_ops->fabric_make_wwn) { |
6708bb27 | 936 | pr_err("tf->tf_ops.fabric_make_wwn is NULL\n"); |
c66ac9db NB |
937 | return ERR_PTR(-ENOSYS); |
938 | } | |
939 | ||
ef0caf8d | 940 | wwn = tf->tf_ops->fabric_make_wwn(tf, group, name); |
6708bb27 | 941 | if (!wwn || IS_ERR(wwn)) |
c66ac9db NB |
942 | return ERR_PTR(-EINVAL); |
943 | ||
944 | wwn->wwn_tf = tf; | |
12d23384 | 945 | |
968ebe75 | 946 | config_group_init_type_name(&wwn->wwn_group, name, &tf->tf_tpg_cit); |
1ae1602d | 947 | |
12d23384 | 948 | config_group_init_type_name(&wwn->fabric_stat_group, "fabric_statistics", |
968ebe75 | 949 | &tf->tf_wwn_fabric_stats_cit); |
1ae1602d | 950 | configfs_add_default_group(&wwn->fabric_stat_group, &wwn->wwn_group); |
c66ac9db | 951 | |
839559e1 CH |
952 | if (tf->tf_ops->add_wwn_groups) |
953 | tf->tf_ops->add_wwn_groups(wwn); | |
c66ac9db NB |
954 | return &wwn->wwn_group; |
955 | } | |
956 | ||
957 | static void target_fabric_drop_wwn( | |
958 | struct config_group *group, | |
959 | struct config_item *item) | |
960 | { | |
12d23384 NB |
961 | struct se_wwn *wwn = container_of(to_config_group(item), |
962 | struct se_wwn, wwn_group); | |
12d23384 | 963 | |
1ae1602d | 964 | configfs_remove_default_groups(&wwn->wwn_group); |
c66ac9db | 965 | config_item_put(item); |
c66ac9db NB |
966 | } |
967 | ||
968 | static struct configfs_group_operations target_fabric_wwn_group_ops = { | |
969 | .make_group = target_fabric_make_wwn, | |
970 | .drop_item = target_fabric_drop_wwn, | |
971 | }; | |
c66ac9db | 972 | |
2eafd729 CH |
973 | TF_CIT_SETUP_DRV(wwn, NULL, &target_fabric_wwn_group_ops); |
974 | TF_CIT_SETUP_DRV(discovery, NULL, NULL); | |
c66ac9db NB |
975 | |
976 | int target_fabric_setup_cits(struct target_fabric_configfs *tf) | |
977 | { | |
978 | target_fabric_setup_discovery_cit(tf); | |
979 | target_fabric_setup_wwn_cit(tf); | |
12d23384 | 980 | target_fabric_setup_wwn_fabric_stats_cit(tf); |
c66ac9db NB |
981 | target_fabric_setup_tpg_cit(tf); |
982 | target_fabric_setup_tpg_base_cit(tf); | |
983 | target_fabric_setup_tpg_port_cit(tf); | |
12d23384 | 984 | target_fabric_setup_tpg_port_stat_cit(tf); |
c66ac9db NB |
985 | target_fabric_setup_tpg_lun_cit(tf); |
986 | target_fabric_setup_tpg_np_cit(tf); | |
987 | target_fabric_setup_tpg_np_base_cit(tf); | |
988 | target_fabric_setup_tpg_attrib_cit(tf); | |
e4b512e7 | 989 | target_fabric_setup_tpg_auth_cit(tf); |
c66ac9db NB |
990 | target_fabric_setup_tpg_param_cit(tf); |
991 | target_fabric_setup_tpg_nacl_cit(tf); | |
992 | target_fabric_setup_tpg_nacl_base_cit(tf); | |
993 | target_fabric_setup_tpg_nacl_attrib_cit(tf); | |
994 | target_fabric_setup_tpg_nacl_auth_cit(tf); | |
995 | target_fabric_setup_tpg_nacl_param_cit(tf); | |
12d23384 | 996 | target_fabric_setup_tpg_nacl_stat_cit(tf); |
c66ac9db | 997 | target_fabric_setup_tpg_mappedlun_cit(tf); |
12d23384 | 998 | target_fabric_setup_tpg_mappedlun_stat_cit(tf); |
c66ac9db NB |
999 | |
1000 | return 0; | |
1001 | } |