diff options
Diffstat (limited to 'drivers/target/iscsi/iscsi_target_tpg.c')
-rw-r--r-- | drivers/target/iscsi/iscsi_target_tpg.c | 759 |
1 files changed, 759 insertions, 0 deletions
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c new file mode 100644 index 000000000000..d4cf2cd25c44 --- /dev/null +++ b/drivers/target/iscsi/iscsi_target_tpg.c | |||
@@ -0,0 +1,759 @@ | |||
1 | /******************************************************************************* | ||
2 | * This file contains iSCSI Target Portal Group related functions. | ||
3 | * | ||
4 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | ||
5 | * | ||
6 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
7 | * | ||
8 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | ******************************************************************************/ | ||
20 | |||
21 | #include <target/target_core_base.h> | ||
22 | #include <target/target_core_transport.h> | ||
23 | #include <target/target_core_fabric_ops.h> | ||
24 | #include <target/target_core_configfs.h> | ||
25 | #include <target/target_core_tpg.h> | ||
26 | |||
27 | #include "iscsi_target_core.h" | ||
28 | #include "iscsi_target_erl0.h" | ||
29 | #include "iscsi_target_login.h" | ||
30 | #include "iscsi_target_nodeattrib.h" | ||
31 | #include "iscsi_target_tpg.h" | ||
32 | #include "iscsi_target_util.h" | ||
33 | #include "iscsi_target.h" | ||
34 | #include "iscsi_target_parameters.h" | ||
35 | |||
36 | struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *tiqn, u16 tpgt) | ||
37 | { | ||
38 | struct iscsi_portal_group *tpg; | ||
39 | |||
40 | tpg = kzalloc(sizeof(struct iscsi_portal_group), GFP_KERNEL); | ||
41 | if (!tpg) { | ||
42 | pr_err("Unable to allocate struct iscsi_portal_group\n"); | ||
43 | return NULL; | ||
44 | } | ||
45 | |||
46 | tpg->tpgt = tpgt; | ||
47 | tpg->tpg_state = TPG_STATE_FREE; | ||
48 | tpg->tpg_tiqn = tiqn; | ||
49 | INIT_LIST_HEAD(&tpg->tpg_gnp_list); | ||
50 | INIT_LIST_HEAD(&tpg->tpg_list); | ||
51 | mutex_init(&tpg->tpg_access_lock); | ||
52 | mutex_init(&tpg->np_login_lock); | ||
53 | spin_lock_init(&tpg->tpg_state_lock); | ||
54 | spin_lock_init(&tpg->tpg_np_lock); | ||
55 | |||
56 | return tpg; | ||
57 | } | ||
58 | |||
59 | static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *); | ||
60 | |||
61 | int iscsit_load_discovery_tpg(void) | ||
62 | { | ||
63 | struct iscsi_param *param; | ||
64 | struct iscsi_portal_group *tpg; | ||
65 | int ret; | ||
66 | |||
67 | tpg = iscsit_alloc_portal_group(NULL, 1); | ||
68 | if (!tpg) { | ||
69 | pr_err("Unable to allocate struct iscsi_portal_group\n"); | ||
70 | return -1; | ||
71 | } | ||
72 | |||
73 | ret = core_tpg_register( | ||
74 | &lio_target_fabric_configfs->tf_ops, | ||
75 | NULL, &tpg->tpg_se_tpg, (void *)tpg, | ||
76 | TRANSPORT_TPG_TYPE_DISCOVERY); | ||
77 | if (ret < 0) { | ||
78 | kfree(tpg); | ||
79 | return -1; | ||
80 | } | ||
81 | |||
82 | tpg->sid = 1; /* First Assigned LIO Session ID */ | ||
83 | iscsit_set_default_tpg_attribs(tpg); | ||
84 | |||
85 | if (iscsi_create_default_params(&tpg->param_list) < 0) | ||
86 | goto out; | ||
87 | /* | ||
88 | * By default we disable authentication for discovery sessions, | ||
89 | * this can be changed with: | ||
90 | * | ||
91 | * /sys/kernel/config/target/iscsi/discovery_auth/enforce_discovery_auth | ||
92 | */ | ||
93 | param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list); | ||
94 | if (!param) | ||
95 | goto out; | ||
96 | |||
97 | if (iscsi_update_param_value(param, "CHAP,None") < 0) | ||
98 | goto out; | ||
99 | |||
100 | tpg->tpg_attrib.authentication = 0; | ||
101 | |||
102 | spin_lock(&tpg->tpg_state_lock); | ||
103 | tpg->tpg_state = TPG_STATE_ACTIVE; | ||
104 | spin_unlock(&tpg->tpg_state_lock); | ||
105 | |||
106 | iscsit_global->discovery_tpg = tpg; | ||
107 | pr_debug("CORE[0] - Allocated Discovery TPG\n"); | ||
108 | |||
109 | return 0; | ||
110 | out: | ||
111 | if (tpg->sid == 1) | ||
112 | core_tpg_deregister(&tpg->tpg_se_tpg); | ||
113 | kfree(tpg); | ||
114 | return -1; | ||
115 | } | ||
116 | |||
117 | void iscsit_release_discovery_tpg(void) | ||
118 | { | ||
119 | struct iscsi_portal_group *tpg = iscsit_global->discovery_tpg; | ||
120 | |||
121 | if (!tpg) | ||
122 | return; | ||
123 | |||
124 | core_tpg_deregister(&tpg->tpg_se_tpg); | ||
125 | |||
126 | kfree(tpg); | ||
127 | iscsit_global->discovery_tpg = NULL; | ||
128 | } | ||
129 | |||
130 | struct iscsi_portal_group *iscsit_get_tpg_from_np( | ||
131 | struct iscsi_tiqn *tiqn, | ||
132 | struct iscsi_np *np) | ||
133 | { | ||
134 | struct iscsi_portal_group *tpg = NULL; | ||
135 | struct iscsi_tpg_np *tpg_np; | ||
136 | |||
137 | spin_lock(&tiqn->tiqn_tpg_lock); | ||
138 | list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) { | ||
139 | |||
140 | spin_lock(&tpg->tpg_state_lock); | ||
141 | if (tpg->tpg_state == TPG_STATE_FREE) { | ||
142 | spin_unlock(&tpg->tpg_state_lock); | ||
143 | continue; | ||
144 | } | ||
145 | spin_unlock(&tpg->tpg_state_lock); | ||
146 | |||
147 | spin_lock(&tpg->tpg_np_lock); | ||
148 | list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) { | ||
149 | if (tpg_np->tpg_np == np) { | ||
150 | spin_unlock(&tpg->tpg_np_lock); | ||
151 | spin_unlock(&tiqn->tiqn_tpg_lock); | ||
152 | return tpg; | ||
153 | } | ||
154 | } | ||
155 | spin_unlock(&tpg->tpg_np_lock); | ||
156 | } | ||
157 | spin_unlock(&tiqn->tiqn_tpg_lock); | ||
158 | |||
159 | return NULL; | ||
160 | } | ||
161 | |||
162 | int iscsit_get_tpg( | ||
163 | struct iscsi_portal_group *tpg) | ||
164 | { | ||
165 | int ret; | ||
166 | |||
167 | ret = mutex_lock_interruptible(&tpg->tpg_access_lock); | ||
168 | return ((ret != 0) || signal_pending(current)) ? -1 : 0; | ||
169 | } | ||
170 | |||
171 | void iscsit_put_tpg(struct iscsi_portal_group *tpg) | ||
172 | { | ||
173 | mutex_unlock(&tpg->tpg_access_lock); | ||
174 | } | ||
175 | |||
176 | static void iscsit_clear_tpg_np_login_thread( | ||
177 | struct iscsi_tpg_np *tpg_np, | ||
178 | struct iscsi_portal_group *tpg) | ||
179 | { | ||
180 | if (!tpg_np->tpg_np) { | ||
181 | pr_err("struct iscsi_tpg_np->tpg_np is NULL!\n"); | ||
182 | return; | ||
183 | } | ||
184 | |||
185 | iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg); | ||
186 | } | ||
187 | |||
188 | void iscsit_clear_tpg_np_login_threads( | ||
189 | struct iscsi_portal_group *tpg) | ||
190 | { | ||
191 | struct iscsi_tpg_np *tpg_np; | ||
192 | |||
193 | spin_lock(&tpg->tpg_np_lock); | ||
194 | list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) { | ||
195 | if (!tpg_np->tpg_np) { | ||
196 | pr_err("struct iscsi_tpg_np->tpg_np is NULL!\n"); | ||
197 | continue; | ||
198 | } | ||
199 | spin_unlock(&tpg->tpg_np_lock); | ||
200 | iscsit_clear_tpg_np_login_thread(tpg_np, tpg); | ||
201 | spin_lock(&tpg->tpg_np_lock); | ||
202 | } | ||
203 | spin_unlock(&tpg->tpg_np_lock); | ||
204 | } | ||
205 | |||
206 | void iscsit_tpg_dump_params(struct iscsi_portal_group *tpg) | ||
207 | { | ||
208 | iscsi_print_params(tpg->param_list); | ||
209 | } | ||
210 | |||
211 | static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *tpg) | ||
212 | { | ||
213 | struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; | ||
214 | |||
215 | a->authentication = TA_AUTHENTICATION; | ||
216 | a->login_timeout = TA_LOGIN_TIMEOUT; | ||
217 | a->netif_timeout = TA_NETIF_TIMEOUT; | ||
218 | a->default_cmdsn_depth = TA_DEFAULT_CMDSN_DEPTH; | ||
219 | a->generate_node_acls = TA_GENERATE_NODE_ACLS; | ||
220 | a->cache_dynamic_acls = TA_CACHE_DYNAMIC_ACLS; | ||
221 | a->demo_mode_write_protect = TA_DEMO_MODE_WRITE_PROTECT; | ||
222 | a->prod_mode_write_protect = TA_PROD_MODE_WRITE_PROTECT; | ||
223 | } | ||
224 | |||
225 | int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_group *tpg) | ||
226 | { | ||
227 | if (tpg->tpg_state != TPG_STATE_FREE) { | ||
228 | pr_err("Unable to add iSCSI Target Portal Group: %d" | ||
229 | " while not in TPG_STATE_FREE state.\n", tpg->tpgt); | ||
230 | return -EEXIST; | ||
231 | } | ||
232 | iscsit_set_default_tpg_attribs(tpg); | ||
233 | |||
234 | if (iscsi_create_default_params(&tpg->param_list) < 0) | ||
235 | goto err_out; | ||
236 | |||
237 | ISCSI_TPG_ATTRIB(tpg)->tpg = tpg; | ||
238 | |||
239 | spin_lock(&tpg->tpg_state_lock); | ||
240 | tpg->tpg_state = TPG_STATE_INACTIVE; | ||
241 | spin_unlock(&tpg->tpg_state_lock); | ||
242 | |||
243 | spin_lock(&tiqn->tiqn_tpg_lock); | ||
244 | list_add_tail(&tpg->tpg_list, &tiqn->tiqn_tpg_list); | ||
245 | tiqn->tiqn_ntpgs++; | ||
246 | pr_debug("CORE[%s]_TPG[%hu] - Added iSCSI Target Portal Group\n", | ||
247 | tiqn->tiqn, tpg->tpgt); | ||
248 | spin_unlock(&tiqn->tiqn_tpg_lock); | ||
249 | |||
250 | return 0; | ||
251 | err_out: | ||
252 | if (tpg->param_list) { | ||
253 | iscsi_release_param_list(tpg->param_list); | ||
254 | tpg->param_list = NULL; | ||
255 | } | ||
256 | kfree(tpg); | ||
257 | return -ENOMEM; | ||
258 | } | ||
259 | |||
260 | int iscsit_tpg_del_portal_group( | ||
261 | struct iscsi_tiqn *tiqn, | ||
262 | struct iscsi_portal_group *tpg, | ||
263 | int force) | ||
264 | { | ||
265 | u8 old_state = tpg->tpg_state; | ||
266 | |||
267 | spin_lock(&tpg->tpg_state_lock); | ||
268 | tpg->tpg_state = TPG_STATE_INACTIVE; | ||
269 | spin_unlock(&tpg->tpg_state_lock); | ||
270 | |||
271 | if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { | ||
272 | pr_err("Unable to delete iSCSI Target Portal Group:" | ||
273 | " %hu while active sessions exist, and force=0\n", | ||
274 | tpg->tpgt); | ||
275 | tpg->tpg_state = old_state; | ||
276 | return -EPERM; | ||
277 | } | ||
278 | |||
279 | core_tpg_clear_object_luns(&tpg->tpg_se_tpg); | ||
280 | |||
281 | if (tpg->param_list) { | ||
282 | iscsi_release_param_list(tpg->param_list); | ||
283 | tpg->param_list = NULL; | ||
284 | } | ||
285 | |||
286 | core_tpg_deregister(&tpg->tpg_se_tpg); | ||
287 | |||
288 | spin_lock(&tpg->tpg_state_lock); | ||
289 | tpg->tpg_state = TPG_STATE_FREE; | ||
290 | spin_unlock(&tpg->tpg_state_lock); | ||
291 | |||
292 | spin_lock(&tiqn->tiqn_tpg_lock); | ||
293 | tiqn->tiqn_ntpgs--; | ||
294 | list_del(&tpg->tpg_list); | ||
295 | spin_unlock(&tiqn->tiqn_tpg_lock); | ||
296 | |||
297 | pr_debug("CORE[%s]_TPG[%hu] - Deleted iSCSI Target Portal Group\n", | ||
298 | tiqn->tiqn, tpg->tpgt); | ||
299 | |||
300 | kfree(tpg); | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg) | ||
305 | { | ||
306 | struct iscsi_param *param; | ||
307 | struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; | ||
308 | |||
309 | spin_lock(&tpg->tpg_state_lock); | ||
310 | if (tpg->tpg_state == TPG_STATE_ACTIVE) { | ||
311 | pr_err("iSCSI target portal group: %hu is already" | ||
312 | " active, ignoring request.\n", tpg->tpgt); | ||
313 | spin_unlock(&tpg->tpg_state_lock); | ||
314 | return -EINVAL; | ||
315 | } | ||
316 | /* | ||
317 | * Make sure that AuthMethod does not contain None as an option | ||
318 | * unless explictly disabled. Set the default to CHAP if authentication | ||
319 | * is enforced (as per default), and remove the NONE option. | ||
320 | */ | ||
321 | param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list); | ||
322 | if (!param) { | ||
323 | spin_unlock(&tpg->tpg_state_lock); | ||
324 | return -ENOMEM; | ||
325 | } | ||
326 | |||
327 | if (ISCSI_TPG_ATTRIB(tpg)->authentication) { | ||
328 | if (!strcmp(param->value, NONE)) | ||
329 | if (iscsi_update_param_value(param, CHAP) < 0) { | ||
330 | spin_unlock(&tpg->tpg_state_lock); | ||
331 | return -ENOMEM; | ||
332 | } | ||
333 | if (iscsit_ta_authentication(tpg, 1) < 0) { | ||
334 | spin_unlock(&tpg->tpg_state_lock); | ||
335 | return -ENOMEM; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | tpg->tpg_state = TPG_STATE_ACTIVE; | ||
340 | spin_unlock(&tpg->tpg_state_lock); | ||
341 | |||
342 | spin_lock(&tiqn->tiqn_tpg_lock); | ||
343 | tiqn->tiqn_active_tpgs++; | ||
344 | pr_debug("iSCSI_TPG[%hu] - Enabled iSCSI Target Portal Group\n", | ||
345 | tpg->tpgt); | ||
346 | spin_unlock(&tiqn->tiqn_tpg_lock); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | int iscsit_tpg_disable_portal_group(struct iscsi_portal_group *tpg, int force) | ||
352 | { | ||
353 | struct iscsi_tiqn *tiqn; | ||
354 | u8 old_state = tpg->tpg_state; | ||
355 | |||
356 | spin_lock(&tpg->tpg_state_lock); | ||
357 | if (tpg->tpg_state == TPG_STATE_INACTIVE) { | ||
358 | pr_err("iSCSI Target Portal Group: %hu is already" | ||
359 | " inactive, ignoring request.\n", tpg->tpgt); | ||
360 | spin_unlock(&tpg->tpg_state_lock); | ||
361 | return -EINVAL; | ||
362 | } | ||
363 | tpg->tpg_state = TPG_STATE_INACTIVE; | ||
364 | spin_unlock(&tpg->tpg_state_lock); | ||
365 | |||
366 | iscsit_clear_tpg_np_login_threads(tpg); | ||
367 | |||
368 | if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { | ||
369 | spin_lock(&tpg->tpg_state_lock); | ||
370 | tpg->tpg_state = old_state; | ||
371 | spin_unlock(&tpg->tpg_state_lock); | ||
372 | pr_err("Unable to disable iSCSI Target Portal Group:" | ||
373 | " %hu while active sessions exist, and force=0\n", | ||
374 | tpg->tpgt); | ||
375 | return -EPERM; | ||
376 | } | ||
377 | |||
378 | tiqn = tpg->tpg_tiqn; | ||
379 | if (!tiqn || (tpg == iscsit_global->discovery_tpg)) | ||
380 | return 0; | ||
381 | |||
382 | spin_lock(&tiqn->tiqn_tpg_lock); | ||
383 | tiqn->tiqn_active_tpgs--; | ||
384 | pr_debug("iSCSI_TPG[%hu] - Disabled iSCSI Target Portal Group\n", | ||
385 | tpg->tpgt); | ||
386 | spin_unlock(&tiqn->tiqn_tpg_lock); | ||
387 | |||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | struct iscsi_node_attrib *iscsit_tpg_get_node_attrib( | ||
392 | struct iscsi_session *sess) | ||
393 | { | ||
394 | struct se_session *se_sess = sess->se_sess; | ||
395 | struct se_node_acl *se_nacl = se_sess->se_node_acl; | ||
396 | struct iscsi_node_acl *acl = container_of(se_nacl, struct iscsi_node_acl, | ||
397 | se_node_acl); | ||
398 | |||
399 | return &acl->node_attrib; | ||
400 | } | ||
401 | |||
402 | struct iscsi_tpg_np *iscsit_tpg_locate_child_np( | ||
403 | struct iscsi_tpg_np *tpg_np, | ||
404 | int network_transport) | ||
405 | { | ||
406 | struct iscsi_tpg_np *tpg_np_child, *tpg_np_child_tmp; | ||
407 | |||
408 | spin_lock(&tpg_np->tpg_np_parent_lock); | ||
409 | list_for_each_entry_safe(tpg_np_child, tpg_np_child_tmp, | ||
410 | &tpg_np->tpg_np_parent_list, tpg_np_child_list) { | ||
411 | if (tpg_np_child->tpg_np->np_network_transport == | ||
412 | network_transport) { | ||
413 | spin_unlock(&tpg_np->tpg_np_parent_lock); | ||
414 | return tpg_np_child; | ||
415 | } | ||
416 | } | ||
417 | spin_unlock(&tpg_np->tpg_np_parent_lock); | ||
418 | |||
419 | return NULL; | ||
420 | } | ||
421 | |||
422 | struct iscsi_tpg_np *iscsit_tpg_add_network_portal( | ||
423 | struct iscsi_portal_group *tpg, | ||
424 | struct __kernel_sockaddr_storage *sockaddr, | ||
425 | char *ip_str, | ||
426 | struct iscsi_tpg_np *tpg_np_parent, | ||
427 | int network_transport) | ||
428 | { | ||
429 | struct iscsi_np *np; | ||
430 | struct iscsi_tpg_np *tpg_np; | ||
431 | |||
432 | tpg_np = kzalloc(sizeof(struct iscsi_tpg_np), GFP_KERNEL); | ||
433 | if (!tpg_np) { | ||
434 | pr_err("Unable to allocate memory for" | ||
435 | " struct iscsi_tpg_np.\n"); | ||
436 | return ERR_PTR(-ENOMEM); | ||
437 | } | ||
438 | |||
439 | np = iscsit_add_np(sockaddr, ip_str, network_transport); | ||
440 | if (IS_ERR(np)) { | ||
441 | kfree(tpg_np); | ||
442 | return ERR_CAST(np); | ||
443 | } | ||
444 | |||
445 | INIT_LIST_HEAD(&tpg_np->tpg_np_list); | ||
446 | INIT_LIST_HEAD(&tpg_np->tpg_np_child_list); | ||
447 | INIT_LIST_HEAD(&tpg_np->tpg_np_parent_list); | ||
448 | spin_lock_init(&tpg_np->tpg_np_parent_lock); | ||
449 | tpg_np->tpg_np = np; | ||
450 | tpg_np->tpg = tpg; | ||
451 | |||
452 | spin_lock(&tpg->tpg_np_lock); | ||
453 | list_add_tail(&tpg_np->tpg_np_list, &tpg->tpg_gnp_list); | ||
454 | tpg->num_tpg_nps++; | ||
455 | if (tpg->tpg_tiqn) | ||
456 | tpg->tpg_tiqn->tiqn_num_tpg_nps++; | ||
457 | spin_unlock(&tpg->tpg_np_lock); | ||
458 | |||
459 | if (tpg_np_parent) { | ||
460 | tpg_np->tpg_np_parent = tpg_np_parent; | ||
461 | spin_lock(&tpg_np_parent->tpg_np_parent_lock); | ||
462 | list_add_tail(&tpg_np->tpg_np_child_list, | ||
463 | &tpg_np_parent->tpg_np_parent_list); | ||
464 | spin_unlock(&tpg_np_parent->tpg_np_parent_lock); | ||
465 | } | ||
466 | |||
467 | pr_debug("CORE[%s] - Added Network Portal: %s:%hu,%hu on %s\n", | ||
468 | tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, | ||
469 | (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP"); | ||
470 | |||
471 | return tpg_np; | ||
472 | } | ||
473 | |||
474 | static int iscsit_tpg_release_np( | ||
475 | struct iscsi_tpg_np *tpg_np, | ||
476 | struct iscsi_portal_group *tpg, | ||
477 | struct iscsi_np *np) | ||
478 | { | ||
479 | iscsit_clear_tpg_np_login_thread(tpg_np, tpg); | ||
480 | |||
481 | pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n", | ||
482 | tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, | ||
483 | (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP"); | ||
484 | |||
485 | tpg_np->tpg_np = NULL; | ||
486 | tpg_np->tpg = NULL; | ||
487 | kfree(tpg_np); | ||
488 | /* | ||
489 | * iscsit_del_np() will shutdown struct iscsi_np when last TPG reference is released. | ||
490 | */ | ||
491 | return iscsit_del_np(np); | ||
492 | } | ||
493 | |||
494 | int iscsit_tpg_del_network_portal( | ||
495 | struct iscsi_portal_group *tpg, | ||
496 | struct iscsi_tpg_np *tpg_np) | ||
497 | { | ||
498 | struct iscsi_np *np; | ||
499 | struct iscsi_tpg_np *tpg_np_child, *tpg_np_child_tmp; | ||
500 | int ret = 0; | ||
501 | |||
502 | np = tpg_np->tpg_np; | ||
503 | if (!np) { | ||
504 | pr_err("Unable to locate struct iscsi_np from" | ||
505 | " struct iscsi_tpg_np\n"); | ||
506 | return -EINVAL; | ||
507 | } | ||
508 | |||
509 | if (!tpg_np->tpg_np_parent) { | ||
510 | /* | ||
511 | * We are the parent tpg network portal. Release all of the | ||
512 | * child tpg_np's (eg: the non ISCSI_TCP ones) on our parent | ||
513 | * list first. | ||
514 | */ | ||
515 | list_for_each_entry_safe(tpg_np_child, tpg_np_child_tmp, | ||
516 | &tpg_np->tpg_np_parent_list, | ||
517 | tpg_np_child_list) { | ||
518 | ret = iscsit_tpg_del_network_portal(tpg, tpg_np_child); | ||
519 | if (ret < 0) | ||
520 | pr_err("iscsit_tpg_del_network_portal()" | ||
521 | " failed: %d\n", ret); | ||
522 | } | ||
523 | } else { | ||
524 | /* | ||
525 | * We are not the parent ISCSI_TCP tpg network portal. Release | ||
526 | * our own network portals from the child list. | ||
527 | */ | ||
528 | spin_lock(&tpg_np->tpg_np_parent->tpg_np_parent_lock); | ||
529 | list_del(&tpg_np->tpg_np_child_list); | ||
530 | spin_unlock(&tpg_np->tpg_np_parent->tpg_np_parent_lock); | ||
531 | } | ||
532 | |||
533 | spin_lock(&tpg->tpg_np_lock); | ||
534 | list_del(&tpg_np->tpg_np_list); | ||
535 | tpg->num_tpg_nps--; | ||
536 | if (tpg->tpg_tiqn) | ||
537 | tpg->tpg_tiqn->tiqn_num_tpg_nps--; | ||
538 | spin_unlock(&tpg->tpg_np_lock); | ||
539 | |||
540 | return iscsit_tpg_release_np(tpg_np, tpg, np); | ||
541 | } | ||
542 | |||
543 | int iscsit_tpg_set_initiator_node_queue_depth( | ||
544 | struct iscsi_portal_group *tpg, | ||
545 | unsigned char *initiatorname, | ||
546 | u32 queue_depth, | ||
547 | int force) | ||
548 | { | ||
549 | return core_tpg_set_initiator_node_queue_depth(&tpg->tpg_se_tpg, | ||
550 | initiatorname, queue_depth, force); | ||
551 | } | ||
552 | |||
553 | int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication) | ||
554 | { | ||
555 | unsigned char buf1[256], buf2[256], *none = NULL; | ||
556 | int len; | ||
557 | struct iscsi_param *param; | ||
558 | struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; | ||
559 | |||
560 | if ((authentication != 1) && (authentication != 0)) { | ||
561 | pr_err("Illegal value for authentication parameter:" | ||
562 | " %u, ignoring request.\n", authentication); | ||
563 | return -1; | ||
564 | } | ||
565 | |||
566 | memset(buf1, 0, sizeof(buf1)); | ||
567 | memset(buf2, 0, sizeof(buf2)); | ||
568 | |||
569 | param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list); | ||
570 | if (!param) | ||
571 | return -EINVAL; | ||
572 | |||
573 | if (authentication) { | ||
574 | snprintf(buf1, sizeof(buf1), "%s", param->value); | ||
575 | none = strstr(buf1, NONE); | ||
576 | if (!none) | ||
577 | goto out; | ||
578 | if (!strncmp(none + 4, ",", 1)) { | ||
579 | if (!strcmp(buf1, none)) | ||
580 | sprintf(buf2, "%s", none+5); | ||
581 | else { | ||
582 | none--; | ||
583 | *none = '\0'; | ||
584 | len = sprintf(buf2, "%s", buf1); | ||
585 | none += 5; | ||
586 | sprintf(buf2 + len, "%s", none); | ||
587 | } | ||
588 | } else { | ||
589 | none--; | ||
590 | *none = '\0'; | ||
591 | sprintf(buf2, "%s", buf1); | ||
592 | } | ||
593 | if (iscsi_update_param_value(param, buf2) < 0) | ||
594 | return -EINVAL; | ||
595 | } else { | ||
596 | snprintf(buf1, sizeof(buf1), "%s", param->value); | ||
597 | none = strstr(buf1, NONE); | ||
598 | if ((none)) | ||
599 | goto out; | ||
600 | strncat(buf1, ",", strlen(",")); | ||
601 | strncat(buf1, NONE, strlen(NONE)); | ||
602 | if (iscsi_update_param_value(param, buf1) < 0) | ||
603 | return -EINVAL; | ||
604 | } | ||
605 | |||
606 | out: | ||
607 | a->authentication = authentication; | ||
608 | pr_debug("%s iSCSI Authentication Methods for TPG: %hu.\n", | ||
609 | a->authentication ? "Enforcing" : "Disabling", tpg->tpgt); | ||
610 | |||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | int iscsit_ta_login_timeout( | ||
615 | struct iscsi_portal_group *tpg, | ||
616 | u32 login_timeout) | ||
617 | { | ||
618 | struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; | ||
619 | |||
620 | if (login_timeout > TA_LOGIN_TIMEOUT_MAX) { | ||
621 | pr_err("Requested Login Timeout %u larger than maximum" | ||
622 | " %u\n", login_timeout, TA_LOGIN_TIMEOUT_MAX); | ||
623 | return -EINVAL; | ||
624 | } else if (login_timeout < TA_LOGIN_TIMEOUT_MIN) { | ||
625 | pr_err("Requested Logout Timeout %u smaller than" | ||
626 | " minimum %u\n", login_timeout, TA_LOGIN_TIMEOUT_MIN); | ||
627 | return -EINVAL; | ||
628 | } | ||
629 | |||
630 | a->login_timeout = login_timeout; | ||
631 | pr_debug("Set Logout Timeout to %u for Target Portal Group" | ||
632 | " %hu\n", a->login_timeout, tpg->tpgt); | ||
633 | |||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | int iscsit_ta_netif_timeout( | ||
638 | struct iscsi_portal_group *tpg, | ||
639 | u32 netif_timeout) | ||
640 | { | ||
641 | struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; | ||
642 | |||
643 | if (netif_timeout > TA_NETIF_TIMEOUT_MAX) { | ||
644 | pr_err("Requested Network Interface Timeout %u larger" | ||
645 | " than maximum %u\n", netif_timeout, | ||
646 | TA_NETIF_TIMEOUT_MAX); | ||
647 | return -EINVAL; | ||
648 | } else if (netif_timeout < TA_NETIF_TIMEOUT_MIN) { | ||
649 | pr_err("Requested Network Interface Timeout %u smaller" | ||
650 | " than minimum %u\n", netif_timeout, | ||
651 | TA_NETIF_TIMEOUT_MIN); | ||
652 | return -EINVAL; | ||
653 | } | ||
654 | |||
655 | a->netif_timeout = netif_timeout; | ||
656 | pr_debug("Set Network Interface Timeout to %u for" | ||
657 | " Target Portal Group %hu\n", a->netif_timeout, tpg->tpgt); | ||
658 | |||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | int iscsit_ta_generate_node_acls( | ||
663 | struct iscsi_portal_group *tpg, | ||
664 | u32 flag) | ||
665 | { | ||
666 | struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; | ||
667 | |||
668 | if ((flag != 0) && (flag != 1)) { | ||
669 | pr_err("Illegal value %d\n", flag); | ||
670 | return -EINVAL; | ||
671 | } | ||
672 | |||
673 | a->generate_node_acls = flag; | ||
674 | pr_debug("iSCSI_TPG[%hu] - Generate Initiator Portal Group ACLs: %s\n", | ||
675 | tpg->tpgt, (a->generate_node_acls) ? "Enabled" : "Disabled"); | ||
676 | |||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | int iscsit_ta_default_cmdsn_depth( | ||
681 | struct iscsi_portal_group *tpg, | ||
682 | u32 tcq_depth) | ||
683 | { | ||
684 | struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; | ||
685 | |||
686 | if (tcq_depth > TA_DEFAULT_CMDSN_DEPTH_MAX) { | ||
687 | pr_err("Requested Default Queue Depth: %u larger" | ||
688 | " than maximum %u\n", tcq_depth, | ||
689 | TA_DEFAULT_CMDSN_DEPTH_MAX); | ||
690 | return -EINVAL; | ||
691 | } else if (tcq_depth < TA_DEFAULT_CMDSN_DEPTH_MIN) { | ||
692 | pr_err("Requested Default Queue Depth: %u smaller" | ||
693 | " than minimum %u\n", tcq_depth, | ||
694 | TA_DEFAULT_CMDSN_DEPTH_MIN); | ||
695 | return -EINVAL; | ||
696 | } | ||
697 | |||
698 | a->default_cmdsn_depth = tcq_depth; | ||
699 | pr_debug("iSCSI_TPG[%hu] - Set Default CmdSN TCQ Depth to %u\n", | ||
700 | tpg->tpgt, a->default_cmdsn_depth); | ||
701 | |||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | int iscsit_ta_cache_dynamic_acls( | ||
706 | struct iscsi_portal_group *tpg, | ||
707 | u32 flag) | ||
708 | { | ||
709 | struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; | ||
710 | |||
711 | if ((flag != 0) && (flag != 1)) { | ||
712 | pr_err("Illegal value %d\n", flag); | ||
713 | return -EINVAL; | ||
714 | } | ||
715 | |||
716 | a->cache_dynamic_acls = flag; | ||
717 | pr_debug("iSCSI_TPG[%hu] - Cache Dynamic Initiator Portal Group" | ||
718 | " ACLs %s\n", tpg->tpgt, (a->cache_dynamic_acls) ? | ||
719 | "Enabled" : "Disabled"); | ||
720 | |||
721 | return 0; | ||
722 | } | ||
723 | |||
724 | int iscsit_ta_demo_mode_write_protect( | ||
725 | struct iscsi_portal_group *tpg, | ||
726 | u32 flag) | ||
727 | { | ||
728 | struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; | ||
729 | |||
730 | if ((flag != 0) && (flag != 1)) { | ||
731 | pr_err("Illegal value %d\n", flag); | ||
732 | return -EINVAL; | ||
733 | } | ||
734 | |||
735 | a->demo_mode_write_protect = flag; | ||
736 | pr_debug("iSCSI_TPG[%hu] - Demo Mode Write Protect bit: %s\n", | ||
737 | tpg->tpgt, (a->demo_mode_write_protect) ? "ON" : "OFF"); | ||
738 | |||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | int iscsit_ta_prod_mode_write_protect( | ||
743 | struct iscsi_portal_group *tpg, | ||
744 | u32 flag) | ||
745 | { | ||
746 | struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; | ||
747 | |||
748 | if ((flag != 0) && (flag != 1)) { | ||
749 | pr_err("Illegal value %d\n", flag); | ||
750 | return -EINVAL; | ||
751 | } | ||
752 | |||
753 | a->prod_mode_write_protect = flag; | ||
754 | pr_debug("iSCSI_TPG[%hu] - Production Mode Write Protect bit:" | ||
755 | " %s\n", tpg->tpgt, (a->prod_mode_write_protect) ? | ||
756 | "ON" : "OFF"); | ||
757 | |||
758 | return 0; | ||
759 | } | ||