These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / target / target_core_alua.c
index 4f8d4d4..49aba4a 100644 (file)
 #include <linux/configfs.h>
 #include <linux/export.h>
 #include <linux/file.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_proto.h>
 #include <asm/unaligned.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_backend.h>
 #include <target/target_core_fabric.h>
-#include <target/target_core_configfs.h>
 
 #include "target_core_internal.h"
 #include "target_core_alua.h"
 static sense_reason_t core_alua_check_transition(int state, int valid,
                                                 int *primary);
 static int core_alua_set_tg_pt_secondary_state(
-               struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
-               struct se_port *port, int explicit, int offline);
+               struct se_lun *lun, int explicit, int offline);
 
 static char *core_alua_dump_state(int state);
 
+static void __target_attach_tg_pt_gp(struct se_lun *lun,
+               struct t10_alua_tg_pt_gp *tg_pt_gp);
+
 static u16 alua_lu_gps_counter;
 static u32 alua_lu_gps_count;
 
@@ -146,9 +146,8 @@ sense_reason_t
 target_emulate_report_target_port_groups(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
-       struct se_port *port;
        struct t10_alua_tg_pt_gp *tg_pt_gp;
-       struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+       struct se_lun *lun;
        unsigned char *buf;
        u32 rd_len = 0, off;
        int ext_hdr = (cmd->t_task_cdb[1] & 0x20);
@@ -223,9 +222,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
                rd_len += 8;
 
                spin_lock(&tg_pt_gp->tg_pt_gp_lock);
-               list_for_each_entry(tg_pt_gp_mem, &tg_pt_gp->tg_pt_gp_mem_list,
-                               tg_pt_gp_mem_list) {
-                       port = tg_pt_gp_mem->tg_pt;
+               list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list,
+                               lun_tg_pt_gp_link) {
                        /*
                         * Start Target Port descriptor format
                         *
@@ -235,8 +233,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
                        /*
                         * Set RELATIVE TARGET PORT IDENTIFIER
                         */
-                       buf[off++] = ((port->sep_rtpi >> 8) & 0xff);
-                       buf[off++] = (port->sep_rtpi & 0xff);
+                       buf[off++] = ((lun->lun_rtpi >> 8) & 0xff);
+                       buf[off++] = (lun->lun_rtpi & 0xff);
                        rd_len += 4;
                }
                spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
@@ -260,15 +258,11 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd)
                 * this CDB was received upon to determine this value individually
                 * for ALUA target port group.
                 */
-               port = cmd->se_lun->lun_sep;
-               tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
-               if (tg_pt_gp_mem) {
-                       spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
-                       tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
-                       if (tg_pt_gp)
-                               buf[5] = tg_pt_gp->tg_pt_gp_implicit_trans_secs;
-                       spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
-               }
+               spin_lock(&cmd->se_lun->lun_tg_pt_gp_lock);
+               tg_pt_gp = cmd->se_lun->lun_tg_pt_gp;
+               if (tg_pt_gp)
+                       buf[5] = tg_pt_gp->tg_pt_gp_implicit_trans_secs;
+               spin_unlock(&cmd->se_lun->lun_tg_pt_gp_lock);
        }
        transport_kunmap_data_sg(cmd);
 
@@ -285,10 +279,9 @@ sense_reason_t
 target_emulate_set_target_port_groups(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
-       struct se_port *port, *l_port = cmd->se_lun->lun_sep;
+       struct se_lun *l_lun = cmd->se_lun;
        struct se_node_acl *nacl = cmd->se_sess->se_node_acl;
        struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *l_tg_pt_gp;
-       struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *l_tg_pt_gp_mem;
        unsigned char *buf;
        unsigned char *ptr;
        sense_reason_t rc = TCM_NO_SENSE;
@@ -296,9 +289,6 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
        int alua_access_state, primary = 0, valid_states;
        u16 tg_pt_id, rtpi;
 
-       if (!l_port)
-               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-
        if (cmd->data_length < 4) {
                pr_warn("SET TARGET PORT GROUPS parameter list length %u too"
                        " small\n", cmd->data_length);
@@ -313,29 +303,24 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
         * Determine if explicit ALUA via SET_TARGET_PORT_GROUPS is allowed
         * for the local tg_pt_gp.
         */
-       l_tg_pt_gp_mem = l_port->sep_alua_tg_pt_gp_mem;
-       if (!l_tg_pt_gp_mem) {
-               pr_err("Unable to access l_port->sep_alua_tg_pt_gp_mem\n");
-               rc = TCM_UNSUPPORTED_SCSI_OPCODE;
-               goto out;
-       }
-       spin_lock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock);
-       l_tg_pt_gp = l_tg_pt_gp_mem->tg_pt_gp;
+       spin_lock(&l_lun->lun_tg_pt_gp_lock);
+       l_tg_pt_gp = l_lun->lun_tg_pt_gp;
        if (!l_tg_pt_gp) {
-               spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock);
-               pr_err("Unable to access *l_tg_pt_gp_mem->tg_pt_gp\n");
+               spin_unlock(&l_lun->lun_tg_pt_gp_lock);
+               pr_err("Unable to access l_lun->tg_pt_gp\n");
                rc = TCM_UNSUPPORTED_SCSI_OPCODE;
                goto out;
        }
