blob: 373567eda8f667c9846b09ace239637a51e570e2 [file] [log] [blame]
Swen Schillig41fa2ad2007-09-07 09:15:31 +02001/*
Christof Schmitt553448f2008-06-10 18:20:58 +02002 * zfcp device driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Christof Schmitt553448f2008-06-10 18:20:58 +02004 * Error Recovery Procedures (ERP).
Swen Schillig41fa2ad2007-09-07 09:15:31 +02005 *
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01006 * Copyright IBM Corporation 2002, 2009
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8
Christof Schmittecf39d42008-12-25 13:39:53 +01009#define KMSG_COMPONENT "zfcp"
10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include "zfcp_ext.h"
13
Christof Schmitt287ac012008-07-02 10:56:40 +020014#define ZFCP_MAX_ERPS 3
Linus Torvalds1da177e2005-04-16 15:20:36 -070015
Christof Schmitt287ac012008-07-02 10:56:40 +020016enum zfcp_erp_act_flags {
17 ZFCP_STATUS_ERP_TIMEDOUT = 0x10000000,
18 ZFCP_STATUS_ERP_CLOSE_ONLY = 0x01000000,
19 ZFCP_STATUS_ERP_DISMISSING = 0x00100000,
20 ZFCP_STATUS_ERP_DISMISSED = 0x00200000,
21 ZFCP_STATUS_ERP_LOWMEM = 0x00400000,
22};
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
Christof Schmitt287ac012008-07-02 10:56:40 +020024enum zfcp_erp_steps {
25 ZFCP_ERP_STEP_UNINITIALIZED = 0x0000,
26 ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001,
27 ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010,
28 ZFCP_ERP_STEP_PORT_CLOSING = 0x0100,
Christof Schmitt287ac012008-07-02 10:56:40 +020029 ZFCP_ERP_STEP_PORT_OPENING = 0x0800,
30 ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000,
31 ZFCP_ERP_STEP_UNIT_OPENING = 0x2000,
32};
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
Christof Schmitt287ac012008-07-02 10:56:40 +020034enum zfcp_erp_act_type {
35 ZFCP_ERP_ACTION_REOPEN_UNIT = 1,
36 ZFCP_ERP_ACTION_REOPEN_PORT = 2,
37 ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3,
38 ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4,
39};
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
Christof Schmitt287ac012008-07-02 10:56:40 +020041enum zfcp_erp_act_state {
42 ZFCP_ERP_ACTION_RUNNING = 1,
43 ZFCP_ERP_ACTION_READY = 2,
44};
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
Christof Schmitt287ac012008-07-02 10:56:40 +020046enum zfcp_erp_act_result {
47 ZFCP_ERP_SUCCEEDED = 0,
48 ZFCP_ERP_FAILED = 1,
49 ZFCP_ERP_CONTINUES = 2,
50 ZFCP_ERP_EXIT = 3,
51 ZFCP_ERP_DISMISSED = 4,
52 ZFCP_ERP_NOMEM = 5,
53};
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Christof Schmitt287ac012008-07-02 10:56:40 +020055static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask)
Andreas Herrmann2abbe862006-09-18 22:29:56 +020056{
Swen Schillig5ffd51a2009-03-02 13:09:04 +010057 zfcp_erp_modify_adapter_status(adapter, "erablk1", NULL,
Christof Schmitt287ac012008-07-02 10:56:40 +020058 ZFCP_STATUS_COMMON_UNBLOCKED | mask,
59 ZFCP_CLEAR);
Andreas Herrmann2abbe862006-09-18 22:29:56 +020060}
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
Christof Schmitt287ac012008-07-02 10:56:40 +020062static int zfcp_erp_action_exists(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063{
Christof Schmitt287ac012008-07-02 10:56:40 +020064 struct zfcp_erp_action *curr_act;
65
66 list_for_each_entry(curr_act, &act->adapter->erp_running_head, list)
67 if (act == curr_act)
68 return ZFCP_ERP_ACTION_RUNNING;
69 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070}
71
Christof Schmitt287ac012008-07-02 10:56:40 +020072static void zfcp_erp_action_ready(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -070073{
Christof Schmitt287ac012008-07-02 10:56:40 +020074 struct zfcp_adapter *adapter = act->adapter;
75
76 list_move(&act->list, &act->adapter->erp_ready_head);
Swen Schillig57717102009-08-18 15:43:21 +020077 zfcp_dbf_rec_action("erardy1", act);
Christof Schmitt287ac012008-07-02 10:56:40 +020078 up(&adapter->erp_ready_sem);
Swen Schillig57717102009-08-18 15:43:21 +020079 zfcp_dbf_rec_thread("erardy2", adapter->dbf);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080}
81
Christof Schmitt287ac012008-07-02 10:56:40 +020082static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -070083{
Christof Schmitt287ac012008-07-02 10:56:40 +020084 act->status |= ZFCP_STATUS_ERP_DISMISSED;
85 if (zfcp_erp_action_exists(act) == ZFCP_ERP_ACTION_RUNNING)
86 zfcp_erp_action_ready(act);
87}
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
Christof Schmitt287ac012008-07-02 10:56:40 +020089static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
90{
91 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
92 zfcp_erp_action_dismiss(&unit->erp_action);
93}
94
95static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
96{
97 struct zfcp_unit *unit;
98
99 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
100 zfcp_erp_action_dismiss(&port->erp_action);
101 else
102 list_for_each_entry(unit, &port->unit_list_head, list)
103 zfcp_erp_action_dismiss_unit(unit);
104}
105
106static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
107{
108 struct zfcp_port *port;
109
110 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
111 zfcp_erp_action_dismiss(&adapter->erp_action);
112 else
113 list_for_each_entry(port, &adapter->port_list_head, list)
114 zfcp_erp_action_dismiss_port(port);
115}
116
117static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
118 struct zfcp_port *port,
119 struct zfcp_unit *unit)
120{
121 int need = want;
122 int u_status, p_status, a_status;
123
124 switch (want) {
125 case ZFCP_ERP_ACTION_REOPEN_UNIT:
126 u_status = atomic_read(&unit->status);
127 if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE)
128 return 0;
129 p_status = atomic_read(&port->status);
130 if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) ||
131 p_status & ZFCP_STATUS_COMMON_ERP_FAILED)
132 return 0;
133 if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
134 need = ZFCP_ERP_ACTION_REOPEN_PORT;
135 /* fall through */
136 case ZFCP_ERP_ACTION_REOPEN_PORT:
137 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
138 p_status = atomic_read(&port->status);
139 if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
140 return 0;
141 a_status = atomic_read(&adapter->status);
142 if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) ||
143 a_status & ZFCP_STATUS_COMMON_ERP_FAILED)
144 return 0;
145 if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))
146 need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
147 /* fall through */
148 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
149 a_status = atomic_read(&adapter->status);
150 if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
151 return 0;
152 }
153
154 return need;
155}
156
157static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
158 struct zfcp_adapter *adapter,
159 struct zfcp_port *port,
160 struct zfcp_unit *unit)
161{
162 struct zfcp_erp_action *erp_action;
163 u32 status = 0;
164
165 switch (need) {
166 case ZFCP_ERP_ACTION_REOPEN_UNIT:
167 zfcp_unit_get(unit);
168 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status);
169 erp_action = &unit->erp_action;
170 if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING))
171 status = ZFCP_STATUS_ERP_CLOSE_ONLY;
172 break;
173
174 case ZFCP_ERP_ACTION_REOPEN_PORT:
175 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
176 zfcp_port_get(port);
177 zfcp_erp_action_dismiss_port(port);
178 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
179 erp_action = &port->erp_action;
180 if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
181 status = ZFCP_STATUS_ERP_CLOSE_ONLY;
182 break;
183
184 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
185 zfcp_adapter_get(adapter);
186 zfcp_erp_action_dismiss_adapter(adapter);
187 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
188 erp_action = &adapter->erp_action;
189 if (!(atomic_read(&adapter->status) &
190 ZFCP_STATUS_COMMON_RUNNING))
191 status = ZFCP_STATUS_ERP_CLOSE_ONLY;
192 break;
193
194 default:
195 return NULL;
196 }
197
198 memset(erp_action, 0, sizeof(struct zfcp_erp_action));
199 erp_action->adapter = adapter;
200 erp_action->port = port;
201 erp_action->unit = unit;
202 erp_action->action = need;
203 erp_action->status = status;
204
205 return erp_action;
206}
207
208static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
209 struct zfcp_port *port,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100210 struct zfcp_unit *unit, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200211{
212 int retval = 1, need;
213 struct zfcp_erp_action *act = NULL;
214
215 if (!(atomic_read(&adapter->status) &
216 ZFCP_STATUS_ADAPTER_ERP_THREAD_UP))
217 return -EIO;
218
219 need = zfcp_erp_required_act(want, adapter, port, unit);
220 if (!need)
221 goto out;
222
223 atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
224 act = zfcp_erp_setup_act(need, adapter, port, unit);
225 if (!act)
226 goto out;
227 ++adapter->erp_total_count;
228 list_add_tail(&act->list, &adapter->erp_ready_head);
229 up(&adapter->erp_ready_sem);
Swen Schillig57717102009-08-18 15:43:21 +0200230 zfcp_dbf_rec_thread("eracte1", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200231 retval = 0;
232 out:
Swen Schillig57717102009-08-18 15:43:21 +0200233 zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, unit);
Christof Schmitt287ac012008-07-02 10:56:40 +0200234 return retval;
235}
236
237static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100238 int clear_mask, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200239{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 zfcp_erp_adapter_block(adapter, clear_mask);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100241 zfcp_scsi_schedule_rports_block(adapter);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Christof Schmitt287ac012008-07-02 10:56:40 +0200243 /* ensure propagation of failed status to new devices */
244 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100245 zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200246 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200248 return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
249 adapter, NULL, NULL, id, ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250}
251
252/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200253 * zfcp_erp_adapter_reopen - Reopen adapter.
254 * @adapter: Adapter to reopen.
255 * @clear: Status flags to clear.
256 * @id: Id for debug trace event.
257 * @ref: Reference for debug trace event.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200259void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100260 char *id, void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261{
Christof Schmitt287ac012008-07-02 10:56:40 +0200262 unsigned long flags;
263
264 read_lock_irqsave(&zfcp_data.config_lock, flags);
265 write_lock(&adapter->erp_lock);
266 _zfcp_erp_adapter_reopen(adapter, clear, id, ref);
267 write_unlock(&adapter->erp_lock);
268 read_unlock_irqrestore(&zfcp_data.config_lock, flags);
269}
270
271/**
272 * zfcp_erp_adapter_shutdown - Shutdown adapter.
273 * @adapter: Adapter to shut down.
274 * @clear: Status flags to clear.
275 * @id: Id for debug trace event.
276 * @ref: Reference for debug trace event.
277 */
278void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100279 char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200280{
281 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
282 zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref);
283}
284
285/**
286 * zfcp_erp_port_shutdown - Shutdown port
287 * @port: Port to shut down.
288 * @clear: Status flags to clear.
289 * @id: Id for debug trace event.
290 * @ref: Reference for debug trace event.
291 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100292void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id,
293 void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200294{
295 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
296 zfcp_erp_port_reopen(port, clear | flags, id, ref);
297}
298
299/**
300 * zfcp_erp_unit_shutdown - Shutdown unit
301 * @unit: Unit to shut down.
302 * @clear: Status flags to clear.
303 * @id: Id for debug trace event.
304 * @ref: Reference for debug trace event.
305 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100306void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, char *id,
307 void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200308{
309 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
310 zfcp_erp_unit_reopen(unit, clear | flags, id, ref);
311}
312
313static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
314{
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100315 zfcp_erp_modify_port_status(port, "erpblk1", NULL,
Christof Schmitt287ac012008-07-02 10:56:40 +0200316 ZFCP_STATUS_COMMON_UNBLOCKED | clear,
317 ZFCP_CLEAR);
318}
319
320static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100321 int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200322{
323 zfcp_erp_port_block(port, clear);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100324 zfcp_scsi_schedule_rport_block(port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200325
326 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
327 return;
328
329 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
330 port->adapter, port, NULL, id, ref);
331}
332
333/**
334 * zfcp_erp_port_forced_reopen - Forced close of port and open again
335 * @port: Port to force close and to reopen.
336 * @id: Id for debug trace event.
337 * @ref: Reference for debug trace event.
338 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100339void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +0200340 void *ref)
341{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 unsigned long flags;
343 struct zfcp_adapter *adapter = port->adapter;
344
345 read_lock_irqsave(&zfcp_data.config_lock, flags);
346 write_lock(&adapter->erp_lock);
Christof Schmitt287ac012008-07-02 10:56:40 +0200347 _zfcp_erp_port_forced_reopen(port, clear, id, ref);
348 write_unlock(&adapter->erp_lock);
349 read_unlock_irqrestore(&zfcp_data.config_lock, flags);
350}
351
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100352static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +0200353 void *ref)
354{
355 zfcp_erp_port_block(port, clear);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100356 zfcp_scsi_schedule_rport_block(port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200357
358 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
359 /* ensure propagation of failed status to new devices */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100360 zfcp_erp_port_failed(port, "erpreo1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200361 return -EIO;
362 }
363
364 return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
365 port->adapter, port, NULL, id, ref);
366}
367
368/**
369 * zfcp_erp_port_reopen - trigger remote port recovery
370 * @port: port to recover
371 * @clear_mask: flags in port status to be cleared
372 *
373 * Returns 0 if recovery has been triggered, < 0 if not.
374 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100375int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200376{
377 unsigned long flags;
378 int retval;
379 struct zfcp_adapter *adapter = port->adapter;
380
381 read_lock_irqsave(&zfcp_data.config_lock, flags);
382 write_lock(&adapter->erp_lock);
383 retval = _zfcp_erp_port_reopen(port, clear, id, ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 write_unlock(&adapter->erp_lock);
385 read_unlock_irqrestore(&zfcp_data.config_lock, flags);
386
387 return retval;
388}
389
Christof Schmitt287ac012008-07-02 10:56:40 +0200390static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391{
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100392 zfcp_erp_modify_unit_status(unit, "erublk1", NULL,
Christof Schmitt287ac012008-07-02 10:56:40 +0200393 ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask,
394 ZFCP_CLEAR);
395}
396
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100397static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +0200398 void *ref)
399{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 struct zfcp_adapter *adapter = unit->port->adapter;
401
Christof Schmitt287ac012008-07-02 10:56:40 +0200402 zfcp_erp_unit_block(unit, clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Christof Schmitt287ac012008-07-02 10:56:40 +0200404 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
405 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Christof Schmitt287ac012008-07-02 10:56:40 +0200407 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT,
408 adapter, unit->port, unit, id, ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409}
410
411/**
412 * zfcp_erp_unit_reopen - initiate reopen of a unit
413 * @unit: unit to be reopened
414 * @clear_mask: specifies flags in unit status to be cleared
415 * Return: 0 on success, < 0 on error
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100417void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
418 void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +0200421 struct zfcp_port *port = unit->port;
422 struct zfcp_adapter *adapter = port->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
424 read_lock_irqsave(&zfcp_data.config_lock, flags);
425 write_lock(&adapter->erp_lock);
Christof Schmitt287ac012008-07-02 10:56:40 +0200426 _zfcp_erp_unit_reopen(unit, clear, id, ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 write_unlock(&adapter->erp_lock);
428 read_unlock_irqrestore(&zfcp_data.config_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429}
430
Christof Schmitt287ac012008-07-02 10:56:40 +0200431static int status_change_set(unsigned long mask, atomic_t *status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
Christof Schmitt287ac012008-07-02 10:56:40 +0200433 return (atomic_read(status) ^ mask) & mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434}
435
Christof Schmitt287ac012008-07-02 10:56:40 +0200436static int status_change_clear(unsigned long mask, atomic_t *status)
Martin Peschke698ec0162008-03-27 14:22:02 +0100437{
Christof Schmitt287ac012008-07-02 10:56:40 +0200438 return atomic_read(status) & mask;
Martin Peschke698ec0162008-03-27 14:22:02 +0100439}
440
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200441static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442{
Christof Schmitt287ac012008-07-02 10:56:40 +0200443 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status))
Swen Schillig57717102009-08-18 15:43:21 +0200444 zfcp_dbf_rec_adapter("eraubl1", NULL, adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200445 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446}
447
Christof Schmitt287ac012008-07-02 10:56:40 +0200448static void zfcp_erp_port_unblock(struct zfcp_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
Christof Schmitt287ac012008-07-02 10:56:40 +0200450 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status))
Swen Schillig57717102009-08-18 15:43:21 +0200451 zfcp_dbf_rec_port("erpubl1", NULL, port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200452 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453}
454
Christof Schmitt287ac012008-07-02 10:56:40 +0200455static void zfcp_erp_unit_unblock(struct zfcp_unit *unit)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456{
Christof Schmitt287ac012008-07-02 10:56:40 +0200457 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))
Swen Schillig57717102009-08-18 15:43:21 +0200458 zfcp_dbf_rec_unit("eruubl1", NULL, unit);
Christof Schmitt287ac012008-07-02 10:56:40 +0200459 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460}
461
Christof Schmitt287ac012008-07-02 10:56:40 +0200462static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463{
Christof Schmitt287ac012008-07-02 10:56:40 +0200464 list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
Swen Schillig57717102009-08-18 15:43:21 +0200465 zfcp_dbf_rec_action("erator1", erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466}
467
Christof Schmitt287ac012008-07-02 10:56:40 +0200468static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469{
Christof Schmitt287ac012008-07-02 10:56:40 +0200470 struct zfcp_adapter *adapter = act->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
Christof Schmitt287ac012008-07-02 10:56:40 +0200472 if (!act->fsf_req)
473 return;
474
475 spin_lock(&adapter->req_list_lock);
476 if (zfcp_reqlist_find_safe(adapter, act->fsf_req) &&
477 act->fsf_req->erp_action == act) {
478 if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
479 ZFCP_STATUS_ERP_TIMEDOUT)) {
480 act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
Swen Schillig57717102009-08-18 15:43:21 +0200481 zfcp_dbf_rec_action("erscf_1", act);
Martin Petermann7ea633f2008-11-04 16:35:11 +0100482 act->fsf_req->erp_action = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200484 if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
Swen Schillig57717102009-08-18 15:43:21 +0200485 zfcp_dbf_rec_action("erscf_2", act);
Swen Schillig058b8642009-08-18 15:43:14 +0200486 if (act->fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
Christof Schmitt287ac012008-07-02 10:56:40 +0200487 act->fsf_req = NULL;
488 } else
489 act->fsf_req = NULL;
490 spin_unlock(&adapter->req_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491}
492
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200493/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200494 * zfcp_erp_notify - Trigger ERP action.
495 * @erp_action: ERP action to continue.
496 * @set_mask: ERP action status flags to set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200498void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
500 struct zfcp_adapter *adapter = erp_action->adapter;
501 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
503 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200504 if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
505 erp_action->status |= set_mask;
506 zfcp_erp_action_ready(erp_action);
507 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509}
510
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200511/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200512 * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request
513 * @data: ERP action (from timer data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200515void zfcp_erp_timeout_handler(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516{
Christof Schmitt287ac012008-07-02 10:56:40 +0200517 struct zfcp_erp_action *act = (struct zfcp_erp_action *) data;
518 zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519}
520
Christof Schmitt287ac012008-07-02 10:56:40 +0200521static void zfcp_erp_memwait_handler(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522{
Christof Schmitt287ac012008-07-02 10:56:40 +0200523 zfcp_erp_notify((struct zfcp_erp_action *)data, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524}
525
Christof Schmitt287ac012008-07-02 10:56:40 +0200526static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 init_timer(&erp_action->timer);
529 erp_action->timer.function = zfcp_erp_memwait_handler;
530 erp_action->timer.data = (unsigned long) erp_action;
Christof Schmitt287ac012008-07-02 10:56:40 +0200531 erp_action->timer.expires = jiffies + HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 add_timer(&erp_action->timer);
Christof Schmitt287ac012008-07-02 10:56:40 +0200533}
534
535static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100536 int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200537{
538 struct zfcp_port *port;
539
540 list_for_each_entry(port, &adapter->port_list_head, list)
Swen Schillig5ab944f2008-10-01 12:42:17 +0200541 _zfcp_erp_port_reopen(port, clear, id, ref);
Christof Schmitt287ac012008-07-02 10:56:40 +0200542}
543
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100544static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
545 char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200546{
547 struct zfcp_unit *unit;
548
549 list_for_each_entry(unit, &port->unit_list_head, list)
550 _zfcp_erp_unit_reopen(unit, clear, id, ref);
551}
552
Christof Schmitt85600f72009-07-13 15:06:09 +0200553static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
Christof Schmitt287ac012008-07-02 10:56:40 +0200554{
Christof Schmitt287ac012008-07-02 10:56:40 +0200555 switch (act->action) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200556 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitt85600f72009-07-13 15:06:09 +0200557 _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200558 break;
Christof Schmitt287ac012008-07-02 10:56:40 +0200559 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
Christof Schmitt85600f72009-07-13 15:06:09 +0200560 _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200561 break;
Christof Schmitt287ac012008-07-02 10:56:40 +0200562 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitt85600f72009-07-13 15:06:09 +0200563 _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200564 break;
Christof Schmitt287ac012008-07-02 10:56:40 +0200565 case ZFCP_ERP_ACTION_REOPEN_UNIT:
Christof Schmitt85600f72009-07-13 15:06:09 +0200566 _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL);
567 break;
568 }
569}
570
571static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act)
572{
573 switch (act->action) {
574 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
575 _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL);
576 break;
577 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
578 _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL);
579 break;
580 case ZFCP_ERP_ACTION_REOPEN_PORT:
581 _zfcp_erp_unit_reopen_all(act->port, 0, "ersfs_3", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200582 break;
583 }
584}
585
586static void zfcp_erp_wakeup(struct zfcp_adapter *adapter)
587{
588 unsigned long flags;
589
590 read_lock_irqsave(&zfcp_data.config_lock, flags);
591 read_lock(&adapter->erp_lock);
592 if (list_empty(&adapter->erp_ready_head) &&
593 list_empty(&adapter->erp_running_head)) {
594 atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING,
595 &adapter->status);
596 wake_up(&adapter->erp_done_wqh);
597 }
598 read_unlock(&adapter->erp_lock);
599 read_unlock_irqrestore(&zfcp_data.config_lock, flags);
600}
601
602static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
603{
Swen Schillig564e1c82009-08-18 15:43:19 +0200604 struct zfcp_qdio *qdio = act->adapter->qdio;
605
606 if (zfcp_qdio_open(qdio))
Christof Schmitt287ac012008-07-02 10:56:40 +0200607 return ZFCP_ERP_FAILED;
Swen Schillig564e1c82009-08-18 15:43:19 +0200608 init_waitqueue_head(&qdio->req_q_wq);
Christof Schmitt287ac012008-07-02 10:56:40 +0200609 atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status);
610 return ZFCP_ERP_SUCCEEDED;
611}
612
613static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
614{
615 struct zfcp_port *port;
616 port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0,
617 adapter->peer_d_id);
618 if (IS_ERR(port)) /* error or port already attached */
619 return;
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100620 _zfcp_erp_port_reopen(port, 0, "ereptp1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200621}
622
623static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
624{
625 int retries;
626 int sleep = 1;
627 struct zfcp_adapter *adapter = erp_action->adapter;
628
629 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
630
631 for (retries = 7; retries; retries--) {
632 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
633 &adapter->status);
634 write_lock_irq(&adapter->erp_lock);
635 zfcp_erp_action_to_running(erp_action);
636 write_unlock_irq(&adapter->erp_lock);
637 if (zfcp_fsf_exchange_config_data(erp_action)) {
638 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
639 &adapter->status);
640 return ZFCP_ERP_FAILED;
641 }
642
Swen Schillig57717102009-08-18 15:43:21 +0200643 zfcp_dbf_rec_thread_lock("erasfx1", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200644 down(&adapter->erp_ready_sem);
Swen Schillig57717102009-08-18 15:43:21 +0200645 zfcp_dbf_rec_thread_lock("erasfx2", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200646 if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
647 break;
648
649 if (!(atomic_read(&adapter->status) &
650 ZFCP_STATUS_ADAPTER_HOST_CON_INIT))
651 break;
652
653 ssleep(sleep);
654 sleep *= 2;
655 }
656
657 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
658 &adapter->status);
659
660 if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK))
661 return ZFCP_ERP_FAILED;
662
663 if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
664 zfcp_erp_enqueue_ptp_port(adapter);
665
666 return ZFCP_ERP_SUCCEEDED;
667}
668
669static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act)
670{
671 int ret;
672 struct zfcp_adapter *adapter = act->adapter;
673
Christof Schmitt287ac012008-07-02 10:56:40 +0200674 write_lock_irq(&adapter->erp_lock);
675 zfcp_erp_action_to_running(act);
676 write_unlock_irq(&adapter->erp_lock);
677
678 ret = zfcp_fsf_exchange_port_data(act);
679 if (ret == -EOPNOTSUPP)
680 return ZFCP_ERP_SUCCEEDED;
681 if (ret)
682 return ZFCP_ERP_FAILED;
683
Swen Schillig57717102009-08-18 15:43:21 +0200684 zfcp_dbf_rec_thread_lock("erasox1", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200685 down(&adapter->erp_ready_sem);
Swen Schillig57717102009-08-18 15:43:21 +0200686 zfcp_dbf_rec_thread_lock("erasox2", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200687 if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
688 return ZFCP_ERP_FAILED;
689
690 return ZFCP_ERP_SUCCEEDED;
691}
692
693static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)
694{
695 if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED)
696 return ZFCP_ERP_FAILED;
697
698 if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)
699 return ZFCP_ERP_FAILED;
700
701 atomic_set(&act->adapter->stat_miss, 16);
702 if (zfcp_status_read_refill(act->adapter))
703 return ZFCP_ERP_FAILED;
704
705 return ZFCP_ERP_SUCCEEDED;
706}
707
Swen Schilligcf13c082009-03-02 13:09:03 +0100708static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act)
Christof Schmitt287ac012008-07-02 10:56:40 +0200709{
Christof Schmitt287ac012008-07-02 10:56:40 +0200710 struct zfcp_adapter *adapter = act->adapter;
711
Christof Schmitt287ac012008-07-02 10:56:40 +0200712 /* close queues to ensure that buffers are not accessed by adapter */
Swen Schillig564e1c82009-08-18 15:43:19 +0200713 zfcp_qdio_close(adapter->qdio);
Christof Schmitt287ac012008-07-02 10:56:40 +0200714 zfcp_fsf_req_dismiss_all(adapter);
715 adapter->fsf_req_seq_no = 0;
Christof Schmitt55c770f2009-08-18 15:43:12 +0200716 zfcp_fc_wka_ports_force_offline(adapter->gs);
Christof Schmitt287ac012008-07-02 10:56:40 +0200717 /* all ports and units are closed */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100718 zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL,
Christof Schmitt287ac012008-07-02 10:56:40 +0200719 ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
Swen Schilligcf13c082009-03-02 13:09:03 +0100720
Christof Schmitt287ac012008-07-02 10:56:40 +0200721 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
Swen Schilligcf13c082009-03-02 13:09:03 +0100722 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
723}
724
725static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act)
726{
727 struct zfcp_adapter *adapter = act->adapter;
728
729 if (zfcp_erp_adapter_strategy_open_qdio(act)) {
730 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
731 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
732 &adapter->status);
733 return ZFCP_ERP_FAILED;
734 }
735
736 if (zfcp_erp_adapter_strategy_open_fsf(act)) {
737 zfcp_erp_adapter_strategy_close(act);
738 return ZFCP_ERP_FAILED;
739 }
740
741 atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &adapter->status);
742
743 return ZFCP_ERP_SUCCEEDED;
Christof Schmitt287ac012008-07-02 10:56:40 +0200744}
745
746static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act)
747{
Swen Schilligcf13c082009-03-02 13:09:03 +0100748 struct zfcp_adapter *adapter = act->adapter;
Christof Schmitt287ac012008-07-02 10:56:40 +0200749
Swen Schilligcf13c082009-03-02 13:09:03 +0100750 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN) {
751 zfcp_erp_adapter_strategy_close(act);
752 if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
753 return ZFCP_ERP_EXIT;
754 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200755
Swen Schilligcf13c082009-03-02 13:09:03 +0100756 if (zfcp_erp_adapter_strategy_open(act)) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200757 ssleep(8);
Swen Schilligcf13c082009-03-02 13:09:03 +0100758 return ZFCP_ERP_FAILED;
759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760
Swen Schilligcf13c082009-03-02 13:09:03 +0100761 return ZFCP_ERP_SUCCEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762}
763
Christof Schmitt287ac012008-07-02 10:56:40 +0200764static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765{
Christof Schmitt287ac012008-07-02 10:56:40 +0200766 int retval;
767
768 retval = zfcp_fsf_close_physical_port(act);
769 if (retval == -ENOMEM)
770 return ZFCP_ERP_NOMEM;
771 act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING;
772 if (retval)
773 return ZFCP_ERP_FAILED;
774
775 return ZFCP_ERP_CONTINUES;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776}
777
Christof Schmitt287ac012008-07-02 10:56:40 +0200778static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779{
Christof Schmitta5b11dd2009-03-02 13:08:54 +0100780 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200781}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Christof Schmitt287ac012008-07-02 10:56:40 +0200783static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
784{
785 struct zfcp_port *port = erp_action->port;
786 int status = atomic_read(&port->status);
787
788 switch (erp_action->step) {
789 case ZFCP_ERP_STEP_UNINITIALIZED:
790 zfcp_erp_port_strategy_clearstati(port);
791 if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) &&
792 (status & ZFCP_STATUS_COMMON_OPEN))
793 return zfcp_erp_port_forced_strategy_close(erp_action);
794 else
795 return ZFCP_ERP_FAILED;
796
797 case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
Christof Schmittddb3e0c2009-07-13 15:06:08 +0200798 if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN))
Christof Schmitt287ac012008-07-02 10:56:40 +0200799 return ZFCP_ERP_SUCCEEDED;
800 }
801 return ZFCP_ERP_FAILED;
802}
803
804static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action)
805{
806 int retval;
807
808 retval = zfcp_fsf_close_port(erp_action);
809 if (retval == -ENOMEM)
810 return ZFCP_ERP_NOMEM;
811 erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING;
812 if (retval)
813 return ZFCP_ERP_FAILED;
814 return ZFCP_ERP_CONTINUES;
815}
816
817static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action)
818{
819 int retval;
820
821 retval = zfcp_fsf_open_port(erp_action);
822 if (retval == -ENOMEM)
823 return ZFCP_ERP_NOMEM;
824 erp_action->step = ZFCP_ERP_STEP_PORT_OPENING;
825 if (retval)
826 return ZFCP_ERP_FAILED;
827 return ZFCP_ERP_CONTINUES;
828}
829
Christof Schmitt287ac012008-07-02 10:56:40 +0200830static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
831{
832 struct zfcp_adapter *adapter = act->adapter;
833 struct zfcp_port *port = act->port;
834
835 if (port->wwpn != adapter->peer_wwpn) {
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100836 zfcp_erp_port_failed(port, "eroptp1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200837 return ZFCP_ERP_FAILED;
838 }
839 port->d_id = adapter->peer_d_id;
Christof Schmitt287ac012008-07-02 10:56:40 +0200840 return zfcp_erp_port_strategy_open_port(act);
841}
842
843static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
844{
845 struct zfcp_adapter *adapter = act->adapter;
846 struct zfcp_port *port = act->port;
Christof Schmitt287ac012008-07-02 10:56:40 +0200847 int p_status = atomic_read(&port->status);
848
849 switch (act->step) {
850 case ZFCP_ERP_STEP_UNINITIALIZED:
851 case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
852 case ZFCP_ERP_STEP_PORT_CLOSING:
853 if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
854 return zfcp_erp_open_ptp_port(act);
Christof Schmittb98478d2008-12-19 16:56:59 +0100855 if (!port->d_id) {
Swen Schillig947a9ac2009-03-02 13:09:10 +0100856 zfcp_port_get(port);
Swen Schillig45446832009-08-18 15:43:17 +0200857 if (!queue_work(adapter->work_queue,
Swen Schillig947a9ac2009-03-02 13:09:10 +0100858 &port->gid_pn_work))
859 zfcp_port_put(port);
Christof Schmitt799b76d2009-08-18 15:43:20 +0200860 return ZFCP_ERP_EXIT;
Christof Schmitt287ac012008-07-02 10:56:40 +0200861 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200862 return zfcp_erp_port_strategy_open_port(act);
863
864 case ZFCP_ERP_STEP_PORT_OPENING:
865 /* D_ID might have changed during open */
Swen Schillig5ab944f2008-10-01 12:42:17 +0200866 if (p_status & ZFCP_STATUS_COMMON_OPEN) {
Christof Schmittb98478d2008-12-19 16:56:59 +0100867 if (port->d_id)
Swen Schillig5ab944f2008-10-01 12:42:17 +0200868 return ZFCP_ERP_SUCCEEDED;
869 else {
870 act->step = ZFCP_ERP_STEP_PORT_CLOSING;
871 return ZFCP_ERP_CONTINUES;
872 }
Swen Schillig5ab944f2008-10-01 12:42:17 +0200873 }
Swen Schilligea460a82009-05-15 13:18:20 +0200874 if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
875 port->d_id = 0;
876 _zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL);
877 return ZFCP_ERP_EXIT;
878 }
879 /* fall through otherwise */
Christof Schmitt287ac012008-07-02 10:56:40 +0200880 }
881 return ZFCP_ERP_FAILED;
882}
883
Christof Schmitt287ac012008-07-02 10:56:40 +0200884static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
885{
886 struct zfcp_port *port = erp_action->port;
887
Swen Schillig5ab944f2008-10-01 12:42:17 +0200888 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC)
889 goto close_init_done;
890
Christof Schmitt287ac012008-07-02 10:56:40 +0200891 switch (erp_action->step) {
892 case ZFCP_ERP_STEP_UNINITIALIZED:
893 zfcp_erp_port_strategy_clearstati(port);
894 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)
895 return zfcp_erp_port_strategy_close(erp_action);
896 break;
897
898 case ZFCP_ERP_STEP_PORT_CLOSING:
899 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN)
900 return ZFCP_ERP_FAILED;
901 break;
902 }
Swen Schillig5ab944f2008-10-01 12:42:17 +0200903
904close_init_done:
Christof Schmitt287ac012008-07-02 10:56:40 +0200905 if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
906 return ZFCP_ERP_EXIT;
Christof Schmitt287ac012008-07-02 10:56:40 +0200907
Swen Schillig5ab944f2008-10-01 12:42:17 +0200908 return zfcp_erp_port_strategy_open_common(erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909}
910
Christof Schmitt287ac012008-07-02 10:56:40 +0200911static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912{
Swen Schillig44cc76f2008-10-01 12:42:16 +0200913 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
Christof Schmitt287ac012008-07-02 10:56:40 +0200914 ZFCP_STATUS_UNIT_SHARED |
915 ZFCP_STATUS_UNIT_READONLY,
916 &unit->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917}
918
Christof Schmitt287ac012008-07-02 10:56:40 +0200919static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action)
920{
921 int retval = zfcp_fsf_close_unit(erp_action);
922 if (retval == -ENOMEM)
923 return ZFCP_ERP_NOMEM;
924 erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING;
925 if (retval)
926 return ZFCP_ERP_FAILED;
927 return ZFCP_ERP_CONTINUES;
928}
929
930static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action)
931{
932 int retval = zfcp_fsf_open_unit(erp_action);
933 if (retval == -ENOMEM)
934 return ZFCP_ERP_NOMEM;
935 erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING;
936 if (retval)
937 return ZFCP_ERP_FAILED;
938 return ZFCP_ERP_CONTINUES;
939}
940
941static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action)
942{
943 struct zfcp_unit *unit = erp_action->unit;
944
945 switch (erp_action->step) {
946 case ZFCP_ERP_STEP_UNINITIALIZED:
947 zfcp_erp_unit_strategy_clearstati(unit);
948 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
949 return zfcp_erp_unit_strategy_close(erp_action);
950 /* already closed, fall through */
951 case ZFCP_ERP_STEP_UNIT_CLOSING:
952 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
953 return ZFCP_ERP_FAILED;
954 if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
955 return ZFCP_ERP_EXIT;
956 return zfcp_erp_unit_strategy_open(erp_action);
957
958 case ZFCP_ERP_STEP_UNIT_OPENING:
959 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
960 return ZFCP_ERP_SUCCEEDED;
961 }
962 return ZFCP_ERP_FAILED;
963}
964
965static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result)
966{
967 switch (result) {
968 case ZFCP_ERP_SUCCEEDED :
969 atomic_set(&unit->erp_counter, 0);
970 zfcp_erp_unit_unblock(unit);
971 break;
972 case ZFCP_ERP_FAILED :
973 atomic_inc(&unit->erp_counter);
Christof Schmittff3b24f2008-10-01 12:42:15 +0200974 if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) {
975 dev_err(&unit->port->adapter->ccw_device->dev,
976 "ERP failed for unit 0x%016Lx on "
977 "port 0x%016Lx\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +0200978 (unsigned long long)unit->fcp_lun,
979 (unsigned long long)unit->port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100980 zfcp_erp_unit_failed(unit, "erusck1", NULL);
Christof Schmittff3b24f2008-10-01 12:42:15 +0200981 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200982 break;
983 }
984
985 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
986 zfcp_erp_unit_block(unit, 0);
987 result = ZFCP_ERP_EXIT;
988 }
989 return result;
990}
991
992static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
993{
994 switch (result) {
995 case ZFCP_ERP_SUCCEEDED :
996 atomic_set(&port->erp_counter, 0);
997 zfcp_erp_port_unblock(port);
998 break;
999
1000 case ZFCP_ERP_FAILED :
1001 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) {
1002 zfcp_erp_port_block(port, 0);
1003 result = ZFCP_ERP_EXIT;
1004 }
1005 atomic_inc(&port->erp_counter);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001006 if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
1007 dev_err(&port->adapter->ccw_device->dev,
1008 "ERP failed for remote port 0x%016Lx\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001009 (unsigned long long)port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001010 zfcp_erp_port_failed(port, "erpsck1", NULL);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001011 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001012 break;
1013 }
1014
1015 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1016 zfcp_erp_port_block(port, 0);
1017 result = ZFCP_ERP_EXIT;
1018 }
1019 return result;
1020}
1021
1022static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter,
1023 int result)
1024{
1025 switch (result) {
1026 case ZFCP_ERP_SUCCEEDED :
1027 atomic_set(&adapter->erp_counter, 0);
1028 zfcp_erp_adapter_unblock(adapter);
1029 break;
1030
1031 case ZFCP_ERP_FAILED :
1032 atomic_inc(&adapter->erp_counter);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001033 if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) {
1034 dev_err(&adapter->ccw_device->dev,
1035 "ERP cannot recover an error "
1036 "on the FCP device\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001037 zfcp_erp_adapter_failed(adapter, "erasck1", NULL);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001038 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001039 break;
1040 }
1041
1042 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1043 zfcp_erp_adapter_block(adapter, 0);
1044 result = ZFCP_ERP_EXIT;
1045 }
1046 return result;
1047}
1048
1049static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action,
1050 int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051{
1052 struct zfcp_adapter *adapter = erp_action->adapter;
1053 struct zfcp_port *port = erp_action->port;
1054 struct zfcp_unit *unit = erp_action->unit;
1055
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 switch (erp_action->action) {
1057
1058 case ZFCP_ERP_ACTION_REOPEN_UNIT:
1059 result = zfcp_erp_strategy_check_unit(unit, result);
1060 break;
1061
1062 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1063 case ZFCP_ERP_ACTION_REOPEN_PORT:
1064 result = zfcp_erp_strategy_check_port(port, result);
1065 break;
1066
1067 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1068 result = zfcp_erp_strategy_check_adapter(adapter, result);
1069 break;
1070 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 return result;
1072}
1073
Christof Schmitt287ac012008-07-02 10:56:40 +02001074static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075{
Christof Schmitt287ac012008-07-02 10:56:40 +02001076 int status = atomic_read(target_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
Christof Schmitt287ac012008-07-02 10:56:40 +02001078 if ((status & ZFCP_STATUS_COMMON_RUNNING) &&
1079 (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1080 return 1; /* take it online */
1081
1082 if (!(status & ZFCP_STATUS_COMMON_RUNNING) &&
1083 !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1084 return 1; /* take it offline */
1085
1086 return 0;
1087}
1088
1089static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
1090{
1091 int action = act->action;
1092 struct zfcp_adapter *adapter = act->adapter;
1093 struct zfcp_port *port = act->port;
1094 struct zfcp_unit *unit = act->unit;
1095 u32 erp_status = act->status;
1096
1097 switch (action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitt287ac012008-07-02 10:56:40 +02001099 if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) {
1100 _zfcp_erp_adapter_reopen(adapter,
1101 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001102 "ersscg1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001103 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 }
1105 break;
1106
1107 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1108 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitt287ac012008-07-02 10:56:40 +02001109 if (zfcp_erp_strat_change_det(&port->status, erp_status)) {
1110 _zfcp_erp_port_reopen(port,
1111 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001112 "ersscg2", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001113 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 }
1115 break;
1116
1117 case ZFCP_ERP_ACTION_REOPEN_UNIT:
Christof Schmitt287ac012008-07-02 10:56:40 +02001118 if (zfcp_erp_strat_change_det(&unit->status, erp_status)) {
1119 _zfcp_erp_unit_reopen(unit,
1120 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001121 "ersscg3", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001122 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 }
1124 break;
1125 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001126 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127}
1128
Christof Schmitt287ac012008-07-02 10:56:40 +02001129static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130{
Christof Schmitt287ac012008-07-02 10:56:40 +02001131 struct zfcp_adapter *adapter = erp_action->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Christof Schmitt287ac012008-07-02 10:56:40 +02001133 adapter->erp_total_count--;
1134 if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1135 adapter->erp_low_mem_count--;
1136 erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 }
1138
Christof Schmitt287ac012008-07-02 10:56:40 +02001139 list_del(&erp_action->list);
Swen Schillig57717102009-08-18 15:43:21 +02001140 zfcp_dbf_rec_action("eractd1", erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
Christof Schmitt287ac012008-07-02 10:56:40 +02001142 switch (erp_action->action) {
1143 case ZFCP_ERP_ACTION_REOPEN_UNIT:
1144 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1145 &erp_action->unit->status);
1146 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
Christof Schmitt287ac012008-07-02 10:56:40 +02001148 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1149 case ZFCP_ERP_ACTION_REOPEN_PORT:
1150 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1151 &erp_action->port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001153
1154 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1155 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1156 &erp_action->adapter->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 break;
1158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159}
1160
Christof Schmitt287ac012008-07-02 10:56:40 +02001161static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001162{
Christof Schmitt287ac012008-07-02 10:56:40 +02001163 struct zfcp_adapter *adapter = act->adapter;
1164 struct zfcp_port *port = act->port;
1165 struct zfcp_unit *unit = act->unit;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001166
Christof Schmitt287ac012008-07-02 10:56:40 +02001167 switch (act->action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 case ZFCP_ERP_ACTION_REOPEN_UNIT:
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001169 if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
Swen Schillig92d51932009-04-17 15:08:04 +02001170 zfcp_unit_get(unit);
1171 if (scsi_queue_work(unit->port->adapter->scsi_host,
1172 &unit->scsi_work) <= 0)
1173 zfcp_unit_put(unit);
Andreas Herrmannad58f7d2006-03-10 00:56:16 +01001174 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 zfcp_unit_put(unit);
1176 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001177
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1179 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001180 if (result == ZFCP_ERP_SUCCEEDED)
1181 zfcp_scsi_schedule_rport_register(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 zfcp_port_put(port);
1183 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001184
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001186 if (result == ZFCP_ERP_SUCCEEDED) {
Christof Schmittbd43a42b72008-12-25 13:38:50 +01001187 register_service_level(&adapter->service_level);
Swen Schilligfca55b62008-11-26 18:07:40 +01001188 schedule_work(&adapter->scan_work);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001189 } else
1190 unregister_service_level(&adapter->service_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 zfcp_adapter_put(adapter);
1192 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 }
1194}
1195
Christof Schmitt287ac012008-07-02 10:56:40 +02001196static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
1197{
1198 switch (erp_action->action) {
1199 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1200 return zfcp_erp_adapter_strategy(erp_action);
1201 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1202 return zfcp_erp_port_forced_strategy(erp_action);
1203 case ZFCP_ERP_ACTION_REOPEN_PORT:
1204 return zfcp_erp_port_strategy(erp_action);
1205 case ZFCP_ERP_ACTION_REOPEN_UNIT:
1206 return zfcp_erp_unit_strategy(erp_action);
1207 }
1208 return ZFCP_ERP_FAILED;
1209}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
Christof Schmitt287ac012008-07-02 10:56:40 +02001211static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
1212{
1213 int retval;
1214 struct zfcp_adapter *adapter = erp_action->adapter;
1215 unsigned long flags;
1216
1217 read_lock_irqsave(&zfcp_data.config_lock, flags);
1218 write_lock(&adapter->erp_lock);
1219
1220 zfcp_erp_strategy_check_fsfreq(erp_action);
1221
1222 if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
1223 zfcp_erp_action_dequeue(erp_action);
1224 retval = ZFCP_ERP_DISMISSED;
1225 goto unlock;
1226 }
1227
1228 zfcp_erp_action_to_running(erp_action);
1229
1230 /* no lock to allow for blocking operations */
1231 write_unlock(&adapter->erp_lock);
1232 read_unlock_irqrestore(&zfcp_data.config_lock, flags);
1233 retval = zfcp_erp_strategy_do_action(erp_action);
1234 read_lock_irqsave(&zfcp_data.config_lock, flags);
1235 write_lock(&adapter->erp_lock);
1236
1237 if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED)
1238 retval = ZFCP_ERP_CONTINUES;
1239
1240 switch (retval) {
1241 case ZFCP_ERP_NOMEM:
1242 if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) {
1243 ++adapter->erp_low_mem_count;
1244 erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
1245 }
1246 if (adapter->erp_total_count == adapter->erp_low_mem_count)
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001247 _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001248 else {
1249 zfcp_erp_strategy_memwait(erp_action);
1250 retval = ZFCP_ERP_CONTINUES;
1251 }
1252 goto unlock;
1253
1254 case ZFCP_ERP_CONTINUES:
1255 if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1256 --adapter->erp_low_mem_count;
1257 erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
1258 }
1259 goto unlock;
1260 }
1261
1262 retval = zfcp_erp_strategy_check_target(erp_action, retval);
1263 zfcp_erp_action_dequeue(erp_action);
1264 retval = zfcp_erp_strategy_statechange(erp_action, retval);
1265 if (retval == ZFCP_ERP_EXIT)
1266 goto unlock;
Christof Schmitt85600f72009-07-13 15:06:09 +02001267 if (retval == ZFCP_ERP_SUCCEEDED)
1268 zfcp_erp_strategy_followup_success(erp_action);
1269 if (retval == ZFCP_ERP_FAILED)
1270 zfcp_erp_strategy_followup_failed(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +02001271
1272 unlock:
1273 write_unlock(&adapter->erp_lock);
1274 read_unlock_irqrestore(&zfcp_data.config_lock, flags);
1275
1276 if (retval != ZFCP_ERP_CONTINUES)
1277 zfcp_erp_action_cleanup(erp_action, retval);
1278
1279 return retval;
1280}
1281
1282static int zfcp_erp_thread(void *data)
1283{
1284 struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
1285 struct list_head *next;
1286 struct zfcp_erp_action *act;
1287 unsigned long flags;
Heiko Carstens06499fa2008-12-19 16:56:56 +01001288 int ignore;
Christof Schmitt287ac012008-07-02 10:56:40 +02001289
Cornelia Huckb9d3aed2008-10-10 21:33:11 +02001290 daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev));
Christof Schmitt287ac012008-07-02 10:56:40 +02001291 /* Block all signals */
1292 siginitsetinv(&current->blocked, 0);
1293 atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
1294 wake_up(&adapter->erp_thread_wqh);
1295
1296 while (!(atomic_read(&adapter->status) &
1297 ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) {
Swen Schillig94ab4b32009-04-17 15:08:06 +02001298
Swen Schillig57717102009-08-18 15:43:21 +02001299 zfcp_dbf_rec_thread_lock("erthrd1", adapter->dbf);
Swen Schillig94ab4b32009-04-17 15:08:06 +02001300 ignore = down_interruptible(&adapter->erp_ready_sem);
Swen Schillig57717102009-08-18 15:43:21 +02001301 zfcp_dbf_rec_thread_lock("erthrd2", adapter->dbf);
Swen Schillig94ab4b32009-04-17 15:08:06 +02001302
Christof Schmitt287ac012008-07-02 10:56:40 +02001303 write_lock_irqsave(&adapter->erp_lock, flags);
1304 next = adapter->erp_ready_head.next;
1305 write_unlock_irqrestore(&adapter->erp_lock, flags);
1306
1307 if (next != &adapter->erp_ready_head) {
1308 act = list_entry(next, struct zfcp_erp_action, list);
1309
1310 /* there is more to come after dismission, no notify */
1311 if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED)
1312 zfcp_erp_wakeup(adapter);
1313 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001314 }
1315
1316 atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
1317 wake_up(&adapter->erp_thread_wqh);
1318
1319 return 0;
1320}
1321
1322/**
1323 * zfcp_erp_thread_setup - Start ERP thread for adapter
1324 * @adapter: Adapter to start the ERP thread for
1325 *
1326 * Returns 0 on success or error code from kernel_thread()
1327 */
1328int zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
1329{
1330 int retval;
1331
1332 atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status);
1333 retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD);
1334 if (retval < 0) {
1335 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001336 "Creating an ERP thread for the FCP device failed.\n");
Christof Schmitt287ac012008-07-02 10:56:40 +02001337 return retval;
1338 }
1339 wait_event(adapter->erp_thread_wqh,
1340 atomic_read(&adapter->status) &
1341 ZFCP_STATUS_ADAPTER_ERP_THREAD_UP);
1342 return 0;
1343}
1344
1345/**
1346 * zfcp_erp_thread_kill - Stop ERP thread.
1347 * @adapter: Adapter where the ERP thread should be stopped.
1348 *
1349 * The caller of this routine ensures that the specified adapter has
1350 * been shut down and that this operation has been completed. Thus,
1351 * there are no pending erp_actions which would need to be handled
1352 * here.
1353 */
1354void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
1355{
1356 atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status);
1357 up(&adapter->erp_ready_sem);
Swen Schillig57717102009-08-18 15:43:21 +02001358 zfcp_dbf_rec_thread_lock("erthrk1", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +02001359
1360 wait_event(adapter->erp_thread_wqh,
1361 !(atomic_read(&adapter->status) &
1362 ZFCP_STATUS_ADAPTER_ERP_THREAD_UP));
1363
1364 atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL,
1365 &adapter->status);
1366}
1367
1368/**
1369 * zfcp_erp_adapter_failed - Set adapter status to failed.
1370 * @adapter: Failed adapter.
1371 * @id: Event id for debug trace.
1372 * @ref: Reference for debug trace.
1373 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001374void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +02001375{
1376 zfcp_erp_modify_adapter_status(adapter, id, ref,
1377 ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
Christof Schmitt287ac012008-07-02 10:56:40 +02001378}
1379
1380/**
1381 * zfcp_erp_port_failed - Set port status to failed.
1382 * @port: Failed port.
1383 * @id: Event id for debug trace.
1384 * @ref: Reference for debug trace.
1385 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001386void zfcp_erp_port_failed(struct zfcp_port *port, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +02001387{
1388 zfcp_erp_modify_port_status(port, id, ref,
1389 ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
Christof Schmitt287ac012008-07-02 10:56:40 +02001390}
1391
1392/**
1393 * zfcp_erp_unit_failed - Set unit status to failed.
1394 * @unit: Failed unit.
1395 * @id: Event id for debug trace.
1396 * @ref: Reference for debug trace.
1397 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001398void zfcp_erp_unit_failed(struct zfcp_unit *unit, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +02001399{
1400 zfcp_erp_modify_unit_status(unit, id, ref,
1401 ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
Christof Schmitt287ac012008-07-02 10:56:40 +02001402}
1403
1404/**
1405 * zfcp_erp_wait - wait for completion of error recovery on an adapter
1406 * @adapter: adapter for which to wait for completion of its error recovery
1407 */
1408void zfcp_erp_wait(struct zfcp_adapter *adapter)
1409{
1410 wait_event(adapter->erp_done_wqh,
1411 !(atomic_read(&adapter->status) &
1412 ZFCP_STATUS_ADAPTER_ERP_PENDING));
1413}
1414
1415/**
1416 * zfcp_erp_modify_adapter_status - change adapter status bits
1417 * @adapter: adapter to change the status
1418 * @id: id for the debug trace
1419 * @ref: reference for the debug trace
1420 * @mask: status bits to change
1421 * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1422 *
1423 * Changes in common status bits are propagated to attached ports and units.
1424 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001425void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +02001426 void *ref, u32 mask, int set_or_clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 struct zfcp_port *port;
Christof Schmitt287ac012008-07-02 10:56:40 +02001429 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
Christof Schmitt287ac012008-07-02 10:56:40 +02001431 if (set_or_clear == ZFCP_SET) {
1432 if (status_change_set(mask, &adapter->status))
Swen Schillig57717102009-08-18 15:43:21 +02001433 zfcp_dbf_rec_adapter(id, ref, adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +02001434 atomic_set_mask(mask, &adapter->status);
1435 } else {
1436 if (status_change_clear(mask, &adapter->status))
Swen Schillig57717102009-08-18 15:43:21 +02001437 zfcp_dbf_rec_adapter(id, ref, adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +02001438 atomic_clear_mask(mask, &adapter->status);
1439 if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
1440 atomic_set(&adapter->erp_counter, 0);
1441 }
1442
1443 if (common_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 list_for_each_entry(port, &adapter->port_list_head, list)
Christof Schmitt287ac012008-07-02 10:56:40 +02001445 zfcp_erp_modify_port_status(port, id, ref, common_mask,
1446 set_or_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447}
1448
Christof Schmitt287ac012008-07-02 10:56:40 +02001449/**
1450 * zfcp_erp_modify_port_status - change port status bits
1451 * @port: port to change the status bits
1452 * @id: id for the debug trace
1453 * @ref: reference for the debug trace
1454 * @mask: status bits to change
1455 * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1456 *
1457 * Changes in common status bits are propagated to attached units.
1458 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001459void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref,
Christof Schmitt287ac012008-07-02 10:56:40 +02001460 u32 mask, int set_or_clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 struct zfcp_unit *unit;
Christof Schmitt287ac012008-07-02 10:56:40 +02001463 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Christof Schmitt287ac012008-07-02 10:56:40 +02001465 if (set_or_clear == ZFCP_SET) {
1466 if (status_change_set(mask, &port->status))
Swen Schillig57717102009-08-18 15:43:21 +02001467 zfcp_dbf_rec_port(id, ref, port);
Christof Schmitt287ac012008-07-02 10:56:40 +02001468 atomic_set_mask(mask, &port->status);
1469 } else {
1470 if (status_change_clear(mask, &port->status))
Swen Schillig57717102009-08-18 15:43:21 +02001471 zfcp_dbf_rec_port(id, ref, port);
Christof Schmitt287ac012008-07-02 10:56:40 +02001472 atomic_clear_mask(mask, &port->status);
1473 if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
1474 atomic_set(&port->erp_counter, 0);
1475 }
1476
1477 if (common_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 list_for_each_entry(unit, &port->unit_list_head, list)
Christof Schmitt287ac012008-07-02 10:56:40 +02001479 zfcp_erp_modify_unit_status(unit, id, ref, common_mask,
1480 set_or_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481}
1482
Christof Schmitt287ac012008-07-02 10:56:40 +02001483/**
1484 * zfcp_erp_modify_unit_status - change unit status bits
1485 * @unit: unit to change the status bits
1486 * @id: id for the debug trace
1487 * @ref: reference for the debug trace
1488 * @mask: status bits to change
1489 * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1490 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001491void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref,
Christof Schmitt287ac012008-07-02 10:56:40 +02001492 u32 mask, int set_or_clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493{
Christof Schmitt287ac012008-07-02 10:56:40 +02001494 if (set_or_clear == ZFCP_SET) {
1495 if (status_change_set(mask, &unit->status))
Swen Schillig57717102009-08-18 15:43:21 +02001496 zfcp_dbf_rec_unit(id, ref, unit);
Christof Schmitt287ac012008-07-02 10:56:40 +02001497 atomic_set_mask(mask, &unit->status);
1498 } else {
1499 if (status_change_clear(mask, &unit->status))
Swen Schillig57717102009-08-18 15:43:21 +02001500 zfcp_dbf_rec_unit(id, ref, unit);
Christof Schmitt287ac012008-07-02 10:56:40 +02001501 atomic_clear_mask(mask, &unit->status);
1502 if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) {
1503 atomic_set(&unit->erp_counter, 0);
1504 }
1505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506}
1507
Christof Schmitt287ac012008-07-02 10:56:40 +02001508/**
1509 * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP
1510 * @port: The "boxed" port.
1511 * @id: The debug trace id.
1512 * @id: Reference for the debug trace.
1513 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001514void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref)
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001515{
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001516 unsigned long flags;
1517
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001518 read_lock_irqsave(&zfcp_data.config_lock, flags);
Martin Peschke698ec0162008-03-27 14:22:02 +01001519 zfcp_erp_modify_port_status(port, id, ref,
1520 ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001521 read_unlock_irqrestore(&zfcp_data.config_lock, flags);
Martin Peschke9467a9b2008-03-27 14:22:03 +01001522 zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001523}
1524
Christof Schmitt287ac012008-07-02 10:56:40 +02001525/**
1526 * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP
1527 * @port: The "boxed" unit.
1528 * @id: The debug trace id.
1529 * @id: Reference for the debug trace.
1530 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001531void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref)
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001532{
Martin Peschke698ec0162008-03-27 14:22:02 +01001533 zfcp_erp_modify_unit_status(unit, id, ref,
1534 ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
Martin Peschke9467a9b2008-03-27 14:22:03 +01001535 zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001536}
1537
Christof Schmitt287ac012008-07-02 10:56:40 +02001538/**
1539 * zfcp_erp_port_access_denied - Adapter denied access to port.
1540 * @port: port where access has been denied
1541 * @id: id for debug trace
1542 * @ref: reference for debug trace
1543 *
1544 * Since the adapter has denied access, stop using the port and the
1545 * attached units.
1546 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001547void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 unsigned long flags;
1550
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 read_lock_irqsave(&zfcp_data.config_lock, flags);
Martin Peschke698ec0162008-03-27 14:22:02 +01001552 zfcp_erp_modify_port_status(port, id, ref,
1553 ZFCP_STATUS_COMMON_ERP_FAILED |
1554 ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 read_unlock_irqrestore(&zfcp_data.config_lock, flags);
1556}
1557
Christof Schmitt287ac012008-07-02 10:56:40 +02001558/**
1559 * zfcp_erp_unit_access_denied - Adapter denied access to unit.
1560 * @unit: unit where access has been denied
1561 * @id: id for debug trace
1562 * @ref: reference for debug trace
1563 *
1564 * Since the adapter has denied access, stop using the unit.
1565 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001566void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, char *id, void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567{
Martin Peschke698ec0162008-03-27 14:22:02 +01001568 zfcp_erp_modify_unit_status(unit, id, ref,
1569 ZFCP_STATUS_COMMON_ERP_FAILED |
1570 ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571}
1572
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001573static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +02001574 void *ref)
1575{
1576 int status = atomic_read(&unit->status);
1577 if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
1578 ZFCP_STATUS_COMMON_ACCESS_BOXED)))
1579 return;
1580
1581 zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
1582}
1583
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001584static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +02001585 void *ref)
1586{
1587 struct zfcp_unit *unit;
1588 int status = atomic_read(&port->status);
1589
1590 if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
1591 ZFCP_STATUS_COMMON_ACCESS_BOXED))) {
Swen Schillig5ab944f2008-10-01 12:42:17 +02001592 list_for_each_entry(unit, &port->unit_list_head, list)
1593 zfcp_erp_unit_access_changed(unit, id, ref);
Christof Schmitt287ac012008-07-02 10:56:40 +02001594 return;
1595 }
1596
1597 zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
1598}
1599
1600/**
1601 * zfcp_erp_adapter_access_changed - Process change in adapter ACT
1602 * @adapter: Adapter where the Access Control Table (ACT) changed
1603 * @id: Id for debug trace
1604 * @ref: Reference for debug trace
1605 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001606void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id,
Martin Peschke1f6f7122008-04-18 12:51:55 +02001607 void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608{
1609 struct zfcp_port *port;
1610 unsigned long flags;
1611
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001612 if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
1613 return;
1614
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 read_lock_irqsave(&zfcp_data.config_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 list_for_each_entry(port, &adapter->port_list_head, list)
Swen Schillig5ab944f2008-10-01 12:42:17 +02001617 zfcp_erp_port_access_changed(port, id, ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 read_unlock_irqrestore(&zfcp_data.config_lock, flags);
1619}