712 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*******************************************************************************3 * Filename: target_core_tpg.c4 *5 * This file contains generic Target Portal Group related functions.6 *7 * (c) Copyright 2002-2013 Datera, Inc.8 *9 * Nicholas A. Bellinger <nab@kernel.org>10 *11 ******************************************************************************/12 13#include <linux/net.h>14#include <linux/string.h>15#include <linux/timer.h>16#include <linux/slab.h>17#include <linux/spinlock.h>18#include <linux/in.h>19#include <linux/export.h>20#include <net/sock.h>21#include <net/tcp.h>22#include <scsi/scsi_proto.h>23 24#include <target/target_core_base.h>25#include <target/target_core_backend.h>26#include <target/target_core_fabric.h>27 28#include "target_core_internal.h"29#include "target_core_alua.h"30#include "target_core_pr.h"31#include "target_core_ua.h"32 33extern struct se_device *g_lun0_dev;34static DEFINE_XARRAY_ALLOC(tpg_xa);35 36/* __core_tpg_get_initiator_node_acl():37 *38 * mutex_lock(&tpg->acl_node_mutex); must be held when calling39 */40struct se_node_acl *__core_tpg_get_initiator_node_acl(41 struct se_portal_group *tpg,42 const char *initiatorname)43{44 struct se_node_acl *acl;45 46 list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {47 if (!strcmp(acl->initiatorname, initiatorname))48 return acl;49 }50 51 return NULL;52}53 54/* core_tpg_get_initiator_node_acl():55 *56 *57 */58struct se_node_acl *core_tpg_get_initiator_node_acl(59 struct se_portal_group *tpg,60 unsigned char *initiatorname)61{62 struct se_node_acl *acl;63 /*64 * Obtain se_node_acl->acl_kref using fabric driver provided65 * initiatorname[] during node acl endpoint lookup driven by66 * new se_session login.67 *68 * The reference is held until se_session shutdown -> release69 * occurs via fabric driver invoked transport_deregister_session()70 * or transport_free_session() code.71 */72 mutex_lock(&tpg->acl_node_mutex);73 acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);74 if (acl) {75 if (!kref_get_unless_zero(&acl->acl_kref))76 acl = NULL;77 }78 mutex_unlock(&tpg->acl_node_mutex);79 80 return acl;81}82EXPORT_SYMBOL(core_tpg_get_initiator_node_acl);83 84void core_allocate_nexus_loss_ua(85 struct se_node_acl *nacl)86{87 struct se_dev_entry *deve;88 89 if (!nacl)90 return;91 92 rcu_read_lock();93 hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link)94 core_scsi3_ua_allocate(deve, 0x29,95 ASCQ_29H_NEXUS_LOSS_OCCURRED);96 rcu_read_unlock();97}98EXPORT_SYMBOL(core_allocate_nexus_loss_ua);99 100/* core_tpg_add_node_to_devs():101 *102 *103 */104void core_tpg_add_node_to_devs(105 struct se_node_acl *acl,106 struct se_portal_group *tpg,107 struct se_lun *lun_orig)108{109 bool lun_access_ro = true;110 struct se_lun *lun;111 struct se_device *dev;112 113 mutex_lock(&tpg->tpg_lun_mutex);114 hlist_for_each_entry_rcu(lun, &tpg->tpg_lun_hlist, link) {115 if (lun_orig && lun != lun_orig)116 continue;117 118 dev = rcu_dereference_check(lun->lun_se_dev,119 lockdep_is_held(&tpg->tpg_lun_mutex));120 /*121 * By default in LIO-Target $FABRIC_MOD,122 * demo_mode_write_protect is ON, or READ_ONLY;123 */124 if (!tpg->se_tpg_tfo->tpg_check_demo_mode_write_protect(tpg)) {125 lun_access_ro = false;126 } else {127 /*128 * Allow only optical drives to issue R/W in default RO129 * demo mode.130 */131 if (dev->transport->get_device_type(dev) == TYPE_DISK)132 lun_access_ro = true;133 else134 lun_access_ro = false;135 }136 137 pr_debug("TARGET_CORE[%s]->TPG[%u]_LUN[%llu] - Adding %s"138 " access for LUN in Demo Mode\n",139 tpg->se_tpg_tfo->fabric_name,140 tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun,141 lun_access_ro ? "READ-ONLY" : "READ-WRITE");142 143 core_enable_device_list_for_node(lun, NULL, lun->unpacked_lun,144 lun_access_ro, acl, tpg);145 /*146 * Check to see if there are any existing persistent reservation147 * APTPL pre-registrations that need to be enabled for this dynamic148 * LUN ACL now..149 */150 core_scsi3_check_aptpl_registration(dev, tpg, lun, acl,151 lun->unpacked_lun);152 }153 mutex_unlock(&tpg->tpg_lun_mutex);154}155 156static void157target_set_nacl_queue_depth(struct se_portal_group *tpg,158 struct se_node_acl *acl, u32 queue_depth)159{160 acl->queue_depth = queue_depth;161 162 if (!acl->queue_depth) {163 pr_warn("Queue depth for %s Initiator Node: %s is 0,"164 "defaulting to 1.\n", tpg->se_tpg_tfo->fabric_name,165 acl->initiatorname);166 acl->queue_depth = 1;167 }168}169 170static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg,171 const unsigned char *initiatorname)172{173 struct se_node_acl *acl;174 u32 queue_depth;175 176 acl = kzalloc(max(sizeof(*acl), tpg->se_tpg_tfo->node_acl_size),177 GFP_KERNEL);178 if (!acl)179 return NULL;180 181 INIT_LIST_HEAD(&acl->acl_list);182 INIT_LIST_HEAD(&acl->acl_sess_list);183 INIT_HLIST_HEAD(&acl->lun_entry_hlist);184 kref_init(&acl->acl_kref);185 init_completion(&acl->acl_free_comp);186 spin_lock_init(&acl->nacl_sess_lock);187 mutex_init(&acl->lun_entry_mutex);188 atomic_set(&acl->acl_pr_ref_count, 0);189 190 if (tpg->se_tpg_tfo->tpg_get_default_depth)191 queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg);192 else193 queue_depth = 1;194 target_set_nacl_queue_depth(tpg, acl, queue_depth);195 196 snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname);197 acl->se_tpg = tpg;198 acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX);199 200 tpg->se_tpg_tfo->set_default_node_attributes(acl);201 202 return acl;203}204 205static void target_add_node_acl(struct se_node_acl *acl)206{207 struct se_portal_group *tpg = acl->se_tpg;208 209 mutex_lock(&tpg->acl_node_mutex);210 list_add_tail(&acl->acl_list, &tpg->acl_node_list);211 mutex_unlock(&tpg->acl_node_mutex);212 213 pr_debug("%s_TPG[%hu] - Added %s ACL with TCQ Depth: %d for %s"214 " Initiator Node: %s\n",215 tpg->se_tpg_tfo->fabric_name,216 tpg->se_tpg_tfo->tpg_get_tag(tpg),217 acl->dynamic_node_acl ? "DYNAMIC" : "",218 acl->queue_depth,219 tpg->se_tpg_tfo->fabric_name,220 acl->initiatorname);221}222 223bool target_tpg_has_node_acl(struct se_portal_group *tpg,224 const char *initiatorname)225{226 struct se_node_acl *acl;227 bool found = false;228 229 mutex_lock(&tpg->acl_node_mutex);230 list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {231 if (!strcmp(acl->initiatorname, initiatorname)) {232 found = true;233 break;234 }235 }236 mutex_unlock(&tpg->acl_node_mutex);237 238 return found;239}240EXPORT_SYMBOL(target_tpg_has_node_acl);241 242struct se_node_acl *core_tpg_check_initiator_node_acl(243 struct se_portal_group *tpg,244 unsigned char *initiatorname)245{246 struct se_node_acl *acl;247 248 acl = core_tpg_get_initiator_node_acl(tpg, initiatorname);249 if (acl)250 return acl;251 252 if (!tpg->se_tpg_tfo->tpg_check_demo_mode(tpg))253 return NULL;254 255 acl = target_alloc_node_acl(tpg, initiatorname);256 if (!acl)257 return NULL;258 /*259 * When allocating a dynamically generated node_acl, go ahead260 * and take the extra kref now before returning to the fabric261 * driver caller.262 *263 * Note this reference will be released at session shutdown264 * time within transport_free_session() code.265 */266 kref_get(&acl->acl_kref);267 acl->dynamic_node_acl = 1;268 269 /*270 * Here we only create demo-mode MappedLUNs from the active271 * TPG LUNs if the fabric is not explicitly asking for272 * tpg_check_demo_mode_login_only() == 1.273 */274 if ((tpg->se_tpg_tfo->tpg_check_demo_mode_login_only == NULL) ||275 (tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg) != 1))276 core_tpg_add_node_to_devs(acl, tpg, NULL);277 278 target_add_node_acl(acl);279 return acl;280}281EXPORT_SYMBOL(core_tpg_check_initiator_node_acl);282 283void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *nacl)284{285 while (atomic_read(&nacl->acl_pr_ref_count) != 0)286 cpu_relax();287}288 289struct se_node_acl *core_tpg_add_initiator_node_acl(290 struct se_portal_group *tpg,291 const char *initiatorname)292{293 struct se_node_acl *acl;294 295 mutex_lock(&tpg->acl_node_mutex);296 acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);297 if (acl) {298 if (acl->dynamic_node_acl) {299 acl->dynamic_node_acl = 0;300 pr_debug("%s_TPG[%u] - Replacing dynamic ACL"301 " for %s\n", tpg->se_tpg_tfo->fabric_name,302 tpg->se_tpg_tfo->tpg_get_tag(tpg), initiatorname);303 mutex_unlock(&tpg->acl_node_mutex);304 return acl;305 }306 307 pr_err("ACL entry for %s Initiator"308 " Node %s already exists for TPG %u, ignoring"309 " request.\n", tpg->se_tpg_tfo->fabric_name,310 initiatorname, tpg->se_tpg_tfo->tpg_get_tag(tpg));311 mutex_unlock(&tpg->acl_node_mutex);312 return ERR_PTR(-EEXIST);313 }314 mutex_unlock(&tpg->acl_node_mutex);315 316 acl = target_alloc_node_acl(tpg, initiatorname);317 if (!acl)318 return ERR_PTR(-ENOMEM);319 320 target_add_node_acl(acl);321 return acl;322}323 324static void target_shutdown_sessions(struct se_node_acl *acl)325{326 struct se_session *sess;327 unsigned long flags;328 329restart:330 spin_lock_irqsave(&acl->nacl_sess_lock, flags);331 list_for_each_entry(sess, &acl->acl_sess_list, sess_acl_list) {332 if (sess->cmd_cnt && atomic_read(&sess->cmd_cnt->stopped))333 continue;334 335 list_del_init(&sess->sess_acl_list);336 spin_unlock_irqrestore(&acl->nacl_sess_lock, flags);337 338 if (acl->se_tpg->se_tpg_tfo->close_session)339 acl->se_tpg->se_tpg_tfo->close_session(sess);340 goto restart;341 }342 spin_unlock_irqrestore(&acl->nacl_sess_lock, flags);343}344 345void core_tpg_del_initiator_node_acl(struct se_node_acl *acl)346{347 struct se_portal_group *tpg = acl->se_tpg;348 349 mutex_lock(&tpg->acl_node_mutex);350 if (acl->dynamic_node_acl)351 acl->dynamic_node_acl = 0;352 list_del_init(&acl->acl_list);353 mutex_unlock(&tpg->acl_node_mutex);354 355 target_shutdown_sessions(acl);356 357 target_put_nacl(acl);358 /*359 * Wait for last target_put_nacl() to complete in target_complete_nacl()360 * for active fabric session transport_deregister_session() callbacks.361 */362 wait_for_completion(&acl->acl_free_comp);363 364 core_tpg_wait_for_nacl_pr_ref(acl);365 core_free_device_list_for_node(acl, tpg);366 367 pr_debug("%s_TPG[%hu] - Deleted ACL with TCQ Depth: %d for %s"368 " Initiator Node: %s\n", tpg->se_tpg_tfo->fabric_name,369 tpg->se_tpg_tfo->tpg_get_tag(tpg), acl->queue_depth,370 tpg->se_tpg_tfo->fabric_name, acl->initiatorname);371 372 kfree(acl);373}374 375/* core_tpg_set_initiator_node_queue_depth():376 *377 *378 */379int core_tpg_set_initiator_node_queue_depth(380 struct se_node_acl *acl,381 u32 queue_depth)382{383 struct se_portal_group *tpg = acl->se_tpg;384 385 /*386 * Allow the setting of se_node_acl queue_depth to be idempotent,387 * and not force a session shutdown event if the value is not388 * changing.389 */390 if (acl->queue_depth == queue_depth)391 return 0;392 /*393 * User has requested to change the queue depth for a Initiator Node.394 * Change the value in the Node's struct se_node_acl, and call395 * target_set_nacl_queue_depth() to set the new queue depth.396 */397 target_set_nacl_queue_depth(tpg, acl, queue_depth);398 399 /*400 * Shutdown all pending sessions to force session reinstatement.401 */402 target_shutdown_sessions(acl);403 404 pr_debug("Successfully changed queue depth to: %d for Initiator"405 " Node: %s on %s Target Portal Group: %u\n", acl->queue_depth,406 acl->initiatorname, tpg->se_tpg_tfo->fabric_name,407 tpg->se_tpg_tfo->tpg_get_tag(tpg));408 409 return 0;410}411EXPORT_SYMBOL(core_tpg_set_initiator_node_queue_depth);412 413/* core_tpg_set_initiator_node_tag():414 *415 * Initiator nodeacl tags are not used internally, but may be used by416 * userspace to emulate aliases or groups.417 * Returns length of newly-set tag or -EINVAL.418 */419int core_tpg_set_initiator_node_tag(420 struct se_portal_group *tpg,421 struct se_node_acl *acl,422 const char *new_tag)423{424 if (strlen(new_tag) >= MAX_ACL_TAG_SIZE)425 return -EINVAL;426 427 if (!strncmp("NULL", new_tag, 4)) {428 acl->acl_tag[0] = '\0';429 return 0;430 }431 432 return snprintf(acl->acl_tag, MAX_ACL_TAG_SIZE, "%s", new_tag);433}434EXPORT_SYMBOL(core_tpg_set_initiator_node_tag);435 436static void core_tpg_lun_ref_release(struct percpu_ref *ref)437{438 struct se_lun *lun = container_of(ref, struct se_lun, lun_ref);439 440 complete(&lun->lun_shutdown_comp);441}442 443static int target_tpg_register_rtpi(struct se_portal_group *se_tpg)444{445 u32 val;446 int ret;447 448 if (se_tpg->rtpi_manual) {449 ret = xa_insert(&tpg_xa, se_tpg->tpg_rtpi, se_tpg, GFP_KERNEL);450 if (ret) {451 pr_info("%s_TPG[%hu] - Can not set RTPI %#x, it is already busy",452 se_tpg->se_tpg_tfo->fabric_name,453 se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg),454 se_tpg->tpg_rtpi);455 return -EINVAL;456 }457 } else {458 ret = xa_alloc(&tpg_xa, &val, se_tpg,459 XA_LIMIT(1, USHRT_MAX), GFP_KERNEL);460 if (!ret)461 se_tpg->tpg_rtpi = val;462 }463 464 return ret;465}466 467static void target_tpg_deregister_rtpi(struct se_portal_group *se_tpg)468{469 if (se_tpg->tpg_rtpi && se_tpg->enabled)470 xa_erase(&tpg_xa, se_tpg->tpg_rtpi);471}472 473int target_tpg_enable(struct se_portal_group *se_tpg)474{475 int ret;476 477 ret = target_tpg_register_rtpi(se_tpg);478 if (ret)479 return ret;480 481 ret = se_tpg->se_tpg_tfo->fabric_enable_tpg(se_tpg, true);482 if (ret) {483 target_tpg_deregister_rtpi(se_tpg);484 return ret;485 }486 487 se_tpg->enabled = true;488 489 return 0;490}491 492int target_tpg_disable(struct se_portal_group *se_tpg)493{494 int ret;495 496 target_tpg_deregister_rtpi(se_tpg);497 498 ret = se_tpg->se_tpg_tfo->fabric_enable_tpg(se_tpg, false);499 if (!ret)500 se_tpg->enabled = false;501 502 return ret;503}504 505/* Does not change se_wwn->priv. */506int core_tpg_register(507 struct se_wwn *se_wwn,508 struct se_portal_group *se_tpg,509 int proto_id)510{511 int ret;512 513 if (!se_tpg)514 return -EINVAL;515 /*516 * For the typical case where core_tpg_register() is called by a517 * fabric driver from target_core_fabric_ops->fabric_make_tpg()518 * configfs context, use the original tf_ops pointer already saved519 * by target-core in target_fabric_make_wwn().520 *521 * Otherwise, for special cases like iscsi-target discovery TPGs522 * the caller is responsible for setting ->se_tpg_tfo ahead of523 * calling core_tpg_register().524 */525 if (se_wwn)526 se_tpg->se_tpg_tfo = se_wwn->wwn_tf->tf_ops;527 528 if (!se_tpg->se_tpg_tfo) {529 pr_err("Unable to locate se_tpg->se_tpg_tfo pointer\n");530 return -EINVAL;531 }532 533 INIT_HLIST_HEAD(&se_tpg->tpg_lun_hlist);534 se_tpg->proto_id = proto_id;535 se_tpg->se_tpg_wwn = se_wwn;536 atomic_set(&se_tpg->tpg_pr_ref_count, 0);537 INIT_LIST_HEAD(&se_tpg->acl_node_list);538 INIT_LIST_HEAD(&se_tpg->tpg_sess_list);539 spin_lock_init(&se_tpg->session_lock);540 mutex_init(&se_tpg->tpg_lun_mutex);541 mutex_init(&se_tpg->acl_node_mutex);542 543 if (se_tpg->proto_id >= 0) {544 se_tpg->tpg_virt_lun0 = core_tpg_alloc_lun(se_tpg, 0);545 if (IS_ERR(se_tpg->tpg_virt_lun0))546 return PTR_ERR(se_tpg->tpg_virt_lun0);547 548 ret = core_tpg_add_lun(se_tpg, se_tpg->tpg_virt_lun0,549 true, g_lun0_dev);550 if (ret < 0) {551 kfree(se_tpg->tpg_virt_lun0);552 return ret;553 }554 }555 556 pr_debug("TARGET_CORE[%s]: Allocated portal_group for endpoint: %s, "557 "Proto: %d, Portal Tag: %u\n", se_tpg->se_tpg_tfo->fabric_name,558 se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg) ?559 se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg) : NULL,560 se_tpg->proto_id, se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg));561 562 return 0;563}564EXPORT_SYMBOL(core_tpg_register);565 566int core_tpg_deregister(struct se_portal_group *se_tpg)567{568 const struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo;569 struct se_node_acl *nacl, *nacl_tmp;570 LIST_HEAD(node_list);571 572 pr_debug("TARGET_CORE[%s]: Deallocating portal_group for endpoint: %s, "573 "Proto: %d, Portal Tag: %u\n", tfo->fabric_name,574 tfo->tpg_get_wwn(se_tpg) ? tfo->tpg_get_wwn(se_tpg) : NULL,575 se_tpg->proto_id, tfo->tpg_get_tag(se_tpg));576 577 while (atomic_read(&se_tpg->tpg_pr_ref_count) != 0)578 cpu_relax();579 580 mutex_lock(&se_tpg->acl_node_mutex);581 list_splice_init(&se_tpg->acl_node_list, &node_list);582 mutex_unlock(&se_tpg->acl_node_mutex);583 /*584 * Release any remaining demo-mode generated se_node_acl that have585 * not been released because of TFO->tpg_check_demo_mode_cache() == 1586 * in transport_deregister_session().587 */588 list_for_each_entry_safe(nacl, nacl_tmp, &node_list, acl_list) {589 list_del_init(&nacl->acl_list);590 591 core_tpg_wait_for_nacl_pr_ref(nacl);592 core_free_device_list_for_node(nacl, se_tpg);593 kfree(nacl);594 }595 596 if (se_tpg->proto_id >= 0) {597 core_tpg_remove_lun(se_tpg, se_tpg->tpg_virt_lun0);598 kfree_rcu(se_tpg->tpg_virt_lun0, rcu_head);599 }600 601 target_tpg_deregister_rtpi(se_tpg);602 603 return 0;604}605EXPORT_SYMBOL(core_tpg_deregister);606 607struct se_lun *core_tpg_alloc_lun(608 struct se_portal_group *tpg,609 u64 unpacked_lun)610{611 struct se_lun *lun;612 613 lun = kzalloc(sizeof(*lun), GFP_KERNEL);614 if (!lun) {615 pr_err("Unable to allocate se_lun memory\n");616 return ERR_PTR(-ENOMEM);617 }618 lun->unpacked_lun = unpacked_lun;619 atomic_set(&lun->lun_acl_count, 0);620 init_completion(&lun->lun_shutdown_comp);621 INIT_LIST_HEAD(&lun->lun_deve_list);622 INIT_LIST_HEAD(&lun->lun_dev_link);623 atomic_set(&lun->lun_tg_pt_secondary_offline, 0);624 spin_lock_init(&lun->lun_deve_lock);625 mutex_init(&lun->lun_tg_pt_md_mutex);626 INIT_LIST_HEAD(&lun->lun_tg_pt_gp_link);627 spin_lock_init(&lun->lun_tg_pt_gp_lock);628 lun->lun_tpg = tpg;629 630 return lun;631}632 633int core_tpg_add_lun(634 struct se_portal_group *tpg,635 struct se_lun *lun,636 bool lun_access_ro,637 struct se_device *dev)638{639 int ret;640 641 ret = percpu_ref_init(&lun->lun_ref, core_tpg_lun_ref_release, 0,642 GFP_KERNEL);643 if (ret < 0)644 goto out;645 646 if (!(dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA) &&647 !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))648 target_attach_tg_pt_gp(lun, dev->t10_alua.default_tg_pt_gp);649 650 mutex_lock(&tpg->tpg_lun_mutex);651 652 spin_lock(&dev->se_port_lock);653 lun->lun_index = dev->dev_index;654 rcu_assign_pointer(lun->lun_se_dev, dev);655 dev->export_count++;656 list_add_tail(&lun->lun_dev_link, &dev->dev_sep_list);657 spin_unlock(&dev->se_port_lock);658 659 if (dev->dev_flags & DF_READ_ONLY)660 lun->lun_access_ro = true;661 else662 lun->lun_access_ro = lun_access_ro;663 if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))664 hlist_add_head_rcu(&lun->link, &tpg->tpg_lun_hlist);665 mutex_unlock(&tpg->tpg_lun_mutex);666 667 return 0;668 669out:670 return ret;671}672 673void core_tpg_remove_lun(674 struct se_portal_group *tpg,675 struct se_lun *lun)676{677 /*678 * rcu_dereference_raw protected by se_lun->lun_group symlink679 * reference to se_device->dev_group.680 */681 struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev);682 683 lun->lun_shutdown = true;684 685 core_clear_lun_from_tpg(lun, tpg);686 /*687 * Wait for any active I/O references to percpu se_lun->lun_ref to688 * be released. Also, se_lun->lun_ref is now used by PR and ALUA689 * logic when referencing a remote target port during ALL_TGT_PT=1690 * and generating UNIT_ATTENTIONs for ALUA access state transition.691 */692 transport_clear_lun_ref(lun);693 694 mutex_lock(&tpg->tpg_lun_mutex);695 if (lun->lun_se_dev) {696 target_detach_tg_pt_gp(lun);697 698 spin_lock(&dev->se_port_lock);699 list_del(&lun->lun_dev_link);700 dev->export_count--;701 rcu_assign_pointer(lun->lun_se_dev, NULL);702 spin_unlock(&dev->se_port_lock);703 }704 if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))705 hlist_del_rcu(&lun->link);706 707 lun->lun_shutdown = false;708 mutex_unlock(&tpg->tpg_lun_mutex);709 710 percpu_ref_exit(&lun->lun_ref);711}712