-       spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock);
 
        if (!(l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA)) {
+               spin_unlock(&l_lun->lun_tg_pt_gp_lock);
                pr_debug("Unable to process SET_TARGET_PORT_GROUPS"
                                " while TPGS_EXPLICIT_ALUA is disabled\n");
                rc = TCM_UNSUPPORTED_SCSI_OPCODE;
                goto out;
        }
        valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states;
+       spin_unlock(&l_lun->lun_tg_pt_gp_lock);
 
        ptr = &buf[4]; /* Skip over RESERVED area in header */
 
@@ -397,7 +382,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
                                spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
 
                                if (!core_alua_do_port_transition(tg_pt_gp,
-                                               dev, l_port, nacl,
+                                               dev, l_lun, nacl,
                                                alua_access_state, 1))
                                        found = true;
 
@@ -407,6 +392,8 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
                        }
                        spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
                } else {
+                       struct se_lun *lun;
+
                        /*
                         * Extract the RELATIVE TARGET PORT IDENTIFIER to identify
                         * the Target Port in question for the the incoming
@@ -418,17 +405,16 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
                         * for the struct se_device storage object.
                         */
                        spin_lock(&dev->se_port_lock);
-                       list_for_each_entry(port, &dev->dev_sep_list,
-                                                       sep_list) {
-                               if (port->sep_rtpi != rtpi)
+                       list_for_each_entry(lun, &dev->dev_sep_list,
+                                                       lun_dev_link) {
+                               if (lun->lun_rtpi != rtpi)
                                        continue;
 
-                               tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
-
+                               // XXX: racy unlock
                                spin_unlock(&dev->se_port_lock);
 
                                if (!core_alua_set_tg_pt_secondary_state(
-                                               tg_pt_gp_mem, port, 1, 1))
+                                               lun, 1, 1))
                                        found = true;
 
                                spin_lock(&dev->se_port_lock);
@@ -697,9 +683,7 @@ target_alua_state_check(struct se_cmd *cmd)
        struct se_device *dev = cmd->se_dev;
        unsigned char *cdb = cmd->t_task_cdb;
        struct se_lun *lun = cmd->se_lun;
-       struct se_port *port = lun->lun_sep;
        struct t10_alua_tg_pt_gp *tg_pt_gp;
-       struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
        int out_alua_state, nonop_delay_msecs;
 
        if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)
@@ -707,33 +691,27 @@ target_alua_state_check(struct se_cmd *cmd)
        if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return 0;
 
-       if (!port)
-               return 0;
        /*
         * First, check for a struct se_port specific secondary ALUA target port
         * access state: OFFLINE
         */
-       if (atomic_read(&port->sep_tg_pt_secondary_offline)) {
+       if (atomic_read(&lun->lun_tg_pt_secondary_offline)) {
                pr_debug("ALUA: Got secondary offline status for local"
                                " target port\n");
                set_ascq(cmd, ASCQ_04H_ALUA_OFFLINE);
                return TCM_CHECK_CONDITION_NOT_READY;
        }
-        /*
-        * Second, obtain the struct t10_alua_tg_pt_gp_member pointer to the
-        * ALUA target port group, to obtain current ALUA access state.
-        * Otherwise look for the underlying struct se_device association with
-        * a ALUA logical unit group.
-        */
-       tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
-       if (!tg_pt_gp_mem)
+
+       if (!lun->lun_tg_pt_gp)
                return 0;
 
-       spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
-       tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+       spin_lock(&lun->lun_tg_pt_gp_lock);
+       tg_pt_gp = lun->lun_tg_pt_gp;
        out_alua_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state);
        nonop_delay_msecs = tg_pt_gp->tg_pt_gp_nonop_delay_msecs;
-       spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+
+       // XXX: keeps using tg_pt_gp witout reference after unlock
+       spin_unlock(&lun->lun_tg_pt_gp_lock);
        /*
         * Process ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED in a separate conditional
         * statement so the compiler knows explicitly to check this case first.
@@ -765,7 +743,7 @@ target_alua_state_check(struct se_cmd *cmd)
                break;
        /*
         * OFFLINE is a secondary ALUA target port group access state, that is
-        * handled above with struct se_port->sep_tg_pt_secondary_offline=1
+        * handled above with struct se_lun->lun_tg_pt_secondary_offline=1
         */
        case ALUA_ACCESS_STATE_OFFLINE:
        default:
