xref: /openbmc/linux/drivers/s390/scsi/zfcp_erp.c (revision 799b76d0)
11da177e4SLinus Torvalds /*
2553448f6SChristof Schmitt  * zfcp device driver
31da177e4SLinus Torvalds  *
4553448f6SChristof Schmitt  * Error Recovery Procedures (ERP).
51da177e4SLinus Torvalds  *
6a2fa0aedSChristof Schmitt  * Copyright IBM Corporation 2002, 2009
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
9ecf39d42SChristof Schmitt #define KMSG_COMPONENT "zfcp"
10ecf39d42SChristof Schmitt #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11ecf39d42SChristof Schmitt 
121da177e4SLinus Torvalds #include "zfcp_ext.h"
131da177e4SLinus Torvalds 
14287ac01aSChristof Schmitt #define ZFCP_MAX_ERPS                   3
151da177e4SLinus Torvalds 
16287ac01aSChristof Schmitt enum zfcp_erp_act_flags {
17287ac01aSChristof Schmitt 	ZFCP_STATUS_ERP_TIMEDOUT	= 0x10000000,
18287ac01aSChristof Schmitt 	ZFCP_STATUS_ERP_CLOSE_ONLY	= 0x01000000,
19287ac01aSChristof Schmitt 	ZFCP_STATUS_ERP_DISMISSING	= 0x00100000,
20287ac01aSChristof Schmitt 	ZFCP_STATUS_ERP_DISMISSED	= 0x00200000,
21287ac01aSChristof Schmitt 	ZFCP_STATUS_ERP_LOWMEM		= 0x00400000,
22287ac01aSChristof Schmitt };
231da177e4SLinus Torvalds 
24287ac01aSChristof Schmitt enum zfcp_erp_steps {
25287ac01aSChristof Schmitt 	ZFCP_ERP_STEP_UNINITIALIZED	= 0x0000,
26287ac01aSChristof Schmitt 	ZFCP_ERP_STEP_FSF_XCONFIG	= 0x0001,
27287ac01aSChristof Schmitt 	ZFCP_ERP_STEP_PHYS_PORT_CLOSING	= 0x0010,
28287ac01aSChristof Schmitt 	ZFCP_ERP_STEP_PORT_CLOSING	= 0x0100,
29287ac01aSChristof Schmitt 	ZFCP_ERP_STEP_PORT_OPENING	= 0x0800,
30287ac01aSChristof Schmitt 	ZFCP_ERP_STEP_UNIT_CLOSING	= 0x1000,
31287ac01aSChristof Schmitt 	ZFCP_ERP_STEP_UNIT_OPENING	= 0x2000,
32287ac01aSChristof Schmitt };
331da177e4SLinus Torvalds 
34287ac01aSChristof Schmitt enum zfcp_erp_act_type {
35287ac01aSChristof Schmitt 	ZFCP_ERP_ACTION_REOPEN_UNIT        = 1,
36287ac01aSChristof Schmitt 	ZFCP_ERP_ACTION_REOPEN_PORT	   = 2,
37287ac01aSChristof Schmitt 	ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3,
38287ac01aSChristof Schmitt 	ZFCP_ERP_ACTION_REOPEN_ADAPTER     = 4,
39287ac01aSChristof Schmitt };
401da177e4SLinus Torvalds 
41287ac01aSChristof Schmitt enum zfcp_erp_act_state {
42287ac01aSChristof Schmitt 	ZFCP_ERP_ACTION_RUNNING = 1,
43287ac01aSChristof Schmitt 	ZFCP_ERP_ACTION_READY   = 2,
44287ac01aSChristof Schmitt };
451da177e4SLinus Torvalds 
46287ac01aSChristof Schmitt enum zfcp_erp_act_result {
47287ac01aSChristof Schmitt 	ZFCP_ERP_SUCCEEDED = 0,
48287ac01aSChristof Schmitt 	ZFCP_ERP_FAILED    = 1,
49287ac01aSChristof Schmitt 	ZFCP_ERP_CONTINUES = 2,
50287ac01aSChristof Schmitt 	ZFCP_ERP_EXIT      = 3,
51287ac01aSChristof Schmitt 	ZFCP_ERP_DISMISSED = 4,
52287ac01aSChristof Schmitt 	ZFCP_ERP_NOMEM     = 5,
53287ac01aSChristof Schmitt };
541da177e4SLinus Torvalds 
55287ac01aSChristof Schmitt static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask)
562abbe866SAndreas Herrmann {
575ffd51a5SSwen Schillig 	zfcp_erp_modify_adapter_status(adapter, "erablk1", NULL,
58287ac01aSChristof Schmitt 				       ZFCP_STATUS_COMMON_UNBLOCKED | mask,
59287ac01aSChristof Schmitt 				       ZFCP_CLEAR);
602abbe866SAndreas Herrmann }
611da177e4SLinus Torvalds 
62287ac01aSChristof Schmitt static int zfcp_erp_action_exists(struct zfcp_erp_action *act)
631da177e4SLinus Torvalds {
64287ac01aSChristof Schmitt 	struct zfcp_erp_action *curr_act;
65287ac01aSChristof Schmitt 
66287ac01aSChristof Schmitt 	list_for_each_entry(curr_act, &act->adapter->erp_running_head, list)
67287ac01aSChristof Schmitt 		if (act == curr_act)
68287ac01aSChristof Schmitt 			return ZFCP_ERP_ACTION_RUNNING;
69287ac01aSChristof Schmitt 	return 0;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds 
72287ac01aSChristof Schmitt static void zfcp_erp_action_ready(struct zfcp_erp_action *act)
731da177e4SLinus Torvalds {
74287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
75287ac01aSChristof Schmitt 
76287ac01aSChristof Schmitt 	list_move(&act->list, &act->adapter->erp_ready_head);
775ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_action("erardy1", act);
78287ac01aSChristof Schmitt 	up(&adapter->erp_ready_sem);
795ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_thread("erardy2", adapter);
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds 
82287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
83287ac01aSChristof Schmitt {
84287ac01aSChristof Schmitt 	act->status |= ZFCP_STATUS_ERP_DISMISSED;
85287ac01aSChristof Schmitt 	if (zfcp_erp_action_exists(act) == ZFCP_ERP_ACTION_RUNNING)
86287ac01aSChristof Schmitt 		zfcp_erp_action_ready(act);
87287ac01aSChristof Schmitt }
88287ac01aSChristof Schmitt 
89287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
90287ac01aSChristof Schmitt {
91287ac01aSChristof Schmitt 	if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
92287ac01aSChristof Schmitt 		zfcp_erp_action_dismiss(&unit->erp_action);
93287ac01aSChristof Schmitt }
94287ac01aSChristof Schmitt 
95287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
96287ac01aSChristof Schmitt {
97287ac01aSChristof Schmitt 	struct zfcp_unit *unit;
98287ac01aSChristof Schmitt 
99287ac01aSChristof Schmitt 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
100287ac01aSChristof Schmitt 		zfcp_erp_action_dismiss(&port->erp_action);
101287ac01aSChristof Schmitt 	else
102287ac01aSChristof Schmitt 		list_for_each_entry(unit, &port->unit_list_head, list)
103287ac01aSChristof Schmitt 		    zfcp_erp_action_dismiss_unit(unit);
104287ac01aSChristof Schmitt }
105287ac01aSChristof Schmitt 
106287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
107287ac01aSChristof Schmitt {
108287ac01aSChristof Schmitt 	struct zfcp_port *port;
109287ac01aSChristof Schmitt 
110287ac01aSChristof Schmitt 	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
111287ac01aSChristof Schmitt 		zfcp_erp_action_dismiss(&adapter->erp_action);
112287ac01aSChristof Schmitt 	else
113287ac01aSChristof Schmitt 		list_for_each_entry(port, &adapter->port_list_head, list)
114287ac01aSChristof Schmitt 		    zfcp_erp_action_dismiss_port(port);
115287ac01aSChristof Schmitt }
116287ac01aSChristof Schmitt 
117287ac01aSChristof Schmitt static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
118287ac01aSChristof Schmitt 				 struct zfcp_port *port,
119287ac01aSChristof Schmitt 				 struct zfcp_unit *unit)
120287ac01aSChristof Schmitt {
121287ac01aSChristof Schmitt 	int need = want;
122287ac01aSChristof Schmitt 	int u_status, p_status, a_status;
123287ac01aSChristof Schmitt 
124287ac01aSChristof Schmitt 	switch (want) {
125287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
126287ac01aSChristof Schmitt 		u_status = atomic_read(&unit->status);
127287ac01aSChristof Schmitt 		if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE)
128287ac01aSChristof Schmitt 			return 0;
129287ac01aSChristof Schmitt 		p_status = atomic_read(&port->status);
130287ac01aSChristof Schmitt 		if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) ||
131287ac01aSChristof Schmitt 		      p_status & ZFCP_STATUS_COMMON_ERP_FAILED)
132287ac01aSChristof Schmitt 			return 0;
133287ac01aSChristof Schmitt 		if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
134287ac01aSChristof Schmitt 			need = ZFCP_ERP_ACTION_REOPEN_PORT;
135287ac01aSChristof Schmitt 		/* fall through */
136287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
137287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
138287ac01aSChristof Schmitt 		p_status = atomic_read(&port->status);
139287ac01aSChristof Schmitt 		if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
140287ac01aSChristof Schmitt 			return 0;
141287ac01aSChristof Schmitt 		a_status = atomic_read(&adapter->status);
142287ac01aSChristof Schmitt 		if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) ||
143287ac01aSChristof Schmitt 		      a_status & ZFCP_STATUS_COMMON_ERP_FAILED)
144287ac01aSChristof Schmitt 			return 0;
145287ac01aSChristof Schmitt 		if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))
146287ac01aSChristof Schmitt 			need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
147287ac01aSChristof Schmitt 		/* fall through */
148287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
149287ac01aSChristof Schmitt 		a_status = atomic_read(&adapter->status);
150287ac01aSChristof Schmitt 		if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
151287ac01aSChristof Schmitt 			return 0;
152287ac01aSChristof Schmitt 	}
153287ac01aSChristof Schmitt 
154287ac01aSChristof Schmitt 	return need;
155287ac01aSChristof Schmitt }
156287ac01aSChristof Schmitt 
157287ac01aSChristof Schmitt static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
158287ac01aSChristof Schmitt 						  struct zfcp_adapter *adapter,
159287ac01aSChristof Schmitt 						  struct zfcp_port *port,
160287ac01aSChristof Schmitt 						  struct zfcp_unit *unit)
161287ac01aSChristof Schmitt {
162287ac01aSChristof Schmitt 	struct zfcp_erp_action *erp_action;
163287ac01aSChristof Schmitt 	u32 status = 0;
164287ac01aSChristof Schmitt 
165287ac01aSChristof Schmitt 	switch (need) {
166287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
167287ac01aSChristof Schmitt 		zfcp_unit_get(unit);
168287ac01aSChristof Schmitt 		atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status);
169287ac01aSChristof Schmitt 		erp_action = &unit->erp_action;
170287ac01aSChristof Schmitt 		if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING))
171287ac01aSChristof Schmitt 			status = ZFCP_STATUS_ERP_CLOSE_ONLY;
172287ac01aSChristof Schmitt 		break;
173287ac01aSChristof Schmitt 
174287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
175287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
176287ac01aSChristof Schmitt 		zfcp_port_get(port);
177287ac01aSChristof Schmitt 		zfcp_erp_action_dismiss_port(port);
178287ac01aSChristof Schmitt 		atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
179287ac01aSChristof Schmitt 		erp_action = &port->erp_action;
180287ac01aSChristof Schmitt 		if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
181287ac01aSChristof Schmitt 			status = ZFCP_STATUS_ERP_CLOSE_ONLY;
182287ac01aSChristof Schmitt 		break;
183287ac01aSChristof Schmitt 
184287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
185287ac01aSChristof Schmitt 		zfcp_adapter_get(adapter);
186287ac01aSChristof Schmitt 		zfcp_erp_action_dismiss_adapter(adapter);
187287ac01aSChristof Schmitt 		atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
188287ac01aSChristof Schmitt 		erp_action = &adapter->erp_action;
189287ac01aSChristof Schmitt 		if (!(atomic_read(&adapter->status) &
190287ac01aSChristof Schmitt 		      ZFCP_STATUS_COMMON_RUNNING))
191287ac01aSChristof Schmitt 			status = ZFCP_STATUS_ERP_CLOSE_ONLY;
192287ac01aSChristof Schmitt 		break;
193287ac01aSChristof Schmitt 
194287ac01aSChristof Schmitt 	default:
195287ac01aSChristof Schmitt 		return NULL;
196287ac01aSChristof Schmitt 	}
197287ac01aSChristof Schmitt 
198287ac01aSChristof Schmitt 	memset(erp_action, 0, sizeof(struct zfcp_erp_action));
199287ac01aSChristof Schmitt 	erp_action->adapter = adapter;
200287ac01aSChristof Schmitt 	erp_action->port = port;
201287ac01aSChristof Schmitt 	erp_action->unit = unit;
202287ac01aSChristof Schmitt 	erp_action->action = need;
203287ac01aSChristof Schmitt 	erp_action->status = status;
204287ac01aSChristof Schmitt 
205287ac01aSChristof Schmitt 	return erp_action;
206287ac01aSChristof Schmitt }
207287ac01aSChristof Schmitt 
208287ac01aSChristof Schmitt static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
209287ac01aSChristof Schmitt 				   struct zfcp_port *port,
2105ffd51a5SSwen Schillig 				   struct zfcp_unit *unit, char *id, void *ref)
211287ac01aSChristof Schmitt {
212287ac01aSChristof Schmitt 	int retval = 1, need;
213287ac01aSChristof Schmitt 	struct zfcp_erp_action *act = NULL;
214287ac01aSChristof Schmitt 
215287ac01aSChristof Schmitt 	if (!(atomic_read(&adapter->status) &
216287ac01aSChristof Schmitt 	      ZFCP_STATUS_ADAPTER_ERP_THREAD_UP))
217287ac01aSChristof Schmitt 		return -EIO;
218287ac01aSChristof Schmitt 
219287ac01aSChristof Schmitt 	need = zfcp_erp_required_act(want, adapter, port, unit);
220287ac01aSChristof Schmitt 	if (!need)
221287ac01aSChristof Schmitt 		goto out;
222287ac01aSChristof Schmitt 
223287ac01aSChristof Schmitt 	atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
224287ac01aSChristof Schmitt 	act = zfcp_erp_setup_act(need, adapter, port, unit);
225287ac01aSChristof Schmitt 	if (!act)
226287ac01aSChristof Schmitt 		goto out;
227287ac01aSChristof Schmitt 	++adapter->erp_total_count;
228287ac01aSChristof Schmitt 	list_add_tail(&act->list, &adapter->erp_ready_head);
229287ac01aSChristof Schmitt 	up(&adapter->erp_ready_sem);
2305ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_thread("eracte1", adapter);
231287ac01aSChristof Schmitt 	retval = 0;
232287ac01aSChristof Schmitt  out:
233287ac01aSChristof Schmitt 	zfcp_rec_dbf_event_trigger(id, ref, want, need, act,
234287ac01aSChristof Schmitt 				   adapter, port, unit);
235287ac01aSChristof Schmitt 	return retval;
236287ac01aSChristof Schmitt }
237287ac01aSChristof Schmitt 
238287ac01aSChristof Schmitt static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
2395ffd51a5SSwen Schillig 				    int clear_mask, char *id, void *ref)
2401da177e4SLinus Torvalds {
2411da177e4SLinus Torvalds 	zfcp_erp_adapter_block(adapter, clear_mask);
242a2fa0aedSChristof Schmitt 	zfcp_scsi_schedule_rports_block(adapter);
2431da177e4SLinus Torvalds 
2441da177e4SLinus Torvalds 	/* ensure propagation of failed status to new devices */
245287ac01aSChristof Schmitt 	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
2465ffd51a5SSwen Schillig 		zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
247287ac01aSChristof Schmitt 		return -EIO;
2481da177e4SLinus Torvalds 	}
249287ac01aSChristof Schmitt 	return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
2509467a9b3SMartin Peschke 				       adapter, NULL, NULL, id, ref);
2511da177e4SLinus Torvalds }
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds /**
254287ac01aSChristof Schmitt  * zfcp_erp_adapter_reopen - Reopen adapter.
255287ac01aSChristof Schmitt  * @adapter: Adapter to reopen.
256287ac01aSChristof Schmitt  * @clear: Status flags to clear.
257287ac01aSChristof Schmitt  * @id: Id for debug trace event.
258287ac01aSChristof Schmitt  * @ref: Reference for debug trace event.
2591da177e4SLinus Torvalds  */
260287ac01aSChristof Schmitt void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
2615ffd51a5SSwen Schillig 			     char *id, void *ref)
262287ac01aSChristof Schmitt {
263287ac01aSChristof Schmitt 	unsigned long flags;
264287ac01aSChristof Schmitt 
265287ac01aSChristof Schmitt 	read_lock_irqsave(&zfcp_data.config_lock, flags);
266287ac01aSChristof Schmitt 	write_lock(&adapter->erp_lock);
267287ac01aSChristof Schmitt 	_zfcp_erp_adapter_reopen(adapter, clear, id, ref);
268287ac01aSChristof Schmitt 	write_unlock(&adapter->erp_lock);
269287ac01aSChristof Schmitt 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
270287ac01aSChristof Schmitt }
271287ac01aSChristof Schmitt 
272287ac01aSChristof Schmitt /**
273287ac01aSChristof Schmitt  * zfcp_erp_adapter_shutdown - Shutdown adapter.
274287ac01aSChristof Schmitt  * @adapter: Adapter to shut down.
275287ac01aSChristof Schmitt  * @clear: Status flags to clear.
276287ac01aSChristof Schmitt  * @id: Id for debug trace event.
277287ac01aSChristof Schmitt  * @ref: Reference for debug trace event.
278287ac01aSChristof Schmitt  */
279287ac01aSChristof Schmitt void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
2805ffd51a5SSwen Schillig 			       char *id, void *ref)
281287ac01aSChristof Schmitt {
282287ac01aSChristof Schmitt 	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
283287ac01aSChristof Schmitt 	zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref);
284287ac01aSChristof Schmitt }
285287ac01aSChristof Schmitt 
286287ac01aSChristof Schmitt /**
287287ac01aSChristof Schmitt  * zfcp_erp_port_shutdown - Shutdown port
288287ac01aSChristof Schmitt  * @port: Port to shut down.
289287ac01aSChristof Schmitt  * @clear: Status flags to clear.
290287ac01aSChristof Schmitt  * @id: Id for debug trace event.
291287ac01aSChristof Schmitt  * @ref: Reference for debug trace event.
292287ac01aSChristof Schmitt  */
2935ffd51a5SSwen Schillig void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id,
2945ffd51a5SSwen Schillig 			    void *ref)
295287ac01aSChristof Schmitt {
296287ac01aSChristof Schmitt 	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
297287ac01aSChristof Schmitt 	zfcp_erp_port_reopen(port, clear | flags, id, ref);
298287ac01aSChristof Schmitt }
299287ac01aSChristof Schmitt 
300287ac01aSChristof Schmitt /**
301287ac01aSChristof Schmitt  * zfcp_erp_unit_shutdown - Shutdown unit
302287ac01aSChristof Schmitt  * @unit: Unit to shut down.
303287ac01aSChristof Schmitt  * @clear: Status flags to clear.
304287ac01aSChristof Schmitt  * @id: Id for debug trace event.
305287ac01aSChristof Schmitt  * @ref: Reference for debug trace event.
306287ac01aSChristof Schmitt  */
3075ffd51a5SSwen Schillig void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, char *id,
3085ffd51a5SSwen Schillig 			    void *ref)
309287ac01aSChristof Schmitt {
310287ac01aSChristof Schmitt 	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
311287ac01aSChristof Schmitt 	zfcp_erp_unit_reopen(unit, clear | flags, id, ref);
312287ac01aSChristof Schmitt }
313287ac01aSChristof Schmitt 
314287ac01aSChristof Schmitt static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
315287ac01aSChristof Schmitt {
3165ffd51a5SSwen Schillig 	zfcp_erp_modify_port_status(port, "erpblk1", NULL,
317287ac01aSChristof Schmitt 				    ZFCP_STATUS_COMMON_UNBLOCKED | clear,
318287ac01aSChristof Schmitt 				    ZFCP_CLEAR);
319287ac01aSChristof Schmitt }
320287ac01aSChristof Schmitt 
321287ac01aSChristof Schmitt static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
3225ffd51a5SSwen Schillig 					 int clear, char *id, void *ref)
323287ac01aSChristof Schmitt {
324287ac01aSChristof Schmitt 	zfcp_erp_port_block(port, clear);
325a2fa0aedSChristof Schmitt 	zfcp_scsi_schedule_rport_block(port);
326287ac01aSChristof Schmitt 
327287ac01aSChristof Schmitt 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
328287ac01aSChristof Schmitt 		return;
329287ac01aSChristof Schmitt 
330287ac01aSChristof Schmitt 	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
331287ac01aSChristof Schmitt 				port->adapter, port, NULL, id, ref);
332287ac01aSChristof Schmitt }
333287ac01aSChristof Schmitt 
334287ac01aSChristof Schmitt /**
335287ac01aSChristof Schmitt  * zfcp_erp_port_forced_reopen - Forced close of port and open again
336287ac01aSChristof Schmitt  * @port: Port to force close and to reopen.
337287ac01aSChristof Schmitt  * @id: Id for debug trace event.
338287ac01aSChristof Schmitt  * @ref: Reference for debug trace event.
339287ac01aSChristof Schmitt  */
3405ffd51a5SSwen Schillig void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id,
3411f6f7129SMartin Peschke 				 void *ref)
3421da177e4SLinus Torvalds {
3431da177e4SLinus Torvalds 	unsigned long flags;
3441da177e4SLinus Torvalds 	struct zfcp_adapter *adapter = port->adapter;
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds 	read_lock_irqsave(&zfcp_data.config_lock, flags);
3471da177e4SLinus Torvalds 	write_lock(&adapter->erp_lock);
348287ac01aSChristof Schmitt 	_zfcp_erp_port_forced_reopen(port, clear, id, ref);
349287ac01aSChristof Schmitt 	write_unlock(&adapter->erp_lock);
350287ac01aSChristof Schmitt 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
351287ac01aSChristof Schmitt }
352287ac01aSChristof Schmitt 
3535ffd51a5SSwen Schillig static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
354287ac01aSChristof Schmitt 				 void *ref)
355287ac01aSChristof Schmitt {
356287ac01aSChristof Schmitt 	zfcp_erp_port_block(port, clear);
357a2fa0aedSChristof Schmitt 	zfcp_scsi_schedule_rport_block(port);
358287ac01aSChristof Schmitt 
359287ac01aSChristof Schmitt 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
360287ac01aSChristof Schmitt 		/* ensure propagation of failed status to new devices */
3615ffd51a5SSwen Schillig 		zfcp_erp_port_failed(port, "erpreo1", NULL);
362287ac01aSChristof Schmitt 		return -EIO;
363287ac01aSChristof Schmitt 	}
364287ac01aSChristof Schmitt 
365287ac01aSChristof Schmitt 	return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
366287ac01aSChristof Schmitt 				       port->adapter, port, NULL, id, ref);
367287ac01aSChristof Schmitt }
368287ac01aSChristof Schmitt 
369287ac01aSChristof Schmitt /**
370287ac01aSChristof Schmitt  * zfcp_erp_port_reopen - trigger remote port recovery
371287ac01aSChristof Schmitt  * @port: port to recover
372287ac01aSChristof Schmitt  * @clear_mask: flags in port status to be cleared
373287ac01aSChristof Schmitt  *
374287ac01aSChristof Schmitt  * Returns 0 if recovery has been triggered, < 0 if not.
375287ac01aSChristof Schmitt  */
3765ffd51a5SSwen Schillig int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref)
377287ac01aSChristof Schmitt {
378287ac01aSChristof Schmitt 	unsigned long flags;
379287ac01aSChristof Schmitt 	int retval;
380287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = port->adapter;
381287ac01aSChristof Schmitt 
382287ac01aSChristof Schmitt 	read_lock_irqsave(&zfcp_data.config_lock, flags);
383287ac01aSChristof Schmitt 	write_lock(&adapter->erp_lock);
384287ac01aSChristof Schmitt 	retval = _zfcp_erp_port_reopen(port, clear, id, ref);
3851da177e4SLinus Torvalds 	write_unlock(&adapter->erp_lock);
3861da177e4SLinus Torvalds 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 	return retval;
3891da177e4SLinus Torvalds }
3901da177e4SLinus Torvalds 
391287ac01aSChristof Schmitt static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask)
3921da177e4SLinus Torvalds {
3935ffd51a5SSwen Schillig 	zfcp_erp_modify_unit_status(unit, "erublk1", NULL,
394287ac01aSChristof Schmitt 				    ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask,
395287ac01aSChristof Schmitt 				    ZFCP_CLEAR);
3961da177e4SLinus Torvalds }
3971da177e4SLinus Torvalds 
3985ffd51a5SSwen Schillig static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
399287ac01aSChristof Schmitt 				  void *ref)
400287ac01aSChristof Schmitt {
401287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = unit->port->adapter;
402287ac01aSChristof Schmitt 
403287ac01aSChristof Schmitt 	zfcp_erp_unit_block(unit, clear);
404287ac01aSChristof Schmitt 
405287ac01aSChristof Schmitt 	if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
406287ac01aSChristof Schmitt 		return;
407287ac01aSChristof Schmitt 
408287ac01aSChristof Schmitt 	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT,
4099467a9b3SMartin Peschke 				adapter, unit->port, unit, id, ref);
4101da177e4SLinus Torvalds }
4111da177e4SLinus Torvalds 
4121da177e4SLinus Torvalds /**
4131da177e4SLinus Torvalds  * zfcp_erp_unit_reopen - initiate reopen of a unit
4141da177e4SLinus Torvalds  * @unit: unit to be reopened
4151da177e4SLinus Torvalds  * @clear_mask: specifies flags in unit status to be cleared
4161da177e4SLinus Torvalds  * Return: 0 on success, < 0 on error
4171da177e4SLinus Torvalds  */
4185ffd51a5SSwen Schillig void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
4195ffd51a5SSwen Schillig 			  void *ref)
4201da177e4SLinus Torvalds {
4211da177e4SLinus Torvalds 	unsigned long flags;
422287ac01aSChristof Schmitt 	struct zfcp_port *port = unit->port;
423287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = port->adapter;
4241da177e4SLinus Torvalds 
4251da177e4SLinus Torvalds 	read_lock_irqsave(&zfcp_data.config_lock, flags);
4261da177e4SLinus Torvalds 	write_lock(&adapter->erp_lock);
427287ac01aSChristof Schmitt 	_zfcp_erp_unit_reopen(unit, clear, id, ref);
4281da177e4SLinus Torvalds 	write_unlock(&adapter->erp_lock);
4291da177e4SLinus Torvalds 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
4301da177e4SLinus Torvalds }
4311da177e4SLinus Torvalds 
432287ac01aSChristof Schmitt static int status_change_set(unsigned long mask, atomic_t *status)
4331da177e4SLinus Torvalds {
434287ac01aSChristof Schmitt 	return (atomic_read(status) ^ mask) & mask;
4351da177e4SLinus Torvalds }
4361da177e4SLinus Torvalds 
437287ac01aSChristof Schmitt static int status_change_clear(unsigned long mask, atomic_t *status)
438698ec016SMartin Peschke {
439287ac01aSChristof Schmitt 	return atomic_read(status) & mask;
440698ec016SMartin Peschke }
441698ec016SMartin Peschke 
442f6c0e7a7SAndreas Herrmann static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
4431da177e4SLinus Torvalds {
444287ac01aSChristof Schmitt 	if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status))
4455ffd51a5SSwen Schillig 		zfcp_rec_dbf_event_adapter("eraubl1", NULL, adapter);
446287ac01aSChristof Schmitt 	atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
4471da177e4SLinus Torvalds }
4481da177e4SLinus Torvalds 
449287ac01aSChristof Schmitt static void zfcp_erp_port_unblock(struct zfcp_port *port)
4501da177e4SLinus Torvalds {
451287ac01aSChristof Schmitt 	if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status))
4525ffd51a5SSwen Schillig 		zfcp_rec_dbf_event_port("erpubl1", NULL, port);
453287ac01aSChristof Schmitt 	atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
4541da177e4SLinus Torvalds }
4551da177e4SLinus Torvalds 
456287ac01aSChristof Schmitt static void zfcp_erp_unit_unblock(struct zfcp_unit *unit)
4571da177e4SLinus Torvalds {
458287ac01aSChristof Schmitt 	if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))
4595ffd51a5SSwen Schillig 		zfcp_rec_dbf_event_unit("eruubl1", NULL, unit);
460287ac01aSChristof Schmitt 	atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status);
4611da177e4SLinus Torvalds }
4621da177e4SLinus Torvalds 
463287ac01aSChristof Schmitt static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
4641da177e4SLinus Torvalds {
465287ac01aSChristof Schmitt 	list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
4665ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_action("erator1", erp_action);
4671da177e4SLinus Torvalds }
4681da177e4SLinus Torvalds 
469287ac01aSChristof Schmitt static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
4701da177e4SLinus Torvalds {
471287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
4721da177e4SLinus Torvalds 
473287ac01aSChristof Schmitt 	if (!act->fsf_req)
474287ac01aSChristof Schmitt 		return;
4751da177e4SLinus Torvalds 
476fea9d6c7SVolker Sameske 	spin_lock(&adapter->req_list_lock);
477287ac01aSChristof Schmitt 	if (zfcp_reqlist_find_safe(adapter, act->fsf_req) &&
478287ac01aSChristof Schmitt 	    act->fsf_req->erp_action == act) {
479287ac01aSChristof Schmitt 		if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
4801da177e4SLinus Torvalds 				   ZFCP_STATUS_ERP_TIMEDOUT)) {
481287ac01aSChristof Schmitt 			act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
4825ffd51a5SSwen Schillig 			zfcp_rec_dbf_event_action("erscf_1", act);
4837ea633ffSMartin Petermann 			act->fsf_req->erp_action = NULL;
4841da177e4SLinus Torvalds 		}
485287ac01aSChristof Schmitt 		if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
4865ffd51a5SSwen Schillig 			zfcp_rec_dbf_event_action("erscf_2", act);
487058b8647SSwen Schillig 		if (act->fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
488287ac01aSChristof Schmitt 			act->fsf_req = NULL;
489287ac01aSChristof Schmitt 	} else
490287ac01aSChristof Schmitt 		act->fsf_req = NULL;
491fea9d6c7SVolker Sameske 	spin_unlock(&adapter->req_list_lock);
492507e4969SMartin Peschke }
4931da177e4SLinus Torvalds 
494f6c0e7a7SAndreas Herrmann /**
495287ac01aSChristof Schmitt  * zfcp_erp_notify - Trigger ERP action.
496287ac01aSChristof Schmitt  * @erp_action: ERP action to continue.
497287ac01aSChristof Schmitt  * @set_mask: ERP action status flags to set.
4981da177e4SLinus Torvalds  */
499287ac01aSChristof Schmitt void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask)
5001da177e4SLinus Torvalds {
501287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = erp_action->adapter;
502287ac01aSChristof Schmitt 	unsigned long flags;
503287ac01aSChristof Schmitt 
504287ac01aSChristof Schmitt 	write_lock_irqsave(&adapter->erp_lock, flags);
5051da177e4SLinus Torvalds 	if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
5061da177e4SLinus Torvalds 		erp_action->status |= set_mask;
5071da177e4SLinus Torvalds 		zfcp_erp_action_ready(erp_action);
508f6c0e7a7SAndreas Herrmann 	}
5091da177e4SLinus Torvalds 	write_unlock_irqrestore(&adapter->erp_lock, flags);
5101da177e4SLinus Torvalds }
5111da177e4SLinus Torvalds 
512f6c0e7a7SAndreas Herrmann /**
513287ac01aSChristof Schmitt  * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request
514287ac01aSChristof Schmitt  * @data: ERP action (from timer data)
5151da177e4SLinus Torvalds  */
516287ac01aSChristof Schmitt void zfcp_erp_timeout_handler(unsigned long data)
5171da177e4SLinus Torvalds {
518287ac01aSChristof Schmitt 	struct zfcp_erp_action *act = (struct zfcp_erp_action *) data;
519287ac01aSChristof Schmitt 	zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT);
5201da177e4SLinus Torvalds }
5211da177e4SLinus Torvalds 
522287ac01aSChristof Schmitt static void zfcp_erp_memwait_handler(unsigned long data)
5231da177e4SLinus Torvalds {
524287ac01aSChristof Schmitt 	zfcp_erp_notify((struct zfcp_erp_action *)data, 0);
5251da177e4SLinus Torvalds }
5261da177e4SLinus Torvalds 
527287ac01aSChristof Schmitt static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
5281da177e4SLinus Torvalds {
5291da177e4SLinus Torvalds 	init_timer(&erp_action->timer);
5301da177e4SLinus Torvalds 	erp_action->timer.function = zfcp_erp_memwait_handler;
5311da177e4SLinus Torvalds 	erp_action->timer.data = (unsigned long) erp_action;
532287ac01aSChristof Schmitt 	erp_action->timer.expires = jiffies + HZ;
5331da177e4SLinus Torvalds 	add_timer(&erp_action->timer);
534287ac01aSChristof Schmitt }
535287ac01aSChristof Schmitt 
536287ac01aSChristof Schmitt static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
5375ffd51a5SSwen Schillig 				      int clear, char *id, void *ref)
538287ac01aSChristof Schmitt {
539287ac01aSChristof Schmitt 	struct zfcp_port *port;
540287ac01aSChristof Schmitt 
541287ac01aSChristof Schmitt 	list_for_each_entry(port, &adapter->port_list_head, list)
542287ac01aSChristof Schmitt 		_zfcp_erp_port_reopen(port, clear, id, ref);
543287ac01aSChristof Schmitt }
544287ac01aSChristof Schmitt 
5455ffd51a5SSwen Schillig static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
5465ffd51a5SSwen Schillig 				      char *id, void *ref)
547287ac01aSChristof Schmitt {
548287ac01aSChristof Schmitt 	struct zfcp_unit *unit;
549287ac01aSChristof Schmitt 
550287ac01aSChristof Schmitt 	list_for_each_entry(unit, &port->unit_list_head, list)
551287ac01aSChristof Schmitt 		_zfcp_erp_unit_reopen(unit, clear, id, ref);
552287ac01aSChristof Schmitt }
553287ac01aSChristof Schmitt 
55485600f7fSChristof Schmitt static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
555287ac01aSChristof Schmitt {
556287ac01aSChristof Schmitt 	switch (act->action) {
557287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
55885600f7fSChristof Schmitt 		_zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL);
559287ac01aSChristof Schmitt 		break;
560287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
56185600f7fSChristof Schmitt 		_zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL);
562287ac01aSChristof Schmitt 		break;
563287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
56485600f7fSChristof Schmitt 		_zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);
565287ac01aSChristof Schmitt 		break;
566287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
56785600f7fSChristof Schmitt 		_zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL);
56885600f7fSChristof Schmitt 		break;
56985600f7fSChristof Schmitt 	}
57085600f7fSChristof Schmitt }
57185600f7fSChristof Schmitt 
57285600f7fSChristof Schmitt static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act)
57385600f7fSChristof Schmitt {
57485600f7fSChristof Schmitt 	switch (act->action) {
57585600f7fSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
57685600f7fSChristof Schmitt 		_zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL);
57785600f7fSChristof Schmitt 		break;
57885600f7fSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
57985600f7fSChristof Schmitt 		_zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL);
58085600f7fSChristof Schmitt 		break;
58185600f7fSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
58285600f7fSChristof Schmitt 		_zfcp_erp_unit_reopen_all(act->port, 0, "ersfs_3", NULL);
583287ac01aSChristof Schmitt 		break;
584287ac01aSChristof Schmitt 	}
585287ac01aSChristof Schmitt }
586287ac01aSChristof Schmitt 
587287ac01aSChristof Schmitt static void zfcp_erp_wakeup(struct zfcp_adapter *adapter)
588287ac01aSChristof Schmitt {
589287ac01aSChristof Schmitt 	unsigned long flags;
590287ac01aSChristof Schmitt 
591287ac01aSChristof Schmitt 	read_lock_irqsave(&zfcp_data.config_lock, flags);
592287ac01aSChristof Schmitt 	read_lock(&adapter->erp_lock);
593287ac01aSChristof Schmitt 	if (list_empty(&adapter->erp_ready_head) &&
594287ac01aSChristof Schmitt 	    list_empty(&adapter->erp_running_head)) {
595287ac01aSChristof Schmitt 			atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING,
596287ac01aSChristof Schmitt 					  &adapter->status);
597287ac01aSChristof Schmitt 			wake_up(&adapter->erp_done_wqh);
598287ac01aSChristof Schmitt 	}
599287ac01aSChristof Schmitt 	read_unlock(&adapter->erp_lock);
600287ac01aSChristof Schmitt 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
601287ac01aSChristof Schmitt }
602287ac01aSChristof Schmitt 
603287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
604287ac01aSChristof Schmitt {
605564e1c86SSwen Schillig 	struct zfcp_qdio *qdio = act->adapter->qdio;
606564e1c86SSwen Schillig 
607564e1c86SSwen Schillig 	if (zfcp_qdio_open(qdio))
608287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
609564e1c86SSwen Schillig 	init_waitqueue_head(&qdio->req_q_wq);
610287ac01aSChristof Schmitt 	atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status);
611287ac01aSChristof Schmitt 	return ZFCP_ERP_SUCCEEDED;
612287ac01aSChristof Schmitt }
613287ac01aSChristof Schmitt 
614287ac01aSChristof Schmitt static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
615287ac01aSChristof Schmitt {
616287ac01aSChristof Schmitt 	struct zfcp_port *port;
617287ac01aSChristof Schmitt 	port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0,
618287ac01aSChristof Schmitt 				 adapter->peer_d_id);
619287ac01aSChristof Schmitt 	if (IS_ERR(port)) /* error or port already attached */
620287ac01aSChristof Schmitt 		return;
6215ffd51a5SSwen Schillig 	_zfcp_erp_port_reopen(port, 0, "ereptp1", NULL);
622287ac01aSChristof Schmitt }
623287ac01aSChristof Schmitt 
624287ac01aSChristof Schmitt static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
625287ac01aSChristof Schmitt {
626287ac01aSChristof Schmitt 	int retries;
627287ac01aSChristof Schmitt 	int sleep = 1;
628287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = erp_action->adapter;
629287ac01aSChristof Schmitt 
630287ac01aSChristof Schmitt 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
631287ac01aSChristof Schmitt 
632287ac01aSChristof Schmitt 	for (retries = 7; retries; retries--) {
633287ac01aSChristof Schmitt 		atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
634287ac01aSChristof Schmitt 				  &adapter->status);
635287ac01aSChristof Schmitt 		write_lock_irq(&adapter->erp_lock);
636287ac01aSChristof Schmitt 		zfcp_erp_action_to_running(erp_action);
637287ac01aSChristof Schmitt 		write_unlock_irq(&adapter->erp_lock);
638287ac01aSChristof Schmitt 		if (zfcp_fsf_exchange_config_data(erp_action)) {
639287ac01aSChristof Schmitt 			atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
640287ac01aSChristof Schmitt 					  &adapter->status);
641287ac01aSChristof Schmitt 			return ZFCP_ERP_FAILED;
642287ac01aSChristof Schmitt 		}
643287ac01aSChristof Schmitt 
6445ffd51a5SSwen Schillig 		zfcp_rec_dbf_event_thread_lock("erasfx1", adapter);
645287ac01aSChristof Schmitt 		down(&adapter->erp_ready_sem);
6465ffd51a5SSwen Schillig 		zfcp_rec_dbf_event_thread_lock("erasfx2", adapter);
647287ac01aSChristof Schmitt 		if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
648287ac01aSChristof Schmitt 			break;
649287ac01aSChristof Schmitt 
650287ac01aSChristof Schmitt 		if (!(atomic_read(&adapter->status) &
651287ac01aSChristof Schmitt 		      ZFCP_STATUS_ADAPTER_HOST_CON_INIT))
652287ac01aSChristof Schmitt 			break;
653287ac01aSChristof Schmitt 
654287ac01aSChristof Schmitt 		ssleep(sleep);
655287ac01aSChristof Schmitt 		sleep *= 2;
656287ac01aSChristof Schmitt 	}
657287ac01aSChristof Schmitt 
658287ac01aSChristof Schmitt 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
659287ac01aSChristof Schmitt 			  &adapter->status);
660287ac01aSChristof Schmitt 
661287ac01aSChristof Schmitt 	if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK))
662287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
663287ac01aSChristof Schmitt 
664287ac01aSChristof Schmitt 	if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
665287ac01aSChristof Schmitt 		zfcp_erp_enqueue_ptp_port(adapter);
666287ac01aSChristof Schmitt 
667287ac01aSChristof Schmitt 	return ZFCP_ERP_SUCCEEDED;
668287ac01aSChristof Schmitt }
669287ac01aSChristof Schmitt 
670287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act)
671287ac01aSChristof Schmitt {
672287ac01aSChristof Schmitt 	int ret;
673287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
674287ac01aSChristof Schmitt 
675287ac01aSChristof Schmitt 	write_lock_irq(&adapter->erp_lock);
676287ac01aSChristof Schmitt 	zfcp_erp_action_to_running(act);
677287ac01aSChristof Schmitt 	write_unlock_irq(&adapter->erp_lock);
678287ac01aSChristof Schmitt 
679287ac01aSChristof Schmitt 	ret = zfcp_fsf_exchange_port_data(act);
680287ac01aSChristof Schmitt 	if (ret == -EOPNOTSUPP)
681287ac01aSChristof Schmitt 		return ZFCP_ERP_SUCCEEDED;
682287ac01aSChristof Schmitt 	if (ret)
683287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
684287ac01aSChristof Schmitt 
6855ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_thread_lock("erasox1", adapter);
686287ac01aSChristof Schmitt 	down(&adapter->erp_ready_sem);
6875ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_thread_lock("erasox2", adapter);
688287ac01aSChristof Schmitt 	if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
689287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
690287ac01aSChristof Schmitt 
691287ac01aSChristof Schmitt 	return ZFCP_ERP_SUCCEEDED;
692287ac01aSChristof Schmitt }
693287ac01aSChristof Schmitt 
694287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)
695287ac01aSChristof Schmitt {
696287ac01aSChristof Schmitt 	if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED)
697287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
698287ac01aSChristof Schmitt 
699287ac01aSChristof Schmitt 	if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)
700287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
701287ac01aSChristof Schmitt 
702287ac01aSChristof Schmitt 	atomic_set(&act->adapter->stat_miss, 16);
703287ac01aSChristof Schmitt 	if (zfcp_status_read_refill(act->adapter))
704287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
705287ac01aSChristof Schmitt 
706287ac01aSChristof Schmitt 	return ZFCP_ERP_SUCCEEDED;
707287ac01aSChristof Schmitt }
708287ac01aSChristof Schmitt 
709cf13c082SSwen Schillig static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act)
710287ac01aSChristof Schmitt {
711287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
712287ac01aSChristof Schmitt 
713287ac01aSChristof Schmitt 	/* close queues to ensure that buffers are not accessed by adapter */
714564e1c86SSwen Schillig 	zfcp_qdio_close(adapter->qdio);
715287ac01aSChristof Schmitt 	zfcp_fsf_req_dismiss_all(adapter);
716287ac01aSChristof Schmitt 	adapter->fsf_req_seq_no = 0;
71755c770faSChristof Schmitt 	zfcp_fc_wka_ports_force_offline(adapter->gs);
718287ac01aSChristof Schmitt 	/* all ports and units are closed */
7195ffd51a5SSwen Schillig 	zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL,
720287ac01aSChristof Schmitt 				       ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
721cf13c082SSwen Schillig 
722cf13c082SSwen Schillig 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
723cf13c082SSwen Schillig 			  ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
724cf13c082SSwen Schillig }
725cf13c082SSwen Schillig 
726cf13c082SSwen Schillig static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act)
727cf13c082SSwen Schillig {
728cf13c082SSwen Schillig 	struct zfcp_adapter *adapter = act->adapter;
729cf13c082SSwen Schillig 
730cf13c082SSwen Schillig 	if (zfcp_erp_adapter_strategy_open_qdio(act)) {
731287ac01aSChristof Schmitt 		atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
73244cc76f2SSwen Schillig 				  ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
733cf13c082SSwen Schillig 				  &adapter->status);
734cf13c082SSwen Schillig 		return ZFCP_ERP_FAILED;
735cf13c082SSwen Schillig 	}
736cf13c082SSwen Schillig 
737cf13c082SSwen Schillig 	if (zfcp_erp_adapter_strategy_open_fsf(act)) {
738cf13c082SSwen Schillig 		zfcp_erp_adapter_strategy_close(act);
739cf13c082SSwen Schillig 		return ZFCP_ERP_FAILED;
740cf13c082SSwen Schillig 	}
741cf13c082SSwen Schillig 
742cf13c082SSwen Schillig 	atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &adapter->status);
743cf13c082SSwen Schillig 
744cf13c082SSwen Schillig 	return ZFCP_ERP_SUCCEEDED;
745287ac01aSChristof Schmitt }
746287ac01aSChristof Schmitt 
747287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act)
748287ac01aSChristof Schmitt {
749cf13c082SSwen Schillig 	struct zfcp_adapter *adapter = act->adapter;
750287ac01aSChristof Schmitt 
751cf13c082SSwen Schillig 	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN) {
752cf13c082SSwen Schillig 		zfcp_erp_adapter_strategy_close(act);
753287ac01aSChristof Schmitt 		if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
754287ac01aSChristof Schmitt 			return ZFCP_ERP_EXIT;
755cf13c082SSwen Schillig 	}
756287ac01aSChristof Schmitt 
757cf13c082SSwen Schillig 	if (zfcp_erp_adapter_strategy_open(act)) {
758287ac01aSChristof Schmitt 		ssleep(8);
759cf13c082SSwen Schillig 		return ZFCP_ERP_FAILED;
760cf13c082SSwen Schillig 	}
7611da177e4SLinus Torvalds 
762cf13c082SSwen Schillig 	return ZFCP_ERP_SUCCEEDED;
7631da177e4SLinus Torvalds }
7641da177e4SLinus Torvalds 
765287ac01aSChristof Schmitt static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act)
7661da177e4SLinus Torvalds {
767287ac01aSChristof Schmitt 	int retval;
768287ac01aSChristof Schmitt 
769287ac01aSChristof Schmitt 	retval = zfcp_fsf_close_physical_port(act);
770287ac01aSChristof Schmitt 	if (retval == -ENOMEM)
771287ac01aSChristof Schmitt 		return ZFCP_ERP_NOMEM;
772287ac01aSChristof Schmitt 	act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING;
773287ac01aSChristof Schmitt 	if (retval)
774287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
775287ac01aSChristof Schmitt 
776287ac01aSChristof Schmitt 	return ZFCP_ERP_CONTINUES;
7771da177e4SLinus Torvalds }
7781da177e4SLinus Torvalds 
779287ac01aSChristof Schmitt static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
7801da177e4SLinus Torvalds {
781a5b11ddaSChristof Schmitt 	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status);
782287ac01aSChristof Schmitt }
7831da177e4SLinus Torvalds 
784287ac01aSChristof Schmitt static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
785287ac01aSChristof Schmitt {
786287ac01aSChristof Schmitt 	struct zfcp_port *port = erp_action->port;
787287ac01aSChristof Schmitt 	int status = atomic_read(&port->status);
788287ac01aSChristof Schmitt 
789287ac01aSChristof Schmitt 	switch (erp_action->step) {
790287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNINITIALIZED:
791287ac01aSChristof Schmitt 		zfcp_erp_port_strategy_clearstati(port);
792287ac01aSChristof Schmitt 		if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) &&
793287ac01aSChristof Schmitt 		    (status & ZFCP_STATUS_COMMON_OPEN))
794287ac01aSChristof Schmitt 			return zfcp_erp_port_forced_strategy_close(erp_action);
7951da177e4SLinus Torvalds 		else
796287ac01aSChristof Schmitt 			return ZFCP_ERP_FAILED;
797287ac01aSChristof Schmitt 
798287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
799ddb3e0c1SChristof Schmitt 		if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN))
800287ac01aSChristof Schmitt 			return ZFCP_ERP_SUCCEEDED;
801287ac01aSChristof Schmitt 	}
802287ac01aSChristof Schmitt 	return ZFCP_ERP_FAILED;
8031da177e4SLinus Torvalds }
8041da177e4SLinus Torvalds 
805287ac01aSChristof Schmitt static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action)
8061da177e4SLinus Torvalds {
807287ac01aSChristof Schmitt 	int retval;
8081da177e4SLinus Torvalds 
809287ac01aSChristof Schmitt 	retval = zfcp_fsf_close_port(erp_action);
810287ac01aSChristof Schmitt 	if (retval == -ENOMEM)
811287ac01aSChristof Schmitt 		return ZFCP_ERP_NOMEM;
812287ac01aSChristof Schmitt 	erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING;
813287ac01aSChristof Schmitt 	if (retval)
814287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
815287ac01aSChristof Schmitt 	return ZFCP_ERP_CONTINUES;
8161da177e4SLinus Torvalds }
8171da177e4SLinus Torvalds 
818287ac01aSChristof Schmitt static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action)
819287ac01aSChristof Schmitt {
820287ac01aSChristof Schmitt 	int retval;
821287ac01aSChristof Schmitt 
822287ac01aSChristof Schmitt 	retval = zfcp_fsf_open_port(erp_action);
823287ac01aSChristof Schmitt 	if (retval == -ENOMEM)
824287ac01aSChristof Schmitt 		return ZFCP_ERP_NOMEM;
825287ac01aSChristof Schmitt 	erp_action->step = ZFCP_ERP_STEP_PORT_OPENING;
826287ac01aSChristof Schmitt 	if (retval)
827287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
828287ac01aSChristof Schmitt 	return ZFCP_ERP_CONTINUES;
829287ac01aSChristof Schmitt }
830287ac01aSChristof Schmitt 
831287ac01aSChristof Schmitt static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
832287ac01aSChristof Schmitt {
833287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
834287ac01aSChristof Schmitt 	struct zfcp_port *port = act->port;
835287ac01aSChristof Schmitt 
836287ac01aSChristof Schmitt 	if (port->wwpn != adapter->peer_wwpn) {
8375ffd51a5SSwen Schillig 		zfcp_erp_port_failed(port, "eroptp1", NULL);
838287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
839287ac01aSChristof Schmitt 	}
840287ac01aSChristof Schmitt 	port->d_id = adapter->peer_d_id;
841287ac01aSChristof Schmitt 	return zfcp_erp_port_strategy_open_port(act);
842287ac01aSChristof Schmitt }
843287ac01aSChristof Schmitt 
844287ac01aSChristof Schmitt static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
845287ac01aSChristof Schmitt {
846287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
847287ac01aSChristof Schmitt 	struct zfcp_port *port = act->port;
848287ac01aSChristof Schmitt 	int p_status = atomic_read(&port->status);
849287ac01aSChristof Schmitt 
850287ac01aSChristof Schmitt 	switch (act->step) {
851287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNINITIALIZED:
852287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
853287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_PORT_CLOSING:
854287ac01aSChristof Schmitt 		if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
855287ac01aSChristof Schmitt 			return zfcp_erp_open_ptp_port(act);
856b98478d7SChristof Schmitt 		if (!port->d_id) {
857947a9acaSSwen Schillig 			zfcp_port_get(port);
8584544683aSSwen Schillig 			if (!queue_work(adapter->work_queue,
859947a9acaSSwen Schillig 					&port->gid_pn_work))
860947a9acaSSwen Schillig 				zfcp_port_put(port);
861799b76d0SChristof Schmitt 			return ZFCP_ERP_EXIT;
862287ac01aSChristof Schmitt 		}
863287ac01aSChristof Schmitt 		return zfcp_erp_port_strategy_open_port(act);
864287ac01aSChristof Schmitt 
865287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_PORT_OPENING:
866287ac01aSChristof Schmitt 		/* D_ID might have changed during open */
8675ab944f9SSwen Schillig 		if (p_status & ZFCP_STATUS_COMMON_OPEN) {
868b98478d7SChristof Schmitt 			if (port->d_id)
869287ac01aSChristof Schmitt 				return ZFCP_ERP_SUCCEEDED;
8705ab944f9SSwen Schillig 			else {
8715ab944f9SSwen Schillig 				act->step = ZFCP_ERP_STEP_PORT_CLOSING;
8725ab944f9SSwen Schillig 				return ZFCP_ERP_CONTINUES;
8735ab944f9SSwen Schillig 			}
874287ac01aSChristof Schmitt 		}
875ea460a81SSwen Schillig 		if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
876ea460a81SSwen Schillig 			port->d_id = 0;
877ea460a81SSwen Schillig 			_zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL);
878ea460a81SSwen Schillig 			return ZFCP_ERP_EXIT;
879ea460a81SSwen Schillig 		}
880ea460a81SSwen Schillig 		/* fall through otherwise */
881287ac01aSChristof Schmitt 	}
8825ab944f9SSwen Schillig 	return ZFCP_ERP_FAILED;
883287ac01aSChristof Schmitt }
884287ac01aSChristof Schmitt 
885287ac01aSChristof Schmitt static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
886287ac01aSChristof Schmitt {
887287ac01aSChristof Schmitt 	struct zfcp_port *port = erp_action->port;
888287ac01aSChristof Schmitt 
8895ab944f9SSwen Schillig 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC)
8905ab944f9SSwen Schillig 		goto close_init_done;
8915ab944f9SSwen Schillig 
892287ac01aSChristof Schmitt 	switch (erp_action->step) {
893287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNINITIALIZED:
894287ac01aSChristof Schmitt 		zfcp_erp_port_strategy_clearstati(port);
895287ac01aSChristof Schmitt 		if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)
896287ac01aSChristof Schmitt 			return zfcp_erp_port_strategy_close(erp_action);
897287ac01aSChristof Schmitt 		break;
898287ac01aSChristof Schmitt 
899287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_PORT_CLOSING:
900287ac01aSChristof Schmitt 		if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)
901287ac01aSChristof Schmitt 			return ZFCP_ERP_FAILED;
902287ac01aSChristof Schmitt 		break;
903287ac01aSChristof Schmitt 	}
9045ab944f9SSwen Schillig 
9055ab944f9SSwen Schillig close_init_done:
906287ac01aSChristof Schmitt 	if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
907287ac01aSChristof Schmitt 		return ZFCP_ERP_EXIT;
908287ac01aSChristof Schmitt 
9095ab944f9SSwen Schillig 	return zfcp_erp_port_strategy_open_common(erp_action);
910287ac01aSChristof Schmitt }
911287ac01aSChristof Schmitt 
912287ac01aSChristof Schmitt static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit)
913287ac01aSChristof Schmitt {
91444cc76f2SSwen Schillig 	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
915287ac01aSChristof Schmitt 			  ZFCP_STATUS_UNIT_SHARED |
916287ac01aSChristof Schmitt 			  ZFCP_STATUS_UNIT_READONLY,
917287ac01aSChristof Schmitt 			  &unit->status);
918287ac01aSChristof Schmitt }
919287ac01aSChristof Schmitt 
920287ac01aSChristof Schmitt static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action)
921287ac01aSChristof Schmitt {
922287ac01aSChristof Schmitt 	int retval = zfcp_fsf_close_unit(erp_action);
923287ac01aSChristof Schmitt 	if (retval == -ENOMEM)
924287ac01aSChristof Schmitt 		return ZFCP_ERP_NOMEM;
925287ac01aSChristof Schmitt 	erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING;
926287ac01aSChristof Schmitt 	if (retval)
927287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
928287ac01aSChristof Schmitt 	return ZFCP_ERP_CONTINUES;
929287ac01aSChristof Schmitt }
930287ac01aSChristof Schmitt 
931287ac01aSChristof Schmitt static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action)
932287ac01aSChristof Schmitt {
933287ac01aSChristof Schmitt 	int retval = zfcp_fsf_open_unit(erp_action);
934287ac01aSChristof Schmitt 	if (retval == -ENOMEM)
935287ac01aSChristof Schmitt 		return ZFCP_ERP_NOMEM;
936287ac01aSChristof Schmitt 	erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING;
937287ac01aSChristof Schmitt 	if (retval)
938287ac01aSChristof Schmitt 		return  ZFCP_ERP_FAILED;
939287ac01aSChristof Schmitt 	return ZFCP_ERP_CONTINUES;
940287ac01aSChristof Schmitt }
941287ac01aSChristof Schmitt 
942287ac01aSChristof Schmitt static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action)
943287ac01aSChristof Schmitt {
944287ac01aSChristof Schmitt 	struct zfcp_unit *unit = erp_action->unit;
945287ac01aSChristof Schmitt 
946287ac01aSChristof Schmitt 	switch (erp_action->step) {
947287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNINITIALIZED:
948287ac01aSChristof Schmitt 		zfcp_erp_unit_strategy_clearstati(unit);
949287ac01aSChristof Schmitt 		if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
950287ac01aSChristof Schmitt 			return zfcp_erp_unit_strategy_close(erp_action);
951287ac01aSChristof Schmitt 		/* already closed, fall through */
952287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNIT_CLOSING:
953287ac01aSChristof Schmitt 		if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
954287ac01aSChristof Schmitt 			return ZFCP_ERP_FAILED;
955287ac01aSChristof Schmitt 		if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
956287ac01aSChristof Schmitt 			return ZFCP_ERP_EXIT;
957287ac01aSChristof Schmitt 		return zfcp_erp_unit_strategy_open(erp_action);
958287ac01aSChristof Schmitt 
959287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNIT_OPENING:
960287ac01aSChristof Schmitt 		if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
961287ac01aSChristof Schmitt 			return ZFCP_ERP_SUCCEEDED;
962287ac01aSChristof Schmitt 	}
963287ac01aSChristof Schmitt 	return ZFCP_ERP_FAILED;
964287ac01aSChristof Schmitt }
965287ac01aSChristof Schmitt 
966287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result)
967287ac01aSChristof Schmitt {
968287ac01aSChristof Schmitt 	switch (result) {
969287ac01aSChristof Schmitt 	case ZFCP_ERP_SUCCEEDED :
970287ac01aSChristof Schmitt 		atomic_set(&unit->erp_counter, 0);
971287ac01aSChristof Schmitt 		zfcp_erp_unit_unblock(unit);
972287ac01aSChristof Schmitt 		break;
973287ac01aSChristof Schmitt 	case ZFCP_ERP_FAILED :
974287ac01aSChristof Schmitt 		atomic_inc(&unit->erp_counter);
975ff3b24faSChristof Schmitt 		if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) {
976ff3b24faSChristof Schmitt 			dev_err(&unit->port->adapter->ccw_device->dev,
977ff3b24faSChristof Schmitt 				"ERP failed for unit 0x%016Lx on "
978ff3b24faSChristof Schmitt 				"port 0x%016Lx\n",
9797ba58c9cSSwen Schillig 				(unsigned long long)unit->fcp_lun,
9807ba58c9cSSwen Schillig 				(unsigned long long)unit->port->wwpn);
9815ffd51a5SSwen Schillig 			zfcp_erp_unit_failed(unit, "erusck1", NULL);
982ff3b24faSChristof Schmitt 		}
983287ac01aSChristof Schmitt 		break;
984287ac01aSChristof Schmitt 	}
985287ac01aSChristof Schmitt 
986287ac01aSChristof Schmitt 	if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
987287ac01aSChristof Schmitt 		zfcp_erp_unit_block(unit, 0);
988287ac01aSChristof Schmitt 		result = ZFCP_ERP_EXIT;
989287ac01aSChristof Schmitt 	}
990287ac01aSChristof Schmitt 	return result;
991287ac01aSChristof Schmitt }
992287ac01aSChristof Schmitt 
993287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
994287ac01aSChristof Schmitt {
995287ac01aSChristof Schmitt 	switch (result) {
996287ac01aSChristof Schmitt 	case ZFCP_ERP_SUCCEEDED :
997287ac01aSChristof Schmitt 		atomic_set(&port->erp_counter, 0);
998287ac01aSChristof Schmitt 		zfcp_erp_port_unblock(port);
999287ac01aSChristof Schmitt 		break;
1000287ac01aSChristof Schmitt 
1001287ac01aSChristof Schmitt 	case ZFCP_ERP_FAILED :
1002287ac01aSChristof Schmitt 		if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) {
1003287ac01aSChristof Schmitt 			zfcp_erp_port_block(port, 0);
1004287ac01aSChristof Schmitt 			result = ZFCP_ERP_EXIT;
1005287ac01aSChristof Schmitt 		}
1006287ac01aSChristof Schmitt 		atomic_inc(&port->erp_counter);
1007ff3b24faSChristof Schmitt 		if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
1008ff3b24faSChristof Schmitt 			dev_err(&port->adapter->ccw_device->dev,
1009ff3b24faSChristof Schmitt 				"ERP failed for remote port 0x%016Lx\n",
10107ba58c9cSSwen Schillig 				(unsigned long long)port->wwpn);
10115ffd51a5SSwen Schillig 			zfcp_erp_port_failed(port, "erpsck1", NULL);
1012ff3b24faSChristof Schmitt 		}
1013287ac01aSChristof Schmitt 		break;
1014287ac01aSChristof Schmitt 	}
1015287ac01aSChristof Schmitt 
1016287ac01aSChristof Schmitt 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1017287ac01aSChristof Schmitt 		zfcp_erp_port_block(port, 0);
1018287ac01aSChristof Schmitt 		result = ZFCP_ERP_EXIT;
1019287ac01aSChristof Schmitt 	}
1020287ac01aSChristof Schmitt 	return result;
1021287ac01aSChristof Schmitt }
1022287ac01aSChristof Schmitt 
1023287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter,
1024287ac01aSChristof Schmitt 					   int result)
1025287ac01aSChristof Schmitt {
1026287ac01aSChristof Schmitt 	switch (result) {
1027287ac01aSChristof Schmitt 	case ZFCP_ERP_SUCCEEDED :
1028287ac01aSChristof Schmitt 		atomic_set(&adapter->erp_counter, 0);
1029287ac01aSChristof Schmitt 		zfcp_erp_adapter_unblock(adapter);
1030287ac01aSChristof Schmitt 		break;
1031287ac01aSChristof Schmitt 
1032287ac01aSChristof Schmitt 	case ZFCP_ERP_FAILED :
1033287ac01aSChristof Schmitt 		atomic_inc(&adapter->erp_counter);
1034ff3b24faSChristof Schmitt 		if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) {
1035ff3b24faSChristof Schmitt 			dev_err(&adapter->ccw_device->dev,
1036ff3b24faSChristof Schmitt 				"ERP cannot recover an error "
1037ff3b24faSChristof Schmitt 				"on the FCP device\n");
10385ffd51a5SSwen Schillig 			zfcp_erp_adapter_failed(adapter, "erasck1", NULL);
1039ff3b24faSChristof Schmitt 		}
1040287ac01aSChristof Schmitt 		break;
1041287ac01aSChristof Schmitt 	}
1042287ac01aSChristof Schmitt 
1043287ac01aSChristof Schmitt 	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1044287ac01aSChristof Schmitt 		zfcp_erp_adapter_block(adapter, 0);
1045287ac01aSChristof Schmitt 		result = ZFCP_ERP_EXIT;
1046287ac01aSChristof Schmitt 	}
1047287ac01aSChristof Schmitt 	return result;
1048287ac01aSChristof Schmitt }
1049287ac01aSChristof Schmitt 
1050287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action,
1051287ac01aSChristof Schmitt 					  int result)
10521da177e4SLinus Torvalds {
10531da177e4SLinus Torvalds 	struct zfcp_adapter *adapter = erp_action->adapter;
10541da177e4SLinus Torvalds 	struct zfcp_port *port = erp_action->port;
10551da177e4SLinus Torvalds 	struct zfcp_unit *unit = erp_action->unit;
10561da177e4SLinus Torvalds 
10571da177e4SLinus Torvalds 	switch (erp_action->action) {
10581da177e4SLinus Torvalds 
10591da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
10601da177e4SLinus Torvalds 		result = zfcp_erp_strategy_check_unit(unit, result);
10611da177e4SLinus Torvalds 		break;
10621da177e4SLinus Torvalds 
10631da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
10641da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_PORT:
10651da177e4SLinus Torvalds 		result = zfcp_erp_strategy_check_port(port, result);
10661da177e4SLinus Torvalds 		break;
10671da177e4SLinus Torvalds 
10681da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
10691da177e4SLinus Torvalds 		result = zfcp_erp_strategy_check_adapter(adapter, result);
10701da177e4SLinus Torvalds 		break;
10711da177e4SLinus Torvalds 	}
10721da177e4SLinus Torvalds 	return result;
10731da177e4SLinus Torvalds }
10741da177e4SLinus Torvalds 
1075287ac01aSChristof Schmitt static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status)
10761da177e4SLinus Torvalds {
1077287ac01aSChristof Schmitt 	int status = atomic_read(target_status);
10781da177e4SLinus Torvalds 
1079287ac01aSChristof Schmitt 	if ((status & ZFCP_STATUS_COMMON_RUNNING) &&
1080287ac01aSChristof Schmitt 	    (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1081287ac01aSChristof Schmitt 		return 1; /* take it online */
1082287ac01aSChristof Schmitt 
1083287ac01aSChristof Schmitt 	if (!(status & ZFCP_STATUS_COMMON_RUNNING) &&
1084287ac01aSChristof Schmitt 	    !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1085287ac01aSChristof Schmitt 		return 1; /* take it offline */
1086287ac01aSChristof Schmitt 
1087287ac01aSChristof Schmitt 	return 0;
1088287ac01aSChristof Schmitt }
1089287ac01aSChristof Schmitt 
1090287ac01aSChristof Schmitt static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
1091287ac01aSChristof Schmitt {
1092287ac01aSChristof Schmitt 	int action = act->action;
1093287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
1094287ac01aSChristof Schmitt 	struct zfcp_port *port = act->port;
1095287ac01aSChristof Schmitt 	struct zfcp_unit *unit = act->unit;
1096287ac01aSChristof Schmitt 	u32 erp_status = act->status;
1097287ac01aSChristof Schmitt 
1098287ac01aSChristof Schmitt 	switch (action) {
10991da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1100287ac01aSChristof Schmitt 		if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) {
1101287ac01aSChristof Schmitt 			_zfcp_erp_adapter_reopen(adapter,
11029467a9b3SMartin Peschke 						 ZFCP_STATUS_COMMON_ERP_FAILED,
11035ffd51a5SSwen Schillig 						 "ersscg1", NULL);
1104287ac01aSChristof Schmitt 			return ZFCP_ERP_EXIT;
11051da177e4SLinus Torvalds 		}
11061da177e4SLinus Torvalds 		break;
11071da177e4SLinus Torvalds 
11081da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
11091da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_PORT:
1110287ac01aSChristof Schmitt 		if (zfcp_erp_strat_change_det(&port->status, erp_status)) {
1111287ac01aSChristof Schmitt 			_zfcp_erp_port_reopen(port,
11129467a9b3SMartin Peschke 					      ZFCP_STATUS_COMMON_ERP_FAILED,
11135ffd51a5SSwen Schillig 					      "ersscg2", NULL);
1114287ac01aSChristof Schmitt 			return ZFCP_ERP_EXIT;
11151da177e4SLinus Torvalds 		}
11161da177e4SLinus Torvalds 		break;
11171da177e4SLinus Torvalds 
11181da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
1119287ac01aSChristof Schmitt 		if (zfcp_erp_strat_change_det(&unit->status, erp_status)) {
1120287ac01aSChristof Schmitt 			_zfcp_erp_unit_reopen(unit,
11219467a9b3SMartin Peschke 					      ZFCP_STATUS_COMMON_ERP_FAILED,
11225ffd51a5SSwen Schillig 					      "ersscg3", NULL);
1123287ac01aSChristof Schmitt 			return ZFCP_ERP_EXIT;
11241da177e4SLinus Torvalds 		}
11251da177e4SLinus Torvalds 		break;
11261da177e4SLinus Torvalds 	}
1127287ac01aSChristof Schmitt 	return ret;
11281da177e4SLinus Torvalds }
11291da177e4SLinus Torvalds 
1130287ac01aSChristof Schmitt static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
11311da177e4SLinus Torvalds {
1132287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = erp_action->adapter;
1133287ac01aSChristof Schmitt 
1134287ac01aSChristof Schmitt 	adapter->erp_total_count--;
1135287ac01aSChristof Schmitt 	if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1136287ac01aSChristof Schmitt 		adapter->erp_low_mem_count--;
1137287ac01aSChristof Schmitt 		erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
11381da177e4SLinus Torvalds 	}
11391da177e4SLinus Torvalds 
1140287ac01aSChristof Schmitt 	list_del(&erp_action->list);
11415ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_action("eractd1", erp_action);
11421da177e4SLinus Torvalds 
1143287ac01aSChristof Schmitt 	switch (erp_action->action) {
1144287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
1145287ac01aSChristof Schmitt 		atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1146287ac01aSChristof Schmitt 				  &erp_action->unit->status);
11471da177e4SLinus Torvalds 		break;
1148287ac01aSChristof Schmitt 
1149287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1150287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
1151287ac01aSChristof Schmitt 		atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1152287ac01aSChristof Schmitt 				  &erp_action->port->status);
11531da177e4SLinus Torvalds 		break;
1154287ac01aSChristof Schmitt 
1155287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1156287ac01aSChristof Schmitt 		atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1157287ac01aSChristof Schmitt 				  &erp_action->adapter->status);
11581da177e4SLinus Torvalds 		break;
11591da177e4SLinus Torvalds 	}
11601da177e4SLinus Torvalds }
11611da177e4SLinus Torvalds 
1162287ac01aSChristof Schmitt static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
1163287ac01aSChristof Schmitt {
1164287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
1165287ac01aSChristof Schmitt 	struct zfcp_port *port = act->port;
1166287ac01aSChristof Schmitt 	struct zfcp_unit *unit = act->unit;
1167287ac01aSChristof Schmitt 
1168287ac01aSChristof Schmitt 	switch (act->action) {
1169287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
1170a2fa0aedSChristof Schmitt 		if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
117192d5193bSSwen Schillig 			zfcp_unit_get(unit);
117292d5193bSSwen Schillig 			if (scsi_queue_work(unit->port->adapter->scsi_host,
117392d5193bSSwen Schillig 					    &unit->scsi_work) <= 0)
117492d5193bSSwen Schillig 				zfcp_unit_put(unit);
1175287ac01aSChristof Schmitt 		}
1176287ac01aSChristof Schmitt 		zfcp_unit_put(unit);
1177287ac01aSChristof Schmitt 		break;
1178287ac01aSChristof Schmitt 
1179287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1180287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
1181a2fa0aedSChristof Schmitt 		if (result == ZFCP_ERP_SUCCEEDED)
1182a2fa0aedSChristof Schmitt 			zfcp_scsi_schedule_rport_register(port);
11831da177e4SLinus Torvalds 		zfcp_port_put(port);
11841da177e4SLinus Torvalds 		break;
1185287ac01aSChristof Schmitt 
11861da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1187a2fa0aedSChristof Schmitt 		if (result == ZFCP_ERP_SUCCEEDED) {
1188bd43a42bSChristof Schmitt 			register_service_level(&adapter->service_level);
1189fca55b6fSSwen Schillig 			schedule_work(&adapter->scan_work);
1190a2fa0aedSChristof Schmitt 		} else
1191a2fa0aedSChristof Schmitt 			unregister_service_level(&adapter->service_level);
11921da177e4SLinus Torvalds 		zfcp_adapter_put(adapter);
11931da177e4SLinus Torvalds 		break;
11941da177e4SLinus Torvalds 	}
11951da177e4SLinus Torvalds }
11961da177e4SLinus Torvalds 
1197287ac01aSChristof Schmitt static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
1198287ac01aSChristof Schmitt {
1199287ac01aSChristof Schmitt 	switch (erp_action->action) {
1200287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1201287ac01aSChristof Schmitt 		return zfcp_erp_adapter_strategy(erp_action);
1202287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1203287ac01aSChristof Schmitt 		return zfcp_erp_port_forced_strategy(erp_action);
1204287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
1205287ac01aSChristof Schmitt 		return zfcp_erp_port_strategy(erp_action);
1206287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
1207287ac01aSChristof Schmitt 		return zfcp_erp_unit_strategy(erp_action);
1208287ac01aSChristof Schmitt 	}
1209287ac01aSChristof Schmitt 	return ZFCP_ERP_FAILED;
1210287ac01aSChristof Schmitt }
12111da177e4SLinus Torvalds 
1212287ac01aSChristof Schmitt static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
1213287ac01aSChristof Schmitt {
1214287ac01aSChristof Schmitt 	int retval;
1215287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = erp_action->adapter;
1216287ac01aSChristof Schmitt 	unsigned long flags;
1217287ac01aSChristof Schmitt 
1218287ac01aSChristof Schmitt 	read_lock_irqsave(&zfcp_data.config_lock, flags);
1219287ac01aSChristof Schmitt 	write_lock(&adapter->erp_lock);
1220287ac01aSChristof Schmitt 
1221287ac01aSChristof Schmitt 	zfcp_erp_strategy_check_fsfreq(erp_action);
1222287ac01aSChristof Schmitt 
1223287ac01aSChristof Schmitt 	if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
1224287ac01aSChristof Schmitt 		zfcp_erp_action_dequeue(erp_action);
1225287ac01aSChristof Schmitt 		retval = ZFCP_ERP_DISMISSED;
1226287ac01aSChristof Schmitt 		goto unlock;
1227287ac01aSChristof Schmitt 	}
1228287ac01aSChristof Schmitt 
1229287ac01aSChristof Schmitt 	zfcp_erp_action_to_running(erp_action);
1230287ac01aSChristof Schmitt 
1231287ac01aSChristof Schmitt 	/* no lock to allow for blocking operations */
1232287ac01aSChristof Schmitt 	write_unlock(&adapter->erp_lock);
1233287ac01aSChristof Schmitt 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
1234287ac01aSChristof Schmitt 	retval = zfcp_erp_strategy_do_action(erp_action);
1235287ac01aSChristof Schmitt 	read_lock_irqsave(&zfcp_data.config_lock, flags);
1236287ac01aSChristof Schmitt 	write_lock(&adapter->erp_lock);
1237287ac01aSChristof Schmitt 
1238287ac01aSChristof Schmitt 	if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED)
1239287ac01aSChristof Schmitt 		retval = ZFCP_ERP_CONTINUES;
1240287ac01aSChristof Schmitt 
1241287ac01aSChristof Schmitt 	switch (retval) {
1242287ac01aSChristof Schmitt 	case ZFCP_ERP_NOMEM:
1243287ac01aSChristof Schmitt 		if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) {
1244287ac01aSChristof Schmitt 			++adapter->erp_low_mem_count;
1245287ac01aSChristof Schmitt 			erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
1246287ac01aSChristof Schmitt 		}
1247287ac01aSChristof Schmitt 		if (adapter->erp_total_count == adapter->erp_low_mem_count)
12485ffd51a5SSwen Schillig 			_zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL);
1249287ac01aSChristof Schmitt 		else {
1250287ac01aSChristof Schmitt 			zfcp_erp_strategy_memwait(erp_action);
1251287ac01aSChristof Schmitt 			retval = ZFCP_ERP_CONTINUES;
1252287ac01aSChristof Schmitt 		}
1253287ac01aSChristof Schmitt 		goto unlock;
1254287ac01aSChristof Schmitt 
1255287ac01aSChristof Schmitt 	case ZFCP_ERP_CONTINUES:
1256287ac01aSChristof Schmitt 		if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1257287ac01aSChristof Schmitt 			--adapter->erp_low_mem_count;
1258287ac01aSChristof Schmitt 			erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
1259287ac01aSChristof Schmitt 		}
1260287ac01aSChristof Schmitt 		goto unlock;
1261287ac01aSChristof Schmitt 	}
1262287ac01aSChristof Schmitt 
1263287ac01aSChristof Schmitt 	retval = zfcp_erp_strategy_check_target(erp_action, retval);
1264287ac01aSChristof Schmitt 	zfcp_erp_action_dequeue(erp_action);
1265287ac01aSChristof Schmitt 	retval = zfcp_erp_strategy_statechange(erp_action, retval);
1266287ac01aSChristof Schmitt 	if (retval == ZFCP_ERP_EXIT)
1267287ac01aSChristof Schmitt 		goto unlock;
126885600f7fSChristof Schmitt 	if (retval == ZFCP_ERP_SUCCEEDED)
126985600f7fSChristof Schmitt 		zfcp_erp_strategy_followup_success(erp_action);
127085600f7fSChristof Schmitt 	if (retval == ZFCP_ERP_FAILED)
127185600f7fSChristof Schmitt 		zfcp_erp_strategy_followup_failed(erp_action);
1272287ac01aSChristof Schmitt 
1273287ac01aSChristof Schmitt  unlock:
1274287ac01aSChristof Schmitt 	write_unlock(&adapter->erp_lock);
1275287ac01aSChristof Schmitt 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
1276287ac01aSChristof Schmitt 
1277287ac01aSChristof Schmitt 	if (retval != ZFCP_ERP_CONTINUES)
1278287ac01aSChristof Schmitt 		zfcp_erp_action_cleanup(erp_action, retval);
1279287ac01aSChristof Schmitt 
1280287ac01aSChristof Schmitt 	return retval;
1281287ac01aSChristof Schmitt }
1282287ac01aSChristof Schmitt 
1283287ac01aSChristof Schmitt static int zfcp_erp_thread(void *data)
1284287ac01aSChristof Schmitt {
1285287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
1286287ac01aSChristof Schmitt 	struct list_head *next;
1287287ac01aSChristof Schmitt 	struct zfcp_erp_action *act;
1288287ac01aSChristof Schmitt 	unsigned long flags;
128906499facSHeiko Carstens 	int ignore;
1290287ac01aSChristof Schmitt 
1291b9d3aed7SCornelia Huck 	daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev));
1292287ac01aSChristof Schmitt 	/* Block all signals */
1293287ac01aSChristof Schmitt 	siginitsetinv(&current->blocked, 0);
1294287ac01aSChristof Schmitt 	atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
1295287ac01aSChristof Schmitt 	wake_up(&adapter->erp_thread_wqh);
1296287ac01aSChristof Schmitt 
1297287ac01aSChristof Schmitt 	while (!(atomic_read(&adapter->status) &
1298287ac01aSChristof Schmitt 		 ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) {
129994ab4b38SSwen Schillig 
130094ab4b38SSwen Schillig 		zfcp_rec_dbf_event_thread_lock("erthrd1", adapter);
130194ab4b38SSwen Schillig 		ignore = down_interruptible(&adapter->erp_ready_sem);
130294ab4b38SSwen Schillig 		zfcp_rec_dbf_event_thread_lock("erthrd2", adapter);
130394ab4b38SSwen Schillig 
1304287ac01aSChristof Schmitt 		write_lock_irqsave(&adapter->erp_lock, flags);
1305287ac01aSChristof Schmitt 		next = adapter->erp_ready_head.next;
1306287ac01aSChristof Schmitt 		write_unlock_irqrestore(&adapter->erp_lock, flags);
1307287ac01aSChristof Schmitt 
1308287ac01aSChristof Schmitt 		if (next != &adapter->erp_ready_head) {
1309287ac01aSChristof Schmitt 			act = list_entry(next, struct zfcp_erp_action, list);
1310287ac01aSChristof Schmitt 
1311287ac01aSChristof Schmitt 			/* there is more to come after dismission, no notify */
1312287ac01aSChristof Schmitt 			if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED)
1313287ac01aSChristof Schmitt 				zfcp_erp_wakeup(adapter);
1314287ac01aSChristof Schmitt 		}
1315287ac01aSChristof Schmitt 	}
1316287ac01aSChristof Schmitt 
1317287ac01aSChristof Schmitt 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
1318287ac01aSChristof Schmitt 	wake_up(&adapter->erp_thread_wqh);
1319287ac01aSChristof Schmitt 
1320287ac01aSChristof Schmitt 	return 0;
1321287ac01aSChristof Schmitt }
1322287ac01aSChristof Schmitt 
1323287ac01aSChristof Schmitt /**
1324287ac01aSChristof Schmitt  * zfcp_erp_thread_setup - Start ERP thread for adapter
1325287ac01aSChristof Schmitt  * @adapter: Adapter to start the ERP thread for
1326287ac01aSChristof Schmitt  *
1327287ac01aSChristof Schmitt  * Returns 0 on success or error code from kernel_thread()
1328287ac01aSChristof Schmitt  */
1329287ac01aSChristof Schmitt int zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
1330287ac01aSChristof Schmitt {
1331287ac01aSChristof Schmitt 	int retval;
1332287ac01aSChristof Schmitt 
1333287ac01aSChristof Schmitt 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
1334287ac01aSChristof Schmitt 	retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD);
1335287ac01aSChristof Schmitt 	if (retval < 0) {
1336287ac01aSChristof Schmitt 		dev_err(&adapter->ccw_device->dev,
1337ff3b24faSChristof Schmitt 			"Creating an ERP thread for the FCP device failed.\n");
1338287ac01aSChristof Schmitt 		return retval;
1339287ac01aSChristof Schmitt 	}
1340287ac01aSChristof Schmitt 	wait_event(adapter->erp_thread_wqh,
1341287ac01aSChristof Schmitt 		   atomic_read(&adapter->status) &
1342287ac01aSChristof Schmitt 			ZFCP_STATUS_ADAPTER_ERP_THREAD_UP);
1343287ac01aSChristof Schmitt 	return 0;
1344287ac01aSChristof Schmitt }
1345287ac01aSChristof Schmitt 
1346287ac01aSChristof Schmitt /**
1347287ac01aSChristof Schmitt  * zfcp_erp_thread_kill - Stop ERP thread.
1348287ac01aSChristof Schmitt  * @adapter: Adapter where the ERP thread should be stopped.
1349287ac01aSChristof Schmitt  *
1350287ac01aSChristof Schmitt  * The caller of this routine ensures that the specified adapter has
1351287ac01aSChristof Schmitt  * been shut down and that this operation has been completed. Thus,
1352287ac01aSChristof Schmitt  * there are no pending erp_actions which would need to be handled
1353287ac01aSChristof Schmitt  * here.
1354287ac01aSChristof Schmitt  */
1355287ac01aSChristof Schmitt void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
1356287ac01aSChristof Schmitt {
1357287ac01aSChristof Schmitt 	atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status);
1358287ac01aSChristof Schmitt 	up(&adapter->erp_ready_sem);
13595ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_thread_lock("erthrk1", adapter);
1360287ac01aSChristof Schmitt 
1361287ac01aSChristof Schmitt 	wait_event(adapter->erp_thread_wqh,
1362287ac01aSChristof Schmitt 		   !(atomic_read(&adapter->status) &
1363287ac01aSChristof Schmitt 				ZFCP_STATUS_ADAPTER_ERP_THREAD_UP));
1364287ac01aSChristof Schmitt 
1365287ac01aSChristof Schmitt 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL,
1366287ac01aSChristof Schmitt 			  &adapter->status);
1367287ac01aSChristof Schmitt }
1368287ac01aSChristof Schmitt 
1369287ac01aSChristof Schmitt /**
1370287ac01aSChristof Schmitt  * zfcp_erp_adapter_failed - Set adapter status to failed.
1371287ac01aSChristof Schmitt  * @adapter: Failed adapter.
1372287ac01aSChristof Schmitt  * @id: Event id for debug trace.
1373287ac01aSChristof Schmitt  * @ref: Reference for debug trace.
1374287ac01aSChristof Schmitt  */
13755ffd51a5SSwen Schillig void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, char *id, void *ref)
1376287ac01aSChristof Schmitt {
1377287ac01aSChristof Schmitt 	zfcp_erp_modify_adapter_status(adapter, id, ref,
1378287ac01aSChristof Schmitt 				       ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
1379287ac01aSChristof Schmitt }
1380287ac01aSChristof Schmitt 
1381287ac01aSChristof Schmitt /**
1382287ac01aSChristof Schmitt  * zfcp_erp_port_failed - Set port status to failed.
1383287ac01aSChristof Schmitt  * @port: Failed port.
1384287ac01aSChristof Schmitt  * @id: Event id for debug trace.
1385287ac01aSChristof Schmitt  * @ref: Reference for debug trace.
1386287ac01aSChristof Schmitt  */
13875ffd51a5SSwen Schillig void zfcp_erp_port_failed(struct zfcp_port *port, char *id, void *ref)
1388287ac01aSChristof Schmitt {
1389287ac01aSChristof Schmitt 	zfcp_erp_modify_port_status(port, id, ref,
1390287ac01aSChristof Schmitt 				    ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
1391287ac01aSChristof Schmitt }
1392287ac01aSChristof Schmitt 
1393287ac01aSChristof Schmitt /**
1394287ac01aSChristof Schmitt  * zfcp_erp_unit_failed - Set unit status to failed.
1395287ac01aSChristof Schmitt  * @unit: Failed unit.
1396287ac01aSChristof Schmitt  * @id: Event id for debug trace.
1397287ac01aSChristof Schmitt  * @ref: Reference for debug trace.
1398287ac01aSChristof Schmitt  */
13995ffd51a5SSwen Schillig void zfcp_erp_unit_failed(struct zfcp_unit *unit, char *id, void *ref)
1400287ac01aSChristof Schmitt {
1401287ac01aSChristof Schmitt 	zfcp_erp_modify_unit_status(unit, id, ref,
1402287ac01aSChristof Schmitt 				    ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
1403287ac01aSChristof Schmitt }
1404287ac01aSChristof Schmitt 
1405287ac01aSChristof Schmitt /**
1406287ac01aSChristof Schmitt  * zfcp_erp_wait - wait for completion of error recovery on an adapter
1407287ac01aSChristof Schmitt  * @adapter: adapter for which to wait for completion of its error recovery
1408287ac01aSChristof Schmitt  */
1409287ac01aSChristof Schmitt void zfcp_erp_wait(struct zfcp_adapter *adapter)
1410287ac01aSChristof Schmitt {
1411287ac01aSChristof Schmitt 	wait_event(adapter->erp_done_wqh,
1412287ac01aSChristof Schmitt 		   !(atomic_read(&adapter->status) &
1413287ac01aSChristof Schmitt 			ZFCP_STATUS_ADAPTER_ERP_PENDING));
1414287ac01aSChristof Schmitt }
1415287ac01aSChristof Schmitt 
1416287ac01aSChristof Schmitt /**
1417287ac01aSChristof Schmitt  * zfcp_erp_modify_adapter_status - change adapter status bits
1418287ac01aSChristof Schmitt  * @adapter: adapter to change the status
1419287ac01aSChristof Schmitt  * @id: id for the debug trace
1420287ac01aSChristof Schmitt  * @ref: reference for the debug trace
1421287ac01aSChristof Schmitt  * @mask: status bits to change
1422287ac01aSChristof Schmitt  * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1423287ac01aSChristof Schmitt  *
1424287ac01aSChristof Schmitt  * Changes in common status bits are propagated to attached ports and units.
1425287ac01aSChristof Schmitt  */
14265ffd51a5SSwen Schillig void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id,
1427287ac01aSChristof Schmitt 				    void *ref, u32 mask, int set_or_clear)
14281da177e4SLinus Torvalds {
14291da177e4SLinus Torvalds 	struct zfcp_port *port;
1430287ac01aSChristof Schmitt 	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
14311da177e4SLinus Torvalds 
1432287ac01aSChristof Schmitt 	if (set_or_clear == ZFCP_SET) {
1433287ac01aSChristof Schmitt 		if (status_change_set(mask, &adapter->status))
1434287ac01aSChristof Schmitt 			zfcp_rec_dbf_event_adapter(id, ref, adapter);
1435287ac01aSChristof Schmitt 		atomic_set_mask(mask, &adapter->status);
1436287ac01aSChristof Schmitt 	} else {
1437287ac01aSChristof Schmitt 		if (status_change_clear(mask, &adapter->status))
1438287ac01aSChristof Schmitt 			zfcp_rec_dbf_event_adapter(id, ref, adapter);
1439287ac01aSChristof Schmitt 		atomic_clear_mask(mask, &adapter->status);
1440287ac01aSChristof Schmitt 		if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
1441287ac01aSChristof Schmitt 			atomic_set(&adapter->erp_counter, 0);
14421da177e4SLinus Torvalds 	}
14431da177e4SLinus Torvalds 
1444287ac01aSChristof Schmitt 	if (common_mask)
1445287ac01aSChristof Schmitt 		list_for_each_entry(port, &adapter->port_list_head, list)
1446287ac01aSChristof Schmitt 			zfcp_erp_modify_port_status(port, id, ref, common_mask,
1447287ac01aSChristof Schmitt 						    set_or_clear);
1448287ac01aSChristof Schmitt }
1449287ac01aSChristof Schmitt 
1450287ac01aSChristof Schmitt /**
1451287ac01aSChristof Schmitt  * zfcp_erp_modify_port_status - change port status bits
1452287ac01aSChristof Schmitt  * @port: port to change the status bits
1453287ac01aSChristof Schmitt  * @id: id for the debug trace
1454287ac01aSChristof Schmitt  * @ref: reference for the debug trace
1455287ac01aSChristof Schmitt  * @mask: status bits to change
1456287ac01aSChristof Schmitt  * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1457287ac01aSChristof Schmitt  *
1458287ac01aSChristof Schmitt  * Changes in common status bits are propagated to attached units.
1459287ac01aSChristof Schmitt  */
14605ffd51a5SSwen Schillig void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref,
1461287ac01aSChristof Schmitt 				 u32 mask, int set_or_clear)
14621da177e4SLinus Torvalds {
14631da177e4SLinus Torvalds 	struct zfcp_unit *unit;
1464287ac01aSChristof Schmitt 	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
14651da177e4SLinus Torvalds 
1466287ac01aSChristof Schmitt 	if (set_or_clear == ZFCP_SET) {
1467287ac01aSChristof Schmitt 		if (status_change_set(mask, &port->status))
1468287ac01aSChristof Schmitt 			zfcp_rec_dbf_event_port(id, ref, port);
1469287ac01aSChristof Schmitt 		atomic_set_mask(mask, &port->status);
1470287ac01aSChristof Schmitt 	} else {
1471287ac01aSChristof Schmitt 		if (status_change_clear(mask, &port->status))
1472287ac01aSChristof Schmitt 			zfcp_rec_dbf_event_port(id, ref, port);
1473287ac01aSChristof Schmitt 		atomic_clear_mask(mask, &port->status);
1474287ac01aSChristof Schmitt 		if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
1475287ac01aSChristof Schmitt 			atomic_set(&port->erp_counter, 0);
1476287ac01aSChristof Schmitt 	}
1477287ac01aSChristof Schmitt 
1478287ac01aSChristof Schmitt 	if (common_mask)
14791da177e4SLinus Torvalds 		list_for_each_entry(unit, &port->unit_list_head, list)
1480287ac01aSChristof Schmitt 			zfcp_erp_modify_unit_status(unit, id, ref, common_mask,
1481287ac01aSChristof Schmitt 						    set_or_clear);
14821da177e4SLinus Torvalds }
14831da177e4SLinus Torvalds 
1484287ac01aSChristof Schmitt /**
1485287ac01aSChristof Schmitt  * zfcp_erp_modify_unit_status - change unit status bits
1486287ac01aSChristof Schmitt  * @unit: unit to change the status bits
1487287ac01aSChristof Schmitt  * @id: id for the debug trace
1488287ac01aSChristof Schmitt  * @ref: reference for the debug trace
1489287ac01aSChristof Schmitt  * @mask: status bits to change
1490287ac01aSChristof Schmitt  * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1491287ac01aSChristof Schmitt  */
14925ffd51a5SSwen Schillig void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref,
1493287ac01aSChristof Schmitt 				 u32 mask, int set_or_clear)
14941da177e4SLinus Torvalds {
1495287ac01aSChristof Schmitt 	if (set_or_clear == ZFCP_SET) {
1496287ac01aSChristof Schmitt 		if (status_change_set(mask, &unit->status))
1497287ac01aSChristof Schmitt 			zfcp_rec_dbf_event_unit(id, ref, unit);
1498287ac01aSChristof Schmitt 		atomic_set_mask(mask, &unit->status);
1499287ac01aSChristof Schmitt 	} else {
1500287ac01aSChristof Schmitt 		if (status_change_clear(mask, &unit->status))
1501287ac01aSChristof Schmitt 			zfcp_rec_dbf_event_unit(id, ref, unit);
1502287ac01aSChristof Schmitt 		atomic_clear_mask(mask, &unit->status);
1503287ac01aSChristof Schmitt 		if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) {
1504287ac01aSChristof Schmitt 			atomic_set(&unit->erp_counter, 0);
1505287ac01aSChristof Schmitt 		}
1506287ac01aSChristof Schmitt 	}
15071da177e4SLinus Torvalds }
15081da177e4SLinus Torvalds 
1509287ac01aSChristof Schmitt /**
1510287ac01aSChristof Schmitt  * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP
1511287ac01aSChristof Schmitt  * @port: The "boxed" port.
1512287ac01aSChristof Schmitt  * @id: The debug trace id.
1513287ac01aSChristof Schmitt  * @id: Reference for the debug trace.
1514287ac01aSChristof Schmitt  */
15155ffd51a5SSwen Schillig void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref)
1516d736a27bSAndreas Herrmann {
1517d736a27bSAndreas Herrmann 	unsigned long flags;
1518d736a27bSAndreas Herrmann 
1519d736a27bSAndreas Herrmann 	read_lock_irqsave(&zfcp_data.config_lock, flags);
1520698ec016SMartin Peschke 	zfcp_erp_modify_port_status(port, id, ref,
1521698ec016SMartin Peschke 				    ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
1522d736a27bSAndreas Herrmann 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
15239467a9b3SMartin Peschke 	zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
1524d736a27bSAndreas Herrmann }
1525d736a27bSAndreas Herrmann 
1526287ac01aSChristof Schmitt /**
1527287ac01aSChristof Schmitt  * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP
1528287ac01aSChristof Schmitt  * @port: The "boxed" unit.
1529287ac01aSChristof Schmitt  * @id: The debug trace id.
1530287ac01aSChristof Schmitt  * @id: Reference for the debug trace.
1531287ac01aSChristof Schmitt  */
15325ffd51a5SSwen Schillig void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref)
1533d736a27bSAndreas Herrmann {
1534698ec016SMartin Peschke 	zfcp_erp_modify_unit_status(unit, id, ref,
1535698ec016SMartin Peschke 				    ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
15369467a9b3SMartin Peschke 	zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
1537d736a27bSAndreas Herrmann }
1538d736a27bSAndreas Herrmann 
1539287ac01aSChristof Schmitt /**
1540287ac01aSChristof Schmitt  * zfcp_erp_port_access_denied - Adapter denied access to port.
1541287ac01aSChristof Schmitt  * @port: port where access has been denied
1542287ac01aSChristof Schmitt  * @id: id for debug trace
1543287ac01aSChristof Schmitt  * @ref: reference for debug trace
1544287ac01aSChristof Schmitt  *
1545287ac01aSChristof Schmitt  * Since the adapter has denied access, stop using the port and the
1546287ac01aSChristof Schmitt  * attached units.
1547287ac01aSChristof Schmitt  */
15485ffd51a5SSwen Schillig void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref)
15491da177e4SLinus Torvalds {
15501da177e4SLinus Torvalds 	unsigned long flags;
15511da177e4SLinus Torvalds 
15521da177e4SLinus Torvalds 	read_lock_irqsave(&zfcp_data.config_lock, flags);
1553698ec016SMartin Peschke 	zfcp_erp_modify_port_status(port, id, ref,
1554d736a27bSAndreas Herrmann 				    ZFCP_STATUS_COMMON_ERP_FAILED |
1555698ec016SMartin Peschke 				    ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
15561da177e4SLinus Torvalds 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
15571da177e4SLinus Torvalds }
15581da177e4SLinus Torvalds 
1559287ac01aSChristof Schmitt /**
1560287ac01aSChristof Schmitt  * zfcp_erp_unit_access_denied - Adapter denied access to unit.
1561287ac01aSChristof Schmitt  * @unit: unit where access has been denied
1562287ac01aSChristof Schmitt  * @id: id for debug trace
1563287ac01aSChristof Schmitt  * @ref: reference for debug trace
1564287ac01aSChristof Schmitt  *
1565287ac01aSChristof Schmitt  * Since the adapter has denied access, stop using the unit.
1566287ac01aSChristof Schmitt  */
15675ffd51a5SSwen Schillig void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, char *id, void *ref)
15681da177e4SLinus Torvalds {
1569698ec016SMartin Peschke 	zfcp_erp_modify_unit_status(unit, id, ref,
1570d736a27bSAndreas Herrmann 				    ZFCP_STATUS_COMMON_ERP_FAILED |
1571698ec016SMartin Peschke 				    ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
15721da177e4SLinus Torvalds }
15731da177e4SLinus Torvalds 
15745ffd51a5SSwen Schillig static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, char *id,
1575287ac01aSChristof Schmitt 					 void *ref)
1576287ac01aSChristof Schmitt {
1577287ac01aSChristof Schmitt 	int status = atomic_read(&unit->status);
1578287ac01aSChristof Schmitt 	if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
1579287ac01aSChristof Schmitt 			ZFCP_STATUS_COMMON_ACCESS_BOXED)))
1580287ac01aSChristof Schmitt 		return;
1581287ac01aSChristof Schmitt 
1582287ac01aSChristof Schmitt 	zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
1583287ac01aSChristof Schmitt }
1584287ac01aSChristof Schmitt 
15855ffd51a5SSwen Schillig static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id,
1586287ac01aSChristof Schmitt 					 void *ref)
1587287ac01aSChristof Schmitt {
1588287ac01aSChristof Schmitt 	struct zfcp_unit *unit;
1589287ac01aSChristof Schmitt 	int status = atomic_read(&port->status);
1590287ac01aSChristof Schmitt 
1591287ac01aSChristof Schmitt 	if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
1592287ac01aSChristof Schmitt 			ZFCP_STATUS_COMMON_ACCESS_BOXED))) {
1593287ac01aSChristof Schmitt 		list_for_each_entry(unit, &port->unit_list_head, list)
1594287ac01aSChristof Schmitt 				    zfcp_erp_unit_access_changed(unit, id, ref);
1595287ac01aSChristof Schmitt 		return;
1596287ac01aSChristof Schmitt 	}
1597287ac01aSChristof Schmitt 
1598287ac01aSChristof Schmitt 	zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
1599287ac01aSChristof Schmitt }
1600287ac01aSChristof Schmitt 
1601287ac01aSChristof Schmitt /**
1602287ac01aSChristof Schmitt  * zfcp_erp_adapter_access_changed - Process change in adapter ACT
1603287ac01aSChristof Schmitt  * @adapter: Adapter where the Access Control Table (ACT) changed
1604287ac01aSChristof Schmitt  * @id: Id for debug trace
1605287ac01aSChristof Schmitt  * @ref: Reference for debug trace
1606287ac01aSChristof Schmitt  */
16075ffd51a5SSwen Schillig void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id,
16081f6f7129SMartin Peschke 				     void *ref)
16091da177e4SLinus Torvalds {
16101da177e4SLinus Torvalds 	struct zfcp_port *port;
16111da177e4SLinus Torvalds 	unsigned long flags;
16121da177e4SLinus Torvalds 
1613aef4a983SMaxim Shchetynin 	if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
1614aef4a983SMaxim Shchetynin 		return;
1615aef4a983SMaxim Shchetynin 
16161da177e4SLinus Torvalds 	read_lock_irqsave(&zfcp_data.config_lock, flags);
16171da177e4SLinus Torvalds 	list_for_each_entry(port, &adapter->port_list_head, list)
16189467a9b3SMartin Peschke 		zfcp_erp_port_access_changed(port, id, ref);
16191da177e4SLinus Torvalds 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
16201da177e4SLinus Torvalds }
1621