]>
Commit | Line | Data |
---|---|---|
41fa2ada | 1 | /* |
553448f6 | 2 | * zfcp device driver |
1da177e4 | 3 | * |
553448f6 | 4 | * Error Recovery Procedures (ERP). |
41fa2ada | 5 | * |
553448f6 | 6 | * Copyright IBM Corporation 2002, 2008 |
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 | { |
287ac01a CS |
58 | zfcp_erp_modify_adapter_status(adapter, 15, NULL, |
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); | |
78 | zfcp_rec_dbf_event_action(146, act); | |
79 | up(&adapter->erp_ready_sem); | |
80 | zfcp_rec_dbf_event_thread(2, 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, | |
211 | struct zfcp_unit *unit, u8 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); | |
231 | zfcp_rec_dbf_event_thread(1, adapter); | |
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 CS |
239 | static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, |
240 | int clear_mask, u8 id, void *ref) | |
241 | { | |
242 | zfcp_erp_adapter_block(adapter, clear_mask); | |
243 | ||
244 | /* ensure propagation of failed status to new devices */ | |
245 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { | |
246 | zfcp_erp_adapter_failed(adapter, 13, NULL); | |
247 | return -EIO; | |
248 | } | |
249 | return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, | |
250 | adapter, NULL, NULL, id, ref); | |
251 | } | |
252 | ||
253 | /** | |
254 | * zfcp_erp_adapter_reopen - Reopen adapter. | |
255 | * @adapter: Adapter to reopen. | |
256 | * @clear: Status flags to clear. | |
257 | * @id: Id for debug trace event. | |
258 | * @ref: Reference for debug trace event. | |
1da177e4 | 259 | */ |
287ac01a CS |
260 | void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, |
261 | u8 id, void *ref) | |
1da177e4 | 262 | { |
1da177e4 | 263 | unsigned long flags; |
1da177e4 | 264 | |
1da177e4 LT |
265 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
266 | write_lock(&adapter->erp_lock); | |
287ac01a | 267 | _zfcp_erp_adapter_reopen(adapter, clear, id, ref); |
1da177e4 LT |
268 | write_unlock(&adapter->erp_lock); |
269 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | |
287ac01a | 270 | } |
1da177e4 | 271 | |
287ac01a CS |
272 | /** |
273 | * zfcp_erp_adapter_shutdown - Shutdown adapter. | |
274 | * @adapter: Adapter to shut down. | |
275 | * @clear: Status flags to clear. | |
276 | * @id: Id for debug trace event. | |
277 | * @ref: Reference for debug trace event. | |
278 | */ | |
279 | void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear, | |
280 | u8 id, void *ref) | |
281 | { | |
282 | int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; | |
283 | zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref); | |
1da177e4 LT |
284 | } |
285 | ||
287ac01a CS |
286 | /** |
287 | * zfcp_erp_port_shutdown - Shutdown port | |
288 | * @port: Port to shut down. | |
289 | * @clear: Status flags to clear. | |
290 | * @id: Id for debug trace event. | |
291 | * @ref: Reference for debug trace event. | |
1da177e4 | 292 | */ |
287ac01a | 293 | void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, u8 id, void *ref) |
1da177e4 | 294 | { |
287ac01a CS |
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 | */ | |
306 | void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, u8 id, void *ref) | |
307 | { | |
308 | int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; | |
309 | zfcp_erp_unit_reopen(unit, clear | flags, id, ref); | |
310 | } | |
311 | ||
312 | static void zfcp_erp_port_block(struct zfcp_port *port, int clear) | |
313 | { | |
314 | zfcp_erp_modify_port_status(port, 17, NULL, | |
315 | ZFCP_STATUS_COMMON_UNBLOCKED | clear, | |
316 | ZFCP_CLEAR); | |
317 | } | |
318 | ||
319 | static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, | |
320 | int clear, u8 id, void *ref) | |
321 | { | |
322 | zfcp_erp_port_block(port, clear); | |
323 | ||
324 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) | |
325 | return; | |
1da177e4 | 326 | |
287ac01a CS |
327 | zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, |
328 | port->adapter, port, NULL, id, ref); | |
329 | } | |
330 | ||
331 | /** | |
332 | * zfcp_erp_port_forced_reopen - Forced close of port and open again | |
333 | * @port: Port to force close and to reopen. | |
334 | * @id: Id for debug trace event. | |
335 | * @ref: Reference for debug trace event. | |
336 | */ | |
337 | void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, u8 id, | |
338 | void *ref) | |
339 | { | |
340 | unsigned long flags; | |
341 | struct zfcp_adapter *adapter = port->adapter; | |
342 | ||
343 | read_lock_irqsave(&zfcp_data.config_lock, flags); | |
344 | write_lock(&adapter->erp_lock); | |
345 | _zfcp_erp_port_forced_reopen(port, clear, id, ref); | |
346 | write_unlock(&adapter->erp_lock); | |
347 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | |
348 | } | |
349 | ||
350 | static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id, | |
351 | void *ref) | |
352 | { | |
353 | zfcp_erp_port_block(port, clear); | |
1da177e4 | 354 | |
287ac01a | 355 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
1da177e4 | 356 | /* ensure propagation of failed status to new devices */ |
1f6f7129 | 357 | zfcp_erp_port_failed(port, 14, NULL); |
287ac01a | 358 | return -EIO; |
1da177e4 LT |
359 | } |
360 | ||
287ac01a CS |
361 | return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, |
362 | port->adapter, port, NULL, id, ref); | |
1da177e4 LT |
363 | } |
364 | ||
365 | /** | |
287ac01a CS |
366 | * zfcp_erp_port_reopen - trigger remote port recovery |
367 | * @port: port to recover | |
368 | * @clear_mask: flags in port status to be cleared | |
1da177e4 | 369 | * |
287ac01a | 370 | * Returns 0 if recovery has been triggered, < 0 if not. |
1da177e4 | 371 | */ |
287ac01a | 372 | int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, u8 id, void *ref) |
1da177e4 | 373 | { |
1da177e4 | 374 | unsigned long flags; |
287ac01a | 375 | int retval; |
1da177e4 LT |
376 | struct zfcp_adapter *adapter = port->adapter; |
377 | ||
378 | read_lock_irqsave(&zfcp_data.config_lock, flags); | |
379 | write_lock(&adapter->erp_lock); | |
287ac01a | 380 | retval = _zfcp_erp_port_reopen(port, clear, id, ref); |
1da177e4 LT |
381 | write_unlock(&adapter->erp_lock); |
382 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | |
383 | ||
384 | return retval; | |
385 | } | |
386 | ||
287ac01a CS |
387 | static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) |
388 | { | |
389 | zfcp_erp_modify_unit_status(unit, 19, NULL, | |
390 | ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, | |
391 | ZFCP_CLEAR); | |
392 | } | |
393 | ||
394 | static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, u8 id, | |
395 | void *ref) | |
1da177e4 | 396 | { |
1da177e4 LT |
397 | struct zfcp_adapter *adapter = unit->port->adapter; |
398 | ||
287ac01a | 399 | zfcp_erp_unit_block(unit, clear); |
1da177e4 | 400 | |
287ac01a CS |
401 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) |
402 | return; | |
1da177e4 | 403 | |
287ac01a CS |
404 | zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, |
405 | adapter, unit->port, unit, id, ref); | |
1da177e4 LT |
406 | } |
407 | ||
408 | /** | |
409 | * zfcp_erp_unit_reopen - initiate reopen of a unit | |
410 | * @unit: unit to be reopened | |
411 | * @clear_mask: specifies flags in unit status to be cleared | |
412 | * Return: 0 on success, < 0 on error | |
1da177e4 | 413 | */ |
287ac01a | 414 | void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, u8 id, void *ref) |
1da177e4 | 415 | { |
1da177e4 | 416 | unsigned long flags; |
287ac01a CS |
417 | struct zfcp_port *port = unit->port; |
418 | struct zfcp_adapter *adapter = port->adapter; | |
1da177e4 LT |
419 | |
420 | read_lock_irqsave(&zfcp_data.config_lock, flags); | |
421 | write_lock(&adapter->erp_lock); | |
287ac01a | 422 | _zfcp_erp_unit_reopen(unit, clear, id, ref); |
1da177e4 LT |
423 | write_unlock(&adapter->erp_lock); |
424 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | |
1da177e4 LT |
425 | } |
426 | ||
287ac01a | 427 | static int status_change_set(unsigned long mask, atomic_t *status) |
1da177e4 | 428 | { |
287ac01a | 429 | return (atomic_read(status) ^ mask) & mask; |
1da177e4 LT |
430 | } |
431 | ||
287ac01a | 432 | static int status_change_clear(unsigned long mask, atomic_t *status) |
698ec016 | 433 | { |
287ac01a | 434 | return atomic_read(status) & mask; |
698ec016 MP |
435 | } |
436 | ||
287ac01a | 437 | static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) |
698ec016 | 438 | { |
287ac01a CS |
439 | if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) |
440 | zfcp_rec_dbf_event_adapter(16, NULL, adapter); | |
441 | atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); | |
698ec016 MP |
442 | } |
443 | ||
287ac01a | 444 | static void zfcp_erp_port_unblock(struct zfcp_port *port) |
1da177e4 | 445 | { |
287ac01a CS |
446 | if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) |
447 | zfcp_rec_dbf_event_port(18, NULL, port); | |
448 | atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); | |
1da177e4 LT |
449 | } |
450 | ||
287ac01a | 451 | static void zfcp_erp_unit_unblock(struct zfcp_unit *unit) |
1da177e4 | 452 | { |
287ac01a CS |
453 | if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status)) |
454 | zfcp_rec_dbf_event_unit(20, NULL, unit); | |
455 | atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status); | |
1da177e4 LT |
456 | } |
457 | ||
287ac01a | 458 | static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) |
1da177e4 | 459 | { |
287ac01a CS |
460 | list_move(&erp_action->list, &erp_action->adapter->erp_running_head); |
461 | zfcp_rec_dbf_event_action(145, erp_action); | |
1da177e4 LT |
462 | } |
463 | ||
287ac01a | 464 | static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) |
1da177e4 | 465 | { |
287ac01a | 466 | struct zfcp_adapter *adapter = act->adapter; |
1da177e4 | 467 | |
287ac01a CS |
468 | if (!act->fsf_req) |
469 | return; | |
1da177e4 | 470 | |
287ac01a CS |
471 | spin_lock(&adapter->req_list_lock); |
472 | if (zfcp_reqlist_find_safe(adapter, act->fsf_req) && | |
473 | act->fsf_req->erp_action == act) { | |
474 | if (act->status & (ZFCP_STATUS_ERP_DISMISSED | | |
475 | ZFCP_STATUS_ERP_TIMEDOUT)) { | |
476 | act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; | |
477 | zfcp_rec_dbf_event_action(142, act); | |
7ea633ff | 478 | act->fsf_req->erp_action = NULL; |
1da177e4 | 479 | } |
287ac01a CS |
480 | if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) |
481 | zfcp_rec_dbf_event_action(143, act); | |
482 | if (act->fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED | | |
483 | ZFCP_STATUS_FSFREQ_DISMISSED)) | |
484 | act->fsf_req = NULL; | |
485 | } else | |
486 | act->fsf_req = NULL; | |
487 | spin_unlock(&adapter->req_list_lock); | |
1da177e4 LT |
488 | } |
489 | ||
287ac01a CS |
490 | /** |
491 | * zfcp_erp_notify - Trigger ERP action. | |
492 | * @erp_action: ERP action to continue. | |
493 | * @set_mask: ERP action status flags to set. | |
1da177e4 | 494 | */ |
287ac01a | 495 | void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask) |
1da177e4 | 496 | { |
1da177e4 | 497 | struct zfcp_adapter *adapter = erp_action->adapter; |
287ac01a | 498 | unsigned long flags; |
1da177e4 | 499 | |
287ac01a | 500 | write_lock_irqsave(&adapter->erp_lock, flags); |
1da177e4 | 501 | if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) { |
1da177e4 LT |
502 | erp_action->status |= set_mask; |
503 | zfcp_erp_action_ready(erp_action); | |
1da177e4 | 504 | } |
1da177e4 | 505 | write_unlock_irqrestore(&adapter->erp_lock, flags); |
1da177e4 LT |
506 | } |
507 | ||
287ac01a CS |
508 | /** |
509 | * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request | |
510 | * @data: ERP action (from timer data) | |
1da177e4 | 511 | */ |
287ac01a | 512 | void zfcp_erp_timeout_handler(unsigned long data) |
1da177e4 | 513 | { |
287ac01a CS |
514 | struct zfcp_erp_action *act = (struct zfcp_erp_action *) data; |
515 | zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT); | |
1da177e4 LT |
516 | } |
517 | ||
287ac01a | 518 | static void zfcp_erp_memwait_handler(unsigned long data) |
1da177e4 | 519 | { |
287ac01a | 520 | zfcp_erp_notify((struct zfcp_erp_action *)data, 0); |
1da177e4 LT |
521 | } |
522 | ||
287ac01a | 523 | static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action) |
1da177e4 | 524 | { |
287ac01a CS |
525 | init_timer(&erp_action->timer); |
526 | erp_action->timer.function = zfcp_erp_memwait_handler; | |
527 | erp_action->timer.data = (unsigned long) erp_action; | |
528 | erp_action->timer.expires = jiffies + HZ; | |
529 | add_timer(&erp_action->timer); | |
1da177e4 LT |
530 | } |
531 | ||
287ac01a CS |
532 | static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, |
533 | int clear, u8 id, void *ref) | |
1da177e4 | 534 | { |
287ac01a | 535 | struct zfcp_port *port; |
1da177e4 | 536 | |
287ac01a | 537 | list_for_each_entry(port, &adapter->port_list_head, list) |
5ab944f9 | 538 | _zfcp_erp_port_reopen(port, clear, id, ref); |
1da177e4 LT |
539 | } |
540 | ||
287ac01a CS |
541 | static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, u8 id, |
542 | void *ref) | |
1da177e4 | 543 | { |
287ac01a | 544 | struct zfcp_unit *unit; |
1da177e4 | 545 | |
287ac01a CS |
546 | list_for_each_entry(unit, &port->unit_list_head, list) |
547 | _zfcp_erp_unit_reopen(unit, clear, id, ref); | |
1da177e4 LT |
548 | } |
549 | ||
287ac01a | 550 | static void zfcp_erp_strategy_followup_actions(struct zfcp_erp_action *act) |
1da177e4 | 551 | { |
287ac01a CS |
552 | struct zfcp_adapter *adapter = act->adapter; |
553 | struct zfcp_port *port = act->port; | |
554 | struct zfcp_unit *unit = act->unit; | |
555 | u32 status = act->status; | |
1da177e4 | 556 | |
287ac01a CS |
557 | /* initiate follow-up actions depending on success of finished action */ |
558 | switch (act->action) { | |
1da177e4 | 559 | |
287ac01a CS |
560 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
561 | if (status == ZFCP_ERP_SUCCEEDED) | |
562 | _zfcp_erp_port_reopen_all(adapter, 0, 70, NULL); | |
563 | else | |
564 | _zfcp_erp_adapter_reopen(adapter, 0, 71, NULL); | |
565 | break; | |
1da177e4 | 566 | |
287ac01a CS |
567 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
568 | if (status == ZFCP_ERP_SUCCEEDED) | |
569 | _zfcp_erp_port_reopen(port, 0, 72, NULL); | |
570 | else | |
571 | _zfcp_erp_adapter_reopen(adapter, 0, 73, NULL); | |
572 | break; | |
1da177e4 | 573 | |
287ac01a CS |
574 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
575 | if (status == ZFCP_ERP_SUCCEEDED) | |
576 | _zfcp_erp_unit_reopen_all(port, 0, 74, NULL); | |
577 | else | |
578 | _zfcp_erp_port_forced_reopen(port, 0, 75, NULL); | |
579 | break; | |
1da177e4 | 580 | |
287ac01a CS |
581 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
582 | if (status != ZFCP_ERP_SUCCEEDED) | |
583 | _zfcp_erp_port_reopen(unit->port, 0, 76, NULL); | |
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; | |
620 | _zfcp_erp_port_reopen(port, 0, 150, NULL); | |
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 | |
287ac01a CS |
643 | zfcp_rec_dbf_event_thread_lock(6, adapter); |
644 | down(&adapter->erp_ready_sem); | |
645 | zfcp_rec_dbf_event_thread_lock(7, adapter); | |
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 | ||
684 | zfcp_rec_dbf_event_thread_lock(8, adapter); | |
685 | down(&adapter->erp_ready_sem); | |
686 | zfcp_rec_dbf_event_thread_lock(9, adapter); | |
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 | |
287ac01a CS |
708 | static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *act, |
709 | int close) | |
710 | { | |
711 | int retval = ZFCP_ERP_SUCCEEDED; | |
712 | struct zfcp_adapter *adapter = act->adapter; | |
1da177e4 | 713 | |
287ac01a CS |
714 | if (close) |
715 | goto close_only; | |
716 | ||
717 | retval = zfcp_erp_adapter_strategy_open_qdio(act); | |
718 | if (retval != ZFCP_ERP_SUCCEEDED) | |
719 | goto failed_qdio; | |
1da177e4 | 720 | |
287ac01a CS |
721 | retval = zfcp_erp_adapter_strategy_open_fsf(act); |
722 | if (retval != ZFCP_ERP_SUCCEEDED) | |
723 | goto failed_openfcp; | |
724 | ||
725 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &act->adapter->status); | |
287ac01a CS |
726 | |
727 | return ZFCP_ERP_SUCCEEDED; | |
728 | ||
729 | close_only: | |
730 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, | |
731 | &act->adapter->status); | |
732 | ||
733 | failed_openfcp: | |
734 | /* close queues to ensure that buffers are not accessed by adapter */ | |
735 | zfcp_qdio_close(adapter); | |
736 | zfcp_fsf_req_dismiss_all(adapter); | |
737 | adapter->fsf_req_seq_no = 0; | |
738 | /* all ports and units are closed */ | |
739 | zfcp_erp_modify_adapter_status(adapter, 24, NULL, | |
740 | ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); | |
741 | failed_qdio: | |
742 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | | |
44cc76f2 | 743 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, |
287ac01a | 744 | &act->adapter->status); |
1da177e4 LT |
745 | return retval; |
746 | } | |
747 | ||
287ac01a | 748 | static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act) |
1da177e4 | 749 | { |
287ac01a | 750 | int retval; |
1da177e4 | 751 | |
287ac01a | 752 | zfcp_erp_adapter_strategy_generic(act, 1); /* close */ |
287ac01a CS |
753 | if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY) |
754 | return ZFCP_ERP_EXIT; | |
755 | ||
287ac01a | 756 | retval = zfcp_erp_adapter_strategy_generic(act, 0); /* open */ |
287ac01a CS |
757 | |
758 | if (retval == ZFCP_ERP_FAILED) | |
759 | ssleep(8); | |
1da177e4 LT |
760 | |
761 | return retval; | |
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 | { |
44cc76f2 | 780 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | |
287ac01a CS |
781 | ZFCP_STATUS_PORT_PHYS_CLOSING | |
782 | ZFCP_STATUS_PORT_INVALID_WWPN, | |
783 | &port->status); | |
784 | } | |
1da177e4 | 785 | |
287ac01a CS |
786 | static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action) |
787 | { | |
788 | struct zfcp_port *port = erp_action->port; | |
789 | int status = atomic_read(&port->status); | |
790 | ||
791 | switch (erp_action->step) { | |
792 | case ZFCP_ERP_STEP_UNINITIALIZED: | |
793 | zfcp_erp_port_strategy_clearstati(port); | |
794 | if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) && | |
795 | (status & ZFCP_STATUS_COMMON_OPEN)) | |
796 | return zfcp_erp_port_forced_strategy_close(erp_action); | |
797 | else | |
798 | return ZFCP_ERP_FAILED; | |
799 | ||
800 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: | |
801 | if (status & ZFCP_STATUS_PORT_PHYS_OPEN) | |
802 | return ZFCP_ERP_SUCCEEDED; | |
803 | } | |
804 | return ZFCP_ERP_FAILED; | |
1da177e4 LT |
805 | } |
806 | ||
287ac01a | 807 | static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action) |
1da177e4 | 808 | { |
287ac01a | 809 | int retval; |
1da177e4 | 810 | |
287ac01a CS |
811 | retval = zfcp_fsf_close_port(erp_action); |
812 | if (retval == -ENOMEM) | |
813 | return ZFCP_ERP_NOMEM; | |
814 | erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING; | |
815 | if (retval) | |
816 | return ZFCP_ERP_FAILED; | |
817 | return ZFCP_ERP_CONTINUES; | |
1da177e4 LT |
818 | } |
819 | ||
287ac01a | 820 | static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action) |
1da177e4 | 821 | { |
287ac01a | 822 | int retval; |
1da177e4 | 823 | |
287ac01a CS |
824 | retval = zfcp_fsf_open_port(erp_action); |
825 | if (retval == -ENOMEM) | |
826 | return ZFCP_ERP_NOMEM; | |
827 | erp_action->step = ZFCP_ERP_STEP_PORT_OPENING; | |
828 | if (retval) | |
829 | return ZFCP_ERP_FAILED; | |
830 | return ZFCP_ERP_CONTINUES; | |
831 | } | |
1da177e4 | 832 | |
287ac01a | 833 | static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) |
1da177e4 | 834 | { |
287ac01a CS |
835 | struct zfcp_adapter *adapter = act->adapter; |
836 | struct zfcp_port *port = act->port; | |
1da177e4 | 837 | |
287ac01a | 838 | if (port->wwpn != adapter->peer_wwpn) { |
287ac01a CS |
839 | zfcp_erp_port_failed(port, 25, NULL); |
840 | return ZFCP_ERP_FAILED; | |
841 | } | |
842 | port->d_id = adapter->peer_d_id; | |
287ac01a CS |
843 | return zfcp_erp_port_strategy_open_port(act); |
844 | } | |
845 | ||
5ab944f9 SS |
846 | void zfcp_erp_port_strategy_open_lookup(struct work_struct *work) |
847 | { | |
848 | int retval; | |
849 | struct zfcp_port *port = container_of(work, struct zfcp_port, | |
850 | gid_pn_work); | |
851 | ||
852 | retval = zfcp_fc_ns_gid_pn(&port->erp_action); | |
853 | if (retval == -ENOMEM) | |
854 | zfcp_erp_notify(&port->erp_action, ZFCP_ERP_NOMEM); | |
855 | port->erp_action.step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; | |
856 | if (retval) | |
857 | zfcp_erp_notify(&port->erp_action, ZFCP_ERP_FAILED); | |
858 | ||
859 | } | |
860 | ||
287ac01a CS |
861 | static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) |
862 | { | |
863 | struct zfcp_adapter *adapter = act->adapter; | |
864 | struct zfcp_port *port = act->port; | |
287ac01a CS |
865 | int p_status = atomic_read(&port->status); |
866 | ||
867 | switch (act->step) { | |
868 | case ZFCP_ERP_STEP_UNINITIALIZED: | |
869 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: | |
870 | case ZFCP_ERP_STEP_PORT_CLOSING: | |
871 | if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) | |
872 | return zfcp_erp_open_ptp_port(act); | |
b98478d7 | 873 | if (!port->d_id) { |
b7f15f3c | 874 | queue_work(zfcp_data.work_queue, &port->gid_pn_work); |
5ab944f9 | 875 | return ZFCP_ERP_CONTINUES; |
287ac01a | 876 | } |
287ac01a | 877 | case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: |
b98478d7 | 878 | if (!port->d_id) { |
287ac01a CS |
879 | if (p_status & (ZFCP_STATUS_PORT_INVALID_WWPN)) { |
880 | zfcp_erp_port_failed(port, 26, NULL); | |
881 | return ZFCP_ERP_EXIT; | |
882 | } | |
883 | return ZFCP_ERP_FAILED; | |
1da177e4 | 884 | } |
287ac01a CS |
885 | return zfcp_erp_port_strategy_open_port(act); |
886 | ||
887 | case ZFCP_ERP_STEP_PORT_OPENING: | |
888 | /* D_ID might have changed during open */ | |
5ab944f9 | 889 | if (p_status & ZFCP_STATUS_COMMON_OPEN) { |
b98478d7 | 890 | if (port->d_id) |
5ab944f9 SS |
891 | return ZFCP_ERP_SUCCEEDED; |
892 | else { | |
893 | act->step = ZFCP_ERP_STEP_PORT_CLOSING; | |
894 | return ZFCP_ERP_CONTINUES; | |
895 | } | |
287ac01a | 896 | /* fall through otherwise */ |
5ab944f9 | 897 | } |
287ac01a CS |
898 | } |
899 | return ZFCP_ERP_FAILED; | |
900 | } | |
901 | ||
287ac01a CS |
902 | static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) |
903 | { | |
904 | struct zfcp_port *port = erp_action->port; | |
905 | ||
5ab944f9 SS |
906 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) |
907 | goto close_init_done; | |
908 | ||
287ac01a CS |
909 | switch (erp_action->step) { |
910 | case ZFCP_ERP_STEP_UNINITIALIZED: | |
911 | zfcp_erp_port_strategy_clearstati(port); | |
912 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) | |
913 | return zfcp_erp_port_strategy_close(erp_action); | |
1da177e4 LT |
914 | break; |
915 | ||
287ac01a CS |
916 | case ZFCP_ERP_STEP_PORT_CLOSING: |
917 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_OPEN) | |
918 | return ZFCP_ERP_FAILED; | |
1da177e4 LT |
919 | break; |
920 | } | |
5ab944f9 SS |
921 | |
922 | close_init_done: | |
287ac01a CS |
923 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) |
924 | return ZFCP_ERP_EXIT; | |
1da177e4 | 925 | |
5ab944f9 | 926 | return zfcp_erp_port_strategy_open_common(erp_action); |
287ac01a CS |
927 | } |
928 | ||
929 | static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) | |
930 | { | |
44cc76f2 | 931 | atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | |
287ac01a CS |
932 | ZFCP_STATUS_UNIT_SHARED | |
933 | ZFCP_STATUS_UNIT_READONLY, | |
934 | &unit->status); | |
935 | } | |
936 | ||
937 | static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) | |
938 | { | |
939 | int retval = zfcp_fsf_close_unit(erp_action); | |
940 | if (retval == -ENOMEM) | |
941 | return ZFCP_ERP_NOMEM; | |
942 | erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING; | |
943 | if (retval) | |
944 | return ZFCP_ERP_FAILED; | |
945 | return ZFCP_ERP_CONTINUES; | |
946 | } | |
947 | ||
948 | static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action) | |
949 | { | |
950 | int retval = zfcp_fsf_open_unit(erp_action); | |
951 | if (retval == -ENOMEM) | |
952 | return ZFCP_ERP_NOMEM; | |
953 | erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING; | |
954 | if (retval) | |
955 | return ZFCP_ERP_FAILED; | |
956 | return ZFCP_ERP_CONTINUES; | |
1da177e4 LT |
957 | } |
958 | ||
287ac01a | 959 | static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) |
1da177e4 | 960 | { |
287ac01a CS |
961 | struct zfcp_unit *unit = erp_action->unit; |
962 | ||
963 | switch (erp_action->step) { | |
964 | case ZFCP_ERP_STEP_UNINITIALIZED: | |
965 | zfcp_erp_unit_strategy_clearstati(unit); | |
966 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) | |
967 | return zfcp_erp_unit_strategy_close(erp_action); | |
968 | /* already closed, fall through */ | |
969 | case ZFCP_ERP_STEP_UNIT_CLOSING: | |
970 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) | |
971 | return ZFCP_ERP_FAILED; | |
972 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) | |
973 | return ZFCP_ERP_EXIT; | |
974 | return zfcp_erp_unit_strategy_open(erp_action); | |
975 | ||
976 | case ZFCP_ERP_STEP_UNIT_OPENING: | |
977 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN) | |
978 | return ZFCP_ERP_SUCCEEDED; | |
979 | } | |
980 | return ZFCP_ERP_FAILED; | |
1da177e4 LT |
981 | } |
982 | ||
287ac01a | 983 | static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) |
1da177e4 | 984 | { |
1da177e4 LT |
985 | switch (result) { |
986 | case ZFCP_ERP_SUCCEEDED : | |
987 | atomic_set(&unit->erp_counter, 0); | |
988 | zfcp_erp_unit_unblock(unit); | |
989 | break; | |
990 | case ZFCP_ERP_FAILED : | |
991 | atomic_inc(&unit->erp_counter); | |
ff3b24fa CS |
992 | if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) { |
993 | dev_err(&unit->port->adapter->ccw_device->dev, | |
994 | "ERP failed for unit 0x%016Lx on " | |
995 | "port 0x%016Lx\n", | |
7ba58c9c SS |
996 | (unsigned long long)unit->fcp_lun, |
997 | (unsigned long long)unit->port->wwpn); | |
1f6f7129 | 998 | zfcp_erp_unit_failed(unit, 21, NULL); |
ff3b24fa | 999 | } |
1da177e4 | 1000 | break; |
1da177e4 LT |
1001 | } |
1002 | ||
287ac01a CS |
1003 | if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
1004 | zfcp_erp_unit_block(unit, 0); | |
1da177e4 LT |
1005 | result = ZFCP_ERP_EXIT; |
1006 | } | |
1da177e4 LT |
1007 | return result; |
1008 | } | |
1009 | ||
287ac01a | 1010 | static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) |
1da177e4 | 1011 | { |
1da177e4 LT |
1012 | switch (result) { |
1013 | case ZFCP_ERP_SUCCEEDED : | |
1014 | atomic_set(&port->erp_counter, 0); | |
1015 | zfcp_erp_port_unblock(port); | |
1016 | break; | |
287ac01a | 1017 | |
1da177e4 | 1018 | case ZFCP_ERP_FAILED : |
287ac01a | 1019 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) { |
cc8c2829 SS |
1020 | zfcp_erp_port_block(port, 0); |
1021 | result = ZFCP_ERP_EXIT; | |
1022 | } | |
1da177e4 | 1023 | atomic_inc(&port->erp_counter); |
ff3b24fa CS |
1024 | if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) { |
1025 | dev_err(&port->adapter->ccw_device->dev, | |
1026 | "ERP failed for remote port 0x%016Lx\n", | |
7ba58c9c | 1027 | (unsigned long long)port->wwpn); |
1f6f7129 | 1028 | zfcp_erp_port_failed(port, 22, NULL); |
ff3b24fa | 1029 | } |
1da177e4 | 1030 | break; |
1da177e4 LT |
1031 | } |
1032 | ||
287ac01a CS |
1033 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
1034 | zfcp_erp_port_block(port, 0); | |
1da177e4 LT |
1035 | result = ZFCP_ERP_EXIT; |
1036 | } | |
1da177e4 LT |
1037 | return result; |
1038 | } | |
1039 | ||
287ac01a CS |
1040 | static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, |
1041 | int result) | |
1da177e4 | 1042 | { |
1da177e4 LT |
1043 | switch (result) { |
1044 | case ZFCP_ERP_SUCCEEDED : | |
1045 | atomic_set(&adapter->erp_counter, 0); | |
1046 | zfcp_erp_adapter_unblock(adapter); | |
1047 | break; | |
287ac01a | 1048 | |
1da177e4 LT |
1049 | case ZFCP_ERP_FAILED : |
1050 | atomic_inc(&adapter->erp_counter); | |
ff3b24fa CS |
1051 | if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) { |
1052 | dev_err(&adapter->ccw_device->dev, | |
1053 | "ERP cannot recover an error " | |
1054 | "on the FCP device\n"); | |
1f6f7129 | 1055 | zfcp_erp_adapter_failed(adapter, 23, NULL); |
ff3b24fa | 1056 | } |
1da177e4 | 1057 | break; |
1da177e4 LT |
1058 | } |
1059 | ||
287ac01a CS |
1060 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { |
1061 | zfcp_erp_adapter_block(adapter, 0); | |
1da177e4 LT |
1062 | result = ZFCP_ERP_EXIT; |
1063 | } | |
1da177e4 LT |
1064 | return result; |
1065 | } | |
1066 | ||
287ac01a CS |
1067 | static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action, |
1068 | int result) | |
5f852be9 | 1069 | { |
287ac01a CS |
1070 | struct zfcp_adapter *adapter = erp_action->adapter; |
1071 | struct zfcp_port *port = erp_action->port; | |
1072 | struct zfcp_unit *unit = erp_action->unit; | |
1073 | ||
1074 | switch (erp_action->action) { | |
1075 | ||
1076 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | |
1077 | result = zfcp_erp_strategy_check_unit(unit, result); | |
1078 | break; | |
1079 | ||
1080 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | |
1081 | case ZFCP_ERP_ACTION_REOPEN_PORT: | |
1082 | result = zfcp_erp_strategy_check_port(port, result); | |
1083 | break; | |
1084 | ||
1085 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | |
1086 | result = zfcp_erp_strategy_check_adapter(adapter, result); | |
1087 | break; | |
1088 | } | |
1089 | return result; | |
5f852be9 CS |
1090 | } |
1091 | ||
287ac01a | 1092 | static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status) |
5f852be9 | 1093 | { |
287ac01a | 1094 | int status = atomic_read(target_status); |
5f852be9 | 1095 | |
287ac01a CS |
1096 | if ((status & ZFCP_STATUS_COMMON_RUNNING) && |
1097 | (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) | |
1098 | return 1; /* take it online */ | |
5f852be9 | 1099 | |
287ac01a CS |
1100 | if (!(status & ZFCP_STATUS_COMMON_RUNNING) && |
1101 | !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY)) | |
1102 | return 1; /* take it offline */ | |
1103 | ||
1104 | return 0; | |
5f852be9 CS |
1105 | } |
1106 | ||
287ac01a | 1107 | static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) |
1da177e4 | 1108 | { |
287ac01a CS |
1109 | int action = act->action; |
1110 | struct zfcp_adapter *adapter = act->adapter; | |
1111 | struct zfcp_port *port = act->port; | |
1112 | struct zfcp_unit *unit = act->unit; | |
1113 | u32 erp_status = act->status; | |
1da177e4 | 1114 | |
287ac01a | 1115 | switch (action) { |
1da177e4 | 1116 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
287ac01a CS |
1117 | if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) { |
1118 | _zfcp_erp_adapter_reopen(adapter, | |
1119 | ZFCP_STATUS_COMMON_ERP_FAILED, | |
1120 | 67, NULL); | |
1121 | return ZFCP_ERP_EXIT; | |
1122 | } | |
1da177e4 LT |
1123 | break; |
1124 | ||
1125 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | |
1da177e4 | 1126 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
287ac01a CS |
1127 | if (zfcp_erp_strat_change_det(&port->status, erp_status)) { |
1128 | _zfcp_erp_port_reopen(port, | |
1129 | ZFCP_STATUS_COMMON_ERP_FAILED, | |
1130 | 68, NULL); | |
1131 | return ZFCP_ERP_EXIT; | |
1132 | } | |
1da177e4 LT |
1133 | break; |
1134 | ||
1135 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | |
287ac01a CS |
1136 | if (zfcp_erp_strat_change_det(&unit->status, erp_status)) { |
1137 | _zfcp_erp_unit_reopen(unit, | |
1138 | ZFCP_STATUS_COMMON_ERP_FAILED, | |
1139 | 69, NULL); | |
1140 | return ZFCP_ERP_EXIT; | |
1141 | } | |
1da177e4 LT |
1142 | break; |
1143 | } | |
287ac01a | 1144 | return ret; |
1da177e4 LT |
1145 | } |
1146 | ||
287ac01a | 1147 | static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) |
1da177e4 | 1148 | { |
287ac01a | 1149 | struct zfcp_adapter *adapter = erp_action->adapter; |
1da177e4 | 1150 | |
287ac01a CS |
1151 | adapter->erp_total_count--; |
1152 | if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { | |
1153 | adapter->erp_low_mem_count--; | |
1154 | erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; | |
507e4969 | 1155 | } |
1da177e4 | 1156 | |
287ac01a CS |
1157 | list_del(&erp_action->list); |
1158 | zfcp_rec_dbf_event_action(144, erp_action); | |
1da177e4 | 1159 | |
287ac01a CS |
1160 | switch (erp_action->action) { |
1161 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | |
1162 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | |
1163 | &erp_action->unit->status); | |
1164 | break; | |
1da177e4 | 1165 | |
287ac01a CS |
1166 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
1167 | case ZFCP_ERP_ACTION_REOPEN_PORT: | |
1168 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | |
1169 | &erp_action->port->status); | |
1170 | break; | |
1da177e4 | 1171 | |
287ac01a CS |
1172 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
1173 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | |
1174 | &erp_action->adapter->status); | |
1175 | break; | |
1176 | } | |
1da177e4 LT |
1177 | } |
1178 | ||
287ac01a CS |
1179 | struct zfcp_erp_add_work { |
1180 | struct zfcp_unit *unit; | |
1181 | struct work_struct work; | |
1182 | }; | |
1da177e4 | 1183 | |
287ac01a CS |
1184 | static void zfcp_erp_scsi_scan(struct work_struct *work) |
1185 | { | |
1186 | struct zfcp_erp_add_work *p = | |
1187 | container_of(work, struct zfcp_erp_add_work, work); | |
1188 | struct zfcp_unit *unit = p->unit; | |
1189 | struct fc_rport *rport = unit->port->rport; | |
26871c97 SS |
1190 | |
1191 | if (rport && rport->port_state == FC_PORTSTATE_ONLINE) | |
1192 | scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, | |
0406289e | 1193 | scsilun_to_int((struct scsi_lun *)&unit->fcp_lun), 0); |
287ac01a CS |
1194 | atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); |
1195 | zfcp_unit_put(unit); | |
091694a5 | 1196 | wake_up(&unit->port->adapter->erp_done_wqh); |
287ac01a | 1197 | kfree(p); |
1da177e4 LT |
1198 | } |
1199 | ||
287ac01a | 1200 | static void zfcp_erp_schedule_work(struct zfcp_unit *unit) |
1da177e4 | 1201 | { |
287ac01a | 1202 | struct zfcp_erp_add_work *p; |
1da177e4 | 1203 | |
287ac01a CS |
1204 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
1205 | if (!p) { | |
1206 | dev_err(&unit->port->adapter->ccw_device->dev, | |
ff3b24fa | 1207 | "Registering unit 0x%016Lx on port 0x%016Lx failed\n", |
7ba58c9c SS |
1208 | (unsigned long long)unit->fcp_lun, |
1209 | (unsigned long long)unit->port->wwpn); | |
287ac01a | 1210 | return; |
1da177e4 | 1211 | } |
1da177e4 | 1212 | |
287ac01a CS |
1213 | zfcp_unit_get(unit); |
1214 | atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); | |
1215 | INIT_WORK(&p->work, zfcp_erp_scsi_scan); | |
1216 | p->unit = unit; | |
b7f15f3c | 1217 | queue_work(zfcp_data.work_queue, &p->work); |
1da177e4 LT |
1218 | } |
1219 | ||
287ac01a | 1220 | static void zfcp_erp_rport_register(struct zfcp_port *port) |
1da177e4 | 1221 | { |
287ac01a CS |
1222 | struct fc_rport_identifiers ids; |
1223 | ids.node_name = port->wwnn; | |
1224 | ids.port_name = port->wwpn; | |
1225 | ids.port_id = port->d_id; | |
1226 | ids.roles = FC_RPORT_ROLE_FCP_TARGET; | |
1227 | port->rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids); | |
1228 | if (!port->rport) { | |
1229 | dev_err(&port->adapter->ccw_device->dev, | |
ff3b24fa | 1230 | "Registering port 0x%016Lx failed\n", |
7ba58c9c | 1231 | (unsigned long long)port->wwpn); |
287ac01a | 1232 | return; |
1da177e4 | 1233 | } |
1da177e4 | 1234 | |
287ac01a CS |
1235 | scsi_target_unblock(&port->rport->dev); |
1236 | port->rport->maxframe_size = port->maxframe_size; | |
1237 | port->rport->supported_classes = port->supported_classes; | |
1da177e4 LT |
1238 | } |
1239 | ||
287ac01a | 1240 | static void zfcp_erp_rports_del(struct zfcp_adapter *adapter) |
1da177e4 | 1241 | { |
1da177e4 | 1242 | struct zfcp_port *port; |
5ab944f9 | 1243 | list_for_each_entry(port, &adapter->port_list_head, list) { |
e4e9ba5d SS |
1244 | if (!port->rport) |
1245 | continue; | |
5ab944f9 SS |
1246 | fc_remote_port_delete(port->rport); |
1247 | port->rport = NULL; | |
1248 | } | |
1da177e4 LT |
1249 | } |
1250 | ||
287ac01a | 1251 | static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) |
1da177e4 | 1252 | { |
287ac01a CS |
1253 | struct zfcp_adapter *adapter = act->adapter; |
1254 | struct zfcp_port *port = act->port; | |
1255 | struct zfcp_unit *unit = act->unit; | |
1da177e4 | 1256 | |
287ac01a CS |
1257 | switch (act->action) { |
1258 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | |
1259 | if ((result == ZFCP_ERP_SUCCEEDED) && | |
1260 | !unit->device && port->rport) { | |
1261 | atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED, | |
1262 | &unit->status); | |
1263 | if (!(atomic_read(&unit->status) & | |
1264 | ZFCP_STATUS_UNIT_SCSI_WORK_PENDING)) | |
1265 | zfcp_erp_schedule_work(unit); | |
1266 | } | |
1267 | zfcp_unit_put(unit); | |
1268 | break; | |
1da177e4 | 1269 | |
287ac01a CS |
1270 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
1271 | case ZFCP_ERP_ACTION_REOPEN_PORT: | |
1272 | if (atomic_read(&port->status) & ZFCP_STATUS_PORT_NO_WWPN) { | |
1273 | zfcp_port_put(port); | |
1274 | return; | |
1275 | } | |
1276 | if ((result == ZFCP_ERP_SUCCEEDED) && !port->rport) | |
1277 | zfcp_erp_rport_register(port); | |
1278 | if ((result != ZFCP_ERP_SUCCEEDED) && port->rport) { | |
1279 | fc_remote_port_delete(port->rport); | |
1280 | port->rport = NULL; | |
1281 | } | |
1282 | zfcp_port_put(port); | |
1283 | break; | |
1284 | ||
1285 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | |
bd43a42b CS |
1286 | if (result != ZFCP_ERP_SUCCEEDED) { |
1287 | unregister_service_level(&adapter->service_level); | |
287ac01a | 1288 | zfcp_erp_rports_del(adapter); |
bd43a42b CS |
1289 | } else { |
1290 | register_service_level(&adapter->service_level); | |
fca55b6f | 1291 | schedule_work(&adapter->scan_work); |
bd43a42b | 1292 | } |
287ac01a CS |
1293 | zfcp_adapter_put(adapter); |
1294 | break; | |
1295 | } | |
1da177e4 LT |
1296 | } |
1297 | ||
287ac01a | 1298 | static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) |
1da177e4 | 1299 | { |
287ac01a CS |
1300 | switch (erp_action->action) { |
1301 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | |
1302 | return zfcp_erp_adapter_strategy(erp_action); | |
1303 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | |
1304 | return zfcp_erp_port_forced_strategy(erp_action); | |
1305 | case ZFCP_ERP_ACTION_REOPEN_PORT: | |
1306 | return zfcp_erp_port_strategy(erp_action); | |
1307 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | |
1308 | return zfcp_erp_unit_strategy(erp_action); | |
1309 | } | |
1310 | return ZFCP_ERP_FAILED; | |
1da177e4 LT |
1311 | } |
1312 | ||
287ac01a | 1313 | static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) |
1da177e4 LT |
1314 | { |
1315 | int retval; | |
287ac01a CS |
1316 | struct zfcp_adapter *adapter = erp_action->adapter; |
1317 | unsigned long flags; | |
1da177e4 | 1318 | |
287ac01a CS |
1319 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
1320 | write_lock(&adapter->erp_lock); | |
1da177e4 | 1321 | |
287ac01a | 1322 | zfcp_erp_strategy_check_fsfreq(erp_action); |
1da177e4 | 1323 | |
287ac01a CS |
1324 | if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { |
1325 | zfcp_erp_action_dequeue(erp_action); | |
1326 | retval = ZFCP_ERP_DISMISSED; | |
1327 | goto unlock; | |
22753fa5 | 1328 | } |
1da177e4 | 1329 | |
2f8f3ed5 | 1330 | zfcp_erp_action_to_running(erp_action); |
1da177e4 | 1331 | |
287ac01a CS |
1332 | /* no lock to allow for blocking operations */ |
1333 | write_unlock(&adapter->erp_lock); | |
1334 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | |
1335 | retval = zfcp_erp_strategy_do_action(erp_action); | |
1336 | read_lock_irqsave(&zfcp_data.config_lock, flags); | |
1337 | write_lock(&adapter->erp_lock); | |
1da177e4 | 1338 | |
287ac01a CS |
1339 | if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) |
1340 | retval = ZFCP_ERP_CONTINUES; | |
cc8c2829 | 1341 | |
287ac01a CS |
1342 | switch (retval) { |
1343 | case ZFCP_ERP_NOMEM: | |
1344 | if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) { | |
1345 | ++adapter->erp_low_mem_count; | |
1346 | erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; | |
1da177e4 | 1347 | } |
287ac01a CS |
1348 | if (adapter->erp_total_count == adapter->erp_low_mem_count) |
1349 | _zfcp_erp_adapter_reopen(adapter, 0, 66, NULL); | |
1350 | else { | |
1351 | zfcp_erp_strategy_memwait(erp_action); | |
1352 | retval = ZFCP_ERP_CONTINUES; | |
1da177e4 | 1353 | } |
287ac01a | 1354 | goto unlock; |
1da177e4 | 1355 | |
287ac01a CS |
1356 | case ZFCP_ERP_CONTINUES: |
1357 | if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { | |
1358 | --adapter->erp_low_mem_count; | |
1359 | erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; | |
1da177e4 | 1360 | } |
287ac01a | 1361 | goto unlock; |
1da177e4 LT |
1362 | } |
1363 | ||
287ac01a CS |
1364 | retval = zfcp_erp_strategy_check_target(erp_action, retval); |
1365 | zfcp_erp_action_dequeue(erp_action); | |
1366 | retval = zfcp_erp_strategy_statechange(erp_action, retval); | |
1367 | if (retval == ZFCP_ERP_EXIT) | |
1368 | goto unlock; | |
1369 | zfcp_erp_strategy_followup_actions(erp_action); | |
1da177e4 | 1370 | |
287ac01a CS |
1371 | unlock: |
1372 | write_unlock(&adapter->erp_lock); | |
1373 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | |
1da177e4 | 1374 | |
287ac01a CS |
1375 | if (retval != ZFCP_ERP_CONTINUES) |
1376 | zfcp_erp_action_cleanup(erp_action, retval); | |
1da177e4 | 1377 | |
1da177e4 LT |
1378 | return retval; |
1379 | } | |
1380 | ||
287ac01a | 1381 | static int zfcp_erp_thread(void *data) |
1da177e4 | 1382 | { |
287ac01a CS |
1383 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; |
1384 | struct list_head *next; | |
1385 | struct zfcp_erp_action *act; | |
1386 | unsigned long flags; | |
06499fac | 1387 | int ignore; |
1da177e4 | 1388 | |
b9d3aed7 | 1389 | daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev)); |
287ac01a CS |
1390 | /* Block all signals */ |
1391 | siginitsetinv(¤t->blocked, 0); | |
1392 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | |
1393 | wake_up(&adapter->erp_thread_wqh); | |
1da177e4 | 1394 | |
287ac01a CS |
1395 | while (!(atomic_read(&adapter->status) & |
1396 | ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL)) { | |
1397 | write_lock_irqsave(&adapter->erp_lock, flags); | |
1398 | next = adapter->erp_ready_head.next; | |
1399 | write_unlock_irqrestore(&adapter->erp_lock, flags); | |
1da177e4 | 1400 | |
287ac01a CS |
1401 | if (next != &adapter->erp_ready_head) { |
1402 | act = list_entry(next, struct zfcp_erp_action, list); | |
1da177e4 | 1403 | |
287ac01a CS |
1404 | /* there is more to come after dismission, no notify */ |
1405 | if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED) | |
1406 | zfcp_erp_wakeup(adapter); | |
1da177e4 | 1407 | } |
1da177e4 | 1408 | |
9fb3cd86 | 1409 | zfcp_rec_dbf_event_thread_lock(4, adapter); |
06499fac | 1410 | ignore = down_interruptible(&adapter->erp_ready_sem); |
9fb3cd86 | 1411 | zfcp_rec_dbf_event_thread_lock(5, adapter); |
1da177e4 LT |
1412 | } |
1413 | ||
287ac01a CS |
1414 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); |
1415 | wake_up(&adapter->erp_thread_wqh); | |
1da177e4 | 1416 | |
287ac01a CS |
1417 | return 0; |
1418 | } | |
1da177e4 | 1419 | |
287ac01a CS |
1420 | /** |
1421 | * zfcp_erp_thread_setup - Start ERP thread for adapter | |
1422 | * @adapter: Adapter to start the ERP thread for | |
1423 | * | |
1424 | * Returns 0 on success or error code from kernel_thread() | |
1425 | */ | |
1426 | int zfcp_erp_thread_setup(struct zfcp_adapter *adapter) | |
1427 | { | |
1428 | int retval; | |
1da177e4 | 1429 | |
287ac01a CS |
1430 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); |
1431 | retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); | |
1432 | if (retval < 0) { | |
1433 | dev_err(&adapter->ccw_device->dev, | |
ff3b24fa | 1434 | "Creating an ERP thread for the FCP device failed.\n"); |
287ac01a | 1435 | return retval; |
1da177e4 | 1436 | } |
287ac01a CS |
1437 | wait_event(adapter->erp_thread_wqh, |
1438 | atomic_read(&adapter->status) & | |
1439 | ZFCP_STATUS_ADAPTER_ERP_THREAD_UP); | |
1440 | return 0; | |
1441 | } | |
1da177e4 | 1442 | |
287ac01a CS |
1443 | /** |
1444 | * zfcp_erp_thread_kill - Stop ERP thread. | |
1445 | * @adapter: Adapter where the ERP thread should be stopped. | |
1446 | * | |
1447 | * The caller of this routine ensures that the specified adapter has | |
1448 | * been shut down and that this operation has been completed. Thus, | |
1449 | * there are no pending erp_actions which would need to be handled | |
1450 | * here. | |
1451 | */ | |
1452 | void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) | |
1453 | { | |
1454 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); | |
1455 | up(&adapter->erp_ready_sem); | |
41bfcf90 | 1456 | zfcp_rec_dbf_event_thread_lock(3, adapter); |
1da177e4 | 1457 | |
287ac01a CS |
1458 | wait_event(adapter->erp_thread_wqh, |
1459 | !(atomic_read(&adapter->status) & | |
1460 | ZFCP_STATUS_ADAPTER_ERP_THREAD_UP)); | |
1da177e4 | 1461 | |
287ac01a CS |
1462 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, |
1463 | &adapter->status); | |
1da177e4 LT |
1464 | } |
1465 | ||
287ac01a CS |
1466 | /** |
1467 | * zfcp_erp_adapter_failed - Set adapter status to failed. | |
1468 | * @adapter: Failed adapter. | |
1469 | * @id: Event id for debug trace. | |
1470 | * @ref: Reference for debug trace. | |
1471 | */ | |
1472 | void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, u8 id, void *ref) | |
1da177e4 | 1473 | { |
287ac01a CS |
1474 | zfcp_erp_modify_adapter_status(adapter, id, ref, |
1475 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | |
287ac01a | 1476 | } |
1da177e4 | 1477 | |
287ac01a CS |
1478 | /** |
1479 | * zfcp_erp_port_failed - Set port status to failed. | |
1480 | * @port: Failed port. | |
1481 | * @id: Event id for debug trace. | |
1482 | * @ref: Reference for debug trace. | |
1483 | */ | |
1484 | void zfcp_erp_port_failed(struct zfcp_port *port, u8 id, void *ref) | |
1485 | { | |
1486 | zfcp_erp_modify_port_status(port, id, ref, | |
1487 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | |
1da177e4 LT |
1488 | } |
1489 | ||
1490 | /** | |
287ac01a CS |
1491 | * zfcp_erp_unit_failed - Set unit status to failed. |
1492 | * @unit: Failed unit. | |
1493 | * @id: Event id for debug trace. | |
1494 | * @ref: Reference for debug trace. | |
1da177e4 | 1495 | */ |
287ac01a | 1496 | void zfcp_erp_unit_failed(struct zfcp_unit *unit, u8 id, void *ref) |
1da177e4 | 1497 | { |
287ac01a CS |
1498 | zfcp_erp_modify_unit_status(unit, id, ref, |
1499 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | |
1da177e4 LT |
1500 | } |
1501 | ||
287ac01a CS |
1502 | /** |
1503 | * zfcp_erp_wait - wait for completion of error recovery on an adapter | |
1504 | * @adapter: adapter for which to wait for completion of its error recovery | |
1505 | */ | |
1506 | void zfcp_erp_wait(struct zfcp_adapter *adapter) | |
1507 | { | |
1508 | wait_event(adapter->erp_done_wqh, | |
1509 | !(atomic_read(&adapter->status) & | |
1510 | ZFCP_STATUS_ADAPTER_ERP_PENDING)); | |
1511 | } | |
1da177e4 | 1512 | |
287ac01a CS |
1513 | /** |
1514 | * zfcp_erp_modify_adapter_status - change adapter status bits | |
1515 | * @adapter: adapter to change the status | |
1516 | * @id: id for the debug trace | |
1517 | * @ref: reference for the debug trace | |
1518 | * @mask: status bits to change | |
1519 | * @set_or_clear: ZFCP_SET or ZFCP_CLEAR | |
1520 | * | |
1521 | * Changes in common status bits are propagated to attached ports and units. | |
1522 | */ | |
1523 | void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, u8 id, | |
1524 | void *ref, u32 mask, int set_or_clear) | |
1da177e4 | 1525 | { |
1da177e4 | 1526 | struct zfcp_port *port; |
287ac01a | 1527 | u32 common_mask = mask & ZFCP_COMMON_FLAGS; |
1da177e4 | 1528 | |
287ac01a CS |
1529 | if (set_or_clear == ZFCP_SET) { |
1530 | if (status_change_set(mask, &adapter->status)) | |
1531 | zfcp_rec_dbf_event_adapter(id, ref, adapter); | |
1532 | atomic_set_mask(mask, &adapter->status); | |
1533 | } else { | |
1534 | if (status_change_clear(mask, &adapter->status)) | |
1535 | zfcp_rec_dbf_event_adapter(id, ref, adapter); | |
1536 | atomic_clear_mask(mask, &adapter->status); | |
1537 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) | |
1538 | atomic_set(&adapter->erp_counter, 0); | |
1539 | } | |
1540 | ||
1541 | if (common_mask) | |
1da177e4 | 1542 | list_for_each_entry(port, &adapter->port_list_head, list) |
287ac01a CS |
1543 | zfcp_erp_modify_port_status(port, id, ref, common_mask, |
1544 | set_or_clear); | |
1da177e4 LT |
1545 | } |
1546 | ||
287ac01a CS |
1547 | /** |
1548 | * zfcp_erp_modify_port_status - change port status bits | |
1549 | * @port: port to change the status bits | |
1550 | * @id: id for the debug trace | |
1551 | * @ref: reference for the debug trace | |
1552 | * @mask: status bits to change | |
1553 | * @set_or_clear: ZFCP_SET or ZFCP_CLEAR | |
1554 | * | |
1555 | * Changes in common status bits are propagated to attached units. | |
1556 | */ | |
1557 | void zfcp_erp_modify_port_status(struct zfcp_port *port, u8 id, void *ref, | |
1558 | u32 mask, int set_or_clear) | |
1da177e4 | 1559 | { |
1da177e4 | 1560 | struct zfcp_unit *unit; |
287ac01a | 1561 | u32 common_mask = mask & ZFCP_COMMON_FLAGS; |
1da177e4 | 1562 | |
287ac01a CS |
1563 | if (set_or_clear == ZFCP_SET) { |
1564 | if (status_change_set(mask, &port->status)) | |
1565 | zfcp_rec_dbf_event_port(id, ref, port); | |
1566 | atomic_set_mask(mask, &port->status); | |
1567 | } else { | |
1568 | if (status_change_clear(mask, &port->status)) | |
1569 | zfcp_rec_dbf_event_port(id, ref, port); | |
1570 | atomic_clear_mask(mask, &port->status); | |
1571 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) | |
1572 | atomic_set(&port->erp_counter, 0); | |
1573 | } | |
1da177e4 | 1574 | |
287ac01a CS |
1575 | if (common_mask) |
1576 | list_for_each_entry(unit, &port->unit_list_head, list) | |
1577 | zfcp_erp_modify_unit_status(unit, id, ref, common_mask, | |
1578 | set_or_clear); | |
1da177e4 LT |
1579 | } |
1580 | ||
287ac01a CS |
1581 | /** |
1582 | * zfcp_erp_modify_unit_status - change unit status bits | |
1583 | * @unit: unit to change the status bits | |
1584 | * @id: id for the debug trace | |
1585 | * @ref: reference for the debug trace | |
1586 | * @mask: status bits to change | |
1587 | * @set_or_clear: ZFCP_SET or ZFCP_CLEAR | |
1588 | */ | |
1589 | void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u8 id, void *ref, | |
1590 | u32 mask, int set_or_clear) | |
1da177e4 | 1591 | { |
287ac01a CS |
1592 | if (set_or_clear == ZFCP_SET) { |
1593 | if (status_change_set(mask, &unit->status)) | |
1594 | zfcp_rec_dbf_event_unit(id, ref, unit); | |
1595 | atomic_set_mask(mask, &unit->status); | |
1596 | } else { | |
1597 | if (status_change_clear(mask, &unit->status)) | |
1598 | zfcp_rec_dbf_event_unit(id, ref, unit); | |
1599 | atomic_clear_mask(mask, &unit->status); | |
1600 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { | |
1601 | atomic_set(&unit->erp_counter, 0); | |
1602 | } | |
1603 | } | |
1da177e4 LT |
1604 | } |
1605 | ||
287ac01a CS |
1606 | /** |
1607 | * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP | |
1608 | * @port: The "boxed" port. | |
1609 | * @id: The debug trace id. | |
1610 | * @id: Reference for the debug trace. | |
1611 | */ | |
1f6f7129 | 1612 | void zfcp_erp_port_boxed(struct zfcp_port *port, u8 id, void *ref) |
d736a27b | 1613 | { |
d736a27b AH |
1614 | unsigned long flags; |
1615 | ||
d736a27b | 1616 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
698ec016 MP |
1617 | zfcp_erp_modify_port_status(port, id, ref, |
1618 | ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); | |
d736a27b | 1619 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
9467a9b3 | 1620 | zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
d736a27b AH |
1621 | } |
1622 | ||
287ac01a CS |
1623 | /** |
1624 | * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP | |
1625 | * @port: The "boxed" unit. | |
1626 | * @id: The debug trace id. | |
1627 | * @id: Reference for the debug trace. | |
1628 | */ | |
1f6f7129 | 1629 | void zfcp_erp_unit_boxed(struct zfcp_unit *unit, u8 id, void *ref) |
d736a27b | 1630 | { |
698ec016 MP |
1631 | zfcp_erp_modify_unit_status(unit, id, ref, |
1632 | ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET); | |
9467a9b3 | 1633 | zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
d736a27b AH |
1634 | } |
1635 | ||
287ac01a CS |
1636 | /** |
1637 | * zfcp_erp_port_access_denied - Adapter denied access to port. | |
1638 | * @port: port where access has been denied | |
1639 | * @id: id for debug trace | |
1640 | * @ref: reference for debug trace | |
1641 | * | |
1642 | * Since the adapter has denied access, stop using the port and the | |
1643 | * attached units. | |
1644 | */ | |
1f6f7129 | 1645 | void zfcp_erp_port_access_denied(struct zfcp_port *port, u8 id, void *ref) |
1da177e4 | 1646 | { |
1da177e4 LT |
1647 | unsigned long flags; |
1648 | ||
1da177e4 | 1649 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
698ec016 MP |
1650 | zfcp_erp_modify_port_status(port, id, ref, |
1651 | ZFCP_STATUS_COMMON_ERP_FAILED | | |
1652 | ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); | |
1da177e4 LT |
1653 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
1654 | } | |
1655 | ||
287ac01a CS |
1656 | /** |
1657 | * zfcp_erp_unit_access_denied - Adapter denied access to unit. | |
1658 | * @unit: unit where access has been denied | |
1659 | * @id: id for debug trace | |
1660 | * @ref: reference for debug trace | |
1661 | * | |
1662 | * Since the adapter has denied access, stop using the unit. | |
1663 | */ | |
1f6f7129 | 1664 | void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, u8 id, void *ref) |
1da177e4 | 1665 | { |
698ec016 MP |
1666 | zfcp_erp_modify_unit_status(unit, id, ref, |
1667 | ZFCP_STATUS_COMMON_ERP_FAILED | | |
1668 | ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); | |
1da177e4 LT |
1669 | } |
1670 | ||
287ac01a CS |
1671 | static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, u8 id, |
1672 | void *ref) | |
1da177e4 | 1673 | { |
287ac01a CS |
1674 | int status = atomic_read(&unit->status); |
1675 | if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | | |
1676 | ZFCP_STATUS_COMMON_ACCESS_BOXED))) | |
aef4a983 MS |
1677 | return; |
1678 | ||
287ac01a | 1679 | zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
1da177e4 LT |
1680 | } |
1681 | ||
287ac01a CS |
1682 | static void zfcp_erp_port_access_changed(struct zfcp_port *port, u8 id, |
1683 | void *ref) | |
1da177e4 | 1684 | { |
1da177e4 | 1685 | struct zfcp_unit *unit; |
287ac01a | 1686 | int status = atomic_read(&port->status); |
1da177e4 | 1687 | |
287ac01a CS |
1688 | if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED | |
1689 | ZFCP_STATUS_COMMON_ACCESS_BOXED))) { | |
5ab944f9 SS |
1690 | list_for_each_entry(unit, &port->unit_list_head, list) |
1691 | zfcp_erp_unit_access_changed(unit, id, ref); | |
1da177e4 LT |
1692 | return; |
1693 | } | |
1694 | ||
553448f6 | 1695 | zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref); |
1da177e4 LT |
1696 | } |
1697 | ||
287ac01a CS |
1698 | /** |
1699 | * zfcp_erp_adapter_access_changed - Process change in adapter ACT | |
1700 | * @adapter: Adapter where the Access Control Table (ACT) changed | |
1701 | * @id: Id for debug trace | |
1702 | * @ref: Reference for debug trace | |
1703 | */ | |
1704 | void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, u8 id, | |
1705 | void *ref) | |
1da177e4 | 1706 | { |
287ac01a CS |
1707 | struct zfcp_port *port; |
1708 | unsigned long flags; | |
1709 | ||
1710 | if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) | |
1da177e4 LT |
1711 | return; |
1712 | ||
287ac01a | 1713 | read_lock_irqsave(&zfcp_data.config_lock, flags); |
287ac01a | 1714 | list_for_each_entry(port, &adapter->port_list_head, list) |
5ab944f9 | 1715 | zfcp_erp_port_access_changed(port, id, ref); |
287ac01a | 1716 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); |
1da177e4 | 1717 | } |