@@ -907,10 +885,6 @@ int core_alua_check_nonop_delay(
 }
 EXPORT_SYMBOL(core_alua_check_nonop_delay);
 
-/*
- * Called with tg_pt_gp->tg_pt_gp_md_mutex or tg_pt_gp_mem->sep_tg_pt_md_mutex
- *
- */
 static int core_alua_write_tpg_metadata(
        const char *path,
        unsigned char *md_buf,
@@ -966,22 +940,15 @@ static int core_alua_update_tpg_primary_metadata(
        return rc;
 }
 
-static void core_alua_do_transition_tg_pt_work(struct work_struct *work)
+static void core_alua_queue_state_change_ua(struct t10_alua_tg_pt_gp *tg_pt_gp)
 {
-       struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(work,
-               struct t10_alua_tg_pt_gp, tg_pt_gp_transition_work.work);
-       struct se_device *dev = tg_pt_gp->tg_pt_gp_dev;
        struct se_dev_entry *se_deve;
+       struct se_lun *lun;
        struct se_lun_acl *lacl;
-       struct se_port *port;
-       struct t10_alua_tg_pt_gp_member *mem;
-       bool explicit = (tg_pt_gp->tg_pt_gp_alua_access_status ==
-                        ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG);
 
        spin_lock(&tg_pt_gp->tg_pt_gp_lock);
-       list_for_each_entry(mem, &tg_pt_gp->tg_pt_gp_mem_list,
-                               tg_pt_gp_mem_list) {
-               port = mem->tg_pt;
+       list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list,
+                               lun_tg_pt_gp_link) {
                /*
                 * After an implicit target port asymmetric access state
                 * change, a device server shall establish a unit attention
@@ -996,38 +963,58 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work)
                 * every I_T nexus other than the I_T nexus on which the SET
                 * TARGET PORT GROUPS command
                 */
-               atomic_inc_mb(&mem->tg_pt_gp_mem_ref_cnt);
+               if (!percpu_ref_tryget_live(&lun->lun_ref))
+                       continue;
                spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
 
-               spin_lock_bh(&port->sep_alua_lock);
-               list_for_each_entry(se_deve, &port->sep_alua_list,
-                                       alua_port_list) {
-                       lacl = se_deve->se_lun_acl;
+               spin_lock(&lun->lun_deve_lock);
+               list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link) {
+                       lacl = rcu_dereference_check(se_deve->se_lun_acl,
+                                       lockdep_is_held(&lun->lun_deve_lock));
+
                        /*
-                        * se_deve->se_lun_acl pointer may be NULL for a
-                        * entry created without explicit Node+MappedLUN ACLs
+                        * spc4r37 p.242:
+                        * After an explicit target port asymmetric access
+                        * state change, a device server shall establish a
+                        * unit attention condition with the additional sense
+                        * code set to ASYMMETRIC ACCESS STATE CHANGED for
+                        * the initiator port associated with every I_T nexus
+                        * other than the I_T nexus on which the SET TARGET
+                        * PORT GROUPS command was received.
                         */
-                       if (!lacl)
-                               continue;
-
                        if ((tg_pt_gp->tg_pt_gp_alua_access_status ==
                             ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG) &&
-                          (tg_pt_gp->tg_pt_gp_alua_nacl != NULL) &&
-                           (tg_pt_gp->tg_pt_gp_alua_nacl == lacl->se_lun_nacl) &&
-                          (tg_pt_gp->tg_pt_gp_alua_port != NULL) &&
-                           (tg_pt_gp->tg_pt_gp_alua_port == port))
+                          (tg_pt_gp->tg_pt_gp_alua_lun != NULL) &&
+                           (tg_pt_gp->tg_pt_gp_alua_lun == lun))
                                continue;
 
-                       core_scsi3_ua_allocate(lacl->se_lun_nacl,
-                               se_deve->mapped_lun, 0x2A,
+                       /*
+                        * se_deve->se_lun_acl pointer may be NULL for a
+                        * entry created without explicit Node+MappedLUN ACLs
+                        */
+                       if (lacl && (tg_pt_gp->tg_pt_gp_alua_nacl != NULL) &&
+                           (tg_pt_gp->tg_pt_gp_alua_nacl == lacl->se_lun_nacl))
+                               continue;
+
+                       core_scsi3_ua_allocate(se_deve, 0x2A,
                                ASCQ_2AH_ASYMMETRIC_ACCESS_STATE_CHANGED);
                }
-               spin_unlock_bh(&port->sep_alua_lock);
+               spin_unlock(&lun->lun_deve_lock);
 
                spin_lock(&tg_pt_gp->tg_pt_gp_lock);
-               atomic_dec_mb(&mem->tg_pt_gp_mem_ref_cnt);
+               percpu_ref_put(&lun->lun_ref);
        }
        spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+}
+
+static void core_alua_do_transition_tg_pt_work(struct work_struct *work)
+{
+       struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(work,
+               struct t10_alua_tg_pt_gp, tg_pt_gp_transition_work.work);
+       struct se_device *dev = tg_pt_gp->tg_pt_gp_dev;
+       bool explicit = (tg_pt_gp->tg_pt_gp_alua_access_status ==
+                        ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG);
+
        /*
         * Update the ALUA metadata buf that has been allocated in
         * core_alua_do_port_transition(), this metadata will be written
@@ -1057,6 +1044,9 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work)
                tg_pt_gp->tg_pt_gp_id,
                core_alua_dump_state(tg_pt_gp->tg_pt_gp_alua_previous_state),
                core_alua_dump_state(tg_pt_gp->tg_pt_gp_alua_pending_state));
+
+       core_alua_queue_state_change_ua(tg_pt_gp);
+
        spin_lock(&dev->t10_alua.tg_pt_gps_lock);
        atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt);
        spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
@@ -1109,6 +1099,8 @@ static int core_alua_do_transition_tg_pt(
                                ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG :
                                ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA;
 
+       core_alua_queue_state_change_ua(tg_pt_gp);
+
        /*
         * Check for the optional ALUA primary state transition delay
         */
@@ -1143,7 +1135,7 @@ static int core_alua_do_transition_tg_pt(
 int core_alua_do_port_transition(
        struct t10_alua_tg_pt_gp *l_tg_pt_gp,
        struct se_device *l_dev,
-       struct se_port *l_port,
+       struct se_lun *l_lun,
        struct se_node_acl *l_nacl,
        int new_state,
        int explicit)
@@ -1173,7 +1165,7 @@ int core_alua_do_port_transition(
                 * core_alua_do_transition_tg_pt() will always return
                 * success.
                 */
-               l_tg_pt_gp->tg_pt_gp_alua_port = l_port;
+               l_tg_pt_gp->tg_pt_gp_alua_lun = l_lun;
                l_tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl;
                rc = core_alua_do_transition_tg_pt(l_tg_pt_gp,
                                                   new_state, explicit);
@@ -1212,10 +1204,10 @@ int core_alua_do_port_transition(
                                continue;
 
                        if (l_tg_pt_gp == tg_pt_gp) {
-                               tg_pt_gp->tg_pt_gp_alua_port = l_port;
+                               tg_pt_gp->tg_pt_gp_alua_lun = l_lun;
                                tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl;
                        } else {
-                               tg_pt_gp->tg_pt_gp_alua_port = NULL;
+                               tg_pt_gp->tg_pt_gp_alua_lun = NULL;
                                tg_pt_gp->tg_pt_gp_alua_nacl = NULL;
                        }
                        atomic_inc_mb(&tg_pt_gp->tg_pt_gp_ref_cnt);
@@ -1252,22 +1244,20 @@ int core_alua_do_port_transition(
        return rc;
 }
 
-/*
- * Called with tg_pt_gp_mem->sep_tg_pt_md_mutex held
- */
-static int core_alua_update_tpg_secondary_metadata(
-       struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
-       struct se_port *port)
+static int core_alua_update_tpg_secondary_metadata(struct se_lun *lun)
 {
+       struct se_portal_group *se_tpg = lun->lun_tpg;
        unsigned char *md_buf;
-       struct se_portal_group *se_tpg = port->sep_tpg;
        char path[ALUA_METADATA_PATH_LEN], wwn[ALUA_SECONDARY_METADATA_WWN_LEN];
        int len, rc;
 
+       mutex_lock(&lun->lun_tg_pt_md_mutex);
+
        md_buf = kzalloc(ALUA_MD_BUF_LEN, GFP_KERNEL);
        if (!md_buf) {
                pr_err("Unable to allocate buf for ALUA metadata\n");
-               return -ENOMEM;
+               rc = -ENOMEM;
+               goto out_unlock;
        }
 
        memset(path, 0, ALUA_METADATA_PATH_LEN);
@@ -1282,32 +1272,33 @@ static int core_alua_update_tpg_secondary_metadata(
 
        len = snprintf(md_buf, ALUA_MD_BUF_LEN, "alua_tg_pt_offline=%d\n"
                        "alua_tg_pt_status=0x%02x\n",
-                       atomic_read(&port->sep_tg_pt_secondary_offline),
-                       port->sep_tg_pt_secondary_stat);
+                       atomic_read(&lun->lun_tg_pt_secondary_offline),
+                       lun->lun_tg_pt_secondary_stat);
 
-       snprintf(path, ALUA_METADATA_PATH_LEN, "/var/target/alua/%s/%s/lun_%u",
+       snprintf(path, ALUA_METADATA_PATH_LEN, "/var/target/alua/%s/%s/lun_%llu",
                        se_tpg->se_tpg_tfo->get_fabric_name(), wwn,
-                       port->sep_lun->unpacked_lun);
+                       lun->unpacked_lun);
 
        rc = core_alua_write_tpg_metadata(path, md_buf, len);
        kfree(md_buf);
 
+out_unlock:
+       mutex_unlock(&lun->lun_tg_pt_md_mutex);
        return rc;
 }
 
 static int core_alua_set_tg_pt_secondary_state(
-       struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
-       struct se_port *port,
+       struct se_lun *lun,
        int explicit,
        int offline)
 {
        struct t10_alua_tg_pt_gp *tg_pt_gp;
        int trans_delay_msecs;
 
-       spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
-       tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+       spin_lock(&lun->lun_tg_pt_gp_lock);
+       tg_pt_gp = lun->lun_tg_pt_gp;
        if (!tg_pt_gp) {
-               spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+               spin_unlock(&lun->lun_tg_pt_gp_lock);
                pr_err("Unable to complete secondary state"
                                " transition\n");
                return -EINVAL;
@@ -1315,14 +1306,14 @@ static int core_alua_set_tg_pt_secondary_state(
        trans_delay_msecs = tg_pt_gp->tg_pt_gp_trans_delay_msecs;
        /*
         * Set the secondary ALUA target port access state to OFFLINE
-        * or release the previously secondary state for struct se_port
+        * or release the previously secondary state for struct se_lun
         */
        if (offline)
-               atomic_set(&port->sep_tg_pt_secondary_offline, 1);
+               atomic_set(&lun->lun_tg_pt_secondary_offline, 1);
        else
-               atomic_set(&port->sep_tg_pt_secondary_offline, 0);
+               atomic_set(&lun->lun_tg_pt_secondary_offline, 0);
 
-       port->sep_tg_pt_secondary_stat = (explicit) ?
+       lun->lun_tg_pt_secondary_stat = (explicit) ?
                        ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG :
                        ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA;
 
@@ -1331,7 +1322,7 @@ static int core_alua_set_tg_pt_secondary_state(
                "implicit", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item),
                tg_pt_gp->tg_pt_gp_id, (offline) ? "OFFLINE" : "ONLINE");
 
-       spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+       spin_unlock(&lun->lun_tg_pt_gp_lock);
        /*
         * Do the optional transition delay after we set the secondary
         * ALUA access state.
@@ -1342,11 +1333,8 @@ static int core_alua_set_tg_pt_secondary_state(
         * See if we need to update the ALUA fabric port metadata for
         * secondary state and status
         */
-       if (port->sep_tg_pt_secondary_write_md) {
-               mutex_lock(&port->sep_tg_pt_md_mutex);
-               core_alua_update_tpg_secondary_metadata(tg_pt_gp_mem, port);
-               mutex_unlock(&port->sep_tg_pt_md_mutex);
-       }
+       if (lun->lun_tg_pt_secondary_write_md)
+               core_alua_update_tpg_secondary_metadata(lun);
 
        return 0;
 }
@@ -1700,7 +1688,7 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(struct se_device *dev,
                return NULL;
        }
        INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_list);
-       INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_mem_list);
+       INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_lun_list);
        mutex_init(&tg_pt_gp->tg_pt_gp_md_mutex);
        spin_lock_init(&tg_pt_gp->tg_pt_gp_lock);
        atomic_set(&tg_pt_gp->tg_pt_gp_ref_cnt, 0);
@@ -1794,32 +1782,11 @@ again:
        return 0;
 }
 
-struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem(
-       struct se_port *port)
-{
-       struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
-
-       tg_pt_gp_mem = kmem_cache_zalloc(t10_alua_tg_pt_gp_mem_cache,
-                               GFP_KERNEL);
-       if (!tg_pt_gp_mem) {
-               pr_err("Unable to allocate struct t10_alua_tg_pt_gp_member\n");
-               return ERR_PTR(-ENOMEM);
-       }
-       INIT_LIST_HEAD(&tg_pt_gp_mem->tg_pt_gp_mem_list);
-       spin_lock_init(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
-       atomic_set(&tg_pt_gp_mem->tg_pt_gp_mem_ref_cnt, 0);
-
-       tg_pt_gp_mem->tg_pt = port;
-       port->sep_alua_tg_pt_gp_mem = tg_pt_gp_mem;
-
-       return tg_pt_gp_mem;
-}
-
 void core_alua_free_tg_pt_gp(
        struct t10_alua_tg_pt_gp *tg_pt_gp)
 {
        struct se_device *dev = tg_pt_gp->tg_pt_gp_dev;
-       struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *tg_pt_gp_mem_tmp;
+       struct se_lun *lun, *next;
 
        /*
         * Once we have reached this point, config_item_put() has already
@@ -1850,30 +1817,24 @@ void core_alua_free_tg_pt_gp(
         * struct se_port.
         */
        spin_lock(&tg_pt_gp->tg_pt_gp_lock);
-       list_for_each_entry_safe(tg_pt_gp_mem, tg_pt_gp_mem_tmp,
-                       &tg_pt_gp->tg_pt_gp_mem_list, tg_pt_gp_mem_list) {
-               if (tg_pt_gp_mem->tg_pt_gp_assoc) {
-                       list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list);
-                       tg_pt_gp->tg_pt_gp_members--;
-                       tg_pt_gp_mem->tg_pt_gp_assoc = 0;
-               }
+       list_for_each_entry_safe(lun, next,
+                       &tg_pt_gp->tg_pt_gp_lun_list, lun_tg_pt_gp_link) {
+               list_del_init(&lun->lun_tg_pt_gp_link);
+               tg_pt_gp->tg_pt_gp_members--;
+
                spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
                /*
-                * tg_pt_gp_mem is associated with a single
-                * se_port->sep_alua_tg_pt_gp_mem, and is released via
-                * core_alua_free_tg_pt_gp_mem().
-                *
                 * If the passed tg_pt_gp does NOT match the default_tg_pt_gp,
                 * assume we want to re-associate a given tg_pt_gp_mem with
                 * default_tg_pt_gp.
                 */
-               spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+               spin_lock(&lun->lun_tg_pt_gp_lock);
                if (tg_pt_gp != dev->t10_alua.default_tg_pt_gp) {
-                       __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem,
+                       __target_attach_tg_pt_gp(lun,
                                        dev->t10_alua.default_tg_pt_gp);
                } else
-                       tg_pt_gp_mem->tg_pt_gp = NULL;
-               spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+                       lun->lun_tg_pt_gp = NULL;
+               spin_unlock(&lun->lun_tg_pt_gp_lock);
 
                spin_lock(&tg_pt_gp->tg_pt_gp_lock);
        }
@@ -1882,35 +1843,6 @@ void core_alua_free_tg_pt_gp(
        kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp);
 }
 
-void core_alua_free_tg_pt_gp_mem(struct se_port *port)
-{
-       struct t10_alua_tg_pt_gp *tg_pt_gp;
-       struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
-
-       tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
-       if (!tg_pt_gp_mem)
-               return;
-
-       while (atomic_read(&tg_pt_gp_mem->tg_pt_gp_mem_ref_cnt))
-               cpu_relax();
-
-       spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
-       tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
-       if (tg_pt_gp) {
-               spin_lock(&tg_pt_gp->tg_pt_gp_lock);
-               if (tg_pt_gp_mem->tg_pt_gp_assoc) {
-                       list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list);
-                       tg_pt_gp->tg_pt_gp_members--;
-                       tg_pt_gp_mem->tg_pt_gp_assoc = 0;
-               }
-               spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
-               tg_pt_gp_mem->tg_pt_gp = NULL;
-       }
-       spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
-
-       kmem_cache_free(t10_alua_tg_pt_gp_mem_cache, tg_pt_gp_mem);
-}
-
 static struct t10_alua_tg_pt_gp *core_alua_get_tg_pt_gp_by_name(
                struct se_device *dev, const char *name)
 {
@@ -1944,50 +1876,65 @@ static void core_alua_put_tg_pt_gp_from_name(
        spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
 }
 
-/*
- * Called with struct t10_alua_tg_pt_gp_member->tg_pt_gp_mem_lock held
- */
-void __core_alua_attach_tg_pt_gp_mem(
-       struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
-       struct t10_alua_tg_pt_gp *tg_pt_gp)
+static void __target_attach_tg_pt_gp(struct se_lun *lun,
+               struct t10_alua_tg_pt_gp *tg_pt_gp)
 {
+       struct se_dev_entry *se_deve;
+
+       assert_spin_locked(&lun->lun_tg_pt_gp_lock);
+
        spin_lock(&tg_pt_gp->tg_pt_gp_lock);
-       tg_pt_gp_mem->tg_pt_gp = tg_pt_gp;
-       tg_pt_gp_mem->tg_pt_gp_assoc = 1;
-       list_add_tail(&tg_pt_gp_mem->tg_pt_gp_mem_list,
-                       &tg_pt_gp->tg_pt_gp_mem_list);
+       lun->lun_tg_pt_gp = tg_pt_gp;
+       list_add_tail(&lun->lun_tg_pt_gp_link, &tg_pt_gp->tg_pt_gp_lun_list);
        tg_pt_gp->tg_pt_gp_members++;
+       spin_lock(&lun->lun_deve_lock);
+       list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link)
+               core_scsi3_ua_allocate(se_deve, 0x3f,
+                                      ASCQ_3FH_INQUIRY_DATA_HAS_CHANGED);
+       spin_unlock(&lun->lun_deve_lock);
        spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
 }
 
-/*
- * Called with struct t10_alua_tg_pt_gp_member->tg_pt_gp_mem_lock held
- */
-static void __core_alua_drop_tg_pt_gp_mem(
-       struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
-       struct t10_alua_tg_pt_gp *tg_pt_gp)
+void target_attach_tg_pt_gp(struct se_lun *lun,
+               struct t10_alua_tg_pt_gp *tg_pt_gp)
 {
+       spin_lock(&lun->lun_tg_pt_gp_lock);
+       __target_attach_tg_pt_gp(lun, tg_pt_gp);
+       spin_unlock(&lun->lun_tg_pt_gp_lock);
+}
+
+static void __target_detach_tg_pt_gp(struct se_lun *lun,
+               struct t10_alua_tg_pt_gp *tg_pt_gp)
+{
+       assert_spin_locked(&lun->lun_tg_pt_gp_lock);
+
        spin_lock(&tg_pt_gp->tg_pt_gp_lock);
-       list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list);
-       tg_pt_gp_mem->tg_pt_gp = NULL;
-       tg_pt_gp_mem->tg_pt_gp_assoc = 0;
+       list_del_init(&lun->lun_tg_pt_gp_link);
        tg_pt_gp->tg_pt_gp_members--;
        spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+
+       lun->lun_tg_pt_gp = NULL;
 }
 
-ssize_t core_alua_show_tg_pt_gp_info(struct se_port *port, char *page)
+void target_detach_tg_pt_gp(struct se_lun *lun)
+{
+       struct t10_alua_tg_pt_gp *tg_pt_gp;
+
+       spin_lock(&lun->lun_tg_pt_gp_lock);
+       tg_pt_gp = lun->lun_tg_pt_gp;
+       if (tg_pt_gp)
+               __target_detach_tg_pt_gp(lun, tg_pt_gp);
+       spin_unlock(&lun->lun_tg_pt_gp_lock);
+}
+
+ssize_t core_alua_show_tg_pt_gp_info(struct se_lun *lun, char *page)
 {
        struct config_item *tg_pt_ci;
        struct t10_alua_tg_pt_gp *tg_pt_gp;
-       struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
        ssize_t len = 0;
 
-       tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
-       if (!tg_pt_gp_mem)
-               return len;
-
-       spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
-       tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+       spin_lock(&lun->lun_tg_pt_gp_lock);
+       tg_pt_gp = lun->lun_tg_pt_gp;
        if (tg_pt_gp) {
                tg_pt_ci = &tg_pt_gp->tg_pt_gp_group.cg_item;
                len += sprintf(page, "TG Port Alias: %s\nTG Port Group ID:"
@@ -1999,34 +1946,33 @@ ssize_t core_alua_show_tg_pt_gp_info(struct se_port *port, char *page)
                                        &tg_pt_gp->tg_pt_gp_alua_access_state)),
                        core_alua_dump_status(
                                tg_pt_gp->tg_pt_gp_alua_access_status),
-                       (atomic_read(&port->sep_tg_pt_secondary_offline)) ?
+                       atomic_read(&lun->lun_tg_pt_secondary_offline) ?
                        "Offline" : "None",
-                       core_alua_dump_status(port->sep_tg_pt_secondary_stat));
+                       core_alua_dump_status(lun->lun_tg_pt_secondary_stat));
        }
