diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/s390/scsi/zfcp_erp.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/s390/scsi/zfcp_erp.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 3585 |
1 files changed, 3585 insertions, 0 deletions
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c new file mode 100644 index 000000000000..cfc0d8c588df --- /dev/null +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -0,0 +1,3585 @@ | |||
1 | /* | ||
2 | * | ||
3 | * linux/drivers/s390/scsi/zfcp_erp.c | ||
4 | * | ||
5 | * FCP adapter driver for IBM eServer zSeries | ||
6 | * | ||
7 | * (C) Copyright IBM Corp. 2002, 2004 | ||
8 | * | ||
9 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> | ||
10 | * Raimund Schroeder <raimund.schroeder@de.ibm.com> | ||
11 | * Aron Zeh | ||
12 | * Wolfgang Taphorn | ||
13 | * Stefan Bader <stefan.bader@de.ibm.com> | ||
14 | * Heiko Carstens <heiko.carstens@de.ibm.com> | ||
15 | * Andreas Herrmann <aherrman@de.ibm.com> | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or modify | ||
18 | * it under the terms of the GNU General Public License as published by | ||
19 | * the Free Software Foundation; either version 2, or (at your option) | ||
20 | * any later version. | ||
21 | * | ||
22 | * This program is distributed in the hope that it will be useful, | ||
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
25 | * GNU General Public License for more details. | ||
26 | * | ||
27 | * You should have received a copy of the GNU General Public License | ||
28 | * along with this program; if not, write to the Free Software | ||
29 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
30 | */ | ||
31 | |||
32 | #define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP | ||
33 | |||
34 | #define ZFCP_ERP_REVISION "$Revision: 1.86 $" | ||
35 | |||
36 | #include "zfcp_ext.h" | ||
37 | |||
38 | static int zfcp_erp_adisc(struct zfcp_adapter *, fc_id_t); | ||
39 | static void zfcp_erp_adisc_handler(unsigned long); | ||
40 | |||
41 | static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *, int); | ||
42 | static int zfcp_erp_port_forced_reopen_internal(struct zfcp_port *, int); | ||
43 | static int zfcp_erp_port_reopen_internal(struct zfcp_port *, int); | ||
44 | static int zfcp_erp_unit_reopen_internal(struct zfcp_unit *, int); | ||
45 | |||
46 | static int zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *, int); | ||
47 | static int zfcp_erp_unit_reopen_all_internal(struct zfcp_port *, int); | ||
48 | |||
49 | static void zfcp_erp_adapter_block(struct zfcp_adapter *, int); | ||
50 | static void zfcp_erp_adapter_unblock(struct zfcp_adapter *); | ||
51 | static void zfcp_erp_port_block(struct zfcp_port *, int); | ||
52 | static void zfcp_erp_port_unblock(struct zfcp_port *); | ||
53 | static void zfcp_erp_unit_block(struct zfcp_unit *, int); | ||
54 | static void zfcp_erp_unit_unblock(struct zfcp_unit *); | ||
55 | |||
56 | static int zfcp_erp_thread(void *); | ||
57 | |||
58 | static int zfcp_erp_strategy(struct zfcp_erp_action *); | ||
59 | |||
60 | static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *); | ||
61 | static int zfcp_erp_strategy_memwait(struct zfcp_erp_action *); | ||
62 | static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *, int); | ||
63 | static int zfcp_erp_strategy_check_unit(struct zfcp_unit *, int); | ||
64 | static int zfcp_erp_strategy_check_port(struct zfcp_port *, int); | ||
65 | static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *, int); | ||
66 | static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *, | ||
67 | struct zfcp_port *, | ||
68 | struct zfcp_unit *, int); | ||
69 | static inline int zfcp_erp_strategy_statechange_detected(atomic_t *, u32); | ||
70 | static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *, | ||
71 | struct zfcp_port *, | ||
72 | struct zfcp_unit *, int); | ||
73 | static int zfcp_erp_strategy_check_queues(struct zfcp_adapter *); | ||
74 | static int zfcp_erp_strategy_check_action(struct zfcp_erp_action *, int); | ||
75 | |||
76 | static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *); | ||
77 | static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *, int); | ||
78 | static int zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *); | ||
79 | static int zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *); | ||
80 | static int zfcp_erp_adapter_strategy_close_fsf(struct zfcp_erp_action *); | ||
81 | static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *); | ||
82 | static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *); | ||
83 | static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *); | ||
84 | static int zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *); | ||
85 | static int zfcp_erp_adapter_strategy_open_fsf_statusread( | ||
86 | struct zfcp_erp_action *); | ||
87 | |||
88 | static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *); | ||
89 | static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *); | ||
90 | |||
91 | static int zfcp_erp_port_strategy(struct zfcp_erp_action *); | ||
92 | static int zfcp_erp_port_strategy_clearstati(struct zfcp_port *); | ||
93 | static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *); | ||
94 | static int zfcp_erp_port_strategy_open(struct zfcp_erp_action *); | ||
95 | static int zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *); | ||
96 | static int zfcp_erp_port_strategy_open_nameserver_wakeup( | ||
97 | struct zfcp_erp_action *); | ||
98 | static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *); | ||
99 | static int zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *); | ||
100 | static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *); | ||
101 | |||
102 | static int zfcp_erp_unit_strategy(struct zfcp_erp_action *); | ||
103 | static int zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *); | ||
104 | static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *); | ||
105 | static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *); | ||
106 | |||
107 | static int zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *); | ||
108 | static int zfcp_erp_action_dismiss_port(struct zfcp_port *); | ||
109 | static int zfcp_erp_action_dismiss_unit(struct zfcp_unit *); | ||
110 | static int zfcp_erp_action_dismiss(struct zfcp_erp_action *); | ||
111 | |||
112 | static int zfcp_erp_action_enqueue(int, struct zfcp_adapter *, | ||
113 | struct zfcp_port *, struct zfcp_unit *); | ||
114 | static int zfcp_erp_action_dequeue(struct zfcp_erp_action *); | ||
115 | static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *, | ||
116 | struct zfcp_port *, struct zfcp_unit *, | ||
117 | int); | ||
118 | |||
119 | static void zfcp_erp_action_ready(struct zfcp_erp_action *); | ||
120 | static int zfcp_erp_action_exists(struct zfcp_erp_action *); | ||
121 | |||
122 | static inline void zfcp_erp_action_to_ready(struct zfcp_erp_action *); | ||
123 | static inline void zfcp_erp_action_to_running(struct zfcp_erp_action *); | ||
124 | |||
125 | static void zfcp_erp_memwait_handler(unsigned long); | ||
126 | static void zfcp_erp_timeout_handler(unsigned long); | ||
127 | static inline void zfcp_erp_timeout_init(struct zfcp_erp_action *); | ||
128 | |||
129 | /** | ||
130 | * zfcp_fsf_request_timeout_handler - called if a request timed out | ||
131 | * @data: pointer to adapter for handler function | ||
132 | * | ||
133 | * This function needs to be called if requests (ELS, Generic Service, | ||
134 | * or SCSI commands) exceed a certain time limit. The assumption is | ||
135 | * that after the time limit the adapter get stuck. So we trigger a reopen of | ||
136 | * the adapter. This should not be used for error recovery, SCSI abort | ||
137 | * commands and SCSI requests from SCSI mid-layer. | ||
138 | */ | ||
139 | void | ||
140 | zfcp_fsf_request_timeout_handler(unsigned long data) | ||
141 | { | ||
142 | struct zfcp_adapter *adapter; | ||
143 | |||
144 | adapter = (struct zfcp_adapter *) data; | ||
145 | |||
146 | zfcp_erp_adapter_reopen(adapter, 0); | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * function: zfcp_fsf_scsi_er_timeout_handler | ||
151 | * | ||
152 | * purpose: This function needs to be called whenever a SCSI error recovery | ||
153 | * action (abort/reset) does not return. | ||
154 | * Re-opening the adapter means that the command can be returned | ||
155 | * by zfcp (it is guarranteed that it does not return via the | ||
156 | * adapter anymore). The buffer can then be used again. | ||
157 | * | ||
158 | * returns: sod all | ||
159 | */ | ||
160 | void | ||
161 | zfcp_fsf_scsi_er_timeout_handler(unsigned long data) | ||
162 | { | ||
163 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; | ||
164 | |||
165 | ZFCP_LOG_NORMAL("warning: SCSI error recovery timed out. " | ||
166 | "Restarting all operations on the adapter %s\n", | ||
167 | zfcp_get_busid_by_adapter(adapter)); | ||
168 | debug_text_event(adapter->erp_dbf, 1, "eh_lmem_tout"); | ||
169 | zfcp_erp_adapter_reopen(adapter, 0); | ||
170 | |||
171 | return; | ||
172 | } | ||
173 | |||
174 | /* | ||
175 | * function: | ||
176 | * | ||
177 | * purpose: called if an adapter failed, | ||
178 | * initiates adapter recovery which is done | ||
179 | * asynchronously | ||
180 | * | ||
181 | * returns: 0 - initiated action succesfully | ||
182 | * <0 - failed to initiate action | ||
183 | */ | ||
184 | int | ||
185 | zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask) | ||
186 | { | ||
187 | int retval; | ||
188 | |||
189 | debug_text_event(adapter->erp_dbf, 5, "a_ro"); | ||
190 | ZFCP_LOG_DEBUG("reopen adapter %s\n", | ||
191 | zfcp_get_busid_by_adapter(adapter)); | ||
192 | |||
193 | zfcp_erp_adapter_block(adapter, clear_mask); | ||
194 | |||
195 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) { | ||
196 | ZFCP_LOG_DEBUG("skipped reopen of failed adapter %s\n", | ||
197 | zfcp_get_busid_by_adapter(adapter)); | ||
198 | debug_text_event(adapter->erp_dbf, 5, "a_ro_f"); | ||
199 | /* ensure propagation of failed status to new devices */ | ||
200 | zfcp_erp_adapter_failed(adapter); | ||
201 | retval = -EIO; | ||
202 | goto out; | ||
203 | } | ||
204 | retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, | ||
205 | adapter, NULL, NULL); | ||
206 | |||
207 | out: | ||
208 | return retval; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * function: | ||
213 | * | ||
214 | * purpose: Wrappper for zfcp_erp_adapter_reopen_internal | ||
215 | * used to ensure the correct locking | ||
216 | * | ||
217 | * returns: 0 - initiated action succesfully | ||
218 | * <0 - failed to initiate action | ||
219 | */ | ||
220 | int | ||
221 | zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear_mask) | ||
222 | { | ||
223 | int retval; | ||
224 | unsigned long flags; | ||
225 | |||
226 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
227 | write_lock(&adapter->erp_lock); | ||
228 | retval = zfcp_erp_adapter_reopen_internal(adapter, clear_mask); | ||
229 | write_unlock(&adapter->erp_lock); | ||
230 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
231 | |||
232 | return retval; | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * function: | ||
237 | * | ||
238 | * purpose: | ||
239 | * | ||
240 | * returns: | ||
241 | */ | ||
242 | int | ||
243 | zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear_mask) | ||
244 | { | ||
245 | int retval; | ||
246 | |||
247 | retval = zfcp_erp_adapter_reopen(adapter, | ||
248 | ZFCP_STATUS_COMMON_RUNNING | | ||
249 | ZFCP_STATUS_COMMON_ERP_FAILED | | ||
250 | clear_mask); | ||
251 | |||
252 | return retval; | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * function: | ||
257 | * | ||
258 | * purpose: | ||
259 | * | ||
260 | * returns: | ||
261 | */ | ||
262 | int | ||
263 | zfcp_erp_port_shutdown(struct zfcp_port *port, int clear_mask) | ||
264 | { | ||
265 | int retval; | ||
266 | |||
267 | retval = zfcp_erp_port_reopen(port, | ||
268 | ZFCP_STATUS_COMMON_RUNNING | | ||
269 | ZFCP_STATUS_COMMON_ERP_FAILED | | ||
270 | clear_mask); | ||
271 | |||
272 | return retval; | ||
273 | } | ||
274 | |||
275 | /* | ||
276 | * function: | ||
277 | * | ||
278 | * purpose: | ||
279 | * | ||
280 | * returns: | ||
281 | */ | ||
282 | int | ||
283 | zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask) | ||
284 | { | ||
285 | int retval; | ||
286 | |||
287 | retval = zfcp_erp_unit_reopen(unit, | ||
288 | ZFCP_STATUS_COMMON_RUNNING | | ||
289 | ZFCP_STATUS_COMMON_ERP_FAILED | | ||
290 | clear_mask); | ||
291 | |||
292 | return retval; | ||
293 | } | ||
294 | |||
295 | |||
296 | /** | ||
297 | * zfcp_erp_adisc - send ADISC ELS command | ||
298 | * @adapter: adapter structure | ||
299 | * @d_id: d_id of port where ADISC is sent to | ||
300 | */ | ||
301 | int | ||
302 | zfcp_erp_adisc(struct zfcp_adapter *adapter, fc_id_t d_id) | ||
303 | { | ||
304 | struct zfcp_send_els *send_els; | ||
305 | struct zfcp_ls_adisc *adisc; | ||
306 | void *address = NULL; | ||
307 | int retval = 0; | ||
308 | struct timer_list *timer; | ||
309 | |||
310 | send_els = kmalloc(sizeof(struct zfcp_send_els), GFP_ATOMIC); | ||
311 | if (send_els == NULL) | ||
312 | goto nomem; | ||
313 | memset(send_els, 0, sizeof(*send_els)); | ||
314 | |||
315 | send_els->req = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC); | ||
316 | if (send_els->req == NULL) | ||
317 | goto nomem; | ||
318 | memset(send_els->req, 0, sizeof(*send_els->req)); | ||
319 | |||
320 | send_els->resp = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC); | ||
321 | if (send_els->resp == NULL) | ||
322 | goto nomem; | ||
323 | memset(send_els->resp, 0, sizeof(*send_els->resp)); | ||
324 | |||
325 | address = (void *) get_zeroed_page(GFP_ATOMIC); | ||
326 | if (address == NULL) | ||
327 | goto nomem; | ||
328 | |||
329 | zfcp_address_to_sg(address, send_els->req); | ||
330 | address += PAGE_SIZE >> 1; | ||
331 | zfcp_address_to_sg(address, send_els->resp); | ||
332 | send_els->req_count = send_els->resp_count = 1; | ||
333 | |||
334 | send_els->adapter = adapter; | ||
335 | send_els->d_id = d_id; | ||
336 | send_els->handler = zfcp_erp_adisc_handler; | ||
337 | send_els->handler_data = (unsigned long) send_els; | ||
338 | |||
339 | adisc = zfcp_sg_to_address(send_els->req); | ||
340 | send_els->ls_code = adisc->code = ZFCP_LS_ADISC; | ||
341 | |||
342 | send_els->req->length = sizeof(struct zfcp_ls_adisc); | ||
343 | send_els->resp->length = sizeof(struct zfcp_ls_adisc_acc); | ||
344 | |||
345 | /* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports | ||
346 | without FC-AL-2 capability, so we don't set it */ | ||
347 | adisc->wwpn = adapter->wwpn; | ||
348 | adisc->wwnn = adapter->wwnn; | ||
349 | adisc->nport_id = adapter->s_id; | ||
350 | ZFCP_LOG_INFO("ADISC request from s_id 0x%08x to d_id 0x%08x " | ||
351 | "(wwpn=0x%016Lx, wwnn=0x%016Lx, " | ||
352 | "hard_nport_id=0x%08x, nport_id=0x%08x)\n", | ||
353 | adapter->s_id, d_id, (wwn_t) adisc->wwpn, | ||
354 | (wwn_t) adisc->wwnn, adisc->hard_nport_id, | ||
355 | adisc->nport_id); | ||
356 | |||
357 | timer = kmalloc(sizeof(struct timer_list), GFP_ATOMIC); | ||
358 | if (!timer) | ||
359 | goto nomem; | ||
360 | |||
361 | init_timer(timer); | ||
362 | timer->function = zfcp_fsf_request_timeout_handler; | ||
363 | timer->data = (unsigned long) adapter; | ||
364 | timer->expires = ZFCP_FSF_REQUEST_TIMEOUT; | ||
365 | send_els->timer = timer; | ||
366 | |||
367 | retval = zfcp_fsf_send_els(send_els); | ||
368 | if (retval != 0) { | ||
369 | ZFCP_LOG_NORMAL("error: initiation of Send ELS failed for port " | ||
370 | "0x%08x on adapter %s\n", d_id, | ||
371 | zfcp_get_busid_by_adapter(adapter)); | ||
372 | del_timer(send_els->timer); | ||
373 | goto freemem; | ||
374 | } | ||
375 | |||
376 | goto out; | ||
377 | |||
378 | nomem: | ||
379 | retval = -ENOMEM; | ||
380 | freemem: | ||
381 | if (address != NULL) | ||
382 | __free_pages(send_els->req->page, 0); | ||
383 | if (send_els != NULL) { | ||
384 | kfree(send_els->timer); | ||
385 | kfree(send_els->req); | ||
386 | kfree(send_els->resp); | ||
387 | kfree(send_els); | ||
388 | } | ||
389 | out: | ||
390 | return retval; | ||
391 | } | ||
392 | |||
393 | |||
394 | /** | ||
395 | * zfcp_erp_adisc_handler - handler for ADISC ELS command | ||
396 | * @data: pointer to struct zfcp_send_els | ||
397 | * | ||
398 | * If ADISC failed (LS_RJT or timed out) forced reopen of the port is triggered. | ||
399 | */ | ||
400 | void | ||
401 | zfcp_erp_adisc_handler(unsigned long data) | ||
402 | { | ||
403 | struct zfcp_send_els *send_els; | ||
404 | struct zfcp_port *port; | ||
405 | struct zfcp_adapter *adapter; | ||
406 | fc_id_t d_id; | ||
407 | struct zfcp_ls_adisc_acc *adisc; | ||
408 | |||
409 | send_els = (struct zfcp_send_els *) data; | ||
410 | |||
411 | del_timer(send_els->timer); | ||
412 | |||
413 | adapter = send_els->adapter; | ||
414 | d_id = send_els->d_id; | ||
415 | |||
416 | read_lock(&zfcp_data.config_lock); | ||
417 | port = zfcp_get_port_by_did(send_els->adapter, send_els->d_id); | ||
418 | read_unlock(&zfcp_data.config_lock); | ||
419 | |||
420 | BUG_ON(port == NULL); | ||
421 | |||
422 | /* request rejected or timed out */ | ||
423 | if (send_els->status != 0) { | ||
424 | ZFCP_LOG_NORMAL("ELS request rejected/timed out, " | ||
425 | "force physical port reopen " | ||
426 | "(adapter %s, port d_id=0x%08x)\n", | ||
427 | zfcp_get_busid_by_adapter(adapter), d_id); | ||
428 | debug_text_event(adapter->erp_dbf, 3, "forcreop"); | ||
429 | if (zfcp_erp_port_forced_reopen(port, 0)) | ||
430 | ZFCP_LOG_NORMAL("failed reopen of port " | ||
431 | "(adapter %s, wwpn=0x%016Lx)\n", | ||
432 | zfcp_get_busid_by_port(port), | ||
433 | port->wwpn); | ||
434 | goto out; | ||
435 | } | ||
436 | |||
437 | adisc = zfcp_sg_to_address(send_els->resp); | ||
438 | |||
439 | ZFCP_LOG_INFO("ADISC response from d_id 0x%08x to s_id " | ||
440 | "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, " | ||
441 | "hard_nport_id=0x%08x, nport_id=0x%08x)\n", | ||
442 | d_id, adapter->s_id, (wwn_t) adisc->wwpn, | ||
443 | (wwn_t) adisc->wwnn, adisc->hard_nport_id, | ||
444 | adisc->nport_id); | ||
445 | |||
446 | /* set wwnn for port */ | ||
447 | if (port->wwnn == 0) | ||
448 | port->wwnn = adisc->wwnn; | ||
449 | |||
450 | if (port->wwpn != adisc->wwpn) { | ||
451 | ZFCP_LOG_NORMAL("d_id assignment changed, reopening " | ||
452 | "port (adapter %s, wwpn=0x%016Lx, " | ||
453 | "adisc_resp_wwpn=0x%016Lx)\n", | ||
454 | zfcp_get_busid_by_port(port), | ||
455 | port->wwpn, (wwn_t) adisc->wwpn); | ||
456 | if (zfcp_erp_port_reopen(port, 0)) | ||
457 | ZFCP_LOG_NORMAL("failed reopen of port " | ||
458 | "(adapter %s, wwpn=0x%016Lx)\n", | ||
459 | zfcp_get_busid_by_port(port), | ||
460 | port->wwpn); | ||
461 | } | ||
462 | |||
463 | out: | ||
464 | zfcp_port_put(port); | ||
465 | __free_pages(send_els->req->page, 0); | ||
466 | kfree(send_els->timer); | ||
467 | kfree(send_els->req); | ||
468 | kfree(send_els->resp); | ||
469 | kfree(send_els); | ||
470 | } | ||
471 | |||
472 | |||
473 | /** | ||
474 | * zfcp_test_link - lightweight link test procedure | ||
475 | * @port: port to be tested | ||
476 | * | ||
477 | * Test status of a link to a remote port using the ELS command ADISC. | ||
478 | */ | ||
479 | int | ||
480 | zfcp_test_link(struct zfcp_port *port) | ||
481 | { | ||
482 | int retval; | ||
483 | |||
484 | zfcp_port_get(port); | ||
485 | retval = zfcp_erp_adisc(port->adapter, port->d_id); | ||
486 | if (retval != 0) { | ||
487 | zfcp_port_put(port); | ||
488 | ZFCP_LOG_NORMAL("reopen needed for port 0x%016Lx " | ||
489 | "on adapter %s\n ", port->wwpn, | ||
490 | zfcp_get_busid_by_port(port)); | ||
491 | retval = zfcp_erp_port_forced_reopen(port, 0); | ||
492 | if (retval != 0) { | ||
493 | ZFCP_LOG_NORMAL("reopen of remote port 0x%016Lx " | ||
494 | "on adapter %s failed\n", port->wwpn, | ||
495 | zfcp_get_busid_by_port(port)); | ||
496 | retval = -EPERM; | ||
497 | } | ||
498 | } | ||
499 | |||
500 | return retval; | ||
501 | } | ||
502 | |||
503 | |||
504 | /* | ||
505 | * function: | ||
506 | * | ||
507 | * purpose: called if a port failed to be opened normally | ||
508 | * initiates Forced Reopen recovery which is done | ||
509 | * asynchronously | ||
510 | * | ||
511 | * returns: 0 - initiated action succesfully | ||
512 | * <0 - failed to initiate action | ||
513 | */ | ||
514 | static int | ||
515 | zfcp_erp_port_forced_reopen_internal(struct zfcp_port *port, int clear_mask) | ||
516 | { | ||
517 | int retval; | ||
518 | struct zfcp_adapter *adapter = port->adapter; | ||
519 | |||
520 | debug_text_event(adapter->erp_dbf, 5, "pf_ro"); | ||
521 | debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); | ||
522 | |||
523 | ZFCP_LOG_DEBUG("forced reopen of port 0x%016Lx on adapter %s\n", | ||
524 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
525 | |||
526 | zfcp_erp_port_block(port, clear_mask); | ||
527 | |||
528 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { | ||
529 | ZFCP_LOG_DEBUG("skipped forced reopen of failed port 0x%016Lx " | ||
530 | "on adapter %s\n", port->wwpn, | ||
531 | zfcp_get_busid_by_port(port)); | ||
532 | debug_text_event(adapter->erp_dbf, 5, "pf_ro_f"); | ||
533 | debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); | ||
534 | retval = -EIO; | ||
535 | goto out; | ||
536 | } | ||
537 | |||
538 | retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, | ||
539 | port->adapter, port, NULL); | ||
540 | |||
541 | out: | ||
542 | return retval; | ||
543 | } | ||
544 | |||
545 | /* | ||
546 | * function: | ||
547 | * | ||
548 | * purpose: Wrappper for zfcp_erp_port_forced_reopen_internal | ||
549 | * used to ensure the correct locking | ||
550 | * | ||
551 | * returns: 0 - initiated action succesfully | ||
552 | * <0 - failed to initiate action | ||
553 | */ | ||
554 | int | ||
555 | zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear_mask) | ||
556 | { | ||
557 | int retval; | ||
558 | unsigned long flags; | ||
559 | struct zfcp_adapter *adapter; | ||
560 | |||
561 | adapter = port->adapter; | ||
562 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
563 | write_lock(&adapter->erp_lock); | ||
564 | retval = zfcp_erp_port_forced_reopen_internal(port, clear_mask); | ||
565 | write_unlock(&adapter->erp_lock); | ||
566 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
567 | |||
568 | return retval; | ||
569 | } | ||
570 | |||
571 | /* | ||
572 | * function: | ||
573 | * | ||
574 | * purpose: called if a port is to be opened | ||
575 | * initiates Reopen recovery which is done | ||
576 | * asynchronously | ||
577 | * | ||
578 | * returns: 0 - initiated action succesfully | ||
579 | * <0 - failed to initiate action | ||
580 | */ | ||
581 | static int | ||
582 | zfcp_erp_port_reopen_internal(struct zfcp_port *port, int clear_mask) | ||
583 | { | ||
584 | int retval; | ||
585 | struct zfcp_adapter *adapter = port->adapter; | ||
586 | |||
587 | debug_text_event(adapter->erp_dbf, 5, "p_ro"); | ||
588 | debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); | ||
589 | |||
590 | ZFCP_LOG_DEBUG("reopen of port 0x%016Lx on adapter %s\n", | ||
591 | port->wwpn, zfcp_get_busid_by_port(port)); | ||
592 | |||
593 | zfcp_erp_port_block(port, clear_mask); | ||
594 | |||
595 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { | ||
596 | ZFCP_LOG_DEBUG("skipped reopen of failed port 0x%016Lx " | ||
597 | "on adapter %s\n", port->wwpn, | ||
598 | zfcp_get_busid_by_port(port)); | ||
599 | debug_text_event(adapter->erp_dbf, 5, "p_ro_f"); | ||
600 | debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); | ||
601 | /* ensure propagation of failed status to new devices */ | ||
602 | zfcp_erp_port_failed(port); | ||
603 | retval = -EIO; | ||
604 | goto out; | ||
605 | } | ||
606 | |||
607 | retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, | ||
608 | port->adapter, port, NULL); | ||
609 | |||
610 | out: | ||
611 | return retval; | ||
612 | } | ||
613 | |||
614 | /** | ||
615 | * zfcp_erp_port_reopen - initiate reopen of a remote port | ||
616 | * @port: port to be reopened | ||
617 | * @clear_mask: specifies flags in port status to be cleared | ||
618 | * Return: 0 on success, < 0 on error | ||
619 | * | ||
620 | * This is a wrappper function for zfcp_erp_port_reopen_internal. It ensures | ||
621 | * correct locking. An error recovery task is initiated to do the reopen. | ||
622 | * To wait for the completion of the reopen zfcp_erp_wait should be used. | ||
623 | */ | ||
624 | int | ||
625 | zfcp_erp_port_reopen(struct zfcp_port *port, int clear_mask) | ||
626 | { | ||
627 | int retval; | ||
628 | unsigned long flags; | ||
629 | struct zfcp_adapter *adapter = port->adapter; | ||
630 | |||
631 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
632 | write_lock(&adapter->erp_lock); | ||
633 | retval = zfcp_erp_port_reopen_internal(port, clear_mask); | ||
634 | write_unlock(&adapter->erp_lock); | ||
635 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
636 | |||
637 | return retval; | ||
638 | } | ||
639 | |||
640 | /* | ||
641 | * function: | ||
642 | * | ||
643 | * purpose: called if a unit is to be opened | ||
644 | * initiates Reopen recovery which is done | ||
645 | * asynchronously | ||
646 | * | ||
647 | * returns: 0 - initiated action succesfully | ||
648 | * <0 - failed to initiate action | ||
649 | */ | ||
650 | static int | ||
651 | zfcp_erp_unit_reopen_internal(struct zfcp_unit *unit, int clear_mask) | ||
652 | { | ||
653 | int retval; | ||
654 | struct zfcp_adapter *adapter = unit->port->adapter; | ||
655 | |||
656 | debug_text_event(adapter->erp_dbf, 5, "u_ro"); | ||
657 | debug_event(adapter->erp_dbf, 5, &unit->fcp_lun, sizeof (fcp_lun_t)); | ||
658 | ZFCP_LOG_DEBUG("reopen of unit 0x%016Lx on port 0x%016Lx " | ||
659 | "on adapter %s\n", unit->fcp_lun, | ||
660 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | ||
661 | |||
662 | zfcp_erp_unit_block(unit, clear_mask); | ||
663 | |||
664 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) { | ||
665 | ZFCP_LOG_DEBUG("skipped reopen of failed unit 0x%016Lx " | ||
666 | "on port 0x%016Lx on adapter %s\n", | ||
667 | unit->fcp_lun, unit->port->wwpn, | ||
668 | zfcp_get_busid_by_unit(unit)); | ||
669 | debug_text_event(adapter->erp_dbf, 5, "u_ro_f"); | ||
670 | debug_event(adapter->erp_dbf, 5, &unit->fcp_lun, | ||
671 | sizeof (fcp_lun_t)); | ||
672 | retval = -EIO; | ||
673 | goto out; | ||
674 | } | ||
675 | |||
676 | retval = zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, | ||
677 | unit->port->adapter, unit->port, unit); | ||
678 | out: | ||
679 | return retval; | ||
680 | } | ||
681 | |||
682 | /** | ||
683 | * zfcp_erp_unit_reopen - initiate reopen of a unit | ||
684 | * @unit: unit to be reopened | ||
685 | * @clear_mask: specifies flags in unit status to be cleared | ||
686 | * Return: 0 on success, < 0 on error | ||
687 | * | ||
688 | * This is a wrappper for zfcp_erp_unit_reopen_internal. It ensures correct | ||
689 | * locking. An error recovery task is initiated to do the reopen. | ||
690 | * To wait for the completion of the reopen zfcp_erp_wait should be used. | ||
691 | */ | ||
692 | int | ||
693 | zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear_mask) | ||
694 | { | ||
695 | int retval; | ||
696 | unsigned long flags; | ||
697 | struct zfcp_adapter *adapter; | ||
698 | struct zfcp_port *port; | ||
699 | |||
700 | port = unit->port; | ||
701 | adapter = port->adapter; | ||
702 | |||
703 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
704 | write_lock(&adapter->erp_lock); | ||
705 | retval = zfcp_erp_unit_reopen_internal(unit, clear_mask); | ||
706 | write_unlock(&adapter->erp_lock); | ||
707 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
708 | |||
709 | return retval; | ||
710 | } | ||
711 | |||
712 | /* | ||
713 | * function: | ||
714 | * | ||
715 | * purpose: disable I/O, | ||
716 | * return any open requests and clean them up, | ||
717 | * aim: no pending and incoming I/O | ||
718 | * | ||
719 | * returns: | ||
720 | */ | ||
721 | static void | ||
722 | zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask) | ||
723 | { | ||
724 | debug_text_event(adapter->erp_dbf, 6, "a_bl"); | ||
725 | zfcp_erp_modify_adapter_status(adapter, | ||
726 | ZFCP_STATUS_COMMON_UNBLOCKED | | ||
727 | clear_mask, ZFCP_CLEAR); | ||
728 | } | ||
729 | |||
730 | /* | ||
731 | * function: | ||
732 | * | ||
733 | * purpose: enable I/O | ||
734 | * | ||
735 | * returns: | ||
736 | */ | ||
737 | static void | ||
738 | zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) | ||
739 | { | ||
740 | debug_text_event(adapter->erp_dbf, 6, "a_ubl"); | ||
741 | atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); | ||
742 | } | ||
743 | |||
744 | /* | ||
745 | * function: | ||
746 | * | ||
747 | * purpose: disable I/O, | ||
748 | * return any open requests and clean them up, | ||
749 | * aim: no pending and incoming I/O | ||
750 | * | ||
751 | * returns: | ||
752 | */ | ||
753 | static void | ||
754 | zfcp_erp_port_block(struct zfcp_port *port, int clear_mask) | ||
755 | { | ||
756 | struct zfcp_adapter *adapter = port->adapter; | ||
757 | |||
758 | debug_text_event(adapter->erp_dbf, 6, "p_bl"); | ||
759 | debug_event(adapter->erp_dbf, 6, &port->wwpn, sizeof (wwn_t)); | ||
760 | zfcp_erp_modify_port_status(port, | ||
761 | ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, | ||
762 | ZFCP_CLEAR); | ||
763 | } | ||
764 | |||
765 | /* | ||
766 | * function: | ||
767 | * | ||
768 | * purpose: enable I/O | ||
769 | * | ||
770 | * returns: | ||
771 | */ | ||
772 | static void | ||
773 | zfcp_erp_port_unblock(struct zfcp_port *port) | ||
774 | { | ||
775 | struct zfcp_adapter *adapter = port->adapter; | ||
776 | |||
777 | debug_text_event(adapter->erp_dbf, 6, "p_ubl"); | ||
778 | debug_event(adapter->erp_dbf, 6, &port->wwpn, sizeof (wwn_t)); | ||
779 | atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); | ||
780 | } | ||
781 | |||
782 | /* | ||
783 | * function: | ||
784 | * | ||
785 | * purpose: disable I/O, | ||
786 | * return any open requests and clean them up, | ||
787 | * aim: no pending and incoming I/O | ||
788 | * | ||
789 | * returns: | ||
790 | */ | ||
791 | static void | ||
792 | zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) | ||
793 | { | ||
794 | struct zfcp_adapter *adapter = unit->port->adapter; | ||
795 | |||
796 | debug_text_event(adapter->erp_dbf, 6, "u_bl"); | ||
797 | debug_event(adapter->erp_dbf, 6, &unit->fcp_lun, sizeof (fcp_lun_t)); | ||
798 | zfcp_erp_modify_unit_status(unit, | ||
799 | ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask, | ||
800 | ZFCP_CLEAR); | ||
801 | } | ||
802 | |||
803 | /* | ||
804 | * function: | ||
805 | * | ||
806 | * purpose: enable I/O | ||
807 | * | ||
808 | * returns: | ||
809 | */ | ||
810 | static void | ||
811 | zfcp_erp_unit_unblock(struct zfcp_unit *unit) | ||
812 | { | ||
813 | struct zfcp_adapter *adapter = unit->port->adapter; | ||
814 | |||
815 | debug_text_event(adapter->erp_dbf, 6, "u_ubl"); | ||
816 | debug_event(adapter->erp_dbf, 6, &unit->fcp_lun, sizeof (fcp_lun_t)); | ||
817 | atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status); | ||
818 | } | ||
819 | |||
820 | /* | ||
821 | * function: | ||
822 | * | ||
823 | * purpose: | ||
824 | * | ||
825 | * returns: | ||
826 | */ | ||
827 | static void | ||
828 | zfcp_erp_action_ready(struct zfcp_erp_action *erp_action) | ||
829 | { | ||
830 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
831 | |||
832 | debug_text_event(adapter->erp_dbf, 4, "a_ar"); | ||
833 | debug_event(adapter->erp_dbf, 4, &erp_action->action, sizeof (int)); | ||
834 | |||
835 | zfcp_erp_action_to_ready(erp_action); | ||
836 | up(&adapter->erp_ready_sem); | ||
837 | } | ||
838 | |||
839 | /* | ||
840 | * function: | ||
841 | * | ||
842 | * purpose: | ||
843 | * | ||
844 | * returns: <0 erp_action not found in any list | ||
845 | * ZFCP_ERP_ACTION_READY erp_action is in ready list | ||
846 | * ZFCP_ERP_ACTION_RUNNING erp_action is in running list | ||
847 | * | ||
848 | * locks: erp_lock must be held | ||
849 | */ | ||
850 | static int | ||
851 | zfcp_erp_action_exists(struct zfcp_erp_action *erp_action) | ||
852 | { | ||
853 | int retval = -EINVAL; | ||
854 | struct list_head *entry; | ||
855 | struct zfcp_erp_action *entry_erp_action; | ||
856 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
857 | |||
858 | /* search in running list */ | ||
859 | list_for_each(entry, &adapter->erp_running_head) { | ||
860 | entry_erp_action = | ||
861 | list_entry(entry, struct zfcp_erp_action, list); | ||
862 | if (entry_erp_action == erp_action) { | ||
863 | retval = ZFCP_ERP_ACTION_RUNNING; | ||
864 | goto out; | ||
865 | } | ||
866 | } | ||
867 | /* search in ready list */ | ||
868 | list_for_each(entry, &adapter->erp_ready_head) { | ||
869 | entry_erp_action = | ||
870 | list_entry(entry, struct zfcp_erp_action, list); | ||
871 | if (entry_erp_action == erp_action) { | ||
872 | retval = ZFCP_ERP_ACTION_READY; | ||
873 | goto out; | ||
874 | } | ||
875 | } | ||
876 | |||
877 | out: | ||
878 | return retval; | ||
879 | } | ||
880 | |||
881 | /* | ||
882 | * purpose: checks current status of action (timed out, dismissed, ...) | ||
883 | * and does appropriate preparations (dismiss fsf request, ...) | ||
884 | * | ||
885 | * locks: called under erp_lock (disabled interrupts) | ||
886 | * | ||
887 | * returns: 0 | ||
888 | */ | ||
889 | static int | ||
890 | zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) | ||
891 | { | ||
892 | int retval = 0; | ||
893 | struct zfcp_fsf_req *fsf_req; | ||
894 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
895 | |||
896 | if (erp_action->fsf_req) { | ||
897 | /* take lock to ensure that request is not being deleted meanwhile */ | ||
898 | write_lock(&adapter->fsf_req_list_lock); | ||
899 | /* check whether fsf req does still exist */ | ||
900 | list_for_each_entry(fsf_req, &adapter->fsf_req_list_head, list) | ||
901 | if (fsf_req == erp_action->fsf_req) | ||
902 | break; | ||
903 | if (fsf_req == erp_action->fsf_req) { | ||
904 | /* fsf_req still exists */ | ||
905 | debug_text_event(adapter->erp_dbf, 3, "a_ca_req"); | ||
906 | debug_event(adapter->erp_dbf, 3, &fsf_req, | ||
907 | sizeof (unsigned long)); | ||
908 | /* dismiss fsf_req of timed out or dismissed erp_action */ | ||
909 | if (erp_action->status & (ZFCP_STATUS_ERP_DISMISSED | | ||
910 | ZFCP_STATUS_ERP_TIMEDOUT)) { | ||
911 | debug_text_event(adapter->erp_dbf, 3, | ||
912 | "a_ca_disreq"); | ||
913 | fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; | ||
914 | } | ||
915 | if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { | ||
916 | ZFCP_LOG_NORMAL("error: erp step timed out " | ||
917 | "(action=%d, fsf_req=%p)\n ", | ||
918 | erp_action->action, | ||
919 | erp_action->fsf_req); | ||
920 | } | ||
921 | /* | ||
922 | * If fsf_req is neither dismissed nor completed | ||
923 | * then keep it running asynchronously and don't mess | ||
924 | * with the association of erp_action and fsf_req. | ||
925 | */ | ||
926 | if (fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED | | ||
927 | ZFCP_STATUS_FSFREQ_DISMISSED)) { | ||
928 | /* forget about association between fsf_req | ||
929 | and erp_action */ | ||
930 | fsf_req->erp_action = NULL; | ||
931 | erp_action->fsf_req = NULL; | ||
932 | } | ||
933 | } else { | ||
934 | debug_text_event(adapter->erp_dbf, 3, "a_ca_gonereq"); | ||
935 | /* | ||
936 | * even if this fsf_req has gone, forget about | ||
937 | * association between erp_action and fsf_req | ||
938 | */ | ||
939 | erp_action->fsf_req = NULL; | ||
940 | } | ||
941 | write_unlock(&adapter->fsf_req_list_lock); | ||
942 | } else | ||
943 | debug_text_event(adapter->erp_dbf, 3, "a_ca_noreq"); | ||
944 | |||
945 | return retval; | ||
946 | } | ||
947 | |||
948 | /* | ||
949 | * purpose: generic handler for asynchronous events related to erp_action events | ||
950 | * (normal completion, time-out, dismissing, retry after | ||
951 | * low memory condition) | ||
952 | * | ||
953 | * note: deletion of timer is not required (e.g. in case of a time-out), | ||
954 | * but a second try does no harm, | ||
955 | * we leave it in here to allow for greater simplification | ||
956 | * | ||
957 | * returns: 0 - there was an action to handle | ||
958 | * !0 - otherwise | ||
959 | */ | ||
960 | static int | ||
961 | zfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action, | ||
962 | unsigned long set_mask) | ||
963 | { | ||
964 | int retval; | ||
965 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
966 | |||
967 | if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) { | ||
968 | debug_text_event(adapter->erp_dbf, 2, "a_asyh_ex"); | ||
969 | debug_event(adapter->erp_dbf, 2, &erp_action->action, | ||
970 | sizeof (int)); | ||
971 | if (!(set_mask & ZFCP_STATUS_ERP_TIMEDOUT)) | ||
972 | del_timer(&erp_action->timer); | ||
973 | erp_action->status |= set_mask; | ||
974 | zfcp_erp_action_ready(erp_action); | ||
975 | retval = 0; | ||
976 | } else { | ||
977 | /* action is ready or gone - nothing to do */ | ||
978 | debug_text_event(adapter->erp_dbf, 3, "a_asyh_gone"); | ||
979 | debug_event(adapter->erp_dbf, 3, &erp_action->action, | ||
980 | sizeof (int)); | ||
981 | retval = 1; | ||
982 | } | ||
983 | |||
984 | return retval; | ||
985 | } | ||
986 | |||
987 | /* | ||
988 | * purpose: generic handler for asynchronous events related to erp_action | ||
989 | * events (normal completion, time-out, dismissing, retry after | ||
990 | * low memory condition) | ||
991 | * | ||
992 | * note: deletion of timer is not required (e.g. in case of a time-out), | ||
993 | * but a second try does no harm, | ||
994 | * we leave it in here to allow for greater simplification | ||
995 | * | ||
996 | * returns: 0 - there was an action to handle | ||
997 | * !0 - otherwise | ||
998 | */ | ||
999 | int | ||
1000 | zfcp_erp_async_handler(struct zfcp_erp_action *erp_action, | ||
1001 | unsigned long set_mask) | ||
1002 | { | ||
1003 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1004 | unsigned long flags; | ||
1005 | int retval; | ||
1006 | |||
1007 | write_lock_irqsave(&adapter->erp_lock, flags); | ||
1008 | retval = zfcp_erp_async_handler_nolock(erp_action, set_mask); | ||
1009 | write_unlock_irqrestore(&adapter->erp_lock, flags); | ||
1010 | |||
1011 | return retval; | ||
1012 | } | ||
1013 | |||
1014 | /* | ||
1015 | * purpose: is called for erp_action which was slept waiting for | ||
1016 | * memory becoming avaliable, | ||
1017 | * will trigger that this action will be continued | ||
1018 | */ | ||
1019 | static void | ||
1020 | zfcp_erp_memwait_handler(unsigned long data) | ||
1021 | { | ||
1022 | struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data; | ||
1023 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1024 | |||
1025 | debug_text_event(adapter->erp_dbf, 2, "a_mwh"); | ||
1026 | debug_event(adapter->erp_dbf, 2, &erp_action->action, sizeof (int)); | ||
1027 | |||
1028 | zfcp_erp_async_handler(erp_action, 0); | ||
1029 | } | ||
1030 | |||
1031 | /* | ||
1032 | * purpose: is called if an asynchronous erp step timed out, | ||
1033 | * action gets an appropriate flag and will be processed | ||
1034 | * accordingly | ||
1035 | */ | ||
1036 | static void | ||
1037 | zfcp_erp_timeout_handler(unsigned long data) | ||
1038 | { | ||
1039 | struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data; | ||
1040 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1041 | |||
1042 | debug_text_event(adapter->erp_dbf, 2, "a_th"); | ||
1043 | debug_event(adapter->erp_dbf, 2, &erp_action->action, sizeof (int)); | ||
1044 | |||
1045 | zfcp_erp_async_handler(erp_action, ZFCP_STATUS_ERP_TIMEDOUT); | ||
1046 | } | ||
1047 | |||
1048 | /* | ||
1049 | * purpose: is called for an erp_action which needs to be ended | ||
1050 | * though not being done, | ||
1051 | * this is usually required if an higher is generated, | ||
1052 | * action gets an appropriate flag and will be processed | ||
1053 | * accordingly | ||
1054 | * | ||
1055 | * locks: erp_lock held (thus we need to call another handler variant) | ||
1056 | */ | ||
1057 | static int | ||
1058 | zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action) | ||
1059 | { | ||
1060 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1061 | |||
1062 | debug_text_event(adapter->erp_dbf, 2, "a_adis"); | ||
1063 | debug_event(adapter->erp_dbf, 2, &erp_action->action, sizeof (int)); | ||
1064 | |||
1065 | zfcp_erp_async_handler_nolock(erp_action, ZFCP_STATUS_ERP_DISMISSED); | ||
1066 | |||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1070 | int | ||
1071 | zfcp_erp_thread_setup(struct zfcp_adapter *adapter) | ||
1072 | { | ||
1073 | int retval = 0; | ||
1074 | |||
1075 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | ||
1076 | |||
1077 | rwlock_init(&adapter->erp_lock); | ||
1078 | INIT_LIST_HEAD(&adapter->erp_ready_head); | ||
1079 | INIT_LIST_HEAD(&adapter->erp_running_head); | ||
1080 | sema_init(&adapter->erp_ready_sem, 0); | ||
1081 | |||
1082 | retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); | ||
1083 | if (retval < 0) { | ||
1084 | ZFCP_LOG_NORMAL("error: creation of erp thread failed for " | ||
1085 | "adapter %s\n", | ||
1086 | zfcp_get_busid_by_adapter(adapter)); | ||
1087 | debug_text_event(adapter->erp_dbf, 5, "a_thset_fail"); | ||
1088 | } else { | ||
1089 | wait_event(adapter->erp_thread_wqh, | ||
1090 | atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, | ||
1091 | &adapter->status)); | ||
1092 | debug_text_event(adapter->erp_dbf, 5, "a_thset_ok"); | ||
1093 | } | ||
1094 | |||
1095 | return (retval < 0); | ||
1096 | } | ||
1097 | |||
1098 | /* | ||
1099 | * function: | ||
1100 | * | ||
1101 | * purpose: | ||
1102 | * | ||
1103 | * returns: | ||
1104 | * | ||
1105 | * context: process (i.e. proc-fs or rmmod/insmod) | ||
1106 | * | ||
1107 | * note: The caller of this routine ensures that the specified | ||
1108 | * adapter has been shut down and that this operation | ||
1109 | * has been completed. Thus, there are no pending erp_actions | ||
1110 | * which would need to be handled here. | ||
1111 | */ | ||
1112 | int | ||
1113 | zfcp_erp_thread_kill(struct zfcp_adapter *adapter) | ||
1114 | { | ||
1115 | int retval = 0; | ||
1116 | |||
1117 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); | ||
1118 | up(&adapter->erp_ready_sem); | ||
1119 | |||
1120 | wait_event(adapter->erp_thread_wqh, | ||
1121 | !atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, | ||
1122 | &adapter->status)); | ||
1123 | |||
1124 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, | ||
1125 | &adapter->status); | ||
1126 | |||
1127 | debug_text_event(adapter->erp_dbf, 5, "a_thki_ok"); | ||
1128 | |||
1129 | return retval; | ||
1130 | } | ||
1131 | |||
1132 | /* | ||
1133 | * purpose: is run as a kernel thread, | ||
1134 | * goes through list of error recovery actions of associated adapter | ||
1135 | * and delegates single action to execution | ||
1136 | * | ||
1137 | * returns: 0 | ||
1138 | */ | ||
1139 | static int | ||
1140 | zfcp_erp_thread(void *data) | ||
1141 | { | ||
1142 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; | ||
1143 | struct list_head *next; | ||
1144 | struct zfcp_erp_action *erp_action; | ||
1145 | unsigned long flags; | ||
1146 | |||
1147 | daemonize("zfcperp%s", zfcp_get_busid_by_adapter(adapter)); | ||
1148 | /* Block all signals */ | ||
1149 | siginitsetinv(¤t->blocked, 0); | ||
1150 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | ||
1151 | debug_text_event(adapter->erp_dbf, 5, "a_th_run"); | ||
1152 | wake_up(&adapter->erp_thread_wqh); | ||
1153 | |||
1154 | while (!atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, | ||
1155 | &adapter->status)) { | ||
1156 | |||
1157 | write_lock_irqsave(&adapter->erp_lock, flags); | ||
1158 | next = adapter->erp_ready_head.prev; | ||
1159 | write_unlock_irqrestore(&adapter->erp_lock, flags); | ||
1160 | |||
1161 | if (next != &adapter->erp_ready_head) { | ||
1162 | erp_action = | ||
1163 | list_entry(next, struct zfcp_erp_action, list); | ||
1164 | /* | ||
1165 | * process action (incl. [re]moving it | ||
1166 | * from 'ready' queue) | ||
1167 | */ | ||
1168 | zfcp_erp_strategy(erp_action); | ||
1169 | } | ||
1170 | |||
1171 | /* | ||
1172 | * sleep as long as there is nothing to do, i.e. | ||
1173 | * no action in 'ready' queue to be processed and | ||
1174 | * thread is not to be killed | ||
1175 | */ | ||
1176 | down_interruptible(&adapter->erp_ready_sem); | ||
1177 | debug_text_event(adapter->erp_dbf, 5, "a_th_woken"); | ||
1178 | } | ||
1179 | |||
1180 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); | ||
1181 | debug_text_event(adapter->erp_dbf, 5, "a_th_stop"); | ||
1182 | wake_up(&adapter->erp_thread_wqh); | ||
1183 | |||
1184 | return 0; | ||
1185 | } | ||
1186 | |||
1187 | /* | ||
1188 | * function: | ||
1189 | * | ||
1190 | * purpose: drives single error recovery action and schedules higher and | ||
1191 | * subordinate actions, if necessary | ||
1192 | * | ||
1193 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
1194 | * ZFCP_ERP_SUCCEEDED - action finished successfully (deqd) | ||
1195 | * ZFCP_ERP_FAILED - action finished unsuccessfully (deqd) | ||
1196 | * ZFCP_ERP_EXIT - action finished (dequeued), offline | ||
1197 | * ZFCP_ERP_DISMISSED - action canceled (dequeued) | ||
1198 | */ | ||
1199 | static int | ||
1200 | zfcp_erp_strategy(struct zfcp_erp_action *erp_action) | ||
1201 | { | ||
1202 | int retval = 0; | ||
1203 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1204 | struct zfcp_port *port = erp_action->port; | ||
1205 | struct zfcp_unit *unit = erp_action->unit; | ||
1206 | int action = erp_action->action; | ||
1207 | u32 status = erp_action->status; | ||
1208 | unsigned long flags; | ||
1209 | |||
1210 | /* serialise dismissing, timing out, moving, enqueueing */ | ||
1211 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1212 | write_lock(&adapter->erp_lock); | ||
1213 | |||
1214 | /* dequeue dismissed action and leave, if required */ | ||
1215 | retval = zfcp_erp_strategy_check_action(erp_action, retval); | ||
1216 | if (retval == ZFCP_ERP_DISMISSED) { | ||
1217 | debug_text_event(adapter->erp_dbf, 4, "a_st_dis1"); | ||
1218 | goto unlock; | ||
1219 | } | ||
1220 | |||
1221 | /* | ||
1222 | * move action to 'running' queue before processing it | ||
1223 | * (to avoid a race condition regarding moving the | ||
1224 | * action to the 'running' queue and back) | ||
1225 | */ | ||
1226 | zfcp_erp_action_to_running(erp_action); | ||
1227 | |||
1228 | /* | ||
1229 | * try to process action as far as possible, | ||
1230 | * no lock to allow for blocking operations (kmalloc, qdio, ...), | ||
1231 | * afterwards the lock is required again for the following reasons: | ||
1232 | * - dequeueing of finished action and enqueueing of | ||
1233 | * follow-up actions must be atomic so that any other | ||
1234 | * reopen-routine does not believe there is nothing to do | ||
1235 | * and that it is safe to enqueue something else, | ||
1236 | * - we want to force any control thread which is dismissing | ||
1237 | * actions to finish this before we decide about | ||
1238 | * necessary steps to be taken here further | ||
1239 | */ | ||
1240 | write_unlock(&adapter->erp_lock); | ||
1241 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1242 | retval = zfcp_erp_strategy_do_action(erp_action); | ||
1243 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1244 | write_lock(&adapter->erp_lock); | ||
1245 | |||
1246 | /* | ||
1247 | * check for dismissed status again to avoid follow-up actions, | ||
1248 | * failing of targets and so on for dismissed actions | ||
1249 | */ | ||
1250 | retval = zfcp_erp_strategy_check_action(erp_action, retval); | ||
1251 | |||
1252 | switch (retval) { | ||
1253 | case ZFCP_ERP_DISMISSED: | ||
1254 | /* leave since this action has ridden to its ancestors */ | ||
1255 | debug_text_event(adapter->erp_dbf, 6, "a_st_dis2"); | ||
1256 | goto unlock; | ||
1257 | case ZFCP_ERP_NOMEM: | ||
1258 | /* no memory to continue immediately, let it sleep */ | ||
1259 | if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) { | ||
1260 | ++adapter->erp_low_mem_count; | ||
1261 | erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; | ||
1262 | } | ||
1263 | /* This condition is true if there is no memory available | ||
1264 | for any erp_action on this adapter. This implies that there | ||
1265 | are no elements in the memory pool(s) left for erp_actions. | ||
1266 | This might happen if an erp_action that used a memory pool | ||
1267 | element was timed out. | ||
1268 | */ | ||
1269 | if (adapter->erp_total_count == adapter->erp_low_mem_count) { | ||
1270 | debug_text_event(adapter->erp_dbf, 3, "a_st_lowmem"); | ||
1271 | ZFCP_LOG_NORMAL("error: no mempool elements available, " | ||
1272 | "restarting I/O on adapter %s " | ||
1273 | "to free mempool\n", | ||
1274 | zfcp_get_busid_by_adapter(adapter)); | ||
1275 | zfcp_erp_adapter_reopen_internal(adapter, 0); | ||
1276 | } else { | ||
1277 | debug_text_event(adapter->erp_dbf, 2, "a_st_memw"); | ||
1278 | retval = zfcp_erp_strategy_memwait(erp_action); | ||
1279 | } | ||
1280 | goto unlock; | ||
1281 | case ZFCP_ERP_CONTINUES: | ||
1282 | /* leave since this action runs asynchronously */ | ||
1283 | debug_text_event(adapter->erp_dbf, 6, "a_st_cont"); | ||
1284 | if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { | ||
1285 | --adapter->erp_low_mem_count; | ||
1286 | erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; | ||
1287 | } | ||
1288 | goto unlock; | ||
1289 | } | ||
1290 | /* ok, finished action (whatever its result is) */ | ||
1291 | |||
1292 | /* check for unrecoverable targets */ | ||
1293 | retval = zfcp_erp_strategy_check_target(erp_action, retval); | ||
1294 | |||
1295 | /* action must be dequeued (here to allow for further ones) */ | ||
1296 | zfcp_erp_action_dequeue(erp_action); | ||
1297 | |||
1298 | /* | ||
1299 | * put this target through the erp mill again if someone has | ||
1300 | * requested to change the status of a target being online | ||
1301 | * to offline or the other way around | ||
1302 | * (old retval is preserved if nothing has to be done here) | ||
1303 | */ | ||
1304 | retval = zfcp_erp_strategy_statechange(action, status, adapter, | ||
1305 | port, unit, retval); | ||
1306 | |||
1307 | /* | ||
1308 | * leave if target is in permanent error state or if | ||
1309 | * action is repeated in order to process state change | ||
1310 | */ | ||
1311 | if (retval == ZFCP_ERP_EXIT) { | ||
1312 | debug_text_event(adapter->erp_dbf, 2, "a_st_exit"); | ||
1313 | goto unlock; | ||
1314 | } | ||
1315 | |||
1316 | /* trigger follow up actions */ | ||
1317 | zfcp_erp_strategy_followup_actions(action, adapter, port, unit, retval); | ||
1318 | |||
1319 | unlock: | ||
1320 | write_unlock(&adapter->erp_lock); | ||
1321 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1322 | |||
1323 | if (retval != ZFCP_ERP_CONTINUES) | ||
1324 | zfcp_erp_action_cleanup(action, adapter, port, unit, retval); | ||
1325 | |||
1326 | /* | ||
1327 | * a few tasks remain when the erp queues are empty | ||
1328 | * (don't do that if the last action evaluated was dismissed | ||
1329 | * since this clearly indicates that there is more to come) : | ||
1330 | * - close the name server port if it is open yet | ||
1331 | * (enqueues another [probably] final action) | ||
1332 | * - otherwise, wake up whoever wants to be woken when we are | ||
1333 | * done with erp | ||
1334 | */ | ||
1335 | if (retval != ZFCP_ERP_DISMISSED) | ||
1336 | zfcp_erp_strategy_check_queues(adapter); | ||
1337 | |||
1338 | debug_text_event(adapter->erp_dbf, 6, "a_st_done"); | ||
1339 | |||
1340 | return retval; | ||
1341 | } | ||
1342 | |||
1343 | /* | ||
1344 | * function: | ||
1345 | * | ||
1346 | * purpose: | ||
1347 | * | ||
1348 | * returns: ZFCP_ERP_DISMISSED - if action has been dismissed | ||
1349 | * retval - otherwise | ||
1350 | */ | ||
1351 | static int | ||
1352 | zfcp_erp_strategy_check_action(struct zfcp_erp_action *erp_action, int retval) | ||
1353 | { | ||
1354 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1355 | |||
1356 | zfcp_erp_strategy_check_fsfreq(erp_action); | ||
1357 | |||
1358 | debug_event(adapter->erp_dbf, 5, &erp_action->action, sizeof (int)); | ||
1359 | if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { | ||
1360 | debug_text_event(adapter->erp_dbf, 3, "a_stcd_dis"); | ||
1361 | zfcp_erp_action_dequeue(erp_action); | ||
1362 | retval = ZFCP_ERP_DISMISSED; | ||
1363 | } else | ||
1364 | debug_text_event(adapter->erp_dbf, 5, "a_stcd_nodis"); | ||
1365 | |||
1366 | return retval; | ||
1367 | } | ||
1368 | |||
1369 | /* | ||
1370 | * function: | ||
1371 | * | ||
1372 | * purpose: | ||
1373 | * | ||
1374 | * returns: | ||
1375 | */ | ||
1376 | static int | ||
1377 | zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) | ||
1378 | { | ||
1379 | int retval = ZFCP_ERP_FAILED; | ||
1380 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1381 | |||
1382 | /* | ||
1383 | * try to execute/continue action as far as possible, | ||
1384 | * note: no lock in subsequent strategy routines | ||
1385 | * (this allows these routine to call schedule, e.g. | ||
1386 | * kmalloc with such flags or qdio_initialize & friends) | ||
1387 | * Note: in case of timeout, the seperate strategies will fail | ||
1388 | * anyhow. No need for a special action. Even worse, a nameserver | ||
1389 | * failure would not wake up waiting ports without the call. | ||
1390 | */ | ||
1391 | switch (erp_action->action) { | ||
1392 | |||
1393 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
1394 | retval = zfcp_erp_adapter_strategy(erp_action); | ||
1395 | break; | ||
1396 | |||
1397 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
1398 | retval = zfcp_erp_port_forced_strategy(erp_action); | ||
1399 | break; | ||
1400 | |||
1401 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
1402 | retval = zfcp_erp_port_strategy(erp_action); | ||
1403 | break; | ||
1404 | |||
1405 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
1406 | retval = zfcp_erp_unit_strategy(erp_action); | ||
1407 | break; | ||
1408 | |||
1409 | default: | ||
1410 | debug_text_exception(adapter->erp_dbf, 1, "a_stda_bug"); | ||
1411 | debug_event(adapter->erp_dbf, 1, &erp_action->action, | ||
1412 | sizeof (int)); | ||
1413 | ZFCP_LOG_NORMAL("bug: unknown erp action requested on " | ||
1414 | "adapter %s (action=%d)\n", | ||
1415 | zfcp_get_busid_by_adapter(erp_action->adapter), | ||
1416 | erp_action->action); | ||
1417 | } | ||
1418 | |||
1419 | return retval; | ||
1420 | } | ||
1421 | |||
1422 | /* | ||
1423 | * function: | ||
1424 | * | ||
1425 | * purpose: triggers retry of this action after a certain amount of time | ||
1426 | * by means of timer provided by erp_action | ||
1427 | * | ||
1428 | * returns: ZFCP_ERP_CONTINUES - erp_action sleeps in erp running queue | ||
1429 | */ | ||
1430 | static int | ||
1431 | zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action) | ||
1432 | { | ||
1433 | int retval = ZFCP_ERP_CONTINUES; | ||
1434 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1435 | |||
1436 | debug_text_event(adapter->erp_dbf, 6, "a_mwinit"); | ||
1437 | debug_event(adapter->erp_dbf, 6, &erp_action->action, sizeof (int)); | ||
1438 | init_timer(&erp_action->timer); | ||
1439 | erp_action->timer.function = zfcp_erp_memwait_handler; | ||
1440 | erp_action->timer.data = (unsigned long) erp_action; | ||
1441 | erp_action->timer.expires = jiffies + ZFCP_ERP_MEMWAIT_TIMEOUT; | ||
1442 | add_timer(&erp_action->timer); | ||
1443 | |||
1444 | return retval; | ||
1445 | } | ||
1446 | |||
1447 | /* | ||
1448 | * function: zfcp_erp_adapter_failed | ||
1449 | * | ||
1450 | * purpose: sets the adapter and all underlying devices to ERP_FAILED | ||
1451 | * | ||
1452 | */ | ||
1453 | void | ||
1454 | zfcp_erp_adapter_failed(struct zfcp_adapter *adapter) | ||
1455 | { | ||
1456 | zfcp_erp_modify_adapter_status(adapter, | ||
1457 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | ||
1458 | ZFCP_LOG_NORMAL("adapter erp failed on adapter %s\n", | ||
1459 | zfcp_get_busid_by_adapter(adapter)); | ||
1460 | debug_text_event(adapter->erp_dbf, 2, "a_afail"); | ||
1461 | } | ||
1462 | |||
1463 | /* | ||
1464 | * function: zfcp_erp_port_failed | ||
1465 | * | ||
1466 | * purpose: sets the port and all underlying devices to ERP_FAILED | ||
1467 | * | ||
1468 | */ | ||
1469 | void | ||
1470 | zfcp_erp_port_failed(struct zfcp_port *port) | ||
1471 | { | ||
1472 | zfcp_erp_modify_port_status(port, | ||
1473 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | ||
1474 | |||
1475 | if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) | ||
1476 | ZFCP_LOG_NORMAL("port erp failed (adapter %s, " | ||
1477 | "port d_id=0x%08x)\n", | ||
1478 | zfcp_get_busid_by_port(port), port->d_id); | ||
1479 | else | ||
1480 | ZFCP_LOG_NORMAL("port erp failed (adapter %s, wwpn=0x%016Lx)\n", | ||
1481 | zfcp_get_busid_by_port(port), port->wwpn); | ||
1482 | |||
1483 | debug_text_event(port->adapter->erp_dbf, 2, "p_pfail"); | ||
1484 | debug_event(port->adapter->erp_dbf, 2, &port->wwpn, sizeof (wwn_t)); | ||
1485 | } | ||
1486 | |||
1487 | /* | ||
1488 | * function: zfcp_erp_unit_failed | ||
1489 | * | ||
1490 | * purpose: sets the unit to ERP_FAILED | ||
1491 | * | ||
1492 | */ | ||
1493 | void | ||
1494 | zfcp_erp_unit_failed(struct zfcp_unit *unit) | ||
1495 | { | ||
1496 | zfcp_erp_modify_unit_status(unit, | ||
1497 | ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET); | ||
1498 | |||
1499 | ZFCP_LOG_NORMAL("unit erp failed on unit 0x%016Lx on port 0x%016Lx " | ||
1500 | " on adapter %s\n", unit->fcp_lun, | ||
1501 | unit->port->wwpn, zfcp_get_busid_by_unit(unit)); | ||
1502 | debug_text_event(unit->port->adapter->erp_dbf, 2, "u_ufail"); | ||
1503 | debug_event(unit->port->adapter->erp_dbf, 2, | ||
1504 | &unit->fcp_lun, sizeof (fcp_lun_t)); | ||
1505 | } | ||
1506 | |||
1507 | /* | ||
1508 | * function: zfcp_erp_strategy_check_target | ||
1509 | * | ||
1510 | * purpose: increments the erp action count on the device currently in | ||
1511 | * recovery if the action failed or resets the count in case of | ||
1512 | * success. If a maximum count is exceeded the device is marked | ||
1513 | * as ERP_FAILED. | ||
1514 | * The 'blocked' state of a target which has been recovered | ||
1515 | * successfully is reset. | ||
1516 | * | ||
1517 | * returns: ZFCP_ERP_CONTINUES - action continues (not considered) | ||
1518 | * ZFCP_ERP_SUCCEEDED - action finished successfully | ||
1519 | * ZFCP_ERP_EXIT - action failed and will not continue | ||
1520 | */ | ||
1521 | static int | ||
1522 | zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action, int result) | ||
1523 | { | ||
1524 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1525 | struct zfcp_port *port = erp_action->port; | ||
1526 | struct zfcp_unit *unit = erp_action->unit; | ||
1527 | |||
1528 | debug_text_event(adapter->erp_dbf, 5, "a_stct_norm"); | ||
1529 | debug_event(adapter->erp_dbf, 5, &erp_action->action, sizeof (int)); | ||
1530 | debug_event(adapter->erp_dbf, 5, &result, sizeof (int)); | ||
1531 | |||
1532 | switch (erp_action->action) { | ||
1533 | |||
1534 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
1535 | result = zfcp_erp_strategy_check_unit(unit, result); | ||
1536 | break; | ||
1537 | |||
1538 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
1539 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
1540 | result = zfcp_erp_strategy_check_port(port, result); | ||
1541 | break; | ||
1542 | |||
1543 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
1544 | result = zfcp_erp_strategy_check_adapter(adapter, result); | ||
1545 | break; | ||
1546 | } | ||
1547 | |||
1548 | return result; | ||
1549 | } | ||
1550 | |||
1551 | /* | ||
1552 | * function: | ||
1553 | * | ||
1554 | * purpose: | ||
1555 | * | ||
1556 | * returns: | ||
1557 | */ | ||
1558 | static int | ||
1559 | zfcp_erp_strategy_statechange(int action, | ||
1560 | u32 status, | ||
1561 | struct zfcp_adapter *adapter, | ||
1562 | struct zfcp_port *port, | ||
1563 | struct zfcp_unit *unit, int retval) | ||
1564 | { | ||
1565 | debug_text_event(adapter->erp_dbf, 3, "a_stsc"); | ||
1566 | debug_event(adapter->erp_dbf, 3, &action, sizeof (int)); | ||
1567 | |||
1568 | switch (action) { | ||
1569 | |||
1570 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
1571 | if (zfcp_erp_strategy_statechange_detected(&adapter->status, | ||
1572 | status)) { | ||
1573 | zfcp_erp_adapter_reopen_internal(adapter, ZFCP_STATUS_COMMON_ERP_FAILED); | ||
1574 | retval = ZFCP_ERP_EXIT; | ||
1575 | } | ||
1576 | break; | ||
1577 | |||
1578 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
1579 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
1580 | if (zfcp_erp_strategy_statechange_detected(&port->status, | ||
1581 | status)) { | ||
1582 | zfcp_erp_port_reopen_internal(port, ZFCP_STATUS_COMMON_ERP_FAILED); | ||
1583 | retval = ZFCP_ERP_EXIT; | ||
1584 | } | ||
1585 | break; | ||
1586 | |||
1587 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
1588 | if (zfcp_erp_strategy_statechange_detected(&unit->status, | ||
1589 | status)) { | ||
1590 | zfcp_erp_unit_reopen_internal(unit, ZFCP_STATUS_COMMON_ERP_FAILED); | ||
1591 | retval = ZFCP_ERP_EXIT; | ||
1592 | } | ||
1593 | break; | ||
1594 | } | ||
1595 | |||
1596 | return retval; | ||
1597 | } | ||
1598 | |||
1599 | /* | ||
1600 | * function: | ||
1601 | * | ||
1602 | * purpose: | ||
1603 | * | ||
1604 | * returns: | ||
1605 | */ | ||
1606 | static inline int | ||
1607 | zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status) | ||
1608 | { | ||
1609 | return | ||
1610 | /* take it online */ | ||
1611 | (atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, target_status) && | ||
1612 | (ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status)) || | ||
1613 | /* take it offline */ | ||
1614 | (!atomic_test_mask(ZFCP_STATUS_COMMON_RUNNING, target_status) && | ||
1615 | !(ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status)); | ||
1616 | } | ||
1617 | |||
1618 | /* | ||
1619 | * function: | ||
1620 | * | ||
1621 | * purpose: | ||
1622 | * | ||
1623 | * returns: | ||
1624 | */ | ||
1625 | static int | ||
1626 | zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result) | ||
1627 | { | ||
1628 | debug_text_event(unit->port->adapter->erp_dbf, 5, "u_stct"); | ||
1629 | debug_event(unit->port->adapter->erp_dbf, 5, &unit->fcp_lun, | ||
1630 | sizeof (fcp_lun_t)); | ||
1631 | |||
1632 | switch (result) { | ||
1633 | case ZFCP_ERP_SUCCEEDED : | ||
1634 | atomic_set(&unit->erp_counter, 0); | ||
1635 | zfcp_erp_unit_unblock(unit); | ||
1636 | break; | ||
1637 | case ZFCP_ERP_FAILED : | ||
1638 | atomic_inc(&unit->erp_counter); | ||
1639 | if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) | ||
1640 | zfcp_erp_unit_failed(unit); | ||
1641 | break; | ||
1642 | case ZFCP_ERP_EXIT : | ||
1643 | /* nothing */ | ||
1644 | break; | ||
1645 | } | ||
1646 | |||
1647 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &unit->status)) { | ||
1648 | zfcp_erp_unit_block(unit, 0); /* for ZFCP_ERP_SUCCEEDED */ | ||
1649 | result = ZFCP_ERP_EXIT; | ||
1650 | } | ||
1651 | |||
1652 | return result; | ||
1653 | } | ||
1654 | |||
1655 | /* | ||
1656 | * function: | ||
1657 | * | ||
1658 | * purpose: | ||
1659 | * | ||
1660 | * returns: | ||
1661 | */ | ||
1662 | static int | ||
1663 | zfcp_erp_strategy_check_port(struct zfcp_port *port, int result) | ||
1664 | { | ||
1665 | debug_text_event(port->adapter->erp_dbf, 5, "p_stct"); | ||
1666 | debug_event(port->adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); | ||
1667 | |||
1668 | switch (result) { | ||
1669 | case ZFCP_ERP_SUCCEEDED : | ||
1670 | atomic_set(&port->erp_counter, 0); | ||
1671 | zfcp_erp_port_unblock(port); | ||
1672 | break; | ||
1673 | case ZFCP_ERP_FAILED : | ||
1674 | atomic_inc(&port->erp_counter); | ||
1675 | if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) | ||
1676 | zfcp_erp_port_failed(port); | ||
1677 | break; | ||
1678 | case ZFCP_ERP_EXIT : | ||
1679 | /* nothing */ | ||
1680 | break; | ||
1681 | } | ||
1682 | |||
1683 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { | ||
1684 | zfcp_erp_port_block(port, 0); /* for ZFCP_ERP_SUCCEEDED */ | ||
1685 | result = ZFCP_ERP_EXIT; | ||
1686 | } | ||
1687 | |||
1688 | return result; | ||
1689 | } | ||
1690 | |||
1691 | /* | ||
1692 | * function: | ||
1693 | * | ||
1694 | * purpose: | ||
1695 | * | ||
1696 | * returns: | ||
1697 | */ | ||
1698 | static int | ||
1699 | zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, int result) | ||
1700 | { | ||
1701 | debug_text_event(adapter->erp_dbf, 5, "a_stct"); | ||
1702 | |||
1703 | switch (result) { | ||
1704 | case ZFCP_ERP_SUCCEEDED : | ||
1705 | atomic_set(&adapter->erp_counter, 0); | ||
1706 | zfcp_erp_adapter_unblock(adapter); | ||
1707 | break; | ||
1708 | case ZFCP_ERP_FAILED : | ||
1709 | atomic_inc(&adapter->erp_counter); | ||
1710 | if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) | ||
1711 | zfcp_erp_adapter_failed(adapter); | ||
1712 | break; | ||
1713 | case ZFCP_ERP_EXIT : | ||
1714 | /* nothing */ | ||
1715 | break; | ||
1716 | } | ||
1717 | |||
1718 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) { | ||
1719 | zfcp_erp_adapter_block(adapter, 0); /* for ZFCP_ERP_SUCCEEDED */ | ||
1720 | result = ZFCP_ERP_EXIT; | ||
1721 | } | ||
1722 | |||
1723 | return result; | ||
1724 | } | ||
1725 | |||
1726 | /* | ||
1727 | * function: | ||
1728 | * | ||
1729 | * purpose: remaining things in good cases, | ||
1730 | * escalation in bad cases | ||
1731 | * | ||
1732 | * returns: | ||
1733 | */ | ||
1734 | static int | ||
1735 | zfcp_erp_strategy_followup_actions(int action, | ||
1736 | struct zfcp_adapter *adapter, | ||
1737 | struct zfcp_port *port, | ||
1738 | struct zfcp_unit *unit, int status) | ||
1739 | { | ||
1740 | debug_text_event(adapter->erp_dbf, 5, "a_stfol"); | ||
1741 | debug_event(adapter->erp_dbf, 5, &action, sizeof (int)); | ||
1742 | |||
1743 | /* initiate follow-up actions depending on success of finished action */ | ||
1744 | switch (action) { | ||
1745 | |||
1746 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
1747 | if (status == ZFCP_ERP_SUCCEEDED) | ||
1748 | zfcp_erp_port_reopen_all_internal(adapter, 0); | ||
1749 | else | ||
1750 | zfcp_erp_adapter_reopen_internal(adapter, 0); | ||
1751 | break; | ||
1752 | |||
1753 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
1754 | if (status == ZFCP_ERP_SUCCEEDED) | ||
1755 | zfcp_erp_port_reopen_internal(port, 0); | ||
1756 | else | ||
1757 | zfcp_erp_adapter_reopen_internal(adapter, 0); | ||
1758 | break; | ||
1759 | |||
1760 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
1761 | if (status == ZFCP_ERP_SUCCEEDED) | ||
1762 | zfcp_erp_unit_reopen_all_internal(port, 0); | ||
1763 | else | ||
1764 | zfcp_erp_port_forced_reopen_internal(port, 0); | ||
1765 | break; | ||
1766 | |||
1767 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
1768 | if (status == ZFCP_ERP_SUCCEEDED) ; /* no further action */ | ||
1769 | else | ||
1770 | zfcp_erp_port_reopen_internal(unit->port, 0); | ||
1771 | break; | ||
1772 | } | ||
1773 | |||
1774 | return 0; | ||
1775 | } | ||
1776 | |||
1777 | /* | ||
1778 | * function: | ||
1779 | * | ||
1780 | * purpose: | ||
1781 | * | ||
1782 | * returns: | ||
1783 | */ | ||
1784 | static int | ||
1785 | zfcp_erp_strategy_check_queues(struct zfcp_adapter *adapter) | ||
1786 | { | ||
1787 | unsigned long flags; | ||
1788 | |||
1789 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1790 | read_lock(&adapter->erp_lock); | ||
1791 | if (list_empty(&adapter->erp_ready_head) && | ||
1792 | list_empty(&adapter->erp_running_head)) { | ||
1793 | debug_text_event(adapter->erp_dbf, 4, "a_cq_wake"); | ||
1794 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, | ||
1795 | &adapter->status); | ||
1796 | wake_up(&adapter->erp_done_wqh); | ||
1797 | } else | ||
1798 | debug_text_event(adapter->erp_dbf, 5, "a_cq_notempty"); | ||
1799 | read_unlock(&adapter->erp_lock); | ||
1800 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1801 | |||
1802 | return 0; | ||
1803 | } | ||
1804 | |||
1805 | /** | ||
1806 | * zfcp_erp_wait - wait for completion of error recovery on an adapter | ||
1807 | * @adapter: adapter for which to wait for completion of its error recovery | ||
1808 | * Return: 0 | ||
1809 | */ | ||
1810 | int | ||
1811 | zfcp_erp_wait(struct zfcp_adapter *adapter) | ||
1812 | { | ||
1813 | int retval = 0; | ||
1814 | |||
1815 | wait_event(adapter->erp_done_wqh, | ||
1816 | !atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, | ||
1817 | &adapter->status)); | ||
1818 | |||
1819 | return retval; | ||
1820 | } | ||
1821 | |||
1822 | /* | ||
1823 | * function: zfcp_erp_modify_adapter_status | ||
1824 | * | ||
1825 | * purpose: | ||
1826 | * | ||
1827 | */ | ||
1828 | void | ||
1829 | zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, | ||
1830 | u32 mask, int set_or_clear) | ||
1831 | { | ||
1832 | struct zfcp_port *port; | ||
1833 | u32 common_mask = mask & ZFCP_COMMON_FLAGS; | ||
1834 | |||
1835 | if (set_or_clear == ZFCP_SET) { | ||
1836 | atomic_set_mask(mask, &adapter->status); | ||
1837 | debug_text_event(adapter->erp_dbf, 3, "a_mod_as_s"); | ||
1838 | } else { | ||
1839 | atomic_clear_mask(mask, &adapter->status); | ||
1840 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
1841 | atomic_set(&adapter->erp_counter, 0); | ||
1842 | debug_text_event(adapter->erp_dbf, 3, "a_mod_as_c"); | ||
1843 | } | ||
1844 | debug_event(adapter->erp_dbf, 3, &mask, sizeof (u32)); | ||
1845 | |||
1846 | /* Deal with all underlying devices, only pass common_mask */ | ||
1847 | if (common_mask) | ||
1848 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
1849 | zfcp_erp_modify_port_status(port, common_mask, | ||
1850 | set_or_clear); | ||
1851 | } | ||
1852 | |||
1853 | /* | ||
1854 | * function: zfcp_erp_modify_port_status | ||
1855 | * | ||
1856 | * purpose: sets the port and all underlying devices to ERP_FAILED | ||
1857 | * | ||
1858 | */ | ||
1859 | void | ||
1860 | zfcp_erp_modify_port_status(struct zfcp_port *port, u32 mask, int set_or_clear) | ||
1861 | { | ||
1862 | struct zfcp_unit *unit; | ||
1863 | u32 common_mask = mask & ZFCP_COMMON_FLAGS; | ||
1864 | |||
1865 | if (set_or_clear == ZFCP_SET) { | ||
1866 | atomic_set_mask(mask, &port->status); | ||
1867 | debug_text_event(port->adapter->erp_dbf, 3, "p_mod_ps_s"); | ||
1868 | } else { | ||
1869 | atomic_clear_mask(mask, &port->status); | ||
1870 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) | ||
1871 | atomic_set(&port->erp_counter, 0); | ||
1872 | debug_text_event(port->adapter->erp_dbf, 3, "p_mod_ps_c"); | ||
1873 | } | ||
1874 | debug_event(port->adapter->erp_dbf, 3, &port->wwpn, sizeof (wwn_t)); | ||
1875 | debug_event(port->adapter->erp_dbf, 3, &mask, sizeof (u32)); | ||
1876 | |||
1877 | /* Modify status of all underlying devices, only pass common mask */ | ||
1878 | if (common_mask) | ||
1879 | list_for_each_entry(unit, &port->unit_list_head, list) | ||
1880 | zfcp_erp_modify_unit_status(unit, common_mask, | ||
1881 | set_or_clear); | ||
1882 | } | ||
1883 | |||
1884 | /* | ||
1885 | * function: zfcp_erp_modify_unit_status | ||
1886 | * | ||
1887 | * purpose: sets the unit to ERP_FAILED | ||
1888 | * | ||
1889 | */ | ||
1890 | void | ||
1891 | zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u32 mask, int set_or_clear) | ||
1892 | { | ||
1893 | if (set_or_clear == ZFCP_SET) { | ||
1894 | atomic_set_mask(mask, &unit->status); | ||
1895 | debug_text_event(unit->port->adapter->erp_dbf, 3, "u_mod_us_s"); | ||
1896 | } else { | ||
1897 | atomic_clear_mask(mask, &unit->status); | ||
1898 | if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) { | ||
1899 | atomic_set(&unit->erp_counter, 0); | ||
1900 | } | ||
1901 | debug_text_event(unit->port->adapter->erp_dbf, 3, "u_mod_us_c"); | ||
1902 | } | ||
1903 | debug_event(unit->port->adapter->erp_dbf, 3, &unit->fcp_lun, | ||
1904 | sizeof (fcp_lun_t)); | ||
1905 | debug_event(unit->port->adapter->erp_dbf, 3, &mask, sizeof (u32)); | ||
1906 | } | ||
1907 | |||
1908 | /* | ||
1909 | * function: | ||
1910 | * | ||
1911 | * purpose: Wrappper for zfcp_erp_port_reopen_all_internal | ||
1912 | * used to ensure the correct locking | ||
1913 | * | ||
1914 | * returns: 0 - initiated action succesfully | ||
1915 | * <0 - failed to initiate action | ||
1916 | */ | ||
1917 | int | ||
1918 | zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter, int clear_mask) | ||
1919 | { | ||
1920 | int retval; | ||
1921 | unsigned long flags; | ||
1922 | |||
1923 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
1924 | write_lock(&adapter->erp_lock); | ||
1925 | retval = zfcp_erp_port_reopen_all_internal(adapter, clear_mask); | ||
1926 | write_unlock(&adapter->erp_lock); | ||
1927 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
1928 | |||
1929 | return retval; | ||
1930 | } | ||
1931 | |||
1932 | /* | ||
1933 | * function: | ||
1934 | * | ||
1935 | * purpose: | ||
1936 | * | ||
1937 | * returns: FIXME | ||
1938 | */ | ||
1939 | static int | ||
1940 | zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *adapter, int clear_mask) | ||
1941 | { | ||
1942 | int retval = 0; | ||
1943 | struct zfcp_port *port; | ||
1944 | |||
1945 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
1946 | if (!atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) | ||
1947 | zfcp_erp_port_reopen_internal(port, clear_mask); | ||
1948 | |||
1949 | return retval; | ||
1950 | } | ||
1951 | |||
1952 | /* | ||
1953 | * function: | ||
1954 | * | ||
1955 | * purpose: | ||
1956 | * | ||
1957 | * returns: FIXME | ||
1958 | */ | ||
1959 | static int | ||
1960 | zfcp_erp_unit_reopen_all_internal(struct zfcp_port *port, int clear_mask) | ||
1961 | { | ||
1962 | int retval = 0; | ||
1963 | struct zfcp_unit *unit; | ||
1964 | |||
1965 | list_for_each_entry(unit, &port->unit_list_head, list) | ||
1966 | zfcp_erp_unit_reopen_internal(unit, clear_mask); | ||
1967 | |||
1968 | return retval; | ||
1969 | } | ||
1970 | |||
1971 | /* | ||
1972 | * function: | ||
1973 | * | ||
1974 | * purpose: this routine executes the 'Reopen Adapter' action | ||
1975 | * (the entire action is processed synchronously, since | ||
1976 | * there are no actions which might be run concurrently | ||
1977 | * per definition) | ||
1978 | * | ||
1979 | * returns: ZFCP_ERP_SUCCEEDED - action finished successfully | ||
1980 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
1981 | */ | ||
1982 | static int | ||
1983 | zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action) | ||
1984 | { | ||
1985 | int retval; | ||
1986 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
1987 | |||
1988 | retval = zfcp_erp_adapter_strategy_close(erp_action); | ||
1989 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) | ||
1990 | retval = ZFCP_ERP_EXIT; | ||
1991 | else | ||
1992 | retval = zfcp_erp_adapter_strategy_open(erp_action); | ||
1993 | |||
1994 | debug_text_event(adapter->erp_dbf, 3, "a_ast/ret"); | ||
1995 | debug_event(adapter->erp_dbf, 3, &erp_action->action, sizeof (int)); | ||
1996 | debug_event(adapter->erp_dbf, 3, &retval, sizeof (int)); | ||
1997 | |||
1998 | if (retval == ZFCP_ERP_FAILED) { | ||
1999 | ZFCP_LOG_INFO("Waiting to allow the adapter %s " | ||
2000 | "to recover itself\n", | ||
2001 | zfcp_get_busid_by_adapter(adapter)); | ||
2002 | msleep(jiffies_to_msecs(ZFCP_TYPE2_RECOVERY_TIME)); | ||
2003 | } | ||
2004 | |||
2005 | return retval; | ||
2006 | } | ||
2007 | |||
2008 | /* | ||
2009 | * function: | ||
2010 | * | ||
2011 | * purpose: | ||
2012 | * | ||
2013 | * returns: ZFCP_ERP_SUCCEEDED - action finished successfully | ||
2014 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2015 | */ | ||
2016 | static int | ||
2017 | zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *erp_action) | ||
2018 | { | ||
2019 | int retval; | ||
2020 | |||
2021 | atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, | ||
2022 | &erp_action->adapter->status); | ||
2023 | retval = zfcp_erp_adapter_strategy_generic(erp_action, 1); | ||
2024 | atomic_clear_mask(ZFCP_STATUS_COMMON_CLOSING, | ||
2025 | &erp_action->adapter->status); | ||
2026 | |||
2027 | return retval; | ||
2028 | } | ||
2029 | |||
2030 | /* | ||
2031 | * function: | ||
2032 | * | ||
2033 | * purpose: | ||
2034 | * | ||
2035 | * returns: ZFCP_ERP_SUCCEEDED - action finished successfully | ||
2036 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2037 | */ | ||
2038 | static int | ||
2039 | zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *erp_action) | ||
2040 | { | ||
2041 | int retval; | ||
2042 | |||
2043 | atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, | ||
2044 | &erp_action->adapter->status); | ||
2045 | retval = zfcp_erp_adapter_strategy_generic(erp_action, 0); | ||
2046 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING, | ||
2047 | &erp_action->adapter->status); | ||
2048 | |||
2049 | return retval; | ||
2050 | } | ||
2051 | |||
2052 | /* | ||
2053 | * function: zfcp_register_adapter | ||
2054 | * | ||
2055 | * purpose: allocate the irq associated with this devno and register | ||
2056 | * the FSF adapter with the SCSI stack | ||
2057 | * | ||
2058 | * returns: | ||
2059 | */ | ||
2060 | static int | ||
2061 | zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close) | ||
2062 | { | ||
2063 | int retval = ZFCP_ERP_SUCCEEDED; | ||
2064 | |||
2065 | if (close) | ||
2066 | goto close_only; | ||
2067 | |||
2068 | retval = zfcp_erp_adapter_strategy_open_qdio(erp_action); | ||
2069 | if (retval != ZFCP_ERP_SUCCEEDED) | ||
2070 | goto failed_qdio; | ||
2071 | |||
2072 | retval = zfcp_erp_adapter_strategy_open_fsf(erp_action); | ||
2073 | if (retval != ZFCP_ERP_SUCCEEDED) | ||
2074 | goto failed_openfcp; | ||
2075 | |||
2076 | atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &erp_action->adapter->status); | ||
2077 | goto out; | ||
2078 | |||
2079 | close_only: | ||
2080 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, | ||
2081 | &erp_action->adapter->status); | ||
2082 | |||
2083 | failed_openfcp: | ||
2084 | zfcp_erp_adapter_strategy_close_qdio(erp_action); | ||
2085 | zfcp_erp_adapter_strategy_close_fsf(erp_action); | ||
2086 | failed_qdio: | ||
2087 | out: | ||
2088 | return retval; | ||
2089 | } | ||
2090 | |||
2091 | /* | ||
2092 | * function: zfcp_qdio_init | ||
2093 | * | ||
2094 | * purpose: setup QDIO operation for specified adapter | ||
2095 | * | ||
2096 | * returns: 0 - successful setup | ||
2097 | * !0 - failed setup | ||
2098 | */ | ||
2099 | int | ||
2100 | zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action) | ||
2101 | { | ||
2102 | int retval; | ||
2103 | int i; | ||
2104 | volatile struct qdio_buffer_element *sbale; | ||
2105 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
2106 | |||
2107 | if (atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) { | ||
2108 | ZFCP_LOG_NORMAL("bug: second attempt to set up QDIO on " | ||
2109 | "adapter %s\n", | ||
2110 | zfcp_get_busid_by_adapter(adapter)); | ||
2111 | goto failed_sanity; | ||
2112 | } | ||
2113 | |||
2114 | if (qdio_establish(&adapter->qdio_init_data) != 0) { | ||
2115 | ZFCP_LOG_INFO("error: establishment of QDIO queues failed " | ||
2116 | "on adapter %s\n", | ||
2117 | zfcp_get_busid_by_adapter(adapter)); | ||
2118 | goto failed_qdio_establish; | ||
2119 | } | ||
2120 | debug_text_event(adapter->erp_dbf, 3, "qdio_est"); | ||
2121 | |||
2122 | if (qdio_activate(adapter->ccw_device, 0) != 0) { | ||
2123 | ZFCP_LOG_INFO("error: activation of QDIO queues failed " | ||
2124 | "on adapter %s\n", | ||
2125 | zfcp_get_busid_by_adapter(adapter)); | ||
2126 | goto failed_qdio_activate; | ||
2127 | } | ||
2128 | debug_text_event(adapter->erp_dbf, 3, "qdio_act"); | ||
2129 | |||
2130 | /* | ||
2131 | * put buffers into response queue, | ||
2132 | */ | ||
2133 | for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { | ||
2134 | sbale = &(adapter->response_queue.buffer[i]->element[0]); | ||
2135 | sbale->length = 0; | ||
2136 | sbale->flags = SBAL_FLAGS_LAST_ENTRY; | ||
2137 | sbale->addr = 0; | ||
2138 | } | ||
2139 | |||
2140 | ZFCP_LOG_TRACE("calling do_QDIO on adapter %s (flags=0x%x, " | ||
2141 | "queue_no=%i, index_in_queue=%i, count=%i)\n", | ||
2142 | zfcp_get_busid_by_adapter(adapter), | ||
2143 | QDIO_FLAG_SYNC_INPUT, 0, 0, QDIO_MAX_BUFFERS_PER_Q); | ||
2144 | |||
2145 | retval = do_QDIO(adapter->ccw_device, | ||
2146 | QDIO_FLAG_SYNC_INPUT, | ||
2147 | 0, 0, QDIO_MAX_BUFFERS_PER_Q, NULL); | ||
2148 | |||
2149 | if (retval) { | ||
2150 | ZFCP_LOG_NORMAL("bug: setup of QDIO failed (retval=%d)\n", | ||
2151 | retval); | ||
2152 | goto failed_do_qdio; | ||
2153 | } else { | ||
2154 | adapter->response_queue.free_index = 0; | ||
2155 | atomic_set(&adapter->response_queue.free_count, 0); | ||
2156 | ZFCP_LOG_DEBUG("%i buffers successfully enqueued to " | ||
2157 | "response queue\n", QDIO_MAX_BUFFERS_PER_Q); | ||
2158 | } | ||
2159 | /* set index of first avalable SBALS / number of available SBALS */ | ||
2160 | adapter->request_queue.free_index = 0; | ||
2161 | atomic_set(&adapter->request_queue.free_count, QDIO_MAX_BUFFERS_PER_Q); | ||
2162 | adapter->request_queue.distance_from_int = 0; | ||
2163 | |||
2164 | /* initialize waitqueue used to wait for free SBALs in requests queue */ | ||
2165 | init_waitqueue_head(&adapter->request_wq); | ||
2166 | |||
2167 | /* ok, we did it - skip all cleanups for different failures */ | ||
2168 | atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); | ||
2169 | retval = ZFCP_ERP_SUCCEEDED; | ||
2170 | goto out; | ||
2171 | |||
2172 | failed_do_qdio: | ||
2173 | /* NOP */ | ||
2174 | |||
2175 | failed_qdio_activate: | ||
2176 | debug_text_event(adapter->erp_dbf, 3, "qdio_down1a"); | ||
2177 | while (qdio_shutdown(adapter->ccw_device, | ||
2178 | QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) | ||
2179 | msleep(1000); | ||
2180 | debug_text_event(adapter->erp_dbf, 3, "qdio_down1b"); | ||
2181 | |||
2182 | failed_qdio_establish: | ||
2183 | failed_sanity: | ||
2184 | retval = ZFCP_ERP_FAILED; | ||
2185 | |||
2186 | out: | ||
2187 | return retval; | ||
2188 | } | ||
2189 | |||
2190 | /* | ||
2191 | * function: zfcp_qdio_cleanup | ||
2192 | * | ||
2193 | * purpose: cleans up QDIO operation for the specified adapter | ||
2194 | * | ||
2195 | * returns: 0 - successful cleanup | ||
2196 | * !0 - failed cleanup | ||
2197 | */ | ||
2198 | int | ||
2199 | zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action) | ||
2200 | { | ||
2201 | int retval = ZFCP_ERP_SUCCEEDED; | ||
2202 | int first_used; | ||
2203 | int used_count; | ||
2204 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
2205 | |||
2206 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) { | ||
2207 | ZFCP_LOG_DEBUG("error: attempt to shut down inactive QDIO " | ||
2208 | "queues on adapter %s\n", | ||
2209 | zfcp_get_busid_by_adapter(adapter)); | ||
2210 | retval = ZFCP_ERP_FAILED; | ||
2211 | goto out; | ||
2212 | } | ||
2213 | |||
2214 | /* | ||
2215 | * Get queue_lock and clear QDIOUP flag. Thus it's guaranteed that | ||
2216 | * do_QDIO won't be called while qdio_shutdown is in progress. | ||
2217 | */ | ||
2218 | |||
2219 | write_lock_irq(&adapter->request_queue.queue_lock); | ||
2220 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); | ||
2221 | write_unlock_irq(&adapter->request_queue.queue_lock); | ||
2222 | |||
2223 | debug_text_event(adapter->erp_dbf, 3, "qdio_down2a"); | ||
2224 | while (qdio_shutdown(adapter->ccw_device, | ||
2225 | QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) | ||
2226 | msleep(1000); | ||
2227 | debug_text_event(adapter->erp_dbf, 3, "qdio_down2b"); | ||
2228 | |||
2229 | /* | ||
2230 | * First we had to stop QDIO operation. | ||
2231 | * Now it is safe to take the following actions. | ||
2232 | */ | ||
2233 | |||
2234 | /* Cleanup only necessary when there are unacknowledged buffers */ | ||
2235 | if (atomic_read(&adapter->request_queue.free_count) | ||
2236 | < QDIO_MAX_BUFFERS_PER_Q) { | ||
2237 | first_used = (adapter->request_queue.free_index + | ||
2238 | atomic_read(&adapter->request_queue.free_count)) | ||
2239 | % QDIO_MAX_BUFFERS_PER_Q; | ||
2240 | used_count = QDIO_MAX_BUFFERS_PER_Q - | ||
2241 | atomic_read(&adapter->request_queue.free_count); | ||
2242 | zfcp_qdio_zero_sbals(adapter->request_queue.buffer, | ||
2243 | first_used, used_count); | ||
2244 | } | ||
2245 | adapter->response_queue.free_index = 0; | ||
2246 | atomic_set(&adapter->response_queue.free_count, 0); | ||
2247 | adapter->request_queue.free_index = 0; | ||
2248 | atomic_set(&adapter->request_queue.free_count, 0); | ||
2249 | adapter->request_queue.distance_from_int = 0; | ||
2250 | out: | ||
2251 | return retval; | ||
2252 | } | ||
2253 | |||
2254 | /* | ||
2255 | * function: zfcp_fsf_init | ||
2256 | * | ||
2257 | * purpose: initializes FSF operation for the specified adapter | ||
2258 | * | ||
2259 | * returns: 0 - succesful initialization of FSF operation | ||
2260 | * !0 - failed to initialize FSF operation | ||
2261 | */ | ||
2262 | static int | ||
2263 | zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *erp_action) | ||
2264 | { | ||
2265 | int retval; | ||
2266 | |||
2267 | /* do 'exchange configuration data' */ | ||
2268 | retval = zfcp_erp_adapter_strategy_open_fsf_xconfig(erp_action); | ||
2269 | if (retval == ZFCP_ERP_FAILED) | ||
2270 | return retval; | ||
2271 | |||
2272 | /* start the desired number of Status Reads */ | ||
2273 | retval = zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action); | ||
2274 | return retval; | ||
2275 | } | ||
2276 | |||
2277 | /* | ||
2278 | * function: | ||
2279 | * | ||
2280 | * purpose: | ||
2281 | * | ||
2282 | * returns: | ||
2283 | */ | ||
2284 | static int | ||
2285 | zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) | ||
2286 | { | ||
2287 | int retval = ZFCP_ERP_SUCCEEDED; | ||
2288 | int retries; | ||
2289 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
2290 | |||
2291 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); | ||
2292 | retries = ZFCP_EXCHANGE_CONFIG_DATA_RETRIES; | ||
2293 | |||
2294 | do { | ||
2295 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, | ||
2296 | &adapter->status); | ||
2297 | ZFCP_LOG_DEBUG("Doing exchange config data\n"); | ||
2298 | zfcp_erp_action_to_running(erp_action); | ||
2299 | zfcp_erp_timeout_init(erp_action); | ||
2300 | if (zfcp_fsf_exchange_config_data(erp_action)) { | ||
2301 | retval = ZFCP_ERP_FAILED; | ||
2302 | debug_text_event(adapter->erp_dbf, 5, "a_fstx_xf"); | ||
2303 | ZFCP_LOG_INFO("error: initiation of exchange of " | ||
2304 | "configuration data failed for " | ||
2305 | "adapter %s\n", | ||
2306 | zfcp_get_busid_by_adapter(adapter)); | ||
2307 | break; | ||
2308 | } | ||
2309 | debug_text_event(adapter->erp_dbf, 6, "a_fstx_xok"); | ||
2310 | ZFCP_LOG_DEBUG("Xchange underway\n"); | ||
2311 | |||
2312 | /* | ||
2313 | * Why this works: | ||
2314 | * Both the normal completion handler as well as the timeout | ||
2315 | * handler will do an 'up' when the 'exchange config data' | ||
2316 | * request completes or times out. Thus, the signal to go on | ||
2317 | * won't be lost utilizing this semaphore. | ||
2318 | * Furthermore, this 'adapter_reopen' action is | ||
2319 | * guaranteed to be the only action being there (highest action | ||
2320 | * which prevents other actions from being created). | ||
2321 | * Resulting from that, the wake signal recognized here | ||
2322 | * _must_ be the one belonging to the 'exchange config | ||
2323 | * data' request. | ||
2324 | */ | ||
2325 | down(&adapter->erp_ready_sem); | ||
2326 | if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { | ||
2327 | ZFCP_LOG_INFO("error: exchange of configuration data " | ||
2328 | "for adapter %s timed out\n", | ||
2329 | zfcp_get_busid_by_adapter(adapter)); | ||
2330 | break; | ||
2331 | } | ||
2332 | if (atomic_test_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, | ||
2333 | &adapter->status)) { | ||
2334 | ZFCP_LOG_DEBUG("host connection still initialising... " | ||
2335 | "waiting and retrying...\n"); | ||
2336 | /* sleep a little bit before retry */ | ||
2337 | msleep(jiffies_to_msecs(ZFCP_EXCHANGE_CONFIG_DATA_SLEEP)); | ||
2338 | } | ||
2339 | } while ((retries--) && | ||
2340 | atomic_test_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, | ||
2341 | &adapter->status)); | ||
2342 | |||
2343 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, | ||
2344 | &adapter->status)) { | ||
2345 | ZFCP_LOG_INFO("error: exchange of configuration data for " | ||
2346 | "adapter %s failed\n", | ||
2347 | zfcp_get_busid_by_adapter(adapter)); | ||
2348 | retval = ZFCP_ERP_FAILED; | ||
2349 | } | ||
2350 | |||
2351 | return retval; | ||
2352 | } | ||
2353 | |||
2354 | /* | ||
2355 | * function: | ||
2356 | * | ||
2357 | * purpose: | ||
2358 | * | ||
2359 | * returns: | ||
2360 | */ | ||
2361 | static int | ||
2362 | zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action | ||
2363 | *erp_action) | ||
2364 | { | ||
2365 | int retval = ZFCP_ERP_SUCCEEDED; | ||
2366 | int temp_ret; | ||
2367 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
2368 | int i; | ||
2369 | |||
2370 | adapter->status_read_failed = 0; | ||
2371 | for (i = 0; i < ZFCP_STATUS_READS_RECOM; i++) { | ||
2372 | temp_ret = zfcp_fsf_status_read(adapter, ZFCP_WAIT_FOR_SBAL); | ||
2373 | if (temp_ret < 0) { | ||
2374 | ZFCP_LOG_INFO("error: set-up of unsolicited status " | ||
2375 | "notification failed on adapter %s\n", | ||
2376 | zfcp_get_busid_by_adapter(adapter)); | ||
2377 | retval = ZFCP_ERP_FAILED; | ||
2378 | i--; | ||
2379 | break; | ||
2380 | } | ||
2381 | } | ||
2382 | |||
2383 | return retval; | ||
2384 | } | ||
2385 | |||
2386 | /* | ||
2387 | * function: zfcp_fsf_cleanup | ||
2388 | * | ||
2389 | * purpose: cleanup FSF operation for specified adapter | ||
2390 | * | ||
2391 | * returns: 0 - FSF operation successfully cleaned up | ||
2392 | * !0 - failed to cleanup FSF operation for this adapter | ||
2393 | */ | ||
2394 | static int | ||
2395 | zfcp_erp_adapter_strategy_close_fsf(struct zfcp_erp_action *erp_action) | ||
2396 | { | ||
2397 | int retval = ZFCP_ERP_SUCCEEDED; | ||
2398 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
2399 | |||
2400 | /* | ||
2401 | * wake waiting initiators of requests, | ||
2402 | * return SCSI commands (with error status), | ||
2403 | * clean up all requests (synchronously) | ||
2404 | */ | ||
2405 | zfcp_fsf_req_dismiss_all(adapter); | ||
2406 | /* reset FSF request sequence number */ | ||
2407 | adapter->fsf_req_seq_no = 0; | ||
2408 | /* all ports and units are closed */ | ||
2409 | zfcp_erp_modify_adapter_status(adapter, | ||
2410 | ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR); | ||
2411 | |||
2412 | return retval; | ||
2413 | } | ||
2414 | |||
2415 | /* | ||
2416 | * function: | ||
2417 | * | ||
2418 | * purpose: this routine executes the 'Reopen Physical Port' action | ||
2419 | * | ||
2420 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2421 | * ZFCP_ERP_SUCCEEDED - action finished successfully | ||
2422 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2423 | */ | ||
2424 | static int | ||
2425 | zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action) | ||
2426 | { | ||
2427 | int retval = ZFCP_ERP_FAILED; | ||
2428 | struct zfcp_port *port = erp_action->port; | ||
2429 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
2430 | |||
2431 | switch (erp_action->step) { | ||
2432 | |||
2433 | /* | ||
2434 | * FIXME: | ||
2435 | * the ULP spec. begs for waiting for oustanding commands | ||
2436 | */ | ||
2437 | case ZFCP_ERP_STEP_UNINITIALIZED: | ||
2438 | zfcp_erp_port_strategy_clearstati(port); | ||
2439 | /* | ||
2440 | * it would be sufficient to test only the normal open flag | ||
2441 | * since the phys. open flag cannot be set if the normal | ||
2442 | * open flag is unset - however, this is for readabilty ... | ||
2443 | */ | ||
2444 | if (atomic_test_mask((ZFCP_STATUS_PORT_PHYS_OPEN | | ||
2445 | ZFCP_STATUS_COMMON_OPEN), | ||
2446 | &port->status)) { | ||
2447 | ZFCP_LOG_DEBUG("port 0x%016Lx is open -> trying " | ||
2448 | "close physical\n", port->wwpn); | ||
2449 | retval = | ||
2450 | zfcp_erp_port_forced_strategy_close(erp_action); | ||
2451 | } else | ||
2452 | retval = ZFCP_ERP_FAILED; | ||
2453 | break; | ||
2454 | |||
2455 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: | ||
2456 | if (atomic_test_mask(ZFCP_STATUS_PORT_PHYS_OPEN, | ||
2457 | &port->status)) { | ||
2458 | ZFCP_LOG_DEBUG("close physical failed for port " | ||
2459 | "0x%016Lx\n", port->wwpn); | ||
2460 | retval = ZFCP_ERP_FAILED; | ||
2461 | } else | ||
2462 | retval = ZFCP_ERP_SUCCEEDED; | ||
2463 | break; | ||
2464 | } | ||
2465 | |||
2466 | debug_text_event(adapter->erp_dbf, 3, "p_pfst/ret"); | ||
2467 | debug_event(adapter->erp_dbf, 3, &port->wwpn, sizeof (wwn_t)); | ||
2468 | debug_event(adapter->erp_dbf, 3, &erp_action->action, sizeof (int)); | ||
2469 | debug_event(adapter->erp_dbf, 3, &retval, sizeof (int)); | ||
2470 | |||
2471 | return retval; | ||
2472 | } | ||
2473 | |||
2474 | /* | ||
2475 | * function: | ||
2476 | * | ||
2477 | * purpose: this routine executes the 'Reopen Port' action | ||
2478 | * | ||
2479 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2480 | * ZFCP_ERP_SUCCEEDED - action finished successfully | ||
2481 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2482 | */ | ||
2483 | static int | ||
2484 | zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action) | ||
2485 | { | ||
2486 | int retval = ZFCP_ERP_FAILED; | ||
2487 | struct zfcp_port *port = erp_action->port; | ||
2488 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
2489 | |||
2490 | switch (erp_action->step) { | ||
2491 | |||
2492 | /* | ||
2493 | * FIXME: | ||
2494 | * the ULP spec. begs for waiting for oustanding commands | ||
2495 | */ | ||
2496 | case ZFCP_ERP_STEP_UNINITIALIZED: | ||
2497 | zfcp_erp_port_strategy_clearstati(port); | ||
2498 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { | ||
2499 | ZFCP_LOG_DEBUG("port 0x%016Lx is open -> trying " | ||
2500 | "close\n", port->wwpn); | ||
2501 | retval = zfcp_erp_port_strategy_close(erp_action); | ||
2502 | goto out; | ||
2503 | } /* else it's already closed, open it */ | ||
2504 | break; | ||
2505 | |||
2506 | case ZFCP_ERP_STEP_PORT_CLOSING: | ||
2507 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { | ||
2508 | ZFCP_LOG_DEBUG("close failed for port 0x%016Lx\n", | ||
2509 | port->wwpn); | ||
2510 | retval = ZFCP_ERP_FAILED; | ||
2511 | goto out; | ||
2512 | } /* else it's closed now, open it */ | ||
2513 | break; | ||
2514 | } | ||
2515 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) | ||
2516 | retval = ZFCP_ERP_EXIT; | ||
2517 | else | ||
2518 | retval = zfcp_erp_port_strategy_open(erp_action); | ||
2519 | |||
2520 | out: | ||
2521 | debug_text_event(adapter->erp_dbf, 3, "p_pst/ret"); | ||
2522 | debug_event(adapter->erp_dbf, 3, &port->wwpn, sizeof (wwn_t)); | ||
2523 | debug_event(adapter->erp_dbf, 3, &erp_action->action, sizeof (int)); | ||
2524 | debug_event(adapter->erp_dbf, 3, &retval, sizeof (int)); | ||
2525 | |||
2526 | return retval; | ||
2527 | } | ||
2528 | |||
2529 | /* | ||
2530 | * function: | ||
2531 | * | ||
2532 | * purpose: | ||
2533 | * | ||
2534 | * returns: | ||
2535 | */ | ||
2536 | static int | ||
2537 | zfcp_erp_port_strategy_open(struct zfcp_erp_action *erp_action) | ||
2538 | { | ||
2539 | int retval; | ||
2540 | |||
2541 | if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, | ||
2542 | &erp_action->port->status)) | ||
2543 | retval = zfcp_erp_port_strategy_open_nameserver(erp_action); | ||
2544 | else | ||
2545 | retval = zfcp_erp_port_strategy_open_common(erp_action); | ||
2546 | |||
2547 | return retval; | ||
2548 | } | ||
2549 | |||
2550 | /* | ||
2551 | * function: | ||
2552 | * | ||
2553 | * purpose: | ||
2554 | * | ||
2555 | * returns: | ||
2556 | * | ||
2557 | * FIXME(design): currently only prepared for fabric (nameserver!) | ||
2558 | */ | ||
2559 | static int | ||
2560 | zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action) | ||
2561 | { | ||
2562 | int retval = 0; | ||
2563 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
2564 | struct zfcp_port *port = erp_action->port; | ||
2565 | |||
2566 | switch (erp_action->step) { | ||
2567 | |||
2568 | case ZFCP_ERP_STEP_UNINITIALIZED: | ||
2569 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: | ||
2570 | case ZFCP_ERP_STEP_PORT_CLOSING: | ||
2571 | if (!(adapter->nameserver_port)) { | ||
2572 | retval = zfcp_nameserver_enqueue(adapter); | ||
2573 | if (retval != 0) { | ||
2574 | ZFCP_LOG_NORMAL("error: nameserver port " | ||
2575 | "unavailable for adapter %s\n", | ||
2576 | zfcp_get_busid_by_adapter(adapter)); | ||
2577 | retval = ZFCP_ERP_FAILED; | ||
2578 | break; | ||
2579 | } | ||
2580 | } | ||
2581 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, | ||
2582 | &adapter->nameserver_port->status)) { | ||
2583 | ZFCP_LOG_DEBUG("nameserver port is not open -> open " | ||
2584 | "nameserver port\n"); | ||
2585 | /* nameserver port may live again */ | ||
2586 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, | ||
2587 | &adapter->nameserver_port->status); | ||
2588 | if (zfcp_erp_port_reopen(adapter->nameserver_port, 0) | ||
2589 | >= 0) { | ||
2590 | erp_action->step = | ||
2591 | ZFCP_ERP_STEP_NAMESERVER_OPEN; | ||
2592 | retval = ZFCP_ERP_CONTINUES; | ||
2593 | } else | ||
2594 | retval = ZFCP_ERP_FAILED; | ||
2595 | break; | ||
2596 | } | ||
2597 | /* else nameserver port is already open, fall through */ | ||
2598 | case ZFCP_ERP_STEP_NAMESERVER_OPEN: | ||
2599 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, | ||
2600 | &adapter->nameserver_port->status)) { | ||
2601 | ZFCP_LOG_DEBUG("open failed for nameserver port\n"); | ||
2602 | retval = ZFCP_ERP_FAILED; | ||
2603 | } else { | ||
2604 | ZFCP_LOG_DEBUG("nameserver port is open -> " | ||
2605 | "nameserver look-up for port 0x%016Lx\n", | ||
2606 | port->wwpn); | ||
2607 | retval = zfcp_erp_port_strategy_open_common_lookup | ||
2608 | (erp_action); | ||
2609 | } | ||
2610 | break; | ||
2611 | |||
2612 | case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: | ||
2613 | if (!atomic_test_mask(ZFCP_STATUS_PORT_DID_DID, &port->status)) { | ||
2614 | if (atomic_test_mask | ||
2615 | (ZFCP_STATUS_PORT_INVALID_WWPN, &port->status)) { | ||
2616 | ZFCP_LOG_DEBUG("nameserver look-up failed " | ||
2617 | "for port 0x%016Lx " | ||
2618 | "(misconfigured WWPN?)\n", | ||
2619 | port->wwpn); | ||
2620 | zfcp_erp_port_failed(port); | ||
2621 | retval = ZFCP_ERP_EXIT; | ||
2622 | } else { | ||
2623 | ZFCP_LOG_DEBUG("nameserver look-up failed for " | ||
2624 | "port 0x%016Lx\n", port->wwpn); | ||
2625 | retval = ZFCP_ERP_FAILED; | ||
2626 | } | ||
2627 | } else { | ||
2628 | ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%08x -> " | ||
2629 | "trying open\n", port->wwpn, port->d_id); | ||
2630 | retval = zfcp_erp_port_strategy_open_port(erp_action); | ||
2631 | } | ||
2632 | break; | ||
2633 | |||
2634 | case ZFCP_ERP_STEP_PORT_OPENING: | ||
2635 | /* D_ID might have changed during open */ | ||
2636 | if (atomic_test_mask((ZFCP_STATUS_COMMON_OPEN | | ||
2637 | ZFCP_STATUS_PORT_DID_DID), | ||
2638 | &port->status)) { | ||
2639 | ZFCP_LOG_DEBUG("port 0x%016Lx is open\n", port->wwpn); | ||
2640 | retval = ZFCP_ERP_SUCCEEDED; | ||
2641 | } else { | ||
2642 | ZFCP_LOG_DEBUG("open failed for port 0x%016Lx\n", | ||
2643 | port->wwpn); | ||
2644 | retval = ZFCP_ERP_FAILED; | ||
2645 | } | ||
2646 | break; | ||
2647 | |||
2648 | default: | ||
2649 | ZFCP_LOG_NORMAL("bug: unknown erp step 0x%08x\n", | ||
2650 | erp_action->step); | ||
2651 | retval = ZFCP_ERP_FAILED; | ||
2652 | } | ||
2653 | |||
2654 | return retval; | ||
2655 | } | ||
2656 | |||
2657 | /* | ||
2658 | * function: | ||
2659 | * | ||
2660 | * purpose: | ||
2661 | * | ||
2662 | * returns: | ||
2663 | */ | ||
2664 | static int | ||
2665 | zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action) | ||
2666 | { | ||
2667 | int retval; | ||
2668 | struct zfcp_port *port = erp_action->port; | ||
2669 | |||
2670 | switch (erp_action->step) { | ||
2671 | |||
2672 | case ZFCP_ERP_STEP_UNINITIALIZED: | ||
2673 | case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: | ||
2674 | case ZFCP_ERP_STEP_PORT_CLOSING: | ||
2675 | ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%08x -> trying open\n", | ||
2676 | port->wwpn, port->d_id); | ||
2677 | retval = zfcp_erp_port_strategy_open_port(erp_action); | ||
2678 | break; | ||
2679 | |||
2680 | case ZFCP_ERP_STEP_PORT_OPENING: | ||
2681 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &port->status)) { | ||
2682 | ZFCP_LOG_DEBUG("WKA port is open\n"); | ||
2683 | retval = ZFCP_ERP_SUCCEEDED; | ||
2684 | } else { | ||
2685 | ZFCP_LOG_DEBUG("open failed for WKA port\n"); | ||
2686 | retval = ZFCP_ERP_FAILED; | ||
2687 | } | ||
2688 | /* this is needed anyway (dont care for retval of wakeup) */ | ||
2689 | ZFCP_LOG_DEBUG("continue other open port operations\n"); | ||
2690 | zfcp_erp_port_strategy_open_nameserver_wakeup(erp_action); | ||
2691 | break; | ||
2692 | |||
2693 | default: | ||
2694 | ZFCP_LOG_NORMAL("bug: unknown erp step 0x%08x\n", | ||
2695 | erp_action->step); | ||
2696 | retval = ZFCP_ERP_FAILED; | ||
2697 | } | ||
2698 | |||
2699 | return retval; | ||
2700 | } | ||
2701 | |||
2702 | /* | ||
2703 | * function: | ||
2704 | * | ||
2705 | * purpose: makes the erp thread continue with reopen (physical) port | ||
2706 | * actions which have been paused until the name server port | ||
2707 | * is opened (or failed) | ||
2708 | * | ||
2709 | * returns: 0 (a kind of void retval, its not used) | ||
2710 | */ | ||
2711 | static int | ||
2712 | zfcp_erp_port_strategy_open_nameserver_wakeup(struct zfcp_erp_action | ||
2713 | *ns_erp_action) | ||
2714 | { | ||
2715 | int retval = 0; | ||
2716 | unsigned long flags; | ||
2717 | struct zfcp_adapter *adapter = ns_erp_action->adapter; | ||
2718 | struct zfcp_erp_action *erp_action, *tmp; | ||
2719 | |||
2720 | read_lock_irqsave(&adapter->erp_lock, flags); | ||
2721 | list_for_each_entry_safe(erp_action, tmp, &adapter->erp_running_head, | ||
2722 | list) { | ||
2723 | debug_text_event(adapter->erp_dbf, 4, "p_pstnsw_n"); | ||
2724 | debug_event(adapter->erp_dbf, 4, &erp_action->port->wwpn, | ||
2725 | sizeof (wwn_t)); | ||
2726 | if (erp_action->step == ZFCP_ERP_STEP_NAMESERVER_OPEN) { | ||
2727 | debug_text_event(adapter->erp_dbf, 3, "p_pstnsw_w"); | ||
2728 | debug_event(adapter->erp_dbf, 3, | ||
2729 | &erp_action->port->wwpn, sizeof (wwn_t)); | ||
2730 | if (atomic_test_mask( | ||
2731 | ZFCP_STATUS_COMMON_ERP_FAILED, | ||
2732 | &adapter->nameserver_port->status)) | ||
2733 | zfcp_erp_port_failed(erp_action->port); | ||
2734 | zfcp_erp_action_ready(erp_action); | ||
2735 | } | ||
2736 | } | ||
2737 | read_unlock_irqrestore(&adapter->erp_lock, flags); | ||
2738 | |||
2739 | return retval; | ||
2740 | } | ||
2741 | |||
2742 | /* | ||
2743 | * function: | ||
2744 | * | ||
2745 | * purpose: | ||
2746 | * | ||
2747 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2748 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2749 | */ | ||
2750 | static int | ||
2751 | zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *erp_action) | ||
2752 | { | ||
2753 | int retval; | ||
2754 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
2755 | struct zfcp_port *port = erp_action->port; | ||
2756 | |||
2757 | zfcp_erp_timeout_init(erp_action); | ||
2758 | retval = zfcp_fsf_close_physical_port(erp_action); | ||
2759 | if (retval == -ENOMEM) { | ||
2760 | debug_text_event(adapter->erp_dbf, 5, "o_pfstc_nomem"); | ||
2761 | debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); | ||
2762 | retval = ZFCP_ERP_NOMEM; | ||
2763 | goto out; | ||
2764 | } | ||
2765 | erp_action->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING; | ||
2766 | if (retval != 0) { | ||
2767 | debug_text_event(adapter->erp_dbf, 5, "o_pfstc_cpf"); | ||
2768 | debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); | ||
2769 | /* could not send 'open', fail */ | ||
2770 | retval = ZFCP_ERP_FAILED; | ||
2771 | goto out; | ||
2772 | } | ||
2773 | debug_text_event(adapter->erp_dbf, 6, "o_pfstc_cpok"); | ||
2774 | debug_event(adapter->erp_dbf, 6, &port->wwpn, sizeof (wwn_t)); | ||
2775 | retval = ZFCP_ERP_CONTINUES; | ||
2776 | out: | ||
2777 | return retval; | ||
2778 | } | ||
2779 | |||
2780 | /* | ||
2781 | * function: | ||
2782 | * | ||
2783 | * purpose: | ||
2784 | * | ||
2785 | * returns: | ||
2786 | */ | ||
2787 | static int | ||
2788 | zfcp_erp_port_strategy_clearstati(struct zfcp_port *port) | ||
2789 | { | ||
2790 | int retval = 0; | ||
2791 | struct zfcp_adapter *adapter = port->adapter; | ||
2792 | |||
2793 | debug_text_event(adapter->erp_dbf, 5, "p_pstclst"); | ||
2794 | debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); | ||
2795 | |||
2796 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | | ||
2797 | ZFCP_STATUS_COMMON_CLOSING | | ||
2798 | ZFCP_STATUS_COMMON_ACCESS_DENIED | | ||
2799 | ZFCP_STATUS_PORT_DID_DID | | ||
2800 | ZFCP_STATUS_PORT_PHYS_CLOSING | | ||
2801 | ZFCP_STATUS_PORT_INVALID_WWPN, | ||
2802 | &port->status); | ||
2803 | return retval; | ||
2804 | } | ||
2805 | |||
2806 | /* | ||
2807 | * function: | ||
2808 | * | ||
2809 | * purpose: | ||
2810 | * | ||
2811 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2812 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2813 | */ | ||
2814 | static int | ||
2815 | zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action) | ||
2816 | { | ||
2817 | int retval; | ||
2818 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
2819 | struct zfcp_port *port = erp_action->port; | ||
2820 | |||
2821 | zfcp_erp_timeout_init(erp_action); | ||
2822 | retval = zfcp_fsf_close_port(erp_action); | ||
2823 | if (retval == -ENOMEM) { | ||
2824 | debug_text_event(adapter->erp_dbf, 5, "p_pstc_nomem"); | ||
2825 | debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); | ||
2826 | retval = ZFCP_ERP_NOMEM; | ||
2827 | goto out; | ||
2828 | } | ||
2829 | erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING; | ||
2830 | if (retval != 0) { | ||
2831 | debug_text_event(adapter->erp_dbf, 5, "p_pstc_cpf"); | ||
2832 | debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); | ||
2833 | /* could not send 'close', fail */ | ||
2834 | retval = ZFCP_ERP_FAILED; | ||
2835 | goto out; | ||
2836 | } | ||
2837 | debug_text_event(adapter->erp_dbf, 6, "p_pstc_cpok"); | ||
2838 | debug_event(adapter->erp_dbf, 6, &port->wwpn, sizeof (wwn_t)); | ||
2839 | retval = ZFCP_ERP_CONTINUES; | ||
2840 | out: | ||
2841 | return retval; | ||
2842 | } | ||
2843 | |||
2844 | /* | ||
2845 | * function: | ||
2846 | * | ||
2847 | * purpose: | ||
2848 | * | ||
2849 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2850 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2851 | */ | ||
2852 | static int | ||
2853 | zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action) | ||
2854 | { | ||
2855 | int retval; | ||
2856 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
2857 | struct zfcp_port *port = erp_action->port; | ||
2858 | |||
2859 | zfcp_erp_timeout_init(erp_action); | ||
2860 | retval = zfcp_fsf_open_port(erp_action); | ||
2861 | if (retval == -ENOMEM) { | ||
2862 | debug_text_event(adapter->erp_dbf, 5, "p_psto_nomem"); | ||
2863 | debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); | ||
2864 | retval = ZFCP_ERP_NOMEM; | ||
2865 | goto out; | ||
2866 | } | ||
2867 | erp_action->step = ZFCP_ERP_STEP_PORT_OPENING; | ||
2868 | if (retval != 0) { | ||
2869 | debug_text_event(adapter->erp_dbf, 5, "p_psto_opf"); | ||
2870 | debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); | ||
2871 | /* could not send 'open', fail */ | ||
2872 | retval = ZFCP_ERP_FAILED; | ||
2873 | goto out; | ||
2874 | } | ||
2875 | debug_text_event(adapter->erp_dbf, 6, "p_psto_opok"); | ||
2876 | debug_event(adapter->erp_dbf, 6, &port->wwpn, sizeof (wwn_t)); | ||
2877 | retval = ZFCP_ERP_CONTINUES; | ||
2878 | out: | ||
2879 | return retval; | ||
2880 | } | ||
2881 | |||
2882 | /* | ||
2883 | * function: | ||
2884 | * | ||
2885 | * purpose: | ||
2886 | * | ||
2887 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2888 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2889 | */ | ||
2890 | static int | ||
2891 | zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *erp_action) | ||
2892 | { | ||
2893 | int retval; | ||
2894 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
2895 | struct zfcp_port *port = erp_action->port; | ||
2896 | |||
2897 | zfcp_erp_timeout_init(erp_action); | ||
2898 | retval = zfcp_ns_gid_pn_request(erp_action); | ||
2899 | if (retval == -ENOMEM) { | ||
2900 | debug_text_event(adapter->erp_dbf, 5, "p_pstn_nomem"); | ||
2901 | debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); | ||
2902 | retval = ZFCP_ERP_NOMEM; | ||
2903 | goto out; | ||
2904 | } | ||
2905 | erp_action->step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP; | ||
2906 | if (retval != 0) { | ||
2907 | debug_text_event(adapter->erp_dbf, 5, "p_pstn_ref"); | ||
2908 | debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); | ||
2909 | /* could not send nameserver request, fail */ | ||
2910 | retval = ZFCP_ERP_FAILED; | ||
2911 | goto out; | ||
2912 | } | ||
2913 | debug_text_event(adapter->erp_dbf, 6, "p_pstn_reok"); | ||
2914 | debug_event(adapter->erp_dbf, 6, &port->wwpn, sizeof (wwn_t)); | ||
2915 | retval = ZFCP_ERP_CONTINUES; | ||
2916 | out: | ||
2917 | return retval; | ||
2918 | } | ||
2919 | |||
2920 | /* | ||
2921 | * function: | ||
2922 | * | ||
2923 | * purpose: this routine executes the 'Reopen Unit' action | ||
2924 | * currently no retries | ||
2925 | * | ||
2926 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
2927 | * ZFCP_ERP_SUCCEEDED - action finished successfully | ||
2928 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
2929 | */ | ||
2930 | static int | ||
2931 | zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action) | ||
2932 | { | ||
2933 | int retval = ZFCP_ERP_FAILED; | ||
2934 | struct zfcp_unit *unit = erp_action->unit; | ||
2935 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
2936 | |||
2937 | switch (erp_action->step) { | ||
2938 | |||
2939 | /* | ||
2940 | * FIXME: | ||
2941 | * the ULP spec. begs for waiting for oustanding commands | ||
2942 | */ | ||
2943 | case ZFCP_ERP_STEP_UNINITIALIZED: | ||
2944 | zfcp_erp_unit_strategy_clearstati(unit); | ||
2945 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) { | ||
2946 | ZFCP_LOG_DEBUG("unit 0x%016Lx is open -> " | ||
2947 | "trying close\n", unit->fcp_lun); | ||
2948 | retval = zfcp_erp_unit_strategy_close(erp_action); | ||
2949 | break; | ||
2950 | } | ||
2951 | /* else it's already closed, fall through */ | ||
2952 | case ZFCP_ERP_STEP_UNIT_CLOSING: | ||
2953 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) { | ||
2954 | ZFCP_LOG_DEBUG("close failed for unit 0x%016Lx\n", | ||
2955 | unit->fcp_lun); | ||
2956 | retval = ZFCP_ERP_FAILED; | ||
2957 | } else { | ||
2958 | if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY) | ||
2959 | retval = ZFCP_ERP_EXIT; | ||
2960 | else { | ||
2961 | ZFCP_LOG_DEBUG("unit 0x%016Lx is not open -> " | ||
2962 | "trying open\n", unit->fcp_lun); | ||
2963 | retval = | ||
2964 | zfcp_erp_unit_strategy_open(erp_action); | ||
2965 | } | ||
2966 | } | ||
2967 | break; | ||
2968 | |||
2969 | case ZFCP_ERP_STEP_UNIT_OPENING: | ||
2970 | if (atomic_test_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status)) { | ||
2971 | ZFCP_LOG_DEBUG("unit 0x%016Lx is open\n", | ||
2972 | unit->fcp_lun); | ||
2973 | retval = ZFCP_ERP_SUCCEEDED; | ||
2974 | } else { | ||
2975 | ZFCP_LOG_DEBUG("open failed for unit 0x%016Lx\n", | ||
2976 | unit->fcp_lun); | ||
2977 | retval = ZFCP_ERP_FAILED; | ||
2978 | } | ||
2979 | break; | ||
2980 | } | ||
2981 | |||
2982 | debug_text_event(adapter->erp_dbf, 3, "u_ust/ret"); | ||
2983 | debug_event(adapter->erp_dbf, 3, &unit->fcp_lun, sizeof (fcp_lun_t)); | ||
2984 | debug_event(adapter->erp_dbf, 3, &erp_action->action, sizeof (int)); | ||
2985 | debug_event(adapter->erp_dbf, 3, &retval, sizeof (int)); | ||
2986 | return retval; | ||
2987 | } | ||
2988 | |||
2989 | /* | ||
2990 | * function: | ||
2991 | * | ||
2992 | * purpose: | ||
2993 | * | ||
2994 | * returns: | ||
2995 | */ | ||
2996 | static int | ||
2997 | zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit) | ||
2998 | { | ||
2999 | int retval = 0; | ||
3000 | struct zfcp_adapter *adapter = unit->port->adapter; | ||
3001 | |||
3002 | debug_text_event(adapter->erp_dbf, 5, "u_ustclst"); | ||
3003 | debug_event(adapter->erp_dbf, 5, &unit->fcp_lun, sizeof (fcp_lun_t)); | ||
3004 | |||
3005 | atomic_clear_mask(ZFCP_STATUS_COMMON_OPENING | | ||
3006 | ZFCP_STATUS_COMMON_CLOSING | | ||
3007 | ZFCP_STATUS_COMMON_ACCESS_DENIED | | ||
3008 | ZFCP_STATUS_UNIT_SHARED | | ||
3009 | ZFCP_STATUS_UNIT_READONLY, | ||
3010 | &unit->status); | ||
3011 | |||
3012 | return retval; | ||
3013 | } | ||
3014 | |||
3015 | /* | ||
3016 | * function: | ||
3017 | * | ||
3018 | * purpose: | ||
3019 | * | ||
3020 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
3021 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
3022 | */ | ||
3023 | static int | ||
3024 | zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action) | ||
3025 | { | ||
3026 | int retval; | ||
3027 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
3028 | struct zfcp_unit *unit = erp_action->unit; | ||
3029 | |||
3030 | zfcp_erp_timeout_init(erp_action); | ||
3031 | retval = zfcp_fsf_close_unit(erp_action); | ||
3032 | if (retval == -ENOMEM) { | ||
3033 | debug_text_event(adapter->erp_dbf, 5, "u_ustc_nomem"); | ||
3034 | debug_event(adapter->erp_dbf, 5, &unit->fcp_lun, | ||
3035 | sizeof (fcp_lun_t)); | ||
3036 | retval = ZFCP_ERP_NOMEM; | ||
3037 | goto out; | ||
3038 | } | ||
3039 | erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING; | ||
3040 | if (retval != 0) { | ||
3041 | debug_text_event(adapter->erp_dbf, 5, "u_ustc_cuf"); | ||
3042 | debug_event(adapter->erp_dbf, 5, &unit->fcp_lun, | ||
3043 | sizeof (fcp_lun_t)); | ||
3044 | /* could not send 'close', fail */ | ||
3045 | retval = ZFCP_ERP_FAILED; | ||
3046 | goto out; | ||
3047 | } | ||
3048 | debug_text_event(adapter->erp_dbf, 6, "u_ustc_cuok"); | ||
3049 | debug_event(adapter->erp_dbf, 6, &unit->fcp_lun, sizeof (fcp_lun_t)); | ||
3050 | retval = ZFCP_ERP_CONTINUES; | ||
3051 | |||
3052 | out: | ||
3053 | return retval; | ||
3054 | } | ||
3055 | |||
3056 | /* | ||
3057 | * function: | ||
3058 | * | ||
3059 | * purpose: | ||
3060 | * | ||
3061 | * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) | ||
3062 | * ZFCP_ERP_FAILED - action finished unsuccessfully | ||
3063 | */ | ||
3064 | static int | ||
3065 | zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action) | ||
3066 | { | ||
3067 | int retval; | ||
3068 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
3069 | struct zfcp_unit *unit = erp_action->unit; | ||
3070 | |||
3071 | zfcp_erp_timeout_init(erp_action); | ||
3072 | retval = zfcp_fsf_open_unit(erp_action); | ||
3073 | if (retval == -ENOMEM) { | ||
3074 | debug_text_event(adapter->erp_dbf, 5, "u_usto_nomem"); | ||
3075 | debug_event(adapter->erp_dbf, 5, &unit->fcp_lun, | ||
3076 | sizeof (fcp_lun_t)); | ||
3077 | retval = ZFCP_ERP_NOMEM; | ||
3078 | goto out; | ||
3079 | } | ||
3080 | erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING; | ||
3081 | if (retval != 0) { | ||
3082 | debug_text_event(adapter->erp_dbf, 5, "u_usto_ouf"); | ||
3083 | debug_event(adapter->erp_dbf, 5, &unit->fcp_lun, | ||
3084 | sizeof (fcp_lun_t)); | ||
3085 | /* could not send 'open', fail */ | ||
3086 | retval = ZFCP_ERP_FAILED; | ||
3087 | goto out; | ||
3088 | } | ||
3089 | debug_text_event(adapter->erp_dbf, 6, "u_usto_ouok"); | ||
3090 | debug_event(adapter->erp_dbf, 6, &unit->fcp_lun, sizeof (fcp_lun_t)); | ||
3091 | retval = ZFCP_ERP_CONTINUES; | ||
3092 | out: | ||
3093 | return retval; | ||
3094 | } | ||
3095 | |||
3096 | /* | ||
3097 | * function: | ||
3098 | * | ||
3099 | * purpose: | ||
3100 | * | ||
3101 | * returns: | ||
3102 | */ | ||
3103 | static inline void | ||
3104 | zfcp_erp_timeout_init(struct zfcp_erp_action *erp_action) | ||
3105 | { | ||
3106 | init_timer(&erp_action->timer); | ||
3107 | erp_action->timer.function = zfcp_erp_timeout_handler; | ||
3108 | erp_action->timer.data = (unsigned long) erp_action; | ||
3109 | /* jiffies will be added in zfcp_fsf_req_send */ | ||
3110 | erp_action->timer.expires = ZFCP_ERP_FSFREQ_TIMEOUT; | ||
3111 | } | ||
3112 | |||
3113 | /* | ||
3114 | * function: | ||
3115 | * | ||
3116 | * purpose: enqueue the specified error recovery action, if needed | ||
3117 | * | ||
3118 | * returns: | ||
3119 | */ | ||
3120 | static int | ||
3121 | zfcp_erp_action_enqueue(int action, | ||
3122 | struct zfcp_adapter *adapter, | ||
3123 | struct zfcp_port *port, struct zfcp_unit *unit) | ||
3124 | { | ||
3125 | int retval = 1; | ||
3126 | struct zfcp_erp_action *erp_action = NULL; | ||
3127 | int stronger_action = 0; | ||
3128 | u32 status = 0; | ||
3129 | |||
3130 | /* | ||
3131 | * We need some rules here which check whether we really need | ||
3132 | * this action or whether we should just drop it. | ||
3133 | * E.g. if there is a unfinished 'Reopen Port' request then we drop a | ||
3134 | * 'Reopen Unit' request for an associated unit since we can't | ||
3135 | * satisfy this request now. A 'Reopen Port' action will trigger | ||
3136 | * 'Reopen Unit' actions when it completes. | ||
3137 | * Thus, there are only actions in the queue which can immediately be | ||
3138 | * executed. This makes the processing of the action queue more | ||
3139 | * efficient. | ||
3140 | */ | ||
3141 | |||
3142 | if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, | ||
3143 | &adapter->status)) | ||
3144 | return -EIO; | ||
3145 | |||
3146 | debug_event(adapter->erp_dbf, 4, &action, sizeof (int)); | ||
3147 | /* check whether we really need this */ | ||
3148 | switch (action) { | ||
3149 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
3150 | if (atomic_test_mask | ||
3151 | (ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status)) { | ||
3152 | debug_text_event(adapter->erp_dbf, 4, "u_actenq_drp"); | ||
3153 | debug_event(adapter->erp_dbf, 4, &port->wwpn, | ||
3154 | sizeof (wwn_t)); | ||
3155 | debug_event(adapter->erp_dbf, 4, &unit->fcp_lun, | ||
3156 | sizeof (fcp_lun_t)); | ||
3157 | goto out; | ||
3158 | } | ||
3159 | if (!atomic_test_mask | ||
3160 | (ZFCP_STATUS_COMMON_RUNNING, &port->status) || | ||
3161 | atomic_test_mask | ||
3162 | (ZFCP_STATUS_COMMON_ERP_FAILED, &port->status)) { | ||
3163 | goto out; | ||
3164 | } | ||
3165 | if (!atomic_test_mask | ||
3166 | (ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) { | ||
3167 | stronger_action = ZFCP_ERP_ACTION_REOPEN_PORT; | ||
3168 | unit = NULL; | ||
3169 | } | ||
3170 | /* fall through !!! */ | ||
3171 | |||
3172 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
3173 | if (atomic_test_mask | ||
3174 | (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)) { | ||
3175 | debug_text_event(adapter->erp_dbf, 4, "p_actenq_drp"); | ||
3176 | debug_event(adapter->erp_dbf, 4, &port->wwpn, | ||
3177 | sizeof (wwn_t)); | ||
3178 | goto out; | ||
3179 | } | ||
3180 | /* fall through !!! */ | ||
3181 | |||
3182 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
3183 | if (atomic_test_mask | ||
3184 | (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status) | ||
3185 | && port->erp_action.action == | ||
3186 | ZFCP_ERP_ACTION_REOPEN_PORT_FORCED) { | ||
3187 | debug_text_event(adapter->erp_dbf, 4, "pf_actenq_drp"); | ||
3188 | debug_event(adapter->erp_dbf, 4, &port->wwpn, | ||
3189 | sizeof (wwn_t)); | ||
3190 | goto out; | ||
3191 | } | ||
3192 | if (!atomic_test_mask | ||
3193 | (ZFCP_STATUS_COMMON_RUNNING, &adapter->status) || | ||
3194 | atomic_test_mask | ||
3195 | (ZFCP_STATUS_COMMON_ERP_FAILED, &adapter->status)) { | ||
3196 | goto out; | ||
3197 | } | ||
3198 | if (!atomic_test_mask | ||
3199 | (ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) { | ||
3200 | stronger_action = ZFCP_ERP_ACTION_REOPEN_ADAPTER; | ||
3201 | port = NULL; | ||
3202 | } | ||
3203 | /* fall through !!! */ | ||
3204 | |||
3205 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
3206 | if (atomic_test_mask | ||
3207 | (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)) { | ||
3208 | debug_text_event(adapter->erp_dbf, 4, "a_actenq_drp"); | ||
3209 | goto out; | ||
3210 | } | ||
3211 | break; | ||
3212 | |||
3213 | default: | ||
3214 | debug_text_exception(adapter->erp_dbf, 1, "a_actenq_bug"); | ||
3215 | debug_event(adapter->erp_dbf, 1, &action, sizeof (int)); | ||
3216 | ZFCP_LOG_NORMAL("bug: unknown erp action requested " | ||
3217 | "on adapter %s (action=%d)\n", | ||
3218 | zfcp_get_busid_by_adapter(adapter), action); | ||
3219 | goto out; | ||
3220 | } | ||
3221 | |||
3222 | /* check whether we need something stronger first */ | ||
3223 | if (stronger_action) { | ||
3224 | debug_text_event(adapter->erp_dbf, 4, "a_actenq_str"); | ||
3225 | debug_event(adapter->erp_dbf, 4, &stronger_action, | ||
3226 | sizeof (int)); | ||
3227 | ZFCP_LOG_DEBUG("stronger erp action %d needed before " | ||
3228 | "erp action %d on adapter %s\n", | ||
3229 | stronger_action, action, | ||
3230 | zfcp_get_busid_by_adapter(adapter)); | ||
3231 | action = stronger_action; | ||
3232 | } | ||
3233 | |||
3234 | /* mark adapter to have some error recovery pending */ | ||
3235 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); | ||
3236 | |||
3237 | /* setup error recovery action */ | ||
3238 | switch (action) { | ||
3239 | |||
3240 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
3241 | zfcp_unit_get(unit); | ||
3242 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); | ||
3243 | erp_action = &unit->erp_action; | ||
3244 | if (!atomic_test_mask | ||
3245 | (ZFCP_STATUS_COMMON_RUNNING, &unit->status)) | ||
3246 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | ||
3247 | break; | ||
3248 | |||
3249 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
3250 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
3251 | zfcp_port_get(port); | ||
3252 | zfcp_erp_action_dismiss_port(port); | ||
3253 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); | ||
3254 | erp_action = &port->erp_action; | ||
3255 | if (!atomic_test_mask | ||
3256 | (ZFCP_STATUS_COMMON_RUNNING, &port->status)) | ||
3257 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | ||
3258 | break; | ||
3259 | |||
3260 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
3261 | zfcp_adapter_get(adapter); | ||
3262 | zfcp_erp_action_dismiss_adapter(adapter); | ||
3263 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); | ||
3264 | erp_action = &adapter->erp_action; | ||
3265 | if (!atomic_test_mask | ||
3266 | (ZFCP_STATUS_COMMON_RUNNING, &adapter->status)) | ||
3267 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | ||
3268 | break; | ||
3269 | } | ||
3270 | |||
3271 | debug_text_event(adapter->erp_dbf, 4, "a_actenq"); | ||
3272 | |||
3273 | memset(erp_action, 0, sizeof (struct zfcp_erp_action)); | ||
3274 | erp_action->adapter = adapter; | ||
3275 | erp_action->port = port; | ||
3276 | erp_action->unit = unit; | ||
3277 | erp_action->action = action; | ||
3278 | erp_action->status = status; | ||
3279 | |||
3280 | ++adapter->erp_total_count; | ||
3281 | |||
3282 | /* finally put it into 'ready' queue and kick erp thread */ | ||
3283 | list_add(&erp_action->list, &adapter->erp_ready_head); | ||
3284 | up(&adapter->erp_ready_sem); | ||
3285 | retval = 0; | ||
3286 | out: | ||
3287 | return retval; | ||
3288 | } | ||
3289 | |||
3290 | /* | ||
3291 | * function: | ||
3292 | * | ||
3293 | * purpose: | ||
3294 | * | ||
3295 | * returns: | ||
3296 | */ | ||
3297 | static int | ||
3298 | zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) | ||
3299 | { | ||
3300 | int retval = 0; | ||
3301 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
3302 | |||
3303 | --adapter->erp_total_count; | ||
3304 | if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { | ||
3305 | --adapter->erp_low_mem_count; | ||
3306 | erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; | ||
3307 | } | ||
3308 | |||
3309 | debug_text_event(adapter->erp_dbf, 4, "a_actdeq"); | ||
3310 | debug_event(adapter->erp_dbf, 4, &erp_action->action, sizeof (int)); | ||
3311 | list_del(&erp_action->list); | ||
3312 | switch (erp_action->action) { | ||
3313 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
3314 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | ||
3315 | &erp_action->unit->status); | ||
3316 | break; | ||
3317 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
3318 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
3319 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | ||
3320 | &erp_action->port->status); | ||
3321 | break; | ||
3322 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
3323 | atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, | ||
3324 | &erp_action->adapter->status); | ||
3325 | break; | ||
3326 | default: | ||
3327 | /* bug */ | ||
3328 | break; | ||
3329 | } | ||
3330 | return retval; | ||
3331 | } | ||
3332 | |||
3333 | /** | ||
3334 | * zfcp_erp_action_cleanup | ||
3335 | * | ||
3336 | * Register unit with scsi stack if appropiate and fix reference counts. | ||
3337 | * Note: Temporary units are not registered with scsi stack. | ||
3338 | */ | ||
3339 | static void | ||
3340 | zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter, | ||
3341 | struct zfcp_port *port, struct zfcp_unit *unit, | ||
3342 | int result) | ||
3343 | { | ||
3344 | switch (action) { | ||
3345 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | ||
3346 | if ((result == ZFCP_ERP_SUCCEEDED) | ||
3347 | && (!atomic_test_mask(ZFCP_STATUS_UNIT_TEMPORARY, | ||
3348 | &unit->status)) | ||
3349 | && (!unit->device)) | ||
3350 | scsi_add_device(unit->port->adapter->scsi_host, 0, | ||
3351 | unit->port->scsi_id, unit->scsi_lun); | ||
3352 | zfcp_unit_put(unit); | ||
3353 | break; | ||
3354 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | ||
3355 | case ZFCP_ERP_ACTION_REOPEN_PORT: | ||
3356 | zfcp_port_put(port); | ||
3357 | break; | ||
3358 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | ||
3359 | zfcp_adapter_put(adapter); | ||
3360 | break; | ||
3361 | default: | ||
3362 | break; | ||
3363 | } | ||
3364 | } | ||
3365 | |||
3366 | |||
3367 | /* | ||
3368 | * function: | ||
3369 | * | ||
3370 | * purpose: | ||
3371 | * | ||
3372 | * returns: FIXME | ||
3373 | */ | ||
3374 | static int | ||
3375 | zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) | ||
3376 | { | ||
3377 | int retval = 0; | ||
3378 | struct zfcp_port *port; | ||
3379 | |||
3380 | debug_text_event(adapter->erp_dbf, 5, "a_actab"); | ||
3381 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)) | ||
3382 | zfcp_erp_action_dismiss(&adapter->erp_action); | ||
3383 | else | ||
3384 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
3385 | zfcp_erp_action_dismiss_port(port); | ||
3386 | |||
3387 | return retval; | ||
3388 | } | ||
3389 | |||
3390 | /* | ||
3391 | * function: | ||
3392 | * | ||
3393 | * purpose: | ||
3394 | * | ||
3395 | * returns: FIXME | ||
3396 | */ | ||
3397 | static int | ||
3398 | zfcp_erp_action_dismiss_port(struct zfcp_port *port) | ||
3399 | { | ||
3400 | int retval = 0; | ||
3401 | struct zfcp_unit *unit; | ||
3402 | struct zfcp_adapter *adapter = port->adapter; | ||
3403 | |||
3404 | debug_text_event(adapter->erp_dbf, 5, "p_actab"); | ||
3405 | debug_event(adapter->erp_dbf, 5, &port->wwpn, sizeof (wwn_t)); | ||
3406 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)) | ||
3407 | zfcp_erp_action_dismiss(&port->erp_action); | ||
3408 | else | ||
3409 | list_for_each_entry(unit, &port->unit_list_head, list) | ||
3410 | zfcp_erp_action_dismiss_unit(unit); | ||
3411 | |||
3412 | return retval; | ||
3413 | } | ||
3414 | |||
3415 | /* | ||
3416 | * function: | ||
3417 | * | ||
3418 | * purpose: | ||
3419 | * | ||
3420 | * returns: FIXME | ||
3421 | */ | ||
3422 | static int | ||
3423 | zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit) | ||
3424 | { | ||
3425 | int retval = 0; | ||
3426 | struct zfcp_adapter *adapter = unit->port->adapter; | ||
3427 | |||
3428 | debug_text_event(adapter->erp_dbf, 5, "u_actab"); | ||
3429 | debug_event(adapter->erp_dbf, 5, &unit->fcp_lun, sizeof (fcp_lun_t)); | ||
3430 | if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status)) | ||
3431 | zfcp_erp_action_dismiss(&unit->erp_action); | ||
3432 | |||
3433 | return retval; | ||
3434 | } | ||
3435 | |||
3436 | /* | ||
3437 | * function: | ||
3438 | * | ||
3439 | * purpose: moves erp_action to 'erp running list' | ||
3440 | * | ||
3441 | * returns: | ||
3442 | */ | ||
3443 | static inline void | ||
3444 | zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) | ||
3445 | { | ||
3446 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
3447 | |||
3448 | debug_text_event(adapter->erp_dbf, 6, "a_toru"); | ||
3449 | debug_event(adapter->erp_dbf, 6, &erp_action->action, sizeof (int)); | ||
3450 | list_move(&erp_action->list, &erp_action->adapter->erp_running_head); | ||
3451 | } | ||
3452 | |||
3453 | /* | ||
3454 | * function: | ||
3455 | * | ||
3456 | * purpose: moves erp_action to 'erp ready list' | ||
3457 | * | ||
3458 | * returns: | ||
3459 | */ | ||
3460 | static inline void | ||
3461 | zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action) | ||
3462 | { | ||
3463 | struct zfcp_adapter *adapter = erp_action->adapter; | ||
3464 | |||
3465 | debug_text_event(adapter->erp_dbf, 6, "a_tore"); | ||
3466 | debug_event(adapter->erp_dbf, 6, &erp_action->action, sizeof (int)); | ||
3467 | list_move(&erp_action->list, &erp_action->adapter->erp_ready_head); | ||
3468 | } | ||
3469 | |||
3470 | /* | ||
3471 | * function: zfcp_erp_port_access_denied | ||
3472 | * | ||
3473 | * purpose: | ||
3474 | */ | ||
3475 | void | ||
3476 | zfcp_erp_port_access_denied(struct zfcp_port *port) | ||
3477 | { | ||
3478 | struct zfcp_adapter *adapter = port->adapter; | ||
3479 | unsigned long flags; | ||
3480 | |||
3481 | debug_text_event(adapter->erp_dbf, 3, "p_access_block"); | ||
3482 | debug_event(adapter->erp_dbf, 3, &port->wwpn, sizeof(wwn_t)); | ||
3483 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
3484 | zfcp_erp_modify_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED | | ||
3485 | ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); | ||
3486 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
3487 | } | ||
3488 | |||
3489 | /* | ||
3490 | * function: zfcp_erp_unit_access_denied | ||
3491 | * | ||
3492 | * purpose: | ||
3493 | */ | ||
3494 | void | ||
3495 | zfcp_erp_unit_access_denied(struct zfcp_unit *unit) | ||
3496 | { | ||
3497 | struct zfcp_adapter *adapter = unit->port->adapter; | ||
3498 | |||
3499 | debug_text_event(adapter->erp_dbf, 3, "u_access_block"); | ||
3500 | debug_event(adapter->erp_dbf, 3, &unit->fcp_lun, sizeof(fcp_lun_t)); | ||
3501 | zfcp_erp_modify_unit_status(unit, ZFCP_STATUS_COMMON_ERP_FAILED | | ||
3502 | ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); | ||
3503 | } | ||
3504 | |||
3505 | /* | ||
3506 | * function: zfcp_erp_adapter_access_changed | ||
3507 | * | ||
3508 | * purpose: | ||
3509 | */ | ||
3510 | void | ||
3511 | zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter) | ||
3512 | { | ||
3513 | struct zfcp_port *port; | ||
3514 | unsigned long flags; | ||
3515 | |||
3516 | debug_text_event(adapter->erp_dbf, 3, "a_access_unblock"); | ||
3517 | debug_event(adapter->erp_dbf, 3, &adapter->name, 8); | ||
3518 | |||
3519 | zfcp_erp_port_access_changed(adapter->nameserver_port); | ||
3520 | read_lock_irqsave(&zfcp_data.config_lock, flags); | ||
3521 | list_for_each_entry(port, &adapter->port_list_head, list) | ||
3522 | if (port != adapter->nameserver_port) | ||
3523 | zfcp_erp_port_access_changed(port); | ||
3524 | read_unlock_irqrestore(&zfcp_data.config_lock, flags); | ||
3525 | } | ||
3526 | |||
3527 | /* | ||
3528 | * function: zfcp_erp_port_access_changed | ||
3529 | * | ||
3530 | * purpose: | ||
3531 | */ | ||
3532 | void | ||
3533 | zfcp_erp_port_access_changed(struct zfcp_port *port) | ||
3534 | { | ||
3535 | struct zfcp_adapter *adapter = port->adapter; | ||
3536 | struct zfcp_unit *unit; | ||
3537 | |||
3538 | debug_text_event(adapter->erp_dbf, 3, "p_access_unblock"); | ||
3539 | debug_event(adapter->erp_dbf, 3, &port->wwpn, sizeof(wwn_t)); | ||
3540 | |||
3541 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, | ||
3542 | &port->status)) { | ||
3543 | if (!atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) | ||
3544 | list_for_each_entry(unit, &port->unit_list_head, list) | ||
3545 | zfcp_erp_unit_access_changed(unit); | ||
3546 | return; | ||
3547 | } | ||
3548 | |||
3549 | ZFCP_LOG_NORMAL("reopen of port 0x%016Lx on adapter %s " | ||
3550 | "(due to ACT update)\n", | ||
3551 | port->wwpn, zfcp_get_busid_by_adapter(adapter)); | ||
3552 | if (zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED) != 0) | ||
3553 | ZFCP_LOG_NORMAL("failed reopen of port" | ||
3554 | "(adapter %s, wwpn=0x%016Lx)\n", | ||
3555 | zfcp_get_busid_by_adapter(adapter), port->wwpn); | ||
3556 | } | ||
3557 | |||
3558 | /* | ||
3559 | * function: zfcp_erp_unit_access_changed | ||
3560 | * | ||
3561 | * purpose: | ||
3562 | */ | ||
3563 | void | ||
3564 | zfcp_erp_unit_access_changed(struct zfcp_unit *unit) | ||
3565 | { | ||
3566 | struct zfcp_adapter *adapter = unit->port->adapter; | ||
3567 | |||
3568 | debug_text_event(adapter->erp_dbf, 3, "u_access_unblock"); | ||
3569 | debug_event(adapter->erp_dbf, 3, &unit->fcp_lun, sizeof(fcp_lun_t)); | ||
3570 | |||
3571 | if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &unit->status)) | ||
3572 | return; | ||
3573 | |||
3574 | ZFCP_LOG_NORMAL("reopen of unit 0x%016Lx on port 0x%016Lx " | ||
3575 | " on adapter %s (due to ACT update)\n", | ||
3576 | unit->fcp_lun, unit->port->wwpn, | ||
3577 | zfcp_get_busid_by_adapter(adapter)); | ||
3578 | if (zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED) != 0) | ||
3579 | ZFCP_LOG_NORMAL("failed reopen of unit (adapter %s, " | ||
3580 | "wwpn=0x%016Lx, fcp_lun=0x%016Lx)\n", | ||
3581 | zfcp_get_busid_by_adapter(adapter), | ||
3582 | unit->port->wwpn, unit->fcp_lun); | ||
3583 | } | ||
3584 | |||
3585 | #undef ZFCP_LOG_AREA | ||