xref: /openbmc/linux/drivers/s390/scsi/zfcp_erp.c (revision addf1372)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
3553448f6SChristof Schmitt  * zfcp device driver
41da177e4SLinus Torvalds  *
5553448f6SChristof Schmitt  * Error Recovery Procedures (ERP).
61da177e4SLinus Torvalds  *
7ac007adcSBenjamin Block  * Copyright IBM Corp. 2002, 2020
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
10ecf39d42SChristof Schmitt #define KMSG_COMPONENT "zfcp"
11ecf39d42SChristof Schmitt #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
12ecf39d42SChristof Schmitt 
13347c6a96SChristof Schmitt #include <linux/kthread.h>
1448464708SBenjamin Block #include <linux/bug.h>
151da177e4SLinus Torvalds #include "zfcp_ext.h"
16b6bd2fb9SChristof Schmitt #include "zfcp_reqlist.h"
17d0dff2acSBenjamin Block #include "zfcp_diag.h"
181da177e4SLinus Torvalds 
19287ac01aSChristof Schmitt #define ZFCP_MAX_ERPS                   3
201da177e4SLinus Torvalds 
21287ac01aSChristof Schmitt enum zfcp_erp_act_flags {
22287ac01aSChristof Schmitt 	ZFCP_STATUS_ERP_TIMEDOUT	= 0x10000000,
23287ac01aSChristof Schmitt 	ZFCP_STATUS_ERP_CLOSE_ONLY	= 0x01000000,
24287ac01aSChristof Schmitt 	ZFCP_STATUS_ERP_DISMISSED	= 0x00200000,
25287ac01aSChristof Schmitt 	ZFCP_STATUS_ERP_LOWMEM		= 0x00400000,
26fdbd1c5eSChristof Schmitt 	ZFCP_STATUS_ERP_NO_REF		= 0x00800000,
27287ac01aSChristof Schmitt };
281da177e4SLinus Torvalds 
29df91eefdSSteffen Maier /*
30df91eefdSSteffen Maier  * Eyecatcher pseudo flag to bitwise or-combine with enum zfcp_erp_act_type.
31df91eefdSSteffen Maier  * Used to indicate that an ERP action could not be set up despite a detected
32df91eefdSSteffen Maier  * need for some recovery.
33512857a7SSteffen Maier  */
34df91eefdSSteffen Maier #define ZFCP_ERP_ACTION_NONE		0xc0
35df91eefdSSteffen Maier /*
36df91eefdSSteffen Maier  * Eyecatcher pseudo flag to bitwise or-combine with enum zfcp_erp_act_type.
37df91eefdSSteffen Maier  * Used to indicate that ERP not needed because the object has
38df91eefdSSteffen Maier  * ZFCP_STATUS_COMMON_ERP_FAILED.
39df91eefdSSteffen Maier  */
40df91eefdSSteffen Maier #define ZFCP_ERP_ACTION_FAILED		0xe0
411da177e4SLinus Torvalds 
42287ac01aSChristof Schmitt enum zfcp_erp_act_result {
43287ac01aSChristof Schmitt 	ZFCP_ERP_SUCCEEDED = 0,
44287ac01aSChristof Schmitt 	ZFCP_ERP_FAILED    = 1,
45287ac01aSChristof Schmitt 	ZFCP_ERP_CONTINUES = 2,
46287ac01aSChristof Schmitt 	ZFCP_ERP_EXIT      = 3,
47287ac01aSChristof Schmitt 	ZFCP_ERP_DISMISSED = 4,
48287ac01aSChristof Schmitt 	ZFCP_ERP_NOMEM     = 5,
49287ac01aSChristof Schmitt };
501da177e4SLinus Torvalds 
zfcp_erp_adapter_block(struct zfcp_adapter * adapter,int mask)51287ac01aSChristof Schmitt static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask)
522abbe866SAndreas Herrmann {
53edaed859SSwen Schillig 	zfcp_erp_clear_adapter_status(adapter,
54edaed859SSwen Schillig 				       ZFCP_STATUS_COMMON_UNBLOCKED | mask);
552abbe866SAndreas Herrmann }
561da177e4SLinus Torvalds 
zfcp_erp_action_is_running(struct zfcp_erp_action * act)57013af857SSteffen Maier static bool zfcp_erp_action_is_running(struct zfcp_erp_action *act)
581da177e4SLinus Torvalds {
59287ac01aSChristof Schmitt 	struct zfcp_erp_action *curr_act;
60287ac01aSChristof Schmitt 
61287ac01aSChristof Schmitt 	list_for_each_entry(curr_act, &act->adapter->erp_running_head, list)
62287ac01aSChristof Schmitt 		if (act == curr_act)
63013af857SSteffen Maier 			return true;
64013af857SSteffen Maier 	return false;
651da177e4SLinus Torvalds }
661da177e4SLinus Torvalds 
zfcp_erp_action_ready(struct zfcp_erp_action * act)67287ac01aSChristof Schmitt static void zfcp_erp_action_ready(struct zfcp_erp_action *act)
681da177e4SLinus Torvalds {
69287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
70287ac01aSChristof Schmitt 
71b43cdb5aSJulian Wiedmann 	list_move(&act->list, &adapter->erp_ready_head);
72ae0904f6SSwen Schillig 	zfcp_dbf_rec_run("erardy1", act);
73347c6a96SChristof Schmitt 	wake_up(&adapter->erp_ready_wq);
74ae0904f6SSwen Schillig 	zfcp_dbf_rec_run("erardy2", act);
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds 
zfcp_erp_action_dismiss(struct zfcp_erp_action * act)77287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
78287ac01aSChristof Schmitt {
79287ac01aSChristof Schmitt 	act->status |= ZFCP_STATUS_ERP_DISMISSED;
80013af857SSteffen Maier 	if (zfcp_erp_action_is_running(act))
81287ac01aSChristof Schmitt 		zfcp_erp_action_ready(act);
82287ac01aSChristof Schmitt }
83287ac01aSChristof Schmitt 
zfcp_erp_action_dismiss_lun(struct scsi_device * sdev)84b62a8d9bSChristof Schmitt static void zfcp_erp_action_dismiss_lun(struct scsi_device *sdev)
85287ac01aSChristof Schmitt {
86b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
87b62a8d9bSChristof Schmitt 
88b62a8d9bSChristof Schmitt 	if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
89b62a8d9bSChristof Schmitt 		zfcp_erp_action_dismiss(&zfcp_sdev->erp_action);
90287ac01aSChristof Schmitt }
91287ac01aSChristof Schmitt 
zfcp_erp_action_dismiss_port(struct zfcp_port * port)92287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
93287ac01aSChristof Schmitt {
94b62a8d9bSChristof Schmitt 	struct scsi_device *sdev;
95287ac01aSChristof Schmitt 
96287ac01aSChristof Schmitt 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
97287ac01aSChristof Schmitt 		zfcp_erp_action_dismiss(&port->erp_action);
98924dd584SMartin Peschke 	else {
99924dd584SMartin Peschke 		spin_lock(port->adapter->scsi_host->host_lock);
100924dd584SMartin Peschke 		__shost_for_each_device(sdev, port->adapter->scsi_host)
101b62a8d9bSChristof Schmitt 			if (sdev_to_zfcp(sdev)->port == port)
102b62a8d9bSChristof Schmitt 				zfcp_erp_action_dismiss_lun(sdev);
103924dd584SMartin Peschke 		spin_unlock(port->adapter->scsi_host->host_lock);
104924dd584SMartin Peschke 	}
105287ac01aSChristof Schmitt }
106287ac01aSChristof Schmitt 
zfcp_erp_action_dismiss_adapter(struct zfcp_adapter * adapter)107287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
108287ac01aSChristof Schmitt {
109287ac01aSChristof Schmitt 	struct zfcp_port *port;
110287ac01aSChristof Schmitt 
111287ac01aSChristof Schmitt 	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
112287ac01aSChristof Schmitt 		zfcp_erp_action_dismiss(&adapter->erp_action);
113ecf0c772SSwen Schillig 	else {
114ecf0c772SSwen Schillig 		read_lock(&adapter->port_list_lock);
115ecf0c772SSwen Schillig 		list_for_each_entry(port, &adapter->port_list, list)
116287ac01aSChristof Schmitt 		    zfcp_erp_action_dismiss_port(port);
117ecf0c772SSwen Schillig 		read_unlock(&adapter->port_list_lock);
118ecf0c772SSwen Schillig 	}
119287ac01aSChristof Schmitt }
120287ac01aSChristof Schmitt 
zfcp_erp_handle_failed(enum zfcp_erp_act_type want,struct zfcp_adapter * adapter,struct zfcp_port * port,struct scsi_device * sdev)121df91eefdSSteffen Maier static enum zfcp_erp_act_type zfcp_erp_handle_failed(
122df91eefdSSteffen Maier 	enum zfcp_erp_act_type want, struct zfcp_adapter *adapter,
123df91eefdSSteffen Maier 	struct zfcp_port *port,	struct scsi_device *sdev)
1248c3d20aaSSteffen Maier {
125df91eefdSSteffen Maier 	enum zfcp_erp_act_type need = want;
1268c3d20aaSSteffen Maier 	struct zfcp_scsi_dev *zsdev;
1278c3d20aaSSteffen Maier 
1288c3d20aaSSteffen Maier 	switch (want) {
1298c3d20aaSSteffen Maier 	case ZFCP_ERP_ACTION_REOPEN_LUN:
1308c3d20aaSSteffen Maier 		zsdev = sdev_to_zfcp(sdev);
1318c3d20aaSSteffen Maier 		if (atomic_read(&zsdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
1328c3d20aaSSteffen Maier 			need = 0;
1338c3d20aaSSteffen Maier 		break;
1348c3d20aaSSteffen Maier 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1358c3d20aaSSteffen Maier 		if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
1368c3d20aaSSteffen Maier 			need = 0;
1378c3d20aaSSteffen Maier 		break;
1388c3d20aaSSteffen Maier 	case ZFCP_ERP_ACTION_REOPEN_PORT:
1398c3d20aaSSteffen Maier 		if (atomic_read(&port->status) &
1408c3d20aaSSteffen Maier 		    ZFCP_STATUS_COMMON_ERP_FAILED) {
1418c3d20aaSSteffen Maier 			need = 0;
1428c3d20aaSSteffen Maier 			/* ensure propagation of failed status to new devices */
1438c3d20aaSSteffen Maier 			zfcp_erp_set_port_status(
1448c3d20aaSSteffen Maier 				port, ZFCP_STATUS_COMMON_ERP_FAILED);
1458c3d20aaSSteffen Maier 		}
1468c3d20aaSSteffen Maier 		break;
1478c3d20aaSSteffen Maier 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1488c3d20aaSSteffen Maier 		if (atomic_read(&adapter->status) &
1498c3d20aaSSteffen Maier 		    ZFCP_STATUS_COMMON_ERP_FAILED) {
1508c3d20aaSSteffen Maier 			need = 0;
1518c3d20aaSSteffen Maier 			/* ensure propagation of failed status to new devices */
1528c3d20aaSSteffen Maier 			zfcp_erp_set_adapter_status(
1538c3d20aaSSteffen Maier 				adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
1548c3d20aaSSteffen Maier 		}
1558c3d20aaSSteffen Maier 		break;
1568c3d20aaSSteffen Maier 	}
1578c3d20aaSSteffen Maier 
1588c3d20aaSSteffen Maier 	return need;
1598c3d20aaSSteffen Maier }
1608c3d20aaSSteffen Maier 
zfcp_erp_required_act(enum zfcp_erp_act_type want,struct zfcp_adapter * adapter,struct zfcp_port * port,struct scsi_device * sdev)161df91eefdSSteffen Maier static enum zfcp_erp_act_type zfcp_erp_required_act(enum zfcp_erp_act_type want,
162df91eefdSSteffen Maier 				 struct zfcp_adapter *adapter,
163287ac01aSChristof Schmitt 				 struct zfcp_port *port,
164b62a8d9bSChristof Schmitt 				 struct scsi_device *sdev)
165287ac01aSChristof Schmitt {
166df91eefdSSteffen Maier 	enum zfcp_erp_act_type need = want;
167b62a8d9bSChristof Schmitt 	int l_status, p_status, a_status;
168b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev;
169287ac01aSChristof Schmitt 
170287ac01aSChristof Schmitt 	switch (want) {
171b62a8d9bSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_LUN:
172b62a8d9bSChristof Schmitt 		zfcp_sdev = sdev_to_zfcp(sdev);
173b62a8d9bSChristof Schmitt 		l_status = atomic_read(&zfcp_sdev->status);
174b62a8d9bSChristof Schmitt 		if (l_status & ZFCP_STATUS_COMMON_ERP_INUSE)
175287ac01aSChristof Schmitt 			return 0;
176287ac01aSChristof Schmitt 		p_status = atomic_read(&port->status);
177287ac01aSChristof Schmitt 		if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) ||
178287ac01aSChristof Schmitt 		    p_status & ZFCP_STATUS_COMMON_ERP_FAILED)
179287ac01aSChristof Schmitt 			return 0;
180287ac01aSChristof Schmitt 		if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
181287ac01aSChristof Schmitt 			need = ZFCP_ERP_ACTION_REOPEN_PORT;
182cec9cbacSJoe Perches 		fallthrough;
183287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
184287ac01aSChristof Schmitt 		p_status = atomic_read(&port->status);
185097ef3bdSChristof Schmitt 		if (!(p_status & ZFCP_STATUS_COMMON_OPEN))
186097ef3bdSChristof Schmitt 			need = ZFCP_ERP_ACTION_REOPEN_PORT;
187cec9cbacSJoe Perches 		fallthrough;
188097ef3bdSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
189097ef3bdSChristof Schmitt 		p_status = atomic_read(&port->status);
190287ac01aSChristof Schmitt 		if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
191287ac01aSChristof Schmitt 			return 0;
192287ac01aSChristof Schmitt 		a_status = atomic_read(&adapter->status);
193287ac01aSChristof Schmitt 		if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) ||
194287ac01aSChristof Schmitt 		    a_status & ZFCP_STATUS_COMMON_ERP_FAILED)
195287ac01aSChristof Schmitt 			return 0;
196d3e1088dSSwen Schillig 		if (p_status & ZFCP_STATUS_COMMON_NOESC)
197d3e1088dSSwen Schillig 			return need;
198287ac01aSChristof Schmitt 		if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))
199287ac01aSChristof Schmitt 			need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
200cec9cbacSJoe Perches 		fallthrough;
201287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
202287ac01aSChristof Schmitt 		a_status = atomic_read(&adapter->status);
203287ac01aSChristof Schmitt 		if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
204287ac01aSChristof Schmitt 			return 0;
205143bb6bfSChristof Schmitt 		if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) &&
206143bb6bfSChristof Schmitt 		    !(a_status & ZFCP_STATUS_COMMON_OPEN))
207143bb6bfSChristof Schmitt 			return 0; /* shutdown requested for closed adapter */
208287ac01aSChristof Schmitt 	}
209287ac01aSChristof Schmitt 
210287ac01aSChristof Schmitt 	return need;
211287ac01aSChristof Schmitt }
212287ac01aSChristof Schmitt 
zfcp_erp_setup_act(enum zfcp_erp_act_type need,u32 act_status,struct zfcp_adapter * adapter,struct zfcp_port * port,struct scsi_device * sdev)213df91eefdSSteffen Maier static struct zfcp_erp_action *zfcp_erp_setup_act(enum zfcp_erp_act_type need,
214df91eefdSSteffen Maier 						  u32 act_status,
215287ac01aSChristof Schmitt 						  struct zfcp_adapter *adapter,
216287ac01aSChristof Schmitt 						  struct zfcp_port *port,
217b62a8d9bSChristof Schmitt 						  struct scsi_device *sdev)
218287ac01aSChristof Schmitt {
219287ac01aSChristof Schmitt 	struct zfcp_erp_action *erp_action;
220b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev;
221287ac01aSChristof Schmitt 
22248464708SBenjamin Block 	if (WARN_ON_ONCE(need != ZFCP_ERP_ACTION_REOPEN_LUN &&
22348464708SBenjamin Block 			 need != ZFCP_ERP_ACTION_REOPEN_PORT &&
22448464708SBenjamin Block 			 need != ZFCP_ERP_ACTION_REOPEN_PORT_FORCED &&
22548464708SBenjamin Block 			 need != ZFCP_ERP_ACTION_REOPEN_ADAPTER))
22648464708SBenjamin Block 		return NULL;
22748464708SBenjamin Block 
228287ac01aSChristof Schmitt 	switch (need) {
229b62a8d9bSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_LUN:
230b62a8d9bSChristof Schmitt 		zfcp_sdev = sdev_to_zfcp(sdev);
231fdbd1c5eSChristof Schmitt 		if (!(act_status & ZFCP_STATUS_ERP_NO_REF))
232b62a8d9bSChristof Schmitt 			if (scsi_device_get(sdev))
2336b183334SSwen Schillig 				return NULL;
234805de8f4SPeter Zijlstra 		atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE,
235b62a8d9bSChristof Schmitt 				&zfcp_sdev->status);
236b62a8d9bSChristof Schmitt 		erp_action = &zfcp_sdev->erp_action;
237ab31fd0cSSteffen Maier 		WARN_ON_ONCE(erp_action->port != port);
238ab31fd0cSSteffen Maier 		WARN_ON_ONCE(erp_action->sdev != sdev);
239b62a8d9bSChristof Schmitt 		if (!(atomic_read(&zfcp_sdev->status) &
240b62a8d9bSChristof Schmitt 		      ZFCP_STATUS_COMMON_RUNNING))
241fdbd1c5eSChristof Schmitt 			act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
242287ac01aSChristof Schmitt 		break;
243287ac01aSChristof Schmitt 
244287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
245287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
246615f59e0SChristof Schmitt 		if (!get_device(&port->dev))
2476b183334SSwen Schillig 			return NULL;
248287ac01aSChristof Schmitt 		zfcp_erp_action_dismiss_port(port);
249805de8f4SPeter Zijlstra 		atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
250287ac01aSChristof Schmitt 		erp_action = &port->erp_action;
251ab31fd0cSSteffen Maier 		WARN_ON_ONCE(erp_action->port != port);
252ab31fd0cSSteffen Maier 		WARN_ON_ONCE(erp_action->sdev != NULL);
253287ac01aSChristof Schmitt 		if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
254fdbd1c5eSChristof Schmitt 			act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
255287ac01aSChristof Schmitt 		break;
256287ac01aSChristof Schmitt 
257287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
258f3450c7bSSwen Schillig 		kref_get(&adapter->ref);
259287ac01aSChristof Schmitt 		zfcp_erp_action_dismiss_adapter(adapter);
260805de8f4SPeter Zijlstra 		atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
261287ac01aSChristof Schmitt 		erp_action = &adapter->erp_action;
262ab31fd0cSSteffen Maier 		WARN_ON_ONCE(erp_action->port != NULL);
263ab31fd0cSSteffen Maier 		WARN_ON_ONCE(erp_action->sdev != NULL);
264287ac01aSChristof Schmitt 		if (!(atomic_read(&adapter->status) &
265287ac01aSChristof Schmitt 		      ZFCP_STATUS_COMMON_RUNNING))
266fdbd1c5eSChristof Schmitt 			act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
267287ac01aSChristof Schmitt 		break;
268287ac01aSChristof Schmitt 	}
269287ac01aSChristof Schmitt 
270ab31fd0cSSteffen Maier 	WARN_ON_ONCE(erp_action->adapter != adapter);
271ab31fd0cSSteffen Maier 	memset(&erp_action->list, 0, sizeof(erp_action->list));
272ab31fd0cSSteffen Maier 	memset(&erp_action->timer, 0, sizeof(erp_action->timer));
273ab31fd0cSSteffen Maier 	erp_action->step = ZFCP_ERP_STEP_UNINITIALIZED;
274ab31fd0cSSteffen Maier 	erp_action->fsf_req_id = 0;
275df91eefdSSteffen Maier 	erp_action->type = need;
276fdbd1c5eSChristof Schmitt 	erp_action->status = act_status;
277287ac01aSChristof Schmitt 
278287ac01aSChristof Schmitt 	return erp_action;
279287ac01aSChristof Schmitt }
280287ac01aSChristof Schmitt 
zfcp_erp_action_enqueue(enum zfcp_erp_act_type want,struct zfcp_adapter * adapter,struct zfcp_port * port,struct scsi_device * sdev,char * dbftag,u32 act_status)281df91eefdSSteffen Maier static void zfcp_erp_action_enqueue(enum zfcp_erp_act_type want,
282df91eefdSSteffen Maier 				    struct zfcp_adapter *adapter,
283287ac01aSChristof Schmitt 				    struct zfcp_port *port,
284b62a8d9bSChristof Schmitt 				    struct scsi_device *sdev,
285208d0961SSteffen Maier 				    char *dbftag, u32 act_status)
286287ac01aSChristof Schmitt {
287df91eefdSSteffen Maier 	enum zfcp_erp_act_type need;
288ae0904f6SSwen Schillig 	struct zfcp_erp_action *act;
289287ac01aSChristof Schmitt 
2908c3d20aaSSteffen Maier 	need = zfcp_erp_handle_failed(want, adapter, port, sdev);
2918c3d20aaSSteffen Maier 	if (!need) {
2928c3d20aaSSteffen Maier 		need = ZFCP_ERP_ACTION_FAILED; /* marker for trace */
2938c3d20aaSSteffen Maier 		goto out;
2948c3d20aaSSteffen Maier 	}
2958c3d20aaSSteffen Maier 
2966a765508SSteffen Maier 	if (!adapter->erp_thread) {
2976a765508SSteffen Maier 		need = ZFCP_ERP_ACTION_NONE; /* marker for trace */
2986a765508SSteffen Maier 		goto out;
2996a765508SSteffen Maier 	}
300287ac01aSChristof Schmitt 
301b62a8d9bSChristof Schmitt 	need = zfcp_erp_required_act(want, adapter, port, sdev);
302287ac01aSChristof Schmitt 	if (!need)
303287ac01aSChristof Schmitt 		goto out;
304287ac01aSChristof Schmitt 
305b62a8d9bSChristof Schmitt 	act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev);
306512857a7SSteffen Maier 	if (!act) {
307512857a7SSteffen Maier 		need |= ZFCP_ERP_ACTION_NONE; /* marker for trace */
308287ac01aSChristof Schmitt 		goto out;
309512857a7SSteffen Maier 	}
310805de8f4SPeter Zijlstra 	atomic_or(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
311287ac01aSChristof Schmitt 	++adapter->erp_total_count;
312287ac01aSChristof Schmitt 	list_add_tail(&act->list, &adapter->erp_ready_head);
313347c6a96SChristof Schmitt 	wake_up(&adapter->erp_ready_wq);
314287ac01aSChristof Schmitt  out:
315208d0961SSteffen Maier 	zfcp_dbf_rec_trig(dbftag, adapter, port, sdev, want, need);
316287ac01aSChristof Schmitt }
317287ac01aSChristof Schmitt 
zfcp_erp_port_forced_no_port_dbf(char * dbftag,struct zfcp_adapter * adapter,u64 port_name,u32 port_id)318208d0961SSteffen Maier void zfcp_erp_port_forced_no_port_dbf(char *dbftag,
319208d0961SSteffen Maier 				      struct zfcp_adapter *adapter,
32096d92704SSteffen Maier 				      u64 port_name, u32 port_id)
32196d92704SSteffen Maier {
32296d92704SSteffen Maier 	unsigned long flags;
32396d92704SSteffen Maier 	static /* don't waste stack */ struct zfcp_port tmpport;
32496d92704SSteffen Maier 
32596d92704SSteffen Maier 	write_lock_irqsave(&adapter->erp_lock, flags);
32696d92704SSteffen Maier 	/* Stand-in zfcp port with fields just good enough for
32796d92704SSteffen Maier 	 * zfcp_dbf_rec_trig() and zfcp_dbf_set_common().
32896d92704SSteffen Maier 	 * Under lock because tmpport is static.
32996d92704SSteffen Maier 	 */
33096d92704SSteffen Maier 	atomic_set(&tmpport.status, -1); /* unknown */
33196d92704SSteffen Maier 	tmpport.wwpn = port_name;
33296d92704SSteffen Maier 	tmpport.d_id = port_id;
333208d0961SSteffen Maier 	zfcp_dbf_rec_trig(dbftag, adapter, &tmpport, NULL,
33496d92704SSteffen Maier 			  ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
33596d92704SSteffen Maier 			  ZFCP_ERP_ACTION_NONE);
33696d92704SSteffen Maier 	write_unlock_irqrestore(&adapter->erp_lock, flags);
33796d92704SSteffen Maier }
33896d92704SSteffen Maier 
_zfcp_erp_adapter_reopen(struct zfcp_adapter * adapter,int clear_mask,char * dbftag)3392fdd45fdSSteffen Maier static void _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
340208d0961SSteffen Maier 				    int clear_mask, char *dbftag)
3411da177e4SLinus Torvalds {
3421da177e4SLinus Torvalds 	zfcp_erp_adapter_block(adapter, clear_mask);
343a2fa0aedSChristof Schmitt 	zfcp_scsi_schedule_rports_block(adapter);
3441da177e4SLinus Torvalds 
3452fdd45fdSSteffen Maier 	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
346208d0961SSteffen Maier 				adapter, NULL, NULL, dbftag, 0);
3471da177e4SLinus Torvalds }
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds /**
350287ac01aSChristof Schmitt  * zfcp_erp_adapter_reopen - Reopen adapter.
351287ac01aSChristof Schmitt  * @adapter: Adapter to reopen.
352287ac01aSChristof Schmitt  * @clear: Status flags to clear.
353208d0961SSteffen Maier  * @dbftag: Tag for debug trace event.
3541da177e4SLinus Torvalds  */
zfcp_erp_adapter_reopen(struct zfcp_adapter * adapter,int clear,char * dbftag)355208d0961SSteffen Maier void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
356208d0961SSteffen Maier 			     char *dbftag)
357287ac01aSChristof Schmitt {
358287ac01aSChristof Schmitt 	unsigned long flags;
359287ac01aSChristof Schmitt 
360ecf0c772SSwen Schillig 	zfcp_erp_adapter_block(adapter, clear);
361ecf0c772SSwen Schillig 	zfcp_scsi_schedule_rports_block(adapter);
362ecf0c772SSwen Schillig 
363ecf0c772SSwen Schillig 	write_lock_irqsave(&adapter->erp_lock, flags);
364ecf0c772SSwen Schillig 	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
365208d0961SSteffen Maier 				NULL, NULL, dbftag, 0);
366ecf0c772SSwen Schillig 	write_unlock_irqrestore(&adapter->erp_lock, flags);
367287ac01aSChristof Schmitt }
368287ac01aSChristof Schmitt 
369287ac01aSChristof Schmitt /**
370287ac01aSChristof Schmitt  * zfcp_erp_adapter_shutdown - Shutdown adapter.
371287ac01aSChristof Schmitt  * @adapter: Adapter to shut down.
372287ac01aSChristof Schmitt  * @clear: Status flags to clear.
373208d0961SSteffen Maier  * @dbftag: Tag for debug trace event.
374287ac01aSChristof Schmitt  */
zfcp_erp_adapter_shutdown(struct zfcp_adapter * adapter,int clear,char * dbftag)375287ac01aSChristof Schmitt void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
376208d0961SSteffen Maier 			       char *dbftag)
377287ac01aSChristof Schmitt {
378287ac01aSChristof Schmitt 	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
379208d0961SSteffen Maier 	zfcp_erp_adapter_reopen(adapter, clear | flags, dbftag);
380287ac01aSChristof Schmitt }
381287ac01aSChristof Schmitt 
382287ac01aSChristof Schmitt /**
383287ac01aSChristof Schmitt  * zfcp_erp_port_shutdown - Shutdown port
384287ac01aSChristof Schmitt  * @port: Port to shut down.
385287ac01aSChristof Schmitt  * @clear: Status flags to clear.
386208d0961SSteffen Maier  * @dbftag: Tag for debug trace event.
387287ac01aSChristof Schmitt  */
zfcp_erp_port_shutdown(struct zfcp_port * port,int clear,char * dbftag)388208d0961SSteffen Maier void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *dbftag)
389287ac01aSChristof Schmitt {
390287ac01aSChristof Schmitt 	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
391208d0961SSteffen Maier 	zfcp_erp_port_reopen(port, clear | flags, dbftag);
392287ac01aSChristof Schmitt }
393287ac01aSChristof Schmitt 
zfcp_erp_port_block(struct zfcp_port * port,int clear)394287ac01aSChristof Schmitt static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
395287ac01aSChristof Schmitt {
396edaed859SSwen Schillig 	zfcp_erp_clear_port_status(port,
397edaed859SSwen Schillig 				    ZFCP_STATUS_COMMON_UNBLOCKED | clear);
398287ac01aSChristof Schmitt }
399287ac01aSChristof Schmitt 
_zfcp_erp_port_forced_reopen(struct zfcp_port * port,int clear,char * dbftag)400ea4a3a6aSSwen Schillig static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear,
401208d0961SSteffen Maier 					 char *dbftag)
402287ac01aSChristof Schmitt {
403287ac01aSChristof Schmitt 	zfcp_erp_port_block(port, clear);
404a2fa0aedSChristof Schmitt 	zfcp_scsi_schedule_rport_block(port);
405287ac01aSChristof Schmitt 
406287ac01aSChristof Schmitt 	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
407208d0961SSteffen Maier 				port->adapter, port, NULL, dbftag, 0);
408287ac01aSChristof Schmitt }
409287ac01aSChristof Schmitt 
410287ac01aSChristof Schmitt /**
411287ac01aSChristof Schmitt  * zfcp_erp_port_forced_reopen - Forced close of port and open again
412287ac01aSChristof Schmitt  * @port: Port to force close and to reopen.
413ea4a3a6aSSwen Schillig  * @clear: Status flags to clear.
414208d0961SSteffen Maier  * @dbftag: Tag for debug trace event.
415287ac01aSChristof Schmitt  */
zfcp_erp_port_forced_reopen(struct zfcp_port * port,int clear,char * dbftag)416208d0961SSteffen Maier void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear,
417208d0961SSteffen Maier 				 char *dbftag)
4181da177e4SLinus Torvalds {
4191da177e4SLinus Torvalds 	unsigned long flags;
4201da177e4SLinus Torvalds 	struct zfcp_adapter *adapter = port->adapter;
4211da177e4SLinus Torvalds 
422ecf0c772SSwen Schillig 	write_lock_irqsave(&adapter->erp_lock, flags);
423208d0961SSteffen Maier 	_zfcp_erp_port_forced_reopen(port, clear, dbftag);
424ecf0c772SSwen Schillig 	write_unlock_irqrestore(&adapter->erp_lock, flags);
425287ac01aSChristof Schmitt }
426287ac01aSChristof Schmitt 
_zfcp_erp_port_reopen(struct zfcp_port * port,int clear,char * dbftag)427208d0961SSteffen Maier static void _zfcp_erp_port_reopen(struct zfcp_port *port, int clear,
428208d0961SSteffen Maier 				  char *dbftag)
429287ac01aSChristof Schmitt {
430287ac01aSChristof Schmitt 	zfcp_erp_port_block(port, clear);
431a2fa0aedSChristof Schmitt 	zfcp_scsi_schedule_rport_block(port);
432287ac01aSChristof Schmitt 
4332fdd45fdSSteffen Maier 	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
434208d0961SSteffen Maier 				port->adapter, port, NULL, dbftag, 0);
435287ac01aSChristof Schmitt }
436287ac01aSChristof Schmitt 
437287ac01aSChristof Schmitt /**
438287ac01aSChristof Schmitt  * zfcp_erp_port_reopen - trigger remote port recovery
439287ac01aSChristof Schmitt  * @port: port to recover
4408684d614SSteffen Maier  * @clear: flags in port status to be cleared
441208d0961SSteffen Maier  * @dbftag: Tag for debug trace event.
442287ac01aSChristof Schmitt  */
zfcp_erp_port_reopen(struct zfcp_port * port,int clear,char * dbftag)443208d0961SSteffen Maier void zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *dbftag)
444287ac01aSChristof Schmitt {
445ecf0c772SSwen Schillig 	unsigned long flags;
446287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = port->adapter;
447287ac01aSChristof Schmitt 
448ecf0c772SSwen Schillig 	write_lock_irqsave(&adapter->erp_lock, flags);
449208d0961SSteffen Maier 	_zfcp_erp_port_reopen(port, clear, dbftag);
450ecf0c772SSwen Schillig 	write_unlock_irqrestore(&adapter->erp_lock, flags);
4511da177e4SLinus Torvalds }
4521da177e4SLinus Torvalds 
zfcp_erp_lun_block(struct scsi_device * sdev,int clear_mask)453b62a8d9bSChristof Schmitt static void zfcp_erp_lun_block(struct scsi_device *sdev, int clear_mask)
4541da177e4SLinus Torvalds {
455edaed859SSwen Schillig 	zfcp_erp_clear_lun_status(sdev,
456edaed859SSwen Schillig 				  ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask);
4571da177e4SLinus Torvalds }
4581da177e4SLinus Torvalds 
_zfcp_erp_lun_reopen(struct scsi_device * sdev,int clear,char * dbftag,u32 act_status)459208d0961SSteffen Maier static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear,
460208d0961SSteffen Maier 				 char *dbftag, u32 act_status)
461287ac01aSChristof Schmitt {
462b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
463b62a8d9bSChristof Schmitt 	struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
464287ac01aSChristof Schmitt 
465b62a8d9bSChristof Schmitt 	zfcp_erp_lun_block(sdev, clear);
466287ac01aSChristof Schmitt 
467b62a8d9bSChristof Schmitt 	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter,
468208d0961SSteffen Maier 				zfcp_sdev->port, sdev, dbftag, act_status);
4691da177e4SLinus Torvalds }
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds /**
472b62a8d9bSChristof Schmitt  * zfcp_erp_lun_reopen - initiate reopen of a LUN
473b62a8d9bSChristof Schmitt  * @sdev: SCSI device / LUN to be reopened
4748684d614SSteffen Maier  * @clear: specifies flags in LUN status to be cleared
475208d0961SSteffen Maier  * @dbftag: Tag for debug trace event.
476ea4a3a6aSSwen Schillig  *
4771da177e4SLinus Torvalds  * Return: 0 on success, < 0 on error
4781da177e4SLinus Torvalds  */
zfcp_erp_lun_reopen(struct scsi_device * sdev,int clear,char * dbftag)479208d0961SSteffen Maier void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *dbftag)
4801da177e4SLinus Torvalds {
4811da177e4SLinus Torvalds 	unsigned long flags;
482b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
483b62a8d9bSChristof Schmitt 	struct zfcp_port *port = zfcp_sdev->port;
484287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = port->adapter;
4851da177e4SLinus Torvalds 
486ecf0c772SSwen Schillig 	write_lock_irqsave(&adapter->erp_lock, flags);
487208d0961SSteffen Maier 	_zfcp_erp_lun_reopen(sdev, clear, dbftag, 0);
488ecf0c772SSwen Schillig 	write_unlock_irqrestore(&adapter->erp_lock, flags);
4891da177e4SLinus Torvalds }
4901da177e4SLinus Torvalds 
491fdbd1c5eSChristof Schmitt /**
492b62a8d9bSChristof Schmitt  * zfcp_erp_lun_shutdown - Shutdown LUN
493b62a8d9bSChristof Schmitt  * @sdev: SCSI device / LUN to shut down.
494fdbd1c5eSChristof Schmitt  * @clear: Status flags to clear.
495208d0961SSteffen Maier  * @dbftag: Tag for debug trace event.
496fdbd1c5eSChristof Schmitt  */
zfcp_erp_lun_shutdown(struct scsi_device * sdev,int clear,char * dbftag)497208d0961SSteffen Maier void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *dbftag)
498fdbd1c5eSChristof Schmitt {
499fdbd1c5eSChristof Schmitt 	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
500208d0961SSteffen Maier 	zfcp_erp_lun_reopen(sdev, clear | flags, dbftag);
501fdbd1c5eSChristof Schmitt }
502fdbd1c5eSChristof Schmitt 
503fdbd1c5eSChristof Schmitt /**
504b62a8d9bSChristof Schmitt  * zfcp_erp_lun_shutdown_wait - Shutdown LUN and wait for erp completion
505b62a8d9bSChristof Schmitt  * @sdev: SCSI device / LUN to shut down.
506208d0961SSteffen Maier  * @dbftag: Tag for debug trace event.
507fdbd1c5eSChristof Schmitt  *
508b62a8d9bSChristof Schmitt  * Do not acquire a reference for the LUN when creating the ERP
509fdbd1c5eSChristof Schmitt  * action. It is safe, because this function waits for the ERP to
510b62a8d9bSChristof Schmitt  * complete first. This allows to shutdown the LUN, even when the SCSI
511b62a8d9bSChristof Schmitt  * device is in the state SDEV_DEL when scsi_device_get will fail.
512fdbd1c5eSChristof Schmitt  */
zfcp_erp_lun_shutdown_wait(struct scsi_device * sdev,char * dbftag)513208d0961SSteffen Maier void zfcp_erp_lun_shutdown_wait(struct scsi_device *sdev, char *dbftag)
514fdbd1c5eSChristof Schmitt {
515fdbd1c5eSChristof Schmitt 	unsigned long flags;
516b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
517b62a8d9bSChristof Schmitt 	struct zfcp_port *port = zfcp_sdev->port;
518fdbd1c5eSChristof Schmitt 	struct zfcp_adapter *adapter = port->adapter;
519fdbd1c5eSChristof Schmitt 	int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
520fdbd1c5eSChristof Schmitt 
521fdbd1c5eSChristof Schmitt 	write_lock_irqsave(&adapter->erp_lock, flags);
522208d0961SSteffen Maier 	_zfcp_erp_lun_reopen(sdev, clear, dbftag, ZFCP_STATUS_ERP_NO_REF);
523fdbd1c5eSChristof Schmitt 	write_unlock_irqrestore(&adapter->erp_lock, flags);
524fdbd1c5eSChristof Schmitt 
525fdbd1c5eSChristof Schmitt 	zfcp_erp_wait(adapter);
526fdbd1c5eSChristof Schmitt }
527fdbd1c5eSChristof Schmitt 
zfcp_erp_status_change_set(unsigned long mask,atomic_t * status)528d39eda54SSteffen Maier static int zfcp_erp_status_change_set(unsigned long mask, atomic_t *status)
5291da177e4SLinus Torvalds {
530287ac01aSChristof Schmitt 	return (atomic_read(status) ^ mask) & mask;
5311da177e4SLinus Torvalds }
5321da177e4SLinus Torvalds 
zfcp_erp_adapter_unblock(struct zfcp_adapter * adapter)533f6c0e7a7SAndreas Herrmann static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
5341da177e4SLinus Torvalds {
535d39eda54SSteffen Maier 	if (zfcp_erp_status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED,
536d39eda54SSteffen Maier 				       &adapter->status))
537ae0904f6SSwen Schillig 		zfcp_dbf_rec_run("eraubl1", &adapter->erp_action);
538805de8f4SPeter Zijlstra 	atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
5391da177e4SLinus Torvalds }
5401da177e4SLinus Torvalds 
zfcp_erp_port_unblock(struct zfcp_port * port)541287ac01aSChristof Schmitt static void zfcp_erp_port_unblock(struct zfcp_port *port)
5421da177e4SLinus Torvalds {
543d39eda54SSteffen Maier 	if (zfcp_erp_status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED,
544d39eda54SSteffen Maier 				       &port->status))
545ae0904f6SSwen Schillig 		zfcp_dbf_rec_run("erpubl1", &port->erp_action);
546805de8f4SPeter Zijlstra 	atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
5471da177e4SLinus Torvalds }
5481da177e4SLinus Torvalds 
zfcp_erp_lun_unblock(struct scsi_device * sdev)549b62a8d9bSChristof Schmitt static void zfcp_erp_lun_unblock(struct scsi_device *sdev)
5501da177e4SLinus Torvalds {
551b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
552b62a8d9bSChristof Schmitt 
553d39eda54SSteffen Maier 	if (zfcp_erp_status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED,
554d39eda54SSteffen Maier 				       &zfcp_sdev->status))
555ae0904f6SSwen Schillig 		zfcp_dbf_rec_run("erlubl1", &sdev_to_zfcp(sdev)->erp_action);
556805de8f4SPeter Zijlstra 	atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status);
5571da177e4SLinus Torvalds }
5581da177e4SLinus Torvalds 
zfcp_erp_action_to_running(struct zfcp_erp_action * erp_action)559287ac01aSChristof Schmitt static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
5601da177e4SLinus Torvalds {
561287ac01aSChristof Schmitt 	list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
562ae0904f6SSwen Schillig 	zfcp_dbf_rec_run("erator1", erp_action);
5631da177e4SLinus Torvalds }
5641da177e4SLinus Torvalds 
zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action * act)565287ac01aSChristof Schmitt static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
5661da177e4SLinus Torvalds {
567287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
568e60a6d69SChristof Schmitt 	struct zfcp_fsf_req *req;
5691da177e4SLinus Torvalds 
570e60a6d69SChristof Schmitt 	if (!act->fsf_req_id)
571287ac01aSChristof Schmitt 		return;
5721da177e4SLinus Torvalds 
573b6bd2fb9SChristof Schmitt 	spin_lock(&adapter->req_list->lock);
574b6bd2fb9SChristof Schmitt 	req = _zfcp_reqlist_find(adapter->req_list, act->fsf_req_id);
575e60a6d69SChristof Schmitt 	if (req && req->erp_action == act) {
576287ac01aSChristof Schmitt 		if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
5771da177e4SLinus Torvalds 				   ZFCP_STATUS_ERP_TIMEDOUT)) {
578e60a6d69SChristof Schmitt 			req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
579ae0904f6SSwen Schillig 			zfcp_dbf_rec_run("erscf_1", act);
580936e6b85SSteffen Maier 			/* lock-free concurrent access with
581936e6b85SSteffen Maier 			 * zfcp_erp_timeout_handler()
582936e6b85SSteffen Maier 			 */
583936e6b85SSteffen Maier 			WRITE_ONCE(req->erp_action, NULL);
5841da177e4SLinus Torvalds 		}
585287ac01aSChristof Schmitt 		if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
586ae0904f6SSwen Schillig 			zfcp_dbf_rec_run("erscf_2", act);
587e60a6d69SChristof Schmitt 		if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
588e60a6d69SChristof Schmitt 			act->fsf_req_id = 0;
589287ac01aSChristof Schmitt 	} else
590e60a6d69SChristof Schmitt 		act->fsf_req_id = 0;
591b6bd2fb9SChristof Schmitt 	spin_unlock(&adapter->req_list->lock);
592507e4969SMartin Peschke }
5931da177e4SLinus Torvalds 
594f6c0e7a7SAndreas Herrmann /**
595287ac01aSChristof Schmitt  * zfcp_erp_notify - Trigger ERP action.
596287ac01aSChristof Schmitt  * @erp_action: ERP action to continue.
597287ac01aSChristof Schmitt  * @set_mask: ERP action status flags to set.
5981da177e4SLinus Torvalds  */
zfcp_erp_notify(struct zfcp_erp_action * erp_action,unsigned long set_mask)599287ac01aSChristof Schmitt void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask)
6001da177e4SLinus Torvalds {
601287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = erp_action->adapter;
602287ac01aSChristof Schmitt 	unsigned long flags;
603287ac01aSChristof Schmitt 
604287ac01aSChristof Schmitt 	write_lock_irqsave(&adapter->erp_lock, flags);
605013af857SSteffen Maier 	if (zfcp_erp_action_is_running(erp_action)) {
6061da177e4SLinus Torvalds 		erp_action->status |= set_mask;
6071da177e4SLinus Torvalds 		zfcp_erp_action_ready(erp_action);
608f6c0e7a7SAndreas Herrmann 	}
6091da177e4SLinus Torvalds 	write_unlock_irqrestore(&adapter->erp_lock, flags);
6101da177e4SLinus Torvalds }
6111da177e4SLinus Torvalds 
612f6c0e7a7SAndreas Herrmann /**
613287ac01aSChristof Schmitt  * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request
6148684d614SSteffen Maier  * @t: timer list entry embedded in zfcp FSF request
6151da177e4SLinus Torvalds  */
zfcp_erp_timeout_handler(struct timer_list * t)61675492a51SKees Cook void zfcp_erp_timeout_handler(struct timer_list *t)
6171da177e4SLinus Torvalds {
61875492a51SKees Cook 	struct zfcp_fsf_req *fsf_req = from_timer(fsf_req, t, timer);
619936e6b85SSteffen Maier 	struct zfcp_erp_action *act;
6205c13db9bSSteffen Maier 
621936e6b85SSteffen Maier 	if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
622936e6b85SSteffen Maier 		return;
623936e6b85SSteffen Maier 	/* lock-free concurrent access with zfcp_erp_strategy_check_fsfreq() */
624936e6b85SSteffen Maier 	act = READ_ONCE(fsf_req->erp_action);
625936e6b85SSteffen Maier 	if (!act)
626936e6b85SSteffen Maier 		return;
627287ac01aSChristof Schmitt 	zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT);
6281da177e4SLinus Torvalds }
6291da177e4SLinus Torvalds 
zfcp_erp_memwait_handler(struct timer_list * t)63075492a51SKees Cook static void zfcp_erp_memwait_handler(struct timer_list *t)
6311da177e4SLinus Torvalds {
63275492a51SKees Cook 	struct zfcp_erp_action *act = from_timer(act, t, timer);
63375492a51SKees Cook 
63475492a51SKees Cook 	zfcp_erp_notify(act, 0);
6351da177e4SLinus Torvalds }
6361da177e4SLinus Torvalds 
zfcp_erp_strategy_memwait(struct zfcp_erp_action * erp_action)637287ac01aSChristof Schmitt static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
6381da177e4SLinus Torvalds {
6395c13db9bSSteffen Maier 	timer_setup(&erp_action->timer, zfcp_erp_memwait_handler, 0);
640287ac01aSChristof Schmitt 	erp_action->timer.expires = jiffies + HZ;
6411da177e4SLinus Torvalds 	add_timer(&erp_action->timer);
642287ac01aSChristof Schmitt }
643287ac01aSChristof Schmitt 
zfcp_erp_port_forced_reopen_all(struct zfcp_adapter * adapter,int clear,char * dbftag)644242ec145SSteffen Maier void zfcp_erp_port_forced_reopen_all(struct zfcp_adapter *adapter,
645242ec145SSteffen Maier 				     int clear, char *dbftag)
646242ec145SSteffen Maier {
647242ec145SSteffen Maier 	unsigned long flags;
648242ec145SSteffen Maier 	struct zfcp_port *port;
649242ec145SSteffen Maier 
650242ec145SSteffen Maier 	write_lock_irqsave(&adapter->erp_lock, flags);
651242ec145SSteffen Maier 	read_lock(&adapter->port_list_lock);
652242ec145SSteffen Maier 	list_for_each_entry(port, &adapter->port_list, list)
653242ec145SSteffen Maier 		_zfcp_erp_port_forced_reopen(port, clear, dbftag);
654242ec145SSteffen Maier 	read_unlock(&adapter->port_list_lock);
655242ec145SSteffen Maier 	write_unlock_irqrestore(&adapter->erp_lock, flags);
656242ec145SSteffen Maier }
657242ec145SSteffen Maier 
_zfcp_erp_port_reopen_all(struct zfcp_adapter * adapter,int clear,char * dbftag)658287ac01aSChristof Schmitt static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
659208d0961SSteffen Maier 				      int clear, char *dbftag)
660287ac01aSChristof Schmitt {
661287ac01aSChristof Schmitt 	struct zfcp_port *port;
662287ac01aSChristof Schmitt 
663ecf0c772SSwen Schillig 	read_lock(&adapter->port_list_lock);
664ecf0c772SSwen Schillig 	list_for_each_entry(port, &adapter->port_list, list)
665208d0961SSteffen Maier 		_zfcp_erp_port_reopen(port, clear, dbftag);
666ecf0c772SSwen Schillig 	read_unlock(&adapter->port_list_lock);
667287ac01aSChristof Schmitt }
668287ac01aSChristof Schmitt 
_zfcp_erp_lun_reopen_all(struct zfcp_port * port,int clear,char * dbftag)669b62a8d9bSChristof Schmitt static void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear,
670208d0961SSteffen Maier 				     char *dbftag)
671287ac01aSChristof Schmitt {
672b62a8d9bSChristof Schmitt 	struct scsi_device *sdev;
673287ac01aSChristof Schmitt 
674924dd584SMartin Peschke 	spin_lock(port->adapter->scsi_host->host_lock);
675924dd584SMartin Peschke 	__shost_for_each_device(sdev, port->adapter->scsi_host)
676b62a8d9bSChristof Schmitt 		if (sdev_to_zfcp(sdev)->port == port)
677208d0961SSteffen Maier 			_zfcp_erp_lun_reopen(sdev, clear, dbftag, 0);
678924dd584SMartin Peschke 	spin_unlock(port->adapter->scsi_host->host_lock);
679287ac01aSChristof Schmitt }
680287ac01aSChristof Schmitt 
zfcp_erp_strategy_followup_failed(struct zfcp_erp_action * act)68185600f7fSChristof Schmitt static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
682287ac01aSChristof Schmitt {
683df91eefdSSteffen Maier 	switch (act->type) {
684287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
685ea4a3a6aSSwen Schillig 		_zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1");
686287ac01aSChristof Schmitt 		break;
687287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
688ea4a3a6aSSwen Schillig 		_zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2");
689287ac01aSChristof Schmitt 		break;
690287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
691ea4a3a6aSSwen Schillig 		_zfcp_erp_port_reopen(act->port, 0, "ersff_3");
692287ac01aSChristof Schmitt 		break;
693b62a8d9bSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_LUN:
694ea4a3a6aSSwen Schillig 		_zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", 0);
69585600f7fSChristof Schmitt 		break;
69685600f7fSChristof Schmitt 	}
69785600f7fSChristof Schmitt }
69885600f7fSChristof Schmitt 
zfcp_erp_strategy_followup_success(struct zfcp_erp_action * act)69985600f7fSChristof Schmitt static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act)
70085600f7fSChristof Schmitt {
701df91eefdSSteffen Maier 	switch (act->type) {
70285600f7fSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
703ea4a3a6aSSwen Schillig 		_zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1");
70485600f7fSChristof Schmitt 		break;
70585600f7fSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
706ea4a3a6aSSwen Schillig 		_zfcp_erp_port_reopen(act->port, 0, "ersfs_2");
70785600f7fSChristof Schmitt 		break;
70885600f7fSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
709ea4a3a6aSSwen Schillig 		_zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3");
710287ac01aSChristof Schmitt 		break;
711df91eefdSSteffen Maier 	case ZFCP_ERP_ACTION_REOPEN_LUN:
712df91eefdSSteffen Maier 		/* NOP */
713df91eefdSSteffen Maier 		break;
714287ac01aSChristof Schmitt 	}
715287ac01aSChristof Schmitt }
716287ac01aSChristof Schmitt 
zfcp_erp_wakeup(struct zfcp_adapter * adapter)717287ac01aSChristof Schmitt static void zfcp_erp_wakeup(struct zfcp_adapter *adapter)
718287ac01aSChristof Schmitt {
719287ac01aSChristof Schmitt 	unsigned long flags;
720287ac01aSChristof Schmitt 
721ecf0c772SSwen Schillig 	read_lock_irqsave(&adapter->erp_lock, flags);
722287ac01aSChristof Schmitt 	if (list_empty(&adapter->erp_ready_head) &&
723287ac01aSChristof Schmitt 	    list_empty(&adapter->erp_running_head)) {
724805de8f4SPeter Zijlstra 			atomic_andnot(ZFCP_STATUS_ADAPTER_ERP_PENDING,
725287ac01aSChristof Schmitt 					  &adapter->status);
726287ac01aSChristof Schmitt 			wake_up(&adapter->erp_done_wqh);
727287ac01aSChristof Schmitt 	}
728ecf0c772SSwen Schillig 	read_unlock_irqrestore(&adapter->erp_lock, flags);
729287ac01aSChristof Schmitt }
730287ac01aSChristof Schmitt 
zfcp_erp_enqueue_ptp_port(struct zfcp_adapter * adapter)731287ac01aSChristof Schmitt static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
732287ac01aSChristof Schmitt {
733287ac01aSChristof Schmitt 	struct zfcp_port *port;
734287ac01aSChristof Schmitt 	port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0,
735287ac01aSChristof Schmitt 				 adapter->peer_d_id);
736287ac01aSChristof Schmitt 	if (IS_ERR(port)) /* error or port already attached */
737287ac01aSChristof Schmitt 		return;
738819732beSSteffen Maier 	zfcp_erp_port_reopen(port, 0, "ereptp1");
739287ac01aSChristof Schmitt }
740287ac01aSChristof Schmitt 
zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action * erp_action)741d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_adapter_strat_fsf_xconf(
742d5fcdcedSSteffen Maier 	struct zfcp_erp_action *erp_action)
743287ac01aSChristof Schmitt {
744287ac01aSChristof Schmitt 	int retries;
745287ac01aSChristof Schmitt 	int sleep = 1;
746287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = erp_action->adapter;
747287ac01aSChristof Schmitt 
748805de8f4SPeter Zijlstra 	atomic_andnot(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
749287ac01aSChristof Schmitt 
750287ac01aSChristof Schmitt 	for (retries = 7; retries; retries--) {
751805de8f4SPeter Zijlstra 		atomic_andnot(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
752287ac01aSChristof Schmitt 				  &adapter->status);
753287ac01aSChristof Schmitt 		write_lock_irq(&adapter->erp_lock);
754287ac01aSChristof Schmitt 		zfcp_erp_action_to_running(erp_action);
755287ac01aSChristof Schmitt 		write_unlock_irq(&adapter->erp_lock);
756287ac01aSChristof Schmitt 		if (zfcp_fsf_exchange_config_data(erp_action)) {
757805de8f4SPeter Zijlstra 			atomic_andnot(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
758287ac01aSChristof Schmitt 					  &adapter->status);
759287ac01aSChristof Schmitt 			return ZFCP_ERP_FAILED;
760287ac01aSChristof Schmitt 		}
761287ac01aSChristof Schmitt 
762347c6a96SChristof Schmitt 		wait_event(adapter->erp_ready_wq,
763347c6a96SChristof Schmitt 			   !list_empty(&adapter->erp_ready_head));
764287ac01aSChristof Schmitt 		if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
765287ac01aSChristof Schmitt 			break;
766287ac01aSChristof Schmitt 
767287ac01aSChristof Schmitt 		if (!(atomic_read(&adapter->status) &
768287ac01aSChristof Schmitt 		      ZFCP_STATUS_ADAPTER_HOST_CON_INIT))
769287ac01aSChristof Schmitt 			break;
770287ac01aSChristof Schmitt 
771287ac01aSChristof Schmitt 		ssleep(sleep);
772287ac01aSChristof Schmitt 		sleep *= 2;
773287ac01aSChristof Schmitt 	}
774287ac01aSChristof Schmitt 
775805de8f4SPeter Zijlstra 	atomic_andnot(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
776287ac01aSChristof Schmitt 			  &adapter->status);
777287ac01aSChristof Schmitt 
778287ac01aSChristof Schmitt 	if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK))
779287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
780287ac01aSChristof Schmitt 
781ac007adcSBenjamin Block 	return ZFCP_ERP_SUCCEEDED;
782ac007adcSBenjamin Block }
783ac007adcSBenjamin Block 
784ac007adcSBenjamin Block static void
zfcp_erp_adapter_strategy_open_ptp_port(struct zfcp_adapter * const adapter)785ac007adcSBenjamin Block zfcp_erp_adapter_strategy_open_ptp_port(struct zfcp_adapter *const adapter)
786ac007adcSBenjamin Block {
787287ac01aSChristof Schmitt 	if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
788287ac01aSChristof Schmitt 		zfcp_erp_enqueue_ptp_port(adapter);
789287ac01aSChristof Schmitt }
790287ac01aSChristof Schmitt 
zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action * act)791d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_adapter_strategy_open_fsf_xport(
792d5fcdcedSSteffen Maier 	struct zfcp_erp_action *act)
793287ac01aSChristof Schmitt {
794287ac01aSChristof Schmitt 	int ret;
795287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
796287ac01aSChristof Schmitt 
797287ac01aSChristof Schmitt 	write_lock_irq(&adapter->erp_lock);
798287ac01aSChristof Schmitt 	zfcp_erp_action_to_running(act);
799287ac01aSChristof Schmitt 	write_unlock_irq(&adapter->erp_lock);
800287ac01aSChristof Schmitt 
801287ac01aSChristof Schmitt 	ret = zfcp_fsf_exchange_port_data(act);
802287ac01aSChristof Schmitt 	if (ret == -EOPNOTSUPP)
803287ac01aSChristof Schmitt 		return ZFCP_ERP_SUCCEEDED;
804287ac01aSChristof Schmitt 	if (ret)
805287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
806287ac01aSChristof Schmitt 
807ae0904f6SSwen Schillig 	zfcp_dbf_rec_run("erasox1", act);
808347c6a96SChristof Schmitt 	wait_event(adapter->erp_ready_wq,
809347c6a96SChristof Schmitt 		   !list_empty(&adapter->erp_ready_head));
810ae0904f6SSwen Schillig 	zfcp_dbf_rec_run("erasox2", act);
811287ac01aSChristof Schmitt 	if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
812287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
813287ac01aSChristof Schmitt 
814287ac01aSChristof Schmitt 	return ZFCP_ERP_SUCCEEDED;
815287ac01aSChristof Schmitt }
816287ac01aSChristof Schmitt 
817d0dff2acSBenjamin Block static enum zfcp_erp_act_result
zfcp_erp_adapter_strategy_alloc_shost(struct zfcp_adapter * const adapter)818d0dff2acSBenjamin Block zfcp_erp_adapter_strategy_alloc_shost(struct zfcp_adapter *const adapter)
819d0dff2acSBenjamin Block {
820d0dff2acSBenjamin Block 	struct zfcp_diag_adapter_config_data *const config_data =
821d0dff2acSBenjamin Block 		&adapter->diagnostics->config_data;
822d0dff2acSBenjamin Block 	struct zfcp_diag_adapter_port_data *const port_data =
823d0dff2acSBenjamin Block 		&adapter->diagnostics->port_data;
824d0dff2acSBenjamin Block 	unsigned long flags;
825d0dff2acSBenjamin Block 	int rc;
826d0dff2acSBenjamin Block 
827d0dff2acSBenjamin Block 	rc = zfcp_scsi_adapter_register(adapter);
828d0dff2acSBenjamin Block 	if (rc == -EEXIST)
829d0dff2acSBenjamin Block 		return ZFCP_ERP_SUCCEEDED;
830d0dff2acSBenjamin Block 	else if (rc)
831d0dff2acSBenjamin Block 		return ZFCP_ERP_FAILED;
832d0dff2acSBenjamin Block 
833d0dff2acSBenjamin Block 	/*
834d0dff2acSBenjamin Block 	 * We allocated the shost for the first time. Before it was NULL,
835d0dff2acSBenjamin Block 	 * and so we deferred all updates in the xconf- and xport-data
836d0dff2acSBenjamin Block 	 * handlers. We need to make up for that now, and make all the updates
837d0dff2acSBenjamin Block 	 * that would have been done before.
838d0dff2acSBenjamin Block 	 *
839d0dff2acSBenjamin Block 	 * We can be sure that xconf- and xport-data succeeded, because
840d0dff2acSBenjamin Block 	 * otherwise this function is not called. But they might have been
841d0dff2acSBenjamin Block 	 * incomplete.
842d0dff2acSBenjamin Block 	 */
843d0dff2acSBenjamin Block 
844d0dff2acSBenjamin Block 	spin_lock_irqsave(&config_data->header.access_lock, flags);
845d0dff2acSBenjamin Block 	zfcp_scsi_shost_update_config_data(adapter, &config_data->data,
846d0dff2acSBenjamin Block 					   !!config_data->header.incomplete);
847d0dff2acSBenjamin Block 	spin_unlock_irqrestore(&config_data->header.access_lock, flags);
848d0dff2acSBenjamin Block 
849d0dff2acSBenjamin Block 	if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) {
850d0dff2acSBenjamin Block 		spin_lock_irqsave(&port_data->header.access_lock, flags);
851d0dff2acSBenjamin Block 		zfcp_scsi_shost_update_port_data(adapter, &port_data->data);
852d0dff2acSBenjamin Block 		spin_unlock_irqrestore(&port_data->header.access_lock, flags);
853d0dff2acSBenjamin Block 	}
854d0dff2acSBenjamin Block 
855d0dff2acSBenjamin Block 	/*
856d0dff2acSBenjamin Block 	 * There is a remote possibility that the 'Exchange Port Data' request
857d0dff2acSBenjamin Block 	 * reports a different connectivity status than 'Exchange Config Data'.
858d0dff2acSBenjamin Block 	 * But any change to the connectivity status of the local optic that
859d0dff2acSBenjamin Block 	 * happens after the initial xconf request is expected to be reported
860d0dff2acSBenjamin Block 	 * to us, as soon as we post Status Read Buffers to the FCP channel
861d0dff2acSBenjamin Block 	 * firmware after this function. So any resulting inconsistency will
862d0dff2acSBenjamin Block 	 * only be momentary.
863d0dff2acSBenjamin Block 	 */
864d0dff2acSBenjamin Block 	if (config_data->header.incomplete)
865d0dff2acSBenjamin Block 		zfcp_fsf_fc_host_link_down(adapter);
866d0dff2acSBenjamin Block 
867d0dff2acSBenjamin Block 	return ZFCP_ERP_SUCCEEDED;
868d0dff2acSBenjamin Block }
869d0dff2acSBenjamin Block 
zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action * act)870d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_adapter_strategy_open_fsf(
871d5fcdcedSSteffen Maier 	struct zfcp_erp_action *act)
872287ac01aSChristof Schmitt {
873287ac01aSChristof Schmitt 	if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED)
874287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
875287ac01aSChristof Schmitt 
876287ac01aSChristof Schmitt 	if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)
877287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
878287ac01aSChristof Schmitt 
879d0dff2acSBenjamin Block 	if (zfcp_erp_adapter_strategy_alloc_shost(act->adapter) ==
880d0dff2acSBenjamin Block 	    ZFCP_ERP_FAILED)
881d0dff2acSBenjamin Block 		return ZFCP_ERP_FAILED;
882d0dff2acSBenjamin Block 
883ac007adcSBenjamin Block 	zfcp_erp_adapter_strategy_open_ptp_port(act->adapter);
884ac007adcSBenjamin Block 
885c7b279aeSChristof Schmitt 	if (mempool_resize(act->adapter->pool.sr_data,
88611d83360SDavid Rientjes 			   act->adapter->stat_read_buf_num))
8878d88cf3fSChristof Schmitt 		return ZFCP_ERP_FAILED;
8888d88cf3fSChristof Schmitt 
8898d88cf3fSChristof Schmitt 	if (mempool_resize(act->adapter->pool.status_read_req,
89011d83360SDavid Rientjes 			   act->adapter->stat_read_buf_num))
8918d88cf3fSChristof Schmitt 		return ZFCP_ERP_FAILED;
8928d88cf3fSChristof Schmitt 
89364deb6efSChristof Schmitt 	atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num);
894287ac01aSChristof Schmitt 	if (zfcp_status_read_refill(act->adapter))
895287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
896287ac01aSChristof Schmitt 
897287ac01aSChristof Schmitt 	return ZFCP_ERP_SUCCEEDED;
898287ac01aSChristof Schmitt }
899287ac01aSChristof Schmitt 
zfcp_erp_adapter_strategy_close(struct zfcp_erp_action * act)900cf13c082SSwen Schillig static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act)
901287ac01aSChristof Schmitt {
902287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
903287ac01aSChristof Schmitt 
904287ac01aSChristof Schmitt 	/* close queues to ensure that buffers are not accessed by adapter */
905564e1c86SSwen Schillig 	zfcp_qdio_close(adapter->qdio);
906287ac01aSChristof Schmitt 	zfcp_fsf_req_dismiss_all(adapter);
907287ac01aSChristof Schmitt 	adapter->fsf_req_seq_no = 0;
90855c770faSChristof Schmitt 	zfcp_fc_wka_ports_force_offline(adapter->gs);
909b62a8d9bSChristof Schmitt 	/* all ports and LUNs are closed */
910edaed859SSwen Schillig 	zfcp_erp_clear_adapter_status(adapter, ZFCP_STATUS_COMMON_OPEN);
911cf13c082SSwen Schillig 
912805de8f4SPeter Zijlstra 	atomic_andnot(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
913cf13c082SSwen Schillig 			  ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
914cf13c082SSwen Schillig }
915cf13c082SSwen Schillig 
zfcp_erp_adapter_strategy_open(struct zfcp_erp_action * act)916d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_adapter_strategy_open(
917d5fcdcedSSteffen Maier 	struct zfcp_erp_action *act)
918cf13c082SSwen Schillig {
919cf13c082SSwen Schillig 	struct zfcp_adapter *adapter = act->adapter;
920cf13c082SSwen Schillig 
9213d63d3b4SChristof Schmitt 	if (zfcp_qdio_open(adapter->qdio)) {
922805de8f4SPeter Zijlstra 		atomic_andnot(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
92344cc76f2SSwen Schillig 				  ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
924cf13c082SSwen Schillig 				  &adapter->status);
925cf13c082SSwen Schillig 		return ZFCP_ERP_FAILED;
926cf13c082SSwen Schillig 	}
927cf13c082SSwen Schillig 
928cf13c082SSwen Schillig 	if (zfcp_erp_adapter_strategy_open_fsf(act)) {
929cf13c082SSwen Schillig 		zfcp_erp_adapter_strategy_close(act);
930cf13c082SSwen Schillig 		return ZFCP_ERP_FAILED;
931cf13c082SSwen Schillig 	}
932cf13c082SSwen Schillig 
933805de8f4SPeter Zijlstra 	atomic_or(ZFCP_STATUS_COMMON_OPEN, &adapter->status);
934cf13c082SSwen Schillig 
935cf13c082SSwen Schillig 	return ZFCP_ERP_SUCCEEDED;
936287ac01aSChristof Schmitt }
937287ac01aSChristof Schmitt 
zfcp_erp_adapter_strategy(struct zfcp_erp_action * act)938d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_adapter_strategy(
939d5fcdcedSSteffen Maier 	struct zfcp_erp_action *act)
940287ac01aSChristof Schmitt {
941cf13c082SSwen Schillig 	struct zfcp_adapter *adapter = act->adapter;
942287ac01aSChristof Schmitt 
943cf13c082SSwen Schillig 	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN) {
944cf13c082SSwen Schillig 		zfcp_erp_adapter_strategy_close(act);
945287ac01aSChristof Schmitt 		if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
946287ac01aSChristof Schmitt 			return ZFCP_ERP_EXIT;
947cf13c082SSwen Schillig 	}
948287ac01aSChristof Schmitt 
949cf13c082SSwen Schillig 	if (zfcp_erp_adapter_strategy_open(act)) {
950287ac01aSChristof Schmitt 		ssleep(8);
951cf13c082SSwen Schillig 		return ZFCP_ERP_FAILED;
952cf13c082SSwen Schillig 	}
9531da177e4SLinus Torvalds 
954cf13c082SSwen Schillig 	return ZFCP_ERP_SUCCEEDED;
9551da177e4SLinus Torvalds }
9561da177e4SLinus Torvalds 
zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action * act)957d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_port_forced_strategy_close(
958d5fcdcedSSteffen Maier 	struct zfcp_erp_action *act)
9591da177e4SLinus Torvalds {
960287ac01aSChristof Schmitt 	int retval;
961287ac01aSChristof Schmitt 
962287ac01aSChristof Schmitt 	retval = zfcp_fsf_close_physical_port(act);
963287ac01aSChristof Schmitt 	if (retval == -ENOMEM)
964287ac01aSChristof Schmitt 		return ZFCP_ERP_NOMEM;
965287ac01aSChristof Schmitt 	act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING;
966287ac01aSChristof Schmitt 	if (retval)
967287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
968287ac01aSChristof Schmitt 
969287ac01aSChristof Schmitt 	return ZFCP_ERP_CONTINUES;
9701da177e4SLinus Torvalds }
9711da177e4SLinus Torvalds 
zfcp_erp_port_forced_strategy(struct zfcp_erp_action * erp_action)972d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_port_forced_strategy(
973d5fcdcedSSteffen Maier 	struct zfcp_erp_action *erp_action)
974287ac01aSChristof Schmitt {
975287ac01aSChristof Schmitt 	struct zfcp_port *port = erp_action->port;
976287ac01aSChristof Schmitt 	int status = atomic_read(&port->status);
977287ac01aSChristof Schmitt 
978287ac01aSChristof Schmitt 	switch (erp_action->step) {
979287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNINITIALIZED:
980287ac01aSChristof Schmitt 		if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) &&
981287ac01aSChristof Schmitt 		    (status & ZFCP_STATUS_COMMON_OPEN))
982287ac01aSChristof Schmitt 			return zfcp_erp_port_forced_strategy_close(erp_action);
9831da177e4SLinus Torvalds 		else
984287ac01aSChristof Schmitt 			return ZFCP_ERP_FAILED;
985287ac01aSChristof Schmitt 
986287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
987ddb3e0c1SChristof Schmitt 		if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN))
988287ac01aSChristof Schmitt 			return ZFCP_ERP_SUCCEEDED;
9890023beecSSteffen Maier 		break;
9900023beecSSteffen Maier 	case ZFCP_ERP_STEP_PORT_CLOSING:
9910023beecSSteffen Maier 	case ZFCP_ERP_STEP_PORT_OPENING:
9920023beecSSteffen Maier 	case ZFCP_ERP_STEP_LUN_CLOSING:
9930023beecSSteffen Maier 	case ZFCP_ERP_STEP_LUN_OPENING:
9940023beecSSteffen Maier 		/* NOP */
9950023beecSSteffen Maier 		break;
996287ac01aSChristof Schmitt 	}
997287ac01aSChristof Schmitt 	return ZFCP_ERP_FAILED;
9981da177e4SLinus Torvalds }
9991da177e4SLinus Torvalds 
zfcp_erp_port_strategy_close(struct zfcp_erp_action * erp_action)1000d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_port_strategy_close(
1001d5fcdcedSSteffen Maier 	struct zfcp_erp_action *erp_action)
10021da177e4SLinus Torvalds {
1003287ac01aSChristof Schmitt 	int retval;
10041da177e4SLinus Torvalds 
1005287ac01aSChristof Schmitt 	retval = zfcp_fsf_close_port(erp_action);
1006287ac01aSChristof Schmitt 	if (retval == -ENOMEM)
1007287ac01aSChristof Schmitt 		return ZFCP_ERP_NOMEM;
1008287ac01aSChristof Schmitt 	erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING;
1009287ac01aSChristof Schmitt 	if (retval)
1010287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
1011287ac01aSChristof Schmitt 	return ZFCP_ERP_CONTINUES;
10121da177e4SLinus Torvalds }
10131da177e4SLinus Torvalds 
zfcp_erp_port_strategy_open_port(struct zfcp_erp_action * erp_action)1014d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_port_strategy_open_port(
1015d5fcdcedSSteffen Maier 	struct zfcp_erp_action *erp_action)
1016287ac01aSChristof Schmitt {
1017287ac01aSChristof Schmitt 	int retval;
1018287ac01aSChristof Schmitt 
1019287ac01aSChristof Schmitt 	retval = zfcp_fsf_open_port(erp_action);
1020287ac01aSChristof Schmitt 	if (retval == -ENOMEM)
1021287ac01aSChristof Schmitt 		return ZFCP_ERP_NOMEM;
1022287ac01aSChristof Schmitt 	erp_action->step = ZFCP_ERP_STEP_PORT_OPENING;
1023287ac01aSChristof Schmitt 	if (retval)
1024287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
1025287ac01aSChristof Schmitt 	return ZFCP_ERP_CONTINUES;
1026287ac01aSChristof Schmitt }
1027287ac01aSChristof Schmitt 
zfcp_erp_open_ptp_port(struct zfcp_erp_action * act)1028287ac01aSChristof Schmitt static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
1029287ac01aSChristof Schmitt {
1030287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
1031287ac01aSChristof Schmitt 	struct zfcp_port *port = act->port;
1032287ac01aSChristof Schmitt 
1033287ac01aSChristof Schmitt 	if (port->wwpn != adapter->peer_wwpn) {
1034edaed859SSwen Schillig 		zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED);
1035287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
1036287ac01aSChristof Schmitt 	}
1037287ac01aSChristof Schmitt 	port->d_id = adapter->peer_d_id;
1038287ac01aSChristof Schmitt 	return zfcp_erp_port_strategy_open_port(act);
1039287ac01aSChristof Schmitt }
1040287ac01aSChristof Schmitt 
zfcp_erp_port_strategy_open_common(struct zfcp_erp_action * act)1041d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_port_strategy_open_common(
1042d5fcdcedSSteffen Maier 	struct zfcp_erp_action *act)
1043287ac01aSChristof Schmitt {
1044287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
1045287ac01aSChristof Schmitt 	struct zfcp_port *port = act->port;
1046287ac01aSChristof Schmitt 	int p_status = atomic_read(&port->status);
1047287ac01aSChristof Schmitt 
1048287ac01aSChristof Schmitt 	switch (act->step) {
1049287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNINITIALIZED:
1050287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
1051287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_PORT_CLOSING:
1052287ac01aSChristof Schmitt 		if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
1053287ac01aSChristof Schmitt 			return zfcp_erp_open_ptp_port(act);
1054b98478d7SChristof Schmitt 		if (!port->d_id) {
1055934aeb58SChristof Schmitt 			zfcp_fc_trigger_did_lookup(port);
1056799b76d0SChristof Schmitt 			return ZFCP_ERP_EXIT;
1057287ac01aSChristof Schmitt 		}
1058287ac01aSChristof Schmitt 		return zfcp_erp_port_strategy_open_port(act);
1059287ac01aSChristof Schmitt 
1060287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_PORT_OPENING:
1061287ac01aSChristof Schmitt 		/* D_ID might have changed during open */
10625ab944f9SSwen Schillig 		if (p_status & ZFCP_STATUS_COMMON_OPEN) {
1063934aeb58SChristof Schmitt 			if (!port->d_id) {
1064934aeb58SChristof Schmitt 				zfcp_fc_trigger_did_lookup(port);
1065934aeb58SChristof Schmitt 				return ZFCP_ERP_EXIT;
10665ab944f9SSwen Schillig 			}
1067934aeb58SChristof Schmitt 			return ZFCP_ERP_SUCCEEDED;
1068287ac01aSChristof Schmitt 		}
1069ea460a81SSwen Schillig 		if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
1070ea460a81SSwen Schillig 			port->d_id = 0;
1071f7bd7c36SChristof Schmitt 			return ZFCP_ERP_FAILED;
1072ea460a81SSwen Schillig 		}
10730023beecSSteffen Maier 		/* no early return otherwise, continue after switch case */
10740023beecSSteffen Maier 		break;
10750023beecSSteffen Maier 	case ZFCP_ERP_STEP_LUN_CLOSING:
10760023beecSSteffen Maier 	case ZFCP_ERP_STEP_LUN_OPENING:
10770023beecSSteffen Maier 		/* NOP */
10780023beecSSteffen Maier 		break;
1079287ac01aSChristof Schmitt 	}
10805ab944f9SSwen Schillig 	return ZFCP_ERP_FAILED;
1081287ac01aSChristof Schmitt }
1082287ac01aSChristof Schmitt 
zfcp_erp_port_strategy(struct zfcp_erp_action * erp_action)1083d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_port_strategy(
1084d5fcdcedSSteffen Maier 	struct zfcp_erp_action *erp_action)
1085287ac01aSChristof Schmitt {
1086287ac01aSChristof Schmitt 	struct zfcp_port *port = erp_action->port;
1087934aeb58SChristof Schmitt 	int p_status = atomic_read(&port->status);
1088287ac01aSChristof Schmitt 
1089934aeb58SChristof Schmitt 	if ((p_status & ZFCP_STATUS_COMMON_NOESC) &&
1090934aeb58SChristof Schmitt 	    !(p_status & ZFCP_STATUS_COMMON_OPEN))
10915ab944f9SSwen Schillig 		goto close_init_done;
10925ab944f9SSwen Schillig 
1093287ac01aSChristof Schmitt 	switch (erp_action->step) {
1094287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNINITIALIZED:
1095934aeb58SChristof Schmitt 		if (p_status & ZFCP_STATUS_COMMON_OPEN)
1096287ac01aSChristof Schmitt 			return zfcp_erp_port_strategy_close(erp_action);
1097287ac01aSChristof Schmitt 		break;
1098287ac01aSChristof Schmitt 
1099287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_PORT_CLOSING:
1100934aeb58SChristof Schmitt 		if (p_status & ZFCP_STATUS_COMMON_OPEN)
1101287ac01aSChristof Schmitt 			return ZFCP_ERP_FAILED;
1102287ac01aSChristof Schmitt 		break;
11030023beecSSteffen Maier 	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
11040023beecSSteffen Maier 	case ZFCP_ERP_STEP_PORT_OPENING:
11050023beecSSteffen Maier 	case ZFCP_ERP_STEP_LUN_CLOSING:
11060023beecSSteffen Maier 	case ZFCP_ERP_STEP_LUN_OPENING:
11070023beecSSteffen Maier 		/* NOP */
11080023beecSSteffen Maier 		break;
1109287ac01aSChristof Schmitt 	}
11105ab944f9SSwen Schillig 
11115ab944f9SSwen Schillig close_init_done:
1112287ac01aSChristof Schmitt 	if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
1113287ac01aSChristof Schmitt 		return ZFCP_ERP_EXIT;
1114287ac01aSChristof Schmitt 
11155ab944f9SSwen Schillig 	return zfcp_erp_port_strategy_open_common(erp_action);
1116287ac01aSChristof Schmitt }
1117287ac01aSChristof Schmitt 
zfcp_erp_lun_strategy_clearstati(struct scsi_device * sdev)1118b62a8d9bSChristof Schmitt static void zfcp_erp_lun_strategy_clearstati(struct scsi_device *sdev)
1119287ac01aSChristof Schmitt {
1120b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
1121b62a8d9bSChristof Schmitt 
1122805de8f4SPeter Zijlstra 	atomic_andnot(ZFCP_STATUS_COMMON_ACCESS_DENIED,
1123b62a8d9bSChristof Schmitt 			  &zfcp_sdev->status);
1124287ac01aSChristof Schmitt }
1125287ac01aSChristof Schmitt 
zfcp_erp_lun_strategy_close(struct zfcp_erp_action * erp_action)1126d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_lun_strategy_close(
1127d5fcdcedSSteffen Maier 	struct zfcp_erp_action *erp_action)
1128287ac01aSChristof Schmitt {
1129b62a8d9bSChristof Schmitt 	int retval = zfcp_fsf_close_lun(erp_action);
1130287ac01aSChristof Schmitt 	if (retval == -ENOMEM)
1131287ac01aSChristof Schmitt 		return ZFCP_ERP_NOMEM;
1132b62a8d9bSChristof Schmitt 	erp_action->step = ZFCP_ERP_STEP_LUN_CLOSING;
1133287ac01aSChristof Schmitt 	if (retval)
1134287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
1135287ac01aSChristof Schmitt 	return ZFCP_ERP_CONTINUES;
1136287ac01aSChristof Schmitt }
1137287ac01aSChristof Schmitt 
zfcp_erp_lun_strategy_open(struct zfcp_erp_action * erp_action)1138d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_lun_strategy_open(
1139d5fcdcedSSteffen Maier 	struct zfcp_erp_action *erp_action)
1140287ac01aSChristof Schmitt {
1141b62a8d9bSChristof Schmitt 	int retval = zfcp_fsf_open_lun(erp_action);
1142287ac01aSChristof Schmitt 	if (retval == -ENOMEM)
1143287ac01aSChristof Schmitt 		return ZFCP_ERP_NOMEM;
1144b62a8d9bSChristof Schmitt 	erp_action->step = ZFCP_ERP_STEP_LUN_OPENING;
1145287ac01aSChristof Schmitt 	if (retval)
1146287ac01aSChristof Schmitt 		return  ZFCP_ERP_FAILED;
1147287ac01aSChristof Schmitt 	return ZFCP_ERP_CONTINUES;
1148287ac01aSChristof Schmitt }
1149287ac01aSChristof Schmitt 
zfcp_erp_lun_strategy(struct zfcp_erp_action * erp_action)1150d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_lun_strategy(
1151d5fcdcedSSteffen Maier 	struct zfcp_erp_action *erp_action)
1152287ac01aSChristof Schmitt {
1153b62a8d9bSChristof Schmitt 	struct scsi_device *sdev = erp_action->sdev;
1154b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
1155287ac01aSChristof Schmitt 
1156287ac01aSChristof Schmitt 	switch (erp_action->step) {
1157287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNINITIALIZED:
1158b62a8d9bSChristof Schmitt 		zfcp_erp_lun_strategy_clearstati(sdev);
1159b62a8d9bSChristof Schmitt 		if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
1160b62a8d9bSChristof Schmitt 			return zfcp_erp_lun_strategy_close(erp_action);
11613505144eSSteffen Maier 		/* already closed */
1162cec9cbacSJoe Perches 		fallthrough;
1163b62a8d9bSChristof Schmitt 	case ZFCP_ERP_STEP_LUN_CLOSING:
1164b62a8d9bSChristof Schmitt 		if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
1165287ac01aSChristof Schmitt 			return ZFCP_ERP_FAILED;
1166287ac01aSChristof Schmitt 		if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
1167287ac01aSChristof Schmitt 			return ZFCP_ERP_EXIT;
1168b62a8d9bSChristof Schmitt 		return zfcp_erp_lun_strategy_open(erp_action);
1169287ac01aSChristof Schmitt 
1170b62a8d9bSChristof Schmitt 	case ZFCP_ERP_STEP_LUN_OPENING:
1171b62a8d9bSChristof Schmitt 		if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
1172287ac01aSChristof Schmitt 			return ZFCP_ERP_SUCCEEDED;
11730023beecSSteffen Maier 		break;
11740023beecSSteffen Maier 	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
11750023beecSSteffen Maier 	case ZFCP_ERP_STEP_PORT_CLOSING:
11760023beecSSteffen Maier 	case ZFCP_ERP_STEP_PORT_OPENING:
11770023beecSSteffen Maier 		/* NOP */
11780023beecSSteffen Maier 		break;
1179287ac01aSChristof Schmitt 	}
1180287ac01aSChristof Schmitt 	return ZFCP_ERP_FAILED;
1181287ac01aSChristof Schmitt }
1182287ac01aSChristof Schmitt 
zfcp_erp_strategy_check_lun(struct scsi_device * sdev,enum zfcp_erp_act_result result)1183d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_strategy_check_lun(
1184d5fcdcedSSteffen Maier 	struct scsi_device *sdev, enum zfcp_erp_act_result result)
1185287ac01aSChristof Schmitt {
1186b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
1187b62a8d9bSChristof Schmitt 
1188287ac01aSChristof Schmitt 	switch (result) {
1189287ac01aSChristof Schmitt 	case ZFCP_ERP_SUCCEEDED :
1190b62a8d9bSChristof Schmitt 		atomic_set(&zfcp_sdev->erp_counter, 0);
1191b62a8d9bSChristof Schmitt 		zfcp_erp_lun_unblock(sdev);
1192287ac01aSChristof Schmitt 		break;
1193287ac01aSChristof Schmitt 	case ZFCP_ERP_FAILED :
1194b62a8d9bSChristof Schmitt 		atomic_inc(&zfcp_sdev->erp_counter);
1195b62a8d9bSChristof Schmitt 		if (atomic_read(&zfcp_sdev->erp_counter) > ZFCP_MAX_ERPS) {
1196b62a8d9bSChristof Schmitt 			dev_err(&zfcp_sdev->port->adapter->ccw_device->dev,
1197b62a8d9bSChristof Schmitt 				"ERP failed for LUN 0x%016Lx on "
1198ff3b24faSChristof Schmitt 				"port 0x%016Lx\n",
1199b62a8d9bSChristof Schmitt 				(unsigned long long)zfcp_scsi_dev_lun(sdev),
1200b62a8d9bSChristof Schmitt 				(unsigned long long)zfcp_sdev->port->wwpn);
1201edaed859SSwen Schillig 			zfcp_erp_set_lun_status(sdev,
1202edaed859SSwen Schillig 						ZFCP_STATUS_COMMON_ERP_FAILED);
1203ff3b24faSChristof Schmitt 		}
1204287ac01aSChristof Schmitt 		break;
1205d5fcdcedSSteffen Maier 	case ZFCP_ERP_CONTINUES:
1206d5fcdcedSSteffen Maier 	case ZFCP_ERP_EXIT:
1207d5fcdcedSSteffen Maier 	case ZFCP_ERP_DISMISSED:
1208d5fcdcedSSteffen Maier 	case ZFCP_ERP_NOMEM:
1209d5fcdcedSSteffen Maier 		/* NOP */
1210d5fcdcedSSteffen Maier 		break;
1211287ac01aSChristof Schmitt 	}
1212287ac01aSChristof Schmitt 
1213b62a8d9bSChristof Schmitt 	if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1214b62a8d9bSChristof Schmitt 		zfcp_erp_lun_block(sdev, 0);
1215287ac01aSChristof Schmitt 		result = ZFCP_ERP_EXIT;
1216287ac01aSChristof Schmitt 	}
1217287ac01aSChristof Schmitt 	return result;
1218287ac01aSChristof Schmitt }
1219287ac01aSChristof Schmitt 
zfcp_erp_strategy_check_port(struct zfcp_port * port,enum zfcp_erp_act_result result)1220d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_strategy_check_port(
1221d5fcdcedSSteffen Maier 	struct zfcp_port *port, enum zfcp_erp_act_result result)
1222287ac01aSChristof Schmitt {
1223287ac01aSChristof Schmitt 	switch (result) {
1224287ac01aSChristof Schmitt 	case ZFCP_ERP_SUCCEEDED :
1225287ac01aSChristof Schmitt 		atomic_set(&port->erp_counter, 0);
1226287ac01aSChristof Schmitt 		zfcp_erp_port_unblock(port);
1227287ac01aSChristof Schmitt 		break;
1228287ac01aSChristof Schmitt 
1229287ac01aSChristof Schmitt 	case ZFCP_ERP_FAILED :
1230287ac01aSChristof Schmitt 		if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) {
1231287ac01aSChristof Schmitt 			zfcp_erp_port_block(port, 0);
1232287ac01aSChristof Schmitt 			result = ZFCP_ERP_EXIT;
1233287ac01aSChristof Schmitt 		}
1234287ac01aSChristof Schmitt 		atomic_inc(&port->erp_counter);
1235ff3b24faSChristof Schmitt 		if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
1236ff3b24faSChristof Schmitt 			dev_err(&port->adapter->ccw_device->dev,
1237ff3b24faSChristof Schmitt 				"ERP failed for remote port 0x%016Lx\n",
12387ba58c9cSSwen Schillig 				(unsigned long long)port->wwpn);
1239edaed859SSwen Schillig 			zfcp_erp_set_port_status(port,
1240edaed859SSwen Schillig 					 ZFCP_STATUS_COMMON_ERP_FAILED);
1241ff3b24faSChristof Schmitt 		}
1242287ac01aSChristof Schmitt 		break;
1243d5fcdcedSSteffen Maier 	case ZFCP_ERP_CONTINUES:
1244d5fcdcedSSteffen Maier 	case ZFCP_ERP_EXIT:
1245d5fcdcedSSteffen Maier 	case ZFCP_ERP_DISMISSED:
1246d5fcdcedSSteffen Maier 	case ZFCP_ERP_NOMEM:
1247d5fcdcedSSteffen Maier 		/* NOP */
1248d5fcdcedSSteffen Maier 		break;
1249287ac01aSChristof Schmitt 	}
1250287ac01aSChristof Schmitt 
1251287ac01aSChristof Schmitt 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1252287ac01aSChristof Schmitt 		zfcp_erp_port_block(port, 0);
1253287ac01aSChristof Schmitt 		result = ZFCP_ERP_EXIT;
1254287ac01aSChristof Schmitt 	}
1255287ac01aSChristof Schmitt 	return result;
1256287ac01aSChristof Schmitt }
1257287ac01aSChristof Schmitt 
zfcp_erp_strategy_check_adapter(struct zfcp_adapter * adapter,enum zfcp_erp_act_result result)1258d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_strategy_check_adapter(
1259d5fcdcedSSteffen Maier 	struct zfcp_adapter *adapter, enum zfcp_erp_act_result result)
1260287ac01aSChristof Schmitt {
1261287ac01aSChristof Schmitt 	switch (result) {
1262287ac01aSChristof Schmitt 	case ZFCP_ERP_SUCCEEDED :
1263287ac01aSChristof Schmitt 		atomic_set(&adapter->erp_counter, 0);
1264287ac01aSChristof Schmitt 		zfcp_erp_adapter_unblock(adapter);
1265287ac01aSChristof Schmitt 		break;
1266287ac01aSChristof Schmitt 
1267287ac01aSChristof Schmitt 	case ZFCP_ERP_FAILED :
1268287ac01aSChristof Schmitt 		atomic_inc(&adapter->erp_counter);
1269ff3b24faSChristof Schmitt 		if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) {
1270ff3b24faSChristof Schmitt 			dev_err(&adapter->ccw_device->dev,
1271ff3b24faSChristof Schmitt 				"ERP cannot recover an error "
1272ff3b24faSChristof Schmitt 				"on the FCP device\n");
1273edaed859SSwen Schillig 			zfcp_erp_set_adapter_status(adapter,
1274edaed859SSwen Schillig 					    ZFCP_STATUS_COMMON_ERP_FAILED);
1275ff3b24faSChristof Schmitt 		}
1276287ac01aSChristof Schmitt 		break;
1277d5fcdcedSSteffen Maier 	case ZFCP_ERP_CONTINUES:
1278d5fcdcedSSteffen Maier 	case ZFCP_ERP_EXIT:
1279d5fcdcedSSteffen Maier 	case ZFCP_ERP_DISMISSED:
1280d5fcdcedSSteffen Maier 	case ZFCP_ERP_NOMEM:
1281d5fcdcedSSteffen Maier 		/* NOP */
1282d5fcdcedSSteffen Maier 		break;
1283287ac01aSChristof Schmitt 	}
1284287ac01aSChristof Schmitt 
1285287ac01aSChristof Schmitt 	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1286287ac01aSChristof Schmitt 		zfcp_erp_adapter_block(adapter, 0);
1287287ac01aSChristof Schmitt 		result = ZFCP_ERP_EXIT;
1288287ac01aSChristof Schmitt 	}
1289287ac01aSChristof Schmitt 	return result;
1290287ac01aSChristof Schmitt }
1291287ac01aSChristof Schmitt 
zfcp_erp_strategy_check_target(struct zfcp_erp_action * erp_action,enum zfcp_erp_act_result result)1292d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_strategy_check_target(
1293d5fcdcedSSteffen Maier 	struct zfcp_erp_action *erp_action, enum zfcp_erp_act_result result)
12941da177e4SLinus Torvalds {
12951da177e4SLinus Torvalds 	struct zfcp_adapter *adapter = erp_action->adapter;
12961da177e4SLinus Torvalds 	struct zfcp_port *port = erp_action->port;
1297b62a8d9bSChristof Schmitt 	struct scsi_device *sdev = erp_action->sdev;
12981da177e4SLinus Torvalds 
1299df91eefdSSteffen Maier 	switch (erp_action->type) {
13001da177e4SLinus Torvalds 
1301b62a8d9bSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_LUN:
1302b62a8d9bSChristof Schmitt 		result = zfcp_erp_strategy_check_lun(sdev, result);
13031da177e4SLinus Torvalds 		break;
13041da177e4SLinus Torvalds 
13051da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
13061da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_PORT:
13071da177e4SLinus Torvalds 		result = zfcp_erp_strategy_check_port(port, result);
13081da177e4SLinus Torvalds 		break;
13091da177e4SLinus Torvalds 
13101da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
13111da177e4SLinus Torvalds 		result = zfcp_erp_strategy_check_adapter(adapter, result);
13121da177e4SLinus Torvalds 		break;
13131da177e4SLinus Torvalds 	}
13141da177e4SLinus Torvalds 	return result;
13151da177e4SLinus Torvalds }
13161da177e4SLinus Torvalds 
zfcp_erp_strat_change_det(atomic_t * target_status,u32 erp_status)1317287ac01aSChristof Schmitt static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status)
13181da177e4SLinus Torvalds {
1319287ac01aSChristof Schmitt 	int status = atomic_read(target_status);
13201da177e4SLinus Torvalds 
1321287ac01aSChristof Schmitt 	if ((status & ZFCP_STATUS_COMMON_RUNNING) &&
1322287ac01aSChristof Schmitt 	    (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1323287ac01aSChristof Schmitt 		return 1; /* take it online */
1324287ac01aSChristof Schmitt 
1325287ac01aSChristof Schmitt 	if (!(status & ZFCP_STATUS_COMMON_RUNNING) &&
1326287ac01aSChristof Schmitt 	    !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1327287ac01aSChristof Schmitt 		return 1; /* take it offline */
1328287ac01aSChristof Schmitt 
1329287ac01aSChristof Schmitt 	return 0;
1330287ac01aSChristof Schmitt }
1331287ac01aSChristof Schmitt 
zfcp_erp_strategy_statechange(struct zfcp_erp_action * act,enum zfcp_erp_act_result result)1332d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_strategy_statechange(
1333d5fcdcedSSteffen Maier 	struct zfcp_erp_action *act, enum zfcp_erp_act_result result)
1334287ac01aSChristof Schmitt {
1335df91eefdSSteffen Maier 	enum zfcp_erp_act_type type = act->type;
1336287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
1337287ac01aSChristof Schmitt 	struct zfcp_port *port = act->port;
1338b62a8d9bSChristof Schmitt 	struct scsi_device *sdev = act->sdev;
1339b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev;
1340287ac01aSChristof Schmitt 	u32 erp_status = act->status;
1341287ac01aSChristof Schmitt 
1342df91eefdSSteffen Maier 	switch (type) {
13431da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1344287ac01aSChristof Schmitt 		if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) {
1345287ac01aSChristof Schmitt 			_zfcp_erp_adapter_reopen(adapter,
13469467a9b3SMartin Peschke 						 ZFCP_STATUS_COMMON_ERP_FAILED,
1347ea4a3a6aSSwen Schillig 						 "ersscg1");
1348287ac01aSChristof Schmitt 			return ZFCP_ERP_EXIT;
13491da177e4SLinus Torvalds 		}
13501da177e4SLinus Torvalds 		break;
13511da177e4SLinus Torvalds 
13521da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
13531da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_PORT:
1354287ac01aSChristof Schmitt 		if (zfcp_erp_strat_change_det(&port->status, erp_status)) {
1355287ac01aSChristof Schmitt 			_zfcp_erp_port_reopen(port,
13569467a9b3SMartin Peschke 					      ZFCP_STATUS_COMMON_ERP_FAILED,
1357ea4a3a6aSSwen Schillig 					      "ersscg2");
1358287ac01aSChristof Schmitt 			return ZFCP_ERP_EXIT;
13591da177e4SLinus Torvalds 		}
13601da177e4SLinus Torvalds 		break;
13611da177e4SLinus Torvalds 
1362b62a8d9bSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_LUN:
1363b62a8d9bSChristof Schmitt 		zfcp_sdev = sdev_to_zfcp(sdev);
1364b62a8d9bSChristof Schmitt 		if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) {
1365b62a8d9bSChristof Schmitt 			_zfcp_erp_lun_reopen(sdev,
13669467a9b3SMartin Peschke 					     ZFCP_STATUS_COMMON_ERP_FAILED,
1367ea4a3a6aSSwen Schillig 					     "ersscg3", 0);
1368287ac01aSChristof Schmitt 			return ZFCP_ERP_EXIT;
13691da177e4SLinus Torvalds 		}
13701da177e4SLinus Torvalds 		break;
13711da177e4SLinus Torvalds 	}
1372d5fcdcedSSteffen Maier 	return result;
13731da177e4SLinus Torvalds }
13741da177e4SLinus Torvalds 
zfcp_erp_action_dequeue(struct zfcp_erp_action * erp_action)1375287ac01aSChristof Schmitt static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
13761da177e4SLinus Torvalds {
1377287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = erp_action->adapter;
1378b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev;
1379287ac01aSChristof Schmitt 
1380287ac01aSChristof Schmitt 	adapter->erp_total_count--;
1381287ac01aSChristof Schmitt 	if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1382287ac01aSChristof Schmitt 		adapter->erp_low_mem_count--;
1383287ac01aSChristof Schmitt 		erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
13841da177e4SLinus Torvalds 	}
13851da177e4SLinus Torvalds 
1386287ac01aSChristof Schmitt 	list_del(&erp_action->list);
1387ae0904f6SSwen Schillig 	zfcp_dbf_rec_run("eractd1", erp_action);
13881da177e4SLinus Torvalds 
1389df91eefdSSteffen Maier 	switch (erp_action->type) {
1390b62a8d9bSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_LUN:
1391b62a8d9bSChristof Schmitt 		zfcp_sdev = sdev_to_zfcp(erp_action->sdev);
1392805de8f4SPeter Zijlstra 		atomic_andnot(ZFCP_STATUS_COMMON_ERP_INUSE,
1393b62a8d9bSChristof Schmitt 				  &zfcp_sdev->status);
13941da177e4SLinus Torvalds 		break;
1395287ac01aSChristof Schmitt 
1396287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1397287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
1398805de8f4SPeter Zijlstra 		atomic_andnot(ZFCP_STATUS_COMMON_ERP_INUSE,
1399287ac01aSChristof Schmitt 				  &erp_action->port->status);
14001da177e4SLinus Torvalds 		break;
1401287ac01aSChristof Schmitt 
1402287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1403805de8f4SPeter Zijlstra 		atomic_andnot(ZFCP_STATUS_COMMON_ERP_INUSE,
1404287ac01aSChristof Schmitt 				  &erp_action->adapter->status);
14051da177e4SLinus Torvalds 		break;
14061da177e4SLinus Torvalds 	}
14071da177e4SLinus Torvalds }
14081da177e4SLinus Torvalds 
14096f2ce1c6SSteffen Maier /**
14106f2ce1c6SSteffen Maier  * zfcp_erp_try_rport_unblock - unblock rport if no more/new recovery
14116f2ce1c6SSteffen Maier  * @port: zfcp_port whose fc_rport we should try to unblock
14126f2ce1c6SSteffen Maier  */
zfcp_erp_try_rport_unblock(struct zfcp_port * port)14136f2ce1c6SSteffen Maier static void zfcp_erp_try_rport_unblock(struct zfcp_port *port)
14146f2ce1c6SSteffen Maier {
14156f2ce1c6SSteffen Maier 	unsigned long flags;
14166f2ce1c6SSteffen Maier 	struct zfcp_adapter *adapter = port->adapter;
14176f2ce1c6SSteffen Maier 	int port_status;
14186f2ce1c6SSteffen Maier 	struct Scsi_Host *shost = adapter->scsi_host;
14196f2ce1c6SSteffen Maier 	struct scsi_device *sdev;
14206f2ce1c6SSteffen Maier 
14216f2ce1c6SSteffen Maier 	write_lock_irqsave(&adapter->erp_lock, flags);
14226f2ce1c6SSteffen Maier 	port_status = atomic_read(&port->status);
14236f2ce1c6SSteffen Maier 	if ((port_status & ZFCP_STATUS_COMMON_UNBLOCKED)    == 0 ||
14246f2ce1c6SSteffen Maier 	    (port_status & (ZFCP_STATUS_COMMON_ERP_INUSE |
14256f2ce1c6SSteffen Maier 			    ZFCP_STATUS_COMMON_ERP_FAILED)) != 0) {
14266f2ce1c6SSteffen Maier 		/* new ERP of severity >= port triggered elsewhere meanwhile or
14276f2ce1c6SSteffen Maier 		 * local link down (adapter erp_failed but not clear unblock)
14286f2ce1c6SSteffen Maier 		 */
14296f2ce1c6SSteffen Maier 		zfcp_dbf_rec_run_lvl(4, "ertru_p", &port->erp_action);
14306f2ce1c6SSteffen Maier 		write_unlock_irqrestore(&adapter->erp_lock, flags);
14316f2ce1c6SSteffen Maier 		return;
14326f2ce1c6SSteffen Maier 	}
14336f2ce1c6SSteffen Maier 	spin_lock(shost->host_lock);
14346f2ce1c6SSteffen Maier 	__shost_for_each_device(sdev, shost) {
14356f2ce1c6SSteffen Maier 		struct zfcp_scsi_dev *zsdev = sdev_to_zfcp(sdev);
14366f2ce1c6SSteffen Maier 		int lun_status;
14376f2ce1c6SSteffen Maier 
1438fe67888fSSteffen Maier 		if (sdev->sdev_state == SDEV_DEL ||
1439fe67888fSSteffen Maier 		    sdev->sdev_state == SDEV_CANCEL)
1440fe67888fSSteffen Maier 			continue;
14416f2ce1c6SSteffen Maier 		if (zsdev->port != port)
14426f2ce1c6SSteffen Maier 			continue;
14436f2ce1c6SSteffen Maier 		/* LUN under port of interest */
14446f2ce1c6SSteffen Maier 		lun_status = atomic_read(&zsdev->status);
14456f2ce1c6SSteffen Maier 		if ((lun_status & ZFCP_STATUS_COMMON_ERP_FAILED) != 0)
14466f2ce1c6SSteffen Maier 			continue; /* unblock rport despite failed LUNs */
14476f2ce1c6SSteffen Maier 		/* LUN recovery not given up yet [maybe follow-up pending] */
14486f2ce1c6SSteffen Maier 		if ((lun_status & ZFCP_STATUS_COMMON_UNBLOCKED) == 0 ||
14496f2ce1c6SSteffen Maier 		    (lun_status & ZFCP_STATUS_COMMON_ERP_INUSE) != 0) {
14506f2ce1c6SSteffen Maier 			/* LUN blocked:
14516f2ce1c6SSteffen Maier 			 * not yet unblocked [LUN recovery pending]
14526f2ce1c6SSteffen Maier 			 * or meanwhile blocked [new LUN recovery triggered]
14536f2ce1c6SSteffen Maier 			 */
14546f2ce1c6SSteffen Maier 			zfcp_dbf_rec_run_lvl(4, "ertru_l", &zsdev->erp_action);
14556f2ce1c6SSteffen Maier 			spin_unlock(shost->host_lock);
14566f2ce1c6SSteffen Maier 			write_unlock_irqrestore(&adapter->erp_lock, flags);
14576f2ce1c6SSteffen Maier 			return;
14586f2ce1c6SSteffen Maier 		}
14596f2ce1c6SSteffen Maier 	}
14606f2ce1c6SSteffen Maier 	/* now port has no child or all children have completed recovery,
14616f2ce1c6SSteffen Maier 	 * and no ERP of severity >= port was meanwhile triggered elsewhere
14626f2ce1c6SSteffen Maier 	 */
14636f2ce1c6SSteffen Maier 	zfcp_scsi_schedule_rport_register(port);
14646f2ce1c6SSteffen Maier 	spin_unlock(shost->host_lock);
14656f2ce1c6SSteffen Maier 	write_unlock_irqrestore(&adapter->erp_lock, flags);
14666f2ce1c6SSteffen Maier }
14676f2ce1c6SSteffen Maier 
zfcp_erp_action_cleanup(struct zfcp_erp_action * act,enum zfcp_erp_act_result result)1468d5fcdcedSSteffen Maier static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act,
1469d5fcdcedSSteffen Maier 				    enum zfcp_erp_act_result result)
1470287ac01aSChristof Schmitt {
1471287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
1472287ac01aSChristof Schmitt 	struct zfcp_port *port = act->port;
1473b62a8d9bSChristof Schmitt 	struct scsi_device *sdev = act->sdev;
1474287ac01aSChristof Schmitt 
1475df91eefdSSteffen Maier 	switch (act->type) {
1476b62a8d9bSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_LUN:
1477fdbd1c5eSChristof Schmitt 		if (!(act->status & ZFCP_STATUS_ERP_NO_REF))
1478b62a8d9bSChristof Schmitt 			scsi_device_put(sdev);
14796f2ce1c6SSteffen Maier 		zfcp_erp_try_rport_unblock(port);
1480287ac01aSChristof Schmitt 		break;
1481287ac01aSChristof Schmitt 
1482287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
14834eeaa4f3SSteffen Maier 		/* This switch case might also happen after a forced reopen
14844eeaa4f3SSteffen Maier 		 * was successfully done and thus overwritten with a new
14854eeaa4f3SSteffen Maier 		 * non-forced reopen at `ersfs_2'. In this case, we must not
14864eeaa4f3SSteffen Maier 		 * do the clean-up of the non-forced version.
14874eeaa4f3SSteffen Maier 		 */
14884eeaa4f3SSteffen Maier 		if (act->step != ZFCP_ERP_STEP_UNINITIALIZED)
1489a2fa0aedSChristof Schmitt 			if (result == ZFCP_ERP_SUCCEEDED)
14906f2ce1c6SSteffen Maier 				zfcp_erp_try_rport_unblock(port);
1491cec9cbacSJoe Perches 		fallthrough;
14925767620cSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1493615f59e0SChristof Schmitt 		put_device(&port->dev);
14941da177e4SLinus Torvalds 		break;
1495287ac01aSChristof Schmitt 
14961da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1497a2fa0aedSChristof Schmitt 		if (result == ZFCP_ERP_SUCCEEDED) {
1498bd43a42bSChristof Schmitt 			register_service_level(&adapter->service_level);
149943f60cbdSSteffen Maier 			zfcp_fc_conditional_port_scan(adapter);
1500038d9446SChristof Schmitt 			queue_work(adapter->work_queue, &adapter->ns_up_work);
1501a2fa0aedSChristof Schmitt 		} else
1502a2fa0aedSChristof Schmitt 			unregister_service_level(&adapter->service_level);
1503038d9446SChristof Schmitt 
1504f3450c7bSSwen Schillig 		kref_put(&adapter->ref, zfcp_adapter_release);
15051da177e4SLinus Torvalds 		break;
15061da177e4SLinus Torvalds 	}
15071da177e4SLinus Torvalds }
15081da177e4SLinus Torvalds 
zfcp_erp_strategy_do_action(struct zfcp_erp_action * erp_action)1509d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_strategy_do_action(
1510d5fcdcedSSteffen Maier 	struct zfcp_erp_action *erp_action)
1511287ac01aSChristof Schmitt {
1512df91eefdSSteffen Maier 	switch (erp_action->type) {
1513287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1514287ac01aSChristof Schmitt 		return zfcp_erp_adapter_strategy(erp_action);
1515287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1516287ac01aSChristof Schmitt 		return zfcp_erp_port_forced_strategy(erp_action);
1517287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
1518287ac01aSChristof Schmitt 		return zfcp_erp_port_strategy(erp_action);
1519b62a8d9bSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_LUN:
1520b62a8d9bSChristof Schmitt 		return zfcp_erp_lun_strategy(erp_action);
1521287ac01aSChristof Schmitt 	}
1522287ac01aSChristof Schmitt 	return ZFCP_ERP_FAILED;
1523287ac01aSChristof Schmitt }
15241da177e4SLinus Torvalds 
zfcp_erp_strategy(struct zfcp_erp_action * erp_action)1525d5fcdcedSSteffen Maier static enum zfcp_erp_act_result zfcp_erp_strategy(
1526d5fcdcedSSteffen Maier 	struct zfcp_erp_action *erp_action)
1527287ac01aSChristof Schmitt {
1528d5fcdcedSSteffen Maier 	enum zfcp_erp_act_result result;
1529287ac01aSChristof Schmitt 	unsigned long flags;
1530ecf0c772SSwen Schillig 	struct zfcp_adapter *adapter = erp_action->adapter;
1531287ac01aSChristof Schmitt 
1532f3450c7bSSwen Schillig 	kref_get(&adapter->ref);
1533287ac01aSChristof Schmitt 
1534f3450c7bSSwen Schillig 	write_lock_irqsave(&adapter->erp_lock, flags);
1535287ac01aSChristof Schmitt 	zfcp_erp_strategy_check_fsfreq(erp_action);
1536287ac01aSChristof Schmitt 
1537287ac01aSChristof Schmitt 	if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
1538287ac01aSChristof Schmitt 		zfcp_erp_action_dequeue(erp_action);
1539d5fcdcedSSteffen Maier 		result = ZFCP_ERP_DISMISSED;
1540287ac01aSChristof Schmitt 		goto unlock;
1541287ac01aSChristof Schmitt 	}
1542287ac01aSChristof Schmitt 
15439c785d94SChristof Schmitt 	if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
1544d5fcdcedSSteffen Maier 		result = ZFCP_ERP_FAILED;
15459c785d94SChristof Schmitt 		goto check_target;
15469c785d94SChristof Schmitt 	}
15479c785d94SChristof Schmitt 
1548287ac01aSChristof Schmitt 	zfcp_erp_action_to_running(erp_action);
1549287ac01aSChristof Schmitt 
1550287ac01aSChristof Schmitt 	/* no lock to allow for blocking operations */
1551ecf0c772SSwen Schillig 	write_unlock_irqrestore(&adapter->erp_lock, flags);
1552d5fcdcedSSteffen Maier 	result = zfcp_erp_strategy_do_action(erp_action);
1553ecf0c772SSwen Schillig 	write_lock_irqsave(&adapter->erp_lock, flags);
1554287ac01aSChristof Schmitt 
1555287ac01aSChristof Schmitt 	if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED)
1556d5fcdcedSSteffen Maier 		result = ZFCP_ERP_CONTINUES;
1557287ac01aSChristof Schmitt 
1558d5fcdcedSSteffen Maier 	switch (result) {
1559287ac01aSChristof Schmitt 	case ZFCP_ERP_NOMEM:
1560287ac01aSChristof Schmitt 		if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) {
1561287ac01aSChristof Schmitt 			++adapter->erp_low_mem_count;
1562287ac01aSChristof Schmitt 			erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
1563287ac01aSChristof Schmitt 		}
1564287ac01aSChristof Schmitt 		if (adapter->erp_total_count == adapter->erp_low_mem_count)
1565ea4a3a6aSSwen Schillig 			_zfcp_erp_adapter_reopen(adapter, 0, "erstgy1");
1566287ac01aSChristof Schmitt 		else {
1567287ac01aSChristof Schmitt 			zfcp_erp_strategy_memwait(erp_action);
1568d5fcdcedSSteffen Maier 			result = ZFCP_ERP_CONTINUES;
1569287ac01aSChristof Schmitt 		}
1570287ac01aSChristof Schmitt 		goto unlock;
1571287ac01aSChristof Schmitt 
1572287ac01aSChristof Schmitt 	case ZFCP_ERP_CONTINUES:
1573287ac01aSChristof Schmitt 		if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1574287ac01aSChristof Schmitt 			--adapter->erp_low_mem_count;
1575287ac01aSChristof Schmitt 			erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
1576287ac01aSChristof Schmitt 		}
1577287ac01aSChristof Schmitt 		goto unlock;
1578d5fcdcedSSteffen Maier 	case ZFCP_ERP_SUCCEEDED:
1579d5fcdcedSSteffen Maier 	case ZFCP_ERP_FAILED:
1580d5fcdcedSSteffen Maier 	case ZFCP_ERP_EXIT:
1581d5fcdcedSSteffen Maier 	case ZFCP_ERP_DISMISSED:
1582d5fcdcedSSteffen Maier 		/* NOP */
1583d5fcdcedSSteffen Maier 		break;
1584287ac01aSChristof Schmitt 	}
1585287ac01aSChristof Schmitt 
15869c785d94SChristof Schmitt check_target:
1587d5fcdcedSSteffen Maier 	result = zfcp_erp_strategy_check_target(erp_action, result);
1588287ac01aSChristof Schmitt 	zfcp_erp_action_dequeue(erp_action);
1589d5fcdcedSSteffen Maier 	result = zfcp_erp_strategy_statechange(erp_action, result);
1590d5fcdcedSSteffen Maier 	if (result == ZFCP_ERP_EXIT)
1591287ac01aSChristof Schmitt 		goto unlock;
1592d5fcdcedSSteffen Maier 	if (result == ZFCP_ERP_SUCCEEDED)
159385600f7fSChristof Schmitt 		zfcp_erp_strategy_followup_success(erp_action);
1594d5fcdcedSSteffen Maier 	if (result == ZFCP_ERP_FAILED)
159585600f7fSChristof Schmitt 		zfcp_erp_strategy_followup_failed(erp_action);
1596287ac01aSChristof Schmitt 
1597287ac01aSChristof Schmitt  unlock:
1598ecf0c772SSwen Schillig 	write_unlock_irqrestore(&adapter->erp_lock, flags);
1599287ac01aSChristof Schmitt 
1600d5fcdcedSSteffen Maier 	if (result != ZFCP_ERP_CONTINUES)
1601d5fcdcedSSteffen Maier 		zfcp_erp_action_cleanup(erp_action, result);
1602287ac01aSChristof Schmitt 
1603f3450c7bSSwen Schillig 	kref_put(&adapter->ref, zfcp_adapter_release);
1604d5fcdcedSSteffen Maier 	return result;
1605287ac01aSChristof Schmitt }
1606287ac01aSChristof Schmitt 
zfcp_erp_thread(void * data)1607287ac01aSChristof Schmitt static int zfcp_erp_thread(void *data)
1608287ac01aSChristof Schmitt {
1609287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
1610287ac01aSChristof Schmitt 	struct zfcp_erp_action *act;
1611287ac01aSChristof Schmitt 	unsigned long flags;
1612287ac01aSChristof Schmitt 
1613347c6a96SChristof Schmitt 	for (;;) {
1614347c6a96SChristof Schmitt 		wait_event_interruptible(adapter->erp_ready_wq,
1615347c6a96SChristof Schmitt 			   !list_empty(&adapter->erp_ready_head) ||
1616347c6a96SChristof Schmitt 			   kthread_should_stop());
161794ab4b38SSwen Schillig 
1618347c6a96SChristof Schmitt 		if (kthread_should_stop())
1619347c6a96SChristof Schmitt 			break;
1620347c6a96SChristof Schmitt 
1621287ac01aSChristof Schmitt 		write_lock_irqsave(&adapter->erp_lock, flags);
1622addf1372SJulian Wiedmann 		act = list_first_entry_or_null(&adapter->erp_ready_head,
1623addf1372SJulian Wiedmann 					       struct zfcp_erp_action, list);
1624287ac01aSChristof Schmitt 		write_unlock_irqrestore(&adapter->erp_lock, flags);
1625287ac01aSChristof Schmitt 
1626addf1372SJulian Wiedmann 		if (act) {
1627287ac01aSChristof Schmitt 			/* there is more to come after dismission, no notify */
1628287ac01aSChristof Schmitt 			if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED)
1629287ac01aSChristof Schmitt 				zfcp_erp_wakeup(adapter);
1630287ac01aSChristof Schmitt 		}
1631287ac01aSChristof Schmitt 	}
1632287ac01aSChristof Schmitt 
1633287ac01aSChristof Schmitt 	return 0;
1634287ac01aSChristof Schmitt }
1635287ac01aSChristof Schmitt 
1636287ac01aSChristof Schmitt /**
1637287ac01aSChristof Schmitt  * zfcp_erp_thread_setup - Start ERP thread for adapter
1638287ac01aSChristof Schmitt  * @adapter: Adapter to start the ERP thread for
1639287ac01aSChristof Schmitt  *
164064eba384SSteffen Maier  * Return: 0 on success, or error code from kthread_run().
1641287ac01aSChristof Schmitt  */
zfcp_erp_thread_setup(struct zfcp_adapter * adapter)1642287ac01aSChristof Schmitt int zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
1643287ac01aSChristof Schmitt {
1644347c6a96SChristof Schmitt 	struct task_struct *thread;
1645287ac01aSChristof Schmitt 
1646347c6a96SChristof Schmitt 	thread = kthread_run(zfcp_erp_thread, adapter, "zfcperp%s",
1647347c6a96SChristof Schmitt 			     dev_name(&adapter->ccw_device->dev));
1648347c6a96SChristof Schmitt 	if (IS_ERR(thread)) {
1649287ac01aSChristof Schmitt 		dev_err(&adapter->ccw_device->dev,
1650ff3b24faSChristof Schmitt 			"Creating an ERP thread for the FCP device failed.\n");
1651347c6a96SChristof Schmitt 		return PTR_ERR(thread);
1652287ac01aSChristof Schmitt 	}
1653347c6a96SChristof Schmitt 
1654347c6a96SChristof Schmitt 	adapter->erp_thread = thread;
1655287ac01aSChristof Schmitt 	return 0;
1656287ac01aSChristof Schmitt }
1657287ac01aSChristof Schmitt 
1658287ac01aSChristof Schmitt /**
1659287ac01aSChristof Schmitt  * zfcp_erp_thread_kill - Stop ERP thread.
1660287ac01aSChristof Schmitt  * @adapter: Adapter where the ERP thread should be stopped.
1661287ac01aSChristof Schmitt  *
1662287ac01aSChristof Schmitt  * The caller of this routine ensures that the specified adapter has
1663287ac01aSChristof Schmitt  * been shut down and that this operation has been completed. Thus,
1664287ac01aSChristof Schmitt  * there are no pending erp_actions which would need to be handled
1665287ac01aSChristof Schmitt  * here.
1666287ac01aSChristof Schmitt  */
zfcp_erp_thread_kill(struct zfcp_adapter * adapter)1667287ac01aSChristof Schmitt void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
1668287ac01aSChristof Schmitt {
1669347c6a96SChristof Schmitt 	kthread_stop(adapter->erp_thread);
1670347c6a96SChristof Schmitt 	adapter->erp_thread = NULL;
1671143bb6bfSChristof Schmitt 	WARN_ON(!list_empty(&adapter->erp_ready_head));
1672143bb6bfSChristof Schmitt 	WARN_ON(!list_empty(&adapter->erp_running_head));
1673287ac01aSChristof Schmitt }
1674287ac01aSChristof Schmitt 
1675287ac01aSChristof Schmitt /**
1676287ac01aSChristof Schmitt  * zfcp_erp_wait - wait for completion of error recovery on an adapter
1677287ac01aSChristof Schmitt  * @adapter: adapter for which to wait for completion of its error recovery
1678287ac01aSChristof Schmitt  */
zfcp_erp_wait(struct zfcp_adapter * adapter)1679287ac01aSChristof Schmitt void zfcp_erp_wait(struct zfcp_adapter *adapter)
1680287ac01aSChristof Schmitt {
1681287ac01aSChristof Schmitt 	wait_event(adapter->erp_done_wqh,
1682287ac01aSChristof Schmitt 		   !(atomic_read(&adapter->status) &
1683287ac01aSChristof Schmitt 			ZFCP_STATUS_ADAPTER_ERP_PENDING));
1684287ac01aSChristof Schmitt }
1685287ac01aSChristof Schmitt 
1686287ac01aSChristof Schmitt /**
1687edaed859SSwen Schillig  * zfcp_erp_set_adapter_status - set adapter status bits
1688287ac01aSChristof Schmitt  * @adapter: adapter to change the status
1689287ac01aSChristof Schmitt  * @mask: status bits to change
1690287ac01aSChristof Schmitt  *
1691b62a8d9bSChristof Schmitt  * Changes in common status bits are propagated to attached ports and LUNs.
1692287ac01aSChristof Schmitt  */
zfcp_erp_set_adapter_status(struct zfcp_adapter * adapter,u32 mask)1693edaed859SSwen Schillig void zfcp_erp_set_adapter_status(struct zfcp_adapter *adapter, u32 mask)
16941da177e4SLinus Torvalds {
16951da177e4SLinus Torvalds 	struct zfcp_port *port;
1696edaed859SSwen Schillig 	struct scsi_device *sdev;
1697ecf0c772SSwen Schillig 	unsigned long flags;
1698287ac01aSChristof Schmitt 	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
16991da177e4SLinus Torvalds 
1700805de8f4SPeter Zijlstra 	atomic_or(mask, &adapter->status);
17011da177e4SLinus Torvalds 
1702edaed859SSwen Schillig 	if (!common_mask)
1703edaed859SSwen Schillig 		return;
1704edaed859SSwen Schillig 
1705ecf0c772SSwen Schillig 	read_lock_irqsave(&adapter->port_list_lock, flags);
1706ecf0c772SSwen Schillig 	list_for_each_entry(port, &adapter->port_list, list)
1707805de8f4SPeter Zijlstra 		atomic_or(common_mask, &port->status);
1708ecf0c772SSwen Schillig 	read_unlock_irqrestore(&adapter->port_list_lock, flags);
1709edaed859SSwen Schillig 
1710971f2abbSBenjamin Block 	/*
1711971f2abbSBenjamin Block 	 * if `scsi_host` is missing, xconfig/xport data has never completed
1712971f2abbSBenjamin Block 	 * yet, so we can't access it, but there are also no SDEVs yet
1713971f2abbSBenjamin Block 	 */
1714971f2abbSBenjamin Block 	if (adapter->scsi_host == NULL)
1715971f2abbSBenjamin Block 		return;
1716971f2abbSBenjamin Block 
1717924dd584SMartin Peschke 	spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
1718924dd584SMartin Peschke 	__shost_for_each_device(sdev, adapter->scsi_host)
1719805de8f4SPeter Zijlstra 		atomic_or(common_mask, &sdev_to_zfcp(sdev)->status);
1720924dd584SMartin Peschke 	spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
1721edaed859SSwen Schillig }
1722edaed859SSwen Schillig 
1723edaed859SSwen Schillig /**
1724edaed859SSwen Schillig  * zfcp_erp_clear_adapter_status - clear adapter status bits
1725edaed859SSwen Schillig  * @adapter: adapter to change the status
1726edaed859SSwen Schillig  * @mask: status bits to change
1727edaed859SSwen Schillig  *
1728edaed859SSwen Schillig  * Changes in common status bits are propagated to attached ports and LUNs.
1729edaed859SSwen Schillig  */
zfcp_erp_clear_adapter_status(struct zfcp_adapter * adapter,u32 mask)1730edaed859SSwen Schillig void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask)
1731edaed859SSwen Schillig {
1732edaed859SSwen Schillig 	struct zfcp_port *port;
1733edaed859SSwen Schillig 	struct scsi_device *sdev;
1734edaed859SSwen Schillig 	unsigned long flags;
1735edaed859SSwen Schillig 	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
1736edaed859SSwen Schillig 	u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED;
1737edaed859SSwen Schillig 
1738805de8f4SPeter Zijlstra 	atomic_andnot(mask, &adapter->status);
1739edaed859SSwen Schillig 
1740edaed859SSwen Schillig 	if (!common_mask)
1741edaed859SSwen Schillig 		return;
1742edaed859SSwen Schillig 
1743edaed859SSwen Schillig 	if (clear_counter)
1744edaed859SSwen Schillig 		atomic_set(&adapter->erp_counter, 0);
1745edaed859SSwen Schillig 
1746edaed859SSwen Schillig 	read_lock_irqsave(&adapter->port_list_lock, flags);
1747edaed859SSwen Schillig 	list_for_each_entry(port, &adapter->port_list, list) {
1748805de8f4SPeter Zijlstra 		atomic_andnot(common_mask, &port->status);
1749edaed859SSwen Schillig 		if (clear_counter)
1750edaed859SSwen Schillig 			atomic_set(&port->erp_counter, 0);
1751edaed859SSwen Schillig 	}
1752edaed859SSwen Schillig 	read_unlock_irqrestore(&adapter->port_list_lock, flags);
1753edaed859SSwen Schillig 
1754971f2abbSBenjamin Block 	/*
1755971f2abbSBenjamin Block 	 * if `scsi_host` is missing, xconfig/xport data has never completed
1756971f2abbSBenjamin Block 	 * yet, so we can't access it, but there are also no SDEVs yet
1757971f2abbSBenjamin Block 	 */
1758971f2abbSBenjamin Block 	if (adapter->scsi_host == NULL)
1759971f2abbSBenjamin Block 		return;
1760971f2abbSBenjamin Block 
1761924dd584SMartin Peschke 	spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
1762924dd584SMartin Peschke 	__shost_for_each_device(sdev, adapter->scsi_host) {
1763805de8f4SPeter Zijlstra 		atomic_andnot(common_mask, &sdev_to_zfcp(sdev)->status);
1764edaed859SSwen Schillig 		if (clear_counter)
1765edaed859SSwen Schillig 			atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
1766ecf0c772SSwen Schillig 	}
1767924dd584SMartin Peschke 	spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
1768287ac01aSChristof Schmitt }
1769287ac01aSChristof Schmitt 
1770287ac01aSChristof Schmitt /**
1771edaed859SSwen Schillig  * zfcp_erp_set_port_status - set port status bits
1772edaed859SSwen Schillig  * @port: port to change the status
1773287ac01aSChristof Schmitt  * @mask: status bits to change
1774287ac01aSChristof Schmitt  *
1775b62a8d9bSChristof Schmitt  * Changes in common status bits are propagated to attached LUNs.
1776287ac01aSChristof Schmitt  */
zfcp_erp_set_port_status(struct zfcp_port * port,u32 mask)1777edaed859SSwen Schillig void zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask)
17781da177e4SLinus Torvalds {
1779b62a8d9bSChristof Schmitt 	struct scsi_device *sdev;
1780287ac01aSChristof Schmitt 	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
1781924dd584SMartin Peschke 	unsigned long flags;
17821da177e4SLinus Torvalds 
1783805de8f4SPeter Zijlstra 	atomic_or(mask, &port->status);
1784287ac01aSChristof Schmitt 
1785edaed859SSwen Schillig 	if (!common_mask)
1786edaed859SSwen Schillig 		return;
1787edaed859SSwen Schillig 
1788924dd584SMartin Peschke 	spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags);
1789924dd584SMartin Peschke 	__shost_for_each_device(sdev, port->adapter->scsi_host)
1790b62a8d9bSChristof Schmitt 		if (sdev_to_zfcp(sdev)->port == port)
1791805de8f4SPeter Zijlstra 			atomic_or(common_mask,
1792edaed859SSwen Schillig 					&sdev_to_zfcp(sdev)->status);
1793924dd584SMartin Peschke 	spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags);
17941da177e4SLinus Torvalds }
17951da177e4SLinus Torvalds 
1796287ac01aSChristof Schmitt /**
1797edaed859SSwen Schillig  * zfcp_erp_clear_port_status - clear port status bits
1798edaed859SSwen Schillig  * @port: adapter to change the status
1799287ac01aSChristof Schmitt  * @mask: status bits to change
1800edaed859SSwen Schillig  *
1801edaed859SSwen Schillig  * Changes in common status bits are propagated to attached LUNs.
1802287ac01aSChristof Schmitt  */
zfcp_erp_clear_port_status(struct zfcp_port * port,u32 mask)1803edaed859SSwen Schillig void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask)
1804edaed859SSwen Schillig {
1805edaed859SSwen Schillig 	struct scsi_device *sdev;
1806edaed859SSwen Schillig 	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
1807edaed859SSwen Schillig 	u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED;
1808924dd584SMartin Peschke 	unsigned long flags;
1809edaed859SSwen Schillig 
1810805de8f4SPeter Zijlstra 	atomic_andnot(mask, &port->status);
1811edaed859SSwen Schillig 
1812edaed859SSwen Schillig 	if (!common_mask)
1813edaed859SSwen Schillig 		return;
1814edaed859SSwen Schillig 
1815edaed859SSwen Schillig 	if (clear_counter)
1816edaed859SSwen Schillig 		atomic_set(&port->erp_counter, 0);
1817edaed859SSwen Schillig 
1818924dd584SMartin Peschke 	spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags);
1819924dd584SMartin Peschke 	__shost_for_each_device(sdev, port->adapter->scsi_host)
1820edaed859SSwen Schillig 		if (sdev_to_zfcp(sdev)->port == port) {
1821805de8f4SPeter Zijlstra 			atomic_andnot(common_mask,
1822edaed859SSwen Schillig 					  &sdev_to_zfcp(sdev)->status);
1823edaed859SSwen Schillig 			if (clear_counter)
1824edaed859SSwen Schillig 				atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
1825edaed859SSwen Schillig 		}
1826924dd584SMartin Peschke 	spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags);
1827edaed859SSwen Schillig }
1828edaed859SSwen Schillig 
1829edaed859SSwen Schillig /**
1830edaed859SSwen Schillig  * zfcp_erp_set_lun_status - set lun status bits
1831edaed859SSwen Schillig  * @sdev: SCSI device / lun to set the status bits
1832edaed859SSwen Schillig  * @mask: status bits to change
1833edaed859SSwen Schillig  */
zfcp_erp_set_lun_status(struct scsi_device * sdev,u32 mask)1834edaed859SSwen Schillig void zfcp_erp_set_lun_status(struct scsi_device *sdev, u32 mask)
18351da177e4SLinus Torvalds {
1836b62a8d9bSChristof Schmitt 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
1837b62a8d9bSChristof Schmitt 
1838805de8f4SPeter Zijlstra 	atomic_or(mask, &zfcp_sdev->status);
1839edaed859SSwen Schillig }
1840edaed859SSwen Schillig 
1841edaed859SSwen Schillig /**
1842edaed859SSwen Schillig  * zfcp_erp_clear_lun_status - clear lun status bits
1843edaed859SSwen Schillig  * @sdev: SCSi device / lun to clear the status bits
1844edaed859SSwen Schillig  * @mask: status bits to change
1845edaed859SSwen Schillig  */
zfcp_erp_clear_lun_status(struct scsi_device * sdev,u32 mask)1846edaed859SSwen Schillig void zfcp_erp_clear_lun_status(struct scsi_device *sdev, u32 mask)
1847edaed859SSwen Schillig {
1848edaed859SSwen Schillig 	struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
1849edaed859SSwen Schillig 
1850805de8f4SPeter Zijlstra 	atomic_andnot(mask, &zfcp_sdev->status);
1851edaed859SSwen Schillig 
1852edaed859SSwen Schillig 	if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
1853b62a8d9bSChristof Schmitt 		atomic_set(&zfcp_sdev->erp_counter, 0);
1854287ac01aSChristof Schmitt }
18551da177e4SLinus Torvalds 
185635e9111aSSteffen Maier /**
185735e9111aSSteffen Maier  * zfcp_erp_adapter_reset_sync() - Really reopen adapter and wait.
185835e9111aSSteffen Maier  * @adapter: Pointer to zfcp_adapter to reopen.
1859208d0961SSteffen Maier  * @dbftag: Trace tag string of length %ZFCP_DBF_TAG_LEN.
186035e9111aSSteffen Maier  */
zfcp_erp_adapter_reset_sync(struct zfcp_adapter * adapter,char * dbftag)1861208d0961SSteffen Maier void zfcp_erp_adapter_reset_sync(struct zfcp_adapter *adapter, char *dbftag)
186235e9111aSSteffen Maier {
186335e9111aSSteffen Maier 	zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING);
1864208d0961SSteffen Maier 	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, dbftag);
186535e9111aSSteffen Maier 	zfcp_erp_wait(adapter);
186635e9111aSSteffen Maier }
1867