-       spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+       spin_unlock(&lun->lun_tg_pt_gp_lock);
 
        return len;
 }
 
 ssize_t core_alua_store_tg_pt_gp_info(
-       struct se_port *port,
+       struct se_lun *lun,
        const char *page,
        size_t count)
 {
-       struct se_portal_group *tpg;
-       struct se_lun *lun;
-       struct se_device *dev = port->sep_lun->lun_se_dev;
+       struct se_portal_group *tpg = lun->lun_tpg;
+       /*
+        * rcu_dereference_raw protected by se_lun->lun_group symlink
+        * reference to se_device->dev_group.
+        */
+       struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev);
        struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *tg_pt_gp_new = NULL;
-       struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
        unsigned char buf[TG_PT_GROUP_NAME_BUF];
        int move = 0;
 
-       tpg = port->sep_tpg;
-       lun = port->sep_lun;
-
-       tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
-       if (!tg_pt_gp_mem)
-               return 0;
+       if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH ||
+           (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))
+               return -ENODEV;
 
        if (count > TG_PT_GROUP_NAME_BUF) {
                pr_err("ALUA Target Port Group alias too large!\n");
@@ -2050,8 +1996,8 @@ ssize_t core_alua_store_tg_pt_gp_info(
                        return -ENODEV;
        }
 
-       spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
-       tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+       spin_lock(&lun->lun_tg_pt_gp_lock);
+       tg_pt_gp = lun->lun_tg_pt_gp;
        if (tg_pt_gp) {
                /*
                 * Clearing an existing tg_pt_gp association, and replacing
@@ -2069,24 +2015,19 @@ ssize_t core_alua_store_tg_pt_gp_info(
                                        &tg_pt_gp->tg_pt_gp_group.cg_item),
                                tg_pt_gp->tg_pt_gp_id);
 
-                       __core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp);
-                       __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem,
+                       __target_detach_tg_pt_gp(lun, tg_pt_gp);
+                       __target_attach_tg_pt_gp(lun,
                                        dev->t10_alua.default_tg_pt_gp);
-                       spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+                       spin_unlock(&lun->lun_tg_pt_gp_lock);
 
                        return count;
                }
-               /*
-                * Removing existing association of tg_pt_gp_mem with tg_pt_gp
-                */
-               __core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp);
+               __target_detach_tg_pt_gp(lun, tg_pt_gp);
                move = 1;
        }
