18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * zfcp device driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Error Recovery Procedures (ERP).
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2002, 2020
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "zfcp"
118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/kthread.h>
148c2ecf20Sopenharmony_ci#include <linux/bug.h>
158c2ecf20Sopenharmony_ci#include "zfcp_ext.h"
168c2ecf20Sopenharmony_ci#include "zfcp_reqlist.h"
178c2ecf20Sopenharmony_ci#include "zfcp_diag.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define ZFCP_MAX_ERPS                   3
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cienum zfcp_erp_act_flags {
228c2ecf20Sopenharmony_ci	ZFCP_STATUS_ERP_TIMEDOUT	= 0x10000000,
238c2ecf20Sopenharmony_ci	ZFCP_STATUS_ERP_CLOSE_ONLY	= 0x01000000,
248c2ecf20Sopenharmony_ci	ZFCP_STATUS_ERP_DISMISSED	= 0x00200000,
258c2ecf20Sopenharmony_ci	ZFCP_STATUS_ERP_LOWMEM		= 0x00400000,
268c2ecf20Sopenharmony_ci	ZFCP_STATUS_ERP_NO_REF		= 0x00800000,
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/*
308c2ecf20Sopenharmony_ci * Eyecatcher pseudo flag to bitwise or-combine with enum zfcp_erp_act_type.
318c2ecf20Sopenharmony_ci * Used to indicate that an ERP action could not be set up despite a detected
328c2ecf20Sopenharmony_ci * need for some recovery.
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_ci#define ZFCP_ERP_ACTION_NONE		0xc0
358c2ecf20Sopenharmony_ci/*
368c2ecf20Sopenharmony_ci * Eyecatcher pseudo flag to bitwise or-combine with enum zfcp_erp_act_type.
378c2ecf20Sopenharmony_ci * Used to indicate that ERP not needed because the object has
388c2ecf20Sopenharmony_ci * ZFCP_STATUS_COMMON_ERP_FAILED.
398c2ecf20Sopenharmony_ci */
408c2ecf20Sopenharmony_ci#define ZFCP_ERP_ACTION_FAILED		0xe0
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cienum zfcp_erp_act_result {
438c2ecf20Sopenharmony_ci	ZFCP_ERP_SUCCEEDED = 0,
448c2ecf20Sopenharmony_ci	ZFCP_ERP_FAILED    = 1,
458c2ecf20Sopenharmony_ci	ZFCP_ERP_CONTINUES = 2,
468c2ecf20Sopenharmony_ci	ZFCP_ERP_EXIT      = 3,
478c2ecf20Sopenharmony_ci	ZFCP_ERP_DISMISSED = 4,
488c2ecf20Sopenharmony_ci	ZFCP_ERP_NOMEM     = 5,
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	zfcp_erp_clear_adapter_status(adapter,
548c2ecf20Sopenharmony_ci				       ZFCP_STATUS_COMMON_UNBLOCKED | mask);
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic bool zfcp_erp_action_is_running(struct zfcp_erp_action *act)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct zfcp_erp_action *curr_act;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	list_for_each_entry(curr_act, &act->adapter->erp_running_head, list)
628c2ecf20Sopenharmony_ci		if (act == curr_act)
638c2ecf20Sopenharmony_ci			return true;
648c2ecf20Sopenharmony_ci	return false;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic void zfcp_erp_action_ready(struct zfcp_erp_action *act)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = act->adapter;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	list_move(&act->list, &adapter->erp_ready_head);
728c2ecf20Sopenharmony_ci	zfcp_dbf_rec_run("erardy1", act);
738c2ecf20Sopenharmony_ci	wake_up(&adapter->erp_ready_wq);
748c2ecf20Sopenharmony_ci	zfcp_dbf_rec_run("erardy2", act);
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	act->status |= ZFCP_STATUS_ERP_DISMISSED;
808c2ecf20Sopenharmony_ci	if (zfcp_erp_action_is_running(act))
818c2ecf20Sopenharmony_ci		zfcp_erp_action_ready(act);
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic void zfcp_erp_action_dismiss_lun(struct scsi_device *sdev)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
898c2ecf20Sopenharmony_ci		zfcp_erp_action_dismiss(&zfcp_sdev->erp_action);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
978c2ecf20Sopenharmony_ci		zfcp_erp_action_dismiss(&port->erp_action);
988c2ecf20Sopenharmony_ci	else {
998c2ecf20Sopenharmony_ci		spin_lock(port->adapter->scsi_host->host_lock);
1008c2ecf20Sopenharmony_ci		__shost_for_each_device(sdev, port->adapter->scsi_host)
1018c2ecf20Sopenharmony_ci			if (sdev_to_zfcp(sdev)->port == port)
1028c2ecf20Sopenharmony_ci				zfcp_erp_action_dismiss_lun(sdev);
1038c2ecf20Sopenharmony_ci		spin_unlock(port->adapter->scsi_host->host_lock);
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	struct zfcp_port *port;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
1128c2ecf20Sopenharmony_ci		zfcp_erp_action_dismiss(&adapter->erp_action);
1138c2ecf20Sopenharmony_ci	else {
1148c2ecf20Sopenharmony_ci		read_lock(&adapter->port_list_lock);
1158c2ecf20Sopenharmony_ci		list_for_each_entry(port, &adapter->port_list, list)
1168c2ecf20Sopenharmony_ci		    zfcp_erp_action_dismiss_port(port);
1178c2ecf20Sopenharmony_ci		read_unlock(&adapter->port_list_lock);
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_type zfcp_erp_handle_failed(
1228c2ecf20Sopenharmony_ci	enum zfcp_erp_act_type want, struct zfcp_adapter *adapter,
1238c2ecf20Sopenharmony_ci	struct zfcp_port *port,	struct scsi_device *sdev)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	enum zfcp_erp_act_type need = want;
1268c2ecf20Sopenharmony_ci	struct zfcp_scsi_dev *zsdev;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	switch (want) {
1298c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_LUN:
1308c2ecf20Sopenharmony_ci		zsdev = sdev_to_zfcp(sdev);
1318c2ecf20Sopenharmony_ci		if (atomic_read(&zsdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
1328c2ecf20Sopenharmony_ci			need = 0;
1338c2ecf20Sopenharmony_ci		break;
1348c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1358c2ecf20Sopenharmony_ci		if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
1368c2ecf20Sopenharmony_ci			need = 0;
1378c2ecf20Sopenharmony_ci		break;
1388c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT:
1398c2ecf20Sopenharmony_ci		if (atomic_read(&port->status) &
1408c2ecf20Sopenharmony_ci		    ZFCP_STATUS_COMMON_ERP_FAILED) {
1418c2ecf20Sopenharmony_ci			need = 0;
1428c2ecf20Sopenharmony_ci			/* ensure propagation of failed status to new devices */
1438c2ecf20Sopenharmony_ci			zfcp_erp_set_port_status(
1448c2ecf20Sopenharmony_ci				port, ZFCP_STATUS_COMMON_ERP_FAILED);
1458c2ecf20Sopenharmony_ci		}
1468c2ecf20Sopenharmony_ci		break;
1478c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1488c2ecf20Sopenharmony_ci		if (atomic_read(&adapter->status) &
1498c2ecf20Sopenharmony_ci		    ZFCP_STATUS_COMMON_ERP_FAILED) {
1508c2ecf20Sopenharmony_ci			need = 0;
1518c2ecf20Sopenharmony_ci			/* ensure propagation of failed status to new devices */
1528c2ecf20Sopenharmony_ci			zfcp_erp_set_adapter_status(
1538c2ecf20Sopenharmony_ci				adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
1548c2ecf20Sopenharmony_ci		}
1558c2ecf20Sopenharmony_ci		break;
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	return need;
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_type zfcp_erp_required_act(enum zfcp_erp_act_type want,
1628c2ecf20Sopenharmony_ci				 struct zfcp_adapter *adapter,
1638c2ecf20Sopenharmony_ci				 struct zfcp_port *port,
1648c2ecf20Sopenharmony_ci				 struct scsi_device *sdev)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	enum zfcp_erp_act_type need = want;
1678c2ecf20Sopenharmony_ci	int l_status, p_status, a_status;
1688c2ecf20Sopenharmony_ci	struct zfcp_scsi_dev *zfcp_sdev;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	switch (want) {
1718c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_LUN:
1728c2ecf20Sopenharmony_ci		zfcp_sdev = sdev_to_zfcp(sdev);
1738c2ecf20Sopenharmony_ci		l_status = atomic_read(&zfcp_sdev->status);
1748c2ecf20Sopenharmony_ci		if (l_status & ZFCP_STATUS_COMMON_ERP_INUSE)
1758c2ecf20Sopenharmony_ci			return 0;
1768c2ecf20Sopenharmony_ci		p_status = atomic_read(&port->status);
1778c2ecf20Sopenharmony_ci		if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) ||
1788c2ecf20Sopenharmony_ci		    p_status & ZFCP_STATUS_COMMON_ERP_FAILED)
1798c2ecf20Sopenharmony_ci			return 0;
1808c2ecf20Sopenharmony_ci		if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
1818c2ecf20Sopenharmony_ci			need = ZFCP_ERP_ACTION_REOPEN_PORT;
1828c2ecf20Sopenharmony_ci		fallthrough;
1838c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1848c2ecf20Sopenharmony_ci		p_status = atomic_read(&port->status);
1858c2ecf20Sopenharmony_ci		if (!(p_status & ZFCP_STATUS_COMMON_OPEN))
1868c2ecf20Sopenharmony_ci			need = ZFCP_ERP_ACTION_REOPEN_PORT;
1878c2ecf20Sopenharmony_ci		fallthrough;
1888c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT:
1898c2ecf20Sopenharmony_ci		p_status = atomic_read(&port->status);
1908c2ecf20Sopenharmony_ci		if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
1918c2ecf20Sopenharmony_ci			return 0;
1928c2ecf20Sopenharmony_ci		a_status = atomic_read(&adapter->status);
1938c2ecf20Sopenharmony_ci		if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) ||
1948c2ecf20Sopenharmony_ci		    a_status & ZFCP_STATUS_COMMON_ERP_FAILED)
1958c2ecf20Sopenharmony_ci			return 0;
1968c2ecf20Sopenharmony_ci		if (p_status & ZFCP_STATUS_COMMON_NOESC)
1978c2ecf20Sopenharmony_ci			return need;
1988c2ecf20Sopenharmony_ci		if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))
1998c2ecf20Sopenharmony_ci			need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
2008c2ecf20Sopenharmony_ci		fallthrough;
2018c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
2028c2ecf20Sopenharmony_ci		a_status = atomic_read(&adapter->status);
2038c2ecf20Sopenharmony_ci		if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
2048c2ecf20Sopenharmony_ci			return 0;
2058c2ecf20Sopenharmony_ci		if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) &&
2068c2ecf20Sopenharmony_ci		    !(a_status & ZFCP_STATUS_COMMON_OPEN))
2078c2ecf20Sopenharmony_ci			return 0; /* shutdown requested for closed adapter */
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	return need;
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic struct zfcp_erp_action *zfcp_erp_setup_act(enum zfcp_erp_act_type need,
2148c2ecf20Sopenharmony_ci						  u32 act_status,
2158c2ecf20Sopenharmony_ci						  struct zfcp_adapter *adapter,
2168c2ecf20Sopenharmony_ci						  struct zfcp_port *port,
2178c2ecf20Sopenharmony_ci						  struct scsi_device *sdev)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	struct zfcp_erp_action *erp_action;
2208c2ecf20Sopenharmony_ci	struct zfcp_scsi_dev *zfcp_sdev;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(need != ZFCP_ERP_ACTION_REOPEN_LUN &&
2238c2ecf20Sopenharmony_ci			 need != ZFCP_ERP_ACTION_REOPEN_PORT &&
2248c2ecf20Sopenharmony_ci			 need != ZFCP_ERP_ACTION_REOPEN_PORT_FORCED &&
2258c2ecf20Sopenharmony_ci			 need != ZFCP_ERP_ACTION_REOPEN_ADAPTER))
2268c2ecf20Sopenharmony_ci		return NULL;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	switch (need) {
2298c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_LUN:
2308c2ecf20Sopenharmony_ci		zfcp_sdev = sdev_to_zfcp(sdev);
2318c2ecf20Sopenharmony_ci		if (!(act_status & ZFCP_STATUS_ERP_NO_REF))
2328c2ecf20Sopenharmony_ci			if (scsi_device_get(sdev))
2338c2ecf20Sopenharmony_ci				return NULL;
2348c2ecf20Sopenharmony_ci		atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE,
2358c2ecf20Sopenharmony_ci				&zfcp_sdev->status);
2368c2ecf20Sopenharmony_ci		erp_action = &zfcp_sdev->erp_action;
2378c2ecf20Sopenharmony_ci		WARN_ON_ONCE(erp_action->port != port);
2388c2ecf20Sopenharmony_ci		WARN_ON_ONCE(erp_action->sdev != sdev);
2398c2ecf20Sopenharmony_ci		if (!(atomic_read(&zfcp_sdev->status) &
2408c2ecf20Sopenharmony_ci		      ZFCP_STATUS_COMMON_RUNNING))
2418c2ecf20Sopenharmony_ci			act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
2428c2ecf20Sopenharmony_ci		break;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT:
2458c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
2468c2ecf20Sopenharmony_ci		if (!get_device(&port->dev))
2478c2ecf20Sopenharmony_ci			return NULL;
2488c2ecf20Sopenharmony_ci		zfcp_erp_action_dismiss_port(port);
2498c2ecf20Sopenharmony_ci		atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
2508c2ecf20Sopenharmony_ci		erp_action = &port->erp_action;
2518c2ecf20Sopenharmony_ci		WARN_ON_ONCE(erp_action->port != port);
2528c2ecf20Sopenharmony_ci		WARN_ON_ONCE(erp_action->sdev != NULL);
2538c2ecf20Sopenharmony_ci		if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
2548c2ecf20Sopenharmony_ci			act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
2558c2ecf20Sopenharmony_ci		break;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
2588c2ecf20Sopenharmony_ci		kref_get(&adapter->ref);
2598c2ecf20Sopenharmony_ci		zfcp_erp_action_dismiss_adapter(adapter);
2608c2ecf20Sopenharmony_ci		atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
2618c2ecf20Sopenharmony_ci		erp_action = &adapter->erp_action;
2628c2ecf20Sopenharmony_ci		WARN_ON_ONCE(erp_action->port != NULL);
2638c2ecf20Sopenharmony_ci		WARN_ON_ONCE(erp_action->sdev != NULL);
2648c2ecf20Sopenharmony_ci		if (!(atomic_read(&adapter->status) &
2658c2ecf20Sopenharmony_ci		      ZFCP_STATUS_COMMON_RUNNING))
2668c2ecf20Sopenharmony_ci			act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
2678c2ecf20Sopenharmony_ci		break;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	WARN_ON_ONCE(erp_action->adapter != adapter);
2718c2ecf20Sopenharmony_ci	memset(&erp_action->list, 0, sizeof(erp_action->list));
2728c2ecf20Sopenharmony_ci	memset(&erp_action->timer, 0, sizeof(erp_action->timer));
2738c2ecf20Sopenharmony_ci	erp_action->step = ZFCP_ERP_STEP_UNINITIALIZED;
2748c2ecf20Sopenharmony_ci	erp_action->fsf_req_id = 0;
2758c2ecf20Sopenharmony_ci	erp_action->type = need;
2768c2ecf20Sopenharmony_ci	erp_action->status = act_status;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	return erp_action;
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic void zfcp_erp_action_enqueue(enum zfcp_erp_act_type want,
2828c2ecf20Sopenharmony_ci				    struct zfcp_adapter *adapter,
2838c2ecf20Sopenharmony_ci				    struct zfcp_port *port,
2848c2ecf20Sopenharmony_ci				    struct scsi_device *sdev,
2858c2ecf20Sopenharmony_ci				    char *dbftag, u32 act_status)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	enum zfcp_erp_act_type need;
2888c2ecf20Sopenharmony_ci	struct zfcp_erp_action *act;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	need = zfcp_erp_handle_failed(want, adapter, port, sdev);
2918c2ecf20Sopenharmony_ci	if (!need) {
2928c2ecf20Sopenharmony_ci		need = ZFCP_ERP_ACTION_FAILED; /* marker for trace */
2938c2ecf20Sopenharmony_ci		goto out;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (!adapter->erp_thread) {
2978c2ecf20Sopenharmony_ci		need = ZFCP_ERP_ACTION_NONE; /* marker for trace */
2988c2ecf20Sopenharmony_ci		goto out;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	need = zfcp_erp_required_act(want, adapter, port, sdev);
3028c2ecf20Sopenharmony_ci	if (!need)
3038c2ecf20Sopenharmony_ci		goto out;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev);
3068c2ecf20Sopenharmony_ci	if (!act) {
3078c2ecf20Sopenharmony_ci		need |= ZFCP_ERP_ACTION_NONE; /* marker for trace */
3088c2ecf20Sopenharmony_ci		goto out;
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci	atomic_or(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
3118c2ecf20Sopenharmony_ci	++adapter->erp_total_count;
3128c2ecf20Sopenharmony_ci	list_add_tail(&act->list, &adapter->erp_ready_head);
3138c2ecf20Sopenharmony_ci	wake_up(&adapter->erp_ready_wq);
3148c2ecf20Sopenharmony_ci out:
3158c2ecf20Sopenharmony_ci	zfcp_dbf_rec_trig(dbftag, adapter, port, sdev, want, need);
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_civoid zfcp_erp_port_forced_no_port_dbf(char *dbftag,
3198c2ecf20Sopenharmony_ci				      struct zfcp_adapter *adapter,
3208c2ecf20Sopenharmony_ci				      u64 port_name, u32 port_id)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	unsigned long flags;
3238c2ecf20Sopenharmony_ci	static /* don't waste stack */ struct zfcp_port tmpport;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	write_lock_irqsave(&adapter->erp_lock, flags);
3268c2ecf20Sopenharmony_ci	/* Stand-in zfcp port with fields just good enough for
3278c2ecf20Sopenharmony_ci	 * zfcp_dbf_rec_trig() and zfcp_dbf_set_common().
3288c2ecf20Sopenharmony_ci	 * Under lock because tmpport is static.
3298c2ecf20Sopenharmony_ci	 */
3308c2ecf20Sopenharmony_ci	atomic_set(&tmpport.status, -1); /* unknown */
3318c2ecf20Sopenharmony_ci	tmpport.wwpn = port_name;
3328c2ecf20Sopenharmony_ci	tmpport.d_id = port_id;
3338c2ecf20Sopenharmony_ci	zfcp_dbf_rec_trig(dbftag, adapter, &tmpport, NULL,
3348c2ecf20Sopenharmony_ci			  ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
3358c2ecf20Sopenharmony_ci			  ZFCP_ERP_ACTION_NONE);
3368c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&adapter->erp_lock, flags);
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic void _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
3408c2ecf20Sopenharmony_ci				    int clear_mask, char *dbftag)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	zfcp_erp_adapter_block(adapter, clear_mask);
3438c2ecf20Sopenharmony_ci	zfcp_scsi_schedule_rports_block(adapter);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
3468c2ecf20Sopenharmony_ci				adapter, NULL, NULL, dbftag, 0);
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci/**
3508c2ecf20Sopenharmony_ci * zfcp_erp_adapter_reopen - Reopen adapter.
3518c2ecf20Sopenharmony_ci * @adapter: Adapter to reopen.
3528c2ecf20Sopenharmony_ci * @clear: Status flags to clear.
3538c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event.
3548c2ecf20Sopenharmony_ci */
3558c2ecf20Sopenharmony_civoid zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
3568c2ecf20Sopenharmony_ci			     char *dbftag)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	unsigned long flags;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	zfcp_erp_adapter_block(adapter, clear);
3618c2ecf20Sopenharmony_ci	zfcp_scsi_schedule_rports_block(adapter);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	write_lock_irqsave(&adapter->erp_lock, flags);
3648c2ecf20Sopenharmony_ci	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
3658c2ecf20Sopenharmony_ci				NULL, NULL, dbftag, 0);
3668c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&adapter->erp_lock, flags);
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci/**
3708c2ecf20Sopenharmony_ci * zfcp_erp_adapter_shutdown - Shutdown adapter.
3718c2ecf20Sopenharmony_ci * @adapter: Adapter to shut down.
3728c2ecf20Sopenharmony_ci * @clear: Status flags to clear.
3738c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event.
3748c2ecf20Sopenharmony_ci */
3758c2ecf20Sopenharmony_civoid zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
3768c2ecf20Sopenharmony_ci			       char *dbftag)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
3798c2ecf20Sopenharmony_ci	zfcp_erp_adapter_reopen(adapter, clear | flags, dbftag);
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci/**
3838c2ecf20Sopenharmony_ci * zfcp_erp_port_shutdown - Shutdown port
3848c2ecf20Sopenharmony_ci * @port: Port to shut down.
3858c2ecf20Sopenharmony_ci * @clear: Status flags to clear.
3868c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event.
3878c2ecf20Sopenharmony_ci */
3888c2ecf20Sopenharmony_civoid zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *dbftag)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
3918c2ecf20Sopenharmony_ci	zfcp_erp_port_reopen(port, clear | flags, dbftag);
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cistatic void zfcp_erp_port_block(struct zfcp_port *port, int clear)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	zfcp_erp_clear_port_status(port,
3978c2ecf20Sopenharmony_ci				    ZFCP_STATUS_COMMON_UNBLOCKED | clear);
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear,
4018c2ecf20Sopenharmony_ci					 char *dbftag)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	zfcp_erp_port_block(port, clear);
4048c2ecf20Sopenharmony_ci	zfcp_scsi_schedule_rport_block(port);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
4078c2ecf20Sopenharmony_ci				port->adapter, port, NULL, dbftag, 0);
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci/**
4118c2ecf20Sopenharmony_ci * zfcp_erp_port_forced_reopen - Forced close of port and open again
4128c2ecf20Sopenharmony_ci * @port: Port to force close and to reopen.
4138c2ecf20Sopenharmony_ci * @clear: Status flags to clear.
4148c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event.
4158c2ecf20Sopenharmony_ci */
4168c2ecf20Sopenharmony_civoid zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear,
4178c2ecf20Sopenharmony_ci				 char *dbftag)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	unsigned long flags;
4208c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = port->adapter;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	write_lock_irqsave(&adapter->erp_lock, flags);
4238c2ecf20Sopenharmony_ci	_zfcp_erp_port_forced_reopen(port, clear, dbftag);
4248c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&adapter->erp_lock, flags);
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic void _zfcp_erp_port_reopen(struct zfcp_port *port, int clear,
4288c2ecf20Sopenharmony_ci				  char *dbftag)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	zfcp_erp_port_block(port, clear);
4318c2ecf20Sopenharmony_ci	zfcp_scsi_schedule_rport_block(port);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
4348c2ecf20Sopenharmony_ci				port->adapter, port, NULL, dbftag, 0);
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci/**
4388c2ecf20Sopenharmony_ci * zfcp_erp_port_reopen - trigger remote port recovery
4398c2ecf20Sopenharmony_ci * @port: port to recover
4408c2ecf20Sopenharmony_ci * @clear: flags in port status to be cleared
4418c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event.
4428c2ecf20Sopenharmony_ci */
4438c2ecf20Sopenharmony_civoid zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *dbftag)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	unsigned long flags;
4468c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = port->adapter;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	write_lock_irqsave(&adapter->erp_lock, flags);
4498c2ecf20Sopenharmony_ci	_zfcp_erp_port_reopen(port, clear, dbftag);
4508c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&adapter->erp_lock, flags);
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic void zfcp_erp_lun_block(struct scsi_device *sdev, int clear_mask)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	zfcp_erp_clear_lun_status(sdev,
4568c2ecf20Sopenharmony_ci				  ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask);
4578c2ecf20Sopenharmony_ci}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_cistatic void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear,
4608c2ecf20Sopenharmony_ci				 char *dbftag, u32 act_status)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
4638c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	zfcp_erp_lun_block(sdev, clear);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter,
4688c2ecf20Sopenharmony_ci				zfcp_sdev->port, sdev, dbftag, act_status);
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci/**
4728c2ecf20Sopenharmony_ci * zfcp_erp_lun_reopen - initiate reopen of a LUN
4738c2ecf20Sopenharmony_ci * @sdev: SCSI device / LUN to be reopened
4748c2ecf20Sopenharmony_ci * @clear: specifies flags in LUN status to be cleared
4758c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event.
4768c2ecf20Sopenharmony_ci *
4778c2ecf20Sopenharmony_ci * Return: 0 on success, < 0 on error
4788c2ecf20Sopenharmony_ci */
4798c2ecf20Sopenharmony_civoid zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *dbftag)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	unsigned long flags;
4828c2ecf20Sopenharmony_ci	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
4838c2ecf20Sopenharmony_ci	struct zfcp_port *port = zfcp_sdev->port;
4848c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = port->adapter;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	write_lock_irqsave(&adapter->erp_lock, flags);
4878c2ecf20Sopenharmony_ci	_zfcp_erp_lun_reopen(sdev, clear, dbftag, 0);
4888c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&adapter->erp_lock, flags);
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci/**
4928c2ecf20Sopenharmony_ci * zfcp_erp_lun_shutdown - Shutdown LUN
4938c2ecf20Sopenharmony_ci * @sdev: SCSI device / LUN to shut down.
4948c2ecf20Sopenharmony_ci * @clear: Status flags to clear.
4958c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event.
4968c2ecf20Sopenharmony_ci */
4978c2ecf20Sopenharmony_civoid zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *dbftag)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
5008c2ecf20Sopenharmony_ci	zfcp_erp_lun_reopen(sdev, clear | flags, dbftag);
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci/**
5048c2ecf20Sopenharmony_ci * zfcp_erp_lun_shutdown_wait - Shutdown LUN and wait for erp completion
5058c2ecf20Sopenharmony_ci * @sdev: SCSI device / LUN to shut down.
5068c2ecf20Sopenharmony_ci * @dbftag: Tag for debug trace event.
5078c2ecf20Sopenharmony_ci *
5088c2ecf20Sopenharmony_ci * Do not acquire a reference for the LUN when creating the ERP
5098c2ecf20Sopenharmony_ci * action. It is safe, because this function waits for the ERP to
5108c2ecf20Sopenharmony_ci * complete first. This allows to shutdown the LUN, even when the SCSI
5118c2ecf20Sopenharmony_ci * device is in the state SDEV_DEL when scsi_device_get will fail.
5128c2ecf20Sopenharmony_ci */
5138c2ecf20Sopenharmony_civoid zfcp_erp_lun_shutdown_wait(struct scsi_device *sdev, char *dbftag)
5148c2ecf20Sopenharmony_ci{
5158c2ecf20Sopenharmony_ci	unsigned long flags;
5168c2ecf20Sopenharmony_ci	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
5178c2ecf20Sopenharmony_ci	struct zfcp_port *port = zfcp_sdev->port;
5188c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = port->adapter;
5198c2ecf20Sopenharmony_ci	int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	write_lock_irqsave(&adapter->erp_lock, flags);
5228c2ecf20Sopenharmony_ci	_zfcp_erp_lun_reopen(sdev, clear, dbftag, ZFCP_STATUS_ERP_NO_REF);
5238c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&adapter->erp_lock, flags);
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	zfcp_erp_wait(adapter);
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic int zfcp_erp_status_change_set(unsigned long mask, atomic_t *status)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	return (atomic_read(status) ^ mask) & mask;
5318c2ecf20Sopenharmony_ci}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_cistatic void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
5348c2ecf20Sopenharmony_ci{
5358c2ecf20Sopenharmony_ci	if (zfcp_erp_status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED,
5368c2ecf20Sopenharmony_ci				       &adapter->status))
5378c2ecf20Sopenharmony_ci		zfcp_dbf_rec_run("eraubl1", &adapter->erp_action);
5388c2ecf20Sopenharmony_ci	atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
5398c2ecf20Sopenharmony_ci}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_cistatic void zfcp_erp_port_unblock(struct zfcp_port *port)
5428c2ecf20Sopenharmony_ci{
5438c2ecf20Sopenharmony_ci	if (zfcp_erp_status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED,
5448c2ecf20Sopenharmony_ci				       &port->status))
5458c2ecf20Sopenharmony_ci		zfcp_dbf_rec_run("erpubl1", &port->erp_action);
5468c2ecf20Sopenharmony_ci	atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
5478c2ecf20Sopenharmony_ci}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_cistatic void zfcp_erp_lun_unblock(struct scsi_device *sdev)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (zfcp_erp_status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED,
5548c2ecf20Sopenharmony_ci				       &zfcp_sdev->status))
5558c2ecf20Sopenharmony_ci		zfcp_dbf_rec_run("erlubl1", &sdev_to_zfcp(sdev)->erp_action);
5568c2ecf20Sopenharmony_ci	atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status);
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_cistatic void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
5608c2ecf20Sopenharmony_ci{
5618c2ecf20Sopenharmony_ci	list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
5628c2ecf20Sopenharmony_ci	zfcp_dbf_rec_run("erator1", erp_action);
5638c2ecf20Sopenharmony_ci}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_cistatic void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = act->adapter;
5688c2ecf20Sopenharmony_ci	struct zfcp_fsf_req *req;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	if (!act->fsf_req_id)
5718c2ecf20Sopenharmony_ci		return;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	spin_lock(&adapter->req_list->lock);
5748c2ecf20Sopenharmony_ci	req = _zfcp_reqlist_find(adapter->req_list, act->fsf_req_id);
5758c2ecf20Sopenharmony_ci	if (req && req->erp_action == act) {
5768c2ecf20Sopenharmony_ci		if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
5778c2ecf20Sopenharmony_ci				   ZFCP_STATUS_ERP_TIMEDOUT)) {
5788c2ecf20Sopenharmony_ci			req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
5798c2ecf20Sopenharmony_ci			zfcp_dbf_rec_run("erscf_1", act);
5808c2ecf20Sopenharmony_ci			/* lock-free concurrent access with
5818c2ecf20Sopenharmony_ci			 * zfcp_erp_timeout_handler()
5828c2ecf20Sopenharmony_ci			 */
5838c2ecf20Sopenharmony_ci			WRITE_ONCE(req->erp_action, NULL);
5848c2ecf20Sopenharmony_ci		}
5858c2ecf20Sopenharmony_ci		if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
5868c2ecf20Sopenharmony_ci			zfcp_dbf_rec_run("erscf_2", act);
5878c2ecf20Sopenharmony_ci		if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
5888c2ecf20Sopenharmony_ci			act->fsf_req_id = 0;
5898c2ecf20Sopenharmony_ci	} else
5908c2ecf20Sopenharmony_ci		act->fsf_req_id = 0;
5918c2ecf20Sopenharmony_ci	spin_unlock(&adapter->req_list->lock);
5928c2ecf20Sopenharmony_ci}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci/**
5958c2ecf20Sopenharmony_ci * zfcp_erp_notify - Trigger ERP action.
5968c2ecf20Sopenharmony_ci * @erp_action: ERP action to continue.
5978c2ecf20Sopenharmony_ci * @set_mask: ERP action status flags to set.
5988c2ecf20Sopenharmony_ci */
5998c2ecf20Sopenharmony_civoid zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask)
6008c2ecf20Sopenharmony_ci{
6018c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = erp_action->adapter;
6028c2ecf20Sopenharmony_ci	unsigned long flags;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	write_lock_irqsave(&adapter->erp_lock, flags);
6058c2ecf20Sopenharmony_ci	if (zfcp_erp_action_is_running(erp_action)) {
6068c2ecf20Sopenharmony_ci		erp_action->status |= set_mask;
6078c2ecf20Sopenharmony_ci		zfcp_erp_action_ready(erp_action);
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&adapter->erp_lock, flags);
6108c2ecf20Sopenharmony_ci}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci/**
6138c2ecf20Sopenharmony_ci * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request
6148c2ecf20Sopenharmony_ci * @t: timer list entry embedded in zfcp FSF request
6158c2ecf20Sopenharmony_ci */
6168c2ecf20Sopenharmony_civoid zfcp_erp_timeout_handler(struct timer_list *t)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci	struct zfcp_fsf_req *fsf_req = from_timer(fsf_req, t, timer);
6198c2ecf20Sopenharmony_ci	struct zfcp_erp_action *act;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
6228c2ecf20Sopenharmony_ci		return;
6238c2ecf20Sopenharmony_ci	/* lock-free concurrent access with zfcp_erp_strategy_check_fsfreq() */
6248c2ecf20Sopenharmony_ci	act = READ_ONCE(fsf_req->erp_action);
6258c2ecf20Sopenharmony_ci	if (!act)
6268c2ecf20Sopenharmony_ci		return;
6278c2ecf20Sopenharmony_ci	zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT);
6288c2ecf20Sopenharmony_ci}
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_cistatic void zfcp_erp_memwait_handler(struct timer_list *t)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	struct zfcp_erp_action *act = from_timer(act, t, timer);
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	zfcp_erp_notify(act, 0);
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_cistatic void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
6388c2ecf20Sopenharmony_ci{
6398c2ecf20Sopenharmony_ci	timer_setup(&erp_action->timer, zfcp_erp_memwait_handler, 0);
6408c2ecf20Sopenharmony_ci	erp_action->timer.expires = jiffies + HZ;
6418c2ecf20Sopenharmony_ci	add_timer(&erp_action->timer);
6428c2ecf20Sopenharmony_ci}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_civoid zfcp_erp_port_forced_reopen_all(struct zfcp_adapter *adapter,
6458c2ecf20Sopenharmony_ci				     int clear, char *dbftag)
6468c2ecf20Sopenharmony_ci{
6478c2ecf20Sopenharmony_ci	unsigned long flags;
6488c2ecf20Sopenharmony_ci	struct zfcp_port *port;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	write_lock_irqsave(&adapter->erp_lock, flags);
6518c2ecf20Sopenharmony_ci	read_lock(&adapter->port_list_lock);
6528c2ecf20Sopenharmony_ci	list_for_each_entry(port, &adapter->port_list, list)
6538c2ecf20Sopenharmony_ci		_zfcp_erp_port_forced_reopen(port, clear, dbftag);
6548c2ecf20Sopenharmony_ci	read_unlock(&adapter->port_list_lock);
6558c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&adapter->erp_lock, flags);
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_cistatic void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
6598c2ecf20Sopenharmony_ci				      int clear, char *dbftag)
6608c2ecf20Sopenharmony_ci{
6618c2ecf20Sopenharmony_ci	struct zfcp_port *port;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	read_lock(&adapter->port_list_lock);
6648c2ecf20Sopenharmony_ci	list_for_each_entry(port, &adapter->port_list, list)
6658c2ecf20Sopenharmony_ci		_zfcp_erp_port_reopen(port, clear, dbftag);
6668c2ecf20Sopenharmony_ci	read_unlock(&adapter->port_list_lock);
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_cistatic void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear,
6708c2ecf20Sopenharmony_ci				     char *dbftag)
6718c2ecf20Sopenharmony_ci{
6728c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	spin_lock(port->adapter->scsi_host->host_lock);
6758c2ecf20Sopenharmony_ci	__shost_for_each_device(sdev, port->adapter->scsi_host)
6768c2ecf20Sopenharmony_ci		if (sdev_to_zfcp(sdev)->port == port)
6778c2ecf20Sopenharmony_ci			_zfcp_erp_lun_reopen(sdev, clear, dbftag, 0);
6788c2ecf20Sopenharmony_ci	spin_unlock(port->adapter->scsi_host->host_lock);
6798c2ecf20Sopenharmony_ci}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_cistatic void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
6828c2ecf20Sopenharmony_ci{
6838c2ecf20Sopenharmony_ci	switch (act->type) {
6848c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
6858c2ecf20Sopenharmony_ci		_zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1");
6868c2ecf20Sopenharmony_ci		break;
6878c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
6888c2ecf20Sopenharmony_ci		_zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2");
6898c2ecf20Sopenharmony_ci		break;
6908c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT:
6918c2ecf20Sopenharmony_ci		_zfcp_erp_port_reopen(act->port, 0, "ersff_3");
6928c2ecf20Sopenharmony_ci		break;
6938c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_LUN:
6948c2ecf20Sopenharmony_ci		_zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", 0);
6958c2ecf20Sopenharmony_ci		break;
6968c2ecf20Sopenharmony_ci	}
6978c2ecf20Sopenharmony_ci}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_cistatic void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act)
7008c2ecf20Sopenharmony_ci{
7018c2ecf20Sopenharmony_ci	switch (act->type) {
7028c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
7038c2ecf20Sopenharmony_ci		_zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1");
7048c2ecf20Sopenharmony_ci		break;
7058c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
7068c2ecf20Sopenharmony_ci		_zfcp_erp_port_reopen(act->port, 0, "ersfs_2");
7078c2ecf20Sopenharmony_ci		break;
7088c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT:
7098c2ecf20Sopenharmony_ci		_zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3");
7108c2ecf20Sopenharmony_ci		break;
7118c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_LUN:
7128c2ecf20Sopenharmony_ci		/* NOP */
7138c2ecf20Sopenharmony_ci		break;
7148c2ecf20Sopenharmony_ci	}
7158c2ecf20Sopenharmony_ci}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_cistatic void zfcp_erp_wakeup(struct zfcp_adapter *adapter)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci	unsigned long flags;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	read_lock_irqsave(&adapter->erp_lock, flags);
7228c2ecf20Sopenharmony_ci	if (list_empty(&adapter->erp_ready_head) &&
7238c2ecf20Sopenharmony_ci	    list_empty(&adapter->erp_running_head)) {
7248c2ecf20Sopenharmony_ci			atomic_andnot(ZFCP_STATUS_ADAPTER_ERP_PENDING,
7258c2ecf20Sopenharmony_ci					  &adapter->status);
7268c2ecf20Sopenharmony_ci			wake_up(&adapter->erp_done_wqh);
7278c2ecf20Sopenharmony_ci	}
7288c2ecf20Sopenharmony_ci	read_unlock_irqrestore(&adapter->erp_lock, flags);
7298c2ecf20Sopenharmony_ci}
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_cistatic void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
7328c2ecf20Sopenharmony_ci{
7338c2ecf20Sopenharmony_ci	struct zfcp_port *port;
7348c2ecf20Sopenharmony_ci	port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0,
7358c2ecf20Sopenharmony_ci				 adapter->peer_d_id);
7368c2ecf20Sopenharmony_ci	if (IS_ERR(port)) /* error or port already attached */
7378c2ecf20Sopenharmony_ci		return;
7388c2ecf20Sopenharmony_ci	zfcp_erp_port_reopen(port, 0, "ereptp1");
7398c2ecf20Sopenharmony_ci}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_adapter_strat_fsf_xconf(
7428c2ecf20Sopenharmony_ci	struct zfcp_erp_action *erp_action)
7438c2ecf20Sopenharmony_ci{
7448c2ecf20Sopenharmony_ci	int retries;
7458c2ecf20Sopenharmony_ci	int sleep = 1;
7468c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = erp_action->adapter;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	atomic_andnot(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	for (retries = 7; retries; retries--) {
7518c2ecf20Sopenharmony_ci		atomic_andnot(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
7528c2ecf20Sopenharmony_ci				  &adapter->status);
7538c2ecf20Sopenharmony_ci		write_lock_irq(&adapter->erp_lock);
7548c2ecf20Sopenharmony_ci		zfcp_erp_action_to_running(erp_action);
7558c2ecf20Sopenharmony_ci		write_unlock_irq(&adapter->erp_lock);
7568c2ecf20Sopenharmony_ci		if (zfcp_fsf_exchange_config_data(erp_action)) {
7578c2ecf20Sopenharmony_ci			atomic_andnot(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
7588c2ecf20Sopenharmony_ci					  &adapter->status);
7598c2ecf20Sopenharmony_ci			return ZFCP_ERP_FAILED;
7608c2ecf20Sopenharmony_ci		}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci		wait_event(adapter->erp_ready_wq,
7638c2ecf20Sopenharmony_ci			   !list_empty(&adapter->erp_ready_head));
7648c2ecf20Sopenharmony_ci		if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
7658c2ecf20Sopenharmony_ci			break;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci		if (!(atomic_read(&adapter->status) &
7688c2ecf20Sopenharmony_ci		      ZFCP_STATUS_ADAPTER_HOST_CON_INIT))
7698c2ecf20Sopenharmony_ci			break;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci		ssleep(sleep);
7728c2ecf20Sopenharmony_ci		sleep *= 2;
7738c2ecf20Sopenharmony_ci	}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	atomic_andnot(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
7768c2ecf20Sopenharmony_ci			  &adapter->status);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK))
7798c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	return ZFCP_ERP_SUCCEEDED;
7828c2ecf20Sopenharmony_ci}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_cistatic void
7858c2ecf20Sopenharmony_cizfcp_erp_adapter_strategy_open_ptp_port(struct zfcp_adapter *const adapter)
7868c2ecf20Sopenharmony_ci{
7878c2ecf20Sopenharmony_ci	if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
7888c2ecf20Sopenharmony_ci		zfcp_erp_enqueue_ptp_port(adapter);
7898c2ecf20Sopenharmony_ci}
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_adapter_strategy_open_fsf_xport(
7928c2ecf20Sopenharmony_ci	struct zfcp_erp_action *act)
7938c2ecf20Sopenharmony_ci{
7948c2ecf20Sopenharmony_ci	int ret;
7958c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = act->adapter;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	write_lock_irq(&adapter->erp_lock);
7988c2ecf20Sopenharmony_ci	zfcp_erp_action_to_running(act);
7998c2ecf20Sopenharmony_ci	write_unlock_irq(&adapter->erp_lock);
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	ret = zfcp_fsf_exchange_port_data(act);
8028c2ecf20Sopenharmony_ci	if (ret == -EOPNOTSUPP)
8038c2ecf20Sopenharmony_ci		return ZFCP_ERP_SUCCEEDED;
8048c2ecf20Sopenharmony_ci	if (ret)
8058c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	zfcp_dbf_rec_run("erasox1", act);
8088c2ecf20Sopenharmony_ci	wait_event(adapter->erp_ready_wq,
8098c2ecf20Sopenharmony_ci		   !list_empty(&adapter->erp_ready_head));
8108c2ecf20Sopenharmony_ci	zfcp_dbf_rec_run("erasox2", act);
8118c2ecf20Sopenharmony_ci	if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
8128c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	return ZFCP_ERP_SUCCEEDED;
8158c2ecf20Sopenharmony_ci}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result
8188c2ecf20Sopenharmony_cizfcp_erp_adapter_strategy_alloc_shost(struct zfcp_adapter *const adapter)
8198c2ecf20Sopenharmony_ci{
8208c2ecf20Sopenharmony_ci	struct zfcp_diag_adapter_config_data *const config_data =
8218c2ecf20Sopenharmony_ci		&adapter->diagnostics->config_data;
8228c2ecf20Sopenharmony_ci	struct zfcp_diag_adapter_port_data *const port_data =
8238c2ecf20Sopenharmony_ci		&adapter->diagnostics->port_data;
8248c2ecf20Sopenharmony_ci	unsigned long flags;
8258c2ecf20Sopenharmony_ci	int rc;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	rc = zfcp_scsi_adapter_register(adapter);
8288c2ecf20Sopenharmony_ci	if (rc == -EEXIST)
8298c2ecf20Sopenharmony_ci		return ZFCP_ERP_SUCCEEDED;
8308c2ecf20Sopenharmony_ci	else if (rc)
8318c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	/*
8348c2ecf20Sopenharmony_ci	 * We allocated the shost for the first time. Before it was NULL,
8358c2ecf20Sopenharmony_ci	 * and so we deferred all updates in the xconf- and xport-data
8368c2ecf20Sopenharmony_ci	 * handlers. We need to make up for that now, and make all the updates
8378c2ecf20Sopenharmony_ci	 * that would have been done before.
8388c2ecf20Sopenharmony_ci	 *
8398c2ecf20Sopenharmony_ci	 * We can be sure that xconf- and xport-data succeeded, because
8408c2ecf20Sopenharmony_ci	 * otherwise this function is not called. But they might have been
8418c2ecf20Sopenharmony_ci	 * incomplete.
8428c2ecf20Sopenharmony_ci	 */
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	spin_lock_irqsave(&config_data->header.access_lock, flags);
8458c2ecf20Sopenharmony_ci	zfcp_scsi_shost_update_config_data(adapter, &config_data->data,
8468c2ecf20Sopenharmony_ci					   !!config_data->header.incomplete);
8478c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&config_data->header.access_lock, flags);
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) {
8508c2ecf20Sopenharmony_ci		spin_lock_irqsave(&port_data->header.access_lock, flags);
8518c2ecf20Sopenharmony_ci		zfcp_scsi_shost_update_port_data(adapter, &port_data->data);
8528c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&port_data->header.access_lock, flags);
8538c2ecf20Sopenharmony_ci	}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	/*
8568c2ecf20Sopenharmony_ci	 * There is a remote possibility that the 'Exchange Port Data' request
8578c2ecf20Sopenharmony_ci	 * reports a different connectivity status than 'Exchange Config Data'.
8588c2ecf20Sopenharmony_ci	 * But any change to the connectivity status of the local optic that
8598c2ecf20Sopenharmony_ci	 * happens after the initial xconf request is expected to be reported
8608c2ecf20Sopenharmony_ci	 * to us, as soon as we post Status Read Buffers to the FCP channel
8618c2ecf20Sopenharmony_ci	 * firmware after this function. So any resulting inconsistency will
8628c2ecf20Sopenharmony_ci	 * only be momentary.
8638c2ecf20Sopenharmony_ci	 */
8648c2ecf20Sopenharmony_ci	if (config_data->header.incomplete)
8658c2ecf20Sopenharmony_ci		zfcp_fsf_fc_host_link_down(adapter);
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	return ZFCP_ERP_SUCCEEDED;
8688c2ecf20Sopenharmony_ci}
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_adapter_strategy_open_fsf(
8718c2ecf20Sopenharmony_ci	struct zfcp_erp_action *act)
8728c2ecf20Sopenharmony_ci{
8738c2ecf20Sopenharmony_ci	if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED)
8748c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)
8778c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	if (zfcp_erp_adapter_strategy_alloc_shost(act->adapter) ==
8808c2ecf20Sopenharmony_ci	    ZFCP_ERP_FAILED)
8818c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	zfcp_erp_adapter_strategy_open_ptp_port(act->adapter);
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	if (mempool_resize(act->adapter->pool.sr_data,
8868c2ecf20Sopenharmony_ci			   act->adapter->stat_read_buf_num))
8878c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	if (mempool_resize(act->adapter->pool.status_read_req,
8908c2ecf20Sopenharmony_ci			   act->adapter->stat_read_buf_num))
8918c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num);
8948c2ecf20Sopenharmony_ci	if (zfcp_status_read_refill(act->adapter))
8958c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	return ZFCP_ERP_SUCCEEDED;
8988c2ecf20Sopenharmony_ci}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_cistatic void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act)
9018c2ecf20Sopenharmony_ci{
9028c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = act->adapter;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	/* close queues to ensure that buffers are not accessed by adapter */
9058c2ecf20Sopenharmony_ci	zfcp_qdio_close(adapter->qdio);
9068c2ecf20Sopenharmony_ci	zfcp_fsf_req_dismiss_all(adapter);
9078c2ecf20Sopenharmony_ci	adapter->fsf_req_seq_no = 0;
9088c2ecf20Sopenharmony_ci	zfcp_fc_wka_ports_force_offline(adapter->gs);
9098c2ecf20Sopenharmony_ci	/* all ports and LUNs are closed */
9108c2ecf20Sopenharmony_ci	zfcp_erp_clear_adapter_status(adapter, ZFCP_STATUS_COMMON_OPEN);
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	atomic_andnot(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
9138c2ecf20Sopenharmony_ci			  ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
9148c2ecf20Sopenharmony_ci}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_adapter_strategy_open(
9178c2ecf20Sopenharmony_ci	struct zfcp_erp_action *act)
9188c2ecf20Sopenharmony_ci{
9198c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = act->adapter;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	if (zfcp_qdio_open(adapter->qdio)) {
9228c2ecf20Sopenharmony_ci		atomic_andnot(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
9238c2ecf20Sopenharmony_ci				  ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
9248c2ecf20Sopenharmony_ci				  &adapter->status);
9258c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	if (zfcp_erp_adapter_strategy_open_fsf(act)) {
9298c2ecf20Sopenharmony_ci		zfcp_erp_adapter_strategy_close(act);
9308c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
9318c2ecf20Sopenharmony_ci	}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	atomic_or(ZFCP_STATUS_COMMON_OPEN, &adapter->status);
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	return ZFCP_ERP_SUCCEEDED;
9368c2ecf20Sopenharmony_ci}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_adapter_strategy(
9398c2ecf20Sopenharmony_ci	struct zfcp_erp_action *act)
9408c2ecf20Sopenharmony_ci{
9418c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = act->adapter;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN) {
9448c2ecf20Sopenharmony_ci		zfcp_erp_adapter_strategy_close(act);
9458c2ecf20Sopenharmony_ci		if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
9468c2ecf20Sopenharmony_ci			return ZFCP_ERP_EXIT;
9478c2ecf20Sopenharmony_ci	}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	if (zfcp_erp_adapter_strategy_open(act)) {
9508c2ecf20Sopenharmony_ci		ssleep(8);
9518c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
9528c2ecf20Sopenharmony_ci	}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	return ZFCP_ERP_SUCCEEDED;
9558c2ecf20Sopenharmony_ci}
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_port_forced_strategy_close(
9588c2ecf20Sopenharmony_ci	struct zfcp_erp_action *act)
9598c2ecf20Sopenharmony_ci{
9608c2ecf20Sopenharmony_ci	int retval;
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	retval = zfcp_fsf_close_physical_port(act);
9638c2ecf20Sopenharmony_ci	if (retval == -ENOMEM)
9648c2ecf20Sopenharmony_ci		return ZFCP_ERP_NOMEM;
9658c2ecf20Sopenharmony_ci	act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING;
9668c2ecf20Sopenharmony_ci	if (retval)
9678c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	return ZFCP_ERP_CONTINUES;
9708c2ecf20Sopenharmony_ci}
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_port_forced_strategy(
9738c2ecf20Sopenharmony_ci	struct zfcp_erp_action *erp_action)
9748c2ecf20Sopenharmony_ci{
9758c2ecf20Sopenharmony_ci	struct zfcp_port *port = erp_action->port;
9768c2ecf20Sopenharmony_ci	int status = atomic_read(&port->status);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	switch (erp_action->step) {
9798c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_UNINITIALIZED:
9808c2ecf20Sopenharmony_ci		if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) &&
9818c2ecf20Sopenharmony_ci		    (status & ZFCP_STATUS_COMMON_OPEN))
9828c2ecf20Sopenharmony_ci			return zfcp_erp_port_forced_strategy_close(erp_action);
9838c2ecf20Sopenharmony_ci		else
9848c2ecf20Sopenharmony_ci			return ZFCP_ERP_FAILED;
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
9878c2ecf20Sopenharmony_ci		if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN))
9888c2ecf20Sopenharmony_ci			return ZFCP_ERP_SUCCEEDED;
9898c2ecf20Sopenharmony_ci		break;
9908c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_PORT_CLOSING:
9918c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_PORT_OPENING:
9928c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_LUN_CLOSING:
9938c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_LUN_OPENING:
9948c2ecf20Sopenharmony_ci		/* NOP */
9958c2ecf20Sopenharmony_ci		break;
9968c2ecf20Sopenharmony_ci	}
9978c2ecf20Sopenharmony_ci	return ZFCP_ERP_FAILED;
9988c2ecf20Sopenharmony_ci}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_port_strategy_close(
10018c2ecf20Sopenharmony_ci	struct zfcp_erp_action *erp_action)
10028c2ecf20Sopenharmony_ci{
10038c2ecf20Sopenharmony_ci	int retval;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	retval = zfcp_fsf_close_port(erp_action);
10068c2ecf20Sopenharmony_ci	if (retval == -ENOMEM)
10078c2ecf20Sopenharmony_ci		return ZFCP_ERP_NOMEM;
10088c2ecf20Sopenharmony_ci	erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING;
10098c2ecf20Sopenharmony_ci	if (retval)
10108c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
10118c2ecf20Sopenharmony_ci	return ZFCP_ERP_CONTINUES;
10128c2ecf20Sopenharmony_ci}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_port_strategy_open_port(
10158c2ecf20Sopenharmony_ci	struct zfcp_erp_action *erp_action)
10168c2ecf20Sopenharmony_ci{
10178c2ecf20Sopenharmony_ci	int retval;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	retval = zfcp_fsf_open_port(erp_action);
10208c2ecf20Sopenharmony_ci	if (retval == -ENOMEM)
10218c2ecf20Sopenharmony_ci		return ZFCP_ERP_NOMEM;
10228c2ecf20Sopenharmony_ci	erp_action->step = ZFCP_ERP_STEP_PORT_OPENING;
10238c2ecf20Sopenharmony_ci	if (retval)
10248c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
10258c2ecf20Sopenharmony_ci	return ZFCP_ERP_CONTINUES;
10268c2ecf20Sopenharmony_ci}
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_cistatic int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
10298c2ecf20Sopenharmony_ci{
10308c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = act->adapter;
10318c2ecf20Sopenharmony_ci	struct zfcp_port *port = act->port;
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	if (port->wwpn != adapter->peer_wwpn) {
10348c2ecf20Sopenharmony_ci		zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED);
10358c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
10368c2ecf20Sopenharmony_ci	}
10378c2ecf20Sopenharmony_ci	port->d_id = adapter->peer_d_id;
10388c2ecf20Sopenharmony_ci	return zfcp_erp_port_strategy_open_port(act);
10398c2ecf20Sopenharmony_ci}
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_port_strategy_open_common(
10428c2ecf20Sopenharmony_ci	struct zfcp_erp_action *act)
10438c2ecf20Sopenharmony_ci{
10448c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = act->adapter;
10458c2ecf20Sopenharmony_ci	struct zfcp_port *port = act->port;
10468c2ecf20Sopenharmony_ci	int p_status = atomic_read(&port->status);
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	switch (act->step) {
10498c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_UNINITIALIZED:
10508c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
10518c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_PORT_CLOSING:
10528c2ecf20Sopenharmony_ci		if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
10538c2ecf20Sopenharmony_ci			return zfcp_erp_open_ptp_port(act);
10548c2ecf20Sopenharmony_ci		if (!port->d_id) {
10558c2ecf20Sopenharmony_ci			zfcp_fc_trigger_did_lookup(port);
10568c2ecf20Sopenharmony_ci			return ZFCP_ERP_EXIT;
10578c2ecf20Sopenharmony_ci		}
10588c2ecf20Sopenharmony_ci		return zfcp_erp_port_strategy_open_port(act);
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_PORT_OPENING:
10618c2ecf20Sopenharmony_ci		/* D_ID might have changed during open */
10628c2ecf20Sopenharmony_ci		if (p_status & ZFCP_STATUS_COMMON_OPEN) {
10638c2ecf20Sopenharmony_ci			if (!port->d_id) {
10648c2ecf20Sopenharmony_ci				zfcp_fc_trigger_did_lookup(port);
10658c2ecf20Sopenharmony_ci				return ZFCP_ERP_EXIT;
10668c2ecf20Sopenharmony_ci			}
10678c2ecf20Sopenharmony_ci			return ZFCP_ERP_SUCCEEDED;
10688c2ecf20Sopenharmony_ci		}
10698c2ecf20Sopenharmony_ci		if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
10708c2ecf20Sopenharmony_ci			port->d_id = 0;
10718c2ecf20Sopenharmony_ci			return ZFCP_ERP_FAILED;
10728c2ecf20Sopenharmony_ci		}
10738c2ecf20Sopenharmony_ci		/* no early return otherwise, continue after switch case */
10748c2ecf20Sopenharmony_ci		break;
10758c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_LUN_CLOSING:
10768c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_LUN_OPENING:
10778c2ecf20Sopenharmony_ci		/* NOP */
10788c2ecf20Sopenharmony_ci		break;
10798c2ecf20Sopenharmony_ci	}
10808c2ecf20Sopenharmony_ci	return ZFCP_ERP_FAILED;
10818c2ecf20Sopenharmony_ci}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_port_strategy(
10848c2ecf20Sopenharmony_ci	struct zfcp_erp_action *erp_action)
10858c2ecf20Sopenharmony_ci{
10868c2ecf20Sopenharmony_ci	struct zfcp_port *port = erp_action->port;
10878c2ecf20Sopenharmony_ci	int p_status = atomic_read(&port->status);
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	if ((p_status & ZFCP_STATUS_COMMON_NOESC) &&
10908c2ecf20Sopenharmony_ci	    !(p_status & ZFCP_STATUS_COMMON_OPEN))
10918c2ecf20Sopenharmony_ci		goto close_init_done;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	switch (erp_action->step) {
10948c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_UNINITIALIZED:
10958c2ecf20Sopenharmony_ci		if (p_status & ZFCP_STATUS_COMMON_OPEN)
10968c2ecf20Sopenharmony_ci			return zfcp_erp_port_strategy_close(erp_action);
10978c2ecf20Sopenharmony_ci		break;
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_PORT_CLOSING:
11008c2ecf20Sopenharmony_ci		if (p_status & ZFCP_STATUS_COMMON_OPEN)
11018c2ecf20Sopenharmony_ci			return ZFCP_ERP_FAILED;
11028c2ecf20Sopenharmony_ci		break;
11038c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
11048c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_PORT_OPENING:
11058c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_LUN_CLOSING:
11068c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_LUN_OPENING:
11078c2ecf20Sopenharmony_ci		/* NOP */
11088c2ecf20Sopenharmony_ci		break;
11098c2ecf20Sopenharmony_ci	}
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ciclose_init_done:
11128c2ecf20Sopenharmony_ci	if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
11138c2ecf20Sopenharmony_ci		return ZFCP_ERP_EXIT;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	return zfcp_erp_port_strategy_open_common(erp_action);
11168c2ecf20Sopenharmony_ci}
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_cistatic void zfcp_erp_lun_strategy_clearstati(struct scsi_device *sdev)
11198c2ecf20Sopenharmony_ci{
11208c2ecf20Sopenharmony_ci	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	atomic_andnot(ZFCP_STATUS_COMMON_ACCESS_DENIED,
11238c2ecf20Sopenharmony_ci			  &zfcp_sdev->status);
11248c2ecf20Sopenharmony_ci}
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_lun_strategy_close(
11278c2ecf20Sopenharmony_ci	struct zfcp_erp_action *erp_action)
11288c2ecf20Sopenharmony_ci{
11298c2ecf20Sopenharmony_ci	int retval = zfcp_fsf_close_lun(erp_action);
11308c2ecf20Sopenharmony_ci	if (retval == -ENOMEM)
11318c2ecf20Sopenharmony_ci		return ZFCP_ERP_NOMEM;
11328c2ecf20Sopenharmony_ci	erp_action->step = ZFCP_ERP_STEP_LUN_CLOSING;
11338c2ecf20Sopenharmony_ci	if (retval)
11348c2ecf20Sopenharmony_ci		return ZFCP_ERP_FAILED;
11358c2ecf20Sopenharmony_ci	return ZFCP_ERP_CONTINUES;
11368c2ecf20Sopenharmony_ci}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_lun_strategy_open(
11398c2ecf20Sopenharmony_ci	struct zfcp_erp_action *erp_action)
11408c2ecf20Sopenharmony_ci{
11418c2ecf20Sopenharmony_ci	int retval = zfcp_fsf_open_lun(erp_action);
11428c2ecf20Sopenharmony_ci	if (retval == -ENOMEM)
11438c2ecf20Sopenharmony_ci		return ZFCP_ERP_NOMEM;
11448c2ecf20Sopenharmony_ci	erp_action->step = ZFCP_ERP_STEP_LUN_OPENING;
11458c2ecf20Sopenharmony_ci	if (retval)
11468c2ecf20Sopenharmony_ci		return  ZFCP_ERP_FAILED;
11478c2ecf20Sopenharmony_ci	return ZFCP_ERP_CONTINUES;
11488c2ecf20Sopenharmony_ci}
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_lun_strategy(
11518c2ecf20Sopenharmony_ci	struct zfcp_erp_action *erp_action)
11528c2ecf20Sopenharmony_ci{
11538c2ecf20Sopenharmony_ci	struct scsi_device *sdev = erp_action->sdev;
11548c2ecf20Sopenharmony_ci	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	switch (erp_action->step) {
11578c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_UNINITIALIZED:
11588c2ecf20Sopenharmony_ci		zfcp_erp_lun_strategy_clearstati(sdev);
11598c2ecf20Sopenharmony_ci		if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
11608c2ecf20Sopenharmony_ci			return zfcp_erp_lun_strategy_close(erp_action);
11618c2ecf20Sopenharmony_ci		/* already closed */
11628c2ecf20Sopenharmony_ci		fallthrough;
11638c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_LUN_CLOSING:
11648c2ecf20Sopenharmony_ci		if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
11658c2ecf20Sopenharmony_ci			return ZFCP_ERP_FAILED;
11668c2ecf20Sopenharmony_ci		if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
11678c2ecf20Sopenharmony_ci			return ZFCP_ERP_EXIT;
11688c2ecf20Sopenharmony_ci		return zfcp_erp_lun_strategy_open(erp_action);
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_LUN_OPENING:
11718c2ecf20Sopenharmony_ci		if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
11728c2ecf20Sopenharmony_ci			return ZFCP_ERP_SUCCEEDED;
11738c2ecf20Sopenharmony_ci		break;
11748c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
11758c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_PORT_CLOSING:
11768c2ecf20Sopenharmony_ci	case ZFCP_ERP_STEP_PORT_OPENING:
11778c2ecf20Sopenharmony_ci		/* NOP */
11788c2ecf20Sopenharmony_ci		break;
11798c2ecf20Sopenharmony_ci	}
11808c2ecf20Sopenharmony_ci	return ZFCP_ERP_FAILED;
11818c2ecf20Sopenharmony_ci}
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_strategy_check_lun(
11848c2ecf20Sopenharmony_ci	struct scsi_device *sdev, enum zfcp_erp_act_result result)
11858c2ecf20Sopenharmony_ci{
11868c2ecf20Sopenharmony_ci	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	switch (result) {
11898c2ecf20Sopenharmony_ci	case ZFCP_ERP_SUCCEEDED :
11908c2ecf20Sopenharmony_ci		atomic_set(&zfcp_sdev->erp_counter, 0);
11918c2ecf20Sopenharmony_ci		zfcp_erp_lun_unblock(sdev);
11928c2ecf20Sopenharmony_ci		break;
11938c2ecf20Sopenharmony_ci	case ZFCP_ERP_FAILED :
11948c2ecf20Sopenharmony_ci		atomic_inc(&zfcp_sdev->erp_counter);
11958c2ecf20Sopenharmony_ci		if (atomic_read(&zfcp_sdev->erp_counter) > ZFCP_MAX_ERPS) {
11968c2ecf20Sopenharmony_ci			dev_err(&zfcp_sdev->port->adapter->ccw_device->dev,
11978c2ecf20Sopenharmony_ci				"ERP failed for LUN 0x%016Lx on "
11988c2ecf20Sopenharmony_ci				"port 0x%016Lx\n",
11998c2ecf20Sopenharmony_ci				(unsigned long long)zfcp_scsi_dev_lun(sdev),
12008c2ecf20Sopenharmony_ci				(unsigned long long)zfcp_sdev->port->wwpn);
12018c2ecf20Sopenharmony_ci			zfcp_erp_set_lun_status(sdev,
12028c2ecf20Sopenharmony_ci						ZFCP_STATUS_COMMON_ERP_FAILED);
12038c2ecf20Sopenharmony_ci		}
12048c2ecf20Sopenharmony_ci		break;
12058c2ecf20Sopenharmony_ci	case ZFCP_ERP_CONTINUES:
12068c2ecf20Sopenharmony_ci	case ZFCP_ERP_EXIT:
12078c2ecf20Sopenharmony_ci	case ZFCP_ERP_DISMISSED:
12088c2ecf20Sopenharmony_ci	case ZFCP_ERP_NOMEM:
12098c2ecf20Sopenharmony_ci		/* NOP */
12108c2ecf20Sopenharmony_ci		break;
12118c2ecf20Sopenharmony_ci	}
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
12148c2ecf20Sopenharmony_ci		zfcp_erp_lun_block(sdev, 0);
12158c2ecf20Sopenharmony_ci		result = ZFCP_ERP_EXIT;
12168c2ecf20Sopenharmony_ci	}
12178c2ecf20Sopenharmony_ci	return result;
12188c2ecf20Sopenharmony_ci}
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_strategy_check_port(
12218c2ecf20Sopenharmony_ci	struct zfcp_port *port, enum zfcp_erp_act_result result)
12228c2ecf20Sopenharmony_ci{
12238c2ecf20Sopenharmony_ci	switch (result) {
12248c2ecf20Sopenharmony_ci	case ZFCP_ERP_SUCCEEDED :
12258c2ecf20Sopenharmony_ci		atomic_set(&port->erp_counter, 0);
12268c2ecf20Sopenharmony_ci		zfcp_erp_port_unblock(port);
12278c2ecf20Sopenharmony_ci		break;
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	case ZFCP_ERP_FAILED :
12308c2ecf20Sopenharmony_ci		if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) {
12318c2ecf20Sopenharmony_ci			zfcp_erp_port_block(port, 0);
12328c2ecf20Sopenharmony_ci			result = ZFCP_ERP_EXIT;
12338c2ecf20Sopenharmony_ci		}
12348c2ecf20Sopenharmony_ci		atomic_inc(&port->erp_counter);
12358c2ecf20Sopenharmony_ci		if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
12368c2ecf20Sopenharmony_ci			dev_err(&port->adapter->ccw_device->dev,
12378c2ecf20Sopenharmony_ci				"ERP failed for remote port 0x%016Lx\n",
12388c2ecf20Sopenharmony_ci				(unsigned long long)port->wwpn);
12398c2ecf20Sopenharmony_ci			zfcp_erp_set_port_status(port,
12408c2ecf20Sopenharmony_ci					 ZFCP_STATUS_COMMON_ERP_FAILED);
12418c2ecf20Sopenharmony_ci		}
12428c2ecf20Sopenharmony_ci		break;
12438c2ecf20Sopenharmony_ci	case ZFCP_ERP_CONTINUES:
12448c2ecf20Sopenharmony_ci	case ZFCP_ERP_EXIT:
12458c2ecf20Sopenharmony_ci	case ZFCP_ERP_DISMISSED:
12468c2ecf20Sopenharmony_ci	case ZFCP_ERP_NOMEM:
12478c2ecf20Sopenharmony_ci		/* NOP */
12488c2ecf20Sopenharmony_ci		break;
12498c2ecf20Sopenharmony_ci	}
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
12528c2ecf20Sopenharmony_ci		zfcp_erp_port_block(port, 0);
12538c2ecf20Sopenharmony_ci		result = ZFCP_ERP_EXIT;
12548c2ecf20Sopenharmony_ci	}
12558c2ecf20Sopenharmony_ci	return result;
12568c2ecf20Sopenharmony_ci}
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_strategy_check_adapter(
12598c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter, enum zfcp_erp_act_result result)
12608c2ecf20Sopenharmony_ci{
12618c2ecf20Sopenharmony_ci	switch (result) {
12628c2ecf20Sopenharmony_ci	case ZFCP_ERP_SUCCEEDED :
12638c2ecf20Sopenharmony_ci		atomic_set(&adapter->erp_counter, 0);
12648c2ecf20Sopenharmony_ci		zfcp_erp_adapter_unblock(adapter);
12658c2ecf20Sopenharmony_ci		break;
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	case ZFCP_ERP_FAILED :
12688c2ecf20Sopenharmony_ci		atomic_inc(&adapter->erp_counter);
12698c2ecf20Sopenharmony_ci		if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) {
12708c2ecf20Sopenharmony_ci			dev_err(&adapter->ccw_device->dev,
12718c2ecf20Sopenharmony_ci				"ERP cannot recover an error "
12728c2ecf20Sopenharmony_ci				"on the FCP device\n");
12738c2ecf20Sopenharmony_ci			zfcp_erp_set_adapter_status(adapter,
12748c2ecf20Sopenharmony_ci					    ZFCP_STATUS_COMMON_ERP_FAILED);
12758c2ecf20Sopenharmony_ci		}
12768c2ecf20Sopenharmony_ci		break;
12778c2ecf20Sopenharmony_ci	case ZFCP_ERP_CONTINUES:
12788c2ecf20Sopenharmony_ci	case ZFCP_ERP_EXIT:
12798c2ecf20Sopenharmony_ci	case ZFCP_ERP_DISMISSED:
12808c2ecf20Sopenharmony_ci	case ZFCP_ERP_NOMEM:
12818c2ecf20Sopenharmony_ci		/* NOP */
12828c2ecf20Sopenharmony_ci		break;
12838c2ecf20Sopenharmony_ci	}
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
12868c2ecf20Sopenharmony_ci		zfcp_erp_adapter_block(adapter, 0);
12878c2ecf20Sopenharmony_ci		result = ZFCP_ERP_EXIT;
12888c2ecf20Sopenharmony_ci	}
12898c2ecf20Sopenharmony_ci	return result;
12908c2ecf20Sopenharmony_ci}
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_strategy_check_target(
12938c2ecf20Sopenharmony_ci	struct zfcp_erp_action *erp_action, enum zfcp_erp_act_result result)
12948c2ecf20Sopenharmony_ci{
12958c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = erp_action->adapter;
12968c2ecf20Sopenharmony_ci	struct zfcp_port *port = erp_action->port;
12978c2ecf20Sopenharmony_ci	struct scsi_device *sdev = erp_action->sdev;
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci	switch (erp_action->type) {
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_LUN:
13028c2ecf20Sopenharmony_ci		result = zfcp_erp_strategy_check_lun(sdev, result);
13038c2ecf20Sopenharmony_ci		break;
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
13068c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT:
13078c2ecf20Sopenharmony_ci		result = zfcp_erp_strategy_check_port(port, result);
13088c2ecf20Sopenharmony_ci		break;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
13118c2ecf20Sopenharmony_ci		result = zfcp_erp_strategy_check_adapter(adapter, result);
13128c2ecf20Sopenharmony_ci		break;
13138c2ecf20Sopenharmony_ci	}
13148c2ecf20Sopenharmony_ci	return result;
13158c2ecf20Sopenharmony_ci}
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_cistatic int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status)
13188c2ecf20Sopenharmony_ci{
13198c2ecf20Sopenharmony_ci	int status = atomic_read(target_status);
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	if ((status & ZFCP_STATUS_COMMON_RUNNING) &&
13228c2ecf20Sopenharmony_ci	    (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
13238c2ecf20Sopenharmony_ci		return 1; /* take it online */
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	if (!(status & ZFCP_STATUS_COMMON_RUNNING) &&
13268c2ecf20Sopenharmony_ci	    !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
13278c2ecf20Sopenharmony_ci		return 1; /* take it offline */
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	return 0;
13308c2ecf20Sopenharmony_ci}
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_strategy_statechange(
13338c2ecf20Sopenharmony_ci	struct zfcp_erp_action *act, enum zfcp_erp_act_result result)
13348c2ecf20Sopenharmony_ci{
13358c2ecf20Sopenharmony_ci	enum zfcp_erp_act_type type = act->type;
13368c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = act->adapter;
13378c2ecf20Sopenharmony_ci	struct zfcp_port *port = act->port;
13388c2ecf20Sopenharmony_ci	struct scsi_device *sdev = act->sdev;
13398c2ecf20Sopenharmony_ci	struct zfcp_scsi_dev *zfcp_sdev;
13408c2ecf20Sopenharmony_ci	u32 erp_status = act->status;
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	switch (type) {
13438c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
13448c2ecf20Sopenharmony_ci		if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) {
13458c2ecf20Sopenharmony_ci			_zfcp_erp_adapter_reopen(adapter,
13468c2ecf20Sopenharmony_ci						 ZFCP_STATUS_COMMON_ERP_FAILED,
13478c2ecf20Sopenharmony_ci						 "ersscg1");
13488c2ecf20Sopenharmony_ci			return ZFCP_ERP_EXIT;
13498c2ecf20Sopenharmony_ci		}
13508c2ecf20Sopenharmony_ci		break;
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
13538c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT:
13548c2ecf20Sopenharmony_ci		if (zfcp_erp_strat_change_det(&port->status, erp_status)) {
13558c2ecf20Sopenharmony_ci			_zfcp_erp_port_reopen(port,
13568c2ecf20Sopenharmony_ci					      ZFCP_STATUS_COMMON_ERP_FAILED,
13578c2ecf20Sopenharmony_ci					      "ersscg2");
13588c2ecf20Sopenharmony_ci			return ZFCP_ERP_EXIT;
13598c2ecf20Sopenharmony_ci		}
13608c2ecf20Sopenharmony_ci		break;
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_LUN:
13638c2ecf20Sopenharmony_ci		zfcp_sdev = sdev_to_zfcp(sdev);
13648c2ecf20Sopenharmony_ci		if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) {
13658c2ecf20Sopenharmony_ci			_zfcp_erp_lun_reopen(sdev,
13668c2ecf20Sopenharmony_ci					     ZFCP_STATUS_COMMON_ERP_FAILED,
13678c2ecf20Sopenharmony_ci					     "ersscg3", 0);
13688c2ecf20Sopenharmony_ci			return ZFCP_ERP_EXIT;
13698c2ecf20Sopenharmony_ci		}
13708c2ecf20Sopenharmony_ci		break;
13718c2ecf20Sopenharmony_ci	}
13728c2ecf20Sopenharmony_ci	return result;
13738c2ecf20Sopenharmony_ci}
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_cistatic void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
13768c2ecf20Sopenharmony_ci{
13778c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = erp_action->adapter;
13788c2ecf20Sopenharmony_ci	struct zfcp_scsi_dev *zfcp_sdev;
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	adapter->erp_total_count--;
13818c2ecf20Sopenharmony_ci	if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
13828c2ecf20Sopenharmony_ci		adapter->erp_low_mem_count--;
13838c2ecf20Sopenharmony_ci		erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
13848c2ecf20Sopenharmony_ci	}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	list_del(&erp_action->list);
13878c2ecf20Sopenharmony_ci	zfcp_dbf_rec_run("eractd1", erp_action);
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	switch (erp_action->type) {
13908c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_LUN:
13918c2ecf20Sopenharmony_ci		zfcp_sdev = sdev_to_zfcp(erp_action->sdev);
13928c2ecf20Sopenharmony_ci		atomic_andnot(ZFCP_STATUS_COMMON_ERP_INUSE,
13938c2ecf20Sopenharmony_ci				  &zfcp_sdev->status);
13948c2ecf20Sopenharmony_ci		break;
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
13978c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT:
13988c2ecf20Sopenharmony_ci		atomic_andnot(ZFCP_STATUS_COMMON_ERP_INUSE,
13998c2ecf20Sopenharmony_ci				  &erp_action->port->status);
14008c2ecf20Sopenharmony_ci		break;
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
14038c2ecf20Sopenharmony_ci		atomic_andnot(ZFCP_STATUS_COMMON_ERP_INUSE,
14048c2ecf20Sopenharmony_ci				  &erp_action->adapter->status);
14058c2ecf20Sopenharmony_ci		break;
14068c2ecf20Sopenharmony_ci	}
14078c2ecf20Sopenharmony_ci}
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci/**
14108c2ecf20Sopenharmony_ci * zfcp_erp_try_rport_unblock - unblock rport if no more/new recovery
14118c2ecf20Sopenharmony_ci * @port: zfcp_port whose fc_rport we should try to unblock
14128c2ecf20Sopenharmony_ci */
14138c2ecf20Sopenharmony_cistatic void zfcp_erp_try_rport_unblock(struct zfcp_port *port)
14148c2ecf20Sopenharmony_ci{
14158c2ecf20Sopenharmony_ci	unsigned long flags;
14168c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = port->adapter;
14178c2ecf20Sopenharmony_ci	int port_status;
14188c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = adapter->scsi_host;
14198c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	write_lock_irqsave(&adapter->erp_lock, flags);
14228c2ecf20Sopenharmony_ci	port_status = atomic_read(&port->status);
14238c2ecf20Sopenharmony_ci	if ((port_status & ZFCP_STATUS_COMMON_UNBLOCKED)    == 0 ||
14248c2ecf20Sopenharmony_ci	    (port_status & (ZFCP_STATUS_COMMON_ERP_INUSE |
14258c2ecf20Sopenharmony_ci			    ZFCP_STATUS_COMMON_ERP_FAILED)) != 0) {
14268c2ecf20Sopenharmony_ci		/* new ERP of severity >= port triggered elsewhere meanwhile or
14278c2ecf20Sopenharmony_ci		 * local link down (adapter erp_failed but not clear unblock)
14288c2ecf20Sopenharmony_ci		 */
14298c2ecf20Sopenharmony_ci		zfcp_dbf_rec_run_lvl(4, "ertru_p", &port->erp_action);
14308c2ecf20Sopenharmony_ci		write_unlock_irqrestore(&adapter->erp_lock, flags);
14318c2ecf20Sopenharmony_ci		return;
14328c2ecf20Sopenharmony_ci	}
14338c2ecf20Sopenharmony_ci	spin_lock(shost->host_lock);
14348c2ecf20Sopenharmony_ci	__shost_for_each_device(sdev, shost) {
14358c2ecf20Sopenharmony_ci		struct zfcp_scsi_dev *zsdev = sdev_to_zfcp(sdev);
14368c2ecf20Sopenharmony_ci		int lun_status;
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci		if (sdev->sdev_state == SDEV_DEL ||
14398c2ecf20Sopenharmony_ci		    sdev->sdev_state == SDEV_CANCEL)
14408c2ecf20Sopenharmony_ci			continue;
14418c2ecf20Sopenharmony_ci		if (zsdev->port != port)
14428c2ecf20Sopenharmony_ci			continue;
14438c2ecf20Sopenharmony_ci		/* LUN under port of interest */
14448c2ecf20Sopenharmony_ci		lun_status = atomic_read(&zsdev->status);
14458c2ecf20Sopenharmony_ci		if ((lun_status & ZFCP_STATUS_COMMON_ERP_FAILED) != 0)
14468c2ecf20Sopenharmony_ci			continue; /* unblock rport despite failed LUNs */
14478c2ecf20Sopenharmony_ci		/* LUN recovery not given up yet [maybe follow-up pending] */
14488c2ecf20Sopenharmony_ci		if ((lun_status & ZFCP_STATUS_COMMON_UNBLOCKED) == 0 ||
14498c2ecf20Sopenharmony_ci		    (lun_status & ZFCP_STATUS_COMMON_ERP_INUSE) != 0) {
14508c2ecf20Sopenharmony_ci			/* LUN blocked:
14518c2ecf20Sopenharmony_ci			 * not yet unblocked [LUN recovery pending]
14528c2ecf20Sopenharmony_ci			 * or meanwhile blocked [new LUN recovery triggered]
14538c2ecf20Sopenharmony_ci			 */
14548c2ecf20Sopenharmony_ci			zfcp_dbf_rec_run_lvl(4, "ertru_l", &zsdev->erp_action);
14558c2ecf20Sopenharmony_ci			spin_unlock(shost->host_lock);
14568c2ecf20Sopenharmony_ci			write_unlock_irqrestore(&adapter->erp_lock, flags);
14578c2ecf20Sopenharmony_ci			return;
14588c2ecf20Sopenharmony_ci		}
14598c2ecf20Sopenharmony_ci	}
14608c2ecf20Sopenharmony_ci	/* now port has no child or all children have completed recovery,
14618c2ecf20Sopenharmony_ci	 * and no ERP of severity >= port was meanwhile triggered elsewhere
14628c2ecf20Sopenharmony_ci	 */
14638c2ecf20Sopenharmony_ci	zfcp_scsi_schedule_rport_register(port);
14648c2ecf20Sopenharmony_ci	spin_unlock(shost->host_lock);
14658c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&adapter->erp_lock, flags);
14668c2ecf20Sopenharmony_ci}
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_cistatic void zfcp_erp_action_cleanup(struct zfcp_erp_action *act,
14698c2ecf20Sopenharmony_ci				    enum zfcp_erp_act_result result)
14708c2ecf20Sopenharmony_ci{
14718c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = act->adapter;
14728c2ecf20Sopenharmony_ci	struct zfcp_port *port = act->port;
14738c2ecf20Sopenharmony_ci	struct scsi_device *sdev = act->sdev;
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	switch (act->type) {
14768c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_LUN:
14778c2ecf20Sopenharmony_ci		if (!(act->status & ZFCP_STATUS_ERP_NO_REF))
14788c2ecf20Sopenharmony_ci			scsi_device_put(sdev);
14798c2ecf20Sopenharmony_ci		zfcp_erp_try_rport_unblock(port);
14808c2ecf20Sopenharmony_ci		break;
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT:
14838c2ecf20Sopenharmony_ci		/* This switch case might also happen after a forced reopen
14848c2ecf20Sopenharmony_ci		 * was successfully done and thus overwritten with a new
14858c2ecf20Sopenharmony_ci		 * non-forced reopen at `ersfs_2'. In this case, we must not
14868c2ecf20Sopenharmony_ci		 * do the clean-up of the non-forced version.
14878c2ecf20Sopenharmony_ci		 */
14888c2ecf20Sopenharmony_ci		if (act->step != ZFCP_ERP_STEP_UNINITIALIZED)
14898c2ecf20Sopenharmony_ci			if (result == ZFCP_ERP_SUCCEEDED)
14908c2ecf20Sopenharmony_ci				zfcp_erp_try_rport_unblock(port);
14918c2ecf20Sopenharmony_ci		fallthrough;
14928c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
14938c2ecf20Sopenharmony_ci		put_device(&port->dev);
14948c2ecf20Sopenharmony_ci		break;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
14978c2ecf20Sopenharmony_ci		if (result == ZFCP_ERP_SUCCEEDED) {
14988c2ecf20Sopenharmony_ci			register_service_level(&adapter->service_level);
14998c2ecf20Sopenharmony_ci			zfcp_fc_conditional_port_scan(adapter);
15008c2ecf20Sopenharmony_ci			queue_work(adapter->work_queue, &adapter->ns_up_work);
15018c2ecf20Sopenharmony_ci		} else
15028c2ecf20Sopenharmony_ci			unregister_service_level(&adapter->service_level);
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci		kref_put(&adapter->ref, zfcp_adapter_release);
15058c2ecf20Sopenharmony_ci		break;
15068c2ecf20Sopenharmony_ci	}
15078c2ecf20Sopenharmony_ci}
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_strategy_do_action(
15108c2ecf20Sopenharmony_ci	struct zfcp_erp_action *erp_action)
15118c2ecf20Sopenharmony_ci{
15128c2ecf20Sopenharmony_ci	switch (erp_action->type) {
15138c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
15148c2ecf20Sopenharmony_ci		return zfcp_erp_adapter_strategy(erp_action);
15158c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
15168c2ecf20Sopenharmony_ci		return zfcp_erp_port_forced_strategy(erp_action);
15178c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_PORT:
15188c2ecf20Sopenharmony_ci		return zfcp_erp_port_strategy(erp_action);
15198c2ecf20Sopenharmony_ci	case ZFCP_ERP_ACTION_REOPEN_LUN:
15208c2ecf20Sopenharmony_ci		return zfcp_erp_lun_strategy(erp_action);
15218c2ecf20Sopenharmony_ci	}
15228c2ecf20Sopenharmony_ci	return ZFCP_ERP_FAILED;
15238c2ecf20Sopenharmony_ci}
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_cistatic enum zfcp_erp_act_result zfcp_erp_strategy(
15268c2ecf20Sopenharmony_ci	struct zfcp_erp_action *erp_action)
15278c2ecf20Sopenharmony_ci{
15288c2ecf20Sopenharmony_ci	enum zfcp_erp_act_result result;
15298c2ecf20Sopenharmony_ci	unsigned long flags;
15308c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = erp_action->adapter;
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	kref_get(&adapter->ref);
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	write_lock_irqsave(&adapter->erp_lock, flags);
15358c2ecf20Sopenharmony_ci	zfcp_erp_strategy_check_fsfreq(erp_action);
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
15388c2ecf20Sopenharmony_ci		zfcp_erp_action_dequeue(erp_action);
15398c2ecf20Sopenharmony_ci		result = ZFCP_ERP_DISMISSED;
15408c2ecf20Sopenharmony_ci		goto unlock;
15418c2ecf20Sopenharmony_ci	}
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci	if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
15448c2ecf20Sopenharmony_ci		result = ZFCP_ERP_FAILED;
15458c2ecf20Sopenharmony_ci		goto check_target;
15468c2ecf20Sopenharmony_ci	}
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	zfcp_erp_action_to_running(erp_action);
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	/* no lock to allow for blocking operations */
15518c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&adapter->erp_lock, flags);
15528c2ecf20Sopenharmony_ci	result = zfcp_erp_strategy_do_action(erp_action);
15538c2ecf20Sopenharmony_ci	write_lock_irqsave(&adapter->erp_lock, flags);
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED)
15568c2ecf20Sopenharmony_ci		result = ZFCP_ERP_CONTINUES;
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	switch (result) {
15598c2ecf20Sopenharmony_ci	case ZFCP_ERP_NOMEM:
15608c2ecf20Sopenharmony_ci		if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) {
15618c2ecf20Sopenharmony_ci			++adapter->erp_low_mem_count;
15628c2ecf20Sopenharmony_ci			erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
15638c2ecf20Sopenharmony_ci		}
15648c2ecf20Sopenharmony_ci		if (adapter->erp_total_count == adapter->erp_low_mem_count)
15658c2ecf20Sopenharmony_ci			_zfcp_erp_adapter_reopen(adapter, 0, "erstgy1");
15668c2ecf20Sopenharmony_ci		else {
15678c2ecf20Sopenharmony_ci			zfcp_erp_strategy_memwait(erp_action);
15688c2ecf20Sopenharmony_ci			result = ZFCP_ERP_CONTINUES;
15698c2ecf20Sopenharmony_ci		}
15708c2ecf20Sopenharmony_ci		goto unlock;
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	case ZFCP_ERP_CONTINUES:
15738c2ecf20Sopenharmony_ci		if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
15748c2ecf20Sopenharmony_ci			--adapter->erp_low_mem_count;
15758c2ecf20Sopenharmony_ci			erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
15768c2ecf20Sopenharmony_ci		}
15778c2ecf20Sopenharmony_ci		goto unlock;
15788c2ecf20Sopenharmony_ci	case ZFCP_ERP_SUCCEEDED:
15798c2ecf20Sopenharmony_ci	case ZFCP_ERP_FAILED:
15808c2ecf20Sopenharmony_ci	case ZFCP_ERP_EXIT:
15818c2ecf20Sopenharmony_ci	case ZFCP_ERP_DISMISSED:
15828c2ecf20Sopenharmony_ci		/* NOP */
15838c2ecf20Sopenharmony_ci		break;
15848c2ecf20Sopenharmony_ci	}
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_cicheck_target:
15878c2ecf20Sopenharmony_ci	result = zfcp_erp_strategy_check_target(erp_action, result);
15888c2ecf20Sopenharmony_ci	zfcp_erp_action_dequeue(erp_action);
15898c2ecf20Sopenharmony_ci	result = zfcp_erp_strategy_statechange(erp_action, result);
15908c2ecf20Sopenharmony_ci	if (result == ZFCP_ERP_EXIT)
15918c2ecf20Sopenharmony_ci		goto unlock;
15928c2ecf20Sopenharmony_ci	if (result == ZFCP_ERP_SUCCEEDED)
15938c2ecf20Sopenharmony_ci		zfcp_erp_strategy_followup_success(erp_action);
15948c2ecf20Sopenharmony_ci	if (result == ZFCP_ERP_FAILED)
15958c2ecf20Sopenharmony_ci		zfcp_erp_strategy_followup_failed(erp_action);
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci unlock:
15988c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&adapter->erp_lock, flags);
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci	if (result != ZFCP_ERP_CONTINUES)
16018c2ecf20Sopenharmony_ci		zfcp_erp_action_cleanup(erp_action, result);
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	kref_put(&adapter->ref, zfcp_adapter_release);
16048c2ecf20Sopenharmony_ci	return result;
16058c2ecf20Sopenharmony_ci}
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_cistatic int zfcp_erp_thread(void *data)
16088c2ecf20Sopenharmony_ci{
16098c2ecf20Sopenharmony_ci	struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
16108c2ecf20Sopenharmony_ci	struct zfcp_erp_action *act;
16118c2ecf20Sopenharmony_ci	unsigned long flags;
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	for (;;) {
16148c2ecf20Sopenharmony_ci		wait_event_interruptible(adapter->erp_ready_wq,
16158c2ecf20Sopenharmony_ci			   !list_empty(&adapter->erp_ready_head) ||
16168c2ecf20Sopenharmony_ci			   kthread_should_stop());
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci		if (kthread_should_stop())
16198c2ecf20Sopenharmony_ci			break;
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci		write_lock_irqsave(&adapter->erp_lock, flags);
16228c2ecf20Sopenharmony_ci		act = list_first_entry_or_null(&adapter->erp_ready_head,
16238c2ecf20Sopenharmony_ci					       struct zfcp_erp_action, list);
16248c2ecf20Sopenharmony_ci		write_unlock_irqrestore(&adapter->erp_lock, flags);
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci		if (act) {
16278c2ecf20Sopenharmony_ci			/* there is more to come after dismission, no notify */
16288c2ecf20Sopenharmony_ci			if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED)
16298c2ecf20Sopenharmony_ci				zfcp_erp_wakeup(adapter);
16308c2ecf20Sopenharmony_ci		}
16318c2ecf20Sopenharmony_ci	}
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	return 0;
16348c2ecf20Sopenharmony_ci}
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci/**
16378c2ecf20Sopenharmony_ci * zfcp_erp_thread_setup - Start ERP thread for adapter
16388c2ecf20Sopenharmony_ci * @adapter: Adapter to start the ERP thread for
16398c2ecf20Sopenharmony_ci *
16408c2ecf20Sopenharmony_ci * Return: 0 on success, or error code from kthread_run().
16418c2ecf20Sopenharmony_ci */
16428c2ecf20Sopenharmony_ciint zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
16438c2ecf20Sopenharmony_ci{
16448c2ecf20Sopenharmony_ci	struct task_struct *thread;
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	thread = kthread_run(zfcp_erp_thread, adapter, "zfcperp%s",
16478c2ecf20Sopenharmony_ci			     dev_name(&adapter->ccw_device->dev));
16488c2ecf20Sopenharmony_ci	if (IS_ERR(thread)) {
16498c2ecf20Sopenharmony_ci		dev_err(&adapter->ccw_device->dev,
16508c2ecf20Sopenharmony_ci			"Creating an ERP thread for the FCP device failed.\n");
16518c2ecf20Sopenharmony_ci		return PTR_ERR(thread);
16528c2ecf20Sopenharmony_ci	}
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	adapter->erp_thread = thread;
16558c2ecf20Sopenharmony_ci	return 0;
16568c2ecf20Sopenharmony_ci}
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci/**
16598c2ecf20Sopenharmony_ci * zfcp_erp_thread_kill - Stop ERP thread.
16608c2ecf20Sopenharmony_ci * @adapter: Adapter where the ERP thread should be stopped.
16618c2ecf20Sopenharmony_ci *
16628c2ecf20Sopenharmony_ci * The caller of this routine ensures that the specified adapter has
16638c2ecf20Sopenharmony_ci * been shut down and that this operation has been completed. Thus,
16648c2ecf20Sopenharmony_ci * there are no pending erp_actions which would need to be handled
16658c2ecf20Sopenharmony_ci * here.
16668c2ecf20Sopenharmony_ci */
16678c2ecf20Sopenharmony_civoid zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
16688c2ecf20Sopenharmony_ci{
16698c2ecf20Sopenharmony_ci	kthread_stop(adapter->erp_thread);
16708c2ecf20Sopenharmony_ci	adapter->erp_thread = NULL;
16718c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&adapter->erp_ready_head));
16728c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&adapter->erp_running_head));
16738c2ecf20Sopenharmony_ci}
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_ci/**
16768c2ecf20Sopenharmony_ci * zfcp_erp_wait - wait for completion of error recovery on an adapter
16778c2ecf20Sopenharmony_ci * @adapter: adapter for which to wait for completion of its error recovery
16788c2ecf20Sopenharmony_ci */
16798c2ecf20Sopenharmony_civoid zfcp_erp_wait(struct zfcp_adapter *adapter)
16808c2ecf20Sopenharmony_ci{
16818c2ecf20Sopenharmony_ci	wait_event(adapter->erp_done_wqh,
16828c2ecf20Sopenharmony_ci		   !(atomic_read(&adapter->status) &
16838c2ecf20Sopenharmony_ci			ZFCP_STATUS_ADAPTER_ERP_PENDING));
16848c2ecf20Sopenharmony_ci}
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci/**
16878c2ecf20Sopenharmony_ci * zfcp_erp_set_adapter_status - set adapter status bits
16888c2ecf20Sopenharmony_ci * @adapter: adapter to change the status
16898c2ecf20Sopenharmony_ci * @mask: status bits to change
16908c2ecf20Sopenharmony_ci *
16918c2ecf20Sopenharmony_ci * Changes in common status bits are propagated to attached ports and LUNs.
16928c2ecf20Sopenharmony_ci */
16938c2ecf20Sopenharmony_civoid zfcp_erp_set_adapter_status(struct zfcp_adapter *adapter, u32 mask)
16948c2ecf20Sopenharmony_ci{
16958c2ecf20Sopenharmony_ci	struct zfcp_port *port;
16968c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
16978c2ecf20Sopenharmony_ci	unsigned long flags;
16988c2ecf20Sopenharmony_ci	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci	atomic_or(mask, &adapter->status);
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	if (!common_mask)
17038c2ecf20Sopenharmony_ci		return;
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci	read_lock_irqsave(&adapter->port_list_lock, flags);
17068c2ecf20Sopenharmony_ci	list_for_each_entry(port, &adapter->port_list, list)
17078c2ecf20Sopenharmony_ci		atomic_or(common_mask, &port->status);
17088c2ecf20Sopenharmony_ci	read_unlock_irqrestore(&adapter->port_list_lock, flags);
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci	/*
17118c2ecf20Sopenharmony_ci	 * if `scsi_host` is missing, xconfig/xport data has never completed
17128c2ecf20Sopenharmony_ci	 * yet, so we can't access it, but there are also no SDEVs yet
17138c2ecf20Sopenharmony_ci	 */
17148c2ecf20Sopenharmony_ci	if (adapter->scsi_host == NULL)
17158c2ecf20Sopenharmony_ci		return;
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci	spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
17188c2ecf20Sopenharmony_ci	__shost_for_each_device(sdev, adapter->scsi_host)
17198c2ecf20Sopenharmony_ci		atomic_or(common_mask, &sdev_to_zfcp(sdev)->status);
17208c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
17218c2ecf20Sopenharmony_ci}
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci/**
17248c2ecf20Sopenharmony_ci * zfcp_erp_clear_adapter_status - clear adapter status bits
17258c2ecf20Sopenharmony_ci * @adapter: adapter to change the status
17268c2ecf20Sopenharmony_ci * @mask: status bits to change
17278c2ecf20Sopenharmony_ci *
17288c2ecf20Sopenharmony_ci * Changes in common status bits are propagated to attached ports and LUNs.
17298c2ecf20Sopenharmony_ci */
17308c2ecf20Sopenharmony_civoid zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask)
17318c2ecf20Sopenharmony_ci{
17328c2ecf20Sopenharmony_ci	struct zfcp_port *port;
17338c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
17348c2ecf20Sopenharmony_ci	unsigned long flags;
17358c2ecf20Sopenharmony_ci	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
17368c2ecf20Sopenharmony_ci	u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED;
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	atomic_andnot(mask, &adapter->status);
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	if (!common_mask)
17418c2ecf20Sopenharmony_ci		return;
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	if (clear_counter)
17448c2ecf20Sopenharmony_ci		atomic_set(&adapter->erp_counter, 0);
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	read_lock_irqsave(&adapter->port_list_lock, flags);
17478c2ecf20Sopenharmony_ci	list_for_each_entry(port, &adapter->port_list, list) {
17488c2ecf20Sopenharmony_ci		atomic_andnot(common_mask, &port->status);
17498c2ecf20Sopenharmony_ci		if (clear_counter)
17508c2ecf20Sopenharmony_ci			atomic_set(&port->erp_counter, 0);
17518c2ecf20Sopenharmony_ci	}
17528c2ecf20Sopenharmony_ci	read_unlock_irqrestore(&adapter->port_list_lock, flags);
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ci	/*
17558c2ecf20Sopenharmony_ci	 * if `scsi_host` is missing, xconfig/xport data has never completed
17568c2ecf20Sopenharmony_ci	 * yet, so we can't access it, but there are also no SDEVs yet
17578c2ecf20Sopenharmony_ci	 */
17588c2ecf20Sopenharmony_ci	if (adapter->scsi_host == NULL)
17598c2ecf20Sopenharmony_ci		return;
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
17628c2ecf20Sopenharmony_ci	__shost_for_each_device(sdev, adapter->scsi_host) {
17638c2ecf20Sopenharmony_ci		atomic_andnot(common_mask, &sdev_to_zfcp(sdev)->status);
17648c2ecf20Sopenharmony_ci		if (clear_counter)
17658c2ecf20Sopenharmony_ci			atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
17668c2ecf20Sopenharmony_ci	}
17678c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
17688c2ecf20Sopenharmony_ci}
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci/**
17718c2ecf20Sopenharmony_ci * zfcp_erp_set_port_status - set port status bits
17728c2ecf20Sopenharmony_ci * @port: port to change the status
17738c2ecf20Sopenharmony_ci * @mask: status bits to change
17748c2ecf20Sopenharmony_ci *
17758c2ecf20Sopenharmony_ci * Changes in common status bits are propagated to attached LUNs.
17768c2ecf20Sopenharmony_ci */
17778c2ecf20Sopenharmony_civoid zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask)
17788c2ecf20Sopenharmony_ci{
17798c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
17808c2ecf20Sopenharmony_ci	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
17818c2ecf20Sopenharmony_ci	unsigned long flags;
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci	atomic_or(mask, &port->status);
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci	if (!common_mask)
17868c2ecf20Sopenharmony_ci		return;
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci	spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags);
17898c2ecf20Sopenharmony_ci	__shost_for_each_device(sdev, port->adapter->scsi_host)
17908c2ecf20Sopenharmony_ci		if (sdev_to_zfcp(sdev)->port == port)
17918c2ecf20Sopenharmony_ci			atomic_or(common_mask,
17928c2ecf20Sopenharmony_ci					&sdev_to_zfcp(sdev)->status);
17938c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags);
17948c2ecf20Sopenharmony_ci}
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_ci/**
17978c2ecf20Sopenharmony_ci * zfcp_erp_clear_port_status - clear port status bits
17988c2ecf20Sopenharmony_ci * @port: adapter to change the status
17998c2ecf20Sopenharmony_ci * @mask: status bits to change
18008c2ecf20Sopenharmony_ci *
18018c2ecf20Sopenharmony_ci * Changes in common status bits are propagated to attached LUNs.
18028c2ecf20Sopenharmony_ci */
18038c2ecf20Sopenharmony_civoid zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask)
18048c2ecf20Sopenharmony_ci{
18058c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
18068c2ecf20Sopenharmony_ci	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
18078c2ecf20Sopenharmony_ci	u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED;
18088c2ecf20Sopenharmony_ci	unsigned long flags;
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	atomic_andnot(mask, &port->status);
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	if (!common_mask)
18138c2ecf20Sopenharmony_ci		return;
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci	if (clear_counter)
18168c2ecf20Sopenharmony_ci		atomic_set(&port->erp_counter, 0);
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci	spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags);
18198c2ecf20Sopenharmony_ci	__shost_for_each_device(sdev, port->adapter->scsi_host)
18208c2ecf20Sopenharmony_ci		if (sdev_to_zfcp(sdev)->port == port) {
18218c2ecf20Sopenharmony_ci			atomic_andnot(common_mask,
18228c2ecf20Sopenharmony_ci					  &sdev_to_zfcp(sdev)->status);
18238c2ecf20Sopenharmony_ci			if (clear_counter)
18248c2ecf20Sopenharmony_ci				atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
18258c2ecf20Sopenharmony_ci		}
18268c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags);
18278c2ecf20Sopenharmony_ci}
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci/**
18308c2ecf20Sopenharmony_ci * zfcp_erp_set_lun_status - set lun status bits
18318c2ecf20Sopenharmony_ci * @sdev: SCSI device / lun to set the status bits
18328c2ecf20Sopenharmony_ci * @mask: status bits to change
18338c2ecf20Sopenharmony_ci */
18348c2ecf20Sopenharmony_civoid zfcp_erp_set_lun_status(struct scsi_device *sdev, u32 mask)
18358c2ecf20Sopenharmony_ci{
18368c2ecf20Sopenharmony_ci	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ci	atomic_or(mask, &zfcp_sdev->status);
18398c2ecf20Sopenharmony_ci}
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci/**
18428c2ecf20Sopenharmony_ci * zfcp_erp_clear_lun_status - clear lun status bits
18438c2ecf20Sopenharmony_ci * @sdev: SCSi device / lun to clear the status bits
18448c2ecf20Sopenharmony_ci * @mask: status bits to change
18458c2ecf20Sopenharmony_ci */
18468c2ecf20Sopenharmony_civoid zfcp_erp_clear_lun_status(struct scsi_device *sdev, u32 mask)
18478c2ecf20Sopenharmony_ci{
18488c2ecf20Sopenharmony_ci	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci	atomic_andnot(mask, &zfcp_sdev->status);
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci	if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
18538c2ecf20Sopenharmony_ci		atomic_set(&zfcp_sdev->erp_counter, 0);
18548c2ecf20Sopenharmony_ci}
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci/**
18578c2ecf20Sopenharmony_ci * zfcp_erp_adapter_reset_sync() - Really reopen adapter and wait.
18588c2ecf20Sopenharmony_ci * @adapter: Pointer to zfcp_adapter to reopen.
18598c2ecf20Sopenharmony_ci * @dbftag: Trace tag string of length %ZFCP_DBF_TAG_LEN.
18608c2ecf20Sopenharmony_ci */
18618c2ecf20Sopenharmony_civoid zfcp_erp_adapter_reset_sync(struct zfcp_adapter *adapter, char *dbftag)
18628c2ecf20Sopenharmony_ci{
18638c2ecf20Sopenharmony_ci	zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING);
18648c2ecf20Sopenharmony_ci	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, dbftag);
18658c2ecf20Sopenharmony_ci	zfcp_erp_wait(adapter);
18668c2ecf20Sopenharmony_ci}
1867