Commit | Line | Data |
---|---|---|
41fa2ada | 1 | /* |
553448f6 | 2 | * zfcp device driver |
1da177e4 | 3 | * |
553448f6 | 4 | * Error Recovery Procedures (ERP). |
41fa2ada | 5 | * |
a2fa0aed | 6 | * Copyright IBM Corporation 2002, 2009 |
1da177e4 LT |
7 | */ |
8 | ||
ecf39d42 CS |
9 | #define KMSG_COMPONENT "zfcp" |
10 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | |
11 | ||
1da177e4 LT |
12 | #include "zfcp_ext.h" |
13 | ||
287ac01a CS |
14 | #define ZFCP_MAX_ERPS 3 |
15 | ||
16 | enum 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 | }; | |
1da177e4 | 23 | |
287ac01a CS |
24 | enum 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, | |
287ac01a CS |
29 | ZFCP_ERP_STEP_NAMESERVER_LOOKUP = 0x0400, |
30 | ZFCP_ERP_STEP_PORT_OPENING = 0x0800, | |
31 | ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000, | |
32 | ZFCP_ERP_STEP_UNIT_OPENING = 0x2000, | |
33 | }; | |
34 | ||
35 | enum zfcp_erp_act_type { | |
36 | ZFCP_ERP_ACTION_REOPEN_UNIT = 1, | |
37 | ZFCP_ERP_ACTION_REOPEN_PORT = 2, | |
38 | ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3, | |
39 | ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4, | |
40 | }; | |
41 | ||
42 | enum zfcp_erp_act_state { | |
43 | ZFCP_ERP_ACTION_RUNNING = 1, | |
44 | ZFCP_ERP_ACTION_READY = 2, | |
45 | }; | |
46 | ||
47 | enum zfcp_erp_act_result { | |
48 | ZFCP_ERP_SUCCEEDED = 0, | |
49 | ZFCP_ERP_FAILED = 1, | |
50 | ZFCP_ERP_CONTINUES = 2, | |
51 | ZFCP_ERP_EXIT = 3, | |
52 | ZFCP_ERP_DISMISSED = 4, | |
53 | ZFCP_ERP_NOMEM = 5, | |
54 | }; | |
55 | ||
56 | static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask) | |
1da177e4 | 57 | { |
5ffd51a5 | 58 | zfcp_erp_modify_adapter_status(adapter, "erablk1", NULL, |
287ac01a CS |
59 | ZFCP_STATUS_COMMON_UNBLOCKED | mask, |
60 | ZFCP_CLEAR); | |
2abbe866 | 61 | } |
1da177e4 | 62 | |
287ac01a | 63 | static int zfcp_erp_action_exists(struct zfcp_erp_action *act) |
2abbe866 | 64 | { |
287ac01a CS |
65 | struct zfcp_erp_action *curr_act; |
66 | ||
67 | list_for_each_entry(curr_act, &act->adapter->erp_running_head, list) | |
68 | if (act == curr_act) | |
69 | return ZFCP_ERP_ACTION_RUNNING; | |
70 | return 0; | |
1da177e4 LT |
71 | } |
72 | ||
287ac01a | 73 | static void zfcp_erp_action_ready(struct zfcp_erp_action *act) |
2abbe866 | 74 | { |
287ac01a CS |
75 | struct zfcp_adapter *adapter = act->adapter; |
76 | ||
77 | list_move(&act->list, &act->adapter->erp_ready_head); | |
5ffd51a5 | 78 | zfcp_rec_dbf_event_action("erardy1", act); |
287ac01a | 79 | up(&adapter->erp_ready_sem); |
5ffd51a5 | 80 | zfcp_rec_dbf_event_thread("erardy2", adapter); |
2abbe866 AH |
81 | } |
82 | ||
287ac01a | 83 | static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act) |
1da177e4 | 84 | { |
287ac01a CS |
85 | act->status |= ZFCP_STATUS_ERP_DISMISSED; |
86 | if (zfcp_erp_action_exists(act) == ZFCP_ERP_ACTION_RUNNING) | |
87 | zfcp_erp_action_ready(act); | |
88 | } | |
1da177e4 | 89 | |
287ac01a CS |
90 | static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) |
91 | { | |
92 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE) | |
93 | zfcp_erp_action_dismiss(&unit->erp_action); | |
94 | } | |
1da177e4 | 95 | |
287ac01a CS |
96 | static void zfcp_erp_action_dismiss_port(struct zfcp_port *port) |
97 | { | |
98 | struct zfcp_unit *unit; | |
1da177e4 | 99 | |
287ac01a CS |
100 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE) |
101 | zfcp_erp_action_dismiss(&port->erp_action); | |
102 | else | |
103 | list_for_each_entry(unit, &port->unit_list_head, list) | |
104 | zfcp_erp_action_dismiss_unit(unit); | |
1da177e4 LT |
105 | } |
106 | ||
287ac01a | 107 | static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) |
1da177e4 | 108 | { |
287ac01a | 109 | struct zfcp_port *port; |
1da177e4 | 110 | |
287ac01a CS |
111 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE) |
112 | zfcp_erp_action_dismiss(&adapter->erp_action); | |
113 | else | |
114 | list_for_each_entry(port, &adapter->port_list_head, list) | |
115 | zfcp_erp_action_dismiss_port(port); | |
1da177e4 LT |
116 | } |
117 | ||
287ac01a CS |
118 | static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, |
119 | struct zfcp_port *port, | |
120 | struct zfcp_unit *unit) | |
1da177e4 | 121 | { |
287ac01a CS |
122 | int need = want; |
123 | int u_status, p_status, a_status; | |
1da177e4 | 124 | |
287ac01a CS |
125 | switch (want) { |
126 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | |
127 | u_status = atomic_read(&unit->status); | |
128 | if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE) | |
129 | return 0; | |
130 | p_status = atomic_read(&port->status); | |
131 | if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) || | |
132 | p_status & ZFCP_STATUS_COMMON_ERP_FAILED) | |
133 | return 0; | |
134 | if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED)) | |
135 | need = ZFCP_ERP_ACTION_REOPEN_PORT; | |
136 | /* fall through */ | |
137 | case ZFCP_ERP_ACTION_REOPEN_PORT: | |
138 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | |
139 | p_status = atomic_read(&port->status); | |
140 | if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE) | |
141 | return 0; | |
142 | a_status = atomic_read(&adapter->status); | |
143 | if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) || | |
144 | a_status & ZFCP_STATUS_COMMON_ERP_FAILED) | |
145 | return 0; | |
146 | if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED)) | |
147 | need = ZFCP_ERP_ACTION_REOPEN_ADAPTER; | |
148 | /* fall through */ | |
149 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | |
150 | a_status = atomic_read(&adapter->status); | |
151 | if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE) | |
152 | return 0; | |
153 | } | |
1da177e4 | 154 | |
287ac01a | 155 | return need; |
1da177e4 LT |
156 | } |
157 | ||
287ac01a CS |
158 | static struct zfcp_erp_action *zfcp_erp_setup_act(int need, |
159 | struct zfcp_adapter *adapter, | |
160 | struct zfcp_port *port, | |
161 | struct zfcp_unit *unit) | |
1da177e4 | 162 | { |
287ac01a CS |
163 | struct zfcp_erp_action *erp_action; |
164 | u32 status = 0; | |
1da177e4 | 165 | |
287ac01a CS |
166 | switch (need) { |
167 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | |
168 | zfcp_unit_get(unit); | |
169 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); | |
170 | erp_action = &unit->erp_action; | |
171 | if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING)) | |
172 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | |
173 | break; | |
1da177e4 | 174 | |
287ac01a CS |
175 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
176 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | |
177 | zfcp_port_get(port); | |
178 | zfcp_erp_action_dismiss_port(port); | |
179 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); | |
180 | erp_action = &port->erp_action; | |
181 | if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING)) | |
182 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | |
183 | break; | |
1da177e4 | 184 | |
287ac01a CS |
185 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
186 | zfcp_adapter_get(adapter); | |
187 | zfcp_erp_action_dismiss_adapter(adapter); | |
188 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); | |
189 | erp_action = &adapter->erp_action; | |
190 | if (!(atomic_read(&adapter->status) & | |
191 | ZFCP_STATUS_COMMON_RUNNING)) | |
192 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | |
193 | break; | |
194 | ||
195 | default: | |
196 | return NULL; | |
197 | } | |
1da177e4 | 198 | |
287ac01a CS |
199 | memset(erp_action, 0, sizeof(struct zfcp_erp_action)); |
200 | erp_action->adapter = adapter; | |
201 | erp_action->port = port; | |
202 | erp_action->unit = unit; | |
203 | erp_action->action = need; | |
204 | erp_action->status = status; | |
1da177e4 | 205 | |
287ac01a | 206 | return erp_action; |
1da177e4 LT |
207 | } |
208 | ||
287ac01a CS |
209 | static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, |
210 | struct zfcp_port *port, | |
5ffd51a5 | 211 | struct zfcp_unit *unit, char *id, void *ref) |
1da177e4 | 212 | { |
287ac01a CS |
213 | int retval = 1, need; |
214 | struct zfcp_erp_action *act = NULL; | |
1da177e4 | 215 | |
287ac01a CS |
216 | if (!(atomic_read(&adapter->status) & |
217 | ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)) | |
218 | return -EIO; | |
1da177e4 | 219 | |
287ac01a CS |
220 | need = zfcp_erp_required_act(want, adapter, port, unit); |
221 | if (!need) | |
1da177e4 | 222 | goto out; |
1da177e4 | 223 | |
287ac01a CS |
224 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); |
225 | act = zfcp_erp_setup_act(need, adapter, port, unit); | |
226 | if (!act) | |
227 | goto out; | |
228 | ++adapter->erp_total_count; | |
229 | list_add_tail(&act->list, &adapter->erp_ready_head); | |
230 | up(&adapter->erp_ready_sem); | |
5ffd51a5 | 231 | zfcp_rec_dbf_event_thread("eracte1", adapter); |
287ac01a | 232 | retval = 0; |
1da177e4 | 233 | out: |
287ac01a CS |
234 | zfcp_rec_dbf_event_trigger(id, ref, want, need, act, |
235 | adapter, port, unit); | |
1da177e4 LT |
236 | return retval; |
237 | } | |
238 | ||
287ac01a | 239 | static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, |
5ffd51a5 | 240 | int clear_mask, char *id, void *ref) |
287ac01a CS |
241 | { |
242 | zfcp_erp_adapter_block(adapter, clear_mask); | |
a2fa0aed | 243 | zfcp_scsi_schedule_rports_block(adapter); |
287ac01a CS |
244 | |
245 | /* ensure propagation of failed status to new devices */ | |
246 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { | |
5ffd51a5 | 247 | zfcp_erp_adapter_failed(adapter, "erareo1", NULL); |
287ac01a CS |
248 | return -EIO; |
249 | } | |
250 | return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, | |
251 | adapter, NULL, NULL, id, ref); | |
252 | } | |
253 | ||
254 | /** | |
255 | * zfcp_erp_adapter_reopen - Reopen adapter. | |
256 | * @adapter: Adapter to reopen. | |
257 | * @clear: Status flags to clear. | |
258 | * @id: Id for debug trace event. | |
259 | * @ref: Reference for debug trace event. | |
1da177e4 | 260 | */ |
287ac01a | 261 | void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, |
5ffd51a5 | 262 | char *id, void *ref) |
1da177e4 | 263 | { |
1da177e4 | 264 | unsigned long flags; |
1da177e4 | 265 | |
1da177e4 LT |
266 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
267 | write_lock(&adapter->erp_lock); | |
287ac01a | 268 | _zfcp_erp_adapter_reopen(adapter, clear, id, ref); |
1da177e4 LT |
269 | write_unlock(&adapter->erp_lock); |
270 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | |
287ac01a | 271 | } |
1da177e4 | 272 | |
287ac01a CS |
273 | /** |
274 | * zfcp_erp_adapter_shutdown - Shutdown adapter. | |
275 | * @adapter: Adapter to shut down. | |
276 | * @clear: Status flags to clear. | |
277 | * @id: Id for debug trace event. | |
278 | * @ref: Reference for debug trace event. | |
279 | */ | |
280 | void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear, | |
5ffd51a5 | 281 | char *id, void *ref) |
287ac01a CS |
282 | { |
283 | int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; | |
284 | zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref); | |
1da177e4 LT |
285 | } |
286 | ||
287ac01a CS |
287 | /** |
288 | * zfcp_erp_port_shutdown - Shutdown port | |
289 | * @port: Port to shut down. | |
290 | * @clear: Status flags to clear. | |
291 | * @id: Id for debug trace event. | |
292 | * @ref: Reference for debug trace event. | |
1da177e4 | 293 | */ |
5ffd51a5 SS |
294 | void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id, |
295 | void *ref) | |
1da177e4 | 296 | { |
287ac01a CS |
297 | int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; |
298 | zfcp_erp_port_reopen(port, clear | flags, id, ref); | |
299 | } | |
300 | ||
301 | /** | |
302 | * zfcp_erp_unit_shutdown - Shutdown unit | |
303 | * @unit: Unit to shut down. | |
304 | * @clear: Status flags to clear. | |
305 | * @id: Id for debug trace event. | |
306 | * @ref: Reference for debug trace event. | |
307 | */ | |
5ffd51a5 SS |
308 | void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, char *id, |
309 | void *ref) | |
287ac01a CS |
310 | { |
311 | int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; | |
312 | zfcp_erp_unit_reopen(unit, clear | flags, id, ref); | |
313 | } | |
314 | ||
315 | static void zfcp_erp_port_block(struct zfcp_port *port, int clear) | |
316 | { | |
5ffd51a5 | 317 | zfcp_erp_modify_port_status(port, "erpblk1", NULL, |
287ac01a CS |
318 | ZFCP_STATUS_COMMON_UNBLOCKED | clear, |
319 | ZFCP_CLEAR); | |
320 | } | |
321 | ||
322 | static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, | |
5ffd51a5 | 323 | int clear, char *id, void *ref) |
287ac01a CS |
324 | { |
325 | zfcp_erp_port_block(port, clear); | |
a2fa0aed | 326 | zfcp_scsi_schedule_rport_block(port); |
287ac01a CS |
327 | |
328 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) | |
329 | return; | |
1da177e4 | 330 | |
287ac01a CS |
331 | zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, |
332 | port->adapter, port, NULL, id, ref); | |
333 | } | |
334 | ||
335 | /** | |
336 | * zfcp_erp_port_forced_reopen - Forced close of port and open again | |
337 | * @port: Port to force close and to reopen. | |
338 | * @id: Id for debug trace event. | |
339 | * @ref: Reference for debug trace event. | |
340 | */ | |
5ffd51a5 | 341 | void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id, |
287ac01a CS |
342 | void *ref) |
343 | { | |
344 | unsigned long flags; | |
345 | struct zfcp_adapter *adapter = port->adapter; | |
346 | ||
347 | read_lock_irqsave(&zfcp_data.config_lock, flags); | |
348 | write_lock(&adapter->erp_lock); | |
349 | _zfcp_erp_port_forced_reopen(port, clear, id, ref); | |
350 | write_unlock(&adapter->erp_lock); | |
351 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | |
352 | } | |
353 | ||
5ffd51a5 | 354 | static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, |
287ac01a CS |
355 | void *ref) |
356 | { | |
357 | zfcp_erp_port_block(port, clear); | |
a2fa0aed | 358 | zfcp_scsi_schedule_rport_block(port); |
1da177e4 | 359 | |
287ac01a | 360 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
1da177e4 | 361 | /* ensure propagation of failed status to new devices */ |
5ffd51a5 | 362 | zfcp_erp_port_failed(port, "erpreo1", NULL); |
287ac01a | 363 | return -EIO; |
1da177e4 LT |
364 | } |
365 | ||
287ac01a CS |
366 | return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, |
367 | port->adapter, port, NULL, id, ref); | |
1da177e4 LT |
368 | } |
369 | ||
370 | /** | |
287ac01a CS |
371 | * zfcp_erp_port_reopen - trigger remote port recovery |
372 | * @port: port to recover | |
373 | * @clear_mask: flags in port status to be cleared | |
1da177e4 | 374 | * |
287ac01a | 375 | * Returns 0 if recovery has been triggered, < 0 if not. |
1da177e4 | 376 | */ |
5ffd51a5 | 377 | int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref) |
1da177e4 | 378 | { |
1da177e4 | 379 | unsigned long flags; |
287ac01a | 380 | int retval; |
1da177e4 LT |
381 | struct zfcp_adapter *adapter = port->adapter; |
382 | ||
383 | read_lock_irqsave(&zfcp_data.config_lock, flags); | |
384 | write_lock(&adapter->erp_lock); | |
287ac01a | 385 | retval = _zfcp_erp_port_reopen(port, clear, id, ref); |
1da177e4 LT |
386 | write_unlock(&adapter->erp_lock); |
387 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | |
388 | ||
389 | return retval; | |
390 | } | |
391 | ||
287ac01a CS |
392 | static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) |
393 | { | |
5ffd51a5 | 394 | zfcp_erp_modify_unit_status(unit, "erublk1", NULL, |
287ac01a CS |
395 | ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, |
396 | ZFCP_CLEAR); | |
397 | } | |
398 | ||
5ffd51a5 | 399 | static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, |
287ac01a | 400 | void *ref) |
1da177e4 | 401 | { |
1da177e4 LT |
402 | struct zfcp_adapter *adapter = unit->port->adapter; |
403 | ||
287ac01a | 404 | zfcp_erp_unit_block(unit, clear); |
1da177e4 | 405 | |
287ac01a CS |
406 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) |
407 | return; | |
1da177e4 | 408 | |
287ac01a CS |
409 | zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, |
410 | adapter, unit->port, unit, id, ref); | |
1da177e4 LT |
411 | } |
412 | ||
413 | /** | |
414 | * zfcp_erp_unit_reopen - initiate reopen of a unit | |
415 | * @unit: unit to be reopened | |
416 | * @clear_mask: specifies flags in unit status to be cleared | |
417 | * Return: 0 on success, < 0 on error | |
1da177e4 | 418 | */ |
5ffd51a5 SS |
419 | void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, |
420 | void *ref) | |
1da177e4 | 421 | { |
1da177e4 | 422 | unsigned long flags; |
287ac01a CS |
423 | struct zfcp_port *port = unit->port; |
424 | struct zfcp_adapter *adapter = port->adapter; | |
1da177e4 LT |
425 | |
426 | read_lock_irqsave(&zfcp_data.config_lock, flags); | |
427 | write_lock(&adapter->erp_lock); | |
287ac01a | 428 | _zfcp_erp_unit_reopen(unit, clear, id, ref); |
1da177e4 LT |
429 | write_unlock(&adapter->erp_lock); |
430 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | |
1da177e4 LT |
431 | } |
432 | ||
287ac01a | 433 | static int status_change_set(unsigned long mask, atomic_t *status) |
1da177e4 | 434 | { |
287ac01a | 435 | return (atomic_read(status) ^ mask) & mask; |
1da177e4 LT |
436 | } |
437 | ||
287ac01a | 438 | static int status_change_clear(unsigned long mask, atomic_t *status) |
698ec016 | 439 | { |
287ac01a | 440 | return atomic_read(status) & mask; |
698ec016 MP |
441 | } |
442 | ||
287ac01a | 443 | static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) |
698ec016 | 444 | { |
287ac01a | 445 | if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) |
5ffd51a5 | 446 | zfcp_rec_dbf_event_adapter("eraubl1", NULL, adapter); |
287ac01a | 447 | atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); |
698ec016 MP |
448 | } |
449 | ||
287ac01a | 450 | static void zfcp_erp_port_unblock(struct zfcp_port *port) |
1da177e4 | 451 | { |
287ac01a | 452 | if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) |
5ffd51a5 | 453 | zfcp_rec_dbf_event_port("erpubl1", NULL, port); |
287ac01a | 454 | atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); |
1da177e4 LT |
455 | } |
456 | ||
287ac01a | 457 | static void zfcp_erp_unit_unblock(struct zfcp_unit *unit) |
1da177e4 | 458 | { |
287ac01a | 459 | if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status)) |
5ffd51a5 | 460 | zfcp_rec_dbf_event_unit("eruubl1", NULL, unit); |
287ac01a | 461 | atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status); |
1da177e4 LT |
462 | } |
463 | ||
287ac01a | 464 | static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) |
1da177e4 | 465 | { |
287ac01a | 466 | list_move(&erp_action->list, &erp_action->adapter->erp_running_head); |
5ffd51a5 | 467 | zfcp_rec_dbf_event_action("erator1", erp_action); |
1da177e4 LT |
468 | } |
469 | ||
287ac01a | 470 | static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) |
1da177e4 | 471 | { |
287ac01a | 472 | struct zfcp_adapter *adapter = act->adapter; |
1da177e4 | 473 | |
287ac01a CS |
474 | if (!act->fsf_req) |
475 | return; | |
1da177e4 | 476 | |
287ac01a CS |
477 | spin_lock(&adapter->req_list_lock); |
478 | if (zfcp_reqlist_find_safe(adapter, act->fsf_req) && | |
479 | act->fsf_req->erp_action == act) { | |
480 | if (act->status & (ZFCP_STATUS_ERP_DISMISSED | | |
481 | ZFCP_STATUS_ERP_TIMEDOUT)) { | |
482 | act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; | |
5ffd51a5 | 483 | zfcp_rec_dbf_event_action("erscf_1", act); |
7ea633ff | 484 | act->fsf_req->erp_action = NULL; |
1da177e4 | 485 | } |
287ac01a | 486 | if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) |
5ffd51a5 | 487 | zfcp_rec_dbf_event_action("erscf_2", act); |
058b8647 | 488 | if (act->fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) |
287ac01a CS |
489 | act->fsf_req = NULL; |
490 | } else | |
491 | act->fsf_req = NULL; | |
492 | spin_unlock(&adapter->req_list_lock); | |
1da177e4 LT |
493 | } |
494 | ||
287ac01a CS |
495 | /** |
496 | * zfcp_erp_notify - Trigger ERP action. | |
497 | * @erp_action: ERP action to continue. | |
498 | * @set_mask: ERP action status flags to set. | |
1da177e4 | 499 | */ |
287ac01a | 500 | void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask) |
1da177e4 | 501 | { |
1da177e4 | 502 | struct zfcp_adapter *adapter = erp_action->adapter; |
287ac01a | 503 | unsigned long flags; |
1da177e4 | 504 | |
287ac01a | 505 | write_lock_irqsave(&adapter->erp_lock, flags); |
1da177e4 | 506 | if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) { |
1da177e4 LT |
507 | erp_action->status |= set_mask; |
508 | zfcp_erp_action_ready(erp_action); | |
1da177e4 | 509 | } |
1da177e4 | 510 | write_unlock_irqrestore(&adapter->erp_lock, flags); |
1da177e4 LT |
511 | } |
512 | ||
287ac01a CS |
513 | /** |
514 | * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request | |
515 | * @data: ERP action (from timer data) | |
1da177e4 | 516 | */ |
287ac01a | 517 | void zfcp_erp_timeout_handler(unsigned long data) |
1da177e4 | 518 | { |
287ac01a CS |
519 | struct zfcp_erp_action *act = (struct zfcp_erp_action *) data; |
520 | zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT); | |
1da177e4 LT |
521 | } |
522 | ||
287ac01a | 523 | static void zfcp_erp_memwait_handler(unsigned long data) |
1da177e4 | 524 | { |
287ac01a | 525 | zfcp_erp_notify((struct zfcp_erp_action *)data, 0); |
1da177e4 LT |
526 | } |
527 | ||
287ac01a | 528 | static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action) |
1da177e4 | 529 | { |
287ac01a CS |
530 | init_timer(&erp_action->timer); |
531 | erp_action->timer.function = zfcp_erp_memwait_handler; | |
532 | erp_action->timer.data = (unsigned long) erp_action; | |
533 | erp_action->timer.expires = jiffies + HZ; | |
534 | add_timer(&erp_action->timer); | |
1da177e4 LT |
535 | } |
536 | ||
287ac01a | 537 | static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, |
5ffd51a5 | 538 | int clear, char *id, void *ref) |
1da177e4 | 539 | { |
287ac01a | 540 | struct zfcp_port *port; |
1da177e4 | 541 | |
287ac01a | 542 | list_for_each_entry(port, &adapter->port_list_head, list) |
5ab944f9 | 543 | _zfcp_erp_port_reopen(port, clear, id, ref); |
1da177e4 LT |
544 | } |
545 | ||
5ffd51a5 SS |
546 | static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, |
547 | char *id, void *ref) | |
1da177e4 | 548 | { |
287ac01a | 549 | struct zfcp_unit *unit; |
1da177e4 | 550 | |
287ac01a CS |
551 | list_for_each_entry(unit, &port->unit_list_head, list) |
552 | _zfcp_erp_unit_reopen(unit, clear, id, ref); | |
1da177e4 LT |
553 | } |
554 | ||
85600f7f | 555 | static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act) |
1da177e4 | 556 | { |
287ac01a | 557 | switch (act->action) { |
287ac01a | 558 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
85600f7f | 559 | _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL); |
287ac01a | 560 | break; |
287ac01a | 561 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
85600f7f | 562 | _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL); |
287ac01a | 563 | break; |
287ac01a | 564 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
85600f7f | 565 | _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL); |
287ac01a | 566 | break; |
287ac01a | 567 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
85600f7f CS |
568 | _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL); |
569 | break; | |
570 | } | |
571 | } | |
572 | ||
573 | static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act) | |
574 | { | |
575 | switch (act->action) { | |
576 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | |
577 | _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL); | |
578 | break; | |
579 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | |
580 | _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL); | |
581 | break; | |
582 | case ZFCP_ERP_ACTION_REOPEN_PORT: | |
583 | _zfcp_erp_unit_reopen_all(act->port, 0, "ersfs_3", NULL); | |
287ac01a | 584 | break; |
1da177e4 | 585 | } |
1da177e4 LT |
586 | } |
587 | ||
287ac01a | 588 | static void zfcp_erp_wakeup(struct zfcp_adapter *adapter) |
1da177e4 | 589 | { |
1da177e4 LT |
590 | unsigned long flags; |
591 | ||
1da177e4 | 592 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
287ac01a CS |
593 | read_lock(&adapter->erp_lock); |
594 | if (list_empty(&adapter->erp_ready_head) && | |
595 | list_empty(&adapter->erp_running_head)) { | |
596 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, | |
597 | &adapter->status); | |
598 | wake_up(&adapter->erp_done_wqh); | |
1da177e4 | 599 | } |
287ac01a CS |
600 | read_unlock(&adapter->erp_lock); |
601 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | |
602 | } | |
1da177e4 | 603 | |
287ac01a CS |
604 | static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act) |
605 | { | |
606 | if (zfcp_qdio_open(act->adapter)) | |
607 | return ZFCP_ERP_FAILED; | |
608 | init_waitqueue_head(&act->adapter->request_wq); | |
609 | atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status); | |
610 | return ZFCP_ERP_SUCCEEDED; | |
611 | } | |
1da177e4 | 612 | |
287ac01a CS |
613 | static 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; | |
5ffd51a5 | 620 | _zfcp_erp_port_reopen(port, 0, "ereptp1", NULL); |
287ac01a | 621 | } |
1da177e4 | 622 | |
287ac01a CS |
623 | static 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; | |
1da177e4 | 628 | |
287ac01a CS |
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; | |
1da177e4 | 641 | } |
1da177e4 | 642 | |
5ffd51a5 | 643 | zfcp_rec_dbf_event_thread_lock("erasfx1", adapter); |
287ac01a | 644 | down(&adapter->erp_ready_sem); |
5ffd51a5 | 645 | zfcp_rec_dbf_event_thread_lock("erasfx2", adapter); |
287ac01a CS |
646 | if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) |
647 | break; | |
1da177e4 | 648 | |
287ac01a CS |
649 | if (!(atomic_read(&adapter->status) & |
650 | ZFCP_STATUS_ADAPTER_HOST_CON_INIT)) | |
651 | break; | |
1da177e4 | 652 | |
287ac01a CS |
653 | ssleep(sleep); |
654 | sleep *= 2; | |
1da177e4 LT |
655 | } |
656 | ||
287ac01a CS |
657 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, |
658 | &adapter->status); | |
1da177e4 | 659 | |
287ac01a CS |
660 | if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK)) |
661 | return ZFCP_ERP_FAILED; | |
41fa2ada | 662 | |
287ac01a CS |
663 | if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) |
664 | zfcp_erp_enqueue_ptp_port(adapter); | |
1da177e4 | 665 | |
287ac01a | 666 | return ZFCP_ERP_SUCCEEDED; |
1da177e4 LT |
667 | } |
668 | ||
287ac01a | 669 | static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act) |
1da177e4 | 670 | { |
287ac01a CS |
671 | int ret; |
672 | struct zfcp_adapter *adapter = act->adapter; | |
1da177e4 | 673 | |
287ac01a CS |
674 | 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 | ||
5ffd51a5 | 684 | zfcp_rec_dbf_event_thread_lock("erasox1", adapter); |
287ac01a | 685 | down(&adapter->erp_ready_sem); |
5ffd51a5 | 686 | zfcp_rec_dbf_event_thread_lock("erasox2", adapter); |
287ac01a CS |
687 | if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) |
688 | return ZFCP_ERP_FAILED; | |
689 | ||
690 | return ZFCP_ERP_SUCCEEDED; | |
1da177e4 LT |
691 | } |
692 | ||
287ac01a | 693 | static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act) |
1da177e4 | 694 | { |
287ac01a CS |
695 | if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED) |
696 | return ZFCP_ERP_FAILED; | |
1da177e4 | 697 | |
287ac01a CS |
698 | if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED) |
699 | return ZFCP_ERP_FAILED; | |
1da177e4 | 700 | |
287ac01a CS |
701 | atomic_set(&act->adapter->stat_miss, 16); |
702 | if (zfcp_status_read_refill(act->adapter)) | |
703 | return ZFCP_ERP_FAILED; | |
1da177e4 | 704 | |
287ac01a CS |
705 | return ZFCP_ERP_SUCCEEDED; |
706 | } | |
1da177e4 | 707 | |
cf13c082 | 708 | static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act) |
287ac01a | 709 | { |
287ac01a | 710 | struct zfcp_adapter *adapter = act->adapter; |
1da177e4 | 711 | |
287ac01a CS |
712 | /* close queues to ensure that buffers are not accessed by adapter */ |
713 | zfcp_qdio_close(adapter); | |
714 | zfcp_fsf_req_dismiss_all(adapter); | |
715 | adapter->fsf_req_seq_no = 0; | |
55c770fa | 716 | zfcp_fc_wka_ports_force_offline(adapter->gs); |
287ac01a | 717 | /* all ports and units are closed */ |
5ffd51a5 | 718 | zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL, |
287ac01a | 719 | ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); |
cf13c082 | 720 | |
287ac01a | 721 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | |
cf13c082 | 722 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); |
1da177e4 LT |
723 | } |
724 | ||
cf13c082 | 725 | static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act) |
1da177e4 | 726 | { |
cf13c082 | 727 | struct zfcp_adapter *adapter = act->adapter; |
1da177e4 | 728 | |
cf13c082 SS |
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 | } | |
287ac01a | 735 | |
cf13c082 SS |
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; | |
744 | } | |
287ac01a | 745 | |
cf13c082 SS |
746 | static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act) |
747 | { | |
748 | struct zfcp_adapter *adapter = act->adapter; | |
749 | ||
750 | 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 | } | |
755 | ||
756 | if (zfcp_erp_adapter_strategy_open(act)) { | |
287ac01a | 757 | ssleep(8); |
cf13c082 SS |
758 | return ZFCP_ERP_FAILED; |
759 | } | |
1da177e4 | 760 | |
cf13c082 | 761 | return ZFCP_ERP_SUCCEEDED; |
1da177e4 LT |
762 | } |
763 | ||
287ac01a | 764 | static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act) |
1da177e4 | 765 | { |
287ac01a CS |
766 | 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; | |
1da177e4 LT |
776 | } |
777 | ||
287ac01a | 778 | static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port) |
1da177e4 | 779 | { |
a5b11dda | 780 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status); |
287ac01a | 781 | } |
1da177e4 | 782 | |
287ac01a CS |
783 | static 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: | |
ddb3e0c1 | 798 | if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN)) |
287ac01a CS |
799 | return ZFCP_ERP_SUCCEEDED; |
800 | } | |
801 | return ZFCP_ERP_FAILED; | |
1da177e4 LT |
802 | } |
803 | ||
287ac01a | 804 | static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action) |
1da177e4 | 805 | { |
287ac01a | 806 | int retval; |
1da177e4 | 807 | |
287ac01a CS |
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; | |
1da177e4 LT |
815 | } |
816 | ||
287ac01a | 817 | static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action) |
1da177e4 | 818 | { |
287ac01a | 819 | int retval; |
1da177e4 | 820 | |
287ac01a CS |
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 | } | |
1da177e4 | 829 | |
287ac01a | 830 | static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) |
1da177e4 | 831 | { |
287ac01a CS |
832 | struct zfcp_adapter *adapter = act->adapter; |
833 | struct zfcp_port *port = act->port; | |
1da177e4 | 834 | |
287ac01a | 835 | if (port->wwpn != adapter->peer_wwpn) { |
5ffd51a5 | 836 | zfcp_erp_port_failed(port, "eroptp1", NULL); |
287ac01a CS |
837 | return ZFCP_ERP_FAILED; |
838 | } | |
839 | port->d_id = adapter->peer_d_id; | |
287ac01a CS |
840 | return zfcp_erp_port_strategy_open_port(act); |
841 | } | |
842 | ||
5ab944f9 SS |
843 | void zfcp_erp_port_strategy_open_lookup(struct work_struct *work) |
844 | { | |
845 | int retval; | |
846 | struct zfcp_port *port = container_of(work, struct zfcp_port, | |
847 | gid_pn_work); | |
848 | ||
849 | retval = zfcp_fc_ns_gid_pn(&port->erp_action); | |
17a093ef SS |
850 | if (!retval) { |
851 | port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; | |
852 | goto out; | |
853 | } | |
854 | if (retval == -ENOMEM) { | |
688a1820 | 855 | zfcp_erp_notify(&port->erp_action, ZFCP_STATUS_ERP_LOWMEM); |
17a093ef SS |
856 | goto out; |
857 | } | |
858 | /* all other error condtions */ | |
859 | zfcp_erp_notify(&port->erp_action, 0); | |
860 | out: | |
947a9aca | 861 | zfcp_port_put(port); |
5ab944f9 SS |
862 | } |
863 | ||
287ac01a CS |
864 | static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) |
865 | { | |
866 | struct zfcp_adapter *adapter = act->adapter; | |
867 | struct zfcp_port *port = act->port; | |
287ac01a CS |
868 | int p_status = atomic_read(&port->status); |
869 | ||
870 | switch (act->step) { | |
871 | case ZFCP_ERP_STEP_UNINITIALIZED: | |
872 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: | |
873 | case ZFCP_ERP_STEP_PORT_CLOSING: | |
874 | if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) | |
875 | return zfcp_erp_open_ptp_port(act); | |
b98478d7 | 876 | if (!port->d_id) { |
947a9aca | 877 | zfcp_port_get(port); |
4544683a | 878 | if (!queue_work(adapter->work_queue, |
947a9aca SS |
879 | &port->gid_pn_work)) |
880 | zfcp_port_put(port); | |
5ab944f9 | 881 | return ZFCP_ERP_CONTINUES; |
287ac01a | 882 | } |
dceab655 | 883 | /* fall through */ |
287ac01a | 884 | case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: |
a5b11dda | 885 | if (!port->d_id) |
287ac01a | 886 | return ZFCP_ERP_FAILED; |
287ac01a CS |
887 | return zfcp_erp_port_strategy_open_port(act); |
888 | ||
889 | case ZFCP_ERP_STEP_PORT_OPENING: | |
890 | /* D_ID might have changed during open */ | |
5ab944f9 | 891 | if (p_status & ZFCP_STATUS_COMMON_OPEN) { |
b98478d7 | 892 | if (port->d_id) |
5ab944f9 SS |
893 | return ZFCP_ERP_SUCCEEDED; |
894 | else { | |
895 | act->step = ZFCP_ERP_STEP_PORT_CLOSING; | |
896 | return ZFCP_ERP_CONTINUES; | |
897 | } | |
5ab944f9 | 898 | } |
ea460a81 SS |
899 | if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) { |
900 | port->d_id = 0; | |
901 | _zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL); | |
902 | return ZFCP_ERP_EXIT; | |
903 | } | |
904 | /* fall through otherwise */ | |
287ac01a CS |
905 | } |
906 | return ZFCP_ERP_FAILED; | |
907 | } | |
908 | ||
287ac01a CS |
909 | static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) |
910 | { | |
911 | struct zfcp_port *port = erp_action->port; | |
912 | ||
5ab944f9 SS |
913 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) |
914 | goto close_init_done; | |
915 | ||
287ac01a CS |
916 | switch (erp_action->step) { |
917 | case ZFCP_ERP_STEP_UNINITIALIZED: | |
918 | zfcp_erp_port_strategy_clearstati(port); | |
919 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) | |
920 | return zfcp_erp_port_strategy_close(erp_action); | |
1da177e4 LT |
921 | break; |
922 | ||
287ac01a CS |
923 | case ZFCP_ERP_STEP_PORT_CLOSING: |
924 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) | |
925 | return ZFCP_ERP_FAILED; | |
1da177e4 LT |
926 | break; |
927 | } | |
5ab944f9 SS |
928 | |
929 | close_init_done: | |
287ac01a CS |
930 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) |
931 | return ZFCP_ERP_EXIT; | |
1da177e4 | 932 | |
5ab944f9 | 933 | return zfcp_erp_port_strategy_open_common(erp_action); |
287ac01a CS |
934 | } |
935 | ||
936 | static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) | |
937 | { | |
44cc76f2 | 938 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | |
287ac01a CS |
939 | ZFCP_STATUS_UNIT_SHARED | |
940 | ZFCP_STATUS_UNIT_READONLY, | |
941 | &unit->status); | |
942 | } | |
943 | ||
944 | static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) | |
945 | { | |
946 | int retval = zfcp_fsf_close_unit(erp_action); | |
947 | if (retval == -ENOMEM) | |
948 | return ZFCP_ERP_NOMEM; | |
949 | erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING; | |
950 | if (retval) | |
951 | return ZFCP_ERP_FAILED; | |
952 | return ZFCP_ERP_CONTINUES; | |
953 | } | |
954 | ||
955 | static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action) | |
956 | { | |
957 | int retval = zfcp_fsf_open_unit(erp_action); | |
958 | if (retval == -ENOMEM) | |
959 | return ZFCP_ERP_NOMEM; | |
960 | erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING; | |
961 | if (retval) | |
962 | return ZFCP_ERP_FAILED; | |
963 | return ZFCP_ERP_CONTINUES; | |
1da177e4 LT |
964 | } |
965 | ||
287ac01a | 966 | static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) |
1da177e4 | 967 | { |
287ac01a CS |
968 | struct zfcp_unit *unit = erp_action->unit; |
969 | ||
970 | switch (erp_action->step) { | |
971 | case ZFCP_ERP_STEP_UNINITIALIZED: | |
972 | zfcp_erp_unit_strategy_clearstati(unit); | |
973 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) | |
974 | return zfcp_erp_unit_strategy_close(erp_action); | |
975 | /* already closed, fall through */ | |
976 | case ZFCP_ERP_STEP_UNIT_CLOSING: | |
977 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) | |
978 | return ZFCP_ERP_FAILED; | |
979 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) | |
980 | return ZFCP_ERP_EXIT; | |
981 | return zfcp_erp_unit_strategy_open(erp_action); | |
982 | ||
983 | case ZFCP_ERP_STEP_UNIT_OPENING: | |
984 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) | |
985 | return ZFCP_ERP_SUCCEEDED; | |
986 | } | |
987 | return ZFCP_ERP_FAILED; | |
1da177e4 LT |
988 | } |
989 | ||
287ac01a | 990 | static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) |
1da177e4 | 991 | { |
1da177e4 LT |
992 | switch (result) { |
993 | case ZFCP_ERP_SUCCEEDED : | |
994 | atomic_set(&unit->erp_counter, 0); | |
995 | zfcp_erp_unit_unblock(unit); | |
996 | break; | |
997 | case ZFCP_ERP_FAILED : | |
998 | atomic_inc(&unit->erp_counter); | |
ff3b24fa CS |
999 | if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) { |
1000 | dev_err(&unit->port->adapter->ccw_device->dev, | |
1001 | "ERP failed for unit 0x%016Lx on " | |
1002 | "port 0x%016Lx\n", | |
7ba58c9c SS |
1003 | (unsigned long long)unit->fcp_lun, |
1004 | (unsigned long long)unit->port->wwpn); | |
5ffd51a5 | 1005 | zfcp_erp_unit_failed(unit, "erusck1", NULL); |
ff3b24fa | 1006 | } |
1da177e4 | 1007 | break; |
1da177e4 LT |
1008 | } |
1009 | ||
287ac01a CS |
1010 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
1011 | zfcp_erp_unit_block(unit, 0); | |
1da177e4 LT |
1012 | result = ZFCP_ERP_EXIT; |
1013 | } | |
1da177e4 LT |
1014 | return result; |
1015 | } | |
1016 | ||
287ac01a | 1017 | static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) |
1da177e4 | 1018 | { |
1da177e4 LT |
1019 | switch (result) { |
1020 | case ZFCP_ERP_SUCCEEDED : | |
1021 | atomic_set(&port->erp_counter, 0); | |
1022 | zfcp_erp_port_unblock(port); | |
1023 | break; | |
287ac01a | 1024 | |
1da177e4 | 1025 | case ZFCP_ERP_FAILED : |
287ac01a | 1026 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) { |
cc8c2829 SS |
1027 | zfcp_erp_port_block(port, 0); |
1028 | result = ZFCP_ERP_EXIT; | |
1029 | } | |
1da177e4 | 1030 | atomic_inc(&port->erp_counter); |
ff3b24fa CS |
1031 | if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) { |
1032 | dev_err(&port->adapter->ccw_device->dev, | |
1033 | "ERP failed for remote port 0x%016Lx\n", | |
7ba58c9c | 1034 | (unsigned long long)port->wwpn); |
5ffd51a5 | 1035 | zfcp_erp_port_failed(port, "erpsck1", NULL); |
ff3b24fa | 1036 | } |
1da177e4 | 1037 | break; |
1da177e4 LT |
1038 | } |
1039 | ||
287ac01a CS |
1040 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
1041 | zfcp_erp_port_block(port, 0); | |
1da177e4 LT |
1042 | result = ZFCP_ERP_EXIT; |
1043 | } | |
1da177e4 LT |
1044 | return result; |
1045 | } | |
1046 | ||
287ac01a CS |
1047 | static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, |
1048 | int result) | |
1da177e4 | 1049 | { |
1da177e4 LT |
1050 | switch (result) { |
1051 | case ZFCP_ERP_SUCCEEDED : | |
1052 | atomic_set(&adapter->erp_counter, 0); | |
1053 | zfcp_erp_adapter_unblock(adapter); | |
1054 | break; | |
287ac01a | 1055 | |
1da177e4 LT |
1056 | case ZFCP_ERP_FAILED : |
1057 | atomic_inc(&adapter->erp_counter); | |
ff3b24fa CS |
1058 | if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) { |
1059 | dev_err(&adapter->ccw_device->dev, | |
1060 | "ERP cannot recover an error " | |
1061 | "on the FCP device\n"); | |
5ffd51a5 | 1062 | zfcp_erp_adapter_failed(adapter, "erasck1", NULL); |
ff3b24fa | 1063 | } |
1da177e4 | 1064 | break; |
1da177e4 LT |
1065 | } |
1066 | ||
287ac01a CS |
1067 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
1068 | zfcp_erp_adapter_block(adapter, 0); | |
1da177e4 LT |
1069 | result = ZFCP_ERP_EXIT; |
1070 | } | |
1da177e4 LT |
1071 | return result; |
1072 | } | |
1073 | ||
287ac01a CS |
1074 | static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action, |
1075 | int result) | |
5f852be9 | 1076 | { |
287ac01a CS |
1077 | struct zfcp_adapter *adapter = erp_action->adapter; |
1078 | struct zfcp_port *port = erp_action->port; | |
1079 | struct zfcp_unit *unit = erp_action->unit; | |
1080 | ||
1081 | switch (erp_action->action) { | |
1082 | ||
1083 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | |
1084 | result = zfcp_erp_strategy_check_unit(unit, result); | |
1085 | break; | |
1086 | ||
1087 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | |
1088 | case ZFCP_ERP_ACTION_REOPEN_PORT: | |
1089 | result = zfcp_erp_strategy_check_port(port, result); | |
1090 | break; | |
1091 | ||
1092 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | |
1093 | result = zfcp_erp_strategy_check_adapter(adapter, result); | |
1094 | break; | |
1095 | } | |
1096 | return result; | |
5f852be9 CS |
1097 | } |
1098 | ||
287ac01a | 1099 | static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status) |
5f852be9 | 1100 | { |
287ac01a | 1101 | int status = atomic_read(target_status); |
5f852be9 | 1102 | |
287ac01a CS |
1103 | if ((status & ZFCP_STATUS_COMMON_RUNNING) && |
1104 | (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) | |
1105 | return 1; /* take it online */ | |
5f852be9 | 1106 | |
287ac01a CS |
1107 | if (!(status & ZFCP_STATUS_COMMON_RUNNING) && |
1108 | !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) | |
1109 | return 1; /* take it offline */ | |
1110 | ||
1111 | return 0; | |
5f852be9 CS |
1112 | } |
1113 | ||
287ac01a | 1114 | static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) |
1da177e4 | 1115 | { |
287ac01a CS |
1116 | int action = act->action; |
1117 | struct zfcp_adapter *adapter = act->adapter; | |
1118 | struct zfcp_port *port = act->port; | |
1119 | struct zfcp_unit *unit = act->unit; | |
1120 | u32 erp_status = act->status; | |
1da177e4 | 1121 | |
287ac01a | 1122 | switch (action) { |
1da177e4 | 1123 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
287ac01a CS |
1124 | if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) { |
1125 | _zfcp_erp_adapter_reopen(adapter, | |
1126 | ZFCP_STATUS_COMMON_ERP_FAILED, | |
5ffd51a5 | 1127 | "ersscg1", NULL); |
287ac01a CS |
1128 | return ZFCP_ERP_EXIT; |
1129 | } | |
1da177e4 LT |
1130 | break; |
1131 | ||
1132 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | |
1da177e4 | 1133 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
287ac01a CS |
1134 | if (zfcp_erp_strat_change_det(&port->status, erp_status)) { |
1135 | _zfcp_erp_port_reopen(port, | |
1136 | ZFCP_STATUS_COMMON_ERP_FAILED, | |
5ffd51a5 | 1137 | "ersscg2", NULL); |
287ac01a CS |
1138 | return ZFCP_ERP_EXIT; |
1139 | } | |
1da177e4 LT |
1140 | break; |
1141 | ||
1142 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | |
287ac01a CS |
1143 | if (zfcp_erp_strat_change_det(&unit->status, erp_status)) { |
1144 | _zfcp_erp_unit_reopen(unit, | |
1145 | ZFCP_STATUS_COMMON_ERP_FAILED, | |
5ffd51a5 | 1146 | "ersscg3", NULL); |
287ac01a CS |
1147 | return ZFCP_ERP_EXIT; |
1148 | } | |
1da177e4 LT |
1149 | break; |
1150 | } | |
287ac01a | 1151 | return ret; |
1da177e4 LT |
1152 | } |
1153 | ||
287ac01a | 1154 | static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) |
1da177e4 | 1155 | { |
287ac01a | 1156 | struct zfcp_adapter *adapter = erp_action->adapter; |
1da177e4 | 1157 | |
287ac01a CS |
1158 | adapter->erp_total_count--; |
1159 | if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { | |
1160 | adapter->erp_low_mem_count--; | |
1161 | erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; | |
507e4969 | 1162 | } |
1da177e4 | 1163 | |
287ac01a | 1164 | list_del(&erp_action->list); |
5ffd51a5 | 1165 | zfcp_rec_dbf_event_action("eractd1", erp_action); |
1da177e4 | 1166 | |
287ac01a CS |
1167 | switch (erp_action->action) { |
1168 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | |
1169 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | |
1170 | &erp_action->unit->status); | |
1171 | break; | |
1da177e4 | 1172 | |
287ac01a CS |
1173 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
1174 | case ZFCP_ERP_ACTION_REOPEN_PORT: | |
1175 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | |
1176 | &erp_action->port->status); | |
1177 | break; | |
1da177e4 | 1178 | |
287ac01a CS |
1179 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
1180 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | |
1181 | &erp_action->adapter->status); | |
1182 | break; | |
1183 | } | |
1da177e4 LT |
1184 | } |
1185 | ||
287ac01a | 1186 | static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) |
1da177e4 | 1187 | { |
287ac01a CS |
1188 | struct zfcp_adapter *adapter = act->adapter; |
1189 | struct zfcp_port *port = act->port; | |
1190 | struct zfcp_unit *unit = act->unit; | |
1da177e4 | 1191 | |
287ac01a CS |
1192 | switch (act->action) { |
1193 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | |
a2fa0aed | 1194 | if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { |
92d5193b SS |
1195 | zfcp_unit_get(unit); |
1196 | if (scsi_queue_work(unit->port->adapter->scsi_host, | |
1197 | &unit->scsi_work) <= 0) | |
1198 | zfcp_unit_put(unit); | |
287ac01a CS |
1199 | } |
1200 | zfcp_unit_put(unit); | |
1201 | break; | |
1da177e4 | 1202 | |
287ac01a CS |
1203 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
1204 | case ZFCP_ERP_ACTION_REOPEN_PORT: | |
a2fa0aed CS |
1205 | if (result == ZFCP_ERP_SUCCEEDED) |
1206 | zfcp_scsi_schedule_rport_register(port); | |
287ac01a CS |
1207 | zfcp_port_put(port); |
1208 | break; | |
1209 | ||
1210 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | |
a2fa0aed | 1211 | if (result == ZFCP_ERP_SUCCEEDED) { |
bd43a42b | 1212 | register_service_level(&adapter->service_level); |
fca55b6f | 1213 | schedule_work(&adapter->scan_work); |
a2fa0aed CS |
1214 | } else |
1215 | unregister_service_level(&adapter->service_level); | |
287ac01a CS |
1216 | zfcp_adapter_put(adapter); |
1217 | break; | |
1218 | } | |
1da177e4 LT |
1219 | } |
1220 | ||
287ac01a | 1221 | static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) |
1da177e4 | 1222 | { |
287ac01a CS |
1223 | switch (erp_action->action) { |
1224 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | |
1225 | return zfcp_erp_adapter_strategy(erp_action); | |
1226 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | |
1227 | return zfcp_erp_port_forced_strategy(erp_action); | |
1228 | case ZFCP_ERP_ACTION_REOPEN_PORT: | |
1229 | return zfcp_erp_port_strategy(erp_action); | |
1230 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | |
1231 | return zfcp_erp_unit_strategy(erp_action); | |
1232 | } | |
1233 | return ZFCP_ERP_FAILED; | |
1da177e4 LT |
1234 | } |
1235 | ||
287ac01a | 1236 | static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) |
1da177e4 LT |
1237 | { |
1238 | int retval; | |
287ac01a CS |
1239 | struct zfcp_adapter *adapter = erp_action->adapter; |
1240 | unsigned long flags; | |
1da177e4 | 1241 | |
287ac01a CS |
1242 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
1243 | write_lock(&adapter->erp_lock); | |
1da177e4 | 1244 | |
287ac01a | 1245 | zfcp_erp_strategy_check_fsfreq(erp_action); |
1da177e4 | 1246 | |
287ac01a CS |
1247 | if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { |
1248 | zfcp_erp_action_dequeue(erp_action); | |
1249 | retval = ZFCP_ERP_DISMISSED; | |
1250 | goto unlock; | |
22753fa5 | 1251 | } |
1da177e4 | 1252 | |
2f8f3ed5 | 1253 | zfcp_erp_action_to_running(erp_action); |
1da177e4 | 1254 | |
287ac01a CS |
1255 | /* no lock to allow for blocking operations */ |
1256 | write_unlock(&adapter->erp_lock); | |
1257 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | |
1258 | retval = zfcp_erp_strategy_do_action(erp_action); | |
1259 | read_lock_irqsave(&zfcp_data.config_lock, flags); | |
1260 | write_lock(&adapter->erp_lock); | |
1da177e4 | 1261 | |
287ac01a CS |
1262 | if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) |
1263 | retval = ZFCP_ERP_CONTINUES; | |
cc8c2829 | 1264 | |
287ac01a CS |
1265 | switch (retval) { |
1266 | case ZFCP_ERP_NOMEM: | |
1267 | if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) { | |
1268 | ++adapter->erp_low_mem_count; | |
1269 | erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; | |
1da177e4 | 1270 | } |
287ac01a | 1271 | if (adapter->erp_total_count == adapter->erp_low_mem_count) |
5ffd51a5 | 1272 | _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL); |
287ac01a CS |
1273 | else { |
1274 | zfcp_erp_strategy_memwait(erp_action); | |
1275 | retval = ZFCP_ERP_CONTINUES; | |
1da177e4 | 1276 | } |
287ac01a | 1277 | goto unlock; |
1da177e4 | 1278 | |
287ac01a CS |
1279 | case ZFCP_ERP_CONTINUES: |
1280 | if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { | |
1281 | --adapter->erp_low_mem_count; | |
1282 | erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; | |
1da177e4 | 1283 | } |
287ac01a | 1284 | goto unlock; |
1da177e4 LT |
1285 | } |
1286 | ||
287ac01a CS |
1287 | retval = zfcp_erp_strategy_check_target(erp_action, retval); |
1288 | zfcp_erp_action_dequeue(erp_action); | |
1289 | retval = zfcp_erp_strategy_statechange(erp_action, retval); | |
1290 | if (retval == ZFCP_ERP_EXIT) | |
1291 | goto unlock; | |
85600f7f CS |
1292 | if (retval == ZFCP_ERP_SUCCEEDED) |
1293 | zfcp_erp_strategy_followup_success(erp_action); | |
1294 | if (retval == ZFCP_ERP_FAILED) | |
1295 | zfcp_erp_strategy_followup_failed(erp_action); | |
1da177e4 | 1296 | |
287ac01a CS |
1297 | unlock: |
1298 | write_unlock(&adapter->erp_lock); | |
1299 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | |
1da177e4 | 1300 | |
287ac01a CS |
1301 | if (retval != ZFCP_ERP_CONTINUES) |
1302 | zfcp_erp_action_cleanup(erp_action, retval); | |
1da177e4 | 1303 | |
1da177e4 LT |
1304 | return retval; |
1305 | } | |
1306 | ||
287ac01a | 1307 | static int zfcp_erp_thread(void *data) |
1da177e4 | 1308 | { |
287ac01a CS |
1309 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; |
1310 | struct list_head *next; | |
1311 | struct zfcp_erp_action *act; | |
1312 | unsigned long flags; | |
06499fac | 1313 | int ignore; |
1da177e4 | 1314 | |
b9d3aed7 | 1315 | daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev)); |
287ac01a CS |
1316 | /* Block all signals */ |
1317 | siginitsetinv(¤t->blocked, 0); | |
1318 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | |
1319 | wake_up(&adapter->erp_thread_wqh); | |
1da177e4 | 1320 | |
287ac01a CS |
1321 | while (!(atomic_read(&adapter->status) & |
1322 | ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) { | |
94ab4b38 SS |
1323 | |
1324 | zfcp_rec_dbf_event_thread_lock("erthrd1", adapter); | |
1325 | ignore = down_interruptible(&adapter->erp_ready_sem); | |
1326 | zfcp_rec_dbf_event_thread_lock("erthrd2", adapter); | |
1327 | ||
287ac01a CS |
1328 | write_lock_irqsave(&adapter->erp_lock, flags); |
1329 | next = adapter->erp_ready_head.next; | |
1330 | write_unlock_irqrestore(&adapter->erp_lock, flags); | |
1da177e4 | 1331 | |
287ac01a CS |
1332 | if (next != &adapter->erp_ready_head) { |
1333 | act = list_entry(next, struct zfcp_erp_action, list); | |
1da177e4 | 1334 | |
287ac01a CS |
1335 | /* there is more to come after dismission, no notify */ |
1336 | if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED) | |
1337 | zfcp_erp_wakeup(adapter); | |
1da177e4 | 1338 | } |
1da177e4 LT |
1339 | } |
1340 | ||
287ac01a CS |
1341 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); |
1342 | wake_up(&adapter->erp_thread_wqh); | |
1da177e4 | 1343 | |
287ac01a CS |
1344 | return 0; |
1345 | } | |
1da177e4 | 1346 | |
287ac01a CS |
1347 | /** |
1348 | * zfcp_erp_thread_setup - Start ERP thread for adapter | |
1349 | * @adapter: Adapter to start the ERP thread for | |
1350 | * | |
1351 | * Returns 0 on success or error code from kernel_thread() | |
1352 | */ | |
1353 | int zfcp_erp_thread_setup(struct zfcp_adapter *adapter) | |
1354 | { | |
1355 | int retval; | |
1da177e4 | 1356 | |
287ac01a CS |
1357 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); |
1358 | retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); | |
1359 | if (retval < 0) { | |
1360 | dev_err(&adapter->ccw_device->dev, | |
ff3b24fa | 1361 | "Creating an ERP thread for the FCP device failed.\n"); |
287ac01a | 1362 | return retval; |
1da177e4 | 1363 | } |
287ac01a CS |
1364 | wait_event(adapter->erp_thread_wqh, |
1365 | atomic_read(&adapter->status) & | |
1366 | ZFCP_STATUS_ADAPTER_ERP_THREAD_UP); | |
1367 | return 0; | |
1368 | } | |
1da177e4 | 1369 | |
287ac01a CS |
1370 | /** |
1371 | * zfcp_erp_thread_kill - Stop ERP thread. | |
1372 | * @adapter: Adapter where the ERP thread should be stopped. | |
1373 | * | |
1374 | * The caller of this routine ensures that the specified adapter has | |
1375 | * been shut down and that this operation has been completed. Thus, | |
1376 | * there are no pending erp_actions which would need to be handled | |
1377 | * here. | |
1378 | */ | |
1379 | void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) | |
1380 | { | |
1381 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); | |
1382 | up(&adapter->erp_ready_sem); | |
5ffd51a5 | 1383 | zfcp_rec_dbf_event_thread_lock("erthrk1", adapter); |
1da177e4 | 1384 | |
287ac01a CS |
1385 | wait_event(adapter->erp_thread_wqh, |
1386 | !(atomic_read(&adapter->status) & | |
1387 | ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)); | |
1da177e4 | 1388 | |
287ac01a CS |
1389 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, |
1390 | &adapter->status); | |
1da177e4 LT |
1391 | } |
1392 | ||
287ac01a CS |
1393 | /** |
1394 | * zfcp_erp_adapter_failed - Set adapter status to failed. | |
1395 | * @adapter: Failed adapter. | |
1396 | * @id: Event id for debug trace. | |
1397 | * @ref: Reference for debug trace. | |
1398 | */ | |
5ffd51a5 | 1399 | void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, char *id, void *ref) |
1da177e4 | 1400 | { |
287ac01a CS |
1401 | zfcp_erp_modify_adapter_status(adapter, id, ref, |
1402 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | |
287ac01a | 1403 | } |
1da177e4 | 1404 | |
287ac01a CS |
1405 | /** |
1406 | * zfcp_erp_port_failed - Set port status to failed. | |
1407 | * @port: Failed port. | |
1408 | * @id: Event id for debug trace. | |
1409 | * @ref: Reference for debug trace. | |
1410 | */ | |
5ffd51a5 | 1411 | void zfcp_erp_port_failed(struct zfcp_port *port, char *id, void *ref) |
287ac01a CS |
1412 | { |
1413 | zfcp_erp_modify_port_status(port, id, ref, | |
1414 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | |
1da177e4 LT |
1415 | } |
1416 | ||
1417 | /** | |
287ac01a CS |
1418 | * zfcp_erp_unit_failed - Set unit status to failed. |
1419 | * @unit: Failed unit. | |
1420 | * @id: Event id for debug trace. | |
1421 | * @ref: Reference for debug trace. | |
1da177e4 | 1422 | */ |
5ffd51a5 | 1423 | void zfcp_erp_unit_failed(struct zfcp_unit *unit, char *id, void *ref) |
1da177e4 | 1424 | { |
287ac01a CS |
1425 | zfcp_erp_modify_unit_status(unit, id, ref, |
1426 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | |
1da177e4 LT |
1427 | } |
1428 | ||
287ac01a CS |
1429 | /** |
1430 | * zfcp_erp_wait - wait for completion of error recovery on an adapter | |
1431 | * @adapter: adapter for which to wait for completion of its error recovery | |
1432 | */ | |
1433 | void zfcp_erp_wait(struct zfcp_adapter *adapter) | |
1434 | { | |
1435 | wait_event(adapter->erp_done_wqh, | |
1436 | !(atomic_read(&adapter->status) & | |
1437 | ZFCP_STATUS_ADAPTER_ERP_PENDING)); | |
1438 | } | |
1da177e4 | 1439 | |
287ac01a CS |
1440 | /** |
1441 | * zfcp_erp_modify_adapter_status - change adapter status bits | |
1442 | * @adapter: adapter to change the status | |
1443 | * @id: id for the debug trace | |
1444 | * @ref: reference for the debug trace | |
1445 | * @mask: status bits to change | |
1446 | * @set_or_clear: ZFCP_SET or ZFCP_CLEAR | |
1447 | * | |
1448 | * Changes in common status bits are propagated to attached ports and units. | |
1449 | */ | |
5ffd51a5 | 1450 | void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id, |
287ac01a | 1451 | void *ref, u32 mask, int set_or_clear) |
1da177e4 | 1452 | { |
1da177e4 | 1453 | struct zfcp_port *port; |
287ac01a | 1454 | u32 common_mask = mask & ZFCP_COMMON_FLAGS; |
1da177e4 | 1455 | |
287ac01a CS |
1456 | if (set_or_clear == ZFCP_SET) { |
1457 | if (status_change_set(mask, &adapter->status)) | |
1458 | zfcp_rec_dbf_event_adapter(id, ref, adapter); | |
1459 | atomic_set_mask(mask, &adapter->status); | |
1460 | } else { | |
1461 | if (status_change_clear(mask, &adapter->status)) | |
1462 | zfcp_rec_dbf_event_adapter(id, ref, adapter); | |
1463 | atomic_clear_mask(mask, &adapter->status); | |
1464 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) | |
1465 | atomic_set(&adapter->erp_counter, 0); | |
1466 | } | |
1467 | ||
1468 | if (common_mask) | |
1da177e4 | 1469 | list_for_each_entry(port, &adapter->port_list_head, list) |
287ac01a CS |
1470 | zfcp_erp_modify_port_status(port, id, ref, common_mask, |
1471 | set_or_clear); | |
1da177e4 LT |
1472 | } |
1473 | ||
287ac01a CS |
1474 | /** |
1475 | * zfcp_erp_modify_port_status - change port status bits | |
1476 | * @port: port to change the status bits | |
1477 | * @id: id for the debug trace | |
1478 | * @ref: reference for the debug trace | |
1479 | * @mask: status bits to change | |
1480 | * @set_or_clear: ZFCP_SET or ZFCP_CLEAR | |
1481 | * | |
1482 | * Changes in common status bits are propagated to attached units. | |
1483 | */ | |
5ffd51a5 | 1484 | void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref, |
287ac01a | 1485 | u32 mask, int set_or_clear) |
1da177e4 | 1486 | { |
1da177e4 | 1487 | struct zfcp_unit *unit; |
287ac01a | 1488 | u32 common_mask = mask & ZFCP_COMMON_FLAGS; |
1da177e4 | 1489 | |
287ac01a CS |
1490 | if (set_or_clear == ZFCP_SET) { |
1491 | if (status_change_set(mask, &port->status)) | |
1492 | zfcp_rec_dbf_event_port(id, ref, port); | |
1493 | atomic_set_mask(mask, &port->status); | |
1494 | } else { | |
1495 | if (status_change_clear(mask, &port->status)) | |
1496 | zfcp_rec_dbf_event_port(id, ref, port); | |
1497 | atomic_clear_mask(mask, &port->status); | |
1498 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) | |
1499 | atomic_set(&port->erp_counter, 0); | |
1500 | } | |
1da177e4 | 1501 | |
287ac01a CS |
1502 | if (common_mask) |
1503 | list_for_each_entry(unit, &port->unit_list_head, list) | |
1504 | zfcp_erp_modify_unit_status(unit, id, ref, common_mask, | |
1505 | set_or_clear); | |
1da177e4 LT |
1506 | } |
1507 | ||
287ac01a CS |
1508 | /** |
1509 | * zfcp_erp_modify_unit_status - change unit status bits | |
1510 | * @unit: unit to change the status bits | |
1511 | * @id: id for the debug trace | |
1512 | * @ref: reference for the debug trace | |
1513 | * @mask: status bits to change | |
1514 | * @set_or_clear: ZFCP_SET or ZFCP_CLEAR | |
1515 | */ | |
5ffd51a5 | 1516 | void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref, |
287ac01a | 1517 | u32 mask, int set_or_clear) |
1da177e4 | 1518 | { |
287ac01a CS |
1519 | if (set_or_clear == ZFCP_SET) { |
1520 | if (status_change_set(mask, &unit->status)) | |
1521 | zfcp_rec_dbf_event_unit(id, ref, unit); | |
1522 | atomic_set_mask(mask, &unit->status); | |
1523 | } else { | |
1524 | if (status_change_clear(mask, &unit->status)) | |
1525 | zfcp_rec_dbf_event_unit(id, ref, unit); | |
1526 | atomic_clear_mask(mask, &unit->status); | |
1527 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { | |
1528 | atomic_set(&unit->erp_counter, 0); | |
1529 | } | |
1530 | } | |
1da177e4 LT |
1531 | } |
1532 | ||
287ac01a CS |
1533 | /** |
1534 | * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP | |
1535 | * @port: The "boxed" port. | |
1536 | * @id: The debug trace id. | |
1537 | * @id: Reference for the debug trace. | |
1538 | */ | |
5ffd51a5 | 1539 | void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref) |
d736a27b | 1540 | { |
d736a27b AH |
1541 | unsigned long flags; |
1542 | ||
d736a27b | 1543 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
698ec016 MP |
1544 | zfcp_erp_modify_port_status(port, id, ref, |
1545 | ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); | |
d736a27b | 1546 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
9467a9b3 | 1547 | zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
d736a27b AH |
1548 | } |
1549 | ||
287ac01a CS |
1550 | /** |
1551 | * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP | |
1552 | * @port: The "boxed" unit. | |
1553 | * @id: The debug trace id. | |
1554 | * @id: Reference for the debug trace. | |
1555 | */ | |
5ffd51a5 | 1556 | void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref) |
d736a27b | 1557 | { |
698ec016 MP |
1558 | zfcp_erp_modify_unit_status(unit, id, ref, |
1559 | ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); | |
9467a9b3 | 1560 | zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
d736a27b AH |
1561 | } |
1562 | ||
287ac01a CS |
1563 | /** |
1564 | * zfcp_erp_port_access_denied - Adapter denied access to port. | |
1565 | * @port: port where access has been denied | |
1566 | * @id: id for debug trace | |
1567 | * @ref: reference for debug trace | |
1568 | * | |
1569 | * Since the adapter has denied access, stop using the port and the | |
1570 | * attached units. | |
1571 | */ | |
5ffd51a5 | 1572 | void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref) |
1da177e4 | 1573 | { |
1da177e4 LT |
1574 | unsigned long flags; |
1575 | ||
1da177e4 | 1576 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
698ec016 MP |
1577 | zfcp_erp_modify_port_status(port, id, ref, |
1578 | ZFCP_STATUS_COMMON_ERP_FAILED | | |
1579 | ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); | |
1da177e4 LT |
1580 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
1581 | } | |
1582 | ||
287ac01a CS |
1583 | /** |
1584 | * zfcp_erp_unit_access_denied - Adapter denied access to unit. | |
1585 | * @unit: unit where access has been denied | |
1586 | * @id: id for debug trace | |
1587 | * @ref: reference for debug trace | |
1588 | * | |
1589 | * Since the adapter has denied access, stop using the unit. | |
1590 | */ | |
5ffd51a5 | 1591 | void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, char *id, void *ref) |
1da177e4 | 1592 | { |
698ec016 MP |
1593 | zfcp_erp_modify_unit_status(unit, id, ref, |
1594 | ZFCP_STATUS_COMMON_ERP_FAILED | | |
1595 | ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); | |
1da177e4 LT |
1596 | } |
1597 | ||
5ffd51a5 | 1598 | static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, char *id, |
287ac01a | 1599 | void *ref) |
1da177e4 | 1600 | { |
287ac01a CS |
1601 | int status = atomic_read(&unit->status); |
1602 | if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | | |
1603 | ZFCP_STATUS_COMMON_ACCESS_BOXED))) | |
aef4a983 MS |
1604 | return; |
1605 | ||
287ac01a | 1606 | zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
1da177e4 LT |
1607 | } |
1608 | ||
5ffd51a5 | 1609 | static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id, |
287ac01a | 1610 | void *ref) |
1da177e4 | 1611 | { |
1da177e4 | 1612 | struct zfcp_unit *unit; |
287ac01a | 1613 | int status = atomic_read(&port->status); |
1da177e4 | 1614 | |
287ac01a CS |
1615 | if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | |
1616 | ZFCP_STATUS_COMMON_ACCESS_BOXED))) { | |
5ab944f9 SS |
1617 | list_for_each_entry(unit, &port->unit_list_head, list) |
1618 | zfcp_erp_unit_access_changed(unit, id, ref); | |
1da177e4 LT |
1619 | return; |
1620 | } | |
1621 | ||
553448f6 | 1622 | zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
1da177e4 LT |
1623 | } |
1624 | ||
287ac01a CS |
1625 | /** |
1626 | * zfcp_erp_adapter_access_changed - Process change in adapter ACT | |
1627 | * @adapter: Adapter where the Access Control Table (ACT) changed | |
1628 | * @id: Id for debug trace | |
1629 | * @ref: Reference for debug trace | |
1630 | */ | |
5ffd51a5 | 1631 | void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id, |
287ac01a | 1632 | void *ref) |
1da177e4 | 1633 | { |
287ac01a CS |
1634 | struct zfcp_port *port; |
1635 | unsigned long flags; | |
1636 | ||
1637 | if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) | |
1da177e4 LT |
1638 | return; |
1639 | ||
287ac01a | 1640 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
287ac01a | 1641 | list_for_each_entry(port, &adapter->port_list_head, list) |
5ab944f9 | 1642 | zfcp_erp_port_access_changed(port, id, ref); |
287ac01a | 1643 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
1da177e4 | 1644 | } |