-       /*
-        * Associate tg_pt_gp_mem with tg_pt_gp_new.
-        */
-       __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp_new);
-       spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+
+       __target_attach_tg_pt_gp(lun, tg_pt_gp_new);
+       spin_unlock(&lun->lun_tg_pt_gp_lock);
        pr_debug("Target_Core_ConfigFS: %s %s/tpgt_%hu/%s to ALUA"
                " Target Port Group: alua/%s, ID: %hu\n", (move) ?
                "Moving" : "Adding", tpg->se_tpg_tfo->tpg_get_wwn(tpg),
@@ -2269,11 +2210,8 @@ ssize_t core_alua_store_preferred_bit(
 
 ssize_t core_alua_show_offline_bit(struct se_lun *lun, char *page)
 {
-       if (!lun->lun_sep)
-               return -ENODEV;
-
        return sprintf(page, "%d\n",
-               atomic_read(&lun->lun_sep->sep_tg_pt_secondary_offline));
+               atomic_read(&lun->lun_tg_pt_secondary_offline));
 }
 
 ssize_t core_alua_store_offline_bit(
@@ -2281,11 +2219,16 @@ ssize_t core_alua_store_offline_bit(
        const char *page,
        size_t count)
 {
-       struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+       /*
+        * rcu_dereference_raw protected by se_lun->lun_group symlink
+        * reference to se_device->dev_group.
+        */
+       struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev);
        unsigned long tmp;
        int ret;
 
-       if (!lun->lun_sep)
+       if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH ||
+           (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))
                return -ENODEV;
 
        ret = kstrtoul(page, 0, &tmp);
@@ -2298,14 +2241,8 @@ ssize_t core_alua_store_offline_bit(
                                tmp);
                return -EINVAL;
        }
