162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Generic SCSI-3 ALUA SCSI Device Handler
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2007-2010 Hannes Reinecke, SUSE Linux Products GmbH.
662306a36Sopenharmony_ci * All rights reserved.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci#include <linux/slab.h>
962306a36Sopenharmony_ci#include <linux/delay.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <asm/unaligned.h>
1262306a36Sopenharmony_ci#include <scsi/scsi.h>
1362306a36Sopenharmony_ci#include <scsi/scsi_proto.h>
1462306a36Sopenharmony_ci#include <scsi/scsi_dbg.h>
1562306a36Sopenharmony_ci#include <scsi/scsi_eh.h>
1662306a36Sopenharmony_ci#include <scsi/scsi_dh.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define ALUA_DH_NAME "alua"
1962306a36Sopenharmony_ci#define ALUA_DH_VER "2.0"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define TPGS_SUPPORT_NONE		0x00
2262306a36Sopenharmony_ci#define TPGS_SUPPORT_OPTIMIZED		0x01
2362306a36Sopenharmony_ci#define TPGS_SUPPORT_NONOPTIMIZED	0x02
2462306a36Sopenharmony_ci#define TPGS_SUPPORT_STANDBY		0x04
2562306a36Sopenharmony_ci#define TPGS_SUPPORT_UNAVAILABLE	0x08
2662306a36Sopenharmony_ci#define TPGS_SUPPORT_LBA_DEPENDENT	0x10
2762306a36Sopenharmony_ci#define TPGS_SUPPORT_OFFLINE		0x40
2862306a36Sopenharmony_ci#define TPGS_SUPPORT_TRANSITION		0x80
2962306a36Sopenharmony_ci#define TPGS_SUPPORT_ALL		0xdf
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define RTPG_FMT_MASK			0x70
3262306a36Sopenharmony_ci#define RTPG_FMT_EXT_HDR		0x10
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define TPGS_MODE_UNINITIALIZED		 -1
3562306a36Sopenharmony_ci#define TPGS_MODE_NONE			0x0
3662306a36Sopenharmony_ci#define TPGS_MODE_IMPLICIT		0x1
3762306a36Sopenharmony_ci#define TPGS_MODE_EXPLICIT		0x2
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define ALUA_RTPG_SIZE			128
4062306a36Sopenharmony_ci#define ALUA_FAILOVER_TIMEOUT		60
4162306a36Sopenharmony_ci#define ALUA_FAILOVER_RETRIES		5
4262306a36Sopenharmony_ci#define ALUA_RTPG_DELAY_MSECS		5
4362306a36Sopenharmony_ci#define ALUA_RTPG_RETRY_DELAY		2
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* device handler flags */
4662306a36Sopenharmony_ci#define ALUA_OPTIMIZE_STPG		0x01
4762306a36Sopenharmony_ci#define ALUA_RTPG_EXT_HDR_UNSUPP	0x02
4862306a36Sopenharmony_ci/* State machine flags */
4962306a36Sopenharmony_ci#define ALUA_PG_RUN_RTPG		0x10
5062306a36Sopenharmony_ci#define ALUA_PG_RUN_STPG		0x20
5162306a36Sopenharmony_ci#define ALUA_PG_RUNNING			0x40
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic uint optimize_stpg;
5462306a36Sopenharmony_cimodule_param(optimize_stpg, uint, S_IRUGO|S_IWUSR);
5562306a36Sopenharmony_ciMODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than sending a STPG, when implicit TPGS is supported (0=No,1=Yes). Default is 0.");
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic LIST_HEAD(port_group_list);
5862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(port_group_lock);
5962306a36Sopenharmony_cistatic struct workqueue_struct *kaluad_wq;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistruct alua_port_group {
6262306a36Sopenharmony_ci	struct kref		kref;
6362306a36Sopenharmony_ci	struct rcu_head		rcu;
6462306a36Sopenharmony_ci	struct list_head	node;
6562306a36Sopenharmony_ci	struct list_head	dh_list;
6662306a36Sopenharmony_ci	unsigned char		device_id_str[256];
6762306a36Sopenharmony_ci	int			device_id_len;
6862306a36Sopenharmony_ci	int			group_id;
6962306a36Sopenharmony_ci	int			tpgs;
7062306a36Sopenharmony_ci	int			state;
7162306a36Sopenharmony_ci	int			pref;
7262306a36Sopenharmony_ci	int			valid_states;
7362306a36Sopenharmony_ci	unsigned		flags; /* used for optimizing STPG */
7462306a36Sopenharmony_ci	unsigned char		transition_tmo;
7562306a36Sopenharmony_ci	unsigned long		expiry;
7662306a36Sopenharmony_ci	unsigned long		interval;
7762306a36Sopenharmony_ci	struct delayed_work	rtpg_work;
7862306a36Sopenharmony_ci	spinlock_t		lock;
7962306a36Sopenharmony_ci	struct list_head	rtpg_list;
8062306a36Sopenharmony_ci	struct scsi_device	*rtpg_sdev;
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistruct alua_dh_data {
8462306a36Sopenharmony_ci	struct list_head	node;
8562306a36Sopenharmony_ci	struct alua_port_group __rcu *pg;
8662306a36Sopenharmony_ci	int			group_id;
8762306a36Sopenharmony_ci	spinlock_t		pg_lock;
8862306a36Sopenharmony_ci	struct scsi_device	*sdev;
8962306a36Sopenharmony_ci	int			init_error;
9062306a36Sopenharmony_ci	struct mutex		init_mutex;
9162306a36Sopenharmony_ci	bool			disabled;
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistruct alua_queue_data {
9562306a36Sopenharmony_ci	struct list_head	entry;
9662306a36Sopenharmony_ci	activate_complete	callback_fn;
9762306a36Sopenharmony_ci	void			*callback_data;
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define ALUA_POLICY_SWITCH_CURRENT	0
10162306a36Sopenharmony_ci#define ALUA_POLICY_SWITCH_ALL		1
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic void alua_rtpg_work(struct work_struct *work);
10462306a36Sopenharmony_cistatic bool alua_rtpg_queue(struct alua_port_group *pg,
10562306a36Sopenharmony_ci			    struct scsi_device *sdev,
10662306a36Sopenharmony_ci			    struct alua_queue_data *qdata, bool force);
10762306a36Sopenharmony_cistatic void alua_check(struct scsi_device *sdev, bool force);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic void release_port_group(struct kref *kref)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	struct alua_port_group *pg;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	pg = container_of(kref, struct alua_port_group, kref);
11462306a36Sopenharmony_ci	if (pg->rtpg_sdev)
11562306a36Sopenharmony_ci		flush_delayed_work(&pg->rtpg_work);
11662306a36Sopenharmony_ci	spin_lock(&port_group_lock);
11762306a36Sopenharmony_ci	list_del(&pg->node);
11862306a36Sopenharmony_ci	spin_unlock(&port_group_lock);
11962306a36Sopenharmony_ci	kfree_rcu(pg, rcu);
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/*
12362306a36Sopenharmony_ci * submit_rtpg - Issue a REPORT TARGET GROUP STATES command
12462306a36Sopenharmony_ci * @sdev: sdev the command should be sent to
12562306a36Sopenharmony_ci */
12662306a36Sopenharmony_cistatic int submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
12762306a36Sopenharmony_ci		       int bufflen, struct scsi_sense_hdr *sshdr, int flags)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	u8 cdb[MAX_COMMAND_SIZE];
13062306a36Sopenharmony_ci	blk_opf_t opf = REQ_OP_DRV_IN | REQ_FAILFAST_DEV |
13162306a36Sopenharmony_ci				REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER;
13262306a36Sopenharmony_ci	const struct scsi_exec_args exec_args = {
13362306a36Sopenharmony_ci		.sshdr = sshdr,
13462306a36Sopenharmony_ci	};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* Prepare the command. */
13762306a36Sopenharmony_ci	memset(cdb, 0x0, MAX_COMMAND_SIZE);
13862306a36Sopenharmony_ci	cdb[0] = MAINTENANCE_IN;
13962306a36Sopenharmony_ci	if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP))
14062306a36Sopenharmony_ci		cdb[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
14162306a36Sopenharmony_ci	else
14262306a36Sopenharmony_ci		cdb[1] = MI_REPORT_TARGET_PGS;
14362306a36Sopenharmony_ci	put_unaligned_be32(bufflen, &cdb[6]);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	return scsi_execute_cmd(sdev, cdb, opf, buff, bufflen,
14662306a36Sopenharmony_ci				ALUA_FAILOVER_TIMEOUT * HZ,
14762306a36Sopenharmony_ci				ALUA_FAILOVER_RETRIES, &exec_args);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/*
15162306a36Sopenharmony_ci * submit_stpg - Issue a SET TARGET PORT GROUP command
15262306a36Sopenharmony_ci *
15362306a36Sopenharmony_ci * Currently we're only setting the current target port group state
15462306a36Sopenharmony_ci * to 'active/optimized' and let the array firmware figure out
15562306a36Sopenharmony_ci * the states of the remaining groups.
15662306a36Sopenharmony_ci */
15762306a36Sopenharmony_cistatic int submit_stpg(struct scsi_device *sdev, int group_id,
15862306a36Sopenharmony_ci		       struct scsi_sense_hdr *sshdr)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	u8 cdb[MAX_COMMAND_SIZE];
16162306a36Sopenharmony_ci	unsigned char stpg_data[8];
16262306a36Sopenharmony_ci	int stpg_len = 8;
16362306a36Sopenharmony_ci	blk_opf_t opf = REQ_OP_DRV_OUT | REQ_FAILFAST_DEV |
16462306a36Sopenharmony_ci				REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER;
16562306a36Sopenharmony_ci	const struct scsi_exec_args exec_args = {
16662306a36Sopenharmony_ci		.sshdr = sshdr,
16762306a36Sopenharmony_ci	};
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	/* Prepare the data buffer */
17062306a36Sopenharmony_ci	memset(stpg_data, 0, stpg_len);
17162306a36Sopenharmony_ci	stpg_data[4] = SCSI_ACCESS_STATE_OPTIMAL;
17262306a36Sopenharmony_ci	put_unaligned_be16(group_id, &stpg_data[6]);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	/* Prepare the command. */
17562306a36Sopenharmony_ci	memset(cdb, 0x0, MAX_COMMAND_SIZE);
17662306a36Sopenharmony_ci	cdb[0] = MAINTENANCE_OUT;
17762306a36Sopenharmony_ci	cdb[1] = MO_SET_TARGET_PGS;
17862306a36Sopenharmony_ci	put_unaligned_be32(stpg_len, &cdb[6]);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return scsi_execute_cmd(sdev, cdb, opf, stpg_data,
18162306a36Sopenharmony_ci				stpg_len, ALUA_FAILOVER_TIMEOUT * HZ,
18262306a36Sopenharmony_ci				ALUA_FAILOVER_RETRIES, &exec_args);
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic struct alua_port_group *alua_find_get_pg(char *id_str, size_t id_size,
18662306a36Sopenharmony_ci						int group_id)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct alua_port_group *pg;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	if (!id_str || !id_size || !strlen(id_str))
19162306a36Sopenharmony_ci		return NULL;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	list_for_each_entry(pg, &port_group_list, node) {
19462306a36Sopenharmony_ci		if (pg->group_id != group_id)
19562306a36Sopenharmony_ci			continue;
19662306a36Sopenharmony_ci		if (!pg->device_id_len || pg->device_id_len != id_size)
19762306a36Sopenharmony_ci			continue;
19862306a36Sopenharmony_ci		if (strncmp(pg->device_id_str, id_str, id_size))
19962306a36Sopenharmony_ci			continue;
20062306a36Sopenharmony_ci		if (!kref_get_unless_zero(&pg->kref))
20162306a36Sopenharmony_ci			continue;
20262306a36Sopenharmony_ci		return pg;
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	return NULL;
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci/*
20962306a36Sopenharmony_ci * alua_alloc_pg - Allocate a new port_group structure
21062306a36Sopenharmony_ci * @sdev: scsi device
21162306a36Sopenharmony_ci * @group_id: port group id
21262306a36Sopenharmony_ci * @tpgs: target port group settings
21362306a36Sopenharmony_ci *
21462306a36Sopenharmony_ci * Allocate a new port_group structure for a given
21562306a36Sopenharmony_ci * device.
21662306a36Sopenharmony_ci */
21762306a36Sopenharmony_cistatic struct alua_port_group *alua_alloc_pg(struct scsi_device *sdev,
21862306a36Sopenharmony_ci					     int group_id, int tpgs)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct alua_port_group *pg, *tmp_pg;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL);
22362306a36Sopenharmony_ci	if (!pg)
22462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	pg->device_id_len = scsi_vpd_lun_id(sdev, pg->device_id_str,
22762306a36Sopenharmony_ci					    sizeof(pg->device_id_str));
22862306a36Sopenharmony_ci	if (pg->device_id_len <= 0) {
22962306a36Sopenharmony_ci		/*
23062306a36Sopenharmony_ci		 * TPGS supported but no device identification found.
23162306a36Sopenharmony_ci		 * Generate private device identification.
23262306a36Sopenharmony_ci		 */
23362306a36Sopenharmony_ci		sdev_printk(KERN_INFO, sdev,
23462306a36Sopenharmony_ci			    "%s: No device descriptors found\n",
23562306a36Sopenharmony_ci			    ALUA_DH_NAME);
23662306a36Sopenharmony_ci		pg->device_id_str[0] = '\0';
23762306a36Sopenharmony_ci		pg->device_id_len = 0;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci	pg->group_id = group_id;
24062306a36Sopenharmony_ci	pg->tpgs = tpgs;
24162306a36Sopenharmony_ci	pg->state = SCSI_ACCESS_STATE_OPTIMAL;
24262306a36Sopenharmony_ci	pg->valid_states = TPGS_SUPPORT_ALL;
24362306a36Sopenharmony_ci	if (optimize_stpg)
24462306a36Sopenharmony_ci		pg->flags |= ALUA_OPTIMIZE_STPG;
24562306a36Sopenharmony_ci	kref_init(&pg->kref);
24662306a36Sopenharmony_ci	INIT_DELAYED_WORK(&pg->rtpg_work, alua_rtpg_work);
24762306a36Sopenharmony_ci	INIT_LIST_HEAD(&pg->rtpg_list);
24862306a36Sopenharmony_ci	INIT_LIST_HEAD(&pg->node);
24962306a36Sopenharmony_ci	INIT_LIST_HEAD(&pg->dh_list);
25062306a36Sopenharmony_ci	spin_lock_init(&pg->lock);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	spin_lock(&port_group_lock);
25362306a36Sopenharmony_ci	tmp_pg = alua_find_get_pg(pg->device_id_str, pg->device_id_len,
25462306a36Sopenharmony_ci				  group_id);
25562306a36Sopenharmony_ci	if (tmp_pg) {
25662306a36Sopenharmony_ci		spin_unlock(&port_group_lock);
25762306a36Sopenharmony_ci		kfree(pg);
25862306a36Sopenharmony_ci		return tmp_pg;
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	list_add(&pg->node, &port_group_list);
26262306a36Sopenharmony_ci	spin_unlock(&port_group_lock);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return pg;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/*
26862306a36Sopenharmony_ci * alua_check_tpgs - Evaluate TPGS setting
26962306a36Sopenharmony_ci * @sdev: device to be checked
27062306a36Sopenharmony_ci *
27162306a36Sopenharmony_ci * Examine the TPGS setting of the sdev to find out if ALUA
27262306a36Sopenharmony_ci * is supported.
27362306a36Sopenharmony_ci */
27462306a36Sopenharmony_cistatic int alua_check_tpgs(struct scsi_device *sdev)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	int tpgs = TPGS_MODE_NONE;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	/*
27962306a36Sopenharmony_ci	 * ALUA support for non-disk devices is fraught with
28062306a36Sopenharmony_ci	 * difficulties, so disable it for now.
28162306a36Sopenharmony_ci	 */
28262306a36Sopenharmony_ci	if (sdev->type != TYPE_DISK) {
28362306a36Sopenharmony_ci		sdev_printk(KERN_INFO, sdev,
28462306a36Sopenharmony_ci			    "%s: disable for non-disk devices\n",
28562306a36Sopenharmony_ci			    ALUA_DH_NAME);
28662306a36Sopenharmony_ci		return tpgs;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	tpgs = scsi_device_tpgs(sdev);
29062306a36Sopenharmony_ci	switch (tpgs) {
29162306a36Sopenharmony_ci	case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT:
29262306a36Sopenharmony_ci		sdev_printk(KERN_INFO, sdev,
29362306a36Sopenharmony_ci			    "%s: supports implicit and explicit TPGS\n",
29462306a36Sopenharmony_ci			    ALUA_DH_NAME);
29562306a36Sopenharmony_ci		break;
29662306a36Sopenharmony_ci	case TPGS_MODE_EXPLICIT:
29762306a36Sopenharmony_ci		sdev_printk(KERN_INFO, sdev, "%s: supports explicit TPGS\n",
29862306a36Sopenharmony_ci			    ALUA_DH_NAME);
29962306a36Sopenharmony_ci		break;
30062306a36Sopenharmony_ci	case TPGS_MODE_IMPLICIT:
30162306a36Sopenharmony_ci		sdev_printk(KERN_INFO, sdev, "%s: supports implicit TPGS\n",
30262306a36Sopenharmony_ci			    ALUA_DH_NAME);
30362306a36Sopenharmony_ci		break;
30462306a36Sopenharmony_ci	case TPGS_MODE_NONE:
30562306a36Sopenharmony_ci		sdev_printk(KERN_INFO, sdev, "%s: not supported\n",
30662306a36Sopenharmony_ci			    ALUA_DH_NAME);
30762306a36Sopenharmony_ci		break;
30862306a36Sopenharmony_ci	default:
30962306a36Sopenharmony_ci		sdev_printk(KERN_INFO, sdev,
31062306a36Sopenharmony_ci			    "%s: unsupported TPGS setting %d\n",
31162306a36Sopenharmony_ci			    ALUA_DH_NAME, tpgs);
31262306a36Sopenharmony_ci		tpgs = TPGS_MODE_NONE;
31362306a36Sopenharmony_ci		break;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	return tpgs;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci/*
32062306a36Sopenharmony_ci * alua_check_vpd - Evaluate INQUIRY vpd page 0x83
32162306a36Sopenharmony_ci * @sdev: device to be checked
32262306a36Sopenharmony_ci *
32362306a36Sopenharmony_ci * Extract the relative target port and the target port group
32462306a36Sopenharmony_ci * descriptor from the list of identificators.
32562306a36Sopenharmony_ci */
32662306a36Sopenharmony_cistatic int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
32762306a36Sopenharmony_ci			  int tpgs)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	int rel_port = -1, group_id;
33062306a36Sopenharmony_ci	struct alua_port_group *pg, *old_pg = NULL;
33162306a36Sopenharmony_ci	bool pg_updated = false;
33262306a36Sopenharmony_ci	unsigned long flags;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	group_id = scsi_vpd_tpg_id(sdev, &rel_port);
33562306a36Sopenharmony_ci	if (group_id < 0) {
33662306a36Sopenharmony_ci		/*
33762306a36Sopenharmony_ci		 * Internal error; TPGS supported but required
33862306a36Sopenharmony_ci		 * VPD identification descriptors not present.
33962306a36Sopenharmony_ci		 * Disable ALUA support
34062306a36Sopenharmony_ci		 */
34162306a36Sopenharmony_ci		sdev_printk(KERN_INFO, sdev,
34262306a36Sopenharmony_ci			    "%s: No target port descriptors found\n",
34362306a36Sopenharmony_ci			    ALUA_DH_NAME);
34462306a36Sopenharmony_ci		return SCSI_DH_DEV_UNSUPP;
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	pg = alua_alloc_pg(sdev, group_id, tpgs);
34862306a36Sopenharmony_ci	if (IS_ERR(pg)) {
34962306a36Sopenharmony_ci		if (PTR_ERR(pg) == -ENOMEM)
35062306a36Sopenharmony_ci			return SCSI_DH_NOMEM;
35162306a36Sopenharmony_ci		return SCSI_DH_DEV_UNSUPP;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci	if (pg->device_id_len)
35462306a36Sopenharmony_ci		sdev_printk(KERN_INFO, sdev,
35562306a36Sopenharmony_ci			    "%s: device %s port group %x rel port %x\n",
35662306a36Sopenharmony_ci			    ALUA_DH_NAME, pg->device_id_str,
35762306a36Sopenharmony_ci			    group_id, rel_port);
35862306a36Sopenharmony_ci	else
35962306a36Sopenharmony_ci		sdev_printk(KERN_INFO, sdev,
36062306a36Sopenharmony_ci			    "%s: port group %x rel port %x\n",
36162306a36Sopenharmony_ci			    ALUA_DH_NAME, group_id, rel_port);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	kref_get(&pg->kref);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/* Check for existing port group references */
36662306a36Sopenharmony_ci	spin_lock(&h->pg_lock);
36762306a36Sopenharmony_ci	old_pg = rcu_dereference_protected(h->pg, lockdep_is_held(&h->pg_lock));
36862306a36Sopenharmony_ci	if (old_pg != pg) {
36962306a36Sopenharmony_ci		/* port group has changed. Update to new port group */
37062306a36Sopenharmony_ci		if (h->pg) {
37162306a36Sopenharmony_ci			spin_lock_irqsave(&old_pg->lock, flags);
37262306a36Sopenharmony_ci			list_del_rcu(&h->node);
37362306a36Sopenharmony_ci			spin_unlock_irqrestore(&old_pg->lock, flags);
37462306a36Sopenharmony_ci		}
37562306a36Sopenharmony_ci		rcu_assign_pointer(h->pg, pg);
37662306a36Sopenharmony_ci		pg_updated = true;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	spin_lock_irqsave(&pg->lock, flags);
38062306a36Sopenharmony_ci	if (pg_updated)
38162306a36Sopenharmony_ci		list_add_rcu(&h->node, &pg->dh_list);
38262306a36Sopenharmony_ci	spin_unlock_irqrestore(&pg->lock, flags);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	spin_unlock(&h->pg_lock);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	alua_rtpg_queue(pg, sdev, NULL, true);
38762306a36Sopenharmony_ci	kref_put(&pg->kref, release_port_group);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	if (old_pg)
39062306a36Sopenharmony_ci		kref_put(&old_pg->kref, release_port_group);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	return SCSI_DH_OK;
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic char print_alua_state(unsigned char state)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	switch (state) {
39862306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_OPTIMAL:
39962306a36Sopenharmony_ci		return 'A';
40062306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_ACTIVE:
40162306a36Sopenharmony_ci		return 'N';
40262306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_STANDBY:
40362306a36Sopenharmony_ci		return 'S';
40462306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_UNAVAILABLE:
40562306a36Sopenharmony_ci		return 'U';
40662306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_LBA:
40762306a36Sopenharmony_ci		return 'L';
40862306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_OFFLINE:
40962306a36Sopenharmony_ci		return 'O';
41062306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_TRANSITIONING:
41162306a36Sopenharmony_ci		return 'T';
41262306a36Sopenharmony_ci	default:
41362306a36Sopenharmony_ci		return 'X';
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic enum scsi_disposition alua_check_sense(struct scsi_device *sdev,
41862306a36Sopenharmony_ci					      struct scsi_sense_hdr *sense_hdr)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	struct alua_dh_data *h = sdev->handler_data;
42162306a36Sopenharmony_ci	struct alua_port_group *pg;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	switch (sense_hdr->sense_key) {
42462306a36Sopenharmony_ci	case NOT_READY:
42562306a36Sopenharmony_ci		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
42662306a36Sopenharmony_ci			/*
42762306a36Sopenharmony_ci			 * LUN Not Accessible - ALUA state transition
42862306a36Sopenharmony_ci			 */
42962306a36Sopenharmony_ci			rcu_read_lock();
43062306a36Sopenharmony_ci			pg = rcu_dereference(h->pg);
43162306a36Sopenharmony_ci			if (pg)
43262306a36Sopenharmony_ci				pg->state = SCSI_ACCESS_STATE_TRANSITIONING;
43362306a36Sopenharmony_ci			rcu_read_unlock();
43462306a36Sopenharmony_ci			alua_check(sdev, false);
43562306a36Sopenharmony_ci			return NEEDS_RETRY;
43662306a36Sopenharmony_ci		}
43762306a36Sopenharmony_ci		break;
43862306a36Sopenharmony_ci	case UNIT_ATTENTION:
43962306a36Sopenharmony_ci		if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) {
44062306a36Sopenharmony_ci			/*
44162306a36Sopenharmony_ci			 * Power On, Reset, or Bus Device Reset.
44262306a36Sopenharmony_ci			 * Might have obscured a state transition,
44362306a36Sopenharmony_ci			 * so schedule a recheck.
44462306a36Sopenharmony_ci			 */
44562306a36Sopenharmony_ci			alua_check(sdev, true);
44662306a36Sopenharmony_ci			return ADD_TO_MLQUEUE;
44762306a36Sopenharmony_ci		}
44862306a36Sopenharmony_ci		if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x04)
44962306a36Sopenharmony_ci			/*
45062306a36Sopenharmony_ci			 * Device internal reset
45162306a36Sopenharmony_ci			 */
45262306a36Sopenharmony_ci			return ADD_TO_MLQUEUE;
45362306a36Sopenharmony_ci		if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x01)
45462306a36Sopenharmony_ci			/*
45562306a36Sopenharmony_ci			 * Mode Parameters Changed
45662306a36Sopenharmony_ci			 */
45762306a36Sopenharmony_ci			return ADD_TO_MLQUEUE;
45862306a36Sopenharmony_ci		if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
45962306a36Sopenharmony_ci			/*
46062306a36Sopenharmony_ci			 * ALUA state changed
46162306a36Sopenharmony_ci			 */
46262306a36Sopenharmony_ci			alua_check(sdev, true);
46362306a36Sopenharmony_ci			return ADD_TO_MLQUEUE;
46462306a36Sopenharmony_ci		}
46562306a36Sopenharmony_ci		if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
46662306a36Sopenharmony_ci			/*
46762306a36Sopenharmony_ci			 * Implicit ALUA state transition failed
46862306a36Sopenharmony_ci			 */
46962306a36Sopenharmony_ci			alua_check(sdev, true);
47062306a36Sopenharmony_ci			return ADD_TO_MLQUEUE;
47162306a36Sopenharmony_ci		}
47262306a36Sopenharmony_ci		if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x03)
47362306a36Sopenharmony_ci			/*
47462306a36Sopenharmony_ci			 * Inquiry data has changed
47562306a36Sopenharmony_ci			 */
47662306a36Sopenharmony_ci			return ADD_TO_MLQUEUE;
47762306a36Sopenharmony_ci		if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x0e)
47862306a36Sopenharmony_ci			/*
47962306a36Sopenharmony_ci			 * REPORTED_LUNS_DATA_HAS_CHANGED is reported
48062306a36Sopenharmony_ci			 * when switching controllers on targets like
48162306a36Sopenharmony_ci			 * Intel Multi-Flex. We can just retry.
48262306a36Sopenharmony_ci			 */
48362306a36Sopenharmony_ci			return ADD_TO_MLQUEUE;
48462306a36Sopenharmony_ci		break;
48562306a36Sopenharmony_ci	}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	return SCSI_RETURN_NOT_HANDLED;
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci/*
49162306a36Sopenharmony_ci * alua_tur - Send a TEST UNIT READY
49262306a36Sopenharmony_ci * @sdev: device to which the TEST UNIT READY command should be send
49362306a36Sopenharmony_ci *
49462306a36Sopenharmony_ci * Send a TEST UNIT READY to @sdev to figure out the device state
49562306a36Sopenharmony_ci * Returns SCSI_DH_RETRY if the sense code is NOT READY/ALUA TRANSITIONING,
49662306a36Sopenharmony_ci * SCSI_DH_OK if no error occurred, and SCSI_DH_IO otherwise.
49762306a36Sopenharmony_ci */
49862306a36Sopenharmony_cistatic int alua_tur(struct scsi_device *sdev)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	struct scsi_sense_hdr sense_hdr;
50162306a36Sopenharmony_ci	int retval;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	retval = scsi_test_unit_ready(sdev, ALUA_FAILOVER_TIMEOUT * HZ,
50462306a36Sopenharmony_ci				      ALUA_FAILOVER_RETRIES, &sense_hdr);
50562306a36Sopenharmony_ci	if (sense_hdr.sense_key == NOT_READY &&
50662306a36Sopenharmony_ci	    sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
50762306a36Sopenharmony_ci		return SCSI_DH_RETRY;
50862306a36Sopenharmony_ci	else if (retval)
50962306a36Sopenharmony_ci		return SCSI_DH_IO;
51062306a36Sopenharmony_ci	else
51162306a36Sopenharmony_ci		return SCSI_DH_OK;
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci/*
51562306a36Sopenharmony_ci * alua_rtpg - Evaluate REPORT TARGET GROUP STATES
51662306a36Sopenharmony_ci * @sdev: the device to be evaluated.
51762306a36Sopenharmony_ci *
51862306a36Sopenharmony_ci * Evaluate the Target Port Group State.
51962306a36Sopenharmony_ci * Returns SCSI_DH_DEV_OFFLINED if the path is
52062306a36Sopenharmony_ci * found to be unusable.
52162306a36Sopenharmony_ci */
52262306a36Sopenharmony_cistatic int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	struct scsi_sense_hdr sense_hdr;
52562306a36Sopenharmony_ci	struct alua_port_group *tmp_pg;
52662306a36Sopenharmony_ci	int len, k, off, bufflen = ALUA_RTPG_SIZE;
52762306a36Sopenharmony_ci	int group_id_old, state_old, pref_old, valid_states_old;
52862306a36Sopenharmony_ci	unsigned char *desc, *buff;
52962306a36Sopenharmony_ci	unsigned err;
53062306a36Sopenharmony_ci	int retval;
53162306a36Sopenharmony_ci	unsigned int tpg_desc_tbl_off;
53262306a36Sopenharmony_ci	unsigned char orig_transition_tmo;
53362306a36Sopenharmony_ci	unsigned long flags;
53462306a36Sopenharmony_ci	bool transitioning_sense = false;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	group_id_old = pg->group_id;
53762306a36Sopenharmony_ci	state_old = pg->state;
53862306a36Sopenharmony_ci	pref_old = pg->pref;
53962306a36Sopenharmony_ci	valid_states_old = pg->valid_states;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	if (!pg->expiry) {
54262306a36Sopenharmony_ci		unsigned long transition_tmo = ALUA_FAILOVER_TIMEOUT * HZ;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci		if (pg->transition_tmo)
54562306a36Sopenharmony_ci			transition_tmo = pg->transition_tmo * HZ;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		pg->expiry = round_jiffies_up(jiffies + transition_tmo);
54862306a36Sopenharmony_ci	}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	buff = kzalloc(bufflen, GFP_KERNEL);
55162306a36Sopenharmony_ci	if (!buff)
55262306a36Sopenharmony_ci		return SCSI_DH_DEV_TEMP_BUSY;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci retry:
55562306a36Sopenharmony_ci	err = 0;
55662306a36Sopenharmony_ci	retval = submit_rtpg(sdev, buff, bufflen, &sense_hdr, pg->flags);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	if (retval) {
55962306a36Sopenharmony_ci		/*
56062306a36Sopenharmony_ci		 * Some (broken) implementations have a habit of returning
56162306a36Sopenharmony_ci		 * an error during things like firmware update etc.
56262306a36Sopenharmony_ci		 * But if the target only supports active/optimized there's
56362306a36Sopenharmony_ci		 * not much we can do; it's not that we can switch paths
56462306a36Sopenharmony_ci		 * or anything.
56562306a36Sopenharmony_ci		 * So ignore any errors to avoid spurious failures during
56662306a36Sopenharmony_ci		 * path failover.
56762306a36Sopenharmony_ci		 */
56862306a36Sopenharmony_ci		if ((pg->valid_states & ~TPGS_SUPPORT_OPTIMIZED) == 0) {
56962306a36Sopenharmony_ci			sdev_printk(KERN_INFO, sdev,
57062306a36Sopenharmony_ci				    "%s: ignoring rtpg result %d\n",
57162306a36Sopenharmony_ci				    ALUA_DH_NAME, retval);
57262306a36Sopenharmony_ci			kfree(buff);
57362306a36Sopenharmony_ci			return SCSI_DH_OK;
57462306a36Sopenharmony_ci		}
57562306a36Sopenharmony_ci		if (retval < 0 || !scsi_sense_valid(&sense_hdr)) {
57662306a36Sopenharmony_ci			sdev_printk(KERN_INFO, sdev,
57762306a36Sopenharmony_ci				    "%s: rtpg failed, result %d\n",
57862306a36Sopenharmony_ci				    ALUA_DH_NAME, retval);
57962306a36Sopenharmony_ci			kfree(buff);
58062306a36Sopenharmony_ci			if (retval < 0)
58162306a36Sopenharmony_ci				return SCSI_DH_DEV_TEMP_BUSY;
58262306a36Sopenharmony_ci			if (host_byte(retval) == DID_NO_CONNECT)
58362306a36Sopenharmony_ci				return SCSI_DH_RES_TEMP_UNAVAIL;
58462306a36Sopenharmony_ci			return SCSI_DH_IO;
58562306a36Sopenharmony_ci		}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci		/*
58862306a36Sopenharmony_ci		 * submit_rtpg() has failed on existing arrays
58962306a36Sopenharmony_ci		 * when requesting extended header info, and
59062306a36Sopenharmony_ci		 * the array doesn't support extended headers,
59162306a36Sopenharmony_ci		 * even though it shouldn't according to T10.
59262306a36Sopenharmony_ci		 * The retry without rtpg_ext_hdr_req set
59362306a36Sopenharmony_ci		 * handles this.
59462306a36Sopenharmony_ci		 * Note:  some arrays return a sense key of ILLEGAL_REQUEST
59562306a36Sopenharmony_ci		 * with ASC 00h if they don't support the extended header.
59662306a36Sopenharmony_ci		 */
59762306a36Sopenharmony_ci		if (!(pg->flags & ALUA_RTPG_EXT_HDR_UNSUPP) &&
59862306a36Sopenharmony_ci		    sense_hdr.sense_key == ILLEGAL_REQUEST) {
59962306a36Sopenharmony_ci			pg->flags |= ALUA_RTPG_EXT_HDR_UNSUPP;
60062306a36Sopenharmony_ci			goto retry;
60162306a36Sopenharmony_ci		}
60262306a36Sopenharmony_ci		/*
60362306a36Sopenharmony_ci		 * If the array returns with 'ALUA state transition'
60462306a36Sopenharmony_ci		 * sense code here it cannot return RTPG data during
60562306a36Sopenharmony_ci		 * transition. So set the state to 'transitioning' directly.
60662306a36Sopenharmony_ci		 */
60762306a36Sopenharmony_ci		if (sense_hdr.sense_key == NOT_READY &&
60862306a36Sopenharmony_ci		    sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) {
60962306a36Sopenharmony_ci			transitioning_sense = true;
61062306a36Sopenharmony_ci			goto skip_rtpg;
61162306a36Sopenharmony_ci		}
61262306a36Sopenharmony_ci		/*
61362306a36Sopenharmony_ci		 * Retry on any other UNIT ATTENTION occurred.
61462306a36Sopenharmony_ci		 */
61562306a36Sopenharmony_ci		if (sense_hdr.sense_key == UNIT_ATTENTION)
61662306a36Sopenharmony_ci			err = SCSI_DH_RETRY;
61762306a36Sopenharmony_ci		if (err == SCSI_DH_RETRY &&
61862306a36Sopenharmony_ci		    pg->expiry != 0 && time_before(jiffies, pg->expiry)) {
61962306a36Sopenharmony_ci			sdev_printk(KERN_ERR, sdev, "%s: rtpg retry\n",
62062306a36Sopenharmony_ci				    ALUA_DH_NAME);
62162306a36Sopenharmony_ci			scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
62262306a36Sopenharmony_ci			kfree(buff);
62362306a36Sopenharmony_ci			return err;
62462306a36Sopenharmony_ci		}
62562306a36Sopenharmony_ci		sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n",
62662306a36Sopenharmony_ci			    ALUA_DH_NAME);
62762306a36Sopenharmony_ci		scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
62862306a36Sopenharmony_ci		kfree(buff);
62962306a36Sopenharmony_ci		pg->expiry = 0;
63062306a36Sopenharmony_ci		return SCSI_DH_IO;
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	len = get_unaligned_be32(&buff[0]) + 4;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	if (len > bufflen) {
63662306a36Sopenharmony_ci		/* Resubmit with the correct length */
63762306a36Sopenharmony_ci		kfree(buff);
63862306a36Sopenharmony_ci		bufflen = len;
63962306a36Sopenharmony_ci		buff = kmalloc(bufflen, GFP_KERNEL);
64062306a36Sopenharmony_ci		if (!buff) {
64162306a36Sopenharmony_ci			sdev_printk(KERN_WARNING, sdev,
64262306a36Sopenharmony_ci				    "%s: kmalloc buffer failed\n",__func__);
64362306a36Sopenharmony_ci			/* Temporary failure, bypass */
64462306a36Sopenharmony_ci			pg->expiry = 0;
64562306a36Sopenharmony_ci			return SCSI_DH_DEV_TEMP_BUSY;
64662306a36Sopenharmony_ci		}
64762306a36Sopenharmony_ci		goto retry;
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	orig_transition_tmo = pg->transition_tmo;
65162306a36Sopenharmony_ci	if ((buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR && buff[5] != 0)
65262306a36Sopenharmony_ci		pg->transition_tmo = buff[5];
65362306a36Sopenharmony_ci	else
65462306a36Sopenharmony_ci		pg->transition_tmo = ALUA_FAILOVER_TIMEOUT;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	if (orig_transition_tmo != pg->transition_tmo) {
65762306a36Sopenharmony_ci		sdev_printk(KERN_INFO, sdev,
65862306a36Sopenharmony_ci			    "%s: transition timeout set to %d seconds\n",
65962306a36Sopenharmony_ci			    ALUA_DH_NAME, pg->transition_tmo);
66062306a36Sopenharmony_ci		pg->expiry = jiffies + pg->transition_tmo * HZ;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	if ((buff[4] & RTPG_FMT_MASK) == RTPG_FMT_EXT_HDR)
66462306a36Sopenharmony_ci		tpg_desc_tbl_off = 8;
66562306a36Sopenharmony_ci	else
66662306a36Sopenharmony_ci		tpg_desc_tbl_off = 4;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	for (k = tpg_desc_tbl_off, desc = buff + tpg_desc_tbl_off;
66962306a36Sopenharmony_ci	     k < len;
67062306a36Sopenharmony_ci	     k += off, desc += off) {
67162306a36Sopenharmony_ci		u16 group_id = get_unaligned_be16(&desc[2]);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci		spin_lock_irqsave(&port_group_lock, flags);
67462306a36Sopenharmony_ci		tmp_pg = alua_find_get_pg(pg->device_id_str, pg->device_id_len,
67562306a36Sopenharmony_ci					  group_id);
67662306a36Sopenharmony_ci		spin_unlock_irqrestore(&port_group_lock, flags);
67762306a36Sopenharmony_ci		if (tmp_pg) {
67862306a36Sopenharmony_ci			if (spin_trylock_irqsave(&tmp_pg->lock, flags)) {
67962306a36Sopenharmony_ci				if ((tmp_pg == pg) ||
68062306a36Sopenharmony_ci				    !(tmp_pg->flags & ALUA_PG_RUNNING)) {
68162306a36Sopenharmony_ci					struct alua_dh_data *h;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci					tmp_pg->state = desc[0] & 0x0f;
68462306a36Sopenharmony_ci					tmp_pg->pref = desc[0] >> 7;
68562306a36Sopenharmony_ci					rcu_read_lock();
68662306a36Sopenharmony_ci					list_for_each_entry_rcu(h,
68762306a36Sopenharmony_ci						&tmp_pg->dh_list, node) {
68862306a36Sopenharmony_ci						if (!h->sdev)
68962306a36Sopenharmony_ci							continue;
69062306a36Sopenharmony_ci						h->sdev->access_state = desc[0];
69162306a36Sopenharmony_ci					}
69262306a36Sopenharmony_ci					rcu_read_unlock();
69362306a36Sopenharmony_ci				}
69462306a36Sopenharmony_ci				if (tmp_pg == pg)
69562306a36Sopenharmony_ci					tmp_pg->valid_states = desc[1];
69662306a36Sopenharmony_ci				spin_unlock_irqrestore(&tmp_pg->lock, flags);
69762306a36Sopenharmony_ci			}
69862306a36Sopenharmony_ci			kref_put(&tmp_pg->kref, release_port_group);
69962306a36Sopenharmony_ci		}
70062306a36Sopenharmony_ci		off = 8 + (desc[7] * 4);
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci skip_rtpg:
70462306a36Sopenharmony_ci	spin_lock_irqsave(&pg->lock, flags);
70562306a36Sopenharmony_ci	if (transitioning_sense)
70662306a36Sopenharmony_ci		pg->state = SCSI_ACCESS_STATE_TRANSITIONING;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	if (group_id_old != pg->group_id || state_old != pg->state ||
70962306a36Sopenharmony_ci		pref_old != pg->pref || valid_states_old != pg->valid_states)
71062306a36Sopenharmony_ci		sdev_printk(KERN_INFO, sdev,
71162306a36Sopenharmony_ci			"%s: port group %02x state %c %s supports %c%c%c%c%c%c%c\n",
71262306a36Sopenharmony_ci			ALUA_DH_NAME, pg->group_id, print_alua_state(pg->state),
71362306a36Sopenharmony_ci			pg->pref ? "preferred" : "non-preferred",
71462306a36Sopenharmony_ci			pg->valid_states&TPGS_SUPPORT_TRANSITION?'T':'t',
71562306a36Sopenharmony_ci			pg->valid_states&TPGS_SUPPORT_OFFLINE?'O':'o',
71662306a36Sopenharmony_ci			pg->valid_states&TPGS_SUPPORT_LBA_DEPENDENT?'L':'l',
71762306a36Sopenharmony_ci			pg->valid_states&TPGS_SUPPORT_UNAVAILABLE?'U':'u',
71862306a36Sopenharmony_ci			pg->valid_states&TPGS_SUPPORT_STANDBY?'S':'s',
71962306a36Sopenharmony_ci			pg->valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n',
72062306a36Sopenharmony_ci			pg->valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a');
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	switch (pg->state) {
72362306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_TRANSITIONING:
72462306a36Sopenharmony_ci		if (time_before(jiffies, pg->expiry)) {
72562306a36Sopenharmony_ci			/* State transition, retry */
72662306a36Sopenharmony_ci			pg->interval = ALUA_RTPG_RETRY_DELAY;
72762306a36Sopenharmony_ci			err = SCSI_DH_RETRY;
72862306a36Sopenharmony_ci		} else {
72962306a36Sopenharmony_ci			struct alua_dh_data *h;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci			/* Transitioning time exceeded, set port to standby */
73262306a36Sopenharmony_ci			err = SCSI_DH_IO;
73362306a36Sopenharmony_ci			pg->state = SCSI_ACCESS_STATE_STANDBY;
73462306a36Sopenharmony_ci			pg->expiry = 0;
73562306a36Sopenharmony_ci			rcu_read_lock();
73662306a36Sopenharmony_ci			list_for_each_entry_rcu(h, &pg->dh_list, node) {
73762306a36Sopenharmony_ci				if (!h->sdev)
73862306a36Sopenharmony_ci					continue;
73962306a36Sopenharmony_ci				h->sdev->access_state =
74062306a36Sopenharmony_ci					(pg->state & SCSI_ACCESS_STATE_MASK);
74162306a36Sopenharmony_ci				if (pg->pref)
74262306a36Sopenharmony_ci					h->sdev->access_state |=
74362306a36Sopenharmony_ci						SCSI_ACCESS_STATE_PREFERRED;
74462306a36Sopenharmony_ci			}
74562306a36Sopenharmony_ci			rcu_read_unlock();
74662306a36Sopenharmony_ci		}
74762306a36Sopenharmony_ci		break;
74862306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_OFFLINE:
74962306a36Sopenharmony_ci		/* Path unusable */
75062306a36Sopenharmony_ci		err = SCSI_DH_DEV_OFFLINED;
75162306a36Sopenharmony_ci		pg->expiry = 0;
75262306a36Sopenharmony_ci		break;
75362306a36Sopenharmony_ci	default:
75462306a36Sopenharmony_ci		/* Useable path if active */
75562306a36Sopenharmony_ci		err = SCSI_DH_OK;
75662306a36Sopenharmony_ci		pg->expiry = 0;
75762306a36Sopenharmony_ci		break;
75862306a36Sopenharmony_ci	}
75962306a36Sopenharmony_ci	spin_unlock_irqrestore(&pg->lock, flags);
76062306a36Sopenharmony_ci	kfree(buff);
76162306a36Sopenharmony_ci	return err;
76262306a36Sopenharmony_ci}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci/*
76562306a36Sopenharmony_ci * alua_stpg - Issue a SET TARGET PORT GROUP command
76662306a36Sopenharmony_ci *
76762306a36Sopenharmony_ci * Issue a SET TARGET PORT GROUP command and evaluate the
76862306a36Sopenharmony_ci * response. Returns SCSI_DH_RETRY per default to trigger
76962306a36Sopenharmony_ci * a re-evaluation of the target group state or SCSI_DH_OK
77062306a36Sopenharmony_ci * if no further action needs to be taken.
77162306a36Sopenharmony_ci */
77262306a36Sopenharmony_cistatic unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
77362306a36Sopenharmony_ci{
77462306a36Sopenharmony_ci	int retval;
77562306a36Sopenharmony_ci	struct scsi_sense_hdr sense_hdr;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	if (!(pg->tpgs & TPGS_MODE_EXPLICIT)) {
77862306a36Sopenharmony_ci		/* Only implicit ALUA supported, retry */
77962306a36Sopenharmony_ci		return SCSI_DH_RETRY;
78062306a36Sopenharmony_ci	}
78162306a36Sopenharmony_ci	switch (pg->state) {
78262306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_OPTIMAL:
78362306a36Sopenharmony_ci		return SCSI_DH_OK;
78462306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_ACTIVE:
78562306a36Sopenharmony_ci		if ((pg->flags & ALUA_OPTIMIZE_STPG) &&
78662306a36Sopenharmony_ci		    !pg->pref &&
78762306a36Sopenharmony_ci		    (pg->tpgs & TPGS_MODE_IMPLICIT))
78862306a36Sopenharmony_ci			return SCSI_DH_OK;
78962306a36Sopenharmony_ci		break;
79062306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_STANDBY:
79162306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_UNAVAILABLE:
79262306a36Sopenharmony_ci		break;
79362306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_OFFLINE:
79462306a36Sopenharmony_ci		return SCSI_DH_IO;
79562306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_TRANSITIONING:
79662306a36Sopenharmony_ci		break;
79762306a36Sopenharmony_ci	default:
79862306a36Sopenharmony_ci		sdev_printk(KERN_INFO, sdev,
79962306a36Sopenharmony_ci			    "%s: stpg failed, unhandled TPGS state %d",
80062306a36Sopenharmony_ci			    ALUA_DH_NAME, pg->state);
80162306a36Sopenharmony_ci		return SCSI_DH_NOSYS;
80262306a36Sopenharmony_ci	}
80362306a36Sopenharmony_ci	retval = submit_stpg(sdev, pg->group_id, &sense_hdr);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	if (retval) {
80662306a36Sopenharmony_ci		if (retval < 0 || !scsi_sense_valid(&sense_hdr)) {
80762306a36Sopenharmony_ci			sdev_printk(KERN_INFO, sdev,
80862306a36Sopenharmony_ci				    "%s: stpg failed, result %d",
80962306a36Sopenharmony_ci				    ALUA_DH_NAME, retval);
81062306a36Sopenharmony_ci			if (retval < 0)
81162306a36Sopenharmony_ci				return SCSI_DH_DEV_TEMP_BUSY;
81262306a36Sopenharmony_ci		} else {
81362306a36Sopenharmony_ci			sdev_printk(KERN_INFO, sdev, "%s: stpg failed\n",
81462306a36Sopenharmony_ci				    ALUA_DH_NAME);
81562306a36Sopenharmony_ci			scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
81662306a36Sopenharmony_ci		}
81762306a36Sopenharmony_ci	}
81862306a36Sopenharmony_ci	/* Retry RTPG */
81962306a36Sopenharmony_ci	return SCSI_DH_RETRY;
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci/*
82362306a36Sopenharmony_ci * The caller must call scsi_device_put() on the returned pointer if it is not
82462306a36Sopenharmony_ci * NULL.
82562306a36Sopenharmony_ci */
82662306a36Sopenharmony_cistatic struct scsi_device * __must_check
82762306a36Sopenharmony_cialua_rtpg_select_sdev(struct alua_port_group *pg)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	struct alua_dh_data *h;
83062306a36Sopenharmony_ci	struct scsi_device *sdev = NULL, *prev_sdev;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	lockdep_assert_held(&pg->lock);
83362306a36Sopenharmony_ci	if (WARN_ON(!pg->rtpg_sdev))
83462306a36Sopenharmony_ci		return NULL;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	/*
83762306a36Sopenharmony_ci	 * RCU protection isn't necessary for dh_list here
83862306a36Sopenharmony_ci	 * as we hold pg->lock, but for access to h->pg.
83962306a36Sopenharmony_ci	 */
84062306a36Sopenharmony_ci	rcu_read_lock();
84162306a36Sopenharmony_ci	list_for_each_entry_rcu(h, &pg->dh_list, node) {
84262306a36Sopenharmony_ci		if (!h->sdev)
84362306a36Sopenharmony_ci			continue;
84462306a36Sopenharmony_ci		if (h->sdev == pg->rtpg_sdev) {
84562306a36Sopenharmony_ci			h->disabled = true;
84662306a36Sopenharmony_ci			continue;
84762306a36Sopenharmony_ci		}
84862306a36Sopenharmony_ci		if (rcu_dereference(h->pg) == pg &&
84962306a36Sopenharmony_ci		    !h->disabled &&
85062306a36Sopenharmony_ci		    !scsi_device_get(h->sdev)) {
85162306a36Sopenharmony_ci			sdev = h->sdev;
85262306a36Sopenharmony_ci			break;
85362306a36Sopenharmony_ci		}
85462306a36Sopenharmony_ci	}
85562306a36Sopenharmony_ci	rcu_read_unlock();
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	if (!sdev) {
85862306a36Sopenharmony_ci		pr_warn("%s: no device found for rtpg\n",
85962306a36Sopenharmony_ci			(pg->device_id_len ?
86062306a36Sopenharmony_ci			 (char *)pg->device_id_str : "(nameless PG)"));
86162306a36Sopenharmony_ci		return NULL;
86262306a36Sopenharmony_ci	}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	sdev_printk(KERN_INFO, sdev, "rtpg retry on different device\n");
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	prev_sdev = pg->rtpg_sdev;
86762306a36Sopenharmony_ci	pg->rtpg_sdev = sdev;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	return prev_sdev;
87062306a36Sopenharmony_ci}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_cistatic void alua_rtpg_work(struct work_struct *work)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	struct alua_port_group *pg =
87562306a36Sopenharmony_ci		container_of(work, struct alua_port_group, rtpg_work.work);
87662306a36Sopenharmony_ci	struct scsi_device *sdev, *prev_sdev = NULL;
87762306a36Sopenharmony_ci	LIST_HEAD(qdata_list);
87862306a36Sopenharmony_ci	int err = SCSI_DH_OK;
87962306a36Sopenharmony_ci	struct alua_queue_data *qdata, *tmp;
88062306a36Sopenharmony_ci	struct alua_dh_data *h;
88162306a36Sopenharmony_ci	unsigned long flags;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	spin_lock_irqsave(&pg->lock, flags);
88462306a36Sopenharmony_ci	sdev = pg->rtpg_sdev;
88562306a36Sopenharmony_ci	if (!sdev) {
88662306a36Sopenharmony_ci		WARN_ON(pg->flags & ALUA_PG_RUN_RTPG);
88762306a36Sopenharmony_ci		WARN_ON(pg->flags & ALUA_PG_RUN_STPG);
88862306a36Sopenharmony_ci		spin_unlock_irqrestore(&pg->lock, flags);
88962306a36Sopenharmony_ci		kref_put(&pg->kref, release_port_group);
89062306a36Sopenharmony_ci		return;
89162306a36Sopenharmony_ci	}
89262306a36Sopenharmony_ci	pg->flags |= ALUA_PG_RUNNING;
89362306a36Sopenharmony_ci	if (pg->flags & ALUA_PG_RUN_RTPG) {
89462306a36Sopenharmony_ci		int state = pg->state;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci		pg->flags &= ~ALUA_PG_RUN_RTPG;
89762306a36Sopenharmony_ci		spin_unlock_irqrestore(&pg->lock, flags);
89862306a36Sopenharmony_ci		if (state == SCSI_ACCESS_STATE_TRANSITIONING) {
89962306a36Sopenharmony_ci			if (alua_tur(sdev) == SCSI_DH_RETRY) {
90062306a36Sopenharmony_ci				spin_lock_irqsave(&pg->lock, flags);
90162306a36Sopenharmony_ci				pg->flags &= ~ALUA_PG_RUNNING;
90262306a36Sopenharmony_ci				pg->flags |= ALUA_PG_RUN_RTPG;
90362306a36Sopenharmony_ci				if (!pg->interval)
90462306a36Sopenharmony_ci					pg->interval = ALUA_RTPG_RETRY_DELAY;
90562306a36Sopenharmony_ci				spin_unlock_irqrestore(&pg->lock, flags);
90662306a36Sopenharmony_ci				queue_delayed_work(kaluad_wq, &pg->rtpg_work,
90762306a36Sopenharmony_ci						   pg->interval * HZ);
90862306a36Sopenharmony_ci				return;
90962306a36Sopenharmony_ci			}
91062306a36Sopenharmony_ci			/* Send RTPG on failure or if TUR indicates SUCCESS */
91162306a36Sopenharmony_ci		}
91262306a36Sopenharmony_ci		err = alua_rtpg(sdev, pg);
91362306a36Sopenharmony_ci		spin_lock_irqsave(&pg->lock, flags);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci		/* If RTPG failed on the current device, try using another */
91662306a36Sopenharmony_ci		if (err == SCSI_DH_RES_TEMP_UNAVAIL &&
91762306a36Sopenharmony_ci		    (prev_sdev = alua_rtpg_select_sdev(pg)))
91862306a36Sopenharmony_ci			err = SCSI_DH_IMM_RETRY;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci		if (err == SCSI_DH_RETRY || err == SCSI_DH_IMM_RETRY ||
92162306a36Sopenharmony_ci		    pg->flags & ALUA_PG_RUN_RTPG) {
92262306a36Sopenharmony_ci			pg->flags &= ~ALUA_PG_RUNNING;
92362306a36Sopenharmony_ci			if (err == SCSI_DH_IMM_RETRY)
92462306a36Sopenharmony_ci				pg->interval = 0;
92562306a36Sopenharmony_ci			else if (!pg->interval && !(pg->flags & ALUA_PG_RUN_RTPG))
92662306a36Sopenharmony_ci				pg->interval = ALUA_RTPG_RETRY_DELAY;
92762306a36Sopenharmony_ci			pg->flags |= ALUA_PG_RUN_RTPG;
92862306a36Sopenharmony_ci			spin_unlock_irqrestore(&pg->lock, flags);
92962306a36Sopenharmony_ci			goto queue_rtpg;
93062306a36Sopenharmony_ci		}
93162306a36Sopenharmony_ci		if (err != SCSI_DH_OK)
93262306a36Sopenharmony_ci			pg->flags &= ~ALUA_PG_RUN_STPG;
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci	if (pg->flags & ALUA_PG_RUN_STPG) {
93562306a36Sopenharmony_ci		pg->flags &= ~ALUA_PG_RUN_STPG;
93662306a36Sopenharmony_ci		spin_unlock_irqrestore(&pg->lock, flags);
93762306a36Sopenharmony_ci		err = alua_stpg(sdev, pg);
93862306a36Sopenharmony_ci		spin_lock_irqsave(&pg->lock, flags);
93962306a36Sopenharmony_ci		if (err == SCSI_DH_RETRY || pg->flags & ALUA_PG_RUN_RTPG) {
94062306a36Sopenharmony_ci			pg->flags |= ALUA_PG_RUN_RTPG;
94162306a36Sopenharmony_ci			pg->interval = 0;
94262306a36Sopenharmony_ci			pg->flags &= ~ALUA_PG_RUNNING;
94362306a36Sopenharmony_ci			spin_unlock_irqrestore(&pg->lock, flags);
94462306a36Sopenharmony_ci			goto queue_rtpg;
94562306a36Sopenharmony_ci		}
94662306a36Sopenharmony_ci	}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	list_splice_init(&pg->rtpg_list, &qdata_list);
94962306a36Sopenharmony_ci	/*
95062306a36Sopenharmony_ci	 * We went through an RTPG, for good or bad.
95162306a36Sopenharmony_ci	 * Re-enable all devices for the next attempt.
95262306a36Sopenharmony_ci	 */
95362306a36Sopenharmony_ci	list_for_each_entry(h, &pg->dh_list, node)
95462306a36Sopenharmony_ci		h->disabled = false;
95562306a36Sopenharmony_ci	pg->rtpg_sdev = NULL;
95662306a36Sopenharmony_ci	spin_unlock_irqrestore(&pg->lock, flags);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	if (prev_sdev)
95962306a36Sopenharmony_ci		scsi_device_put(prev_sdev);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	list_for_each_entry_safe(qdata, tmp, &qdata_list, entry) {
96262306a36Sopenharmony_ci		list_del(&qdata->entry);
96362306a36Sopenharmony_ci		if (qdata->callback_fn)
96462306a36Sopenharmony_ci			qdata->callback_fn(qdata->callback_data, err);
96562306a36Sopenharmony_ci		kfree(qdata);
96662306a36Sopenharmony_ci	}
96762306a36Sopenharmony_ci	spin_lock_irqsave(&pg->lock, flags);
96862306a36Sopenharmony_ci	pg->flags &= ~ALUA_PG_RUNNING;
96962306a36Sopenharmony_ci	spin_unlock_irqrestore(&pg->lock, flags);
97062306a36Sopenharmony_ci	scsi_device_put(sdev);
97162306a36Sopenharmony_ci	kref_put(&pg->kref, release_port_group);
97262306a36Sopenharmony_ci	return;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ciqueue_rtpg:
97562306a36Sopenharmony_ci	if (prev_sdev)
97662306a36Sopenharmony_ci		scsi_device_put(prev_sdev);
97762306a36Sopenharmony_ci	queue_delayed_work(kaluad_wq, &pg->rtpg_work, pg->interval * HZ);
97862306a36Sopenharmony_ci}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci/**
98162306a36Sopenharmony_ci * alua_rtpg_queue() - cause RTPG to be submitted asynchronously
98262306a36Sopenharmony_ci * @pg: ALUA port group associated with @sdev.
98362306a36Sopenharmony_ci * @sdev: SCSI device for which to submit an RTPG.
98462306a36Sopenharmony_ci * @qdata: Information about the callback to invoke after the RTPG.
98562306a36Sopenharmony_ci * @force: Whether or not to submit an RTPG if a work item that will submit an
98662306a36Sopenharmony_ci *         RTPG already has been scheduled.
98762306a36Sopenharmony_ci *
98862306a36Sopenharmony_ci * Returns true if and only if alua_rtpg_work() will be called asynchronously.
98962306a36Sopenharmony_ci * That function is responsible for calling @qdata->fn().
99062306a36Sopenharmony_ci *
99162306a36Sopenharmony_ci * Context: may be called from atomic context (alua_check()) only if the caller
99262306a36Sopenharmony_ci *	holds an sdev reference.
99362306a36Sopenharmony_ci */
99462306a36Sopenharmony_cistatic bool alua_rtpg_queue(struct alua_port_group *pg,
99562306a36Sopenharmony_ci			    struct scsi_device *sdev,
99662306a36Sopenharmony_ci			    struct alua_queue_data *qdata, bool force)
99762306a36Sopenharmony_ci{
99862306a36Sopenharmony_ci	int start_queue = 0;
99962306a36Sopenharmony_ci	unsigned long flags;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	if (WARN_ON_ONCE(!pg) || scsi_device_get(sdev))
100262306a36Sopenharmony_ci		return false;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	spin_lock_irqsave(&pg->lock, flags);
100562306a36Sopenharmony_ci	if (qdata) {
100662306a36Sopenharmony_ci		list_add_tail(&qdata->entry, &pg->rtpg_list);
100762306a36Sopenharmony_ci		pg->flags |= ALUA_PG_RUN_STPG;
100862306a36Sopenharmony_ci		force = true;
100962306a36Sopenharmony_ci	}
101062306a36Sopenharmony_ci	if (pg->rtpg_sdev == NULL) {
101162306a36Sopenharmony_ci		struct alua_dh_data *h = sdev->handler_data;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci		rcu_read_lock();
101462306a36Sopenharmony_ci		if (h && rcu_dereference(h->pg) == pg) {
101562306a36Sopenharmony_ci			pg->interval = 0;
101662306a36Sopenharmony_ci			pg->flags |= ALUA_PG_RUN_RTPG;
101762306a36Sopenharmony_ci			kref_get(&pg->kref);
101862306a36Sopenharmony_ci			pg->rtpg_sdev = sdev;
101962306a36Sopenharmony_ci			start_queue = 1;
102062306a36Sopenharmony_ci		}
102162306a36Sopenharmony_ci		rcu_read_unlock();
102262306a36Sopenharmony_ci	} else if (!(pg->flags & ALUA_PG_RUN_RTPG) && force) {
102362306a36Sopenharmony_ci		pg->flags |= ALUA_PG_RUN_RTPG;
102462306a36Sopenharmony_ci		/* Do not queue if the worker is already running */
102562306a36Sopenharmony_ci		if (!(pg->flags & ALUA_PG_RUNNING)) {
102662306a36Sopenharmony_ci			kref_get(&pg->kref);
102762306a36Sopenharmony_ci			start_queue = 1;
102862306a36Sopenharmony_ci		}
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	spin_unlock_irqrestore(&pg->lock, flags);
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	if (start_queue) {
103462306a36Sopenharmony_ci		if (queue_delayed_work(kaluad_wq, &pg->rtpg_work,
103562306a36Sopenharmony_ci				msecs_to_jiffies(ALUA_RTPG_DELAY_MSECS)))
103662306a36Sopenharmony_ci			sdev = NULL;
103762306a36Sopenharmony_ci		else
103862306a36Sopenharmony_ci			kref_put(&pg->kref, release_port_group);
103962306a36Sopenharmony_ci	}
104062306a36Sopenharmony_ci	if (sdev)
104162306a36Sopenharmony_ci		scsi_device_put(sdev);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	return true;
104462306a36Sopenharmony_ci}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci/*
104762306a36Sopenharmony_ci * alua_initialize - Initialize ALUA state
104862306a36Sopenharmony_ci * @sdev: the device to be initialized
104962306a36Sopenharmony_ci *
105062306a36Sopenharmony_ci * For the prep_fn to work correctly we have
105162306a36Sopenharmony_ci * to initialize the ALUA state for the device.
105262306a36Sopenharmony_ci */
105362306a36Sopenharmony_cistatic int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	int err = SCSI_DH_DEV_UNSUPP, tpgs;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	mutex_lock(&h->init_mutex);
105862306a36Sopenharmony_ci	h->disabled = false;
105962306a36Sopenharmony_ci	tpgs = alua_check_tpgs(sdev);
106062306a36Sopenharmony_ci	if (tpgs != TPGS_MODE_NONE)
106162306a36Sopenharmony_ci		err = alua_check_vpd(sdev, h, tpgs);
106262306a36Sopenharmony_ci	h->init_error = err;
106362306a36Sopenharmony_ci	mutex_unlock(&h->init_mutex);
106462306a36Sopenharmony_ci	return err;
106562306a36Sopenharmony_ci}
106662306a36Sopenharmony_ci/*
106762306a36Sopenharmony_ci * alua_set_params - set/unset the optimize flag
106862306a36Sopenharmony_ci * @sdev: device on the path to be activated
106962306a36Sopenharmony_ci * params - parameters in the following format
107062306a36Sopenharmony_ci *      "no_of_params\0param1\0param2\0param3\0...\0"
107162306a36Sopenharmony_ci * For example, to set the flag pass the following parameters
107262306a36Sopenharmony_ci * from multipath.conf
107362306a36Sopenharmony_ci *     hardware_handler        "2 alua 1"
107462306a36Sopenharmony_ci */
107562306a36Sopenharmony_cistatic int alua_set_params(struct scsi_device *sdev, const char *params)
107662306a36Sopenharmony_ci{
107762306a36Sopenharmony_ci	struct alua_dh_data *h = sdev->handler_data;
107862306a36Sopenharmony_ci	struct alua_port_group *pg = NULL;
107962306a36Sopenharmony_ci	unsigned int optimize = 0, argc;
108062306a36Sopenharmony_ci	const char *p = params;
108162306a36Sopenharmony_ci	int result = SCSI_DH_OK;
108262306a36Sopenharmony_ci	unsigned long flags;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	if ((sscanf(params, "%u", &argc) != 1) || (argc != 1))
108562306a36Sopenharmony_ci		return -EINVAL;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	while (*p++)
108862306a36Sopenharmony_ci		;
108962306a36Sopenharmony_ci	if ((sscanf(p, "%u", &optimize) != 1) || (optimize > 1))
109062306a36Sopenharmony_ci		return -EINVAL;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	rcu_read_lock();
109362306a36Sopenharmony_ci	pg = rcu_dereference(h->pg);
109462306a36Sopenharmony_ci	if (!pg) {
109562306a36Sopenharmony_ci		rcu_read_unlock();
109662306a36Sopenharmony_ci		return -ENXIO;
109762306a36Sopenharmony_ci	}
109862306a36Sopenharmony_ci	spin_lock_irqsave(&pg->lock, flags);
109962306a36Sopenharmony_ci	if (optimize)
110062306a36Sopenharmony_ci		pg->flags |= ALUA_OPTIMIZE_STPG;
110162306a36Sopenharmony_ci	else
110262306a36Sopenharmony_ci		pg->flags &= ~ALUA_OPTIMIZE_STPG;
110362306a36Sopenharmony_ci	spin_unlock_irqrestore(&pg->lock, flags);
110462306a36Sopenharmony_ci	rcu_read_unlock();
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	return result;
110762306a36Sopenharmony_ci}
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci/*
111062306a36Sopenharmony_ci * alua_activate - activate a path
111162306a36Sopenharmony_ci * @sdev: device on the path to be activated
111262306a36Sopenharmony_ci *
111362306a36Sopenharmony_ci * We're currently switching the port group to be activated only and
111462306a36Sopenharmony_ci * let the array figure out the rest.
111562306a36Sopenharmony_ci * There may be other arrays which require us to switch all port groups
111662306a36Sopenharmony_ci * based on a certain policy. But until we actually encounter them it
111762306a36Sopenharmony_ci * should be okay.
111862306a36Sopenharmony_ci */
111962306a36Sopenharmony_cistatic int alua_activate(struct scsi_device *sdev,
112062306a36Sopenharmony_ci			activate_complete fn, void *data)
112162306a36Sopenharmony_ci{
112262306a36Sopenharmony_ci	struct alua_dh_data *h = sdev->handler_data;
112362306a36Sopenharmony_ci	int err = SCSI_DH_OK;
112462306a36Sopenharmony_ci	struct alua_queue_data *qdata;
112562306a36Sopenharmony_ci	struct alua_port_group *pg;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	qdata = kzalloc(sizeof(*qdata), GFP_KERNEL);
112862306a36Sopenharmony_ci	if (!qdata) {
112962306a36Sopenharmony_ci		err = SCSI_DH_RES_TEMP_UNAVAIL;
113062306a36Sopenharmony_ci		goto out;
113162306a36Sopenharmony_ci	}
113262306a36Sopenharmony_ci	qdata->callback_fn = fn;
113362306a36Sopenharmony_ci	qdata->callback_data = data;
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	mutex_lock(&h->init_mutex);
113662306a36Sopenharmony_ci	rcu_read_lock();
113762306a36Sopenharmony_ci	pg = rcu_dereference(h->pg);
113862306a36Sopenharmony_ci	if (!pg || !kref_get_unless_zero(&pg->kref)) {
113962306a36Sopenharmony_ci		rcu_read_unlock();
114062306a36Sopenharmony_ci		kfree(qdata);
114162306a36Sopenharmony_ci		err = h->init_error;
114262306a36Sopenharmony_ci		mutex_unlock(&h->init_mutex);
114362306a36Sopenharmony_ci		goto out;
114462306a36Sopenharmony_ci	}
114562306a36Sopenharmony_ci	rcu_read_unlock();
114662306a36Sopenharmony_ci	mutex_unlock(&h->init_mutex);
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	if (alua_rtpg_queue(pg, sdev, qdata, true)) {
114962306a36Sopenharmony_ci		fn = NULL;
115062306a36Sopenharmony_ci	} else {
115162306a36Sopenharmony_ci		kfree(qdata);
115262306a36Sopenharmony_ci		err = SCSI_DH_DEV_OFFLINED;
115362306a36Sopenharmony_ci	}
115462306a36Sopenharmony_ci	kref_put(&pg->kref, release_port_group);
115562306a36Sopenharmony_ciout:
115662306a36Sopenharmony_ci	if (fn)
115762306a36Sopenharmony_ci		fn(data, err);
115862306a36Sopenharmony_ci	return 0;
115962306a36Sopenharmony_ci}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci/*
116262306a36Sopenharmony_ci * alua_check - check path status
116362306a36Sopenharmony_ci * @sdev: device on the path to be checked
116462306a36Sopenharmony_ci *
116562306a36Sopenharmony_ci * Check the device status
116662306a36Sopenharmony_ci */
116762306a36Sopenharmony_cistatic void alua_check(struct scsi_device *sdev, bool force)
116862306a36Sopenharmony_ci{
116962306a36Sopenharmony_ci	struct alua_dh_data *h = sdev->handler_data;
117062306a36Sopenharmony_ci	struct alua_port_group *pg;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	rcu_read_lock();
117362306a36Sopenharmony_ci	pg = rcu_dereference(h->pg);
117462306a36Sopenharmony_ci	if (!pg || !kref_get_unless_zero(&pg->kref)) {
117562306a36Sopenharmony_ci		rcu_read_unlock();
117662306a36Sopenharmony_ci		return;
117762306a36Sopenharmony_ci	}
117862306a36Sopenharmony_ci	rcu_read_unlock();
117962306a36Sopenharmony_ci	alua_rtpg_queue(pg, sdev, NULL, force);
118062306a36Sopenharmony_ci	kref_put(&pg->kref, release_port_group);
118162306a36Sopenharmony_ci}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci/*
118462306a36Sopenharmony_ci * alua_prep_fn - request callback
118562306a36Sopenharmony_ci *
118662306a36Sopenharmony_ci * Fail I/O to all paths not in state
118762306a36Sopenharmony_ci * active/optimized or active/non-optimized.
118862306a36Sopenharmony_ci */
118962306a36Sopenharmony_cistatic blk_status_t alua_prep_fn(struct scsi_device *sdev, struct request *req)
119062306a36Sopenharmony_ci{
119162306a36Sopenharmony_ci	struct alua_dh_data *h = sdev->handler_data;
119262306a36Sopenharmony_ci	struct alua_port_group *pg;
119362306a36Sopenharmony_ci	unsigned char state = SCSI_ACCESS_STATE_OPTIMAL;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	rcu_read_lock();
119662306a36Sopenharmony_ci	pg = rcu_dereference(h->pg);
119762306a36Sopenharmony_ci	if (pg)
119862306a36Sopenharmony_ci		state = pg->state;
119962306a36Sopenharmony_ci	rcu_read_unlock();
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	switch (state) {
120262306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_OPTIMAL:
120362306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_ACTIVE:
120462306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_LBA:
120562306a36Sopenharmony_ci	case SCSI_ACCESS_STATE_TRANSITIONING:
120662306a36Sopenharmony_ci		return BLK_STS_OK;
120762306a36Sopenharmony_ci	default:
120862306a36Sopenharmony_ci		req->rq_flags |= RQF_QUIET;
120962306a36Sopenharmony_ci		return BLK_STS_IOERR;
121062306a36Sopenharmony_ci	}
121162306a36Sopenharmony_ci}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_cistatic void alua_rescan(struct scsi_device *sdev)
121462306a36Sopenharmony_ci{
121562306a36Sopenharmony_ci	struct alua_dh_data *h = sdev->handler_data;
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	alua_initialize(sdev, h);
121862306a36Sopenharmony_ci}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci/*
122162306a36Sopenharmony_ci * alua_bus_attach - Attach device handler
122262306a36Sopenharmony_ci * @sdev: device to be attached to
122362306a36Sopenharmony_ci */
122462306a36Sopenharmony_cistatic int alua_bus_attach(struct scsi_device *sdev)
122562306a36Sopenharmony_ci{
122662306a36Sopenharmony_ci	struct alua_dh_data *h;
122762306a36Sopenharmony_ci	int err;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	h = kzalloc(sizeof(*h) , GFP_KERNEL);
123062306a36Sopenharmony_ci	if (!h)
123162306a36Sopenharmony_ci		return SCSI_DH_NOMEM;
123262306a36Sopenharmony_ci	spin_lock_init(&h->pg_lock);
123362306a36Sopenharmony_ci	rcu_assign_pointer(h->pg, NULL);
123462306a36Sopenharmony_ci	h->init_error = SCSI_DH_OK;
123562306a36Sopenharmony_ci	h->sdev = sdev;
123662306a36Sopenharmony_ci	INIT_LIST_HEAD(&h->node);
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	mutex_init(&h->init_mutex);
123962306a36Sopenharmony_ci	err = alua_initialize(sdev, h);
124062306a36Sopenharmony_ci	if (err != SCSI_DH_OK && err != SCSI_DH_DEV_OFFLINED)
124162306a36Sopenharmony_ci		goto failed;
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	sdev->handler_data = h;
124462306a36Sopenharmony_ci	return SCSI_DH_OK;
124562306a36Sopenharmony_cifailed:
124662306a36Sopenharmony_ci	kfree(h);
124762306a36Sopenharmony_ci	return err;
124862306a36Sopenharmony_ci}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci/*
125162306a36Sopenharmony_ci * alua_bus_detach - Detach device handler
125262306a36Sopenharmony_ci * @sdev: device to be detached from
125362306a36Sopenharmony_ci */
125462306a36Sopenharmony_cistatic void alua_bus_detach(struct scsi_device *sdev)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	struct alua_dh_data *h = sdev->handler_data;
125762306a36Sopenharmony_ci	struct alua_port_group *pg;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	spin_lock(&h->pg_lock);
126062306a36Sopenharmony_ci	pg = rcu_dereference_protected(h->pg, lockdep_is_held(&h->pg_lock));
126162306a36Sopenharmony_ci	rcu_assign_pointer(h->pg, NULL);
126262306a36Sopenharmony_ci	spin_unlock(&h->pg_lock);
126362306a36Sopenharmony_ci	if (pg) {
126462306a36Sopenharmony_ci		spin_lock_irq(&pg->lock);
126562306a36Sopenharmony_ci		list_del_rcu(&h->node);
126662306a36Sopenharmony_ci		spin_unlock_irq(&pg->lock);
126762306a36Sopenharmony_ci		kref_put(&pg->kref, release_port_group);
126862306a36Sopenharmony_ci	}
126962306a36Sopenharmony_ci	sdev->handler_data = NULL;
127062306a36Sopenharmony_ci	synchronize_rcu();
127162306a36Sopenharmony_ci	kfree(h);
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cistatic struct scsi_device_handler alua_dh = {
127562306a36Sopenharmony_ci	.name = ALUA_DH_NAME,
127662306a36Sopenharmony_ci	.module = THIS_MODULE,
127762306a36Sopenharmony_ci	.attach = alua_bus_attach,
127862306a36Sopenharmony_ci	.detach = alua_bus_detach,
127962306a36Sopenharmony_ci	.prep_fn = alua_prep_fn,
128062306a36Sopenharmony_ci	.check_sense = alua_check_sense,
128162306a36Sopenharmony_ci	.activate = alua_activate,
128262306a36Sopenharmony_ci	.rescan = alua_rescan,
128362306a36Sopenharmony_ci	.set_params = alua_set_params,
128462306a36Sopenharmony_ci};
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_cistatic int __init alua_init(void)
128762306a36Sopenharmony_ci{
128862306a36Sopenharmony_ci	int r;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	kaluad_wq = alloc_workqueue("kaluad", WQ_MEM_RECLAIM, 0);
129162306a36Sopenharmony_ci	if (!kaluad_wq)
129262306a36Sopenharmony_ci		return -ENOMEM;
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	r = scsi_register_device_handler(&alua_dh);
129562306a36Sopenharmony_ci	if (r != 0) {
129662306a36Sopenharmony_ci		printk(KERN_ERR "%s: Failed to register scsi device handler",
129762306a36Sopenharmony_ci			ALUA_DH_NAME);
129862306a36Sopenharmony_ci		destroy_workqueue(kaluad_wq);
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci	return r;
130162306a36Sopenharmony_ci}
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_cistatic void __exit alua_exit(void)
130462306a36Sopenharmony_ci{
130562306a36Sopenharmony_ci	scsi_unregister_device_handler(&alua_dh);
130662306a36Sopenharmony_ci	destroy_workqueue(kaluad_wq);
130762306a36Sopenharmony_ci}
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_cimodule_init(alua_init);
131062306a36Sopenharmony_cimodule_exit(alua_exit);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ciMODULE_DESCRIPTION("DM Multipath ALUA support");
131362306a36Sopenharmony_ciMODULE_AUTHOR("Hannes Reinecke <hare@suse.de>");
131462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
131562306a36Sopenharmony_ciMODULE_VERSION(ALUA_DH_VER);
1316