xref: /openbmc/linux/drivers/s390/scsi/zfcp_erp.c (revision ea460a81)
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_NAMESERVER_LOOKUP	= 0x0400,
30287ac01aSChristof Schmitt 	ZFCP_ERP_STEP_PORT_OPENING	= 0x0800,
31287ac01aSChristof Schmitt 	ZFCP_ERP_STEP_UNIT_CLOSING	= 0x1000,
32287ac01aSChristof Schmitt 	ZFCP_ERP_STEP_UNIT_OPENING	= 0x2000,
33287ac01aSChristof Schmitt };
341da177e4SLinus Torvalds 
35287ac01aSChristof Schmitt enum zfcp_erp_act_type {
36287ac01aSChristof Schmitt 	ZFCP_ERP_ACTION_REOPEN_UNIT        = 1,
37287ac01aSChristof Schmitt 	ZFCP_ERP_ACTION_REOPEN_PORT	   = 2,
38287ac01aSChristof Schmitt 	ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3,
39287ac01aSChristof Schmitt 	ZFCP_ERP_ACTION_REOPEN_ADAPTER     = 4,
40287ac01aSChristof Schmitt };
411da177e4SLinus Torvalds 
42287ac01aSChristof Schmitt enum zfcp_erp_act_state {
43287ac01aSChristof Schmitt 	ZFCP_ERP_ACTION_RUNNING = 1,
44287ac01aSChristof Schmitt 	ZFCP_ERP_ACTION_READY   = 2,
45287ac01aSChristof Schmitt };
461da177e4SLinus Torvalds 
47287ac01aSChristof Schmitt enum zfcp_erp_act_result {
48287ac01aSChristof Schmitt 	ZFCP_ERP_SUCCEEDED = 0,
49287ac01aSChristof Schmitt 	ZFCP_ERP_FAILED    = 1,
50287ac01aSChristof Schmitt 	ZFCP_ERP_CONTINUES = 2,
51287ac01aSChristof Schmitt 	ZFCP_ERP_EXIT      = 3,
52287ac01aSChristof Schmitt 	ZFCP_ERP_DISMISSED = 4,
53287ac01aSChristof Schmitt 	ZFCP_ERP_NOMEM     = 5,
54287ac01aSChristof Schmitt };
551da177e4SLinus Torvalds 
56287ac01aSChristof Schmitt static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask)
572abbe866SAndreas Herrmann {
585ffd51a5SSwen Schillig 	zfcp_erp_modify_adapter_status(adapter, "erablk1", NULL,
59287ac01aSChristof Schmitt 				       ZFCP_STATUS_COMMON_UNBLOCKED | mask,
60287ac01aSChristof Schmitt 				       ZFCP_CLEAR);
612abbe866SAndreas Herrmann }
621da177e4SLinus Torvalds 
63287ac01aSChristof Schmitt static int zfcp_erp_action_exists(struct zfcp_erp_action *act)
641da177e4SLinus Torvalds {
65287ac01aSChristof Schmitt 	struct zfcp_erp_action *curr_act;
66287ac01aSChristof Schmitt 
67287ac01aSChristof Schmitt 	list_for_each_entry(curr_act, &act->adapter->erp_running_head, list)
68287ac01aSChristof Schmitt 		if (act == curr_act)
69287ac01aSChristof Schmitt 			return ZFCP_ERP_ACTION_RUNNING;
70287ac01aSChristof Schmitt 	return 0;
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds 
73287ac01aSChristof Schmitt static void zfcp_erp_action_ready(struct zfcp_erp_action *act)
741da177e4SLinus Torvalds {
75287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
76287ac01aSChristof Schmitt 
77287ac01aSChristof Schmitt 	list_move(&act->list, &act->adapter->erp_ready_head);
785ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_action("erardy1", act);
79287ac01aSChristof Schmitt 	up(&adapter->erp_ready_sem);
805ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_thread("erardy2", adapter);
811da177e4SLinus Torvalds }
821da177e4SLinus Torvalds 
83287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
84287ac01aSChristof Schmitt {
85287ac01aSChristof Schmitt 	act->status |= ZFCP_STATUS_ERP_DISMISSED;
86287ac01aSChristof Schmitt 	if (zfcp_erp_action_exists(act) == ZFCP_ERP_ACTION_RUNNING)
87287ac01aSChristof Schmitt 		zfcp_erp_action_ready(act);
88287ac01aSChristof Schmitt }
89287ac01aSChristof Schmitt 
90287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
91287ac01aSChristof Schmitt {
92287ac01aSChristof Schmitt 	if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
93287ac01aSChristof Schmitt 		zfcp_erp_action_dismiss(&unit->erp_action);
94287ac01aSChristof Schmitt }
95287ac01aSChristof Schmitt 
96287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
97287ac01aSChristof Schmitt {
98287ac01aSChristof Schmitt 	struct zfcp_unit *unit;
99287ac01aSChristof Schmitt 
100287ac01aSChristof Schmitt 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
101287ac01aSChristof Schmitt 		zfcp_erp_action_dismiss(&port->erp_action);
102287ac01aSChristof Schmitt 	else
103287ac01aSChristof Schmitt 		list_for_each_entry(unit, &port->unit_list_head, list)
104287ac01aSChristof Schmitt 		    zfcp_erp_action_dismiss_unit(unit);
105287ac01aSChristof Schmitt }
106287ac01aSChristof Schmitt 
107287ac01aSChristof Schmitt static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
108287ac01aSChristof Schmitt {
109287ac01aSChristof Schmitt 	struct zfcp_port *port;
110287ac01aSChristof Schmitt 
111287ac01aSChristof Schmitt 	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
112287ac01aSChristof Schmitt 		zfcp_erp_action_dismiss(&adapter->erp_action);
113287ac01aSChristof Schmitt 	else
114287ac01aSChristof Schmitt 		list_for_each_entry(port, &adapter->port_list_head, list)
115287ac01aSChristof Schmitt 		    zfcp_erp_action_dismiss_port(port);
116287ac01aSChristof Schmitt }
117287ac01aSChristof Schmitt 
118287ac01aSChristof Schmitt static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
119287ac01aSChristof Schmitt 				 struct zfcp_port *port,
120287ac01aSChristof Schmitt 				 struct zfcp_unit *unit)
121287ac01aSChristof Schmitt {
122287ac01aSChristof Schmitt 	int need = want;
123287ac01aSChristof Schmitt 	int u_status, p_status, a_status;
124287ac01aSChristof Schmitt 
125287ac01aSChristof Schmitt 	switch (want) {
126287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
127287ac01aSChristof Schmitt 		u_status = atomic_read(&unit->status);
128287ac01aSChristof Schmitt 		if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE)
129287ac01aSChristof Schmitt 			return 0;
130287ac01aSChristof Schmitt 		p_status = atomic_read(&port->status);
131287ac01aSChristof Schmitt 		if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) ||
132287ac01aSChristof Schmitt 		      p_status & ZFCP_STATUS_COMMON_ERP_FAILED)
133287ac01aSChristof Schmitt 			return 0;
134287ac01aSChristof Schmitt 		if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
135287ac01aSChristof Schmitt 			need = ZFCP_ERP_ACTION_REOPEN_PORT;
136287ac01aSChristof Schmitt 		/* fall through */
137287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
138287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
139287ac01aSChristof Schmitt 		p_status = atomic_read(&port->status);
140287ac01aSChristof Schmitt 		if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
141287ac01aSChristof Schmitt 			return 0;
142287ac01aSChristof Schmitt 		a_status = atomic_read(&adapter->status);
143287ac01aSChristof Schmitt 		if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) ||
144287ac01aSChristof Schmitt 		      a_status & ZFCP_STATUS_COMMON_ERP_FAILED)
145287ac01aSChristof Schmitt 			return 0;
146287ac01aSChristof Schmitt 		if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))
147287ac01aSChristof Schmitt 			need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
148287ac01aSChristof Schmitt 		/* fall through */
149287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
150287ac01aSChristof Schmitt 		a_status = atomic_read(&adapter->status);
151287ac01aSChristof Schmitt 		if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
152287ac01aSChristof Schmitt 			return 0;
153287ac01aSChristof Schmitt 	}
154287ac01aSChristof Schmitt 
155287ac01aSChristof Schmitt 	return need;
156287ac01aSChristof Schmitt }
157287ac01aSChristof Schmitt 
158287ac01aSChristof Schmitt static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
159287ac01aSChristof Schmitt 						  struct zfcp_adapter *adapter,
160287ac01aSChristof Schmitt 						  struct zfcp_port *port,
161287ac01aSChristof Schmitt 						  struct zfcp_unit *unit)
162287ac01aSChristof Schmitt {
163287ac01aSChristof Schmitt 	struct zfcp_erp_action *erp_action;
164287ac01aSChristof Schmitt 	u32 status = 0;
165287ac01aSChristof Schmitt 
166287ac01aSChristof Schmitt 	switch (need) {
167287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
168287ac01aSChristof Schmitt 		zfcp_unit_get(unit);
169287ac01aSChristof Schmitt 		atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status);
170287ac01aSChristof Schmitt 		erp_action = &unit->erp_action;
171287ac01aSChristof Schmitt 		if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING))
172287ac01aSChristof Schmitt 			status = ZFCP_STATUS_ERP_CLOSE_ONLY;
173287ac01aSChristof Schmitt 		break;
174287ac01aSChristof Schmitt 
175287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
176287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
177287ac01aSChristof Schmitt 		zfcp_port_get(port);
178287ac01aSChristof Schmitt 		zfcp_erp_action_dismiss_port(port);
179287ac01aSChristof Schmitt 		atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
180287ac01aSChristof Schmitt 		erp_action = &port->erp_action;
181287ac01aSChristof Schmitt 		if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
182287ac01aSChristof Schmitt 			status = ZFCP_STATUS_ERP_CLOSE_ONLY;
183287ac01aSChristof Schmitt 		break;
184287ac01aSChristof Schmitt 
185287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
186287ac01aSChristof Schmitt 		zfcp_adapter_get(adapter);
187287ac01aSChristof Schmitt 		zfcp_erp_action_dismiss_adapter(adapter);
188287ac01aSChristof Schmitt 		atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
189287ac01aSChristof Schmitt 		erp_action = &adapter->erp_action;
190287ac01aSChristof Schmitt 		if (!(atomic_read(&adapter->status) &
191287ac01aSChristof Schmitt 		      ZFCP_STATUS_COMMON_RUNNING))
192287ac01aSChristof Schmitt 			status = ZFCP_STATUS_ERP_CLOSE_ONLY;
193287ac01aSChristof Schmitt 		break;
194287ac01aSChristof Schmitt 
195287ac01aSChristof Schmitt 	default:
196287ac01aSChristof Schmitt 		return NULL;
197287ac01aSChristof Schmitt 	}
198287ac01aSChristof Schmitt 
199287ac01aSChristof Schmitt 	memset(erp_action, 0, sizeof(struct zfcp_erp_action));
200287ac01aSChristof Schmitt 	erp_action->adapter = adapter;
201287ac01aSChristof Schmitt 	erp_action->port = port;
202287ac01aSChristof Schmitt 	erp_action->unit = unit;
203287ac01aSChristof Schmitt 	erp_action->action = need;
204287ac01aSChristof Schmitt 	erp_action->status = status;
205287ac01aSChristof Schmitt 
206287ac01aSChristof Schmitt 	return erp_action;
207287ac01aSChristof Schmitt }
208287ac01aSChristof Schmitt 
209287ac01aSChristof Schmitt static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
210287ac01aSChristof Schmitt 				   struct zfcp_port *port,
2115ffd51a5SSwen Schillig 				   struct zfcp_unit *unit, char *id, void *ref)
212287ac01aSChristof Schmitt {
213287ac01aSChristof Schmitt 	int retval = 1, need;
214287ac01aSChristof Schmitt 	struct zfcp_erp_action *act = NULL;
215287ac01aSChristof Schmitt 
216287ac01aSChristof Schmitt 	if (!(atomic_read(&adapter->status) &
217287ac01aSChristof Schmitt 	      ZFCP_STATUS_ADAPTER_ERP_THREAD_UP))
218287ac01aSChristof Schmitt 		return -EIO;
219287ac01aSChristof Schmitt 
220287ac01aSChristof Schmitt 	need = zfcp_erp_required_act(want, adapter, port, unit);
221287ac01aSChristof Schmitt 	if (!need)
222287ac01aSChristof Schmitt 		goto out;
223287ac01aSChristof Schmitt 
224287ac01aSChristof Schmitt 	atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
225287ac01aSChristof Schmitt 	act = zfcp_erp_setup_act(need, adapter, port, unit);
226287ac01aSChristof Schmitt 	if (!act)
227287ac01aSChristof Schmitt 		goto out;
228287ac01aSChristof Schmitt 	++adapter->erp_total_count;
229287ac01aSChristof Schmitt 	list_add_tail(&act->list, &adapter->erp_ready_head);
230287ac01aSChristof Schmitt 	up(&adapter->erp_ready_sem);
2315ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_thread("eracte1", adapter);
232287ac01aSChristof Schmitt 	retval = 0;
233287ac01aSChristof Schmitt  out:
234287ac01aSChristof Schmitt 	zfcp_rec_dbf_event_trigger(id, ref, want, need, act,
235287ac01aSChristof Schmitt 				   adapter, port, unit);
236287ac01aSChristof Schmitt 	return retval;
237287ac01aSChristof Schmitt }
238287ac01aSChristof Schmitt 
239287ac01aSChristof Schmitt static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
2405ffd51a5SSwen Schillig 				    int clear_mask, char *id, void *ref)
2411da177e4SLinus Torvalds {
2421da177e4SLinus Torvalds 	zfcp_erp_adapter_block(adapter, clear_mask);
243a2fa0aedSChristof Schmitt 	zfcp_scsi_schedule_rports_block(adapter);
2441da177e4SLinus Torvalds 
2451da177e4SLinus Torvalds 	/* ensure propagation of failed status to new devices */
246287ac01aSChristof Schmitt 	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
2475ffd51a5SSwen Schillig 		zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
248287ac01aSChristof Schmitt 		return -EIO;
2491da177e4SLinus Torvalds 	}
250287ac01aSChristof Schmitt 	return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
2519467a9b3SMartin Peschke 				       adapter, NULL, NULL, id, ref);
2521da177e4SLinus Torvalds }
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds /**
255287ac01aSChristof Schmitt  * zfcp_erp_adapter_reopen - Reopen adapter.
256287ac01aSChristof Schmitt  * @adapter: Adapter to reopen.
257287ac01aSChristof Schmitt  * @clear: Status flags to clear.
258287ac01aSChristof Schmitt  * @id: Id for debug trace event.
259287ac01aSChristof Schmitt  * @ref: Reference for debug trace event.
2601da177e4SLinus Torvalds  */
261287ac01aSChristof Schmitt void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
2625ffd51a5SSwen Schillig 			     char *id, void *ref)
263287ac01aSChristof Schmitt {
264287ac01aSChristof Schmitt 	unsigned long flags;
265287ac01aSChristof Schmitt 
266287ac01aSChristof Schmitt 	read_lock_irqsave(&zfcp_data.config_lock, flags);
267287ac01aSChristof Schmitt 	write_lock(&adapter->erp_lock);
268287ac01aSChristof Schmitt 	_zfcp_erp_adapter_reopen(adapter, clear, id, ref);
269287ac01aSChristof Schmitt 	write_unlock(&adapter->erp_lock);
270287ac01aSChristof Schmitt 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
271287ac01aSChristof Schmitt }
272287ac01aSChristof Schmitt 
273287ac01aSChristof Schmitt /**
274287ac01aSChristof Schmitt  * zfcp_erp_adapter_shutdown - Shutdown adapter.
275287ac01aSChristof Schmitt  * @adapter: Adapter to shut down.
276287ac01aSChristof Schmitt  * @clear: Status flags to clear.
277287ac01aSChristof Schmitt  * @id: Id for debug trace event.
278287ac01aSChristof Schmitt  * @ref: Reference for debug trace event.
279287ac01aSChristof Schmitt  */
280287ac01aSChristof Schmitt void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
2815ffd51a5SSwen Schillig 			       char *id, void *ref)
282287ac01aSChristof Schmitt {
283287ac01aSChristof Schmitt 	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
284287ac01aSChristof Schmitt 	zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref);
285287ac01aSChristof Schmitt }
286287ac01aSChristof Schmitt 
287287ac01aSChristof Schmitt /**
288287ac01aSChristof Schmitt  * zfcp_erp_port_shutdown - Shutdown port
289287ac01aSChristof Schmitt  * @port: Port to shut down.
290287ac01aSChristof Schmitt  * @clear: Status flags to clear.
291287ac01aSChristof Schmitt  * @id: Id for debug trace event.
292287ac01aSChristof Schmitt  * @ref: Reference for debug trace event.
293287ac01aSChristof Schmitt  */
2945ffd51a5SSwen Schillig void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id,
2955ffd51a5SSwen Schillig 			    void *ref)
296287ac01aSChristof Schmitt {
297287ac01aSChristof Schmitt 	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
298287ac01aSChristof Schmitt 	zfcp_erp_port_reopen(port, clear | flags, id, ref);
299287ac01aSChristof Schmitt }
300287ac01aSChristof Schmitt 
301287ac01aSChristof Schmitt /**
302287ac01aSChristof Schmitt  * zfcp_erp_unit_shutdown - Shutdown unit
303287ac01aSChristof Schmitt  * @unit: Unit to shut down.
304287ac01aSChristof Schmitt  * @clear: Status flags to clear.
305287ac01aSChristof Schmitt  * @id: Id for debug trace event.
306287ac01aSChristof Schmitt  * @ref: Reference for debug trace event.
307287ac01aSChristof Schmitt  */
3085ffd51a5SSwen Schillig void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, char *id,
3095ffd51a5SSwen Schillig 			    void *ref)
310287ac01aSChristof Schmitt {
311287ac01aSChristof Schmitt 	int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
312287ac01aSChristof Schmitt 	zfcp_erp_unit_reopen(unit, clear | flags, id, ref);
313287ac01aSChristof Schmitt }
314287ac01aSChristof Schmitt 
315287ac01aSChristof Schmitt static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
316287ac01aSChristof Schmitt {
3175ffd51a5SSwen Schillig 	zfcp_erp_modify_port_status(port, "erpblk1", NULL,
318287ac01aSChristof Schmitt 				    ZFCP_STATUS_COMMON_UNBLOCKED | clear,
319287ac01aSChristof Schmitt 				    ZFCP_CLEAR);
320287ac01aSChristof Schmitt }
321287ac01aSChristof Schmitt 
322287ac01aSChristof Schmitt static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
3235ffd51a5SSwen Schillig 					 int clear, char *id, void *ref)
324287ac01aSChristof Schmitt {
325287ac01aSChristof Schmitt 	zfcp_erp_port_block(port, clear);
326a2fa0aedSChristof Schmitt 	zfcp_scsi_schedule_rport_block(port);
327287ac01aSChristof Schmitt 
328287ac01aSChristof Schmitt 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
329287ac01aSChristof Schmitt 		return;
330287ac01aSChristof Schmitt 
331287ac01aSChristof Schmitt 	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
332287ac01aSChristof Schmitt 				port->adapter, port, NULL, id, ref);
333287ac01aSChristof Schmitt }
334287ac01aSChristof Schmitt 
335287ac01aSChristof Schmitt /**
336287ac01aSChristof Schmitt  * zfcp_erp_port_forced_reopen - Forced close of port and open again
337287ac01aSChristof Schmitt  * @port: Port to force close and to reopen.
338287ac01aSChristof Schmitt  * @id: Id for debug trace event.
339287ac01aSChristof Schmitt  * @ref: Reference for debug trace event.
340287ac01aSChristof Schmitt  */
3415ffd51a5SSwen Schillig void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id,
3421f6f7129SMartin Peschke 				 void *ref)
3431da177e4SLinus Torvalds {
3441da177e4SLinus Torvalds 	unsigned long flags;
3451da177e4SLinus Torvalds 	struct zfcp_adapter *adapter = port->adapter;
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds 	read_lock_irqsave(&zfcp_data.config_lock, flags);
3481da177e4SLinus Torvalds 	write_lock(&adapter->erp_lock);
349287ac01aSChristof Schmitt 	_zfcp_erp_port_forced_reopen(port, clear, id, ref);
350287ac01aSChristof Schmitt 	write_unlock(&adapter->erp_lock);
351287ac01aSChristof Schmitt 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
352287ac01aSChristof Schmitt }
353287ac01aSChristof Schmitt 
3545ffd51a5SSwen Schillig static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
355287ac01aSChristof Schmitt 				 void *ref)
356287ac01aSChristof Schmitt {
357287ac01aSChristof Schmitt 	zfcp_erp_port_block(port, clear);
358a2fa0aedSChristof Schmitt 	zfcp_scsi_schedule_rport_block(port);
359287ac01aSChristof Schmitt 
360287ac01aSChristof Schmitt 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
361287ac01aSChristof Schmitt 		/* ensure propagation of failed status to new devices */
3625ffd51a5SSwen Schillig 		zfcp_erp_port_failed(port, "erpreo1", NULL);
363287ac01aSChristof Schmitt 		return -EIO;
364287ac01aSChristof Schmitt 	}
365287ac01aSChristof Schmitt 
366287ac01aSChristof Schmitt 	return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
367287ac01aSChristof Schmitt 				       port->adapter, port, NULL, id, ref);
368287ac01aSChristof Schmitt }
369287ac01aSChristof Schmitt 
370287ac01aSChristof Schmitt /**
371287ac01aSChristof Schmitt  * zfcp_erp_port_reopen - trigger remote port recovery
372287ac01aSChristof Schmitt  * @port: port to recover
373287ac01aSChristof Schmitt  * @clear_mask: flags in port status to be cleared
374287ac01aSChristof Schmitt  *
375287ac01aSChristof Schmitt  * Returns 0 if recovery has been triggered, < 0 if not.
376287ac01aSChristof Schmitt  */
3775ffd51a5SSwen Schillig int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref)
378287ac01aSChristof Schmitt {
379287ac01aSChristof Schmitt 	unsigned long flags;
380287ac01aSChristof Schmitt 	int retval;
381287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = port->adapter;
382287ac01aSChristof Schmitt 
383287ac01aSChristof Schmitt 	read_lock_irqsave(&zfcp_data.config_lock, flags);
384287ac01aSChristof Schmitt 	write_lock(&adapter->erp_lock);
385287ac01aSChristof Schmitt 	retval = _zfcp_erp_port_reopen(port, clear, id, ref);
3861da177e4SLinus Torvalds 	write_unlock(&adapter->erp_lock);
3871da177e4SLinus Torvalds 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds 	return retval;
3901da177e4SLinus Torvalds }
3911da177e4SLinus Torvalds 
392287ac01aSChristof Schmitt static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask)
3931da177e4SLinus Torvalds {
3945ffd51a5SSwen Schillig 	zfcp_erp_modify_unit_status(unit, "erublk1", NULL,
395287ac01aSChristof Schmitt 				    ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask,
396287ac01aSChristof Schmitt 				    ZFCP_CLEAR);
3971da177e4SLinus Torvalds }
3981da177e4SLinus Torvalds 
3995ffd51a5SSwen Schillig static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
400287ac01aSChristof Schmitt 				  void *ref)
401287ac01aSChristof Schmitt {
402287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = unit->port->adapter;
403287ac01aSChristof Schmitt 
404287ac01aSChristof Schmitt 	zfcp_erp_unit_block(unit, clear);
405287ac01aSChristof Schmitt 
406287ac01aSChristof Schmitt 	if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
407287ac01aSChristof Schmitt 		return;
408287ac01aSChristof Schmitt 
409287ac01aSChristof Schmitt 	zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT,
4109467a9b3SMartin Peschke 				adapter, unit->port, unit, id, ref);
4111da177e4SLinus Torvalds }
4121da177e4SLinus Torvalds 
4131da177e4SLinus Torvalds /**
4141da177e4SLinus Torvalds  * zfcp_erp_unit_reopen - initiate reopen of a unit
4151da177e4SLinus Torvalds  * @unit: unit to be reopened
4161da177e4SLinus Torvalds  * @clear_mask: specifies flags in unit status to be cleared
4171da177e4SLinus Torvalds  * Return: 0 on success, < 0 on error
4181da177e4SLinus Torvalds  */
4195ffd51a5SSwen Schillig void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
4205ffd51a5SSwen Schillig 			  void *ref)
4211da177e4SLinus Torvalds {
4221da177e4SLinus Torvalds 	unsigned long flags;
423287ac01aSChristof Schmitt 	struct zfcp_port *port = unit->port;
424287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = port->adapter;
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds 	read_lock_irqsave(&zfcp_data.config_lock, flags);
4271da177e4SLinus Torvalds 	write_lock(&adapter->erp_lock);
428287ac01aSChristof Schmitt 	_zfcp_erp_unit_reopen(unit, clear, id, ref);
4291da177e4SLinus Torvalds 	write_unlock(&adapter->erp_lock);
4301da177e4SLinus Torvalds 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
4311da177e4SLinus Torvalds }
4321da177e4SLinus Torvalds 
433287ac01aSChristof Schmitt static int status_change_set(unsigned long mask, atomic_t *status)
4341da177e4SLinus Torvalds {
435287ac01aSChristof Schmitt 	return (atomic_read(status) ^ mask) & mask;
4361da177e4SLinus Torvalds }
4371da177e4SLinus Torvalds 
438287ac01aSChristof Schmitt static int status_change_clear(unsigned long mask, atomic_t *status)
439698ec016SMartin Peschke {
440287ac01aSChristof Schmitt 	return atomic_read(status) & mask;
441698ec016SMartin Peschke }
442698ec016SMartin Peschke 
443f6c0e7a7SAndreas Herrmann static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
4441da177e4SLinus Torvalds {
445287ac01aSChristof Schmitt 	if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status))
4465ffd51a5SSwen Schillig 		zfcp_rec_dbf_event_adapter("eraubl1", NULL, adapter);
447287ac01aSChristof Schmitt 	atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
4481da177e4SLinus Torvalds }
4491da177e4SLinus Torvalds 
450287ac01aSChristof Schmitt static void zfcp_erp_port_unblock(struct zfcp_port *port)
4511da177e4SLinus Torvalds {
452287ac01aSChristof Schmitt 	if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status))
4535ffd51a5SSwen Schillig 		zfcp_rec_dbf_event_port("erpubl1", NULL, port);
454287ac01aSChristof Schmitt 	atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
4551da177e4SLinus Torvalds }
4561da177e4SLinus Torvalds 
457287ac01aSChristof Schmitt static void zfcp_erp_unit_unblock(struct zfcp_unit *unit)
4581da177e4SLinus Torvalds {
459287ac01aSChristof Schmitt 	if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))
4605ffd51a5SSwen Schillig 		zfcp_rec_dbf_event_unit("eruubl1", NULL, unit);
461287ac01aSChristof Schmitt 	atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status);
4621da177e4SLinus Torvalds }
4631da177e4SLinus Torvalds 
464287ac01aSChristof Schmitt static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
4651da177e4SLinus Torvalds {
466287ac01aSChristof Schmitt 	list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
4675ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_action("erator1", erp_action);
4681da177e4SLinus Torvalds }
4691da177e4SLinus Torvalds 
470287ac01aSChristof Schmitt static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
4711da177e4SLinus Torvalds {
472287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
4731da177e4SLinus Torvalds 
474287ac01aSChristof Schmitt 	if (!act->fsf_req)
475287ac01aSChristof Schmitt 		return;
4761da177e4SLinus Torvalds 
477fea9d6c7SVolker Sameske 	spin_lock(&adapter->req_list_lock);
478287ac01aSChristof Schmitt 	if (zfcp_reqlist_find_safe(adapter, act->fsf_req) &&
479287ac01aSChristof Schmitt 	    act->fsf_req->erp_action == act) {
480287ac01aSChristof Schmitt 		if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
4811da177e4SLinus Torvalds 				   ZFCP_STATUS_ERP_TIMEDOUT)) {
482287ac01aSChristof Schmitt 			act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
4835ffd51a5SSwen Schillig 			zfcp_rec_dbf_event_action("erscf_1", act);
4847ea633ffSMartin Petermann 			act->fsf_req->erp_action = NULL;
4851da177e4SLinus Torvalds 		}
486287ac01aSChristof Schmitt 		if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
4875ffd51a5SSwen Schillig 			zfcp_rec_dbf_event_action("erscf_2", act);
488287ac01aSChristof Schmitt 		if (act->fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED |
489287ac01aSChristof Schmitt 					    ZFCP_STATUS_FSFREQ_DISMISSED))
490287ac01aSChristof Schmitt 			act->fsf_req = NULL;
491287ac01aSChristof Schmitt 	} else
492287ac01aSChristof Schmitt 		act->fsf_req = NULL;
493fea9d6c7SVolker Sameske 	spin_unlock(&adapter->req_list_lock);
494507e4969SMartin Peschke }
4951da177e4SLinus Torvalds 
496f6c0e7a7SAndreas Herrmann /**
497287ac01aSChristof Schmitt  * zfcp_erp_notify - Trigger ERP action.
498287ac01aSChristof Schmitt  * @erp_action: ERP action to continue.
499287ac01aSChristof Schmitt  * @set_mask: ERP action status flags to set.
5001da177e4SLinus Torvalds  */
501287ac01aSChristof Schmitt void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask)
5021da177e4SLinus Torvalds {
503287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = erp_action->adapter;
504287ac01aSChristof Schmitt 	unsigned long flags;
505287ac01aSChristof Schmitt 
506287ac01aSChristof Schmitt 	write_lock_irqsave(&adapter->erp_lock, flags);
5071da177e4SLinus Torvalds 	if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
5081da177e4SLinus Torvalds 		erp_action->status |= set_mask;
5091da177e4SLinus Torvalds 		zfcp_erp_action_ready(erp_action);
510f6c0e7a7SAndreas Herrmann 	}
5111da177e4SLinus Torvalds 	write_unlock_irqrestore(&adapter->erp_lock, flags);
5121da177e4SLinus Torvalds }
5131da177e4SLinus Torvalds 
514f6c0e7a7SAndreas Herrmann /**
515287ac01aSChristof Schmitt  * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request
516287ac01aSChristof Schmitt  * @data: ERP action (from timer data)
5171da177e4SLinus Torvalds  */
518287ac01aSChristof Schmitt void zfcp_erp_timeout_handler(unsigned long data)
5191da177e4SLinus Torvalds {
520287ac01aSChristof Schmitt 	struct zfcp_erp_action *act = (struct zfcp_erp_action *) data;
521287ac01aSChristof Schmitt 	zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT);
5221da177e4SLinus Torvalds }
5231da177e4SLinus Torvalds 
524287ac01aSChristof Schmitt static void zfcp_erp_memwait_handler(unsigned long data)
5251da177e4SLinus Torvalds {
526287ac01aSChristof Schmitt 	zfcp_erp_notify((struct zfcp_erp_action *)data, 0);
5271da177e4SLinus Torvalds }
5281da177e4SLinus Torvalds 
529287ac01aSChristof Schmitt static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
5301da177e4SLinus Torvalds {
5311da177e4SLinus Torvalds 	init_timer(&erp_action->timer);
5321da177e4SLinus Torvalds 	erp_action->timer.function = zfcp_erp_memwait_handler;
5331da177e4SLinus Torvalds 	erp_action->timer.data = (unsigned long) erp_action;
534287ac01aSChristof Schmitt 	erp_action->timer.expires = jiffies + HZ;
5351da177e4SLinus Torvalds 	add_timer(&erp_action->timer);
536287ac01aSChristof Schmitt }
537287ac01aSChristof Schmitt 
538287ac01aSChristof Schmitt static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
5395ffd51a5SSwen Schillig 				      int clear, char *id, void *ref)
540287ac01aSChristof Schmitt {
541287ac01aSChristof Schmitt 	struct zfcp_port *port;
542287ac01aSChristof Schmitt 
543287ac01aSChristof Schmitt 	list_for_each_entry(port, &adapter->port_list_head, list)
544287ac01aSChristof Schmitt 		_zfcp_erp_port_reopen(port, clear, id, ref);
545287ac01aSChristof Schmitt }
546287ac01aSChristof Schmitt 
5475ffd51a5SSwen Schillig static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
5485ffd51a5SSwen Schillig 				      char *id, void *ref)
549287ac01aSChristof Schmitt {
550287ac01aSChristof Schmitt 	struct zfcp_unit *unit;
551287ac01aSChristof Schmitt 
552287ac01aSChristof Schmitt 	list_for_each_entry(unit, &port->unit_list_head, list)
553287ac01aSChristof Schmitt 		_zfcp_erp_unit_reopen(unit, clear, id, ref);
554287ac01aSChristof Schmitt }
555287ac01aSChristof Schmitt 
556287ac01aSChristof Schmitt static void zfcp_erp_strategy_followup_actions(struct zfcp_erp_action *act)
557287ac01aSChristof Schmitt {
558287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
559287ac01aSChristof Schmitt 	struct zfcp_port *port = act->port;
560287ac01aSChristof Schmitt 	struct zfcp_unit *unit = act->unit;
561287ac01aSChristof Schmitt 	u32 status = act->status;
562287ac01aSChristof Schmitt 
563287ac01aSChristof Schmitt 	/* initiate follow-up actions depending on success of finished action */
564287ac01aSChristof Schmitt 	switch (act->action) {
565287ac01aSChristof Schmitt 
566287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
567287ac01aSChristof Schmitt 		if (status == ZFCP_ERP_SUCCEEDED)
5685ffd51a5SSwen Schillig 			_zfcp_erp_port_reopen_all(adapter, 0, "ersfa_1", NULL);
569287ac01aSChristof Schmitt 		else
5705ffd51a5SSwen Schillig 			_zfcp_erp_adapter_reopen(adapter, 0, "ersfa_2", NULL);
571287ac01aSChristof Schmitt 		break;
572287ac01aSChristof Schmitt 
573287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
574287ac01aSChristof Schmitt 		if (status == ZFCP_ERP_SUCCEEDED)
5755ffd51a5SSwen Schillig 			_zfcp_erp_port_reopen(port, 0, "ersfa_3", NULL);
576287ac01aSChristof Schmitt 		else
5775ffd51a5SSwen Schillig 			_zfcp_erp_adapter_reopen(adapter, 0, "ersfa_4", NULL);
578287ac01aSChristof Schmitt 		break;
579287ac01aSChristof Schmitt 
580287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
581287ac01aSChristof Schmitt 		if (status == ZFCP_ERP_SUCCEEDED)
5825ffd51a5SSwen Schillig 			_zfcp_erp_unit_reopen_all(port, 0, "ersfa_5", NULL);
583287ac01aSChristof Schmitt 		else
5845ffd51a5SSwen Schillig 			_zfcp_erp_port_forced_reopen(port, 0, "ersfa_6", NULL);
585287ac01aSChristof Schmitt 		break;
586287ac01aSChristof Schmitt 
587287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
588287ac01aSChristof Schmitt 		if (status != ZFCP_ERP_SUCCEEDED)
5895ffd51a5SSwen Schillig 			_zfcp_erp_port_reopen(unit->port, 0, "ersfa_7", NULL);
590287ac01aSChristof Schmitt 		break;
591287ac01aSChristof Schmitt 	}
592287ac01aSChristof Schmitt }
593287ac01aSChristof Schmitt 
594287ac01aSChristof Schmitt static void zfcp_erp_wakeup(struct zfcp_adapter *adapter)
595287ac01aSChristof Schmitt {
596287ac01aSChristof Schmitt 	unsigned long flags;
597287ac01aSChristof Schmitt 
598287ac01aSChristof Schmitt 	read_lock_irqsave(&zfcp_data.config_lock, flags);
599287ac01aSChristof Schmitt 	read_lock(&adapter->erp_lock);
600287ac01aSChristof Schmitt 	if (list_empty(&adapter->erp_ready_head) &&
601287ac01aSChristof Schmitt 	    list_empty(&adapter->erp_running_head)) {
602287ac01aSChristof Schmitt 			atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING,
603287ac01aSChristof Schmitt 					  &adapter->status);
604287ac01aSChristof Schmitt 			wake_up(&adapter->erp_done_wqh);
605287ac01aSChristof Schmitt 	}
606287ac01aSChristof Schmitt 	read_unlock(&adapter->erp_lock);
607287ac01aSChristof Schmitt 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
608287ac01aSChristof Schmitt }
609287ac01aSChristof Schmitt 
610287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
611287ac01aSChristof Schmitt {
612287ac01aSChristof Schmitt 	if (zfcp_qdio_open(act->adapter))
613287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
614287ac01aSChristof Schmitt 	init_waitqueue_head(&act->adapter->request_wq);
615287ac01aSChristof Schmitt 	atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status);
616287ac01aSChristof Schmitt 	return ZFCP_ERP_SUCCEEDED;
617287ac01aSChristof Schmitt }
618287ac01aSChristof Schmitt 
619287ac01aSChristof Schmitt static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
620287ac01aSChristof Schmitt {
621287ac01aSChristof Schmitt 	struct zfcp_port *port;
622287ac01aSChristof Schmitt 	port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0,
623287ac01aSChristof Schmitt 				 adapter->peer_d_id);
624287ac01aSChristof Schmitt 	if (IS_ERR(port)) /* error or port already attached */
625287ac01aSChristof Schmitt 		return;
6265ffd51a5SSwen Schillig 	_zfcp_erp_port_reopen(port, 0, "ereptp1", NULL);
627287ac01aSChristof Schmitt }
628287ac01aSChristof Schmitt 
629287ac01aSChristof Schmitt static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
630287ac01aSChristof Schmitt {
631287ac01aSChristof Schmitt 	int retries;
632287ac01aSChristof Schmitt 	int sleep = 1;
633287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = erp_action->adapter;
634287ac01aSChristof Schmitt 
635287ac01aSChristof Schmitt 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
636287ac01aSChristof Schmitt 
637287ac01aSChristof Schmitt 	for (retries = 7; retries; retries--) {
638287ac01aSChristof Schmitt 		atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
639287ac01aSChristof Schmitt 				  &adapter->status);
640287ac01aSChristof Schmitt 		write_lock_irq(&adapter->erp_lock);
641287ac01aSChristof Schmitt 		zfcp_erp_action_to_running(erp_action);
642287ac01aSChristof Schmitt 		write_unlock_irq(&adapter->erp_lock);
643287ac01aSChristof Schmitt 		if (zfcp_fsf_exchange_config_data(erp_action)) {
644287ac01aSChristof Schmitt 			atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
645287ac01aSChristof Schmitt 					  &adapter->status);
646287ac01aSChristof Schmitt 			return ZFCP_ERP_FAILED;
647287ac01aSChristof Schmitt 		}
648287ac01aSChristof Schmitt 
6495ffd51a5SSwen Schillig 		zfcp_rec_dbf_event_thread_lock("erasfx1", adapter);
650287ac01aSChristof Schmitt 		down(&adapter->erp_ready_sem);
6515ffd51a5SSwen Schillig 		zfcp_rec_dbf_event_thread_lock("erasfx2", adapter);
652287ac01aSChristof Schmitt 		if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
653287ac01aSChristof Schmitt 			break;
654287ac01aSChristof Schmitt 
655287ac01aSChristof Schmitt 		if (!(atomic_read(&adapter->status) &
656287ac01aSChristof Schmitt 		      ZFCP_STATUS_ADAPTER_HOST_CON_INIT))
657287ac01aSChristof Schmitt 			break;
658287ac01aSChristof Schmitt 
659287ac01aSChristof Schmitt 		ssleep(sleep);
660287ac01aSChristof Schmitt 		sleep *= 2;
661287ac01aSChristof Schmitt 	}
662287ac01aSChristof Schmitt 
663287ac01aSChristof Schmitt 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
664287ac01aSChristof Schmitt 			  &adapter->status);
665287ac01aSChristof Schmitt 
666287ac01aSChristof Schmitt 	if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK))
667287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
668287ac01aSChristof Schmitt 
669287ac01aSChristof Schmitt 	if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
670287ac01aSChristof Schmitt 		zfcp_erp_enqueue_ptp_port(adapter);
671287ac01aSChristof Schmitt 
672287ac01aSChristof Schmitt 	return ZFCP_ERP_SUCCEEDED;
673287ac01aSChristof Schmitt }
674287ac01aSChristof Schmitt 
675287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act)
676287ac01aSChristof Schmitt {
677287ac01aSChristof Schmitt 	int ret;
678287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
679287ac01aSChristof Schmitt 
680287ac01aSChristof Schmitt 	write_lock_irq(&adapter->erp_lock);
681287ac01aSChristof Schmitt 	zfcp_erp_action_to_running(act);
682287ac01aSChristof Schmitt 	write_unlock_irq(&adapter->erp_lock);
683287ac01aSChristof Schmitt 
684287ac01aSChristof Schmitt 	ret = zfcp_fsf_exchange_port_data(act);
685287ac01aSChristof Schmitt 	if (ret == -EOPNOTSUPP)
686287ac01aSChristof Schmitt 		return ZFCP_ERP_SUCCEEDED;
687287ac01aSChristof Schmitt 	if (ret)
688287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
689287ac01aSChristof Schmitt 
6905ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_thread_lock("erasox1", adapter);
691287ac01aSChristof Schmitt 	down(&adapter->erp_ready_sem);
6925ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_thread_lock("erasox2", adapter);
693287ac01aSChristof Schmitt 	if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
694287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
695287ac01aSChristof Schmitt 
696287ac01aSChristof Schmitt 	return ZFCP_ERP_SUCCEEDED;
697287ac01aSChristof Schmitt }
698287ac01aSChristof Schmitt 
699287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)
700287ac01aSChristof Schmitt {
701287ac01aSChristof Schmitt 	if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED)
702287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
703287ac01aSChristof Schmitt 
704287ac01aSChristof Schmitt 	if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)
705287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
706287ac01aSChristof Schmitt 
707287ac01aSChristof Schmitt 	atomic_set(&act->adapter->stat_miss, 16);
708287ac01aSChristof Schmitt 	if (zfcp_status_read_refill(act->adapter))
709287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
710287ac01aSChristof Schmitt 
711287ac01aSChristof Schmitt 	return ZFCP_ERP_SUCCEEDED;
712287ac01aSChristof Schmitt }
713287ac01aSChristof Schmitt 
714cf13c082SSwen Schillig static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act)
715287ac01aSChristof Schmitt {
716287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
717287ac01aSChristof Schmitt 
718287ac01aSChristof Schmitt 	/* close queues to ensure that buffers are not accessed by adapter */
719287ac01aSChristof Schmitt 	zfcp_qdio_close(adapter);
720287ac01aSChristof Schmitt 	zfcp_fsf_req_dismiss_all(adapter);
721287ac01aSChristof Schmitt 	adapter->fsf_req_seq_no = 0;
722828bc121SSwen Schillig 	zfcp_fc_wka_port_force_offline(&adapter->nsp);
723287ac01aSChristof Schmitt 	/* all ports and units are closed */
7245ffd51a5SSwen Schillig 	zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL,
725287ac01aSChristof Schmitt 				       ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
726cf13c082SSwen Schillig 
727cf13c082SSwen Schillig 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
728cf13c082SSwen Schillig 			  ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
729cf13c082SSwen Schillig }
730cf13c082SSwen Schillig 
731cf13c082SSwen Schillig static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act)
732cf13c082SSwen Schillig {
733cf13c082SSwen Schillig 	struct zfcp_adapter *adapter = act->adapter;
734cf13c082SSwen Schillig 
735cf13c082SSwen Schillig 	if (zfcp_erp_adapter_strategy_open_qdio(act)) {
736287ac01aSChristof Schmitt 		atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
73744cc76f2SSwen Schillig 				  ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
738cf13c082SSwen Schillig 				  &adapter->status);
739cf13c082SSwen Schillig 		return ZFCP_ERP_FAILED;
740cf13c082SSwen Schillig 	}
741cf13c082SSwen Schillig 
742cf13c082SSwen Schillig 	if (zfcp_erp_adapter_strategy_open_fsf(act)) {
743cf13c082SSwen Schillig 		zfcp_erp_adapter_strategy_close(act);
744cf13c082SSwen Schillig 		return ZFCP_ERP_FAILED;
745cf13c082SSwen Schillig 	}
746cf13c082SSwen Schillig 
747cf13c082SSwen Schillig 	atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &adapter->status);
748cf13c082SSwen Schillig 
749cf13c082SSwen Schillig 	return ZFCP_ERP_SUCCEEDED;
750287ac01aSChristof Schmitt }
751287ac01aSChristof Schmitt 
752287ac01aSChristof Schmitt static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act)
753287ac01aSChristof Schmitt {
754cf13c082SSwen Schillig 	struct zfcp_adapter *adapter = act->adapter;
755287ac01aSChristof Schmitt 
756cf13c082SSwen Schillig 	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN) {
757cf13c082SSwen Schillig 		zfcp_erp_adapter_strategy_close(act);
758287ac01aSChristof Schmitt 		if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
759287ac01aSChristof Schmitt 			return ZFCP_ERP_EXIT;
760cf13c082SSwen Schillig 	}
761287ac01aSChristof Schmitt 
762cf13c082SSwen Schillig 	if (zfcp_erp_adapter_strategy_open(act)) {
763287ac01aSChristof Schmitt 		ssleep(8);
764cf13c082SSwen Schillig 		return ZFCP_ERP_FAILED;
765cf13c082SSwen Schillig 	}
7661da177e4SLinus Torvalds 
767cf13c082SSwen Schillig 	return ZFCP_ERP_SUCCEEDED;
7681da177e4SLinus Torvalds }
7691da177e4SLinus Torvalds 
770287ac01aSChristof Schmitt static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act)
7711da177e4SLinus Torvalds {
772287ac01aSChristof Schmitt 	int retval;
773287ac01aSChristof Schmitt 
774287ac01aSChristof Schmitt 	retval = zfcp_fsf_close_physical_port(act);
775287ac01aSChristof Schmitt 	if (retval == -ENOMEM)
776287ac01aSChristof Schmitt 		return ZFCP_ERP_NOMEM;
777287ac01aSChristof Schmitt 	act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING;
778287ac01aSChristof Schmitt 	if (retval)
779287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
780287ac01aSChristof Schmitt 
781287ac01aSChristof Schmitt 	return ZFCP_ERP_CONTINUES;
7821da177e4SLinus Torvalds }
7831da177e4SLinus Torvalds 
784287ac01aSChristof Schmitt static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
7851da177e4SLinus Torvalds {
786a5b11ddaSChristof Schmitt 	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status);
787287ac01aSChristof Schmitt }
7881da177e4SLinus Torvalds 
789287ac01aSChristof Schmitt static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
790287ac01aSChristof Schmitt {
791287ac01aSChristof Schmitt 	struct zfcp_port *port = erp_action->port;
792287ac01aSChristof Schmitt 	int status = atomic_read(&port->status);
793287ac01aSChristof Schmitt 
794287ac01aSChristof Schmitt 	switch (erp_action->step) {
795287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNINITIALIZED:
796287ac01aSChristof Schmitt 		zfcp_erp_port_strategy_clearstati(port);
797287ac01aSChristof Schmitt 		if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) &&
798287ac01aSChristof Schmitt 		    (status & ZFCP_STATUS_COMMON_OPEN))
799287ac01aSChristof Schmitt 			return zfcp_erp_port_forced_strategy_close(erp_action);
8001da177e4SLinus Torvalds 		else
801287ac01aSChristof Schmitt 			return ZFCP_ERP_FAILED;
802287ac01aSChristof Schmitt 
803287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
804287ac01aSChristof Schmitt 		if (status & ZFCP_STATUS_PORT_PHYS_OPEN)
805287ac01aSChristof Schmitt 			return ZFCP_ERP_SUCCEEDED;
806287ac01aSChristof Schmitt 	}
807287ac01aSChristof Schmitt 	return ZFCP_ERP_FAILED;
8081da177e4SLinus Torvalds }
8091da177e4SLinus Torvalds 
810287ac01aSChristof Schmitt static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action)
8111da177e4SLinus Torvalds {
812287ac01aSChristof Schmitt 	int retval;
8131da177e4SLinus Torvalds 
814287ac01aSChristof Schmitt 	retval = zfcp_fsf_close_port(erp_action);
815287ac01aSChristof Schmitt 	if (retval == -ENOMEM)
816287ac01aSChristof Schmitt 		return ZFCP_ERP_NOMEM;
817287ac01aSChristof Schmitt 	erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING;
818287ac01aSChristof Schmitt 	if (retval)
819287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
820287ac01aSChristof Schmitt 	return ZFCP_ERP_CONTINUES;
8211da177e4SLinus Torvalds }
8221da177e4SLinus Torvalds 
823287ac01aSChristof Schmitt static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action)
824287ac01aSChristof Schmitt {
825287ac01aSChristof Schmitt 	int retval;
826287ac01aSChristof Schmitt 
827287ac01aSChristof Schmitt 	retval = zfcp_fsf_open_port(erp_action);
828287ac01aSChristof Schmitt 	if (retval == -ENOMEM)
829287ac01aSChristof Schmitt 		return ZFCP_ERP_NOMEM;
830287ac01aSChristof Schmitt 	erp_action->step = ZFCP_ERP_STEP_PORT_OPENING;
831287ac01aSChristof Schmitt 	if (retval)
832287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
833287ac01aSChristof Schmitt 	return ZFCP_ERP_CONTINUES;
834287ac01aSChristof Schmitt }
835287ac01aSChristof Schmitt 
836287ac01aSChristof Schmitt static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
837287ac01aSChristof Schmitt {
838287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
839287ac01aSChristof Schmitt 	struct zfcp_port *port = act->port;
840287ac01aSChristof Schmitt 
841287ac01aSChristof Schmitt 	if (port->wwpn != adapter->peer_wwpn) {
8425ffd51a5SSwen Schillig 		zfcp_erp_port_failed(port, "eroptp1", NULL);
843287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
844287ac01aSChristof Schmitt 	}
845287ac01aSChristof Schmitt 	port->d_id = adapter->peer_d_id;
846287ac01aSChristof Schmitt 	return zfcp_erp_port_strategy_open_port(act);
847287ac01aSChristof Schmitt }
848287ac01aSChristof Schmitt 
8495ab944f9SSwen Schillig void zfcp_erp_port_strategy_open_lookup(struct work_struct *work)
8505ab944f9SSwen Schillig {
8515ab944f9SSwen Schillig 	int retval;
8525ab944f9SSwen Schillig 	struct zfcp_port *port = container_of(work, struct zfcp_port,
8535ab944f9SSwen Schillig 					      gid_pn_work);
8545ab944f9SSwen Schillig 
8555ab944f9SSwen Schillig 	retval = zfcp_fc_ns_gid_pn(&port->erp_action);
8565ab944f9SSwen Schillig 	if (retval == -ENOMEM)
8575ab944f9SSwen Schillig 		zfcp_erp_notify(&port->erp_action, ZFCP_ERP_NOMEM);
8585ab944f9SSwen Schillig 	port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP;
8595ab944f9SSwen Schillig 	if (retval)
8605ab944f9SSwen Schillig 		zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED);
861947a9acaSSwen Schillig 	zfcp_port_put(port);
8625ab944f9SSwen Schillig }
8635ab944f9SSwen Schillig 
864287ac01aSChristof Schmitt static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
865287ac01aSChristof Schmitt {
866287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
867287ac01aSChristof Schmitt 	struct zfcp_port *port = act->port;
868287ac01aSChristof Schmitt 	int p_status = atomic_read(&port->status);
869287ac01aSChristof Schmitt 
870287ac01aSChristof Schmitt 	switch (act->step) {
871287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNINITIALIZED:
872287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
873287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_PORT_CLOSING:
874287ac01aSChristof Schmitt 		if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
875287ac01aSChristof Schmitt 			return zfcp_erp_open_ptp_port(act);
876b98478d7SChristof Schmitt 		if (!port->d_id) {
877947a9acaSSwen Schillig 			zfcp_port_get(port);
878947a9acaSSwen Schillig 			if (!queue_work(zfcp_data.work_queue,
879947a9acaSSwen Schillig 					&port->gid_pn_work))
880947a9acaSSwen Schillig 				zfcp_port_put(port);
881287ac01aSChristof Schmitt 			return ZFCP_ERP_CONTINUES;
882287ac01aSChristof Schmitt 		}
883dceab655SChristof Schmitt 		/* fall through */
884287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_NAMESERVER_LOOKUP:
885a5b11ddaSChristof Schmitt 		if (!port->d_id)
886287ac01aSChristof Schmitt 			return ZFCP_ERP_FAILED;
887287ac01aSChristof Schmitt 		return zfcp_erp_port_strategy_open_port(act);
888287ac01aSChristof Schmitt 
889287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_PORT_OPENING:
890287ac01aSChristof Schmitt 		/* D_ID might have changed during open */
8915ab944f9SSwen Schillig 		if (p_status & ZFCP_STATUS_COMMON_OPEN) {
892b98478d7SChristof Schmitt 			if (port->d_id)
893287ac01aSChristof Schmitt 				return ZFCP_ERP_SUCCEEDED;
8945ab944f9SSwen Schillig 			else {
8955ab944f9SSwen Schillig 				act->step = ZFCP_ERP_STEP_PORT_CLOSING;
8965ab944f9SSwen Schillig 				return ZFCP_ERP_CONTINUES;
8975ab944f9SSwen Schillig 			}
898287ac01aSChristof Schmitt 		}
899ea460a81SSwen Schillig 		if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
900ea460a81SSwen Schillig 			port->d_id = 0;
901ea460a81SSwen Schillig 			_zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL);
902ea460a81SSwen Schillig 			return ZFCP_ERP_EXIT;
903ea460a81SSwen Schillig 		}
904ea460a81SSwen Schillig 		/* fall through otherwise */
905287ac01aSChristof Schmitt 	}
9065ab944f9SSwen Schillig 	return ZFCP_ERP_FAILED;
907287ac01aSChristof Schmitt }
908287ac01aSChristof Schmitt 
909287ac01aSChristof Schmitt static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
910287ac01aSChristof Schmitt {
911287ac01aSChristof Schmitt 	struct zfcp_port *port = erp_action->port;
912287ac01aSChristof Schmitt 
9135ab944f9SSwen Schillig 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC)
9145ab944f9SSwen Schillig 		goto close_init_done;
9155ab944f9SSwen Schillig 
916287ac01aSChristof Schmitt 	switch (erp_action->step) {
917287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNINITIALIZED:
918287ac01aSChristof Schmitt 		zfcp_erp_port_strategy_clearstati(port);
919287ac01aSChristof Schmitt 		if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)
920287ac01aSChristof Schmitt 			return zfcp_erp_port_strategy_close(erp_action);
921287ac01aSChristof Schmitt 		break;
922287ac01aSChristof Schmitt 
923287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_PORT_CLOSING:
924287ac01aSChristof Schmitt 		if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)
925287ac01aSChristof Schmitt 			return ZFCP_ERP_FAILED;
926287ac01aSChristof Schmitt 		break;
927287ac01aSChristof Schmitt 	}
9285ab944f9SSwen Schillig 
9295ab944f9SSwen Schillig close_init_done:
930287ac01aSChristof Schmitt 	if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
931287ac01aSChristof Schmitt 		return ZFCP_ERP_EXIT;
932287ac01aSChristof Schmitt 
9335ab944f9SSwen Schillig 	return zfcp_erp_port_strategy_open_common(erp_action);
934287ac01aSChristof Schmitt }
935287ac01aSChristof Schmitt 
936287ac01aSChristof Schmitt static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit)
937287ac01aSChristof Schmitt {
93844cc76f2SSwen Schillig 	atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
939287ac01aSChristof Schmitt 			  ZFCP_STATUS_UNIT_SHARED |
940287ac01aSChristof Schmitt 			  ZFCP_STATUS_UNIT_READONLY,
941287ac01aSChristof Schmitt 			  &unit->status);
942287ac01aSChristof Schmitt }
943287ac01aSChristof Schmitt 
944287ac01aSChristof Schmitt static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action)
945287ac01aSChristof Schmitt {
946287ac01aSChristof Schmitt 	int retval = zfcp_fsf_close_unit(erp_action);
947287ac01aSChristof Schmitt 	if (retval == -ENOMEM)
948287ac01aSChristof Schmitt 		return ZFCP_ERP_NOMEM;
949287ac01aSChristof Schmitt 	erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING;
950287ac01aSChristof Schmitt 	if (retval)
951287ac01aSChristof Schmitt 		return ZFCP_ERP_FAILED;
952287ac01aSChristof Schmitt 	return ZFCP_ERP_CONTINUES;
953287ac01aSChristof Schmitt }
954287ac01aSChristof Schmitt 
955287ac01aSChristof Schmitt static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action)
956287ac01aSChristof Schmitt {
957287ac01aSChristof Schmitt 	int retval = zfcp_fsf_open_unit(erp_action);
958287ac01aSChristof Schmitt 	if (retval == -ENOMEM)
959287ac01aSChristof Schmitt 		return ZFCP_ERP_NOMEM;
960287ac01aSChristof Schmitt 	erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING;
961287ac01aSChristof Schmitt 	if (retval)
962287ac01aSChristof Schmitt 		return  ZFCP_ERP_FAILED;
963287ac01aSChristof Schmitt 	return ZFCP_ERP_CONTINUES;
964287ac01aSChristof Schmitt }
965287ac01aSChristof Schmitt 
966287ac01aSChristof Schmitt static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action)
967287ac01aSChristof Schmitt {
968287ac01aSChristof Schmitt 	struct zfcp_unit *unit = erp_action->unit;
969287ac01aSChristof Schmitt 
970287ac01aSChristof Schmitt 	switch (erp_action->step) {
971287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNINITIALIZED:
972287ac01aSChristof Schmitt 		zfcp_erp_unit_strategy_clearstati(unit);
973287ac01aSChristof Schmitt 		if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
974287ac01aSChristof Schmitt 			return zfcp_erp_unit_strategy_close(erp_action);
975287ac01aSChristof Schmitt 		/* already closed, fall through */
976287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNIT_CLOSING:
977287ac01aSChristof Schmitt 		if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
978287ac01aSChristof Schmitt 			return ZFCP_ERP_FAILED;
979287ac01aSChristof Schmitt 		if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
980287ac01aSChristof Schmitt 			return ZFCP_ERP_EXIT;
981287ac01aSChristof Schmitt 		return zfcp_erp_unit_strategy_open(erp_action);
982287ac01aSChristof Schmitt 
983287ac01aSChristof Schmitt 	case ZFCP_ERP_STEP_UNIT_OPENING:
984287ac01aSChristof Schmitt 		if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
985287ac01aSChristof Schmitt 			return ZFCP_ERP_SUCCEEDED;
986287ac01aSChristof Schmitt 	}
987287ac01aSChristof Schmitt 	return ZFCP_ERP_FAILED;
988287ac01aSChristof Schmitt }
989287ac01aSChristof Schmitt 
990287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result)
991287ac01aSChristof Schmitt {
992287ac01aSChristof Schmitt 	switch (result) {
993287ac01aSChristof Schmitt 	case ZFCP_ERP_SUCCEEDED :
994287ac01aSChristof Schmitt 		atomic_set(&unit->erp_counter, 0);
995287ac01aSChristof Schmitt 		zfcp_erp_unit_unblock(unit);
996287ac01aSChristof Schmitt 		break;
997287ac01aSChristof Schmitt 	case ZFCP_ERP_FAILED :
998287ac01aSChristof Schmitt 		atomic_inc(&unit->erp_counter);
999ff3b24faSChristof Schmitt 		if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) {
1000ff3b24faSChristof Schmitt 			dev_err(&unit->port->adapter->ccw_device->dev,
1001ff3b24faSChristof Schmitt 				"ERP failed for unit 0x%016Lx on "
1002ff3b24faSChristof Schmitt 				"port 0x%016Lx\n",
10037ba58c9cSSwen Schillig 				(unsigned long long)unit->fcp_lun,
10047ba58c9cSSwen Schillig 				(unsigned long long)unit->port->wwpn);
10055ffd51a5SSwen Schillig 			zfcp_erp_unit_failed(unit, "erusck1", NULL);
1006ff3b24faSChristof Schmitt 		}
1007287ac01aSChristof Schmitt 		break;
1008287ac01aSChristof Schmitt 	}
1009287ac01aSChristof Schmitt 
1010287ac01aSChristof Schmitt 	if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1011287ac01aSChristof Schmitt 		zfcp_erp_unit_block(unit, 0);
1012287ac01aSChristof Schmitt 		result = ZFCP_ERP_EXIT;
1013287ac01aSChristof Schmitt 	}
1014287ac01aSChristof Schmitt 	return result;
1015287ac01aSChristof Schmitt }
1016287ac01aSChristof Schmitt 
1017287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
1018287ac01aSChristof Schmitt {
1019287ac01aSChristof Schmitt 	switch (result) {
1020287ac01aSChristof Schmitt 	case ZFCP_ERP_SUCCEEDED :
1021287ac01aSChristof Schmitt 		atomic_set(&port->erp_counter, 0);
1022287ac01aSChristof Schmitt 		zfcp_erp_port_unblock(port);
1023287ac01aSChristof Schmitt 		break;
1024287ac01aSChristof Schmitt 
1025287ac01aSChristof Schmitt 	case ZFCP_ERP_FAILED :
1026287ac01aSChristof Schmitt 		if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) {
1027287ac01aSChristof Schmitt 			zfcp_erp_port_block(port, 0);
1028287ac01aSChristof Schmitt 			result = ZFCP_ERP_EXIT;
1029287ac01aSChristof Schmitt 		}
1030287ac01aSChristof Schmitt 		atomic_inc(&port->erp_counter);
1031ff3b24faSChristof Schmitt 		if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
1032ff3b24faSChristof Schmitt 			dev_err(&port->adapter->ccw_device->dev,
1033ff3b24faSChristof Schmitt 				"ERP failed for remote port 0x%016Lx\n",
10347ba58c9cSSwen Schillig 				(unsigned long long)port->wwpn);
10355ffd51a5SSwen Schillig 			zfcp_erp_port_failed(port, "erpsck1", NULL);
1036ff3b24faSChristof Schmitt 		}
1037287ac01aSChristof Schmitt 		break;
1038287ac01aSChristof Schmitt 	}
1039287ac01aSChristof Schmitt 
1040287ac01aSChristof Schmitt 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1041287ac01aSChristof Schmitt 		zfcp_erp_port_block(port, 0);
1042287ac01aSChristof Schmitt 		result = ZFCP_ERP_EXIT;
1043287ac01aSChristof Schmitt 	}
1044287ac01aSChristof Schmitt 	return result;
1045287ac01aSChristof Schmitt }
1046287ac01aSChristof Schmitt 
1047287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter,
1048287ac01aSChristof Schmitt 					   int result)
1049287ac01aSChristof Schmitt {
1050287ac01aSChristof Schmitt 	switch (result) {
1051287ac01aSChristof Schmitt 	case ZFCP_ERP_SUCCEEDED :
1052287ac01aSChristof Schmitt 		atomic_set(&adapter->erp_counter, 0);
1053287ac01aSChristof Schmitt 		zfcp_erp_adapter_unblock(adapter);
1054287ac01aSChristof Schmitt 		break;
1055287ac01aSChristof Schmitt 
1056287ac01aSChristof Schmitt 	case ZFCP_ERP_FAILED :
1057287ac01aSChristof Schmitt 		atomic_inc(&adapter->erp_counter);
1058ff3b24faSChristof Schmitt 		if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) {
1059ff3b24faSChristof Schmitt 			dev_err(&adapter->ccw_device->dev,
1060ff3b24faSChristof Schmitt 				"ERP cannot recover an error "
1061ff3b24faSChristof Schmitt 				"on the FCP device\n");
10625ffd51a5SSwen Schillig 			zfcp_erp_adapter_failed(adapter, "erasck1", NULL);
1063ff3b24faSChristof Schmitt 		}
1064287ac01aSChristof Schmitt 		break;
1065287ac01aSChristof Schmitt 	}
1066287ac01aSChristof Schmitt 
1067287ac01aSChristof Schmitt 	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1068287ac01aSChristof Schmitt 		zfcp_erp_adapter_block(adapter, 0);
1069287ac01aSChristof Schmitt 		result = ZFCP_ERP_EXIT;
1070287ac01aSChristof Schmitt 	}
1071287ac01aSChristof Schmitt 	return result;
1072287ac01aSChristof Schmitt }
1073287ac01aSChristof Schmitt 
1074287ac01aSChristof Schmitt static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action,
1075287ac01aSChristof Schmitt 					  int result)
10761da177e4SLinus Torvalds {
10771da177e4SLinus Torvalds 	struct zfcp_adapter *adapter = erp_action->adapter;
10781da177e4SLinus Torvalds 	struct zfcp_port *port = erp_action->port;
10791da177e4SLinus Torvalds 	struct zfcp_unit *unit = erp_action->unit;
10801da177e4SLinus Torvalds 
10811da177e4SLinus Torvalds 	switch (erp_action->action) {
10821da177e4SLinus Torvalds 
10831da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
10841da177e4SLinus Torvalds 		result = zfcp_erp_strategy_check_unit(unit, result);
10851da177e4SLinus Torvalds 		break;
10861da177e4SLinus Torvalds 
10871da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
10881da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_PORT:
10891da177e4SLinus Torvalds 		result = zfcp_erp_strategy_check_port(port, result);
10901da177e4SLinus Torvalds 		break;
10911da177e4SLinus Torvalds 
10921da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
10931da177e4SLinus Torvalds 		result = zfcp_erp_strategy_check_adapter(adapter, result);
10941da177e4SLinus Torvalds 		break;
10951da177e4SLinus Torvalds 	}
10961da177e4SLinus Torvalds 	return result;
10971da177e4SLinus Torvalds }
10981da177e4SLinus Torvalds 
1099287ac01aSChristof Schmitt static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status)
11001da177e4SLinus Torvalds {
1101287ac01aSChristof Schmitt 	int status = atomic_read(target_status);
11021da177e4SLinus Torvalds 
1103287ac01aSChristof Schmitt 	if ((status & ZFCP_STATUS_COMMON_RUNNING) &&
1104287ac01aSChristof Schmitt 	    (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1105287ac01aSChristof Schmitt 		return 1; /* take it online */
1106287ac01aSChristof Schmitt 
1107287ac01aSChristof Schmitt 	if (!(status & ZFCP_STATUS_COMMON_RUNNING) &&
1108287ac01aSChristof Schmitt 	    !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1109287ac01aSChristof Schmitt 		return 1; /* take it offline */
1110287ac01aSChristof Schmitt 
1111287ac01aSChristof Schmitt 	return 0;
1112287ac01aSChristof Schmitt }
1113287ac01aSChristof Schmitt 
1114287ac01aSChristof Schmitt static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
1115287ac01aSChristof Schmitt {
1116287ac01aSChristof Schmitt 	int action = act->action;
1117287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
1118287ac01aSChristof Schmitt 	struct zfcp_port *port = act->port;
1119287ac01aSChristof Schmitt 	struct zfcp_unit *unit = act->unit;
1120287ac01aSChristof Schmitt 	u32 erp_status = act->status;
1121287ac01aSChristof Schmitt 
1122287ac01aSChristof Schmitt 	switch (action) {
11231da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1124287ac01aSChristof Schmitt 		if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) {
1125287ac01aSChristof Schmitt 			_zfcp_erp_adapter_reopen(adapter,
11269467a9b3SMartin Peschke 						 ZFCP_STATUS_COMMON_ERP_FAILED,
11275ffd51a5SSwen Schillig 						 "ersscg1", NULL);
1128287ac01aSChristof Schmitt 			return ZFCP_ERP_EXIT;
11291da177e4SLinus Torvalds 		}
11301da177e4SLinus Torvalds 		break;
11311da177e4SLinus Torvalds 
11321da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
11331da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_PORT:
1134287ac01aSChristof Schmitt 		if (zfcp_erp_strat_change_det(&port->status, erp_status)) {
1135287ac01aSChristof Schmitt 			_zfcp_erp_port_reopen(port,
11369467a9b3SMartin Peschke 					      ZFCP_STATUS_COMMON_ERP_FAILED,
11375ffd51a5SSwen Schillig 					      "ersscg2", NULL);
1138287ac01aSChristof Schmitt 			return ZFCP_ERP_EXIT;
11391da177e4SLinus Torvalds 		}
11401da177e4SLinus Torvalds 		break;
11411da177e4SLinus Torvalds 
11421da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
1143287ac01aSChristof Schmitt 		if (zfcp_erp_strat_change_det(&unit->status, erp_status)) {
1144287ac01aSChristof Schmitt 			_zfcp_erp_unit_reopen(unit,
11459467a9b3SMartin Peschke 					      ZFCP_STATUS_COMMON_ERP_FAILED,
11465ffd51a5SSwen Schillig 					      "ersscg3", NULL);
1147287ac01aSChristof Schmitt 			return ZFCP_ERP_EXIT;
11481da177e4SLinus Torvalds 		}
11491da177e4SLinus Torvalds 		break;
11501da177e4SLinus Torvalds 	}
1151287ac01aSChristof Schmitt 	return ret;
11521da177e4SLinus Torvalds }
11531da177e4SLinus Torvalds 
1154287ac01aSChristof Schmitt static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
11551da177e4SLinus Torvalds {
1156287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = erp_action->adapter;
1157287ac01aSChristof Schmitt 
1158287ac01aSChristof Schmitt 	adapter->erp_total_count--;
1159287ac01aSChristof Schmitt 	if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1160287ac01aSChristof Schmitt 		adapter->erp_low_mem_count--;
1161287ac01aSChristof Schmitt 		erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
11621da177e4SLinus Torvalds 	}
11631da177e4SLinus Torvalds 
1164287ac01aSChristof Schmitt 	list_del(&erp_action->list);
11655ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_action("eractd1", erp_action);
11661da177e4SLinus Torvalds 
1167287ac01aSChristof Schmitt 	switch (erp_action->action) {
1168287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
1169287ac01aSChristof Schmitt 		atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1170287ac01aSChristof Schmitt 				  &erp_action->unit->status);
11711da177e4SLinus Torvalds 		break;
1172287ac01aSChristof Schmitt 
1173287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1174287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
1175287ac01aSChristof Schmitt 		atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1176287ac01aSChristof Schmitt 				  &erp_action->port->status);
11771da177e4SLinus Torvalds 		break;
1178287ac01aSChristof Schmitt 
1179287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1180287ac01aSChristof Schmitt 		atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1181287ac01aSChristof Schmitt 				  &erp_action->adapter->status);
11821da177e4SLinus Torvalds 		break;
11831da177e4SLinus Torvalds 	}
11841da177e4SLinus Torvalds }
11851da177e4SLinus Torvalds 
1186287ac01aSChristof Schmitt static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
1187287ac01aSChristof Schmitt {
1188287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = act->adapter;
1189287ac01aSChristof Schmitt 	struct zfcp_port *port = act->port;
1190287ac01aSChristof Schmitt 	struct zfcp_unit *unit = act->unit;
1191287ac01aSChristof Schmitt 
1192287ac01aSChristof Schmitt 	switch (act->action) {
1193287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
1194a2fa0aedSChristof Schmitt 		if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
119592d5193bSSwen Schillig 			zfcp_unit_get(unit);
119692d5193bSSwen Schillig 			if (scsi_queue_work(unit->port->adapter->scsi_host,
119792d5193bSSwen Schillig 					    &unit->scsi_work) <= 0)
119892d5193bSSwen Schillig 				zfcp_unit_put(unit);
1199287ac01aSChristof Schmitt 		}
1200287ac01aSChristof Schmitt 		zfcp_unit_put(unit);
1201287ac01aSChristof Schmitt 		break;
1202287ac01aSChristof Schmitt 
1203287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1204287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
1205a2fa0aedSChristof Schmitt 		if (result == ZFCP_ERP_SUCCEEDED)
1206a2fa0aedSChristof Schmitt 			zfcp_scsi_schedule_rport_register(port);
12071da177e4SLinus Torvalds 		zfcp_port_put(port);
12081da177e4SLinus Torvalds 		break;
1209287ac01aSChristof Schmitt 
12101da177e4SLinus Torvalds 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1211a2fa0aedSChristof Schmitt 		if (result == ZFCP_ERP_SUCCEEDED) {
1212bd43a42bSChristof Schmitt 			register_service_level(&adapter->service_level);
1213fca55b6fSSwen Schillig 			schedule_work(&adapter->scan_work);
1214a2fa0aedSChristof Schmitt 		} else
1215a2fa0aedSChristof Schmitt 			unregister_service_level(&adapter->service_level);
12161da177e4SLinus Torvalds 		zfcp_adapter_put(adapter);
12171da177e4SLinus Torvalds 		break;
12181da177e4SLinus Torvalds 	}
12191da177e4SLinus Torvalds }
12201da177e4SLinus Torvalds 
1221287ac01aSChristof Schmitt static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
1222287ac01aSChristof Schmitt {
1223287ac01aSChristof Schmitt 	switch (erp_action->action) {
1224287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1225287ac01aSChristof Schmitt 		return zfcp_erp_adapter_strategy(erp_action);
1226287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1227287ac01aSChristof Schmitt 		return zfcp_erp_port_forced_strategy(erp_action);
1228287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_PORT:
1229287ac01aSChristof Schmitt 		return zfcp_erp_port_strategy(erp_action);
1230287ac01aSChristof Schmitt 	case ZFCP_ERP_ACTION_REOPEN_UNIT:
1231287ac01aSChristof Schmitt 		return zfcp_erp_unit_strategy(erp_action);
1232287ac01aSChristof Schmitt 	}
1233287ac01aSChristof Schmitt 	return ZFCP_ERP_FAILED;
1234287ac01aSChristof Schmitt }
12351da177e4SLinus Torvalds 
1236287ac01aSChristof Schmitt static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
1237287ac01aSChristof Schmitt {
1238287ac01aSChristof Schmitt 	int retval;
1239287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = erp_action->adapter;
1240287ac01aSChristof Schmitt 	unsigned long flags;
1241287ac01aSChristof Schmitt 
1242287ac01aSChristof Schmitt 	read_lock_irqsave(&zfcp_data.config_lock, flags);
1243287ac01aSChristof Schmitt 	write_lock(&adapter->erp_lock);
1244287ac01aSChristof Schmitt 
1245287ac01aSChristof Schmitt 	zfcp_erp_strategy_check_fsfreq(erp_action);
1246287ac01aSChristof Schmitt 
1247287ac01aSChristof Schmitt 	if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
1248287ac01aSChristof Schmitt 		zfcp_erp_action_dequeue(erp_action);
1249287ac01aSChristof Schmitt 		retval = ZFCP_ERP_DISMISSED;
1250287ac01aSChristof Schmitt 		goto unlock;
1251287ac01aSChristof Schmitt 	}
1252287ac01aSChristof Schmitt 
1253287ac01aSChristof Schmitt 	zfcp_erp_action_to_running(erp_action);
1254287ac01aSChristof Schmitt 
1255287ac01aSChristof Schmitt 	/* no lock to allow for blocking operations */
1256287ac01aSChristof Schmitt 	write_unlock(&adapter->erp_lock);
1257287ac01aSChristof Schmitt 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
1258287ac01aSChristof Schmitt 	retval = zfcp_erp_strategy_do_action(erp_action);
1259287ac01aSChristof Schmitt 	read_lock_irqsave(&zfcp_data.config_lock, flags);
1260287ac01aSChristof Schmitt 	write_lock(&adapter->erp_lock);
1261287ac01aSChristof Schmitt 
1262287ac01aSChristof Schmitt 	if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED)
1263287ac01aSChristof Schmitt 		retval = ZFCP_ERP_CONTINUES;
1264287ac01aSChristof Schmitt 
1265287ac01aSChristof Schmitt 	switch (retval) {
1266287ac01aSChristof Schmitt 	case ZFCP_ERP_NOMEM:
1267287ac01aSChristof Schmitt 		if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) {
1268287ac01aSChristof Schmitt 			++adapter->erp_low_mem_count;
1269287ac01aSChristof Schmitt 			erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
1270287ac01aSChristof Schmitt 		}
1271287ac01aSChristof Schmitt 		if (adapter->erp_total_count == adapter->erp_low_mem_count)
12725ffd51a5SSwen Schillig 			_zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL);
1273287ac01aSChristof Schmitt 		else {
1274287ac01aSChristof Schmitt 			zfcp_erp_strategy_memwait(erp_action);
1275287ac01aSChristof Schmitt 			retval = ZFCP_ERP_CONTINUES;
1276287ac01aSChristof Schmitt 		}
1277287ac01aSChristof Schmitt 		goto unlock;
1278287ac01aSChristof Schmitt 
1279287ac01aSChristof Schmitt 	case ZFCP_ERP_CONTINUES:
1280287ac01aSChristof Schmitt 		if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1281287ac01aSChristof Schmitt 			--adapter->erp_low_mem_count;
1282287ac01aSChristof Schmitt 			erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
1283287ac01aSChristof Schmitt 		}
1284287ac01aSChristof Schmitt 		goto unlock;
1285287ac01aSChristof Schmitt 	}
1286287ac01aSChristof Schmitt 
1287287ac01aSChristof Schmitt 	retval = zfcp_erp_strategy_check_target(erp_action, retval);
1288287ac01aSChristof Schmitt 	zfcp_erp_action_dequeue(erp_action);
1289287ac01aSChristof Schmitt 	retval = zfcp_erp_strategy_statechange(erp_action, retval);
1290287ac01aSChristof Schmitt 	if (retval == ZFCP_ERP_EXIT)
1291287ac01aSChristof Schmitt 		goto unlock;
1292287ac01aSChristof Schmitt 	zfcp_erp_strategy_followup_actions(erp_action);
1293287ac01aSChristof Schmitt 
1294287ac01aSChristof Schmitt  unlock:
1295287ac01aSChristof Schmitt 	write_unlock(&adapter->erp_lock);
1296287ac01aSChristof Schmitt 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
1297287ac01aSChristof Schmitt 
1298287ac01aSChristof Schmitt 	if (retval != ZFCP_ERP_CONTINUES)
1299287ac01aSChristof Schmitt 		zfcp_erp_action_cleanup(erp_action, retval);
1300287ac01aSChristof Schmitt 
1301287ac01aSChristof Schmitt 	return retval;
1302287ac01aSChristof Schmitt }
1303287ac01aSChristof Schmitt 
1304287ac01aSChristof Schmitt static int zfcp_erp_thread(void *data)
1305287ac01aSChristof Schmitt {
1306287ac01aSChristof Schmitt 	struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
1307287ac01aSChristof Schmitt 	struct list_head *next;
1308287ac01aSChristof Schmitt 	struct zfcp_erp_action *act;
1309287ac01aSChristof Schmitt 	unsigned long flags;
131006499facSHeiko Carstens 	int ignore;
1311287ac01aSChristof Schmitt 
1312b9d3aed7SCornelia Huck 	daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev));
1313287ac01aSChristof Schmitt 	/* Block all signals */
1314287ac01aSChristof Schmitt 	siginitsetinv(&current->blocked, 0);
1315287ac01aSChristof Schmitt 	atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
1316287ac01aSChristof Schmitt 	wake_up(&adapter->erp_thread_wqh);
1317287ac01aSChristof Schmitt 
1318287ac01aSChristof Schmitt 	while (!(atomic_read(&adapter->status) &
1319287ac01aSChristof Schmitt 		 ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) {
132094ab4b38SSwen Schillig 
132194ab4b38SSwen Schillig 		zfcp_rec_dbf_event_thread_lock("erthrd1", adapter);
132294ab4b38SSwen Schillig 		ignore = down_interruptible(&adapter->erp_ready_sem);
132394ab4b38SSwen Schillig 		zfcp_rec_dbf_event_thread_lock("erthrd2", adapter);
132494ab4b38SSwen Schillig 
1325287ac01aSChristof Schmitt 		write_lock_irqsave(&adapter->erp_lock, flags);
1326287ac01aSChristof Schmitt 		next = adapter->erp_ready_head.next;
1327287ac01aSChristof Schmitt 		write_unlock_irqrestore(&adapter->erp_lock, flags);
1328287ac01aSChristof Schmitt 
1329287ac01aSChristof Schmitt 		if (next != &adapter->erp_ready_head) {
1330287ac01aSChristof Schmitt 			act = list_entry(next, struct zfcp_erp_action, list);
1331287ac01aSChristof Schmitt 
1332287ac01aSChristof Schmitt 			/* there is more to come after dismission, no notify */
1333287ac01aSChristof Schmitt 			if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED)
1334287ac01aSChristof Schmitt 				zfcp_erp_wakeup(adapter);
1335287ac01aSChristof Schmitt 		}
1336287ac01aSChristof Schmitt 	}
1337287ac01aSChristof Schmitt 
1338287ac01aSChristof Schmitt 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
1339287ac01aSChristof Schmitt 	wake_up(&adapter->erp_thread_wqh);
1340287ac01aSChristof Schmitt 
1341287ac01aSChristof Schmitt 	return 0;
1342287ac01aSChristof Schmitt }
1343287ac01aSChristof Schmitt 
1344287ac01aSChristof Schmitt /**
1345287ac01aSChristof Schmitt  * zfcp_erp_thread_setup - Start ERP thread for adapter
1346287ac01aSChristof Schmitt  * @adapter: Adapter to start the ERP thread for
1347287ac01aSChristof Schmitt  *
1348287ac01aSChristof Schmitt  * Returns 0 on success or error code from kernel_thread()
1349287ac01aSChristof Schmitt  */
1350287ac01aSChristof Schmitt int zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
1351287ac01aSChristof Schmitt {
1352287ac01aSChristof Schmitt 	int retval;
1353287ac01aSChristof Schmitt 
1354287ac01aSChristof Schmitt 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
1355287ac01aSChristof Schmitt 	retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD);
1356287ac01aSChristof Schmitt 	if (retval < 0) {
1357287ac01aSChristof Schmitt 		dev_err(&adapter->ccw_device->dev,
1358ff3b24faSChristof Schmitt 			"Creating an ERP thread for the FCP device failed.\n");
1359287ac01aSChristof Schmitt 		return retval;
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 	return 0;
1365287ac01aSChristof Schmitt }
1366287ac01aSChristof Schmitt 
1367287ac01aSChristof Schmitt /**
1368287ac01aSChristof Schmitt  * zfcp_erp_thread_kill - Stop ERP thread.
1369287ac01aSChristof Schmitt  * @adapter: Adapter where the ERP thread should be stopped.
1370287ac01aSChristof Schmitt  *
1371287ac01aSChristof Schmitt  * The caller of this routine ensures that the specified adapter has
1372287ac01aSChristof Schmitt  * been shut down and that this operation has been completed. Thus,
1373287ac01aSChristof Schmitt  * there are no pending erp_actions which would need to be handled
1374287ac01aSChristof Schmitt  * here.
1375287ac01aSChristof Schmitt  */
1376287ac01aSChristof Schmitt void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
1377287ac01aSChristof Schmitt {
1378287ac01aSChristof Schmitt 	atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status);
1379287ac01aSChristof Schmitt 	up(&adapter->erp_ready_sem);
13805ffd51a5SSwen Schillig 	zfcp_rec_dbf_event_thread_lock("erthrk1", adapter);
1381287ac01aSChristof Schmitt 
1382287ac01aSChristof Schmitt 	wait_event(adapter->erp_thread_wqh,
1383287ac01aSChristof Schmitt 		   !(atomic_read(&adapter->status) &
1384287ac01aSChristof Schmitt 				ZFCP_STATUS_ADAPTER_ERP_THREAD_UP));
1385287ac01aSChristof Schmitt 
1386287ac01aSChristof Schmitt 	atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL,
1387287ac01aSChristof Schmitt 			  &adapter->status);
1388287ac01aSChristof Schmitt }
1389287ac01aSChristof Schmitt 
1390287ac01aSChristof Schmitt /**
1391287ac01aSChristof Schmitt  * zfcp_erp_adapter_failed - Set adapter status to failed.
1392287ac01aSChristof Schmitt  * @adapter: Failed adapter.
1393287ac01aSChristof Schmitt  * @id: Event id for debug trace.
1394287ac01aSChristof Schmitt  * @ref: Reference for debug trace.
1395287ac01aSChristof Schmitt  */
13965ffd51a5SSwen Schillig void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, char *id, void *ref)
1397287ac01aSChristof Schmitt {
1398287ac01aSChristof Schmitt 	zfcp_erp_modify_adapter_status(adapter, id, ref,
1399287ac01aSChristof Schmitt 				       ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
1400287ac01aSChristof Schmitt }
1401287ac01aSChristof Schmitt 
1402287ac01aSChristof Schmitt /**
1403287ac01aSChristof Schmitt  * zfcp_erp_port_failed - Set port status to failed.
1404287ac01aSChristof Schmitt  * @port: Failed port.
1405287ac01aSChristof Schmitt  * @id: Event id for debug trace.
1406287ac01aSChristof Schmitt  * @ref: Reference for debug trace.
1407287ac01aSChristof Schmitt  */
14085ffd51a5SSwen Schillig void zfcp_erp_port_failed(struct zfcp_port *port, char *id, void *ref)
1409287ac01aSChristof Schmitt {
1410287ac01aSChristof Schmitt 	zfcp_erp_modify_port_status(port, id, ref,
1411287ac01aSChristof Schmitt 				    ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
1412287ac01aSChristof Schmitt }
1413287ac01aSChristof Schmitt 
1414287ac01aSChristof Schmitt /**
1415287ac01aSChristof Schmitt  * zfcp_erp_unit_failed - Set unit status to failed.
1416287ac01aSChristof Schmitt  * @unit: Failed unit.
1417287ac01aSChristof Schmitt  * @id: Event id for debug trace.
1418287ac01aSChristof Schmitt  * @ref: Reference for debug trace.
1419287ac01aSChristof Schmitt  */
14205ffd51a5SSwen Schillig void zfcp_erp_unit_failed(struct zfcp_unit *unit, char *id, void *ref)
1421287ac01aSChristof Schmitt {
1422287ac01aSChristof Schmitt 	zfcp_erp_modify_unit_status(unit, id, ref,
1423287ac01aSChristof Schmitt 				    ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
1424287ac01aSChristof Schmitt }
1425287ac01aSChristof Schmitt 
1426287ac01aSChristof Schmitt /**
1427287ac01aSChristof Schmitt  * zfcp_erp_wait - wait for completion of error recovery on an adapter
1428287ac01aSChristof Schmitt  * @adapter: adapter for which to wait for completion of its error recovery
1429287ac01aSChristof Schmitt  */
1430287ac01aSChristof Schmitt void zfcp_erp_wait(struct zfcp_adapter *adapter)
1431287ac01aSChristof Schmitt {
1432287ac01aSChristof Schmitt 	wait_event(adapter->erp_done_wqh,
1433287ac01aSChristof Schmitt 		   !(atomic_read(&adapter->status) &
1434287ac01aSChristof Schmitt 			ZFCP_STATUS_ADAPTER_ERP_PENDING));
1435287ac01aSChristof Schmitt }
1436287ac01aSChristof Schmitt 
1437287ac01aSChristof Schmitt /**
1438287ac01aSChristof Schmitt  * zfcp_erp_modify_adapter_status - change adapter status bits
1439287ac01aSChristof Schmitt  * @adapter: adapter to change the status
1440287ac01aSChristof Schmitt  * @id: id for the debug trace
1441287ac01aSChristof Schmitt  * @ref: reference for the debug trace
1442287ac01aSChristof Schmitt  * @mask: status bits to change
1443287ac01aSChristof Schmitt  * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1444287ac01aSChristof Schmitt  *
1445287ac01aSChristof Schmitt  * Changes in common status bits are propagated to attached ports and units.
1446287ac01aSChristof Schmitt  */
14475ffd51a5SSwen Schillig void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id,
1448287ac01aSChristof Schmitt 				    void *ref, u32 mask, int set_or_clear)
14491da177e4SLinus Torvalds {
14501da177e4SLinus Torvalds 	struct zfcp_port *port;
1451287ac01aSChristof Schmitt 	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
14521da177e4SLinus Torvalds 
1453287ac01aSChristof Schmitt 	if (set_or_clear == ZFCP_SET) {
1454287ac01aSChristof Schmitt 		if (status_change_set(mask, &adapter->status))
1455287ac01aSChristof Schmitt 			zfcp_rec_dbf_event_adapter(id, ref, adapter);
1456287ac01aSChristof Schmitt 		atomic_set_mask(mask, &adapter->status);
1457287ac01aSChristof Schmitt 	} else {
1458287ac01aSChristof Schmitt 		if (status_change_clear(mask, &adapter->status))
1459287ac01aSChristof Schmitt 			zfcp_rec_dbf_event_adapter(id, ref, adapter);
1460287ac01aSChristof Schmitt 		atomic_clear_mask(mask, &adapter->status);
1461287ac01aSChristof Schmitt 		if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
1462287ac01aSChristof Schmitt 			atomic_set(&adapter->erp_counter, 0);
14631da177e4SLinus Torvalds 	}
14641da177e4SLinus Torvalds 
1465287ac01aSChristof Schmitt 	if (common_mask)
1466287ac01aSChristof Schmitt 		list_for_each_entry(port, &adapter->port_list_head, list)
1467287ac01aSChristof Schmitt 			zfcp_erp_modify_port_status(port, id, ref, common_mask,
1468287ac01aSChristof Schmitt 						    set_or_clear);
1469287ac01aSChristof Schmitt }
1470287ac01aSChristof Schmitt 
1471287ac01aSChristof Schmitt /**
1472287ac01aSChristof Schmitt  * zfcp_erp_modify_port_status - change port status bits
1473287ac01aSChristof Schmitt  * @port: port to change the status bits
1474287ac01aSChristof Schmitt  * @id: id for the debug trace
1475287ac01aSChristof Schmitt  * @ref: reference for the debug trace
1476287ac01aSChristof Schmitt  * @mask: status bits to change
1477287ac01aSChristof Schmitt  * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1478287ac01aSChristof Schmitt  *
1479287ac01aSChristof Schmitt  * Changes in common status bits are propagated to attached units.
1480287ac01aSChristof Schmitt  */
14815ffd51a5SSwen Schillig void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref,
1482287ac01aSChristof Schmitt 				 u32 mask, int set_or_clear)
14831da177e4SLinus Torvalds {
14841da177e4SLinus Torvalds 	struct zfcp_unit *unit;
1485287ac01aSChristof Schmitt 	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
14861da177e4SLinus Torvalds 
1487287ac01aSChristof Schmitt 	if (set_or_clear == ZFCP_SET) {
1488287ac01aSChristof Schmitt 		if (status_change_set(mask, &port->status))
1489287ac01aSChristof Schmitt 			zfcp_rec_dbf_event_port(id, ref, port);
1490287ac01aSChristof Schmitt 		atomic_set_mask(mask, &port->status);
1491287ac01aSChristof Schmitt 	} else {
1492287ac01aSChristof Schmitt 		if (status_change_clear(mask, &port->status))
1493287ac01aSChristof Schmitt 			zfcp_rec_dbf_event_port(id, ref, port);
1494287ac01aSChristof Schmitt 		atomic_clear_mask(mask, &port->status);
1495287ac01aSChristof Schmitt 		if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
1496287ac01aSChristof Schmitt 			atomic_set(&port->erp_counter, 0);
1497287ac01aSChristof Schmitt 	}
1498287ac01aSChristof Schmitt 
1499287ac01aSChristof Schmitt 	if (common_mask)
15001da177e4SLinus Torvalds 		list_for_each_entry(unit, &port->unit_list_head, list)
1501287ac01aSChristof Schmitt 			zfcp_erp_modify_unit_status(unit, id, ref, common_mask,
1502287ac01aSChristof Schmitt 						    set_or_clear);
15031da177e4SLinus Torvalds }
15041da177e4SLinus Torvalds 
1505287ac01aSChristof Schmitt /**
1506287ac01aSChristof Schmitt  * zfcp_erp_modify_unit_status - change unit status bits
1507287ac01aSChristof Schmitt  * @unit: unit to change the status bits
1508287ac01aSChristof Schmitt  * @id: id for the debug trace
1509287ac01aSChristof Schmitt  * @ref: reference for the debug trace
1510287ac01aSChristof Schmitt  * @mask: status bits to change
1511287ac01aSChristof Schmitt  * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1512287ac01aSChristof Schmitt  */
15135ffd51a5SSwen Schillig void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref,
1514287ac01aSChristof Schmitt 				 u32 mask, int set_or_clear)
15151da177e4SLinus Torvalds {
1516287ac01aSChristof Schmitt 	if (set_or_clear == ZFCP_SET) {
1517287ac01aSChristof Schmitt 		if (status_change_set(mask, &unit->status))
1518287ac01aSChristof Schmitt 			zfcp_rec_dbf_event_unit(id, ref, unit);
1519287ac01aSChristof Schmitt 		atomic_set_mask(mask, &unit->status);
1520287ac01aSChristof Schmitt 	} else {
1521287ac01aSChristof Schmitt 		if (status_change_clear(mask, &unit->status))
1522287ac01aSChristof Schmitt 			zfcp_rec_dbf_event_unit(id, ref, unit);
1523287ac01aSChristof Schmitt 		atomic_clear_mask(mask, &unit->status);
1524287ac01aSChristof Schmitt 		if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) {
1525287ac01aSChristof Schmitt 			atomic_set(&unit->erp_counter, 0);
1526287ac01aSChristof Schmitt 		}
1527287ac01aSChristof Schmitt 	}
15281da177e4SLinus Torvalds }
15291da177e4SLinus Torvalds 
1530287ac01aSChristof Schmitt /**
1531287ac01aSChristof Schmitt  * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP
1532287ac01aSChristof Schmitt  * @port: The "boxed" port.
1533287ac01aSChristof Schmitt  * @id: The debug trace id.
1534287ac01aSChristof Schmitt  * @id: Reference for the debug trace.
1535287ac01aSChristof Schmitt  */
15365ffd51a5SSwen Schillig void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref)
1537d736a27bSAndreas Herrmann {
1538d736a27bSAndreas Herrmann 	unsigned long flags;
1539d736a27bSAndreas Herrmann 
1540d736a27bSAndreas Herrmann 	read_lock_irqsave(&zfcp_data.config_lock, flags);
1541698ec016SMartin Peschke 	zfcp_erp_modify_port_status(port, id, ref,
1542698ec016SMartin Peschke 				    ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
1543d736a27bSAndreas Herrmann 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
15449467a9b3SMartin Peschke 	zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
1545d736a27bSAndreas Herrmann }
1546d736a27bSAndreas Herrmann 
1547287ac01aSChristof Schmitt /**
1548287ac01aSChristof Schmitt  * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP
1549287ac01aSChristof Schmitt  * @port: The "boxed" unit.
1550287ac01aSChristof Schmitt  * @id: The debug trace id.
1551287ac01aSChristof Schmitt  * @id: Reference for the debug trace.
1552287ac01aSChristof Schmitt  */
15535ffd51a5SSwen Schillig void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref)
1554d736a27bSAndreas Herrmann {
1555698ec016SMartin Peschke 	zfcp_erp_modify_unit_status(unit, id, ref,
1556698ec016SMartin Peschke 				    ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
15579467a9b3SMartin Peschke 	zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
1558d736a27bSAndreas Herrmann }
1559d736a27bSAndreas Herrmann 
1560287ac01aSChristof Schmitt /**
1561287ac01aSChristof Schmitt  * zfcp_erp_port_access_denied - Adapter denied access to port.
1562287ac01aSChristof Schmitt  * @port: port where access has been denied
1563287ac01aSChristof Schmitt  * @id: id for debug trace
1564287ac01aSChristof Schmitt  * @ref: reference for debug trace
1565287ac01aSChristof Schmitt  *
1566287ac01aSChristof Schmitt  * Since the adapter has denied access, stop using the port and the
1567287ac01aSChristof Schmitt  * attached units.
1568287ac01aSChristof Schmitt  */
15695ffd51a5SSwen Schillig void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref)
15701da177e4SLinus Torvalds {
15711da177e4SLinus Torvalds 	unsigned long flags;
15721da177e4SLinus Torvalds 
15731da177e4SLinus Torvalds 	read_lock_irqsave(&zfcp_data.config_lock, flags);
1574698ec016SMartin Peschke 	zfcp_erp_modify_port_status(port, id, ref,
1575d736a27bSAndreas Herrmann 				    ZFCP_STATUS_COMMON_ERP_FAILED |
1576698ec016SMartin Peschke 				    ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
15771da177e4SLinus Torvalds 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
15781da177e4SLinus Torvalds }
15791da177e4SLinus Torvalds 
1580287ac01aSChristof Schmitt /**
1581287ac01aSChristof Schmitt  * zfcp_erp_unit_access_denied - Adapter denied access to unit.
1582287ac01aSChristof Schmitt  * @unit: unit where access has been denied
1583287ac01aSChristof Schmitt  * @id: id for debug trace
1584287ac01aSChristof Schmitt  * @ref: reference for debug trace
1585287ac01aSChristof Schmitt  *
1586287ac01aSChristof Schmitt  * Since the adapter has denied access, stop using the unit.
1587287ac01aSChristof Schmitt  */
15885ffd51a5SSwen Schillig void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, char *id, void *ref)
15891da177e4SLinus Torvalds {
1590698ec016SMartin Peschke 	zfcp_erp_modify_unit_status(unit, id, ref,
1591d736a27bSAndreas Herrmann 				    ZFCP_STATUS_COMMON_ERP_FAILED |
1592698ec016SMartin Peschke 				    ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
15931da177e4SLinus Torvalds }
15941da177e4SLinus Torvalds 
15955ffd51a5SSwen Schillig static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, char *id,
1596287ac01aSChristof Schmitt 					 void *ref)
1597287ac01aSChristof Schmitt {
1598287ac01aSChristof Schmitt 	int status = atomic_read(&unit->status);
1599287ac01aSChristof Schmitt 	if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
1600287ac01aSChristof Schmitt 			ZFCP_STATUS_COMMON_ACCESS_BOXED)))
1601287ac01aSChristof Schmitt 		return;
1602287ac01aSChristof Schmitt 
1603287ac01aSChristof Schmitt 	zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
1604287ac01aSChristof Schmitt }
1605287ac01aSChristof Schmitt 
16065ffd51a5SSwen Schillig static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id,
1607287ac01aSChristof Schmitt 					 void *ref)
1608287ac01aSChristof Schmitt {
1609287ac01aSChristof Schmitt 	struct zfcp_unit *unit;
1610287ac01aSChristof Schmitt 	int status = atomic_read(&port->status);
1611287ac01aSChristof Schmitt 
1612287ac01aSChristof Schmitt 	if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
1613287ac01aSChristof Schmitt 			ZFCP_STATUS_COMMON_ACCESS_BOXED))) {
1614287ac01aSChristof Schmitt 		list_for_each_entry(unit, &port->unit_list_head, list)
1615287ac01aSChristof Schmitt 				    zfcp_erp_unit_access_changed(unit, id, ref);
1616287ac01aSChristof Schmitt 		return;
1617287ac01aSChristof Schmitt 	}
1618287ac01aSChristof Schmitt 
1619287ac01aSChristof Schmitt 	zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
1620287ac01aSChristof Schmitt }
1621287ac01aSChristof Schmitt 
1622287ac01aSChristof Schmitt /**
1623287ac01aSChristof Schmitt  * zfcp_erp_adapter_access_changed - Process change in adapter ACT
1624287ac01aSChristof Schmitt  * @adapter: Adapter where the Access Control Table (ACT) changed
1625287ac01aSChristof Schmitt  * @id: Id for debug trace
1626287ac01aSChristof Schmitt  * @ref: Reference for debug trace
1627287ac01aSChristof Schmitt  */
16285ffd51a5SSwen Schillig void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id,
16291f6f7129SMartin Peschke 				     void *ref)
16301da177e4SLinus Torvalds {
16311da177e4SLinus Torvalds 	struct zfcp_port *port;
16321da177e4SLinus Torvalds 	unsigned long flags;
16331da177e4SLinus Torvalds 
1634aef4a983SMaxim Shchetynin 	if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
1635aef4a983SMaxim Shchetynin 		return;
1636aef4a983SMaxim Shchetynin 
16371da177e4SLinus Torvalds 	read_lock_irqsave(&zfcp_data.config_lock, flags);
16381da177e4SLinus Torvalds 	list_for_each_entry(port, &adapter->port_list_head, list)
16399467a9b3SMartin Peschke 		zfcp_erp_port_access_changed(port, id, ref);
16401da177e4SLinus Torvalds 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
16411da177e4SLinus Torvalds }
1642