-       tg_pt_gp_mem = lun->lun_sep->sep_alua_tg_pt_gp_mem;
-       if (!tg_pt_gp_mem) {
-               pr_err("Unable to locate *tg_pt_gp_mem\n");
-               return -EINVAL;
-       }
 
-       ret = core_alua_set_tg_pt_secondary_state(tg_pt_gp_mem,
-                       lun->lun_sep, 0, (int)tmp);
+       ret = core_alua_set_tg_pt_secondary_state(lun, 0, (int)tmp);
        if (ret < 0)
                return -EINVAL;
 
@@ -2316,7 +2253,7 @@ ssize_t core_alua_show_secondary_status(
        struct se_lun *lun,
        char *page)
 {
-       return sprintf(page, "%d\n", lun->lun_sep->sep_tg_pt_secondary_stat);
+       return sprintf(page, "%d\n", lun->lun_tg_pt_secondary_stat);
 }
 
 ssize_t core_alua_store_secondary_status(
@@ -2339,7 +2276,7 @@ ssize_t core_alua_store_secondary_status(
                                tmp);
                return -EINVAL;
        }
-       lun->lun_sep->sep_tg_pt_secondary_stat = (int)tmp;
+       lun->lun_tg_pt_secondary_stat = (int)tmp;
 
        return count;
 }
@@ -2348,8 +2285,7 @@ ssize_t core_alua_show_secondary_write_metadata(
        struct se_lun *lun,
        char *page)
 {
-       return sprintf(page, "%d\n",
-                       lun->lun_sep->sep_tg_pt_secondary_write_md);
+       return sprintf(page, "%d\n", lun->lun_tg_pt_secondary_write_md);
 }
 
 ssize_t core_alua_store_secondary_write_metadata(
@@ -2370,7 +2306,7 @@ ssize_t core_alua_store_secondary_write_metadata(
                                " %lu\n", tmp);
                return -EINVAL;
        }
-       lun->lun_sep->sep_tg_pt_secondary_write_md = (int)tmp;
+       lun->lun_tg_pt_secondary_write_md = (int)tmp;
 
        return count;
 }