11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2c66ac9dbSNicholas Bellinger /*******************************************************************************
3c66ac9dbSNicholas Bellinger  * Filename:  target_core_alua.c
4c66ac9dbSNicholas Bellinger  *
5c66ac9dbSNicholas Bellinger  * This file contains SPC-3 compliant asymmetric logical unit assigntment (ALUA)
6c66ac9dbSNicholas Bellinger  *
74c76251eSNicholas Bellinger  * (c) Copyright 2009-2013 Datera, Inc.
8c66ac9dbSNicholas Bellinger  *
9c66ac9dbSNicholas Bellinger  * Nicholas A. Bellinger <nab@kernel.org>
10c66ac9dbSNicholas Bellinger  *
11c66ac9dbSNicholas Bellinger  ******************************************************************************/
12c66ac9dbSNicholas Bellinger 
13c66ac9dbSNicholas Bellinger #include <linux/slab.h>
14c66ac9dbSNicholas Bellinger #include <linux/spinlock.h>
15c66ac9dbSNicholas Bellinger #include <linux/configfs.h>
168dcf07beSBart Van Assche #include <linux/delay.h>
17c53181afSPaul Gortmaker #include <linux/export.h>
188dcf07beSBart Van Assche #include <linux/fcntl.h>
190e9b10a9SAl Viro #include <linux/file.h>
208dcf07beSBart Van Assche #include <linux/fs.h>
21ba929992SBart Van Assche #include <scsi/scsi_proto.h>
2233395fb8SRoland Dreier #include <asm/unaligned.h>
23c66ac9dbSNicholas Bellinger 
24c66ac9dbSNicholas Bellinger #include <target/target_core_base.h>
25c4795fb2SChristoph Hellwig #include <target/target_core_backend.h>
26c4795fb2SChristoph Hellwig #include <target/target_core_fabric.h>
27c66ac9dbSNicholas Bellinger 
28e26d99aeSChristoph Hellwig #include "target_core_internal.h"
29c66ac9dbSNicholas Bellinger #include "target_core_alua.h"
30c66ac9dbSNicholas Bellinger #include "target_core_ua.h"
31c66ac9dbSNicholas Bellinger 
32bb91c1a0SHannes Reinecke static sense_reason_t core_alua_check_transition(int state, int valid,
331ca4d4faSMike Christie 						 int *primary, int explicit);
34c66ac9dbSNicholas Bellinger static int core_alua_set_tg_pt_secondary_state(
35adf653f9SChristoph Hellwig 		struct se_lun *lun, int explicit, int offline);
36c66ac9dbSNicholas Bellinger 
37bb91c1a0SHannes Reinecke static char *core_alua_dump_state(int state);
38bb91c1a0SHannes Reinecke 
39adf653f9SChristoph Hellwig static void __target_attach_tg_pt_gp(struct se_lun *lun,
40adf653f9SChristoph Hellwig 		struct t10_alua_tg_pt_gp *tg_pt_gp);
41adf653f9SChristoph Hellwig 
42e3d6f909SAndy Grover static u16 alua_lu_gps_counter;
43e3d6f909SAndy Grover static u32 alua_lu_gps_count;
44e3d6f909SAndy Grover 
45e3d6f909SAndy Grover static DEFINE_SPINLOCK(lu_gps_lock);
46e3d6f909SAndy Grover static LIST_HEAD(lu_gps_list);
47e3d6f909SAndy Grover 
48e3d6f909SAndy Grover struct t10_alua_lu_gp *default_lu_gp;
49e3d6f909SAndy Grover 
50c66ac9dbSNicholas Bellinger /*
51c66094bfSHannes Reinecke  * REPORT REFERRALS
52c66094bfSHannes Reinecke  *
53c66094bfSHannes Reinecke  * See sbc3r35 section 5.23
54c66094bfSHannes Reinecke  */
55c66094bfSHannes Reinecke sense_reason_t
target_emulate_report_referrals(struct se_cmd * cmd)56c66094bfSHannes Reinecke target_emulate_report_referrals(struct se_cmd *cmd)
57c66094bfSHannes Reinecke {
58c66094bfSHannes Reinecke 	struct se_device *dev = cmd->se_dev;
59c66094bfSHannes Reinecke 	struct t10_alua_lba_map *map;
60c66094bfSHannes Reinecke 	struct t10_alua_lba_map_member *map_mem;
61c66094bfSHannes Reinecke 	unsigned char *buf;
62c66094bfSHannes Reinecke 	u32 rd_len = 0, off;
63c66094bfSHannes Reinecke 
64c66094bfSHannes Reinecke 	if (cmd->data_length < 4) {
65c66094bfSHannes Reinecke 		pr_warn("REPORT REFERRALS allocation length %u too"
66c66094bfSHannes Reinecke 			" small\n", cmd->data_length);
67c66094bfSHannes Reinecke 		return TCM_INVALID_CDB_FIELD;
68c66094bfSHannes Reinecke 	}
69c66094bfSHannes Reinecke 
70c66094bfSHannes Reinecke 	buf = transport_kmap_data_sg(cmd);
71c66094bfSHannes Reinecke 	if (!buf)
72c66094bfSHannes Reinecke 		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
73c66094bfSHannes Reinecke 
74c66094bfSHannes Reinecke 	off = 4;
75c66094bfSHannes Reinecke 	spin_lock(&dev->t10_alua.lba_map_lock);
76c66094bfSHannes Reinecke 	if (list_empty(&dev->t10_alua.lba_map_list)) {
77c66094bfSHannes Reinecke 		spin_unlock(&dev->t10_alua.lba_map_lock);
78c66094bfSHannes Reinecke 		transport_kunmap_data_sg(cmd);
79c66094bfSHannes Reinecke 
80c66094bfSHannes Reinecke 		return TCM_UNSUPPORTED_SCSI_OPCODE;
81c66094bfSHannes Reinecke 	}
82c66094bfSHannes Reinecke 
83c66094bfSHannes Reinecke 	list_for_each_entry(map, &dev->t10_alua.lba_map_list,
84c66094bfSHannes Reinecke 			    lba_map_list) {
85c66094bfSHannes Reinecke 		int desc_num = off + 3;
86c66094bfSHannes Reinecke 		int pg_num;
87c66094bfSHannes Reinecke 
88c66094bfSHannes Reinecke 		off += 4;
8938edd724SHannes Reinecke 		if (cmd->data_length > off)
90c66094bfSHannes Reinecke 			put_unaligned_be64(map->lba_map_first_lba, &buf[off]);
91c66094bfSHannes Reinecke 		off += 8;
9238edd724SHannes Reinecke 		if (cmd->data_length > off)
93c66094bfSHannes Reinecke 			put_unaligned_be64(map->lba_map_last_lba, &buf[off]);
94c66094bfSHannes Reinecke 		off += 8;
95c66094bfSHannes Reinecke 		rd_len += 20;
96c66094bfSHannes Reinecke 		pg_num = 0;
97c66094bfSHannes Reinecke 		list_for_each_entry(map_mem, &map->lba_map_mem_list,
98c66094bfSHannes Reinecke 				    lba_map_mem_list) {
9938edd724SHannes Reinecke 			int alua_state = map_mem->lba_map_mem_alua_state;
10038edd724SHannes Reinecke 			int alua_pg_id = map_mem->lba_map_mem_alua_pg_id;
10138edd724SHannes Reinecke 
10238edd724SHannes Reinecke 			if (cmd->data_length > off)
10338edd724SHannes Reinecke 				buf[off] = alua_state & 0x0f;
10438edd724SHannes Reinecke 			off += 2;
10538edd724SHannes Reinecke 			if (cmd->data_length > off)
10638edd724SHannes Reinecke 				buf[off] = (alua_pg_id >> 8) & 0xff;
107c66094bfSHannes Reinecke 			off++;
10838edd724SHannes Reinecke 			if (cmd->data_length > off)
10938edd724SHannes Reinecke 				buf[off] = (alua_pg_id & 0xff);
11038edd724SHannes Reinecke 			off++;
111c66094bfSHannes Reinecke 			rd_len += 4;
112c66094bfSHannes Reinecke 			pg_num++;
113c66094bfSHannes Reinecke 		}
11438edd724SHannes Reinecke 		if (cmd->data_length > desc_num)
115c66094bfSHannes Reinecke 			buf[desc_num] = pg_num;
116c66094bfSHannes Reinecke 	}
117c66094bfSHannes Reinecke 	spin_unlock(&dev->t10_alua.lba_map_lock);
118c66094bfSHannes Reinecke 
119c66094bfSHannes Reinecke 	/*
120c66094bfSHannes Reinecke 	 * Set the RETURN DATA LENGTH set in the header of the DataIN Payload
121c66094bfSHannes Reinecke 	 */
122c66094bfSHannes Reinecke 	put_unaligned_be16(rd_len, &buf[2]);
123c66094bfSHannes Reinecke 
124c66094bfSHannes Reinecke 	transport_kunmap_data_sg(cmd);
125c66094bfSHannes Reinecke 
12614b40c1eSHannes Reinecke 	target_complete_cmd(cmd, SAM_STAT_GOOD);
127c66094bfSHannes Reinecke 	return 0;
128c66094bfSHannes Reinecke }
129c66094bfSHannes Reinecke 
130c66094bfSHannes Reinecke /*
131c66ac9dbSNicholas Bellinger  * REPORT_TARGET_PORT_GROUPS
132c66ac9dbSNicholas Bellinger  *
133c66ac9dbSNicholas Bellinger  * See spc4r17 section 6.27
134c66ac9dbSNicholas Bellinger  */
135de103c93SChristoph Hellwig sense_reason_t
target_emulate_report_target_port_groups(struct se_cmd * cmd)136de103c93SChristoph Hellwig target_emulate_report_target_port_groups(struct se_cmd *cmd)
137c66ac9dbSNicholas Bellinger {
1380fd97ccfSChristoph Hellwig 	struct se_device *dev = cmd->se_dev;
139c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp;
140adf653f9SChristoph Hellwig 	struct se_lun *lun;
14105d1c7c0SAndy Grover 	unsigned char *buf;
1425b9a4d72SNicholas Bellinger 	u32 rd_len = 0, off;
1435b9a4d72SNicholas Bellinger 	int ext_hdr = (cmd->t_task_cdb[1] & 0x20);
144de103c93SChristoph Hellwig 
1456b20fa9aSNicholas Bellinger 	/*
1465b9a4d72SNicholas Bellinger 	 * Skip over RESERVED area to first Target port group descriptor
1475b9a4d72SNicholas Bellinger 	 * depending on the PARAMETER DATA FORMAT type..
1486b20fa9aSNicholas Bellinger 	 */
1495b9a4d72SNicholas Bellinger 	if (ext_hdr != 0)
1505b9a4d72SNicholas Bellinger 		off = 8;
1515b9a4d72SNicholas Bellinger 	else
1525b9a4d72SNicholas Bellinger 		off = 4;
1535b9a4d72SNicholas Bellinger 
1545b9a4d72SNicholas Bellinger 	if (cmd->data_length < off) {
1555b9a4d72SNicholas Bellinger 		pr_warn("REPORT TARGET PORT GROUPS allocation length %u too"
1565b9a4d72SNicholas Bellinger 			" small for %s header\n", cmd->data_length,
1575b9a4d72SNicholas Bellinger 			(ext_hdr) ? "extended" : "normal");
158de103c93SChristoph Hellwig 		return TCM_INVALID_CDB_FIELD;
1596b20fa9aSNicholas Bellinger 	}
1604949314cSAndy Grover 	buf = transport_kmap_data_sg(cmd);
161de103c93SChristoph Hellwig 	if (!buf)
162de103c93SChristoph Hellwig 		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
16305d1c7c0SAndy Grover 
1640fd97ccfSChristoph Hellwig 	spin_lock(&dev->t10_alua.tg_pt_gps_lock);
1650fd97ccfSChristoph Hellwig 	list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list,
166c66ac9dbSNicholas Bellinger 			tg_pt_gp_list) {
167f04e47e7SDmitry Bogdanov 		/* Skip empty port groups */
168f04e47e7SDmitry Bogdanov 		if (!tg_pt_gp->tg_pt_gp_members)
169f04e47e7SDmitry Bogdanov 			continue;
170c66ac9dbSNicholas Bellinger 		/*
1716b20fa9aSNicholas Bellinger 		 * Check if the Target port group and Target port descriptor list
1726b20fa9aSNicholas Bellinger 		 * based on tg_pt_gp_members count will fit into the response payload.
1736b20fa9aSNicholas Bellinger 		 * Otherwise, bump rd_len to let the initiator know we have exceeded
1746b20fa9aSNicholas Bellinger 		 * the allocation length and the response is truncated.
1756b20fa9aSNicholas Bellinger 		 */
1766b20fa9aSNicholas Bellinger 		if ((off + 8 + (tg_pt_gp->tg_pt_gp_members * 4)) >
1776b20fa9aSNicholas Bellinger 		     cmd->data_length) {
1786b20fa9aSNicholas Bellinger 			rd_len += 8 + (tg_pt_gp->tg_pt_gp_members * 4);
1796b20fa9aSNicholas Bellinger 			continue;
1806b20fa9aSNicholas Bellinger 		}
1816b20fa9aSNicholas Bellinger 		/*
182c66ac9dbSNicholas Bellinger 		 * PREF: Preferred target port bit, determine if this
183c66ac9dbSNicholas Bellinger 		 * bit should be set for port group.
184c66ac9dbSNicholas Bellinger 		 */
185c66ac9dbSNicholas Bellinger 		if (tg_pt_gp->tg_pt_gp_pref)
186c66ac9dbSNicholas Bellinger 			buf[off] = 0x80;
187c66ac9dbSNicholas Bellinger 		/*
188c66ac9dbSNicholas Bellinger 		 * Set the ASYMMETRIC ACCESS State
189c66ac9dbSNicholas Bellinger 		 */
190d19c4643SMike Christie 		buf[off++] |= tg_pt_gp->tg_pt_gp_alua_access_state & 0xff;
191c66ac9dbSNicholas Bellinger 		/*
192c66ac9dbSNicholas Bellinger 		 * Set supported ASYMMETRIC ACCESS State bits
193c66ac9dbSNicholas Bellinger 		 */
194c0dc941eSHannes Reinecke 		buf[off++] |= tg_pt_gp->tg_pt_gp_alua_supported_states;
195c66ac9dbSNicholas Bellinger 		/*
196c66ac9dbSNicholas Bellinger 		 * TARGET PORT GROUP
197c66ac9dbSNicholas Bellinger 		 */
198a85d667eSBart Van Assche 		put_unaligned_be16(tg_pt_gp->tg_pt_gp_id, &buf[off]);
199a85d667eSBart Van Assche 		off += 2;
200c66ac9dbSNicholas Bellinger 
201c66ac9dbSNicholas Bellinger 		off++; /* Skip over Reserved */
202c66ac9dbSNicholas Bellinger 		/*
203c66ac9dbSNicholas Bellinger 		 * STATUS CODE
204c66ac9dbSNicholas Bellinger 		 */
205c66ac9dbSNicholas Bellinger 		buf[off++] = (tg_pt_gp->tg_pt_gp_alua_access_status & 0xff);
206c66ac9dbSNicholas Bellinger 		/*
207c66ac9dbSNicholas Bellinger 		 * Vendor Specific field
208c66ac9dbSNicholas Bellinger 		 */
209c66ac9dbSNicholas Bellinger 		buf[off++] = 0x00;
210c66ac9dbSNicholas Bellinger 		/*
211c66ac9dbSNicholas Bellinger 		 * TARGET PORT COUNT
212c66ac9dbSNicholas Bellinger 		 */
213c66ac9dbSNicholas Bellinger 		buf[off++] = (tg_pt_gp->tg_pt_gp_members & 0xff);
214c66ac9dbSNicholas Bellinger 		rd_len += 8;
215c66ac9dbSNicholas Bellinger 
216c66ac9dbSNicholas Bellinger 		spin_lock(&tg_pt_gp->tg_pt_gp_lock);
217adf653f9SChristoph Hellwig 		list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list,
218adf653f9SChristoph Hellwig 				lun_tg_pt_gp_link) {
219c66ac9dbSNicholas Bellinger 			/*
220c66ac9dbSNicholas Bellinger 			 * Start Target Port descriptor format
221c66ac9dbSNicholas Bellinger 			 *
222c66ac9dbSNicholas Bellinger 			 * See spc4r17 section 6.2.7 Table 247
223c66ac9dbSNicholas Bellinger 			 */
224c66ac9dbSNicholas Bellinger 			off += 2; /* Skip over Obsolete */
225c66ac9dbSNicholas Bellinger 			/*
226c66ac9dbSNicholas Bellinger 			 * Set RELATIVE TARGET PORT IDENTIFIER
227c66ac9dbSNicholas Bellinger 			 */
228*b9e063adSRoman Bolshakov 			put_unaligned_be16(lun->lun_tpg->tpg_rtpi, &buf[off]);
229a85d667eSBart Van Assche 			off += 2;
230c66ac9dbSNicholas Bellinger 			rd_len += 4;
231c66ac9dbSNicholas Bellinger 		}
232c66ac9dbSNicholas Bellinger 		spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
233c66ac9dbSNicholas Bellinger 	}
2340fd97ccfSChristoph Hellwig 	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
235c66ac9dbSNicholas Bellinger 	/*
236c66ac9dbSNicholas Bellinger 	 * Set the RETURN DATA LENGTH set in the header of the DataIN Payload
237c66ac9dbSNicholas Bellinger 	 */
2385b9a4d72SNicholas Bellinger 	put_unaligned_be32(rd_len, &buf[0]);
239c66ac9dbSNicholas Bellinger 
2405b9a4d72SNicholas Bellinger 	/*
2415b9a4d72SNicholas Bellinger 	 * Fill in the Extended header parameter data format if requested
2425b9a4d72SNicholas Bellinger 	 */
2435b9a4d72SNicholas Bellinger 	if (ext_hdr != 0) {
2445b9a4d72SNicholas Bellinger 		buf[4] = 0x10;
2455b9a4d72SNicholas Bellinger 		/*
246125d0119SHannes Reinecke 		 * Set the implicit transition time (in seconds) for the application
2475b9a4d72SNicholas Bellinger 		 * client to use as a base for it's transition timeout value.
2485b9a4d72SNicholas Bellinger 		 *
2495b9a4d72SNicholas Bellinger 		 * Use the current tg_pt_gp_mem -> tg_pt_gp membership from the LUN
2505b9a4d72SNicholas Bellinger 		 * this CDB was received upon to determine this value individually
2515b9a4d72SNicholas Bellinger 		 * for ALUA target port group.
2525b9a4d72SNicholas Bellinger 		 */
2537324f47dSMike Christie 		rcu_read_lock();
2547324f47dSMike Christie 		tg_pt_gp = rcu_dereference(cmd->se_lun->lun_tg_pt_gp);
2555b9a4d72SNicholas Bellinger 		if (tg_pt_gp)
256125d0119SHannes Reinecke 			buf[5] = tg_pt_gp->tg_pt_gp_implicit_trans_secs;
2577324f47dSMike Christie 		rcu_read_unlock();
2585b9a4d72SNicholas Bellinger 	}
2594949314cSAndy Grover 	transport_kunmap_data_sg(cmd);
26005d1c7c0SAndy Grover 
26114b40c1eSHannes Reinecke 	target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, rd_len + 4);
262c66ac9dbSNicholas Bellinger 	return 0;
263c66ac9dbSNicholas Bellinger }
264c66ac9dbSNicholas Bellinger 
265c66ac9dbSNicholas Bellinger /*
266125d0119SHannes Reinecke  * SET_TARGET_PORT_GROUPS for explicit ALUA operation.
267c66ac9dbSNicholas Bellinger  *
268c66ac9dbSNicholas Bellinger  * See spc4r17 section 6.35
269c66ac9dbSNicholas Bellinger  */
270de103c93SChristoph Hellwig sense_reason_t
target_emulate_set_target_port_groups(struct se_cmd * cmd)271de103c93SChristoph Hellwig target_emulate_set_target_port_groups(struct se_cmd *cmd)
272c66ac9dbSNicholas Bellinger {
2735951146dSAndy Grover 	struct se_device *dev = cmd->se_dev;
274adf653f9SChristoph Hellwig 	struct se_lun *l_lun = cmd->se_lun;
275e3d6f909SAndy Grover 	struct se_node_acl *nacl = cmd->se_sess->se_node_acl;
276c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *l_tg_pt_gp;
27705d1c7c0SAndy Grover 	unsigned char *buf;
27805d1c7c0SAndy Grover 	unsigned char *ptr;
279a0d50f62SHannes Reinecke 	sense_reason_t rc = TCM_NO_SENSE;
280c66ac9dbSNicholas Bellinger 	u32 len = 4; /* Skip over RESERVED area in header */
281bb91c1a0SHannes Reinecke 	int alua_access_state, primary = 0, valid_states;
282c66ac9dbSNicholas Bellinger 	u16 tg_pt_id, rtpi;
283c66ac9dbSNicholas Bellinger 
2840d7f1299SPaolo Bonzini 	if (cmd->data_length < 4) {
2850d7f1299SPaolo Bonzini 		pr_warn("SET TARGET PORT GROUPS parameter list length %u too"
2860d7f1299SPaolo Bonzini 			" small\n", cmd->data_length);
287de103c93SChristoph Hellwig 		return TCM_INVALID_PARAMETER_LIST;
2880d7f1299SPaolo Bonzini 	}
2890d7f1299SPaolo Bonzini 
2904949314cSAndy Grover 	buf = transport_kmap_data_sg(cmd);
291de103c93SChristoph Hellwig 	if (!buf)
292de103c93SChristoph Hellwig 		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
29305d1c7c0SAndy Grover 
294c66ac9dbSNicholas Bellinger 	/*
295125d0119SHannes Reinecke 	 * Determine if explicit ALUA via SET_TARGET_PORT_GROUPS is allowed
296c66ac9dbSNicholas Bellinger 	 * for the local tg_pt_gp.
297c66ac9dbSNicholas Bellinger 	 */
2987324f47dSMike Christie 	rcu_read_lock();
2997324f47dSMike Christie 	l_tg_pt_gp = rcu_dereference(l_lun->lun_tg_pt_gp);
3006708bb27SAndy Grover 	if (!l_tg_pt_gp) {
3017324f47dSMike Christie 		rcu_read_unlock();
302adf653f9SChristoph Hellwig 		pr_err("Unable to access l_lun->tg_pt_gp\n");
303de103c93SChristoph Hellwig 		rc = TCM_UNSUPPORTED_SCSI_OPCODE;
30405d1c7c0SAndy Grover 		goto out;
305c66ac9dbSNicholas Bellinger 	}
306c66ac9dbSNicholas Bellinger 
307125d0119SHannes Reinecke 	if (!(l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA)) {
3087324f47dSMike Christie 		rcu_read_unlock();
3096708bb27SAndy Grover 		pr_debug("Unable to process SET_TARGET_PORT_GROUPS"
310125d0119SHannes Reinecke 				" while TPGS_EXPLICIT_ALUA is disabled\n");
311de103c93SChristoph Hellwig 		rc = TCM_UNSUPPORTED_SCSI_OPCODE;
31205d1c7c0SAndy Grover 		goto out;
313c66ac9dbSNicholas Bellinger 	}
314bb91c1a0SHannes Reinecke 	valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states;
3157324f47dSMike Christie 	rcu_read_unlock();
316c66ac9dbSNicholas Bellinger 
31705d1c7c0SAndy Grover 	ptr = &buf[4]; /* Skip over RESERVED area in header */
31805d1c7c0SAndy Grover 
319c66ac9dbSNicholas Bellinger 	while (len < cmd->data_length) {
320de103c93SChristoph Hellwig 		bool found = false;
321c66ac9dbSNicholas Bellinger 		alua_access_state = (ptr[0] & 0x0f);
322c66ac9dbSNicholas Bellinger 		/*
323c66ac9dbSNicholas Bellinger 		 * Check the received ALUA access state, and determine if
324c66ac9dbSNicholas Bellinger 		 * the state is a primary or secondary target port asymmetric
325c66ac9dbSNicholas Bellinger 		 * access state.
326c66ac9dbSNicholas Bellinger 		 */
3271ca4d4faSMike Christie 		rc = core_alua_check_transition(alua_access_state, valid_states,
3281ca4d4faSMike Christie 						&primary, 1);
329de103c93SChristoph Hellwig 		if (rc) {
330c66ac9dbSNicholas Bellinger 			/*
331c66ac9dbSNicholas Bellinger 			 * If the SET TARGET PORT GROUPS attempts to establish
332c66ac9dbSNicholas Bellinger 			 * an invalid combination of target port asymmetric
333c66ac9dbSNicholas Bellinger 			 * access states or attempts to establish an
334c66ac9dbSNicholas Bellinger 			 * unsupported target port asymmetric access state,
335c66ac9dbSNicholas Bellinger 			 * then the command shall be terminated with CHECK
336c66ac9dbSNicholas Bellinger 			 * CONDITION status, with the sense key set to ILLEGAL
337c66ac9dbSNicholas Bellinger 			 * REQUEST, and the additional sense code set to INVALID
338c66ac9dbSNicholas Bellinger 			 * FIELD IN PARAMETER LIST.
339c66ac9dbSNicholas Bellinger 			 */
34005d1c7c0SAndy Grover 			goto out;
341c66ac9dbSNicholas Bellinger 		}
342de103c93SChristoph Hellwig 
343c66ac9dbSNicholas Bellinger 		/*
344c66ac9dbSNicholas Bellinger 		 * If the ASYMMETRIC ACCESS STATE field (see table 267)
345c66ac9dbSNicholas Bellinger 		 * specifies a primary target port asymmetric access state,
346c66ac9dbSNicholas Bellinger 		 * then the TARGET PORT GROUP OR TARGET PORT field specifies
347c66ac9dbSNicholas Bellinger 		 * a primary target port group for which the primary target
348c66ac9dbSNicholas Bellinger 		 * port asymmetric access state shall be changed. If the
349c66ac9dbSNicholas Bellinger 		 * ASYMMETRIC ACCESS STATE field specifies a secondary target
350c66ac9dbSNicholas Bellinger 		 * port asymmetric access state, then the TARGET PORT GROUP OR
351c66ac9dbSNicholas Bellinger 		 * TARGET PORT field specifies the relative target port
352c66ac9dbSNicholas Bellinger 		 * identifier (see 3.1.120) of the target port for which the
353c66ac9dbSNicholas Bellinger 		 * secondary target port asymmetric access state shall be
354c66ac9dbSNicholas Bellinger 		 * changed.
355c66ac9dbSNicholas Bellinger 		 */
356c66ac9dbSNicholas Bellinger 		if (primary) {
35733395fb8SRoland Dreier 			tg_pt_id = get_unaligned_be16(ptr + 2);
358c66ac9dbSNicholas Bellinger 			/*
359c66ac9dbSNicholas Bellinger 			 * Locate the matching target port group ID from
360c66ac9dbSNicholas Bellinger 			 * the global tg_pt_gp list
361c66ac9dbSNicholas Bellinger 			 */
3620fd97ccfSChristoph Hellwig 			spin_lock(&dev->t10_alua.tg_pt_gps_lock);
363c66ac9dbSNicholas Bellinger 			list_for_each_entry(tg_pt_gp,
3640fd97ccfSChristoph Hellwig 					&dev->t10_alua.tg_pt_gps_list,
365c66ac9dbSNicholas Bellinger 					tg_pt_gp_list) {
3666708bb27SAndy Grover 				if (!tg_pt_gp->tg_pt_gp_valid_id)
367c66ac9dbSNicholas Bellinger 					continue;
368c66ac9dbSNicholas Bellinger 
369c66ac9dbSNicholas Bellinger 				if (tg_pt_id != tg_pt_gp->tg_pt_gp_id)
370c66ac9dbSNicholas Bellinger 					continue;
371c66ac9dbSNicholas Bellinger 
37233940d09SJoern Engel 				atomic_inc_mb(&tg_pt_gp->tg_pt_gp_ref_cnt);
373de103c93SChristoph Hellwig 
3740fd97ccfSChristoph Hellwig 				spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
375c66ac9dbSNicholas Bellinger 
376de103c93SChristoph Hellwig 				if (!core_alua_do_port_transition(tg_pt_gp,
377adf653f9SChristoph Hellwig 						dev, l_lun, nacl,
378de103c93SChristoph Hellwig 						alua_access_state, 1))
379de103c93SChristoph Hellwig 					found = true;
380c66ac9dbSNicholas Bellinger 
3810fd97ccfSChristoph Hellwig 				spin_lock(&dev->t10_alua.tg_pt_gps_lock);
38233940d09SJoern Engel 				atomic_dec_mb(&tg_pt_gp->tg_pt_gp_ref_cnt);
383c66ac9dbSNicholas Bellinger 				break;
384c66ac9dbSNicholas Bellinger 			}
3850fd97ccfSChristoph Hellwig 			spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
386c66ac9dbSNicholas Bellinger 		} else {
387adf653f9SChristoph Hellwig 			struct se_lun *lun;
388adf653f9SChristoph Hellwig 
389c66ac9dbSNicholas Bellinger 			/*
390f1ae05d5SHannes Reinecke 			 * Extract the RELATIVE TARGET PORT IDENTIFIER to identify
391b73b1430SJiang Jian 			 * the Target Port in question for the incoming
392c66ac9dbSNicholas Bellinger 			 * SET_TARGET_PORT_GROUPS op.
393c66ac9dbSNicholas Bellinger 			 */
39433395fb8SRoland Dreier 			rtpi = get_unaligned_be16(ptr + 2);
395c66ac9dbSNicholas Bellinger 			/*
39635d1efe8SMasanari Iida 			 * Locate the matching relative target port identifier
397c66ac9dbSNicholas Bellinger 			 * for the struct se_device storage object.
398c66ac9dbSNicholas Bellinger 			 */
399c66ac9dbSNicholas Bellinger 			spin_lock(&dev->se_port_lock);
400adf653f9SChristoph Hellwig 			list_for_each_entry(lun, &dev->dev_sep_list,
401adf653f9SChristoph Hellwig 							lun_dev_link) {
402*b9e063adSRoman Bolshakov 				if (lun->lun_tpg->tpg_rtpi != rtpi)
403c66ac9dbSNicholas Bellinger 					continue;
404c66ac9dbSNicholas Bellinger 
405adf653f9SChristoph Hellwig 				// XXX: racy unlock
406c66ac9dbSNicholas Bellinger 				spin_unlock(&dev->se_port_lock);
407c66ac9dbSNicholas Bellinger 
408de103c93SChristoph Hellwig 				if (!core_alua_set_tg_pt_secondary_state(
409adf653f9SChristoph Hellwig 						lun, 1, 1))
410de103c93SChristoph Hellwig 					found = true;
411c66ac9dbSNicholas Bellinger 
412c66ac9dbSNicholas Bellinger 				spin_lock(&dev->se_port_lock);
413c66ac9dbSNicholas Bellinger 				break;
414c66ac9dbSNicholas Bellinger 			}
415c66ac9dbSNicholas Bellinger 			spin_unlock(&dev->se_port_lock);
41605d1c7c0SAndy Grover 		}
417de103c93SChristoph Hellwig 
418de103c93SChristoph Hellwig 		if (!found) {
419de103c93SChristoph Hellwig 			rc = TCM_INVALID_PARAMETER_LIST;
420de103c93SChristoph Hellwig 			goto out;
421c66ac9dbSNicholas Bellinger 		}
422c66ac9dbSNicholas Bellinger 
423c66ac9dbSNicholas Bellinger 		ptr += 4;
424c66ac9dbSNicholas Bellinger 		len += 4;
425c66ac9dbSNicholas Bellinger 	}
426c66ac9dbSNicholas Bellinger 
42705d1c7c0SAndy Grover out:
4284949314cSAndy Grover 	transport_kunmap_data_sg(cmd);
42959e4f541SRoland Dreier 	if (!rc)
43014b40c1eSHannes Reinecke 		target_complete_cmd(cmd, SAM_STAT_GOOD);
43159e4f541SRoland Dreier 	return rc;
432c66ac9dbSNicholas Bellinger }
433c66ac9dbSNicholas Bellinger 
core_alua_state_nonoptimized(struct se_cmd * cmd,unsigned char * cdb,int nonop_delay_msecs)4341e3ab99dSPaul Bolle static inline void core_alua_state_nonoptimized(
435c66ac9dbSNicholas Bellinger 	struct se_cmd *cmd,
436c66ac9dbSNicholas Bellinger 	unsigned char *cdb,
4371e3ab99dSPaul Bolle 	int nonop_delay_msecs)
438c66ac9dbSNicholas Bellinger {
439c66ac9dbSNicholas Bellinger 	/*
440c66ac9dbSNicholas Bellinger 	 * Set SCF_ALUA_NON_OPTIMIZED here, this value will be checked
441c66ac9dbSNicholas Bellinger 	 * later to determine if processing of this cmd needs to be
442c66ac9dbSNicholas Bellinger 	 * temporarily delayed for the Active/NonOptimized primary access state.
443c66ac9dbSNicholas Bellinger 	 */
444c66ac9dbSNicholas Bellinger 	cmd->se_cmd_flags |= SCF_ALUA_NON_OPTIMIZED;
445c66ac9dbSNicholas Bellinger 	cmd->alua_nonop_delay = nonop_delay_msecs;
446c66ac9dbSNicholas Bellinger }
447c66ac9dbSNicholas Bellinger 
core_alua_state_lba_dependent(struct se_cmd * cmd,u16 tg_pt_gp_id)44840fd8845SDavid Disseldorp static inline sense_reason_t core_alua_state_lba_dependent(
449c66094bfSHannes Reinecke 	struct se_cmd *cmd,
4507e457e5eSDavid Disseldorp 	u16 tg_pt_gp_id)
451c66094bfSHannes Reinecke {
452c66094bfSHannes Reinecke 	struct se_device *dev = cmd->se_dev;
453c66094bfSHannes Reinecke 	u64 segment_size, segment_mult, sectors, lba;
454c66094bfSHannes Reinecke 
455c66094bfSHannes Reinecke 	/* Only need to check for cdb actually containing LBAs */
456c66094bfSHannes Reinecke 	if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB))
457c66094bfSHannes Reinecke 		return 0;
458c66094bfSHannes Reinecke 
459c66094bfSHannes Reinecke 	spin_lock(&dev->t10_alua.lba_map_lock);
460c66094bfSHannes Reinecke 	segment_size = dev->t10_alua.lba_map_segment_size;
461c66094bfSHannes Reinecke 	segment_mult = dev->t10_alua.lba_map_segment_multiplier;
462c66094bfSHannes Reinecke 	sectors = cmd->data_length / dev->dev_attrib.block_size;
463c66094bfSHannes Reinecke 
464c66094bfSHannes Reinecke 	lba = cmd->t_task_lba;
465c66094bfSHannes Reinecke 	while (lba < cmd->t_task_lba + sectors) {
466c66094bfSHannes Reinecke 		struct t10_alua_lba_map *cur_map = NULL, *map;
467c66094bfSHannes Reinecke 		struct t10_alua_lba_map_member *map_mem;
468c66094bfSHannes Reinecke 
469c66094bfSHannes Reinecke 		list_for_each_entry(map, &dev->t10_alua.lba_map_list,
470c66094bfSHannes Reinecke 				    lba_map_list) {
471c66094bfSHannes Reinecke 			u64 start_lba, last_lba;
472c66094bfSHannes Reinecke 			u64 first_lba = map->lba_map_first_lba;
473c66094bfSHannes Reinecke 
474c66094bfSHannes Reinecke 			if (segment_mult) {
475c66094bfSHannes Reinecke 				u64 tmp = lba;
476cdf55949SNicholas Bellinger 				start_lba = do_div(tmp, segment_size * segment_mult);
477c66094bfSHannes Reinecke 
478c66094bfSHannes Reinecke 				last_lba = first_lba + segment_size - 1;
479c66094bfSHannes Reinecke 				if (start_lba >= first_lba &&
480c66094bfSHannes Reinecke 				    start_lba <= last_lba) {
481c66094bfSHannes Reinecke 					lba += segment_size;
482c66094bfSHannes Reinecke 					cur_map = map;
483c66094bfSHannes Reinecke 					break;
484c66094bfSHannes Reinecke 				}
485c66094bfSHannes Reinecke 			} else {
486c66094bfSHannes Reinecke 				last_lba = map->lba_map_last_lba;
487c66094bfSHannes Reinecke 				if (lba >= first_lba && lba <= last_lba) {
488c66094bfSHannes Reinecke 					lba = last_lba + 1;
489c66094bfSHannes Reinecke 					cur_map = map;
490c66094bfSHannes Reinecke 					break;
491c66094bfSHannes Reinecke 				}
492c66094bfSHannes Reinecke 			}
493c66094bfSHannes Reinecke 		}
494c66094bfSHannes Reinecke 		if (!cur_map) {
495c66094bfSHannes Reinecke 			spin_unlock(&dev->t10_alua.lba_map_lock);
49640fd8845SDavid Disseldorp 			return TCM_ALUA_TG_PT_UNAVAILABLE;
497c66094bfSHannes Reinecke 		}
498c66094bfSHannes Reinecke 		list_for_each_entry(map_mem, &cur_map->lba_map_mem_list,
499c66094bfSHannes Reinecke 				    lba_map_mem_list) {
5007e457e5eSDavid Disseldorp 			if (map_mem->lba_map_mem_alua_pg_id != tg_pt_gp_id)
501c66094bfSHannes Reinecke 				continue;
502c66094bfSHannes Reinecke 			switch(map_mem->lba_map_mem_alua_state) {
503c66094bfSHannes Reinecke 			case ALUA_ACCESS_STATE_STANDBY:
504c66094bfSHannes Reinecke 				spin_unlock(&dev->t10_alua.lba_map_lock);
50540fd8845SDavid Disseldorp 				return TCM_ALUA_TG_PT_STANDBY;
506c66094bfSHannes Reinecke 			case ALUA_ACCESS_STATE_UNAVAILABLE:
507c66094bfSHannes Reinecke 				spin_unlock(&dev->t10_alua.lba_map_lock);
50840fd8845SDavid Disseldorp 				return TCM_ALUA_TG_PT_UNAVAILABLE;
509c66094bfSHannes Reinecke 			default:
510c66094bfSHannes Reinecke 				break;
511c66094bfSHannes Reinecke 			}
512c66094bfSHannes Reinecke 		}
513c66094bfSHannes Reinecke 	}
514c66094bfSHannes Reinecke 	spin_unlock(&dev->t10_alua.lba_map_lock);
515c66094bfSHannes Reinecke 	return 0;
516c66094bfSHannes Reinecke }
517c66094bfSHannes Reinecke 
core_alua_state_standby(struct se_cmd * cmd,unsigned char * cdb)51840fd8845SDavid Disseldorp static inline sense_reason_t core_alua_state_standby(
519c66ac9dbSNicholas Bellinger 	struct se_cmd *cmd,
5201e3ab99dSPaul Bolle 	unsigned char *cdb)
521c66ac9dbSNicholas Bellinger {
522c66ac9dbSNicholas Bellinger 	/*
523c66ac9dbSNicholas Bellinger 	 * Allowed CDBs for ALUA_ACCESS_STATE_STANDBY as defined by
524c66ac9dbSNicholas Bellinger 	 * spc4r17 section 5.9.2.4.4
525c66ac9dbSNicholas Bellinger 	 */
526c66ac9dbSNicholas Bellinger 	switch (cdb[0]) {
527c66ac9dbSNicholas Bellinger 	case INQUIRY:
528c66ac9dbSNicholas Bellinger 	case LOG_SELECT:
529c66ac9dbSNicholas Bellinger 	case LOG_SENSE:
530c66ac9dbSNicholas Bellinger 	case MODE_SELECT:
531c66ac9dbSNicholas Bellinger 	case MODE_SENSE:
532c66ac9dbSNicholas Bellinger 	case REPORT_LUNS:
533c66ac9dbSNicholas Bellinger 	case RECEIVE_DIAGNOSTIC:
534c66ac9dbSNicholas Bellinger 	case SEND_DIAGNOSTIC:
535e7810c2dSNicholas Bellinger 	case READ_CAPACITY:
53630f359a6SNicholas Bellinger 		return 0;
537eb846d9fSHannes Reinecke 	case SERVICE_ACTION_IN_16:
538e7810c2dSNicholas Bellinger 		switch (cdb[1] & 0x1f) {
539e7810c2dSNicholas Bellinger 		case SAI_READ_CAPACITY_16:
540e7810c2dSNicholas Bellinger 			return 0;
541e7810c2dSNicholas Bellinger 		default:
54240fd8845SDavid Disseldorp 			return TCM_ALUA_TG_PT_STANDBY;
543e7810c2dSNicholas Bellinger 		}
544c66ac9dbSNicholas Bellinger 	case MAINTENANCE_IN:
545ba539743SNicholas Bellinger 		switch (cdb[1] & 0x1f) {
546c66ac9dbSNicholas Bellinger 		case MI_REPORT_TARGET_PGS:
547c66ac9dbSNicholas Bellinger 			return 0;
548c66ac9dbSNicholas Bellinger 		default:
54940fd8845SDavid Disseldorp 			return TCM_ALUA_TG_PT_STANDBY;
550c66ac9dbSNicholas Bellinger 		}
551c66ac9dbSNicholas Bellinger 	case MAINTENANCE_OUT:
552c66ac9dbSNicholas Bellinger 		switch (cdb[1]) {
553c66ac9dbSNicholas Bellinger 		case MO_SET_TARGET_PGS:
554c66ac9dbSNicholas Bellinger 			return 0;
555c66ac9dbSNicholas Bellinger 		default:
55640fd8845SDavid Disseldorp 			return TCM_ALUA_TG_PT_STANDBY;
557c66ac9dbSNicholas Bellinger 		}
558c66ac9dbSNicholas Bellinger 	case REQUEST_SENSE:
559c66ac9dbSNicholas Bellinger 	case PERSISTENT_RESERVE_IN:
560c66ac9dbSNicholas Bellinger 	case PERSISTENT_RESERVE_OUT:
561c66ac9dbSNicholas Bellinger 	case READ_BUFFER:
562c66ac9dbSNicholas Bellinger 	case WRITE_BUFFER:
563c66ac9dbSNicholas Bellinger 		return 0;
564c66ac9dbSNicholas Bellinger 	default:
56540fd8845SDavid Disseldorp 		return TCM_ALUA_TG_PT_STANDBY;
566c66ac9dbSNicholas Bellinger 	}
567c66ac9dbSNicholas Bellinger 
568c66ac9dbSNicholas Bellinger 	return 0;
569c66ac9dbSNicholas Bellinger }
570c66ac9dbSNicholas Bellinger 
core_alua_state_unavailable(struct se_cmd * cmd,unsigned char * cdb)57140fd8845SDavid Disseldorp static inline sense_reason_t core_alua_state_unavailable(
572c66ac9dbSNicholas Bellinger 	struct se_cmd *cmd,
5731e3ab99dSPaul Bolle 	unsigned char *cdb)
574c66ac9dbSNicholas Bellinger {
575c66ac9dbSNicholas Bellinger 	/*
576c66ac9dbSNicholas Bellinger 	 * Allowed CDBs for ALUA_ACCESS_STATE_UNAVAILABLE as defined by
577c66ac9dbSNicholas Bellinger 	 * spc4r17 section 5.9.2.4.5
578c66ac9dbSNicholas Bellinger 	 */
579c66ac9dbSNicholas Bellinger 	switch (cdb[0]) {
580c66ac9dbSNicholas Bellinger 	case INQUIRY:
581c66ac9dbSNicholas Bellinger 	case REPORT_LUNS:
58230f359a6SNicholas Bellinger 		return 0;
583c66ac9dbSNicholas Bellinger 	case MAINTENANCE_IN:
584ba539743SNicholas Bellinger 		switch (cdb[1] & 0x1f) {
585c66ac9dbSNicholas Bellinger 		case MI_REPORT_TARGET_PGS:
586c66ac9dbSNicholas Bellinger 			return 0;
587c66ac9dbSNicholas Bellinger 		default:
58840fd8845SDavid Disseldorp 			return TCM_ALUA_TG_PT_UNAVAILABLE;
589c66ac9dbSNicholas Bellinger 		}
590c66ac9dbSNicholas Bellinger 	case MAINTENANCE_OUT:
591c66ac9dbSNicholas Bellinger 		switch (cdb[1]) {
592c66ac9dbSNicholas Bellinger 		case MO_SET_TARGET_PGS:
593c66ac9dbSNicholas Bellinger 			return 0;
594c66ac9dbSNicholas Bellinger 		default:
59540fd8845SDavid Disseldorp 			return TCM_ALUA_TG_PT_UNAVAILABLE;
596c66ac9dbSNicholas Bellinger 		}
597c66ac9dbSNicholas Bellinger 	case REQUEST_SENSE:
598c66ac9dbSNicholas Bellinger 	case READ_BUFFER:
599c66ac9dbSNicholas Bellinger 	case WRITE_BUFFER:
600c66ac9dbSNicholas Bellinger 		return 0;
601c66ac9dbSNicholas Bellinger 	default:
60240fd8845SDavid Disseldorp 		return TCM_ALUA_TG_PT_UNAVAILABLE;
603c66ac9dbSNicholas Bellinger 	}
604c66ac9dbSNicholas Bellinger 
605c66ac9dbSNicholas Bellinger 	return 0;
606c66ac9dbSNicholas Bellinger }
607c66ac9dbSNicholas Bellinger 
core_alua_state_transition(struct se_cmd * cmd,unsigned char * cdb)60840fd8845SDavid Disseldorp static inline sense_reason_t core_alua_state_transition(
609c66ac9dbSNicholas Bellinger 	struct se_cmd *cmd,
6101e3ab99dSPaul Bolle 	unsigned char *cdb)
611c66ac9dbSNicholas Bellinger {
612c66ac9dbSNicholas Bellinger 	/*
613f1ae05d5SHannes Reinecke 	 * Allowed CDBs for ALUA_ACCESS_STATE_TRANSITION as defined by
614c66ac9dbSNicholas Bellinger 	 * spc4r17 section 5.9.2.5
615c66ac9dbSNicholas Bellinger 	 */
616c66ac9dbSNicholas Bellinger 	switch (cdb[0]) {
617c66ac9dbSNicholas Bellinger 	case INQUIRY:
618c66ac9dbSNicholas Bellinger 	case REPORT_LUNS:
61930f359a6SNicholas Bellinger 		return 0;
620c66ac9dbSNicholas Bellinger 	case MAINTENANCE_IN:
621ba539743SNicholas Bellinger 		switch (cdb[1] & 0x1f) {
622c66ac9dbSNicholas Bellinger 		case MI_REPORT_TARGET_PGS:
623c66ac9dbSNicholas Bellinger 			return 0;
624c66ac9dbSNicholas Bellinger 		default:
62540fd8845SDavid Disseldorp 			return TCM_ALUA_STATE_TRANSITION;
626c66ac9dbSNicholas Bellinger 		}
627c66ac9dbSNicholas Bellinger 	case REQUEST_SENSE:
628c66ac9dbSNicholas Bellinger 	case READ_BUFFER:
629c66ac9dbSNicholas Bellinger 	case WRITE_BUFFER:
630c66ac9dbSNicholas Bellinger 		return 0;
631c66ac9dbSNicholas Bellinger 	default:
63240fd8845SDavid Disseldorp 		return TCM_ALUA_STATE_TRANSITION;
633c66ac9dbSNicholas Bellinger 	}
634c66ac9dbSNicholas Bellinger 
635c66ac9dbSNicholas Bellinger 	return 0;
636c66ac9dbSNicholas Bellinger }
637c66ac9dbSNicholas Bellinger 
638c66ac9dbSNicholas Bellinger /*
639f1ae05d5SHannes Reinecke  * return 1: Is used to signal LUN not accessible, and check condition/not ready
640c66ac9dbSNicholas Bellinger  * return 0: Used to signal success
641f1ae05d5SHannes Reinecke  * return -1: Used to signal failure, and invalid cdb field
642c66ac9dbSNicholas Bellinger  */
643de103c93SChristoph Hellwig sense_reason_t
target_alua_state_check(struct se_cmd * cmd)644de103c93SChristoph Hellwig target_alua_state_check(struct se_cmd *cmd)
645c66ac9dbSNicholas Bellinger {
646c87fbd56SChristoph Hellwig 	struct se_device *dev = cmd->se_dev;
647c87fbd56SChristoph Hellwig 	unsigned char *cdb = cmd->t_task_cdb;
648e3d6f909SAndy Grover 	struct se_lun *lun = cmd->se_lun;
649c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp;
650c66ac9dbSNicholas Bellinger 	int out_alua_state, nonop_delay_msecs;
6517e457e5eSDavid Disseldorp 	u16 tg_pt_gp_id;
65240fd8845SDavid Disseldorp 	sense_reason_t rc = TCM_NO_SENSE;
653c87fbd56SChristoph Hellwig 
654c87fbd56SChristoph Hellwig 	if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)
655c87fbd56SChristoph Hellwig 		return 0;
65669088a04SBodo Stroesser 	if (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA)
657c87fbd56SChristoph Hellwig 		return 0;
658c66ac9dbSNicholas Bellinger 
659c66ac9dbSNicholas Bellinger 	/*
660c66ac9dbSNicholas Bellinger 	 * First, check for a struct se_port specific secondary ALUA target port
661c66ac9dbSNicholas Bellinger 	 * access state: OFFLINE
662c66ac9dbSNicholas Bellinger 	 */
663adf653f9SChristoph Hellwig 	if (atomic_read(&lun->lun_tg_pt_secondary_offline)) {
6646708bb27SAndy Grover 		pr_debug("ALUA: Got secondary offline status for local"
665c66ac9dbSNicholas Bellinger 				" target port\n");
66640fd8845SDavid Disseldorp 		return TCM_ALUA_OFFLINE;
667c66ac9dbSNicholas Bellinger 	}
6687324f47dSMike Christie 	rcu_read_lock();
6697324f47dSMike Christie 	tg_pt_gp = rcu_dereference(lun->lun_tg_pt_gp);
6707324f47dSMike Christie 	if (!tg_pt_gp) {
6717324f47dSMike Christie 		rcu_read_unlock();
67289c12cc9SNicholas Bellinger 		return 0;
6737324f47dSMike Christie 	}
67489c12cc9SNicholas Bellinger 
675d19c4643SMike Christie 	out_alua_state = tg_pt_gp->tg_pt_gp_alua_access_state;
676c66ac9dbSNicholas Bellinger 	nonop_delay_msecs = tg_pt_gp->tg_pt_gp_nonop_delay_msecs;
6777e457e5eSDavid Disseldorp 	tg_pt_gp_id = tg_pt_gp->tg_pt_gp_id;
6787324f47dSMike Christie 	rcu_read_unlock();
679c66ac9dbSNicholas Bellinger 	/*
68073f3bf51SHannes Reinecke 	 * Process ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED in a separate conditional
68125985edcSLucas De Marchi 	 * statement so the compiler knows explicitly to check this case first.
682c66ac9dbSNicholas Bellinger 	 * For the Optimized ALUA access state case, we want to process the
683c66ac9dbSNicholas Bellinger 	 * incoming fabric cmd ASAP..
684c66ac9dbSNicholas Bellinger 	 */
68573f3bf51SHannes Reinecke 	if (out_alua_state == ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED)
686c66ac9dbSNicholas Bellinger 		return 0;
687c66ac9dbSNicholas Bellinger 
688c66ac9dbSNicholas Bellinger 	switch (out_alua_state) {
689c66ac9dbSNicholas Bellinger 	case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
6901e3ab99dSPaul Bolle 		core_alua_state_nonoptimized(cmd, cdb, nonop_delay_msecs);
691c87fbd56SChristoph Hellwig 		break;
692c66ac9dbSNicholas Bellinger 	case ALUA_ACCESS_STATE_STANDBY:
69340fd8845SDavid Disseldorp 		rc = core_alua_state_standby(cmd, cdb);
694c87fbd56SChristoph Hellwig 		break;
695c66ac9dbSNicholas Bellinger 	case ALUA_ACCESS_STATE_UNAVAILABLE:
69640fd8845SDavid Disseldorp 		rc = core_alua_state_unavailable(cmd, cdb);
697c87fbd56SChristoph Hellwig 		break;
698c66ac9dbSNicholas Bellinger 	case ALUA_ACCESS_STATE_TRANSITION:
69940fd8845SDavid Disseldorp 		rc = core_alua_state_transition(cmd, cdb);
700c87fbd56SChristoph Hellwig 		break;
701c66094bfSHannes Reinecke 	case ALUA_ACCESS_STATE_LBA_DEPENDENT:
70240fd8845SDavid Disseldorp 		rc = core_alua_state_lba_dependent(cmd, tg_pt_gp_id);
703c66094bfSHannes Reinecke 		break;
704c66ac9dbSNicholas Bellinger 	/*
705c66ac9dbSNicholas Bellinger 	 * OFFLINE is a secondary ALUA target port group access state, that is
706adf653f9SChristoph Hellwig 	 * handled above with struct se_lun->lun_tg_pt_secondary_offline=1
707c66ac9dbSNicholas Bellinger 	 */
708c66ac9dbSNicholas Bellinger 	case ALUA_ACCESS_STATE_OFFLINE:
709c66ac9dbSNicholas Bellinger 	default:
7106708bb27SAndy Grover 		pr_err("Unknown ALUA access state: 0x%02x\n",
711c66ac9dbSNicholas Bellinger 				out_alua_state);
71240fd8845SDavid Disseldorp 		rc = TCM_INVALID_CDB_FIELD;
713c66ac9dbSNicholas Bellinger 	}
714c66ac9dbSNicholas Bellinger 
71540fd8845SDavid Disseldorp 	if (rc && rc != TCM_INVALID_CDB_FIELD) {
71640fd8845SDavid Disseldorp 		pr_debug("[%s]: ALUA TG Port not available, "
71740fd8845SDavid Disseldorp 			"SenseKey: NOT_READY, ASC/rc: 0x04/%d\n",
71840fd8845SDavid Disseldorp 			cmd->se_tfo->fabric_name, rc);
71940fd8845SDavid Disseldorp 	}
72040fd8845SDavid Disseldorp 
72140fd8845SDavid Disseldorp 	return rc;
722c66ac9dbSNicholas Bellinger }
723c66ac9dbSNicholas Bellinger 
724c66ac9dbSNicholas Bellinger /*
725125d0119SHannes Reinecke  * Check implicit and explicit ALUA state change request.
726c66ac9dbSNicholas Bellinger  */
727de103c93SChristoph Hellwig static sense_reason_t
core_alua_check_transition(int state,int valid,int * primary,int explicit)7281ca4d4faSMike Christie core_alua_check_transition(int state, int valid, int *primary, int explicit)
729c66ac9dbSNicholas Bellinger {
730c66ac9dbSNicholas Bellinger 	/*
731c66ac9dbSNicholas Bellinger 	 * OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are
732c66ac9dbSNicholas Bellinger 	 * defined as primary target port asymmetric access states.
733c66ac9dbSNicholas Bellinger 	 */
734bb91c1a0SHannes Reinecke 	switch (state) {
735bb91c1a0SHannes Reinecke 	case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED:
736bb91c1a0SHannes Reinecke 		if (!(valid & ALUA_AO_SUP))
737bb91c1a0SHannes Reinecke 			goto not_supported;
738bb91c1a0SHannes Reinecke 		*primary = 1;
739bb91c1a0SHannes Reinecke 		break;
740bb91c1a0SHannes Reinecke 	case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
741bb91c1a0SHannes Reinecke 		if (!(valid & ALUA_AN_SUP))
742bb91c1a0SHannes Reinecke 			goto not_supported;
743bb91c1a0SHannes Reinecke 		*primary = 1;
744bb91c1a0SHannes Reinecke 		break;
745bb91c1a0SHannes Reinecke 	case ALUA_ACCESS_STATE_STANDBY:
746bb91c1a0SHannes Reinecke 		if (!(valid & ALUA_S_SUP))
747bb91c1a0SHannes Reinecke 			goto not_supported;
748bb91c1a0SHannes Reinecke 		*primary = 1;
749bb91c1a0SHannes Reinecke 		break;
750bb91c1a0SHannes Reinecke 	case ALUA_ACCESS_STATE_UNAVAILABLE:
751bb91c1a0SHannes Reinecke 		if (!(valid & ALUA_U_SUP))
752bb91c1a0SHannes Reinecke 			goto not_supported;
753c66ac9dbSNicholas Bellinger 		*primary = 1;
754c66ac9dbSNicholas Bellinger 		break;
755c66094bfSHannes Reinecke 	case ALUA_ACCESS_STATE_LBA_DEPENDENT:
756c66094bfSHannes Reinecke 		if (!(valid & ALUA_LBD_SUP))
757c66094bfSHannes Reinecke 			goto not_supported;
758c66094bfSHannes Reinecke 		*primary = 1;
759c66094bfSHannes Reinecke 		break;
760c66ac9dbSNicholas Bellinger 	case ALUA_ACCESS_STATE_OFFLINE:
761c66ac9dbSNicholas Bellinger 		/*
762c66ac9dbSNicholas Bellinger 		 * OFFLINE state is defined as a secondary target port
763c66ac9dbSNicholas Bellinger 		 * asymmetric access state.
764c66ac9dbSNicholas Bellinger 		 */
765bb91c1a0SHannes Reinecke 		if (!(valid & ALUA_O_SUP))
766bb91c1a0SHannes Reinecke 			goto not_supported;
767c66ac9dbSNicholas Bellinger 		*primary = 0;
768c66ac9dbSNicholas Bellinger 		break;
769bb91c1a0SHannes Reinecke 	case ALUA_ACCESS_STATE_TRANSITION:
7701ca4d4faSMike Christie 		if (!(valid & ALUA_T_SUP) || explicit)
771bb91c1a0SHannes Reinecke 			/*
7721ca4d4faSMike Christie 			 * Transitioning is set internally and by tcmu daemon,
7731ca4d4faSMike Christie 			 * and cannot be selected through a STPG.
774bb91c1a0SHannes Reinecke 			 */
775bb91c1a0SHannes Reinecke 			goto not_supported;
7761ca4d4faSMike Christie 		*primary = 0;
7771ca4d4faSMike Christie 		break;
778c66ac9dbSNicholas Bellinger 	default:
7796708bb27SAndy Grover 		pr_err("Unknown ALUA access state: 0x%02x\n", state);
780de103c93SChristoph Hellwig 		return TCM_INVALID_PARAMETER_LIST;
781c66ac9dbSNicholas Bellinger 	}
782c66ac9dbSNicholas Bellinger 
783c66ac9dbSNicholas Bellinger 	return 0;
784bb91c1a0SHannes Reinecke 
785bb91c1a0SHannes Reinecke not_supported:
786bb91c1a0SHannes Reinecke 	pr_err("ALUA access state %s not supported",
787bb91c1a0SHannes Reinecke 	       core_alua_dump_state(state));
788bb91c1a0SHannes Reinecke 	return TCM_INVALID_PARAMETER_LIST;
789c66ac9dbSNicholas Bellinger }
790c66ac9dbSNicholas Bellinger 
core_alua_dump_state(int state)791c66ac9dbSNicholas Bellinger static char *core_alua_dump_state(int state)
792c66ac9dbSNicholas Bellinger {
793c66ac9dbSNicholas Bellinger 	switch (state) {
79473f3bf51SHannes Reinecke 	case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED:
795c66ac9dbSNicholas Bellinger 		return "Active/Optimized";
796c66ac9dbSNicholas Bellinger 	case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
797c66ac9dbSNicholas Bellinger 		return "Active/NonOptimized";
798c66094bfSHannes Reinecke 	case ALUA_ACCESS_STATE_LBA_DEPENDENT:
799c66094bfSHannes Reinecke 		return "LBA Dependent";
800c66ac9dbSNicholas Bellinger 	case ALUA_ACCESS_STATE_STANDBY:
801c66ac9dbSNicholas Bellinger 		return "Standby";
802c66ac9dbSNicholas Bellinger 	case ALUA_ACCESS_STATE_UNAVAILABLE:
803c66ac9dbSNicholas Bellinger 		return "Unavailable";
804c66ac9dbSNicholas Bellinger 	case ALUA_ACCESS_STATE_OFFLINE:
805c66ac9dbSNicholas Bellinger 		return "Offline";
806bb91c1a0SHannes Reinecke 	case ALUA_ACCESS_STATE_TRANSITION:
807bb91c1a0SHannes Reinecke 		return "Transitioning";
808c66ac9dbSNicholas Bellinger 	default:
809c66ac9dbSNicholas Bellinger 		return "Unknown";
810c66ac9dbSNicholas Bellinger 	}
811c66ac9dbSNicholas Bellinger 
812c66ac9dbSNicholas Bellinger 	return NULL;
813c66ac9dbSNicholas Bellinger }
814c66ac9dbSNicholas Bellinger 
core_alua_dump_status(int status)815c66ac9dbSNicholas Bellinger char *core_alua_dump_status(int status)
816c66ac9dbSNicholas Bellinger {
817c66ac9dbSNicholas Bellinger 	switch (status) {
818c66ac9dbSNicholas Bellinger 	case ALUA_STATUS_NONE:
819c66ac9dbSNicholas Bellinger 		return "None";
820125d0119SHannes Reinecke 	case ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG:
821125d0119SHannes Reinecke 		return "Altered by Explicit STPG";
822125d0119SHannes Reinecke 	case ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA:
823125d0119SHannes Reinecke 		return "Altered by Implicit ALUA";
824c66ac9dbSNicholas Bellinger 	default:
825c66ac9dbSNicholas Bellinger 		return "Unknown";
826c66ac9dbSNicholas Bellinger 	}
827c66ac9dbSNicholas Bellinger 
828c66ac9dbSNicholas Bellinger 	return NULL;
829c66ac9dbSNicholas Bellinger }
830c66ac9dbSNicholas Bellinger 
831c66ac9dbSNicholas Bellinger /*
832c66ac9dbSNicholas Bellinger  * Used by fabric modules to determine when we need to delay processing
833c66ac9dbSNicholas Bellinger  * for the Active/NonOptimized paths..
834c66ac9dbSNicholas Bellinger  */
core_alua_check_nonop_delay(struct se_cmd * cmd)835c66ac9dbSNicholas Bellinger int core_alua_check_nonop_delay(
836c66ac9dbSNicholas Bellinger 	struct se_cmd *cmd)
837c66ac9dbSNicholas Bellinger {
838c66ac9dbSNicholas Bellinger 	if (!(cmd->se_cmd_flags & SCF_ALUA_NON_OPTIMIZED))
839c66ac9dbSNicholas Bellinger 		return 0;
840c66ac9dbSNicholas Bellinger 	/*
841c66ac9dbSNicholas Bellinger 	 * The ALUA Active/NonOptimized access state delay can be disabled
842c66ac9dbSNicholas Bellinger 	 * in via configfs with a value of zero
843c66ac9dbSNicholas Bellinger 	 */
8446708bb27SAndy Grover 	if (!cmd->alua_nonop_delay)
845c66ac9dbSNicholas Bellinger 		return 0;
846c66ac9dbSNicholas Bellinger 	/*
847c66ac9dbSNicholas Bellinger 	 * struct se_cmd->alua_nonop_delay gets set by a target port group
848c66ac9dbSNicholas Bellinger 	 * defined interval in core_alua_state_nonoptimized()
849c66ac9dbSNicholas Bellinger 	 */
850c66ac9dbSNicholas Bellinger 	msleep_interruptible(cmd->alua_nonop_delay);
851c66ac9dbSNicholas Bellinger 	return 0;
852c66ac9dbSNicholas Bellinger }
853c66ac9dbSNicholas Bellinger EXPORT_SYMBOL(core_alua_check_nonop_delay);
854c66ac9dbSNicholas Bellinger 
core_alua_write_tpg_metadata(const char * path,unsigned char * md_buf,u32 md_buf_len)855c66ac9dbSNicholas Bellinger static int core_alua_write_tpg_metadata(
856c66ac9dbSNicholas Bellinger 	const char *path,
857c66ac9dbSNicholas Bellinger 	unsigned char *md_buf,
858c66ac9dbSNicholas Bellinger 	u32 md_buf_len)
859c66ac9dbSNicholas Bellinger {
8600e9b10a9SAl Viro 	struct file *file = filp_open(path, O_RDWR | O_CREAT | O_TRUNC, 0600);
861e13ec939SChristoph Hellwig 	loff_t pos = 0;
8620e9b10a9SAl Viro 	int ret;
863c66ac9dbSNicholas Bellinger 
8640e9b10a9SAl Viro 	if (IS_ERR(file)) {
8650e9b10a9SAl Viro 		pr_err("filp_open(%s) for ALUA metadata failed\n", path);
866c66ac9dbSNicholas Bellinger 		return -ENODEV;
867c66ac9dbSNicholas Bellinger 	}
868e13ec939SChristoph Hellwig 	ret = kernel_write(file, md_buf, md_buf_len, &pos);
8690e9b10a9SAl Viro 	if (ret < 0)
8706708bb27SAndy Grover 		pr_err("Error writing ALUA metadata file: %s\n", path);
8710e9b10a9SAl Viro 	fput(file);
872f730f915SGera Kazakov 	return (ret < 0) ? -EIO : 0;
873c66ac9dbSNicholas Bellinger }
874c66ac9dbSNicholas Bellinger 
core_alua_update_tpg_primary_metadata(struct t10_alua_tg_pt_gp * tg_pt_gp)875c66ac9dbSNicholas Bellinger static int core_alua_update_tpg_primary_metadata(
8769c6e164cSHannes Reinecke 	struct t10_alua_tg_pt_gp *tg_pt_gp)
877c66ac9dbSNicholas Bellinger {
8781e0b9403SHannes Reinecke 	unsigned char *md_buf;
8790fd97ccfSChristoph Hellwig 	struct t10_wwn *wwn = &tg_pt_gp->tg_pt_gp_dev->t10_wwn;
88055435badSDavid Disseldorp 	char *path;
8811e0b9403SHannes Reinecke 	int len, rc;
8821e0b9403SHannes Reinecke 
883618baaf7SBart Van Assche 	lockdep_assert_held(&tg_pt_gp->tg_pt_gp_transition_mutex);
884618baaf7SBart Van Assche 
8851e0b9403SHannes Reinecke 	md_buf = kzalloc(ALUA_MD_BUF_LEN, GFP_KERNEL);
8861e0b9403SHannes Reinecke 	if (!md_buf) {
8871e0b9403SHannes Reinecke 		pr_err("Unable to allocate buf for ALUA metadata\n");
8881e0b9403SHannes Reinecke 		return -ENOMEM;
8891e0b9403SHannes Reinecke 	}
890c66ac9dbSNicholas Bellinger 
8911e0b9403SHannes Reinecke 	len = snprintf(md_buf, ALUA_MD_BUF_LEN,
892c66ac9dbSNicholas Bellinger 			"tg_pt_gp_id=%hu\n"
893c66ac9dbSNicholas Bellinger 			"alua_access_state=0x%02x\n"
894c66ac9dbSNicholas Bellinger 			"alua_access_status=0x%02x\n",
8959c6e164cSHannes Reinecke 			tg_pt_gp->tg_pt_gp_id,
896d19c4643SMike Christie 			tg_pt_gp->tg_pt_gp_alua_access_state,
897c66ac9dbSNicholas Bellinger 			tg_pt_gp->tg_pt_gp_alua_access_status);
898c66ac9dbSNicholas Bellinger 
89955435badSDavid Disseldorp 	rc = -ENOMEM;
90055435badSDavid Disseldorp 	path = kasprintf(GFP_KERNEL, "%s/alua/tpgs_%s/%s", db_root,
90155435badSDavid Disseldorp 			&wwn->unit_serial[0],
902c66ac9dbSNicholas Bellinger 			config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item));
90355435badSDavid Disseldorp 	if (path) {
9041e0b9403SHannes Reinecke 		rc = core_alua_write_tpg_metadata(path, md_buf, len);
90555435badSDavid Disseldorp 		kfree(path);
90655435badSDavid Disseldorp 	}
9071e0b9403SHannes Reinecke 	kfree(md_buf);
9081e0b9403SHannes Reinecke 	return rc;
909c66ac9dbSNicholas Bellinger }
910c66ac9dbSNicholas Bellinger 
core_alua_queue_state_change_ua(struct t10_alua_tg_pt_gp * tg_pt_gp)911ee8c07d0SHannes Reinecke static void core_alua_queue_state_change_ua(struct t10_alua_tg_pt_gp *tg_pt_gp)
912c66ac9dbSNicholas Bellinger {
913c66ac9dbSNicholas Bellinger 	struct se_dev_entry *se_deve;
914adf653f9SChristoph Hellwig 	struct se_lun *lun;
915c66ac9dbSNicholas Bellinger 	struct se_lun_acl *lacl;
916c66ac9dbSNicholas Bellinger 
917c66ac9dbSNicholas Bellinger 	spin_lock(&tg_pt_gp->tg_pt_gp_lock);
918adf653f9SChristoph Hellwig 	list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list,
919adf653f9SChristoph Hellwig 				lun_tg_pt_gp_link) {
920c66ac9dbSNicholas Bellinger 		/*
921c66ac9dbSNicholas Bellinger 		 * After an implicit target port asymmetric access state
922c66ac9dbSNicholas Bellinger 		 * change, a device server shall establish a unit attention
923c66ac9dbSNicholas Bellinger 		 * condition for the initiator port associated with every I_T
924c66ac9dbSNicholas Bellinger 		 * nexus with the additional sense code set to ASYMMETRIC
925f1ae05d5SHannes Reinecke 		 * ACCESS STATE CHANGED.
926c66ac9dbSNicholas Bellinger 		 *
927c66ac9dbSNicholas Bellinger 		 * After an explicit target port asymmetric access state
928c66ac9dbSNicholas Bellinger 		 * change, a device server shall establish a unit attention
929c66ac9dbSNicholas Bellinger 		 * condition with the additional sense code set to ASYMMETRIC
930c66ac9dbSNicholas Bellinger 		 * ACCESS STATE CHANGED for the initiator port associated with
931c66ac9dbSNicholas Bellinger 		 * every I_T nexus other than the I_T nexus on which the SET
932c66ac9dbSNicholas Bellinger 		 * TARGET PORT GROUPS command
933c66ac9dbSNicholas Bellinger 		 */
9349e37d042SNicholas Bellinger 		if (!percpu_ref_tryget_live(&lun->lun_ref))
9359e37d042SNicholas Bellinger 			continue;
936c66ac9dbSNicholas Bellinger 		spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
937c66ac9dbSNicholas Bellinger 
9381adff1b3SNicholas Bellinger 		spin_lock(&lun->lun_deve_lock);
939adf653f9SChristoph Hellwig 		list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link) {
940ef4f7e4bSDmitry Bogdanov 			lacl = se_deve->se_lun_acl;
941c66ac9dbSNicholas Bellinger 
942c51c8e7bSHannes Reinecke 			/*
943c51c8e7bSHannes Reinecke 			 * spc4r37 p.242:
944c51c8e7bSHannes Reinecke 			 * After an explicit target port asymmetric access
945c51c8e7bSHannes Reinecke 			 * state change, a device server shall establish a
946c51c8e7bSHannes Reinecke 			 * unit attention condition with the additional sense
947c51c8e7bSHannes Reinecke 			 * code set to ASYMMETRIC ACCESS STATE CHANGED for
948c51c8e7bSHannes Reinecke 			 * the initiator port associated with every I_T nexus
949c51c8e7bSHannes Reinecke 			 * other than the I_T nexus on which the SET TARGET
950c51c8e7bSHannes Reinecke 			 * PORT GROUPS command was received.
951c51c8e7bSHannes Reinecke 			 */
9529c6e164cSHannes Reinecke 			if ((tg_pt_gp->tg_pt_gp_alua_access_status ==
9539c6e164cSHannes Reinecke 			     ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG) &&
954adf653f9SChristoph Hellwig 			   (tg_pt_gp->tg_pt_gp_alua_lun != NULL) &&
955adf653f9SChristoph Hellwig 			    (tg_pt_gp->tg_pt_gp_alua_lun == lun))
956c66ac9dbSNicholas Bellinger 				continue;
957c66ac9dbSNicholas Bellinger 
958c66ac9dbSNicholas Bellinger 			/*
959c66ac9dbSNicholas Bellinger 			 * se_deve->se_lun_acl pointer may be NULL for a
960c66ac9dbSNicholas Bellinger 			 * entry created without explicit Node+MappedLUN ACLs
961c66ac9dbSNicholas Bellinger 			 */
962c51c8e7bSHannes Reinecke 			if (lacl && (tg_pt_gp->tg_pt_gp_alua_nacl != NULL) &&
963c51c8e7bSHannes Reinecke 			    (tg_pt_gp->tg_pt_gp_alua_nacl == lacl->se_lun_nacl))
964c66ac9dbSNicholas Bellinger 				continue;
965c66ac9dbSNicholas Bellinger 
966c51c8e7bSHannes Reinecke 			core_scsi3_ua_allocate(se_deve, 0x2A,
967c66ac9dbSNicholas Bellinger 				ASCQ_2AH_ASYMMETRIC_ACCESS_STATE_CHANGED);
968c66ac9dbSNicholas Bellinger 		}
9691adff1b3SNicholas Bellinger 		spin_unlock(&lun->lun_deve_lock);
970c66ac9dbSNicholas Bellinger 
971c66ac9dbSNicholas Bellinger 		spin_lock(&tg_pt_gp->tg_pt_gp_lock);
9729e37d042SNicholas Bellinger 		percpu_ref_put(&lun->lun_ref);
973c66ac9dbSNicholas Bellinger 	}
974c66ac9dbSNicholas Bellinger 	spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
975ee8c07d0SHannes Reinecke }
976ee8c07d0SHannes Reinecke 
core_alua_do_transition_tg_pt(struct t10_alua_tg_pt_gp * tg_pt_gp,int new_state,int explicit)977d19c4643SMike Christie static int core_alua_do_transition_tg_pt(
978d19c4643SMike Christie 	struct t10_alua_tg_pt_gp *tg_pt_gp,
979d19c4643SMike Christie 	int new_state,
980d19c4643SMike Christie 	int explicit)
981ee8c07d0SHannes Reinecke {
982d19c4643SMike Christie 	int prev_state;
983d19c4643SMike Christie 
984d19c4643SMike Christie 	mutex_lock(&tg_pt_gp->tg_pt_gp_transition_mutex);
985d19c4643SMike Christie 	/* Nothing to be done here */
986d19c4643SMike Christie 	if (tg_pt_gp->tg_pt_gp_alua_access_state == new_state) {
987d19c4643SMike Christie 		mutex_unlock(&tg_pt_gp->tg_pt_gp_transition_mutex);
988d19c4643SMike Christie 		return 0;
989d19c4643SMike Christie 	}
990d19c4643SMike Christie 
991d19c4643SMike Christie 	if (explicit && new_state == ALUA_ACCESS_STATE_TRANSITION) {
992d19c4643SMike Christie 		mutex_unlock(&tg_pt_gp->tg_pt_gp_transition_mutex);
993d19c4643SMike Christie 		return -EAGAIN;
994d19c4643SMike Christie 	}
995d19c4643SMike Christie 
996d19c4643SMike Christie 	/*
997d19c4643SMike Christie 	 * Save the old primary ALUA access state, and set the current state
998d19c4643SMike Christie 	 * to ALUA_ACCESS_STATE_TRANSITION.
999d19c4643SMike Christie 	 */
1000d19c4643SMike Christie 	prev_state = tg_pt_gp->tg_pt_gp_alua_access_state;
1001d19c4643SMike Christie 	tg_pt_gp->tg_pt_gp_alua_access_state = ALUA_ACCESS_STATE_TRANSITION;
1002d19c4643SMike Christie 	tg_pt_gp->tg_pt_gp_alua_access_status = (explicit) ?
1003d19c4643SMike Christie 				ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG :
1004d19c4643SMike Christie 				ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA;
1005d19c4643SMike Christie 
1006d19c4643SMike Christie 	core_alua_queue_state_change_ua(tg_pt_gp);
1007d19c4643SMike Christie 
1008d19c4643SMike Christie 	if (new_state == ALUA_ACCESS_STATE_TRANSITION) {
1009d19c4643SMike Christie 		mutex_unlock(&tg_pt_gp->tg_pt_gp_transition_mutex);
1010d19c4643SMike Christie 		return 0;
1011d19c4643SMike Christie 	}
1012d19c4643SMike Christie 
1013d19c4643SMike Christie 	/*
1014d19c4643SMike Christie 	 * Check for the optional ALUA primary state transition delay
1015d19c4643SMike Christie 	 */
1016d19c4643SMike Christie 	if (tg_pt_gp->tg_pt_gp_trans_delay_msecs != 0)
1017d19c4643SMike Christie 		msleep_interruptible(tg_pt_gp->tg_pt_gp_trans_delay_msecs);
1018d19c4643SMike Christie 
1019d19c4643SMike Christie 	/*
1020d19c4643SMike Christie 	 * Set the current primary ALUA access state to the requested new state
1021d19c4643SMike Christie 	 */
1022d19c4643SMike Christie 	tg_pt_gp->tg_pt_gp_alua_access_state = new_state;
1023ee8c07d0SHannes Reinecke 
1024c66ac9dbSNicholas Bellinger 	/*
1025c66ac9dbSNicholas Bellinger 	 * Update the ALUA metadata buf that has been allocated in
1026c66ac9dbSNicholas Bellinger 	 * core_alua_do_port_transition(), this metadata will be written
1027c66ac9dbSNicholas Bellinger 	 * to struct file.
1028c66ac9dbSNicholas Bellinger 	 *
1029c66ac9dbSNicholas Bellinger 	 * Note that there is the case where we do not want to update the
1030c66ac9dbSNicholas Bellinger 	 * metadata when the saved metadata is being parsed in userspace
1031c66ac9dbSNicholas Bellinger 	 * when setting the existing port access state and access status.
1032c66ac9dbSNicholas Bellinger 	 *
1033c66ac9dbSNicholas Bellinger 	 * Also note that the failure to write out the ALUA metadata to
1034c66ac9dbSNicholas Bellinger 	 * struct file does NOT affect the actual ALUA transition.
1035c66ac9dbSNicholas Bellinger 	 */
1036c66ac9dbSNicholas Bellinger 	if (tg_pt_gp->tg_pt_gp_write_metadata) {
10379c6e164cSHannes Reinecke 		core_alua_update_tpg_primary_metadata(tg_pt_gp);
1038c66ac9dbSNicholas Bellinger 	}
1039c66ac9dbSNicholas Bellinger 
10406708bb27SAndy Grover 	pr_debug("Successful %s ALUA transition TG PT Group: %s ID: %hu"
1041125d0119SHannes Reinecke 		" from primary access state %s to %s\n", (explicit) ? "explicit" :
1042125d0119SHannes Reinecke 		"implicit", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item),
1043dfbce75aSHannes Reinecke 		tg_pt_gp->tg_pt_gp_id,
1044d19c4643SMike Christie 		core_alua_dump_state(prev_state),
1045d19c4643SMike Christie 		core_alua_dump_state(new_state));
1046ee8c07d0SHannes Reinecke 
1047ee8c07d0SHannes Reinecke 	core_alua_queue_state_change_ua(tg_pt_gp);
1048ee8c07d0SHannes Reinecke 
1049d19c4643SMike Christie 	mutex_unlock(&tg_pt_gp->tg_pt_gp_transition_mutex);
1050c66ac9dbSNicholas Bellinger 	return 0;
1051c66ac9dbSNicholas Bellinger }
1052c66ac9dbSNicholas Bellinger 
core_alua_do_port_transition(struct t10_alua_tg_pt_gp * l_tg_pt_gp,struct se_device * l_dev,struct se_lun * l_lun,struct se_node_acl * l_nacl,int new_state,int explicit)1053c66ac9dbSNicholas Bellinger int core_alua_do_port_transition(
1054c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *l_tg_pt_gp,
1055c66ac9dbSNicholas Bellinger 	struct se_device *l_dev,
1056adf653f9SChristoph Hellwig 	struct se_lun *l_lun,
1057c66ac9dbSNicholas Bellinger 	struct se_node_acl *l_nacl,
1058c66ac9dbSNicholas Bellinger 	int new_state,
1059125d0119SHannes Reinecke 	int explicit)
1060c66ac9dbSNicholas Bellinger {
1061c66ac9dbSNicholas Bellinger 	struct se_device *dev;
1062c66ac9dbSNicholas Bellinger 	struct t10_alua_lu_gp *lu_gp;
1063c66ac9dbSNicholas Bellinger 	struct t10_alua_lu_gp_member *lu_gp_mem, *local_lu_gp_mem;
1064c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp;
10659c6e164cSHannes Reinecke 	int primary, valid_states, rc = 0;
1066c66ac9dbSNicholas Bellinger 
106769088a04SBodo Stroesser 	if (l_dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA)
10680a414572SMike Christie 		return -ENODEV;
10690a414572SMike Christie 
1070bb91c1a0SHannes Reinecke 	valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states;
10711ca4d4faSMike Christie 	if (core_alua_check_transition(new_state, valid_states, &primary,
10721ca4d4faSMike Christie 				       explicit) != 0)
1073c66ac9dbSNicholas Bellinger 		return -EINVAL;
1074c66ac9dbSNicholas Bellinger 
1075c66ac9dbSNicholas Bellinger 	local_lu_gp_mem = l_dev->dev_alua_lu_gp_mem;
1076c66ac9dbSNicholas Bellinger 	spin_lock(&local_lu_gp_mem->lu_gp_mem_lock);
1077c66ac9dbSNicholas Bellinger 	lu_gp = local_lu_gp_mem->lu_gp;
1078c66ac9dbSNicholas Bellinger 	atomic_inc(&lu_gp->lu_gp_ref_cnt);
1079c66ac9dbSNicholas Bellinger 	spin_unlock(&local_lu_gp_mem->lu_gp_mem_lock);
1080c66ac9dbSNicholas Bellinger 	/*
1081c66ac9dbSNicholas Bellinger 	 * For storage objects that are members of the 'default_lu_gp',
1082c66ac9dbSNicholas Bellinger 	 * we only do transition on the passed *l_tp_pt_gp, and not
1083c66ac9dbSNicholas Bellinger 	 * on all of the matching target port groups IDs in default_lu_gp.
1084c66ac9dbSNicholas Bellinger 	 */
10856708bb27SAndy Grover 	if (!lu_gp->lu_gp_id) {
1086c66ac9dbSNicholas Bellinger 		/*
1087c66ac9dbSNicholas Bellinger 		 * core_alua_do_transition_tg_pt() will always return
1088c66ac9dbSNicholas Bellinger 		 * success.
1089c66ac9dbSNicholas Bellinger 		 */
1090adf653f9SChristoph Hellwig 		l_tg_pt_gp->tg_pt_gp_alua_lun = l_lun;
10919c6e164cSHannes Reinecke 		l_tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl;
10929c6e164cSHannes Reinecke 		rc = core_alua_do_transition_tg_pt(l_tg_pt_gp,
10931e0b9403SHannes Reinecke 						   new_state, explicit);
109433940d09SJoern Engel 		atomic_dec_mb(&lu_gp->lu_gp_ref_cnt);
10959c6e164cSHannes Reinecke 		return rc;
1096c66ac9dbSNicholas Bellinger 	}
1097c66ac9dbSNicholas Bellinger 	/*
1098c66ac9dbSNicholas Bellinger 	 * For all other LU groups aside from 'default_lu_gp', walk all of
1099c66ac9dbSNicholas Bellinger 	 * the associated storage objects looking for a matching target port
1100c66ac9dbSNicholas Bellinger 	 * group ID from the local target port group.
1101c66ac9dbSNicholas Bellinger 	 */
1102c66ac9dbSNicholas Bellinger 	spin_lock(&lu_gp->lu_gp_lock);
1103c66ac9dbSNicholas Bellinger 	list_for_each_entry(lu_gp_mem, &lu_gp->lu_gp_mem_list,
1104c66ac9dbSNicholas Bellinger 				lu_gp_mem_list) {
1105c66ac9dbSNicholas Bellinger 
1106c66ac9dbSNicholas Bellinger 		dev = lu_gp_mem->lu_gp_mem_dev;
110733940d09SJoern Engel 		atomic_inc_mb(&lu_gp_mem->lu_gp_mem_ref_cnt);
1108c66ac9dbSNicholas Bellinger 		spin_unlock(&lu_gp->lu_gp_lock);
1109c66ac9dbSNicholas Bellinger 
11100fd97ccfSChristoph Hellwig 		spin_lock(&dev->t10_alua.tg_pt_gps_lock);
1111c66ac9dbSNicholas Bellinger 		list_for_each_entry(tg_pt_gp,
11120fd97ccfSChristoph Hellwig 				&dev->t10_alua.tg_pt_gps_list,
1113c66ac9dbSNicholas Bellinger 				tg_pt_gp_list) {
1114c66ac9dbSNicholas Bellinger 
11156708bb27SAndy Grover 			if (!tg_pt_gp->tg_pt_gp_valid_id)
1116c66ac9dbSNicholas Bellinger 				continue;
1117c66ac9dbSNicholas Bellinger 			/*
1118c66ac9dbSNicholas Bellinger 			 * If the target behavior port asymmetric access state
1119f1ae05d5SHannes Reinecke 			 * is changed for any target port group accessible via
1120c66ac9dbSNicholas Bellinger 			 * a logical unit within a LU group, the target port
1121c66ac9dbSNicholas Bellinger 			 * behavior group asymmetric access states for the same
1122c66ac9dbSNicholas Bellinger 			 * target port group accessible via other logical units
1123c66ac9dbSNicholas Bellinger 			 * in that LU group will also change.
1124c66ac9dbSNicholas Bellinger 			 */
1125c66ac9dbSNicholas Bellinger 			if (l_tg_pt_gp->tg_pt_gp_id != tg_pt_gp->tg_pt_gp_id)
1126c66ac9dbSNicholas Bellinger 				continue;
1127c66ac9dbSNicholas Bellinger 
1128c66ac9dbSNicholas Bellinger 			if (l_tg_pt_gp == tg_pt_gp) {
1129adf653f9SChristoph Hellwig 				tg_pt_gp->tg_pt_gp_alua_lun = l_lun;
11309c6e164cSHannes Reinecke 				tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl;
1131c66ac9dbSNicholas Bellinger 			} else {
1132adf653f9SChristoph Hellwig 				tg_pt_gp->tg_pt_gp_alua_lun = NULL;
11339c6e164cSHannes Reinecke 				tg_pt_gp->tg_pt_gp_alua_nacl = NULL;
1134c66ac9dbSNicholas Bellinger 			}
113533940d09SJoern Engel 			atomic_inc_mb(&tg_pt_gp->tg_pt_gp_ref_cnt);
11360fd97ccfSChristoph Hellwig 			spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
1137c66ac9dbSNicholas Bellinger 			/*
1138c66ac9dbSNicholas Bellinger 			 * core_alua_do_transition_tg_pt() will always return
1139c66ac9dbSNicholas Bellinger 			 * success.
1140c66ac9dbSNicholas Bellinger 			 */
11419c6e164cSHannes Reinecke 			rc = core_alua_do_transition_tg_pt(tg_pt_gp,
11429c6e164cSHannes Reinecke 					new_state, explicit);
1143c66ac9dbSNicholas Bellinger 
11440fd97ccfSChristoph Hellwig 			spin_lock(&dev->t10_alua.tg_pt_gps_lock);
114533940d09SJoern Engel 			atomic_dec_mb(&tg_pt_gp->tg_pt_gp_ref_cnt);
11469c6e164cSHannes Reinecke 			if (rc)
11479c6e164cSHannes Reinecke 				break;
1148c66ac9dbSNicholas Bellinger 		}
11490fd97ccfSChristoph Hellwig 		spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
1150c66ac9dbSNicholas Bellinger 
1151c66ac9dbSNicholas Bellinger 		spin_lock(&lu_gp->lu_gp_lock);
115233940d09SJoern Engel 		atomic_dec_mb(&lu_gp_mem->lu_gp_mem_ref_cnt);
1153c66ac9dbSNicholas Bellinger 	}
1154c66ac9dbSNicholas Bellinger 	spin_unlock(&lu_gp->lu_gp_lock);
1155c66ac9dbSNicholas Bellinger 
11569c6e164cSHannes Reinecke 	if (!rc) {
11576708bb27SAndy Grover 		pr_debug("Successfully processed LU Group: %s all ALUA TG PT"
1158c66ac9dbSNicholas Bellinger 			 " Group IDs: %hu %s transition to primary state: %s\n",
1159c66ac9dbSNicholas Bellinger 			 config_item_name(&lu_gp->lu_gp_group.cg_item),
11609c6e164cSHannes Reinecke 			 l_tg_pt_gp->tg_pt_gp_id,
11619c6e164cSHannes Reinecke 			 (explicit) ? "explicit" : "implicit",
1162c66ac9dbSNicholas Bellinger 			 core_alua_dump_state(new_state));
11639c6e164cSHannes Reinecke 	}
1164c66ac9dbSNicholas Bellinger 
116533940d09SJoern Engel 	atomic_dec_mb(&lu_gp->lu_gp_ref_cnt);
11669c6e164cSHannes Reinecke 	return rc;
1167c66ac9dbSNicholas Bellinger }
1168c66ac9dbSNicholas Bellinger 
core_alua_update_tpg_secondary_metadata(struct se_lun * lun)1169adf653f9SChristoph Hellwig static int core_alua_update_tpg_secondary_metadata(struct se_lun *lun)
1170c66ac9dbSNicholas Bellinger {
1171adf653f9SChristoph Hellwig 	struct se_portal_group *se_tpg = lun->lun_tpg;
11721e0b9403SHannes Reinecke 	unsigned char *md_buf;
117355435badSDavid Disseldorp 	char *path;
11741e0b9403SHannes Reinecke 	int len, rc;
11751e0b9403SHannes Reinecke 
1176adf653f9SChristoph Hellwig 	mutex_lock(&lun->lun_tg_pt_md_mutex);
1177adf653f9SChristoph Hellwig 
11781e0b9403SHannes Reinecke 	md_buf = kzalloc(ALUA_MD_BUF_LEN, GFP_KERNEL);
11791e0b9403SHannes Reinecke 	if (!md_buf) {
11801e0b9403SHannes Reinecke 		pr_err("Unable to allocate buf for ALUA metadata\n");
1181adf653f9SChristoph Hellwig 		rc = -ENOMEM;
1182adf653f9SChristoph Hellwig 		goto out_unlock;
11831e0b9403SHannes Reinecke 	}
1184c66ac9dbSNicholas Bellinger 
11851e0b9403SHannes Reinecke 	len = snprintf(md_buf, ALUA_MD_BUF_LEN, "alua_tg_pt_offline=%d\n"
1186c66ac9dbSNicholas Bellinger 			"alua_tg_pt_status=0x%02x\n",
1187adf653f9SChristoph Hellwig 			atomic_read(&lun->lun_tg_pt_secondary_offline),
1188adf653f9SChristoph Hellwig 			lun->lun_tg_pt_secondary_stat);
1189c66ac9dbSNicholas Bellinger 
119055435badSDavid Disseldorp 	if (se_tpg->se_tpg_tfo->tpg_get_tag != NULL) {
119155435badSDavid Disseldorp 		path = kasprintf(GFP_KERNEL, "%s/alua/%s/%s+%hu/lun_%llu",
119230c7ca93SDavid Disseldorp 				db_root, se_tpg->se_tpg_tfo->fabric_name,
119355435badSDavid Disseldorp 				se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg),
119455435badSDavid Disseldorp 				se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg),
1195adf653f9SChristoph Hellwig 				lun->unpacked_lun);
119655435badSDavid Disseldorp 	} else {
119755435badSDavid Disseldorp 		path = kasprintf(GFP_KERNEL, "%s/alua/%s/%s/lun_%llu",
119830c7ca93SDavid Disseldorp 				db_root, se_tpg->se_tpg_tfo->fabric_name,
119955435badSDavid Disseldorp 				se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg),
120055435badSDavid Disseldorp 				lun->unpacked_lun);
120155435badSDavid Disseldorp 	}
120255435badSDavid Disseldorp 	if (!path) {
120355435badSDavid Disseldorp 		rc = -ENOMEM;
120455435badSDavid Disseldorp 		goto out_free;
120555435badSDavid Disseldorp 	}
1206c66ac9dbSNicholas Bellinger 
12071e0b9403SHannes Reinecke 	rc = core_alua_write_tpg_metadata(path, md_buf, len);
120855435badSDavid Disseldorp 	kfree(path);
120955435badSDavid Disseldorp out_free:
12101e0b9403SHannes Reinecke 	kfree(md_buf);
1211adf653f9SChristoph Hellwig out_unlock:
1212adf653f9SChristoph Hellwig 	mutex_unlock(&lun->lun_tg_pt_md_mutex);
12131e0b9403SHannes Reinecke 	return rc;
1214c66ac9dbSNicholas Bellinger }
1215c66ac9dbSNicholas Bellinger 
core_alua_set_tg_pt_secondary_state(struct se_lun * lun,int explicit,int offline)1216c66ac9dbSNicholas Bellinger static int core_alua_set_tg_pt_secondary_state(
1217adf653f9SChristoph Hellwig 	struct se_lun *lun,
1218125d0119SHannes Reinecke 	int explicit,
1219c66ac9dbSNicholas Bellinger 	int offline)
1220c66ac9dbSNicholas Bellinger {
1221c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp;
1222c66ac9dbSNicholas Bellinger 	int trans_delay_msecs;
1223c66ac9dbSNicholas Bellinger 
12247324f47dSMike Christie 	rcu_read_lock();
12257324f47dSMike Christie 	tg_pt_gp = rcu_dereference(lun->lun_tg_pt_gp);
12266708bb27SAndy Grover 	if (!tg_pt_gp) {
12277324f47dSMike Christie 		rcu_read_unlock();
12286708bb27SAndy Grover 		pr_err("Unable to complete secondary state"
1229c66ac9dbSNicholas Bellinger 				" transition\n");
1230e3d6f909SAndy Grover 		return -EINVAL;
1231c66ac9dbSNicholas Bellinger 	}
1232c66ac9dbSNicholas Bellinger 	trans_delay_msecs = tg_pt_gp->tg_pt_gp_trans_delay_msecs;
1233c66ac9dbSNicholas Bellinger 	/*
1234c66ac9dbSNicholas Bellinger 	 * Set the secondary ALUA target port access state to OFFLINE
1235adf653f9SChristoph Hellwig 	 * or release the previously secondary state for struct se_lun
1236c66ac9dbSNicholas Bellinger 	 */
1237c66ac9dbSNicholas Bellinger 	if (offline)
1238adf653f9SChristoph Hellwig 		atomic_set(&lun->lun_tg_pt_secondary_offline, 1);
1239c66ac9dbSNicholas Bellinger 	else
1240adf653f9SChristoph Hellwig 		atomic_set(&lun->lun_tg_pt_secondary_offline, 0);
1241c66ac9dbSNicholas Bellinger 
1242adf653f9SChristoph Hellwig 	lun->lun_tg_pt_secondary_stat = (explicit) ?
1243125d0119SHannes Reinecke 			ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG :
1244125d0119SHannes Reinecke 			ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA;
1245c66ac9dbSNicholas Bellinger 
12466708bb27SAndy Grover 	pr_debug("Successful %s ALUA transition TG PT Group: %s ID: %hu"
1247125d0119SHannes Reinecke 		" to secondary access state: %s\n", (explicit) ? "explicit" :
1248125d0119SHannes Reinecke 		"implicit", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item),
1249c66ac9dbSNicholas Bellinger 		tg_pt_gp->tg_pt_gp_id, (offline) ? "OFFLINE" : "ONLINE");
1250c66ac9dbSNicholas Bellinger 
12517324f47dSMike Christie 	rcu_read_unlock();
1252c66ac9dbSNicholas Bellinger 	/*
1253c66ac9dbSNicholas Bellinger 	 * Do the optional transition delay after we set the secondary
1254c66ac9dbSNicholas Bellinger 	 * ALUA access state.
1255c66ac9dbSNicholas Bellinger 	 */
1256c66ac9dbSNicholas Bellinger 	if (trans_delay_msecs != 0)
1257c66ac9dbSNicholas Bellinger 		msleep_interruptible(trans_delay_msecs);
1258c66ac9dbSNicholas Bellinger 	/*
1259c66ac9dbSNicholas Bellinger 	 * See if we need to update the ALUA fabric port metadata for
1260c66ac9dbSNicholas Bellinger 	 * secondary state and status
1261c66ac9dbSNicholas Bellinger 	 */
1262adf653f9SChristoph Hellwig 	if (lun->lun_tg_pt_secondary_write_md)
1263adf653f9SChristoph Hellwig 		core_alua_update_tpg_secondary_metadata(lun);
1264c66ac9dbSNicholas Bellinger 
1265c66ac9dbSNicholas Bellinger 	return 0;
1266c66ac9dbSNicholas Bellinger }
1267c66ac9dbSNicholas Bellinger 
1268229d4f11SHannes Reinecke struct t10_alua_lba_map *
core_alua_allocate_lba_map(struct list_head * list,u64 first_lba,u64 last_lba)1269229d4f11SHannes Reinecke core_alua_allocate_lba_map(struct list_head *list,
1270229d4f11SHannes Reinecke 			   u64 first_lba, u64 last_lba)
1271229d4f11SHannes Reinecke {
1272229d4f11SHannes Reinecke 	struct t10_alua_lba_map *lba_map;
1273229d4f11SHannes Reinecke 
1274229d4f11SHannes Reinecke 	lba_map = kmem_cache_zalloc(t10_alua_lba_map_cache, GFP_KERNEL);
1275229d4f11SHannes Reinecke 	if (!lba_map) {
1276229d4f11SHannes Reinecke 		pr_err("Unable to allocate struct t10_alua_lba_map\n");
1277229d4f11SHannes Reinecke 		return ERR_PTR(-ENOMEM);
1278229d4f11SHannes Reinecke 	}
1279229d4f11SHannes Reinecke 	INIT_LIST_HEAD(&lba_map->lba_map_mem_list);
1280229d4f11SHannes Reinecke 	lba_map->lba_map_first_lba = first_lba;
1281229d4f11SHannes Reinecke 	lba_map->lba_map_last_lba = last_lba;
1282229d4f11SHannes Reinecke 
1283229d4f11SHannes Reinecke 	list_add_tail(&lba_map->lba_map_list, list);
1284229d4f11SHannes Reinecke 	return lba_map;
1285229d4f11SHannes Reinecke }
1286229d4f11SHannes Reinecke 
1287229d4f11SHannes Reinecke int
core_alua_allocate_lba_map_mem(struct t10_alua_lba_map * lba_map,int pg_id,int state)1288229d4f11SHannes Reinecke core_alua_allocate_lba_map_mem(struct t10_alua_lba_map *lba_map,
1289229d4f11SHannes Reinecke 			       int pg_id, int state)
1290229d4f11SHannes Reinecke {
1291229d4f11SHannes Reinecke 	struct t10_alua_lba_map_member *lba_map_mem;
1292229d4f11SHannes Reinecke 
1293229d4f11SHannes Reinecke 	list_for_each_entry(lba_map_mem, &lba_map->lba_map_mem_list,
1294229d4f11SHannes Reinecke 			    lba_map_mem_list) {
1295229d4f11SHannes Reinecke 		if (lba_map_mem->lba_map_mem_alua_pg_id == pg_id) {
1296229d4f11SHannes Reinecke 			pr_err("Duplicate pg_id %d in lba_map\n", pg_id);
1297229d4f11SHannes Reinecke 			return -EINVAL;
1298229d4f11SHannes Reinecke 		}
1299229d4f11SHannes Reinecke 	}
1300229d4f11SHannes Reinecke 
1301229d4f11SHannes Reinecke 	lba_map_mem = kmem_cache_zalloc(t10_alua_lba_map_mem_cache, GFP_KERNEL);
1302229d4f11SHannes Reinecke 	if (!lba_map_mem) {
1303229d4f11SHannes Reinecke 		pr_err("Unable to allocate struct t10_alua_lba_map_mem\n");
1304229d4f11SHannes Reinecke 		return -ENOMEM;
1305229d4f11SHannes Reinecke 	}
1306229d4f11SHannes Reinecke 	lba_map_mem->lba_map_mem_alua_state = state;
1307229d4f11SHannes Reinecke 	lba_map_mem->lba_map_mem_alua_pg_id = pg_id;
1308229d4f11SHannes Reinecke 
1309229d4f11SHannes Reinecke 	list_add_tail(&lba_map_mem->lba_map_mem_list,
1310229d4f11SHannes Reinecke 		      &lba_map->lba_map_mem_list);
1311229d4f11SHannes Reinecke 	return 0;
1312229d4f11SHannes Reinecke }
1313229d4f11SHannes Reinecke 
1314229d4f11SHannes Reinecke void
core_alua_free_lba_map(struct list_head * lba_list)1315229d4f11SHannes Reinecke core_alua_free_lba_map(struct list_head *lba_list)
1316229d4f11SHannes Reinecke {
1317229d4f11SHannes Reinecke 	struct t10_alua_lba_map *lba_map, *lba_map_tmp;
1318229d4f11SHannes Reinecke 	struct t10_alua_lba_map_member *lba_map_mem, *lba_map_mem_tmp;
1319229d4f11SHannes Reinecke 
1320229d4f11SHannes Reinecke 	list_for_each_entry_safe(lba_map, lba_map_tmp, lba_list,
1321229d4f11SHannes Reinecke 				 lba_map_list) {
1322229d4f11SHannes Reinecke 		list_for_each_entry_safe(lba_map_mem, lba_map_mem_tmp,
1323229d4f11SHannes Reinecke 					 &lba_map->lba_map_mem_list,
1324229d4f11SHannes Reinecke 					 lba_map_mem_list) {
1325229d4f11SHannes Reinecke 			list_del(&lba_map_mem->lba_map_mem_list);
1326229d4f11SHannes Reinecke 			kmem_cache_free(t10_alua_lba_map_mem_cache,
1327229d4f11SHannes Reinecke 					lba_map_mem);
1328229d4f11SHannes Reinecke 		}
1329229d4f11SHannes Reinecke 		list_del(&lba_map->lba_map_list);
1330229d4f11SHannes Reinecke 		kmem_cache_free(t10_alua_lba_map_cache, lba_map);
1331229d4f11SHannes Reinecke 	}
1332229d4f11SHannes Reinecke }
1333229d4f11SHannes Reinecke 
1334229d4f11SHannes Reinecke void
core_alua_set_lba_map(struct se_device * dev,struct list_head * lba_map_list,int segment_size,int segment_mult)1335229d4f11SHannes Reinecke core_alua_set_lba_map(struct se_device *dev, struct list_head *lba_map_list,
1336229d4f11SHannes Reinecke 		      int segment_size, int segment_mult)
1337229d4f11SHannes Reinecke {
1338229d4f11SHannes Reinecke 	struct list_head old_lba_map_list;
1339229d4f11SHannes Reinecke 	struct t10_alua_tg_pt_gp *tg_pt_gp;
1340229d4f11SHannes Reinecke 	int activate = 0, supported;
1341229d4f11SHannes Reinecke 
1342229d4f11SHannes Reinecke 	INIT_LIST_HEAD(&old_lba_map_list);
1343229d4f11SHannes Reinecke 	spin_lock(&dev->t10_alua.lba_map_lock);
1344229d4f11SHannes Reinecke 	dev->t10_alua.lba_map_segment_size = segment_size;
1345229d4f11SHannes Reinecke 	dev->t10_alua.lba_map_segment_multiplier = segment_mult;
1346229d4f11SHannes Reinecke 	list_splice_init(&dev->t10_alua.lba_map_list, &old_lba_map_list);
1347229d4f11SHannes Reinecke 	if (lba_map_list) {
1348229d4f11SHannes Reinecke 		list_splice_init(lba_map_list, &dev->t10_alua.lba_map_list);
1349229d4f11SHannes Reinecke 		activate = 1;
1350229d4f11SHannes Reinecke 	}
1351229d4f11SHannes Reinecke 	spin_unlock(&dev->t10_alua.lba_map_lock);
1352229d4f11SHannes Reinecke 	spin_lock(&dev->t10_alua.tg_pt_gps_lock);
1353229d4f11SHannes Reinecke 	list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list,
1354229d4f11SHannes Reinecke 			    tg_pt_gp_list) {
1355229d4f11SHannes Reinecke 
1356229d4f11SHannes Reinecke 		if (!tg_pt_gp->tg_pt_gp_valid_id)
1357229d4f11SHannes Reinecke 			continue;
1358229d4f11SHannes Reinecke 		supported = tg_pt_gp->tg_pt_gp_alua_supported_states;
1359229d4f11SHannes Reinecke 		if (activate)
1360229d4f11SHannes Reinecke 			supported |= ALUA_LBD_SUP;
1361229d4f11SHannes Reinecke 		else
1362229d4f11SHannes Reinecke 			supported &= ~ALUA_LBD_SUP;
1363229d4f11SHannes Reinecke 		tg_pt_gp->tg_pt_gp_alua_supported_states = supported;
1364229d4f11SHannes Reinecke 	}
1365229d4f11SHannes Reinecke 	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
1366229d4f11SHannes Reinecke 	core_alua_free_lba_map(&old_lba_map_list);
1367229d4f11SHannes Reinecke }
1368229d4f11SHannes Reinecke 
1369c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp *
core_alua_allocate_lu_gp(const char * name,int def_group)1370c66ac9dbSNicholas Bellinger core_alua_allocate_lu_gp(const char *name, int def_group)
1371c66ac9dbSNicholas Bellinger {
1372c66ac9dbSNicholas Bellinger 	struct t10_alua_lu_gp *lu_gp;
1373c66ac9dbSNicholas Bellinger 
1374c66ac9dbSNicholas Bellinger 	lu_gp = kmem_cache_zalloc(t10_alua_lu_gp_cache, GFP_KERNEL);
13756708bb27SAndy Grover 	if (!lu_gp) {
13766708bb27SAndy Grover 		pr_err("Unable to allocate struct t10_alua_lu_gp\n");
13776eab04a8SJustin P. Mattock 		return ERR_PTR(-ENOMEM);
1378c66ac9dbSNicholas Bellinger 	}
1379e3d6f909SAndy Grover 	INIT_LIST_HEAD(&lu_gp->lu_gp_node);
1380c66ac9dbSNicholas Bellinger 	INIT_LIST_HEAD(&lu_gp->lu_gp_mem_list);
1381c66ac9dbSNicholas Bellinger 	spin_lock_init(&lu_gp->lu_gp_lock);
1382c66ac9dbSNicholas Bellinger 	atomic_set(&lu_gp->lu_gp_ref_cnt, 0);
1383c66ac9dbSNicholas Bellinger 
1384c66ac9dbSNicholas Bellinger 	if (def_group) {
1385e3d6f909SAndy Grover 		lu_gp->lu_gp_id = alua_lu_gps_counter++;
1386c66ac9dbSNicholas Bellinger 		lu_gp->lu_gp_valid_id = 1;
1387e3d6f909SAndy Grover 		alua_lu_gps_count++;
1388c66ac9dbSNicholas Bellinger 	}
1389c66ac9dbSNicholas Bellinger 
1390c66ac9dbSNicholas Bellinger 	return lu_gp;
1391c66ac9dbSNicholas Bellinger }
1392c66ac9dbSNicholas Bellinger 
core_alua_set_lu_gp_id(struct t10_alua_lu_gp * lu_gp,u16 lu_gp_id)1393c66ac9dbSNicholas Bellinger int core_alua_set_lu_gp_id(struct t10_alua_lu_gp *lu_gp, u16 lu_gp_id)
1394c66ac9dbSNicholas Bellinger {
1395c66ac9dbSNicholas Bellinger 	struct t10_alua_lu_gp *lu_gp_tmp;
1396c66ac9dbSNicholas Bellinger 	u16 lu_gp_id_tmp;
1397c66ac9dbSNicholas Bellinger 	/*
1398c66ac9dbSNicholas Bellinger 	 * The lu_gp->lu_gp_id may only be set once..
1399c66ac9dbSNicholas Bellinger 	 */
1400c66ac9dbSNicholas Bellinger 	if (lu_gp->lu_gp_valid_id) {
14016708bb27SAndy Grover 		pr_warn("ALUA LU Group already has a valid ID,"
1402c66ac9dbSNicholas Bellinger 			" ignoring request\n");
1403e3d6f909SAndy Grover 		return -EINVAL;
1404c66ac9dbSNicholas Bellinger 	}
1405c66ac9dbSNicholas Bellinger 
1406e3d6f909SAndy Grover 	spin_lock(&lu_gps_lock);
1407e3d6f909SAndy Grover 	if (alua_lu_gps_count == 0x0000ffff) {
14086708bb27SAndy Grover 		pr_err("Maximum ALUA alua_lu_gps_count:"
1409c66ac9dbSNicholas Bellinger 				" 0x0000ffff reached\n");
1410e3d6f909SAndy Grover 		spin_unlock(&lu_gps_lock);
1411c66ac9dbSNicholas Bellinger 		kmem_cache_free(t10_alua_lu_gp_cache, lu_gp);
1412e3d6f909SAndy Grover 		return -ENOSPC;
1413c66ac9dbSNicholas Bellinger 	}
1414c66ac9dbSNicholas Bellinger again:
1415c66ac9dbSNicholas Bellinger 	lu_gp_id_tmp = (lu_gp_id != 0) ? lu_gp_id :
1416e3d6f909SAndy Grover 				alua_lu_gps_counter++;
1417c66ac9dbSNicholas Bellinger 
1418e3d6f909SAndy Grover 	list_for_each_entry(lu_gp_tmp, &lu_gps_list, lu_gp_node) {
1419c66ac9dbSNicholas Bellinger 		if (lu_gp_tmp->lu_gp_id == lu_gp_id_tmp) {
14206708bb27SAndy Grover 			if (!lu_gp_id)
1421c66ac9dbSNicholas Bellinger 				goto again;
1422c66ac9dbSNicholas Bellinger 
14236708bb27SAndy Grover 			pr_warn("ALUA Logical Unit Group ID: %hu"
1424c66ac9dbSNicholas Bellinger 				" already exists, ignoring request\n",
1425c66ac9dbSNicholas Bellinger 				lu_gp_id);
1426e3d6f909SAndy Grover 			spin_unlock(&lu_gps_lock);
1427e3d6f909SAndy Grover 			return -EINVAL;
1428c66ac9dbSNicholas Bellinger 		}
1429c66ac9dbSNicholas Bellinger 	}
1430c66ac9dbSNicholas Bellinger 
1431c66ac9dbSNicholas Bellinger 	lu_gp->lu_gp_id = lu_gp_id_tmp;
1432c66ac9dbSNicholas Bellinger 	lu_gp->lu_gp_valid_id = 1;
1433e3d6f909SAndy Grover 	list_add_tail(&lu_gp->lu_gp_node, &lu_gps_list);
1434e3d6f909SAndy Grover 	alua_lu_gps_count++;
1435e3d6f909SAndy Grover 	spin_unlock(&lu_gps_lock);
1436c66ac9dbSNicholas Bellinger 
1437c66ac9dbSNicholas Bellinger 	return 0;
1438c66ac9dbSNicholas Bellinger }
1439c66ac9dbSNicholas Bellinger 
1440c66ac9dbSNicholas Bellinger static struct t10_alua_lu_gp_member *
core_alua_allocate_lu_gp_mem(struct se_device * dev)1441c66ac9dbSNicholas Bellinger core_alua_allocate_lu_gp_mem(struct se_device *dev)
1442c66ac9dbSNicholas Bellinger {
1443c66ac9dbSNicholas Bellinger 	struct t10_alua_lu_gp_member *lu_gp_mem;
1444c66ac9dbSNicholas Bellinger 
1445c66ac9dbSNicholas Bellinger 	lu_gp_mem = kmem_cache_zalloc(t10_alua_lu_gp_mem_cache, GFP_KERNEL);
14466708bb27SAndy Grover 	if (!lu_gp_mem) {
14476708bb27SAndy Grover 		pr_err("Unable to allocate struct t10_alua_lu_gp_member\n");
1448c66ac9dbSNicholas Bellinger 		return ERR_PTR(-ENOMEM);
1449c66ac9dbSNicholas Bellinger 	}
1450c66ac9dbSNicholas Bellinger 	INIT_LIST_HEAD(&lu_gp_mem->lu_gp_mem_list);
1451c66ac9dbSNicholas Bellinger 	spin_lock_init(&lu_gp_mem->lu_gp_mem_lock);
1452c66ac9dbSNicholas Bellinger 	atomic_set(&lu_gp_mem->lu_gp_mem_ref_cnt, 0);
1453c66ac9dbSNicholas Bellinger 
1454c66ac9dbSNicholas Bellinger 	lu_gp_mem->lu_gp_mem_dev = dev;
1455c66ac9dbSNicholas Bellinger 	dev->dev_alua_lu_gp_mem = lu_gp_mem;
1456c66ac9dbSNicholas Bellinger 
1457c66ac9dbSNicholas Bellinger 	return lu_gp_mem;
1458c66ac9dbSNicholas Bellinger }
1459c66ac9dbSNicholas Bellinger 
core_alua_free_lu_gp(struct t10_alua_lu_gp * lu_gp)1460c66ac9dbSNicholas Bellinger void core_alua_free_lu_gp(struct t10_alua_lu_gp *lu_gp)
1461c66ac9dbSNicholas Bellinger {
1462c66ac9dbSNicholas Bellinger 	struct t10_alua_lu_gp_member *lu_gp_mem, *lu_gp_mem_tmp;
1463c66ac9dbSNicholas Bellinger 	/*
1464c66ac9dbSNicholas Bellinger 	 * Once we have reached this point, config_item_put() has
1465c66ac9dbSNicholas Bellinger 	 * already been called from target_core_alua_drop_lu_gp().
1466c66ac9dbSNicholas Bellinger 	 *
1467c66ac9dbSNicholas Bellinger 	 * Here, we remove the *lu_gp from the global list so that
1468c66ac9dbSNicholas Bellinger 	 * no associations can be made while we are releasing
1469c66ac9dbSNicholas Bellinger 	 * struct t10_alua_lu_gp.
1470c66ac9dbSNicholas Bellinger 	 */
1471e3d6f909SAndy Grover 	spin_lock(&lu_gps_lock);
1472e3d6f909SAndy Grover 	list_del(&lu_gp->lu_gp_node);
1473e3d6f909SAndy Grover 	alua_lu_gps_count--;
1474e3d6f909SAndy Grover 	spin_unlock(&lu_gps_lock);
1475c66ac9dbSNicholas Bellinger 	/*
1476c66ac9dbSNicholas Bellinger 	 * Allow struct t10_alua_lu_gp * referenced by core_alua_get_lu_gp_by_name()
1477c66ac9dbSNicholas Bellinger 	 * in target_core_configfs.c:target_core_store_alua_lu_gp() to be
1478c66ac9dbSNicholas Bellinger 	 * released with core_alua_put_lu_gp_from_name()
1479c66ac9dbSNicholas Bellinger 	 */
1480c66ac9dbSNicholas Bellinger 	while (atomic_read(&lu_gp->lu_gp_ref_cnt))
1481c66ac9dbSNicholas Bellinger 		cpu_relax();
1482c66ac9dbSNicholas Bellinger 	/*
1483c66ac9dbSNicholas Bellinger 	 * Release reference to struct t10_alua_lu_gp * from all associated
1484c66ac9dbSNicholas Bellinger 	 * struct se_device.
1485c66ac9dbSNicholas Bellinger 	 */
1486c66ac9dbSNicholas Bellinger 	spin_lock(&lu_gp->lu_gp_lock);
1487c66ac9dbSNicholas Bellinger 	list_for_each_entry_safe(lu_gp_mem, lu_gp_mem_tmp,
1488c66ac9dbSNicholas Bellinger 				&lu_gp->lu_gp_mem_list, lu_gp_mem_list) {
1489c66ac9dbSNicholas Bellinger 		if (lu_gp_mem->lu_gp_assoc) {
1490c66ac9dbSNicholas Bellinger 			list_del(&lu_gp_mem->lu_gp_mem_list);
1491c66ac9dbSNicholas Bellinger 			lu_gp->lu_gp_members--;
1492c66ac9dbSNicholas Bellinger 			lu_gp_mem->lu_gp_assoc = 0;
1493c66ac9dbSNicholas Bellinger 		}
1494c66ac9dbSNicholas Bellinger 		spin_unlock(&lu_gp->lu_gp_lock);
1495c66ac9dbSNicholas Bellinger 		/*
1496c66ac9dbSNicholas Bellinger 		 *
149725985edcSLucas De Marchi 		 * lu_gp_mem is associated with a single
1498c66ac9dbSNicholas Bellinger 		 * struct se_device->dev_alua_lu_gp_mem, and is released when
1499c66ac9dbSNicholas Bellinger 		 * struct se_device is released via core_alua_free_lu_gp_mem().
1500c66ac9dbSNicholas Bellinger 		 *
1501c66ac9dbSNicholas Bellinger 		 * If the passed lu_gp does NOT match the default_lu_gp, assume
1502f1ae05d5SHannes Reinecke 		 * we want to re-associate a given lu_gp_mem with default_lu_gp.
1503c66ac9dbSNicholas Bellinger 		 */
1504c66ac9dbSNicholas Bellinger 		spin_lock(&lu_gp_mem->lu_gp_mem_lock);
1505e3d6f909SAndy Grover 		if (lu_gp != default_lu_gp)
1506c66ac9dbSNicholas Bellinger 			__core_alua_attach_lu_gp_mem(lu_gp_mem,
1507e3d6f909SAndy Grover 					default_lu_gp);
1508c66ac9dbSNicholas Bellinger 		else
1509c66ac9dbSNicholas Bellinger 			lu_gp_mem->lu_gp = NULL;
1510c66ac9dbSNicholas Bellinger 		spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
1511c66ac9dbSNicholas Bellinger 
1512c66ac9dbSNicholas Bellinger 		spin_lock(&lu_gp->lu_gp_lock);
1513c66ac9dbSNicholas Bellinger 	}
1514c66ac9dbSNicholas Bellinger 	spin_unlock(&lu_gp->lu_gp_lock);
1515c66ac9dbSNicholas Bellinger 
1516c66ac9dbSNicholas Bellinger 	kmem_cache_free(t10_alua_lu_gp_cache, lu_gp);
1517c66ac9dbSNicholas Bellinger }
1518c66ac9dbSNicholas Bellinger 
core_alua_free_lu_gp_mem(struct se_device * dev)1519c66ac9dbSNicholas Bellinger void core_alua_free_lu_gp_mem(struct se_device *dev)
1520c66ac9dbSNicholas Bellinger {
1521c66ac9dbSNicholas Bellinger 	struct t10_alua_lu_gp *lu_gp;
1522c66ac9dbSNicholas Bellinger 	struct t10_alua_lu_gp_member *lu_gp_mem;
1523c66ac9dbSNicholas Bellinger 
1524c66ac9dbSNicholas Bellinger 	lu_gp_mem = dev->dev_alua_lu_gp_mem;
15256708bb27SAndy Grover 	if (!lu_gp_mem)
1526c66ac9dbSNicholas Bellinger 		return;
1527c66ac9dbSNicholas Bellinger 
1528c66ac9dbSNicholas Bellinger 	while (atomic_read(&lu_gp_mem->lu_gp_mem_ref_cnt))
1529c66ac9dbSNicholas Bellinger 		cpu_relax();
1530c66ac9dbSNicholas Bellinger 
1531c66ac9dbSNicholas Bellinger 	spin_lock(&lu_gp_mem->lu_gp_mem_lock);
1532c66ac9dbSNicholas Bellinger 	lu_gp = lu_gp_mem->lu_gp;
15336708bb27SAndy Grover 	if (lu_gp) {
1534c66ac9dbSNicholas Bellinger 		spin_lock(&lu_gp->lu_gp_lock);
1535c66ac9dbSNicholas Bellinger 		if (lu_gp_mem->lu_gp_assoc) {
1536c66ac9dbSNicholas Bellinger 			list_del(&lu_gp_mem->lu_gp_mem_list);
1537c66ac9dbSNicholas Bellinger 			lu_gp->lu_gp_members--;
1538c66ac9dbSNicholas Bellinger 			lu_gp_mem->lu_gp_assoc = 0;
1539c66ac9dbSNicholas Bellinger 		}
1540c66ac9dbSNicholas Bellinger 		spin_unlock(&lu_gp->lu_gp_lock);
1541c66ac9dbSNicholas Bellinger 		lu_gp_mem->lu_gp = NULL;
1542c66ac9dbSNicholas Bellinger 	}
1543c66ac9dbSNicholas Bellinger 	spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
1544c66ac9dbSNicholas Bellinger 
1545c66ac9dbSNicholas Bellinger 	kmem_cache_free(t10_alua_lu_gp_mem_cache, lu_gp_mem);
1546c66ac9dbSNicholas Bellinger }
1547c66ac9dbSNicholas Bellinger 
core_alua_get_lu_gp_by_name(const char * name)1548c66ac9dbSNicholas Bellinger struct t10_alua_lu_gp *core_alua_get_lu_gp_by_name(const char *name)
1549c66ac9dbSNicholas Bellinger {
1550c66ac9dbSNicholas Bellinger 	struct t10_alua_lu_gp *lu_gp;
1551c66ac9dbSNicholas Bellinger 	struct config_item *ci;
1552c66ac9dbSNicholas Bellinger 
1553e3d6f909SAndy Grover 	spin_lock(&lu_gps_lock);
1554e3d6f909SAndy Grover 	list_for_each_entry(lu_gp, &lu_gps_list, lu_gp_node) {
15556708bb27SAndy Grover 		if (!lu_gp->lu_gp_valid_id)
1556c66ac9dbSNicholas Bellinger 			continue;
1557c66ac9dbSNicholas Bellinger 		ci = &lu_gp->lu_gp_group.cg_item;
15586708bb27SAndy Grover 		if (!strcmp(config_item_name(ci), name)) {
1559c66ac9dbSNicholas Bellinger 			atomic_inc(&lu_gp->lu_gp_ref_cnt);
1560e3d6f909SAndy Grover 			spin_unlock(&lu_gps_lock);
1561c66ac9dbSNicholas Bellinger 			return lu_gp;
1562c66ac9dbSNicholas Bellinger 		}
1563c66ac9dbSNicholas Bellinger 	}
1564e3d6f909SAndy Grover 	spin_unlock(&lu_gps_lock);
1565c66ac9dbSNicholas Bellinger 
1566c66ac9dbSNicholas Bellinger 	return NULL;
1567c66ac9dbSNicholas Bellinger }
1568c66ac9dbSNicholas Bellinger 
core_alua_put_lu_gp_from_name(struct t10_alua_lu_gp * lu_gp)1569c66ac9dbSNicholas Bellinger void core_alua_put_lu_gp_from_name(struct t10_alua_lu_gp *lu_gp)
1570c66ac9dbSNicholas Bellinger {
1571e3d6f909SAndy Grover 	spin_lock(&lu_gps_lock);
1572c66ac9dbSNicholas Bellinger 	atomic_dec(&lu_gp->lu_gp_ref_cnt);
1573e3d6f909SAndy Grover 	spin_unlock(&lu_gps_lock);
1574c66ac9dbSNicholas Bellinger }
1575c66ac9dbSNicholas Bellinger 
1576c66ac9dbSNicholas Bellinger /*
1577c66ac9dbSNicholas Bellinger  * Called with struct t10_alua_lu_gp_member->lu_gp_mem_lock
1578c66ac9dbSNicholas Bellinger  */
__core_alua_attach_lu_gp_mem(struct t10_alua_lu_gp_member * lu_gp_mem,struct t10_alua_lu_gp * lu_gp)1579c66ac9dbSNicholas Bellinger void __core_alua_attach_lu_gp_mem(
1580c66ac9dbSNicholas Bellinger 	struct t10_alua_lu_gp_member *lu_gp_mem,
1581c66ac9dbSNicholas Bellinger 	struct t10_alua_lu_gp *lu_gp)
1582c66ac9dbSNicholas Bellinger {
1583c66ac9dbSNicholas Bellinger 	spin_lock(&lu_gp->lu_gp_lock);
1584c66ac9dbSNicholas Bellinger 	lu_gp_mem->lu_gp = lu_gp;
1585c66ac9dbSNicholas Bellinger 	lu_gp_mem->lu_gp_assoc = 1;
1586c66ac9dbSNicholas Bellinger 	list_add_tail(&lu_gp_mem->lu_gp_mem_list, &lu_gp->lu_gp_mem_list);
1587c66ac9dbSNicholas Bellinger 	lu_gp->lu_gp_members++;
1588c66ac9dbSNicholas Bellinger 	spin_unlock(&lu_gp->lu_gp_lock);
1589c66ac9dbSNicholas Bellinger }
1590c66ac9dbSNicholas Bellinger 
1591c66ac9dbSNicholas Bellinger /*
1592c66ac9dbSNicholas Bellinger  * Called with struct t10_alua_lu_gp_member->lu_gp_mem_lock
1593c66ac9dbSNicholas Bellinger  */
__core_alua_drop_lu_gp_mem(struct t10_alua_lu_gp_member * lu_gp_mem,struct t10_alua_lu_gp * lu_gp)1594c66ac9dbSNicholas Bellinger void __core_alua_drop_lu_gp_mem(
1595c66ac9dbSNicholas Bellinger 	struct t10_alua_lu_gp_member *lu_gp_mem,
1596c66ac9dbSNicholas Bellinger 	struct t10_alua_lu_gp *lu_gp)
1597c66ac9dbSNicholas Bellinger {
1598c66ac9dbSNicholas Bellinger 	spin_lock(&lu_gp->lu_gp_lock);
1599c66ac9dbSNicholas Bellinger 	list_del(&lu_gp_mem->lu_gp_mem_list);
1600c66ac9dbSNicholas Bellinger 	lu_gp_mem->lu_gp = NULL;
1601c66ac9dbSNicholas Bellinger 	lu_gp_mem->lu_gp_assoc = 0;
1602c66ac9dbSNicholas Bellinger 	lu_gp->lu_gp_members--;
1603c66ac9dbSNicholas Bellinger 	spin_unlock(&lu_gp->lu_gp_lock);
1604c66ac9dbSNicholas Bellinger }
1605c66ac9dbSNicholas Bellinger 
core_alua_allocate_tg_pt_gp(struct se_device * dev,const char * name,int def_group)16060fd97ccfSChristoph Hellwig struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(struct se_device *dev,
16070fd97ccfSChristoph Hellwig 		const char *name, int def_group)
1608c66ac9dbSNicholas Bellinger {
1609c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp;
1610c66ac9dbSNicholas Bellinger 
1611c66ac9dbSNicholas Bellinger 	tg_pt_gp = kmem_cache_zalloc(t10_alua_tg_pt_gp_cache, GFP_KERNEL);
16126708bb27SAndy Grover 	if (!tg_pt_gp) {
16136708bb27SAndy Grover 		pr_err("Unable to allocate struct t10_alua_tg_pt_gp\n");
1614c66ac9dbSNicholas Bellinger 		return NULL;
1615c66ac9dbSNicholas Bellinger 	}
1616c66ac9dbSNicholas Bellinger 	INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_list);
1617adf653f9SChristoph Hellwig 	INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_lun_list);
1618d19c4643SMike Christie 	mutex_init(&tg_pt_gp->tg_pt_gp_transition_mutex);
1619c66ac9dbSNicholas Bellinger 	spin_lock_init(&tg_pt_gp->tg_pt_gp_lock);
1620c66ac9dbSNicholas Bellinger 	atomic_set(&tg_pt_gp->tg_pt_gp_ref_cnt, 0);
16210fd97ccfSChristoph Hellwig 	tg_pt_gp->tg_pt_gp_dev = dev;
1622d19c4643SMike Christie 	tg_pt_gp->tg_pt_gp_alua_access_state =
1623d19c4643SMike Christie 			ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED;
1624c66ac9dbSNicholas Bellinger 	/*
1625125d0119SHannes Reinecke 	 * Enable both explicit and implicit ALUA support by default
1626c66ac9dbSNicholas Bellinger 	 */
1627c66ac9dbSNicholas Bellinger 	tg_pt_gp->tg_pt_gp_alua_access_type =
1628125d0119SHannes Reinecke 			TPGS_EXPLICIT_ALUA | TPGS_IMPLICIT_ALUA;
1629c66ac9dbSNicholas Bellinger 	/*
1630c66ac9dbSNicholas Bellinger 	 * Set the default Active/NonOptimized Delay in milliseconds
1631c66ac9dbSNicholas Bellinger 	 */
1632c66ac9dbSNicholas Bellinger 	tg_pt_gp->tg_pt_gp_nonop_delay_msecs = ALUA_DEFAULT_NONOP_DELAY_MSECS;
1633c66ac9dbSNicholas Bellinger 	tg_pt_gp->tg_pt_gp_trans_delay_msecs = ALUA_DEFAULT_TRANS_DELAY_MSECS;
1634125d0119SHannes Reinecke 	tg_pt_gp->tg_pt_gp_implicit_trans_secs = ALUA_DEFAULT_IMPLICIT_TRANS_SECS;
1635c66ac9dbSNicholas Bellinger 
1636c0dc941eSHannes Reinecke 	/*
1637c0dc941eSHannes Reinecke 	 * Enable all supported states
1638c0dc941eSHannes Reinecke 	 */
1639c0dc941eSHannes Reinecke 	tg_pt_gp->tg_pt_gp_alua_supported_states =
1640c0dc941eSHannes Reinecke 	    ALUA_T_SUP | ALUA_O_SUP |
1641c0dc941eSHannes Reinecke 	    ALUA_U_SUP | ALUA_S_SUP | ALUA_AN_SUP | ALUA_AO_SUP;
1642c0dc941eSHannes Reinecke 
1643c66ac9dbSNicholas Bellinger 	if (def_group) {
16440fd97ccfSChristoph Hellwig 		spin_lock(&dev->t10_alua.tg_pt_gps_lock);
1645c66ac9dbSNicholas Bellinger 		tg_pt_gp->tg_pt_gp_id =
16460fd97ccfSChristoph Hellwig 				dev->t10_alua.alua_tg_pt_gps_counter++;
1647c66ac9dbSNicholas Bellinger 		tg_pt_gp->tg_pt_gp_valid_id = 1;
16480fd97ccfSChristoph Hellwig 		dev->t10_alua.alua_tg_pt_gps_count++;
1649c66ac9dbSNicholas Bellinger 		list_add_tail(&tg_pt_gp->tg_pt_gp_list,
16500fd97ccfSChristoph Hellwig 			      &dev->t10_alua.tg_pt_gps_list);
16510fd97ccfSChristoph Hellwig 		spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
1652c66ac9dbSNicholas Bellinger 	}
1653c66ac9dbSNicholas Bellinger 
1654c66ac9dbSNicholas Bellinger 	return tg_pt_gp;
1655c66ac9dbSNicholas Bellinger }
1656c66ac9dbSNicholas Bellinger 
core_alua_set_tg_pt_gp_id(struct t10_alua_tg_pt_gp * tg_pt_gp,u16 tg_pt_gp_id)1657c66ac9dbSNicholas Bellinger int core_alua_set_tg_pt_gp_id(
1658c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp,
1659c66ac9dbSNicholas Bellinger 	u16 tg_pt_gp_id)
1660c66ac9dbSNicholas Bellinger {
16610fd97ccfSChristoph Hellwig 	struct se_device *dev = tg_pt_gp->tg_pt_gp_dev;
1662c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp_tmp;
1663c66ac9dbSNicholas Bellinger 	u16 tg_pt_gp_id_tmp;
16640fd97ccfSChristoph Hellwig 
1665c66ac9dbSNicholas Bellinger 	/*
1666c66ac9dbSNicholas Bellinger 	 * The tg_pt_gp->tg_pt_gp_id may only be set once..
1667c66ac9dbSNicholas Bellinger 	 */
1668c66ac9dbSNicholas Bellinger 	if (tg_pt_gp->tg_pt_gp_valid_id) {
16696708bb27SAndy Grover 		pr_warn("ALUA TG PT Group already has a valid ID,"
1670c66ac9dbSNicholas Bellinger 			" ignoring request\n");
1671e3d6f909SAndy Grover 		return -EINVAL;
1672c66ac9dbSNicholas Bellinger 	}
1673c66ac9dbSNicholas Bellinger 
16740fd97ccfSChristoph Hellwig 	spin_lock(&dev->t10_alua.tg_pt_gps_lock);
16750fd97ccfSChristoph Hellwig 	if (dev->t10_alua.alua_tg_pt_gps_count == 0x0000ffff) {
16766708bb27SAndy Grover 		pr_err("Maximum ALUA alua_tg_pt_gps_count:"
1677c66ac9dbSNicholas Bellinger 			" 0x0000ffff reached\n");
16780fd97ccfSChristoph Hellwig 		spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
1679e3d6f909SAndy Grover 		return -ENOSPC;
1680c66ac9dbSNicholas Bellinger 	}
1681c66ac9dbSNicholas Bellinger again:
1682c66ac9dbSNicholas Bellinger 	tg_pt_gp_id_tmp = (tg_pt_gp_id != 0) ? tg_pt_gp_id :
16830fd97ccfSChristoph Hellwig 			dev->t10_alua.alua_tg_pt_gps_counter++;
1684c66ac9dbSNicholas Bellinger 
16850fd97ccfSChristoph Hellwig 	list_for_each_entry(tg_pt_gp_tmp, &dev->t10_alua.tg_pt_gps_list,
1686c66ac9dbSNicholas Bellinger 			tg_pt_gp_list) {
1687c66ac9dbSNicholas Bellinger 		if (tg_pt_gp_tmp->tg_pt_gp_id == tg_pt_gp_id_tmp) {
16886708bb27SAndy Grover 			if (!tg_pt_gp_id)
1689c66ac9dbSNicholas Bellinger 				goto again;
1690c66ac9dbSNicholas Bellinger 
16916708bb27SAndy Grover 			pr_err("ALUA Target Port Group ID: %hu already"
1692c66ac9dbSNicholas Bellinger 				" exists, ignoring request\n", tg_pt_gp_id);
16930fd97ccfSChristoph Hellwig 			spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
1694e3d6f909SAndy Grover 			return -EINVAL;
1695c66ac9dbSNicholas Bellinger 		}
1696c66ac9dbSNicholas Bellinger 	}
1697c66ac9dbSNicholas Bellinger 
1698c66ac9dbSNicholas Bellinger 	tg_pt_gp->tg_pt_gp_id = tg_pt_gp_id_tmp;
1699c66ac9dbSNicholas Bellinger 	tg_pt_gp->tg_pt_gp_valid_id = 1;
1700c66ac9dbSNicholas Bellinger 	list_add_tail(&tg_pt_gp->tg_pt_gp_list,
17010fd97ccfSChristoph Hellwig 			&dev->t10_alua.tg_pt_gps_list);
17020fd97ccfSChristoph Hellwig 	dev->t10_alua.alua_tg_pt_gps_count++;
17030fd97ccfSChristoph Hellwig 	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
1704c66ac9dbSNicholas Bellinger 
1705c66ac9dbSNicholas Bellinger 	return 0;
1706c66ac9dbSNicholas Bellinger }
1707c66ac9dbSNicholas Bellinger 
core_alua_free_tg_pt_gp(struct t10_alua_tg_pt_gp * tg_pt_gp)1708c66ac9dbSNicholas Bellinger void core_alua_free_tg_pt_gp(
1709c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp)
1710c66ac9dbSNicholas Bellinger {
17110fd97ccfSChristoph Hellwig 	struct se_device *dev = tg_pt_gp->tg_pt_gp_dev;
1712adf653f9SChristoph Hellwig 	struct se_lun *lun, *next;
17130fd97ccfSChristoph Hellwig 
1714c66ac9dbSNicholas Bellinger 	/*
1715c66ac9dbSNicholas Bellinger 	 * Once we have reached this point, config_item_put() has already
1716c66ac9dbSNicholas Bellinger 	 * been called from target_core_alua_drop_tg_pt_gp().
1717c66ac9dbSNicholas Bellinger 	 *
1718c66ac9dbSNicholas Bellinger 	 * Here we remove *tg_pt_gp from the global list so that
1719f1ae05d5SHannes Reinecke 	 * no associations *OR* explicit ALUA via SET_TARGET_PORT_GROUPS
1720c66ac9dbSNicholas Bellinger 	 * can be made while we are releasing struct t10_alua_tg_pt_gp.
1721c66ac9dbSNicholas Bellinger 	 */
17220fd97ccfSChristoph Hellwig 	spin_lock(&dev->t10_alua.tg_pt_gps_lock);
172382129697Stangwenji 	if (tg_pt_gp->tg_pt_gp_valid_id) {
1724c66ac9dbSNicholas Bellinger 		list_del(&tg_pt_gp->tg_pt_gp_list);
172582129697Stangwenji 		dev->t10_alua.alua_tg_pt_gps_count--;
172682129697Stangwenji 	}
17270fd97ccfSChristoph Hellwig 	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
17280fd97ccfSChristoph Hellwig 
1729c66ac9dbSNicholas Bellinger 	/*
1730c66ac9dbSNicholas Bellinger 	 * Allow a struct t10_alua_tg_pt_gp_member * referenced by
1731c66ac9dbSNicholas Bellinger 	 * core_alua_get_tg_pt_gp_by_name() in
1732c66ac9dbSNicholas Bellinger 	 * target_core_configfs.c:target_core_store_alua_tg_pt_gp()
1733c66ac9dbSNicholas Bellinger 	 * to be released with core_alua_put_tg_pt_gp_from_name().
1734c66ac9dbSNicholas Bellinger 	 */
1735c66ac9dbSNicholas Bellinger 	while (atomic_read(&tg_pt_gp->tg_pt_gp_ref_cnt))
1736c66ac9dbSNicholas Bellinger 		cpu_relax();
17370fd97ccfSChristoph Hellwig 
1738c66ac9dbSNicholas Bellinger 	/*
1739c66ac9dbSNicholas Bellinger 	 * Release reference to struct t10_alua_tg_pt_gp from all associated
1740c66ac9dbSNicholas Bellinger 	 * struct se_port.
1741c66ac9dbSNicholas Bellinger 	 */
1742c66ac9dbSNicholas Bellinger 	spin_lock(&tg_pt_gp->tg_pt_gp_lock);
1743adf653f9SChristoph Hellwig 	list_for_each_entry_safe(lun, next,
1744adf653f9SChristoph Hellwig 			&tg_pt_gp->tg_pt_gp_lun_list, lun_tg_pt_gp_link) {
1745adf653f9SChristoph Hellwig 		list_del_init(&lun->lun_tg_pt_gp_link);
1746c66ac9dbSNicholas Bellinger 		tg_pt_gp->tg_pt_gp_members--;
1747adf653f9SChristoph Hellwig 
1748c66ac9dbSNicholas Bellinger 		spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
1749c66ac9dbSNicholas Bellinger 		/*
1750c66ac9dbSNicholas Bellinger 		 * If the passed tg_pt_gp does NOT match the default_tg_pt_gp,
1751f1ae05d5SHannes Reinecke 		 * assume we want to re-associate a given tg_pt_gp_mem with
1752c66ac9dbSNicholas Bellinger 		 * default_tg_pt_gp.
1753c66ac9dbSNicholas Bellinger 		 */
1754adf653f9SChristoph Hellwig 		spin_lock(&lun->lun_tg_pt_gp_lock);
17550fd97ccfSChristoph Hellwig 		if (tg_pt_gp != dev->t10_alua.default_tg_pt_gp) {
1756adf653f9SChristoph Hellwig 			__target_attach_tg_pt_gp(lun,
17570fd97ccfSChristoph Hellwig 					dev->t10_alua.default_tg_pt_gp);
1758c66ac9dbSNicholas Bellinger 		} else
17597324f47dSMike Christie 			rcu_assign_pointer(lun->lun_tg_pt_gp, NULL);
1760adf653f9SChristoph Hellwig 		spin_unlock(&lun->lun_tg_pt_gp_lock);
1761c66ac9dbSNicholas Bellinger 
1762c66ac9dbSNicholas Bellinger 		spin_lock(&tg_pt_gp->tg_pt_gp_lock);
1763c66ac9dbSNicholas Bellinger 	}
1764c66ac9dbSNicholas Bellinger 	spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
1765c66ac9dbSNicholas Bellinger 
17667324f47dSMike Christie 	synchronize_rcu();
1767c66ac9dbSNicholas Bellinger 	kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp);
1768c66ac9dbSNicholas Bellinger }
1769c66ac9dbSNicholas Bellinger 
core_alua_get_tg_pt_gp_by_name(struct se_device * dev,const char * name)1770c66ac9dbSNicholas Bellinger static struct t10_alua_tg_pt_gp *core_alua_get_tg_pt_gp_by_name(
17710fd97ccfSChristoph Hellwig 		struct se_device *dev, const char *name)
1772c66ac9dbSNicholas Bellinger {
1773c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp;
1774c66ac9dbSNicholas Bellinger 	struct config_item *ci;
1775c66ac9dbSNicholas Bellinger 
17760fd97ccfSChristoph Hellwig 	spin_lock(&dev->t10_alua.tg_pt_gps_lock);
17770fd97ccfSChristoph Hellwig 	list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list,
1778c66ac9dbSNicholas Bellinger 			tg_pt_gp_list) {
17796708bb27SAndy Grover 		if (!tg_pt_gp->tg_pt_gp_valid_id)
1780c66ac9dbSNicholas Bellinger 			continue;
1781c66ac9dbSNicholas Bellinger 		ci = &tg_pt_gp->tg_pt_gp_group.cg_item;
17826708bb27SAndy Grover 		if (!strcmp(config_item_name(ci), name)) {
1783c66ac9dbSNicholas Bellinger 			atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt);
17840fd97ccfSChristoph Hellwig 			spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
1785c66ac9dbSNicholas Bellinger 			return tg_pt_gp;
1786c66ac9dbSNicholas Bellinger 		}
1787c66ac9dbSNicholas Bellinger 	}
17880fd97ccfSChristoph Hellwig 	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
1789c66ac9dbSNicholas Bellinger 
1790c66ac9dbSNicholas Bellinger 	return NULL;
1791c66ac9dbSNicholas Bellinger }
1792c66ac9dbSNicholas Bellinger 
core_alua_put_tg_pt_gp_from_name(struct t10_alua_tg_pt_gp * tg_pt_gp)1793c66ac9dbSNicholas Bellinger static void core_alua_put_tg_pt_gp_from_name(
1794c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp)
1795c66ac9dbSNicholas Bellinger {
17960fd97ccfSChristoph Hellwig 	struct se_device *dev = tg_pt_gp->tg_pt_gp_dev;
1797c66ac9dbSNicholas Bellinger 
17980fd97ccfSChristoph Hellwig 	spin_lock(&dev->t10_alua.tg_pt_gps_lock);
1799c66ac9dbSNicholas Bellinger 	atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt);
18000fd97ccfSChristoph Hellwig 	spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
1801c66ac9dbSNicholas Bellinger }
1802c66ac9dbSNicholas Bellinger 
__target_attach_tg_pt_gp(struct se_lun * lun,struct t10_alua_tg_pt_gp * tg_pt_gp)1803adf653f9SChristoph Hellwig static void __target_attach_tg_pt_gp(struct se_lun *lun,
1804c66ac9dbSNicholas Bellinger 		struct t10_alua_tg_pt_gp *tg_pt_gp)
1805c66ac9dbSNicholas Bellinger {
18063dd348fcSHannes Reinecke 	struct se_dev_entry *se_deve;
18073dd348fcSHannes Reinecke 
1808adf653f9SChristoph Hellwig 	assert_spin_locked(&lun->lun_tg_pt_gp_lock);
1809adf653f9SChristoph Hellwig 
1810c66ac9dbSNicholas Bellinger 	spin_lock(&tg_pt_gp->tg_pt_gp_lock);
18117324f47dSMike Christie 	rcu_assign_pointer(lun->lun_tg_pt_gp, tg_pt_gp);
1812adf653f9SChristoph Hellwig 	list_add_tail(&lun->lun_tg_pt_gp_link, &tg_pt_gp->tg_pt_gp_lun_list);
1813c66ac9dbSNicholas Bellinger 	tg_pt_gp->tg_pt_gp_members++;
18143dd348fcSHannes Reinecke 	spin_lock(&lun->lun_deve_lock);
18153dd348fcSHannes Reinecke 	list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link)
18163dd348fcSHannes Reinecke 		core_scsi3_ua_allocate(se_deve, 0x3f,
18173dd348fcSHannes Reinecke 				       ASCQ_3FH_INQUIRY_DATA_HAS_CHANGED);
18183dd348fcSHannes Reinecke 	spin_unlock(&lun->lun_deve_lock);
1819c66ac9dbSNicholas Bellinger 	spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
1820c66ac9dbSNicholas Bellinger }
1821c66ac9dbSNicholas Bellinger 
target_attach_tg_pt_gp(struct se_lun * lun,struct t10_alua_tg_pt_gp * tg_pt_gp)1822adf653f9SChristoph Hellwig void target_attach_tg_pt_gp(struct se_lun *lun,
1823c66ac9dbSNicholas Bellinger 		struct t10_alua_tg_pt_gp *tg_pt_gp)
1824c66ac9dbSNicholas Bellinger {
1825adf653f9SChristoph Hellwig 	spin_lock(&lun->lun_tg_pt_gp_lock);
1826adf653f9SChristoph Hellwig 	__target_attach_tg_pt_gp(lun, tg_pt_gp);
1827adf653f9SChristoph Hellwig 	spin_unlock(&lun->lun_tg_pt_gp_lock);
18287324f47dSMike Christie 	synchronize_rcu();
1829c66ac9dbSNicholas Bellinger }
1830c66ac9dbSNicholas Bellinger 
__target_detach_tg_pt_gp(struct se_lun * lun,struct t10_alua_tg_pt_gp * tg_pt_gp)1831adf653f9SChristoph Hellwig static void __target_detach_tg_pt_gp(struct se_lun *lun,
1832adf653f9SChristoph Hellwig 		struct t10_alua_tg_pt_gp *tg_pt_gp)
1833adf653f9SChristoph Hellwig {
1834adf653f9SChristoph Hellwig 	assert_spin_locked(&lun->lun_tg_pt_gp_lock);
1835adf653f9SChristoph Hellwig 
1836c66ac9dbSNicholas Bellinger 	spin_lock(&tg_pt_gp->tg_pt_gp_lock);
1837adf653f9SChristoph Hellwig 	list_del_init(&lun->lun_tg_pt_gp_link);
1838c66ac9dbSNicholas Bellinger 	tg_pt_gp->tg_pt_gp_members--;
1839c66ac9dbSNicholas Bellinger 	spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
1840c66ac9dbSNicholas Bellinger }
1841c66ac9dbSNicholas Bellinger 
target_detach_tg_pt_gp(struct se_lun * lun)1842adf653f9SChristoph Hellwig void target_detach_tg_pt_gp(struct se_lun *lun)
1843adf653f9SChristoph Hellwig {
1844adf653f9SChristoph Hellwig 	struct t10_alua_tg_pt_gp *tg_pt_gp;
1845adf653f9SChristoph Hellwig 
1846adf653f9SChristoph Hellwig 	spin_lock(&lun->lun_tg_pt_gp_lock);
18477324f47dSMike Christie 	tg_pt_gp = rcu_dereference_check(lun->lun_tg_pt_gp,
18487324f47dSMike Christie 				lockdep_is_held(&lun->lun_tg_pt_gp_lock));
1849f9793d64SMike Christie 	if (tg_pt_gp) {
1850adf653f9SChristoph Hellwig 		__target_detach_tg_pt_gp(lun, tg_pt_gp);
1851f9793d64SMike Christie 		rcu_assign_pointer(lun->lun_tg_pt_gp, NULL);
1852f9793d64SMike Christie 	}
1853adf653f9SChristoph Hellwig 	spin_unlock(&lun->lun_tg_pt_gp_lock);
18547324f47dSMike Christie 	synchronize_rcu();
1855adf653f9SChristoph Hellwig }
1856adf653f9SChristoph Hellwig 
target_swap_tg_pt_gp(struct se_lun * lun,struct t10_alua_tg_pt_gp * old_tg_pt_gp,struct t10_alua_tg_pt_gp * new_tg_pt_gp)1857f9793d64SMike Christie static void target_swap_tg_pt_gp(struct se_lun *lun,
1858f9793d64SMike Christie 				 struct t10_alua_tg_pt_gp *old_tg_pt_gp,
1859f9793d64SMike Christie 				 struct t10_alua_tg_pt_gp *new_tg_pt_gp)
1860f9793d64SMike Christie {
1861f9793d64SMike Christie 	assert_spin_locked(&lun->lun_tg_pt_gp_lock);
1862f9793d64SMike Christie 
1863f9793d64SMike Christie 	if (old_tg_pt_gp)
1864f9793d64SMike Christie 		__target_detach_tg_pt_gp(lun, old_tg_pt_gp);
1865f9793d64SMike Christie 	__target_attach_tg_pt_gp(lun, new_tg_pt_gp);
1866f9793d64SMike Christie }
1867f9793d64SMike Christie 
core_alua_show_tg_pt_gp_info(struct se_lun * lun,char * page)1868adf653f9SChristoph Hellwig ssize_t core_alua_show_tg_pt_gp_info(struct se_lun *lun, char *page)
1869c66ac9dbSNicholas Bellinger {
1870c66ac9dbSNicholas Bellinger 	struct config_item *tg_pt_ci;
1871c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp;
1872c66ac9dbSNicholas Bellinger 	ssize_t len = 0;
1873c66ac9dbSNicholas Bellinger 
18747324f47dSMike Christie 	rcu_read_lock();
18757324f47dSMike Christie 	tg_pt_gp = rcu_dereference(lun->lun_tg_pt_gp);
18766708bb27SAndy Grover 	if (tg_pt_gp) {
1877c66ac9dbSNicholas Bellinger 		tg_pt_ci = &tg_pt_gp->tg_pt_gp_group.cg_item;
1878c66ac9dbSNicholas Bellinger 		len += sprintf(page, "TG Port Alias: %s\nTG Port Group ID:"
1879c66ac9dbSNicholas Bellinger 			" %hu\nTG Port Primary Access State: %s\nTG Port "
1880c66ac9dbSNicholas Bellinger 			"Primary Access Status: %s\nTG Port Secondary Access"
1881c66ac9dbSNicholas Bellinger 			" State: %s\nTG Port Secondary Access Status: %s\n",
1882c66ac9dbSNicholas Bellinger 			config_item_name(tg_pt_ci), tg_pt_gp->tg_pt_gp_id,
1883d19c4643SMike Christie 			core_alua_dump_state(
1884d19c4643SMike Christie 				tg_pt_gp->tg_pt_gp_alua_access_state),
1885c66ac9dbSNicholas Bellinger 			core_alua_dump_status(
1886c66ac9dbSNicholas Bellinger 				tg_pt_gp->tg_pt_gp_alua_access_status),
1887adf653f9SChristoph Hellwig 			atomic_read(&lun->lun_tg_pt_secondary_offline) ?
1888c66ac9dbSNicholas Bellinger 			"Offline" : "None",
1889adf653f9SChristoph Hellwig 			core_alua_dump_status(lun->lun_tg_pt_secondary_stat));
1890c66ac9dbSNicholas Bellinger 	}
18917324f47dSMike Christie 	rcu_read_unlock();
1892c66ac9dbSNicholas Bellinger 
1893c66ac9dbSNicholas Bellinger 	return len;
1894c66ac9dbSNicholas Bellinger }
1895c66ac9dbSNicholas Bellinger 
core_alua_store_tg_pt_gp_info(struct se_lun * lun,const char * page,size_t count)1896c66ac9dbSNicholas Bellinger ssize_t core_alua_store_tg_pt_gp_info(
1897adf653f9SChristoph Hellwig 	struct se_lun *lun,
1898c66ac9dbSNicholas Bellinger 	const char *page,
1899c66ac9dbSNicholas Bellinger 	size_t count)
1900c66ac9dbSNicholas Bellinger {
1901adf653f9SChristoph Hellwig 	struct se_portal_group *tpg = lun->lun_tpg;
19024cc987eaSNicholas Bellinger 	/*
19034cc987eaSNicholas Bellinger 	 * rcu_dereference_raw protected by se_lun->lun_group symlink
19044cc987eaSNicholas Bellinger 	 * reference to se_device->dev_group.
19054cc987eaSNicholas Bellinger 	 */
19064cc987eaSNicholas Bellinger 	struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev);
1907c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *tg_pt_gp_new = NULL;
1908c66ac9dbSNicholas Bellinger 	unsigned char buf[TG_PT_GROUP_NAME_BUF];
1909c66ac9dbSNicholas Bellinger 	int move = 0;
1910c66ac9dbSNicholas Bellinger 
191169088a04SBodo Stroesser 	if (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA ||
1912adf653f9SChristoph Hellwig 	    (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))
1913adf653f9SChristoph Hellwig 		return -ENODEV;
1914c66ac9dbSNicholas Bellinger 
1915c66ac9dbSNicholas Bellinger 	if (count > TG_PT_GROUP_NAME_BUF) {
19166708bb27SAndy Grover 		pr_err("ALUA Target Port Group alias too large!\n");
1917c66ac9dbSNicholas Bellinger 		return -EINVAL;
1918c66ac9dbSNicholas Bellinger 	}
1919c66ac9dbSNicholas Bellinger 	memset(buf, 0, TG_PT_GROUP_NAME_BUF);
1920c66ac9dbSNicholas Bellinger 	memcpy(buf, page, count);
1921c66ac9dbSNicholas Bellinger 	/*
1922c66ac9dbSNicholas Bellinger 	 * Any ALUA target port group alias besides "NULL" means we will be
1923c66ac9dbSNicholas Bellinger 	 * making a new group association.
1924c66ac9dbSNicholas Bellinger 	 */
1925c66ac9dbSNicholas Bellinger 	if (strcmp(strstrip(buf), "NULL")) {
1926c66ac9dbSNicholas Bellinger 		/*
1927c66ac9dbSNicholas Bellinger 		 * core_alua_get_tg_pt_gp_by_name() will increment reference to
1928c66ac9dbSNicholas Bellinger 		 * struct t10_alua_tg_pt_gp.  This reference is released with
1929c66ac9dbSNicholas Bellinger 		 * core_alua_put_tg_pt_gp_from_name() below.
1930c66ac9dbSNicholas Bellinger 		 */
19310fd97ccfSChristoph Hellwig 		tg_pt_gp_new = core_alua_get_tg_pt_gp_by_name(dev,
1932c66ac9dbSNicholas Bellinger 					strstrip(buf));
19336708bb27SAndy Grover 		if (!tg_pt_gp_new)
1934c66ac9dbSNicholas Bellinger 			return -ENODEV;
1935c66ac9dbSNicholas Bellinger 	}
1936c66ac9dbSNicholas Bellinger 
1937adf653f9SChristoph Hellwig 	spin_lock(&lun->lun_tg_pt_gp_lock);
19387324f47dSMike Christie 	tg_pt_gp = rcu_dereference_check(lun->lun_tg_pt_gp,
19397324f47dSMike Christie 				lockdep_is_held(&lun->lun_tg_pt_gp_lock));
19406708bb27SAndy Grover 	if (tg_pt_gp) {
1941c66ac9dbSNicholas Bellinger 		/*
1942c66ac9dbSNicholas Bellinger 		 * Clearing an existing tg_pt_gp association, and replacing
1943c66ac9dbSNicholas Bellinger 		 * with the default_tg_pt_gp.
1944c66ac9dbSNicholas Bellinger 		 */
19456708bb27SAndy Grover 		if (!tg_pt_gp_new) {
19466708bb27SAndy Grover 			pr_debug("Target_Core_ConfigFS: Moving"
1947c66ac9dbSNicholas Bellinger 				" %s/tpgt_%hu/%s from ALUA Target Port Group:"
1948c66ac9dbSNicholas Bellinger 				" alua/%s, ID: %hu back to"
1949c66ac9dbSNicholas Bellinger 				" default_tg_pt_gp\n",
1950e3d6f909SAndy Grover 				tpg->se_tpg_tfo->tpg_get_wwn(tpg),
1951e3d6f909SAndy Grover 				tpg->se_tpg_tfo->tpg_get_tag(tpg),
1952c66ac9dbSNicholas Bellinger 				config_item_name(&lun->lun_group.cg_item),
1953c66ac9dbSNicholas Bellinger 				config_item_name(
1954c66ac9dbSNicholas Bellinger 					&tg_pt_gp->tg_pt_gp_group.cg_item),
1955c66ac9dbSNicholas Bellinger 				tg_pt_gp->tg_pt_gp_id);
1956c66ac9dbSNicholas Bellinger 
1957f9793d64SMike Christie 			target_swap_tg_pt_gp(lun, tg_pt_gp,
19580fd97ccfSChristoph Hellwig 					dev->t10_alua.default_tg_pt_gp);
1959adf653f9SChristoph Hellwig 			spin_unlock(&lun->lun_tg_pt_gp_lock);
1960c66ac9dbSNicholas Bellinger 
19617324f47dSMike Christie 			goto sync_rcu;
1962c66ac9dbSNicholas Bellinger 		}
1963c66ac9dbSNicholas Bellinger 		move = 1;
1964c66ac9dbSNicholas Bellinger 	}
1965adf653f9SChristoph Hellwig 
1966f9793d64SMike Christie 	target_swap_tg_pt_gp(lun, tg_pt_gp, tg_pt_gp_new);
1967adf653f9SChristoph Hellwig 	spin_unlock(&lun->lun_tg_pt_gp_lock);
19686708bb27SAndy Grover 	pr_debug("Target_Core_ConfigFS: %s %s/tpgt_%hu/%s to ALUA"
1969c66ac9dbSNicholas Bellinger 		" Target Port Group: alua/%s, ID: %hu\n", (move) ?
1970e3d6f909SAndy Grover 		"Moving" : "Adding", tpg->se_tpg_tfo->tpg_get_wwn(tpg),
1971e3d6f909SAndy Grover 		tpg->se_tpg_tfo->tpg_get_tag(tpg),
1972c66ac9dbSNicholas Bellinger 		config_item_name(&lun->lun_group.cg_item),
1973c66ac9dbSNicholas Bellinger 		config_item_name(&tg_pt_gp_new->tg_pt_gp_group.cg_item),
1974c66ac9dbSNicholas Bellinger 		tg_pt_gp_new->tg_pt_gp_id);
1975c66ac9dbSNicholas Bellinger 
1976c66ac9dbSNicholas Bellinger 	core_alua_put_tg_pt_gp_from_name(tg_pt_gp_new);
19777324f47dSMike Christie sync_rcu:
19787324f47dSMike Christie 	synchronize_rcu();
1979c66ac9dbSNicholas Bellinger 	return count;
1980c66ac9dbSNicholas Bellinger }
1981c66ac9dbSNicholas Bellinger 
core_alua_show_access_type(struct t10_alua_tg_pt_gp * tg_pt_gp,char * page)1982c66ac9dbSNicholas Bellinger ssize_t core_alua_show_access_type(
1983c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp,
1984c66ac9dbSNicholas Bellinger 	char *page)
1985c66ac9dbSNicholas Bellinger {
1986125d0119SHannes Reinecke 	if ((tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA) &&
1987125d0119SHannes Reinecke 	    (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICIT_ALUA))
1988125d0119SHannes Reinecke 		return sprintf(page, "Implicit and Explicit\n");
1989125d0119SHannes Reinecke 	else if (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICIT_ALUA)
1990125d0119SHannes Reinecke 		return sprintf(page, "Implicit\n");
1991125d0119SHannes Reinecke 	else if (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA)
1992125d0119SHannes Reinecke 		return sprintf(page, "Explicit\n");
1993c66ac9dbSNicholas Bellinger 	else
1994c66ac9dbSNicholas Bellinger 		return sprintf(page, "None\n");
1995c66ac9dbSNicholas Bellinger }
1996c66ac9dbSNicholas Bellinger 
core_alua_store_access_type(struct t10_alua_tg_pt_gp * tg_pt_gp,const char * page,size_t count)1997c66ac9dbSNicholas Bellinger ssize_t core_alua_store_access_type(
1998c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp,
1999c66ac9dbSNicholas Bellinger 	const char *page,
2000c66ac9dbSNicholas Bellinger 	size_t count)
2001c66ac9dbSNicholas Bellinger {
2002c66ac9dbSNicholas Bellinger 	unsigned long tmp;
2003c66ac9dbSNicholas Bellinger 	int ret;
2004c66ac9dbSNicholas Bellinger 
200557103d7fSJingoo Han 	ret = kstrtoul(page, 0, &tmp);
2006c66ac9dbSNicholas Bellinger 	if (ret < 0) {
20076708bb27SAndy Grover 		pr_err("Unable to extract alua_access_type\n");
200857103d7fSJingoo Han 		return ret;
2009c66ac9dbSNicholas Bellinger 	}
2010c66ac9dbSNicholas Bellinger 	if ((tmp != 0) && (tmp != 1) && (tmp != 2) && (tmp != 3)) {
20116708bb27SAndy Grover 		pr_err("Illegal value for alua_access_type:"
2012c66ac9dbSNicholas Bellinger 				" %lu\n", tmp);
2013c66ac9dbSNicholas Bellinger 		return -EINVAL;
2014c66ac9dbSNicholas Bellinger 	}
2015c66ac9dbSNicholas Bellinger 	if (tmp == 3)
2016c66ac9dbSNicholas Bellinger 		tg_pt_gp->tg_pt_gp_alua_access_type =
2017125d0119SHannes Reinecke 			TPGS_IMPLICIT_ALUA | TPGS_EXPLICIT_ALUA;
2018c66ac9dbSNicholas Bellinger 	else if (tmp == 2)
2019125d0119SHannes Reinecke 		tg_pt_gp->tg_pt_gp_alua_access_type = TPGS_EXPLICIT_ALUA;
2020c66ac9dbSNicholas Bellinger 	else if (tmp == 1)
2021125d0119SHannes Reinecke 		tg_pt_gp->tg_pt_gp_alua_access_type = TPGS_IMPLICIT_ALUA;
2022c66ac9dbSNicholas Bellinger 	else
2023c66ac9dbSNicholas Bellinger 		tg_pt_gp->tg_pt_gp_alua_access_type = 0;
2024c66ac9dbSNicholas Bellinger 
2025c66ac9dbSNicholas Bellinger 	return count;
2026c66ac9dbSNicholas Bellinger }
2027c66ac9dbSNicholas Bellinger 
core_alua_show_nonop_delay_msecs(struct t10_alua_tg_pt_gp * tg_pt_gp,char * page)2028c66ac9dbSNicholas Bellinger ssize_t core_alua_show_nonop_delay_msecs(
2029c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp,
2030c66ac9dbSNicholas Bellinger 	char *page)
2031c66ac9dbSNicholas Bellinger {
2032c66ac9dbSNicholas Bellinger 	return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_nonop_delay_msecs);
2033c66ac9dbSNicholas Bellinger }
2034c66ac9dbSNicholas Bellinger 
core_alua_store_nonop_delay_msecs(struct t10_alua_tg_pt_gp * tg_pt_gp,const char * page,size_t count)2035c66ac9dbSNicholas Bellinger ssize_t core_alua_store_nonop_delay_msecs(
2036c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp,
2037c66ac9dbSNicholas Bellinger 	const char *page,
2038c66ac9dbSNicholas Bellinger 	size_t count)
2039c66ac9dbSNicholas Bellinger {
2040c66ac9dbSNicholas Bellinger 	unsigned long tmp;
2041c66ac9dbSNicholas Bellinger 	int ret;
2042c66ac9dbSNicholas Bellinger 
204357103d7fSJingoo Han 	ret = kstrtoul(page, 0, &tmp);
2044c66ac9dbSNicholas Bellinger 	if (ret < 0) {
20456708bb27SAndy Grover 		pr_err("Unable to extract nonop_delay_msecs\n");
204657103d7fSJingoo Han 		return ret;
2047c66ac9dbSNicholas Bellinger 	}
2048c66ac9dbSNicholas Bellinger 	if (tmp > ALUA_MAX_NONOP_DELAY_MSECS) {
20496708bb27SAndy Grover 		pr_err("Passed nonop_delay_msecs: %lu, exceeds"
2050c66ac9dbSNicholas Bellinger 			" ALUA_MAX_NONOP_DELAY_MSECS: %d\n", tmp,
2051c66ac9dbSNicholas Bellinger 			ALUA_MAX_NONOP_DELAY_MSECS);
2052c66ac9dbSNicholas Bellinger 		return -EINVAL;
2053c66ac9dbSNicholas Bellinger 	}
2054c66ac9dbSNicholas Bellinger 	tg_pt_gp->tg_pt_gp_nonop_delay_msecs = (int)tmp;
2055c66ac9dbSNicholas Bellinger 
2056c66ac9dbSNicholas Bellinger 	return count;
2057c66ac9dbSNicholas Bellinger }
2058c66ac9dbSNicholas Bellinger 
core_alua_show_trans_delay_msecs(struct t10_alua_tg_pt_gp * tg_pt_gp,char * page)2059c66ac9dbSNicholas Bellinger ssize_t core_alua_show_trans_delay_msecs(
2060c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp,
2061c66ac9dbSNicholas Bellinger 	char *page)
2062c66ac9dbSNicholas Bellinger {
2063c66ac9dbSNicholas Bellinger 	return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_trans_delay_msecs);
2064c66ac9dbSNicholas Bellinger }
2065c66ac9dbSNicholas Bellinger 
core_alua_store_trans_delay_msecs(struct t10_alua_tg_pt_gp * tg_pt_gp,const char * page,size_t count)2066c66ac9dbSNicholas Bellinger ssize_t core_alua_store_trans_delay_msecs(
2067c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp,
2068c66ac9dbSNicholas Bellinger 	const char *page,
2069c66ac9dbSNicholas Bellinger 	size_t count)
2070c66ac9dbSNicholas Bellinger {
2071c66ac9dbSNicholas Bellinger 	unsigned long tmp;
2072c66ac9dbSNicholas Bellinger 	int ret;
2073c66ac9dbSNicholas Bellinger 
207457103d7fSJingoo Han 	ret = kstrtoul(page, 0, &tmp);
2075c66ac9dbSNicholas Bellinger 	if (ret < 0) {
20766708bb27SAndy Grover 		pr_err("Unable to extract trans_delay_msecs\n");
207757103d7fSJingoo Han 		return ret;
2078c66ac9dbSNicholas Bellinger 	}
2079c66ac9dbSNicholas Bellinger 	if (tmp > ALUA_MAX_TRANS_DELAY_MSECS) {
20806708bb27SAndy Grover 		pr_err("Passed trans_delay_msecs: %lu, exceeds"
2081c66ac9dbSNicholas Bellinger 			" ALUA_MAX_TRANS_DELAY_MSECS: %d\n", tmp,
2082c66ac9dbSNicholas Bellinger 			ALUA_MAX_TRANS_DELAY_MSECS);
2083c66ac9dbSNicholas Bellinger 		return -EINVAL;
2084c66ac9dbSNicholas Bellinger 	}
2085c66ac9dbSNicholas Bellinger 	tg_pt_gp->tg_pt_gp_trans_delay_msecs = (int)tmp;
2086c66ac9dbSNicholas Bellinger 
2087c66ac9dbSNicholas Bellinger 	return count;
2088c66ac9dbSNicholas Bellinger }
2089c66ac9dbSNicholas Bellinger 
core_alua_show_implicit_trans_secs(struct t10_alua_tg_pt_gp * tg_pt_gp,char * page)2090125d0119SHannes Reinecke ssize_t core_alua_show_implicit_trans_secs(
20915b9a4d72SNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp,
20925b9a4d72SNicholas Bellinger 	char *page)
20935b9a4d72SNicholas Bellinger {
2094125d0119SHannes Reinecke 	return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_implicit_trans_secs);
20955b9a4d72SNicholas Bellinger }
20965b9a4d72SNicholas Bellinger 
core_alua_store_implicit_trans_secs(struct t10_alua_tg_pt_gp * tg_pt_gp,const char * page,size_t count)2097125d0119SHannes Reinecke ssize_t core_alua_store_implicit_trans_secs(
20985b9a4d72SNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp,
20995b9a4d72SNicholas Bellinger 	const char *page,
21005b9a4d72SNicholas Bellinger 	size_t count)
21015b9a4d72SNicholas Bellinger {
21025b9a4d72SNicholas Bellinger 	unsigned long tmp;
21035b9a4d72SNicholas Bellinger 	int ret;
21045b9a4d72SNicholas Bellinger 
210557103d7fSJingoo Han 	ret = kstrtoul(page, 0, &tmp);
21065b9a4d72SNicholas Bellinger 	if (ret < 0) {
2107125d0119SHannes Reinecke 		pr_err("Unable to extract implicit_trans_secs\n");
210857103d7fSJingoo Han 		return ret;
21095b9a4d72SNicholas Bellinger 	}
2110125d0119SHannes Reinecke 	if (tmp > ALUA_MAX_IMPLICIT_TRANS_SECS) {
2111125d0119SHannes Reinecke 		pr_err("Passed implicit_trans_secs: %lu, exceeds"
2112125d0119SHannes Reinecke 			" ALUA_MAX_IMPLICIT_TRANS_SECS: %d\n", tmp,
2113125d0119SHannes Reinecke 			ALUA_MAX_IMPLICIT_TRANS_SECS);
21145b9a4d72SNicholas Bellinger 		return  -EINVAL;
21155b9a4d72SNicholas Bellinger 	}
2116125d0119SHannes Reinecke 	tg_pt_gp->tg_pt_gp_implicit_trans_secs = (int)tmp;
21175b9a4d72SNicholas Bellinger 
21185b9a4d72SNicholas Bellinger 	return count;
21195b9a4d72SNicholas Bellinger }
21205b9a4d72SNicholas Bellinger 
core_alua_show_preferred_bit(struct t10_alua_tg_pt_gp * tg_pt_gp,char * page)2121c66ac9dbSNicholas Bellinger ssize_t core_alua_show_preferred_bit(
2122c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp,
2123c66ac9dbSNicholas Bellinger 	char *page)
2124c66ac9dbSNicholas Bellinger {
2125c66ac9dbSNicholas Bellinger 	return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_pref);
2126c66ac9dbSNicholas Bellinger }
2127c66ac9dbSNicholas Bellinger 
core_alua_store_preferred_bit(struct t10_alua_tg_pt_gp * tg_pt_gp,const char * page,size_t count)2128c66ac9dbSNicholas Bellinger ssize_t core_alua_store_preferred_bit(
2129c66ac9dbSNicholas Bellinger 	struct t10_alua_tg_pt_gp *tg_pt_gp,
2130c66ac9dbSNicholas Bellinger 	const char *page,
2131c66ac9dbSNicholas Bellinger 	size_t count)
2132c66ac9dbSNicholas Bellinger {
2133c66ac9dbSNicholas Bellinger 	unsigned long tmp;
2134c66ac9dbSNicholas Bellinger 	int ret;
2135c66ac9dbSNicholas Bellinger 
213657103d7fSJingoo Han 	ret = kstrtoul(page, 0, &tmp);
2137c66ac9dbSNicholas Bellinger 	if (ret < 0) {
21386708bb27SAndy Grover 		pr_err("Unable to extract preferred ALUA value\n");
213957103d7fSJingoo Han 		return ret;
2140c66ac9dbSNicholas Bellinger 	}
2141c66ac9dbSNicholas Bellinger 	if ((tmp != 0) && (tmp != 1)) {
21426708bb27SAndy Grover 		pr_err("Illegal value for preferred ALUA: %lu\n", tmp);
2143c66ac9dbSNicholas Bellinger 		return -EINVAL;
2144c66ac9dbSNicholas Bellinger 	}
2145c66ac9dbSNicholas Bellinger 	tg_pt_gp->tg_pt_gp_pref = (int)tmp;
2146c66ac9dbSNicholas Bellinger 
2147c66ac9dbSNicholas Bellinger 	return count;
2148c66ac9dbSNicholas Bellinger }
2149c66ac9dbSNicholas Bellinger 
core_alua_show_offline_bit(struct se_lun * lun,char * page)2150c66ac9dbSNicholas Bellinger ssize_t core_alua_show_offline_bit(struct se_lun *lun, char *page)
2151c66ac9dbSNicholas Bellinger {
2152c66ac9dbSNicholas Bellinger 	return sprintf(page, "%d\n",
2153adf653f9SChristoph Hellwig 		atomic_read(&lun->lun_tg_pt_secondary_offline));
2154c66ac9dbSNicholas Bellinger }
2155c66ac9dbSNicholas Bellinger 
core_alua_store_offline_bit(struct se_lun * lun,const char * page,size_t count)2156c66ac9dbSNicholas Bellinger ssize_t core_alua_store_offline_bit(
2157c66ac9dbSNicholas Bellinger 	struct se_lun *lun,
2158c66ac9dbSNicholas Bellinger 	const char *page,
2159c66ac9dbSNicholas Bellinger 	size_t count)
2160c66ac9dbSNicholas Bellinger {
21614cc987eaSNicholas Bellinger 	/*
21624cc987eaSNicholas Bellinger 	 * rcu_dereference_raw protected by se_lun->lun_group symlink
21634cc987eaSNicholas Bellinger 	 * reference to se_device->dev_group.
21644cc987eaSNicholas Bellinger 	 */
21654cc987eaSNicholas Bellinger 	struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev);
2166c66ac9dbSNicholas Bellinger 	unsigned long tmp;
2167c66ac9dbSNicholas Bellinger 	int ret;
2168c66ac9dbSNicholas Bellinger 
216969088a04SBodo Stroesser 	if (dev->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_ALUA ||
2170adf653f9SChristoph Hellwig 	    (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))
2171c66ac9dbSNicholas Bellinger 		return -ENODEV;
2172c66ac9dbSNicholas Bellinger 
217357103d7fSJingoo Han 	ret = kstrtoul(page, 0, &tmp);
2174c66ac9dbSNicholas Bellinger 	if (ret < 0) {
21756708bb27SAndy Grover 		pr_err("Unable to extract alua_tg_pt_offline value\n");
217657103d7fSJingoo Han 		return ret;
2177c66ac9dbSNicholas Bellinger 	}
2178c66ac9dbSNicholas Bellinger 	if ((tmp != 0) && (tmp != 1)) {
21796708bb27SAndy Grover 		pr_err("Illegal value for alua_tg_pt_offline: %lu\n",
2180c66ac9dbSNicholas Bellinger 				tmp);
2181c66ac9dbSNicholas Bellinger 		return -EINVAL;
2182c66ac9dbSNicholas Bellinger 	}
2183c66ac9dbSNicholas Bellinger 
2184adf653f9SChristoph Hellwig 	ret = core_alua_set_tg_pt_secondary_state(lun, 0, (int)tmp);
2185c66ac9dbSNicholas Bellinger 	if (ret < 0)
2186c66ac9dbSNicholas Bellinger 		return -EINVAL;
2187c66ac9dbSNicholas Bellinger 
2188c66ac9dbSNicholas Bellinger 	return count;
2189c66ac9dbSNicholas Bellinger }
2190c66ac9dbSNicholas Bellinger 
core_alua_show_secondary_status(struct se_lun * lun,char * page)2191c66ac9dbSNicholas Bellinger ssize_t core_alua_show_secondary_status(
2192c66ac9dbSNicholas Bellinger 	struct se_lun *lun,
2193c66ac9dbSNicholas Bellinger 	char *page)
2194c66ac9dbSNicholas Bellinger {
2195adf653f9SChristoph Hellwig 	return sprintf(page, "%d\n", lun->lun_tg_pt_secondary_stat);
2196c66ac9dbSNicholas Bellinger }
2197c66ac9dbSNicholas Bellinger 
core_alua_store_secondary_status(struct se_lun * lun,const char * page,size_t count)2198c66ac9dbSNicholas Bellinger ssize_t core_alua_store_secondary_status(
2199c66ac9dbSNicholas Bellinger 	struct se_lun *lun,
2200c66ac9dbSNicholas Bellinger 	const char *page,
2201c66ac9dbSNicholas Bellinger 	size_t count)
2202c66ac9dbSNicholas Bellinger {
2203c66ac9dbSNicholas Bellinger 	unsigned long tmp;
2204c66ac9dbSNicholas Bellinger 	int ret;
2205c66ac9dbSNicholas Bellinger 
220657103d7fSJingoo Han 	ret = kstrtoul(page, 0, &tmp);
2207c66ac9dbSNicholas Bellinger 	if (ret < 0) {
22086708bb27SAndy Grover 		pr_err("Unable to extract alua_tg_pt_status\n");
220957103d7fSJingoo Han 		return ret;
2210c66ac9dbSNicholas Bellinger 	}
2211c66ac9dbSNicholas Bellinger 	if ((tmp != ALUA_STATUS_NONE) &&
2212125d0119SHannes Reinecke 	    (tmp != ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG) &&
2213125d0119SHannes Reinecke 	    (tmp != ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA)) {
22146708bb27SAndy Grover 		pr_err("Illegal value for alua_tg_pt_status: %lu\n",
2215c66ac9dbSNicholas Bellinger 				tmp);
2216c66ac9dbSNicholas Bellinger 		return -EINVAL;
2217c66ac9dbSNicholas Bellinger 	}
2218adf653f9SChristoph Hellwig 	lun->lun_tg_pt_secondary_stat = (int)tmp;
2219c66ac9dbSNicholas Bellinger 
2220c66ac9dbSNicholas Bellinger 	return count;
2221c66ac9dbSNicholas Bellinger }
2222c66ac9dbSNicholas Bellinger 
core_alua_show_secondary_write_metadata(struct se_lun * lun,char * page)2223c66ac9dbSNicholas Bellinger ssize_t core_alua_show_secondary_write_metadata(
2224c66ac9dbSNicholas Bellinger 	struct se_lun *lun,
2225c66ac9dbSNicholas Bellinger 	char *page)
2226c66ac9dbSNicholas Bellinger {
2227adf653f9SChristoph Hellwig 	return sprintf(page, "%d\n", lun->lun_tg_pt_secondary_write_md);
2228c66ac9dbSNicholas Bellinger }
2229c66ac9dbSNicholas Bellinger 
core_alua_store_secondary_write_metadata(struct se_lun * lun,const char * page,size_t count)2230c66ac9dbSNicholas Bellinger ssize_t core_alua_store_secondary_write_metadata(
2231c66ac9dbSNicholas Bellinger 	struct se_lun *lun,
2232c66ac9dbSNicholas Bellinger 	const char *page,
2233c66ac9dbSNicholas Bellinger 	size_t count)
2234c66ac9dbSNicholas Bellinger {
2235c66ac9dbSNicholas Bellinger 	unsigned long tmp;
2236c66ac9dbSNicholas Bellinger 	int ret;
2237c66ac9dbSNicholas Bellinger 
223857103d7fSJingoo Han 	ret = kstrtoul(page, 0, &tmp);
2239c66ac9dbSNicholas Bellinger 	if (ret < 0) {
22406708bb27SAndy Grover 		pr_err("Unable to extract alua_tg_pt_write_md\n");
224157103d7fSJingoo Han 		return ret;
2242c66ac9dbSNicholas Bellinger 	}
2243c66ac9dbSNicholas Bellinger 	if ((tmp != 0) && (tmp != 1)) {
22446708bb27SAndy Grover 		pr_err("Illegal value for alua_tg_pt_write_md:"
2245c66ac9dbSNicholas Bellinger 				" %lu\n", tmp);
2246c66ac9dbSNicholas Bellinger 		return -EINVAL;
2247c66ac9dbSNicholas Bellinger 	}
2248adf653f9SChristoph Hellwig 	lun->lun_tg_pt_secondary_write_md = (int)tmp;
2249c66ac9dbSNicholas Bellinger 
2250c66ac9dbSNicholas Bellinger 	return count;
2251c66ac9dbSNicholas Bellinger }
2252c66ac9dbSNicholas Bellinger 
core_setup_alua(struct se_device * dev)22530fd97ccfSChristoph Hellwig int core_setup_alua(struct se_device *dev)
2254c66ac9dbSNicholas Bellinger {
225569088a04SBodo Stroesser 	if (!(dev->transport_flags &
2256530c6891SMike Christie 	     TRANSPORT_FLAG_PASSTHROUGH_ALUA) &&
2257c87fbd56SChristoph Hellwig 	    !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) {
2258c66ac9dbSNicholas Bellinger 		struct t10_alua_lu_gp_member *lu_gp_mem;
22590fd97ccfSChristoph Hellwig 
2260c66ac9dbSNicholas Bellinger 		/*
226125985edcSLucas De Marchi 		 * Associate this struct se_device with the default ALUA
2262c66ac9dbSNicholas Bellinger 		 * LUN Group.
2263c66ac9dbSNicholas Bellinger 		 */
2264c66ac9dbSNicholas Bellinger 		lu_gp_mem = core_alua_allocate_lu_gp_mem(dev);
2265e3d6f909SAndy Grover 		if (IS_ERR(lu_gp_mem))
2266e3d6f909SAndy Grover 			return PTR_ERR(lu_gp_mem);
2267c66ac9dbSNicholas Bellinger 
2268c66ac9dbSNicholas Bellinger 		spin_lock(&lu_gp_mem->lu_gp_mem_lock);
2269c66ac9dbSNicholas Bellinger 		__core_alua_attach_lu_gp_mem(lu_gp_mem,
2270e3d6f909SAndy Grover 				default_lu_gp);
2271c66ac9dbSNicholas Bellinger 		spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
2272c66ac9dbSNicholas Bellinger 
22736708bb27SAndy Grover 		pr_debug("%s: Adding to default ALUA LU Group:"
2274c66ac9dbSNicholas Bellinger 			" core/alua/lu_gps/default_lu_gp\n",
2275e3d6f909SAndy Grover 			dev->transport->name);
2276c66ac9dbSNicholas Bellinger 	}
2277c66ac9dbSNicholas Bellinger 
2278c66ac9dbSNicholas Bellinger 	return 0;
2279c66ac9dbSNicholas Bellinger }
2280