]>
Commit | Line | Data |
---|---|---|
c66ac9db NB |
1 | /******************************************************************************* |
2 | * Filename: target_core_tpg.c | |
3 | * | |
4 | * This file contains generic Target Portal Group related functions. | |
5 | * | |
4c76251e | 6 | * (c) Copyright 2002-2013 Datera, Inc. |
c66ac9db NB |
7 | * |
8 | * Nicholas A. Bellinger <nab@kernel.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 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; if not, write to the Free Software | |
22 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
23 | * | |
24 | ******************************************************************************/ | |
25 | ||
26 | #include <linux/net.h> | |
27 | #include <linux/string.h> | |
28 | #include <linux/timer.h> | |
29 | #include <linux/slab.h> | |
30 | #include <linux/spinlock.h> | |
c66ac9db | 31 | #include <linux/in.h> |
c53181af | 32 | #include <linux/export.h> |
c66ac9db NB |
33 | #include <net/sock.h> |
34 | #include <net/tcp.h> | |
35 | #include <scsi/scsi.h> | |
36 | #include <scsi/scsi_cmnd.h> | |
37 | ||
38 | #include <target/target_core_base.h> | |
c4795fb2 CH |
39 | #include <target/target_core_backend.h> |
40 | #include <target/target_core_fabric.h> | |
c66ac9db | 41 | |
e26d99ae | 42 | #include "target_core_internal.h" |
e2480563 | 43 | #include "target_core_pr.h" |
e3d6f909 AG |
44 | |
45 | extern struct se_device *g_lun0_dev; | |
46 | ||
47 | static DEFINE_SPINLOCK(tpg_lock); | |
48 | static LIST_HEAD(tpg_list); | |
c66ac9db | 49 | |
c66ac9db NB |
50 | /* __core_tpg_get_initiator_node_acl(): |
51 | * | |
52 | * spin_lock_bh(&tpg->acl_node_lock); must be held when calling | |
53 | */ | |
54 | struct se_node_acl *__core_tpg_get_initiator_node_acl( | |
55 | struct se_portal_group *tpg, | |
56 | const char *initiatorname) | |
57 | { | |
58 | struct se_node_acl *acl; | |
59 | ||
60 | list_for_each_entry(acl, &tpg->acl_node_list, acl_list) { | |
6708bb27 | 61 | if (!strcmp(acl->initiatorname, initiatorname)) |
c66ac9db NB |
62 | return acl; |
63 | } | |
64 | ||
65 | return NULL; | |
66 | } | |
67 | ||
68 | /* core_tpg_get_initiator_node_acl(): | |
69 | * | |
70 | * | |
71 | */ | |
72 | struct se_node_acl *core_tpg_get_initiator_node_acl( | |
73 | struct se_portal_group *tpg, | |
74 | unsigned char *initiatorname) | |
75 | { | |
76 | struct se_node_acl *acl; | |
77 | ||
28638887 | 78 | spin_lock_irq(&tpg->acl_node_lock); |
fcf29481 | 79 | acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); |
28638887 | 80 | spin_unlock_irq(&tpg->acl_node_lock); |
c66ac9db | 81 | |
fcf29481 | 82 | return acl; |
c66ac9db | 83 | } |
b3fde035 | 84 | EXPORT_SYMBOL(core_tpg_get_initiator_node_acl); |
c66ac9db NB |
85 | |
86 | /* core_tpg_add_node_to_devs(): | |
87 | * | |
88 | * | |
89 | */ | |
90 | void core_tpg_add_node_to_devs( | |
91 | struct se_node_acl *acl, | |
92 | struct se_portal_group *tpg) | |
93 | { | |
c66ac9db NB |
94 | u32 lun_access = 0; |
95 | struct se_lun *lun; | |
96 | struct se_device *dev; | |
97 | ||
6bb82612 NB |
98 | mutex_lock(&tpg->tpg_lun_mutex); |
99 | hlist_for_each_entry_rcu(lun, &tpg->tpg_lun_hlist, link) { | |
c66ac9db NB |
100 | if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) |
101 | continue; | |
102 | ||
c66ac9db NB |
103 | dev = lun->lun_se_dev; |
104 | /* | |
105 | * By default in LIO-Target $FABRIC_MOD, | |
106 | * demo_mode_write_protect is ON, or READ_ONLY; | |
107 | */ | |
6708bb27 | 108 | if (!tpg->se_tpg_tfo->tpg_check_demo_mode_write_protect(tpg)) { |
58d92618 | 109 | lun_access = TRANSPORT_LUNFLAGS_READ_WRITE; |
c66ac9db NB |
110 | } else { |
111 | /* | |
112 | * Allow only optical drives to issue R/W in default RO | |
113 | * demo mode. | |
114 | */ | |
e3d6f909 | 115 | if (dev->transport->get_device_type(dev) == TYPE_DISK) |
c66ac9db NB |
116 | lun_access = TRANSPORT_LUNFLAGS_READ_ONLY; |
117 | else | |
118 | lun_access = TRANSPORT_LUNFLAGS_READ_WRITE; | |
119 | } | |
120 | ||
6708bb27 | 121 | pr_debug("TARGET_CORE[%s]->TPG[%u]_LUN[%u] - Adding %s" |
c66ac9db | 122 | " access for LUN in Demo Mode\n", |
e3d6f909 AG |
123 | tpg->se_tpg_tfo->get_fabric_name(), |
124 | tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, | |
c66ac9db NB |
125 | (lun_access == TRANSPORT_LUNFLAGS_READ_WRITE) ? |
126 | "READ-WRITE" : "READ-ONLY"); | |
127 | ||
e80ac6c4 | 128 | core_enable_device_list_for_node(lun, NULL, lun->unpacked_lun, |
6bb82612 | 129 | lun_access, acl, tpg); |
e2480563 NB |
130 | /* |
131 | * Check to see if there are any existing persistent reservation | |
132 | * APTPL pre-registrations that need to be enabled for this dynamic | |
133 | * LUN ACL now.. | |
134 | */ | |
135 | core_scsi3_check_aptpl_registration(dev, tpg, lun, acl, | |
136 | lun->unpacked_lun); | |
c66ac9db | 137 | } |
6bb82612 | 138 | mutex_unlock(&tpg->tpg_lun_mutex); |
c66ac9db NB |
139 | } |
140 | ||
141 | /* core_set_queue_depth_for_node(): | |
142 | * | |
143 | * | |
144 | */ | |
145 | static int core_set_queue_depth_for_node( | |
146 | struct se_portal_group *tpg, | |
147 | struct se_node_acl *acl) | |
148 | { | |
149 | if (!acl->queue_depth) { | |
6708bb27 | 150 | pr_err("Queue depth for %s Initiator Node: %s is 0," |
e3d6f909 | 151 | "defaulting to 1.\n", tpg->se_tpg_tfo->get_fabric_name(), |
c66ac9db NB |
152 | acl->initiatorname); |
153 | acl->queue_depth = 1; | |
154 | } | |
155 | ||
156 | return 0; | |
157 | } | |
158 | ||
e413f472 CH |
159 | static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg, |
160 | const unsigned char *initiatorname) | |
c66ac9db NB |
161 | { |
162 | struct se_node_acl *acl; | |
163 | ||
144bc4c2 CH |
164 | acl = kzalloc(max(sizeof(*acl), tpg->se_tpg_tfo->node_acl_size), |
165 | GFP_KERNEL); | |
6708bb27 | 166 | if (!acl) |
c66ac9db NB |
167 | return NULL; |
168 | ||
169 | INIT_LIST_HEAD(&acl->acl_list); | |
170 | INIT_LIST_HEAD(&acl->acl_sess_list); | |
29a05dee | 171 | INIT_HLIST_HEAD(&acl->lun_entry_hlist); |
afb999ff | 172 | kref_init(&acl->acl_kref); |
01468346 | 173 | init_completion(&acl->acl_free_comp); |
c66ac9db | 174 | spin_lock_init(&acl->nacl_sess_lock); |
29a05dee | 175 | mutex_init(&acl->lun_entry_mutex); |
c66ac9db | 176 | atomic_set(&acl->acl_pr_ref_count, 0); |
e1750d20 CH |
177 | if (tpg->se_tpg_tfo->tpg_get_default_depth) |
178 | acl->queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg); | |
179 | else | |
180 | acl->queue_depth = 1; | |
c66ac9db NB |
181 | snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname); |
182 | acl->se_tpg = tpg; | |
183 | acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX); | |
c66ac9db | 184 | |
e3d6f909 | 185 | tpg->se_tpg_tfo->set_default_node_attributes(acl); |
c66ac9db | 186 | |
e413f472 | 187 | if (core_set_queue_depth_for_node(tpg, acl) < 0) |
29a05dee | 188 | goto out_free_acl; |
e413f472 CH |
189 | |
190 | return acl; | |
191 | ||
e413f472 | 192 | out_free_acl: |
144bc4c2 | 193 | kfree(acl); |
e413f472 CH |
194 | return NULL; |
195 | } | |
196 | ||
197 | static void target_add_node_acl(struct se_node_acl *acl) | |
198 | { | |
199 | struct se_portal_group *tpg = acl->se_tpg; | |
200 | ||
201 | spin_lock_irq(&tpg->acl_node_lock); | |
202 | list_add_tail(&acl->acl_list, &tpg->acl_node_list); | |
203 | tpg->num_node_acls++; | |
204 | spin_unlock_irq(&tpg->acl_node_lock); | |
205 | ||
206 | pr_debug("%s_TPG[%hu] - Added %s ACL with TCQ Depth: %d for %s" | |
207 | " Initiator Node: %s\n", | |
208 | tpg->se_tpg_tfo->get_fabric_name(), | |
209 | tpg->se_tpg_tfo->tpg_get_tag(tpg), | |
210 | acl->dynamic_node_acl ? "DYNAMIC" : "", | |
211 | acl->queue_depth, | |
212 | tpg->se_tpg_tfo->get_fabric_name(), | |
213 | acl->initiatorname); | |
214 | } | |
215 | ||
216 | struct se_node_acl *core_tpg_check_initiator_node_acl( | |
217 | struct se_portal_group *tpg, | |
218 | unsigned char *initiatorname) | |
219 | { | |
220 | struct se_node_acl *acl; | |
221 | ||
222 | acl = core_tpg_get_initiator_node_acl(tpg, initiatorname); | |
223 | if (acl) | |
224 | return acl; | |
225 | ||
226 | if (!tpg->se_tpg_tfo->tpg_check_demo_mode(tpg)) | |
c66ac9db | 227 | return NULL; |
c66ac9db | 228 | |
e413f472 CH |
229 | acl = target_alloc_node_acl(tpg, initiatorname); |
230 | if (!acl) | |
c66ac9db | 231 | return NULL; |
e413f472 CH |
232 | acl->dynamic_node_acl = 1; |
233 | ||
052605c6 NB |
234 | /* |
235 | * Here we only create demo-mode MappedLUNs from the active | |
35d1efe8 | 236 | * TPG LUNs if the fabric is not explicitly asking for |
052605c6 NB |
237 | * tpg_check_demo_mode_login_only() == 1. |
238 | */ | |
cdf88a2f AG |
239 | if ((tpg->se_tpg_tfo->tpg_check_demo_mode_login_only == NULL) || |
240 | (tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg) != 1)) | |
052605c6 | 241 | core_tpg_add_node_to_devs(acl, tpg); |
c66ac9db | 242 | |
e413f472 | 243 | target_add_node_acl(acl); |
c66ac9db NB |
244 | return acl; |
245 | } | |
246 | EXPORT_SYMBOL(core_tpg_check_initiator_node_acl); | |
247 | ||
248 | void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *nacl) | |
249 | { | |
250 | while (atomic_read(&nacl->acl_pr_ref_count) != 0) | |
251 | cpu_relax(); | |
252 | } | |
253 | ||
c66ac9db NB |
254 | struct se_node_acl *core_tpg_add_initiator_node_acl( |
255 | struct se_portal_group *tpg, | |
c7d6a803 | 256 | const char *initiatorname) |
c66ac9db | 257 | { |
c7d6a803 | 258 | struct se_node_acl *acl; |
c66ac9db | 259 | |
28638887 | 260 | spin_lock_irq(&tpg->acl_node_lock); |
c66ac9db | 261 | acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); |
6708bb27 | 262 | if (acl) { |
c66ac9db NB |
263 | if (acl->dynamic_node_acl) { |
264 | acl->dynamic_node_acl = 0; | |
6708bb27 | 265 | pr_debug("%s_TPG[%u] - Replacing dynamic ACL" |
e3d6f909 AG |
266 | " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), |
267 | tpg->se_tpg_tfo->tpg_get_tag(tpg), initiatorname); | |
28638887 | 268 | spin_unlock_irq(&tpg->acl_node_lock); |
e413f472 | 269 | return acl; |
c66ac9db NB |
270 | } |
271 | ||
6708bb27 | 272 | pr_err("ACL entry for %s Initiator" |
c66ac9db | 273 | " Node %s already exists for TPG %u, ignoring" |
e3d6f909 AG |
274 | " request.\n", tpg->se_tpg_tfo->get_fabric_name(), |
275 | initiatorname, tpg->se_tpg_tfo->tpg_get_tag(tpg)); | |
28638887 | 276 | spin_unlock_irq(&tpg->acl_node_lock); |
c66ac9db NB |
277 | return ERR_PTR(-EEXIST); |
278 | } | |
28638887 | 279 | spin_unlock_irq(&tpg->acl_node_lock); |
c66ac9db | 280 | |
e413f472 CH |
281 | acl = target_alloc_node_acl(tpg, initiatorname); |
282 | if (!acl) | |
c66ac9db | 283 | return ERR_PTR(-ENOMEM); |
c66ac9db | 284 | |
e413f472 | 285 | target_add_node_acl(acl); |
c66ac9db NB |
286 | return acl; |
287 | } | |
c66ac9db | 288 | |
c7d6a803 | 289 | void core_tpg_del_initiator_node_acl(struct se_node_acl *acl) |
c66ac9db | 290 | { |
c7d6a803 | 291 | struct se_portal_group *tpg = acl->se_tpg; |
337c0607 | 292 | LIST_HEAD(sess_list); |
c66ac9db | 293 | struct se_session *sess, *sess_tmp; |
140854cb | 294 | unsigned long flags; |
28168905 | 295 | int rc; |
c66ac9db | 296 | |
28638887 | 297 | spin_lock_irq(&tpg->acl_node_lock); |
c66ac9db NB |
298 | if (acl->dynamic_node_acl) { |
299 | acl->dynamic_node_acl = 0; | |
c66ac9db NB |
300 | } |
301 | list_del(&acl->acl_list); | |
302 | tpg->num_node_acls--; | |
28638887 | 303 | spin_unlock_irq(&tpg->acl_node_lock); |
c66ac9db | 304 | |
337c0607 NB |
305 | spin_lock_irqsave(&acl->nacl_sess_lock, flags); |
306 | acl->acl_stop = 1; | |
307 | ||
308 | list_for_each_entry_safe(sess, sess_tmp, &acl->acl_sess_list, | |
309 | sess_acl_list) { | |
310 | if (sess->sess_tearing_down != 0) | |
c66ac9db NB |
311 | continue; |
312 | ||
337c0607 NB |
313 | target_get_session(sess); |
314 | list_move(&sess->sess_acl_list, &sess_list); | |
315 | } | |
316 | spin_unlock_irqrestore(&acl->nacl_sess_lock, flags); | |
317 | ||
318 | list_for_each_entry_safe(sess, sess_tmp, &sess_list, sess_acl_list) { | |
319 | list_del(&sess->sess_acl_list); | |
c66ac9db | 320 | |
337c0607 NB |
321 | rc = tpg->se_tpg_tfo->shutdown_session(sess); |
322 | target_put_session(sess); | |
323 | if (!rc) | |
324 | continue; | |
325 | target_put_session(sess); | |
c66ac9db | 326 | } |
337c0607 NB |
327 | target_put_nacl(acl); |
328 | /* | |
329 | * Wait for last target_put_nacl() to complete in target_complete_nacl() | |
330 | * for active fabric session transport_deregister_session() callbacks. | |
331 | */ | |
332 | wait_for_completion(&acl->acl_free_comp); | |
c66ac9db NB |
333 | |
334 | core_tpg_wait_for_nacl_pr_ref(acl); | |
c66ac9db NB |
335 | core_free_device_list_for_node(acl, tpg); |
336 | ||
6708bb27 | 337 | pr_debug("%s_TPG[%hu] - Deleted ACL with TCQ Depth: %d for %s" |
e3d6f909 AG |
338 | " Initiator Node: %s\n", tpg->se_tpg_tfo->get_fabric_name(), |
339 | tpg->se_tpg_tfo->tpg_get_tag(tpg), acl->queue_depth, | |
340 | tpg->se_tpg_tfo->get_fabric_name(), acl->initiatorname); | |
c66ac9db | 341 | |
144bc4c2 | 342 | kfree(acl); |
c66ac9db | 343 | } |
c66ac9db NB |
344 | |
345 | /* core_tpg_set_initiator_node_queue_depth(): | |
346 | * | |
347 | * | |
348 | */ | |
349 | int core_tpg_set_initiator_node_queue_depth( | |
350 | struct se_portal_group *tpg, | |
351 | unsigned char *initiatorname, | |
352 | u32 queue_depth, | |
353 | int force) | |
354 | { | |
355 | struct se_session *sess, *init_sess = NULL; | |
356 | struct se_node_acl *acl; | |
140854cb | 357 | unsigned long flags; |
c66ac9db NB |
358 | int dynamic_acl = 0; |
359 | ||
28638887 | 360 | spin_lock_irq(&tpg->acl_node_lock); |
c66ac9db | 361 | acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); |
6708bb27 AG |
362 | if (!acl) { |
363 | pr_err("Access Control List entry for %s Initiator" | |
c66ac9db | 364 | " Node %s does not exists for TPG %hu, ignoring" |
e3d6f909 AG |
365 | " request.\n", tpg->se_tpg_tfo->get_fabric_name(), |
366 | initiatorname, tpg->se_tpg_tfo->tpg_get_tag(tpg)); | |
28638887 | 367 | spin_unlock_irq(&tpg->acl_node_lock); |
c66ac9db NB |
368 | return -ENODEV; |
369 | } | |
370 | if (acl->dynamic_node_acl) { | |
371 | acl->dynamic_node_acl = 0; | |
372 | dynamic_acl = 1; | |
373 | } | |
28638887 | 374 | spin_unlock_irq(&tpg->acl_node_lock); |
c66ac9db | 375 | |
140854cb | 376 | spin_lock_irqsave(&tpg->session_lock, flags); |
c66ac9db NB |
377 | list_for_each_entry(sess, &tpg->tpg_sess_list, sess_list) { |
378 | if (sess->se_node_acl != acl) | |
379 | continue; | |
380 | ||
381 | if (!force) { | |
6708bb27 | 382 | pr_err("Unable to change queue depth for %s" |
c66ac9db NB |
383 | " Initiator Node: %s while session is" |
384 | " operational. To forcefully change the queue" | |
385 | " depth and force session reinstatement" | |
386 | " use the \"force=1\" parameter.\n", | |
e3d6f909 | 387 | tpg->se_tpg_tfo->get_fabric_name(), initiatorname); |
140854cb | 388 | spin_unlock_irqrestore(&tpg->session_lock, flags); |
c66ac9db | 389 | |
28638887 | 390 | spin_lock_irq(&tpg->acl_node_lock); |
c66ac9db NB |
391 | if (dynamic_acl) |
392 | acl->dynamic_node_acl = 1; | |
28638887 | 393 | spin_unlock_irq(&tpg->acl_node_lock); |
c66ac9db NB |
394 | return -EEXIST; |
395 | } | |
396 | /* | |
397 | * Determine if the session needs to be closed by our context. | |
398 | */ | |
6708bb27 | 399 | if (!tpg->se_tpg_tfo->shutdown_session(sess)) |
c66ac9db NB |
400 | continue; |
401 | ||
402 | init_sess = sess; | |
403 | break; | |
404 | } | |
405 | ||
406 | /* | |
407 | * User has requested to change the queue depth for a Initiator Node. | |
408 | * Change the value in the Node's struct se_node_acl, and call | |
409 | * core_set_queue_depth_for_node() to add the requested queue depth. | |
410 | * | |
e3d6f909 | 411 | * Finally call tpg->se_tpg_tfo->close_session() to force session |
c66ac9db NB |
412 | * reinstatement to occur if there is an active session for the |
413 | * $FABRIC_MOD Initiator Node in question. | |
414 | */ | |
415 | acl->queue_depth = queue_depth; | |
416 | ||
417 | if (core_set_queue_depth_for_node(tpg, acl) < 0) { | |
140854cb | 418 | spin_unlock_irqrestore(&tpg->session_lock, flags); |
c66ac9db NB |
419 | /* |
420 | * Force session reinstatement if | |
421 | * core_set_queue_depth_for_node() failed, because we assume | |
422 | * the $FABRIC_MOD has already the set session reinstatement | |
e3d6f909 | 423 | * bit from tpg->se_tpg_tfo->shutdown_session() called above. |
c66ac9db NB |
424 | */ |
425 | if (init_sess) | |
e3d6f909 | 426 | tpg->se_tpg_tfo->close_session(init_sess); |
c66ac9db | 427 | |
28638887 | 428 | spin_lock_irq(&tpg->acl_node_lock); |
c66ac9db NB |
429 | if (dynamic_acl) |
430 | acl->dynamic_node_acl = 1; | |
28638887 | 431 | spin_unlock_irq(&tpg->acl_node_lock); |
c66ac9db NB |
432 | return -EINVAL; |
433 | } | |
140854cb | 434 | spin_unlock_irqrestore(&tpg->session_lock, flags); |
c66ac9db NB |
435 | /* |
436 | * If the $FABRIC_MOD session for the Initiator Node ACL exists, | |
437 | * forcefully shutdown the $FABRIC_MOD session/nexus. | |
438 | */ | |
439 | if (init_sess) | |
e3d6f909 | 440 | tpg->se_tpg_tfo->close_session(init_sess); |
c66ac9db | 441 | |
bfb9035c | 442 | pr_debug("Successfully changed queue depth to: %d for Initiator" |
c66ac9db | 443 | " Node: %s on %s Target Portal Group: %u\n", queue_depth, |
e3d6f909 AG |
444 | initiatorname, tpg->se_tpg_tfo->get_fabric_name(), |
445 | tpg->se_tpg_tfo->tpg_get_tag(tpg)); | |
c66ac9db | 446 | |
28638887 | 447 | spin_lock_irq(&tpg->acl_node_lock); |
c66ac9db NB |
448 | if (dynamic_acl) |
449 | acl->dynamic_node_acl = 1; | |
28638887 | 450 | spin_unlock_irq(&tpg->acl_node_lock); |
c66ac9db NB |
451 | |
452 | return 0; | |
453 | } | |
454 | EXPORT_SYMBOL(core_tpg_set_initiator_node_queue_depth); | |
455 | ||
79e62fc3 AG |
456 | /* core_tpg_set_initiator_node_tag(): |
457 | * | |
458 | * Initiator nodeacl tags are not used internally, but may be used by | |
459 | * userspace to emulate aliases or groups. | |
460 | * Returns length of newly-set tag or -EINVAL. | |
461 | */ | |
462 | int core_tpg_set_initiator_node_tag( | |
463 | struct se_portal_group *tpg, | |
464 | struct se_node_acl *acl, | |
465 | const char *new_tag) | |
466 | { | |
467 | if (strlen(new_tag) >= MAX_ACL_TAG_SIZE) | |
468 | return -EINVAL; | |
469 | ||
470 | if (!strncmp("NULL", new_tag, 4)) { | |
471 | acl->acl_tag[0] = '\0'; | |
472 | return 0; | |
473 | } | |
474 | ||
475 | return snprintf(acl->acl_tag, MAX_ACL_TAG_SIZE, "%s", new_tag); | |
476 | } | |
477 | EXPORT_SYMBOL(core_tpg_set_initiator_node_tag); | |
478 | ||
5277797d NB |
479 | static void core_tpg_lun_ref_release(struct percpu_ref *ref) |
480 | { | |
481 | struct se_lun *lun = container_of(ref, struct se_lun, lun_ref); | |
482 | ||
483 | complete(&lun->lun_ref_comp); | |
484 | } | |
485 | ||
c66ac9db NB |
486 | static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) |
487 | { | |
488 | /* Set in core_dev_setup_virtual_lun0() */ | |
e3d6f909 | 489 | struct se_device *dev = g_lun0_dev; |
c66ac9db NB |
490 | struct se_lun *lun = &se_tpg->tpg_virt_lun0; |
491 | u32 lun_access = TRANSPORT_LUNFLAGS_READ_ONLY; | |
492 | int ret; | |
493 | ||
494 | lun->unpacked_lun = 0; | |
495 | lun->lun_status = TRANSPORT_LUN_STATUS_FREE; | |
496 | atomic_set(&lun->lun_acl_count, 0); | |
497 | init_completion(&lun->lun_shutdown_comp); | |
498 | INIT_LIST_HEAD(&lun->lun_acl_list); | |
c66ac9db | 499 | spin_lock_init(&lun->lun_acl_lock); |
c66ac9db | 500 | spin_lock_init(&lun->lun_sep_lock); |
5277797d | 501 | init_completion(&lun->lun_ref_comp); |
c66ac9db | 502 | |
d344f8a1 | 503 | ret = core_tpg_add_lun(se_tpg, lun, lun_access, dev); |
de06875f | 504 | if (ret < 0) |
5277797d | 505 | return ret; |
5277797d | 506 | |
c66ac9db NB |
507 | return 0; |
508 | } | |
509 | ||
c66ac9db | 510 | int core_tpg_register( |
9ac8928e | 511 | const struct target_core_fabric_ops *tfo, |
c66ac9db NB |
512 | struct se_wwn *se_wwn, |
513 | struct se_portal_group *se_tpg, | |
e4aae5af | 514 | int proto_id) |
c66ac9db | 515 | { |
6bb82612 | 516 | INIT_HLIST_HEAD(&se_tpg->tpg_lun_hlist); |
e4aae5af | 517 | se_tpg->proto_id = proto_id; |
c66ac9db NB |
518 | se_tpg->se_tpg_tfo = tfo; |
519 | se_tpg->se_tpg_wwn = se_wwn; | |
520 | atomic_set(&se_tpg->tpg_pr_ref_count, 0); | |
521 | INIT_LIST_HEAD(&se_tpg->acl_node_list); | |
e3d6f909 | 522 | INIT_LIST_HEAD(&se_tpg->se_tpg_node); |
c66ac9db NB |
523 | INIT_LIST_HEAD(&se_tpg->tpg_sess_list); |
524 | spin_lock_init(&se_tpg->acl_node_lock); | |
525 | spin_lock_init(&se_tpg->session_lock); | |
6bb82612 | 526 | mutex_init(&se_tpg->tpg_lun_mutex); |
c66ac9db | 527 | |
e4aae5af | 528 | if (se_tpg->proto_id >= 0) { |
6bb82612 | 529 | if (core_tpg_setup_virtual_lun0(se_tpg) < 0) |
c66ac9db | 530 | return -ENOMEM; |
c66ac9db NB |
531 | } |
532 | ||
e3d6f909 AG |
533 | spin_lock_bh(&tpg_lock); |
534 | list_add_tail(&se_tpg->se_tpg_node, &tpg_list); | |
535 | spin_unlock_bh(&tpg_lock); | |
c66ac9db | 536 | |
e4aae5af CH |
537 | pr_debug("TARGET_CORE[%s]: Allocated portal_group for endpoint: %s, " |
538 | "Proto: %d, Portal Tag: %u\n", tfo->get_fabric_name(), | |
539 | tfo->tpg_get_wwn(se_tpg) ? tfo->tpg_get_wwn(se_tpg) : NULL, | |
540 | se_tpg->proto_id, tfo->tpg_get_tag(se_tpg)); | |
c66ac9db NB |
541 | |
542 | return 0; | |
543 | } | |
544 | EXPORT_SYMBOL(core_tpg_register); | |
545 | ||
546 | int core_tpg_deregister(struct se_portal_group *se_tpg) | |
547 | { | |
e4aae5af | 548 | const struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo; |
e89d15ee NB |
549 | struct se_node_acl *nacl, *nacl_tmp; |
550 | ||
e4aae5af CH |
551 | pr_debug("TARGET_CORE[%s]: Deallocating portal_group for endpoint: %s, " |
552 | "Proto: %d, Portal Tag: %u\n", tfo->get_fabric_name(), | |
553 | tfo->tpg_get_wwn(se_tpg) ? tfo->tpg_get_wwn(se_tpg) : NULL, | |
554 | se_tpg->proto_id, tfo->tpg_get_tag(se_tpg)); | |
c66ac9db | 555 | |
e3d6f909 AG |
556 | spin_lock_bh(&tpg_lock); |
557 | list_del(&se_tpg->se_tpg_node); | |
558 | spin_unlock_bh(&tpg_lock); | |
c66ac9db NB |
559 | |
560 | while (atomic_read(&se_tpg->tpg_pr_ref_count) != 0) | |
561 | cpu_relax(); | |
e89d15ee NB |
562 | /* |
563 | * Release any remaining demo-mode generated se_node_acl that have | |
564 | * not been released because of TFO->tpg_check_demo_mode_cache() == 1 | |
565 | * in transport_deregister_session(). | |
566 | */ | |
28638887 | 567 | spin_lock_irq(&se_tpg->acl_node_lock); |
e89d15ee NB |
568 | list_for_each_entry_safe(nacl, nacl_tmp, &se_tpg->acl_node_list, |
569 | acl_list) { | |
570 | list_del(&nacl->acl_list); | |
571 | se_tpg->num_node_acls--; | |
28638887 | 572 | spin_unlock_irq(&se_tpg->acl_node_lock); |
e89d15ee NB |
573 | |
574 | core_tpg_wait_for_nacl_pr_ref(nacl); | |
575 | core_free_device_list_for_node(nacl, se_tpg); | |
144bc4c2 | 576 | kfree(nacl); |
e89d15ee | 577 | |
28638887 | 578 | spin_lock_irq(&se_tpg->acl_node_lock); |
e89d15ee | 579 | } |
28638887 | 580 | spin_unlock_irq(&se_tpg->acl_node_lock); |
c66ac9db | 581 | |
e4aae5af | 582 | if (se_tpg->proto_id >= 0) |
9c7d6154 | 583 | core_tpg_remove_lun(se_tpg, &se_tpg->tpg_virt_lun0); |
c66ac9db | 584 | |
c66ac9db NB |
585 | return 0; |
586 | } | |
587 | EXPORT_SYMBOL(core_tpg_deregister); | |
588 | ||
d344f8a1 | 589 | struct se_lun *core_tpg_alloc_lun( |
c66ac9db NB |
590 | struct se_portal_group *tpg, |
591 | u32 unpacked_lun) | |
592 | { | |
593 | struct se_lun *lun; | |
594 | ||
595 | if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { | |
6708bb27 | 596 | pr_err("%s LUN: %u exceeds TRANSPORT_MAX_LUNS_PER_TPG" |
c66ac9db | 597 | "-1: %u for Target Portal Group: %u\n", |
e3d6f909 | 598 | tpg->se_tpg_tfo->get_fabric_name(), |
c66ac9db | 599 | unpacked_lun, TRANSPORT_MAX_LUNS_PER_TPG-1, |
e3d6f909 | 600 | tpg->se_tpg_tfo->tpg_get_tag(tpg)); |
c66ac9db NB |
601 | return ERR_PTR(-EOVERFLOW); |
602 | } | |
603 | ||
6bb82612 NB |
604 | lun = kzalloc(sizeof(*lun), GFP_KERNEL); |
605 | if (!lun) { | |
606 | pr_err("Unable to allocate se_lun memory\n"); | |
607 | return ERR_PTR(-ENOMEM); | |
c66ac9db | 608 | } |
6bb82612 NB |
609 | lun->unpacked_lun = unpacked_lun; |
610 | lun->lun_link_magic = SE_LUN_LINK_MAGIC; | |
611 | lun->lun_status = TRANSPORT_LUN_STATUS_FREE; | |
612 | atomic_set(&lun->lun_acl_count, 0); | |
613 | init_completion(&lun->lun_shutdown_comp); | |
614 | INIT_LIST_HEAD(&lun->lun_acl_list); | |
615 | spin_lock_init(&lun->lun_acl_lock); | |
616 | spin_lock_init(&lun->lun_sep_lock); | |
617 | init_completion(&lun->lun_ref_comp); | |
c66ac9db NB |
618 | |
619 | return lun; | |
620 | } | |
621 | ||
d344f8a1 | 622 | int core_tpg_add_lun( |
c66ac9db NB |
623 | struct se_portal_group *tpg, |
624 | struct se_lun *lun, | |
625 | u32 lun_access, | |
340dbf72 | 626 | struct se_device *dev) |
c66ac9db | 627 | { |
e3d6f909 AG |
628 | int ret; |
629 | ||
2aad2a86 | 630 | ret = percpu_ref_init(&lun->lun_ref, core_tpg_lun_ref_release, 0, |
a34375ef | 631 | GFP_KERNEL); |
e3d6f909 AG |
632 | if (ret < 0) |
633 | return ret; | |
c66ac9db | 634 | |
340dbf72 | 635 | ret = core_dev_export(dev, tpg, lun); |
5277797d | 636 | if (ret < 0) { |
9a1049da | 637 | percpu_ref_exit(&lun->lun_ref); |
5277797d NB |
638 | return ret; |
639 | } | |
640 | ||
6bb82612 | 641 | mutex_lock(&tpg->tpg_lun_mutex); |
c66ac9db NB |
642 | lun->lun_access = lun_access; |
643 | lun->lun_status = TRANSPORT_LUN_STATUS_ACTIVE; | |
6bb82612 NB |
644 | if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) |
645 | hlist_add_head_rcu(&lun->link, &tpg->tpg_lun_hlist); | |
646 | mutex_unlock(&tpg->tpg_lun_mutex); | |
c66ac9db NB |
647 | |
648 | return 0; | |
649 | } | |
650 | ||
cd9d7cba | 651 | void core_tpg_remove_lun( |
c66ac9db NB |
652 | struct se_portal_group *tpg, |
653 | struct se_lun *lun) | |
654 | { | |
6bb82612 NB |
655 | struct se_device *dev = lun->lun_se_dev; |
656 | ||
4a9a6c8d NB |
657 | core_clear_lun_from_tpg(lun, tpg); |
658 | transport_clear_lun_ref(lun); | |
c66ac9db NB |
659 | |
660 | core_dev_unexport(lun->lun_se_dev, tpg, lun); | |
661 | ||
6bb82612 | 662 | mutex_lock(&tpg->tpg_lun_mutex); |
c66ac9db | 663 | lun->lun_status = TRANSPORT_LUN_STATUS_FREE; |
6bb82612 NB |
664 | if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) |
665 | hlist_del_rcu(&lun->link); | |
666 | mutex_unlock(&tpg->tpg_lun_mutex); | |
c66ac9db | 667 | |
9a1049da | 668 | percpu_ref_exit(&lun->lun_ref); |
c66ac9db | 669 | } |