blob: d40d5b0f263ff90fd2c77a10922e18048899267a [file] [log] [blame]
Swen Schillig41fa2ad2007-09-07 09:15:31 +02001/*
Christof Schmitt553448f2008-06-10 18:20:58 +02002 * zfcp device driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Christof Schmitt553448f2008-06-10 18:20:58 +02004 * Error Recovery Procedures (ERP).
Swen Schillig41fa2ad2007-09-07 09:15:31 +02005 *
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01006 * Copyright IBM Corporation 2002, 2009
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8
Christof Schmittecf39d42008-12-25 13:39:53 +01009#define KMSG_COMPONENT "zfcp"
10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11
Christof Schmitt347c6a92009-08-18 15:43:25 +020012#include <linux/kthread.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include "zfcp_ext.h"
14
Christof Schmitt287ac012008-07-02 10:56:40 +020015#define ZFCP_MAX_ERPS 3
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
Christof Schmitt287ac012008-07-02 10:56:40 +020017enum zfcp_erp_act_flags {
18 ZFCP_STATUS_ERP_TIMEDOUT = 0x10000000,
19 ZFCP_STATUS_ERP_CLOSE_ONLY = 0x01000000,
20 ZFCP_STATUS_ERP_DISMISSING = 0x00100000,
21 ZFCP_STATUS_ERP_DISMISSED = 0x00200000,
22 ZFCP_STATUS_ERP_LOWMEM = 0x00400000,
23};
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Christof Schmitt287ac012008-07-02 10:56:40 +020025enum zfcp_erp_steps {
26 ZFCP_ERP_STEP_UNINITIALIZED = 0x0000,
27 ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001,
28 ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010,
29 ZFCP_ERP_STEP_PORT_CLOSING = 0x0100,
Christof Schmitt287ac012008-07-02 10:56:40 +020030 ZFCP_ERP_STEP_PORT_OPENING = 0x0800,
31 ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000,
32 ZFCP_ERP_STEP_UNIT_OPENING = 0x2000,
33};
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Christof Schmitt287ac012008-07-02 10:56:40 +020035enum zfcp_erp_act_type {
36 ZFCP_ERP_ACTION_REOPEN_UNIT = 1,
37 ZFCP_ERP_ACTION_REOPEN_PORT = 2,
38 ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3,
39 ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4,
40};
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Christof Schmitt287ac012008-07-02 10:56:40 +020042enum zfcp_erp_act_state {
43 ZFCP_ERP_ACTION_RUNNING = 1,
44 ZFCP_ERP_ACTION_READY = 2,
45};
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
Christof Schmitt287ac012008-07-02 10:56:40 +020047enum zfcp_erp_act_result {
48 ZFCP_ERP_SUCCEEDED = 0,
49 ZFCP_ERP_FAILED = 1,
50 ZFCP_ERP_CONTINUES = 2,
51 ZFCP_ERP_EXIT = 3,
52 ZFCP_ERP_DISMISSED = 4,
53 ZFCP_ERP_NOMEM = 5,
54};
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Christof Schmitt287ac012008-07-02 10:56:40 +020056static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask)
Andreas Herrmann2abbe862006-09-18 22:29:56 +020057{
Swen Schillig5ffd51a2009-03-02 13:09:04 +010058 zfcp_erp_modify_adapter_status(adapter, "erablk1", NULL,
Christof Schmitt287ac012008-07-02 10:56:40 +020059 ZFCP_STATUS_COMMON_UNBLOCKED | mask,
60 ZFCP_CLEAR);
Andreas Herrmann2abbe862006-09-18 22:29:56 +020061}
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Christof Schmitt287ac012008-07-02 10:56:40 +020063static int zfcp_erp_action_exists(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -070064{
Christof Schmitt287ac012008-07-02 10:56:40 +020065 struct zfcp_erp_action *curr_act;
66
67 list_for_each_entry(curr_act, &act->adapter->erp_running_head, list)
68 if (act == curr_act)
69 return ZFCP_ERP_ACTION_RUNNING;
70 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071}
72
Christof Schmitt287ac012008-07-02 10:56:40 +020073static void zfcp_erp_action_ready(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -070074{
Christof Schmitt287ac012008-07-02 10:56:40 +020075 struct zfcp_adapter *adapter = act->adapter;
76
77 list_move(&act->list, &act->adapter->erp_ready_head);
Swen Schillig57717102009-08-18 15:43:21 +020078 zfcp_dbf_rec_action("erardy1", act);
Christof Schmitt347c6a92009-08-18 15:43:25 +020079 wake_up(&adapter->erp_ready_wq);
Swen Schillig57717102009-08-18 15:43:21 +020080 zfcp_dbf_rec_thread("erardy2", adapter->dbf);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081}
82
Christof Schmitt287ac012008-07-02 10:56:40 +020083static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -070084{
Christof Schmitt287ac012008-07-02 10:56:40 +020085 act->status |= ZFCP_STATUS_ERP_DISMISSED;
86 if (zfcp_erp_action_exists(act) == ZFCP_ERP_ACTION_RUNNING)
87 zfcp_erp_action_ready(act);
88}
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
Christof Schmitt287ac012008-07-02 10:56:40 +020090static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
91{
92 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
93 zfcp_erp_action_dismiss(&unit->erp_action);
94}
95
96static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
97{
98 struct zfcp_unit *unit;
99
100 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
101 zfcp_erp_action_dismiss(&port->erp_action);
Swen Schilligecf0c772009-11-24 16:53:58 +0100102 else {
103 read_lock(&port->unit_list_lock);
104 list_for_each_entry(unit, &port->unit_list, list)
105 zfcp_erp_action_dismiss_unit(unit);
106 read_unlock(&port->unit_list_lock);
107 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200108}
109
110static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
111{
112 struct zfcp_port *port;
113
114 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
115 zfcp_erp_action_dismiss(&adapter->erp_action);
Swen Schilligecf0c772009-11-24 16:53:58 +0100116 else {
117 read_lock(&adapter->port_list_lock);
118 list_for_each_entry(port, &adapter->port_list, list)
Christof Schmitt287ac012008-07-02 10:56:40 +0200119 zfcp_erp_action_dismiss_port(port);
Swen Schilligecf0c772009-11-24 16:53:58 +0100120 read_unlock(&adapter->port_list_lock);
121 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200122}
123
124static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
125 struct zfcp_port *port,
126 struct zfcp_unit *unit)
127{
128 int need = want;
129 int u_status, p_status, a_status;
130
131 switch (want) {
132 case ZFCP_ERP_ACTION_REOPEN_UNIT:
133 u_status = atomic_read(&unit->status);
134 if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE)
135 return 0;
136 p_status = atomic_read(&port->status);
137 if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) ||
138 p_status & ZFCP_STATUS_COMMON_ERP_FAILED)
139 return 0;
140 if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
141 need = ZFCP_ERP_ACTION_REOPEN_PORT;
142 /* fall through */
143 case ZFCP_ERP_ACTION_REOPEN_PORT:
144 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
145 p_status = atomic_read(&port->status);
146 if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
147 return 0;
148 a_status = atomic_read(&adapter->status);
149 if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) ||
150 a_status & ZFCP_STATUS_COMMON_ERP_FAILED)
151 return 0;
152 if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))
153 need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
154 /* fall through */
155 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
156 a_status = atomic_read(&adapter->status);
157 if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
158 return 0;
Christof Schmitt143bb6b2009-08-18 15:43:27 +0200159 if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) &&
160 !(a_status & ZFCP_STATUS_COMMON_OPEN))
161 return 0; /* shutdown requested for closed adapter */
Christof Schmitt287ac012008-07-02 10:56:40 +0200162 }
163
164 return need;
165}
166
167static struct zfcp_erp_action *zfcp_erp_setup_act(int need,
168 struct zfcp_adapter *adapter,
169 struct zfcp_port *port,
170 struct zfcp_unit *unit)
171{
172 struct zfcp_erp_action *erp_action;
173 u32 status = 0;
174
175 switch (need) {
176 case ZFCP_ERP_ACTION_REOPEN_UNIT:
Swen Schillig6b1833342009-11-24 16:54:05 +0100177 if (!get_device(&unit->sysfs_device))
178 return NULL;
Christof Schmitt287ac012008-07-02 10:56:40 +0200179 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status);
180 erp_action = &unit->erp_action;
181 if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING))
182 status = ZFCP_STATUS_ERP_CLOSE_ONLY;
183 break;
184
185 case ZFCP_ERP_ACTION_REOPEN_PORT:
186 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
Swen Schillig6b1833342009-11-24 16:54:05 +0100187 if (!get_device(&port->sysfs_device))
188 return NULL;
Christof Schmitt287ac012008-07-02 10:56:40 +0200189 zfcp_erp_action_dismiss_port(port);
190 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
191 erp_action = &port->erp_action;
192 if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
193 status = ZFCP_STATUS_ERP_CLOSE_ONLY;
194 break;
195
196 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Swen Schilligf3450c72009-11-24 16:53:59 +0100197 kref_get(&adapter->ref);
Christof Schmitt287ac012008-07-02 10:56:40 +0200198 zfcp_erp_action_dismiss_adapter(adapter);
199 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
200 erp_action = &adapter->erp_action;
201 if (!(atomic_read(&adapter->status) &
202 ZFCP_STATUS_COMMON_RUNNING))
203 status = ZFCP_STATUS_ERP_CLOSE_ONLY;
204 break;
205
206 default:
207 return NULL;
208 }
209
210 memset(erp_action, 0, sizeof(struct zfcp_erp_action));
211 erp_action->adapter = adapter;
212 erp_action->port = port;
213 erp_action->unit = unit;
214 erp_action->action = need;
215 erp_action->status = status;
216
217 return erp_action;
218}
219
220static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
221 struct zfcp_port *port,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100222 struct zfcp_unit *unit, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200223{
224 int retval = 1, need;
225 struct zfcp_erp_action *act = NULL;
226
Christof Schmitt347c6a92009-08-18 15:43:25 +0200227 if (!adapter->erp_thread)
Christof Schmitt287ac012008-07-02 10:56:40 +0200228 return -EIO;
229
230 need = zfcp_erp_required_act(want, adapter, port, unit);
231 if (!need)
232 goto out;
233
234 atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
235 act = zfcp_erp_setup_act(need, adapter, port, unit);
236 if (!act)
237 goto out;
238 ++adapter->erp_total_count;
239 list_add_tail(&act->list, &adapter->erp_ready_head);
Christof Schmitt347c6a92009-08-18 15:43:25 +0200240 wake_up(&adapter->erp_ready_wq);
Swen Schillig57717102009-08-18 15:43:21 +0200241 zfcp_dbf_rec_thread("eracte1", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200242 retval = 0;
243 out:
Swen Schillig57717102009-08-18 15:43:21 +0200244 zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, unit);
Christof Schmitt287ac012008-07-02 10:56:40 +0200245 return retval;
246}
247
248static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100249 int clear_mask, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200250{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 zfcp_erp_adapter_block(adapter, clear_mask);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100252 zfcp_scsi_schedule_rports_block(adapter);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
Christof Schmitt287ac012008-07-02 10:56:40 +0200254 /* ensure propagation of failed status to new devices */
255 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100256 zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200257 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200259 return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
260 adapter, NULL, NULL, id, ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261}
262
263/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200264 * zfcp_erp_adapter_reopen - Reopen adapter.
265 * @adapter: Adapter to reopen.
266 * @clear: Status flags to clear.
267 * @id: Id for debug trace event.
268 * @ref: Reference for debug trace event.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200270void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100271 char *id, void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272{
Christof Schmitt287ac012008-07-02 10:56:40 +0200273 unsigned long flags;
274
Swen Schilligecf0c772009-11-24 16:53:58 +0100275 zfcp_erp_adapter_block(adapter, clear);
276 zfcp_scsi_schedule_rports_block(adapter);
277
278 write_lock_irqsave(&adapter->erp_lock, flags);
279 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
280 zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
281 else
282 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
283 NULL, NULL, id, ref);
284 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200285}
286
287/**
288 * zfcp_erp_adapter_shutdown - Shutdown adapter.
289 * @adapter: Adapter to shut down.
290 * @clear: Status flags to clear.
291 * @id: Id for debug trace event.
292 * @ref: Reference for debug trace event.
293 */
294void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100295 char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200296{
297 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
298 zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref);
299}
300
301/**
302 * zfcp_erp_port_shutdown - Shutdown port
303 * @port: Port to shut down.
304 * @clear: Status flags to clear.
305 * @id: Id for debug trace event.
306 * @ref: Reference for debug trace event.
307 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100308void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id,
309 void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200310{
311 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
312 zfcp_erp_port_reopen(port, clear | flags, id, ref);
313}
314
315/**
316 * zfcp_erp_unit_shutdown - Shutdown unit
317 * @unit: Unit to shut down.
318 * @clear: Status flags to clear.
319 * @id: Id for debug trace event.
320 * @ref: Reference for debug trace event.
321 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100322void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, char *id,
323 void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200324{
325 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
326 zfcp_erp_unit_reopen(unit, clear | flags, id, ref);
327}
328
329static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
330{
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100331 zfcp_erp_modify_port_status(port, "erpblk1", NULL,
Christof Schmitt287ac012008-07-02 10:56:40 +0200332 ZFCP_STATUS_COMMON_UNBLOCKED | clear,
333 ZFCP_CLEAR);
334}
335
336static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100337 int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200338{
339 zfcp_erp_port_block(port, clear);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100340 zfcp_scsi_schedule_rport_block(port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200341
342 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
343 return;
344
345 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
346 port->adapter, port, NULL, id, ref);
347}
348
349/**
350 * zfcp_erp_port_forced_reopen - Forced close of port and open again
351 * @port: Port to force close and to reopen.
352 * @id: Id for debug trace event.
353 * @ref: Reference for debug trace event.
354 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100355void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +0200356 void *ref)
357{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 unsigned long flags;
359 struct zfcp_adapter *adapter = port->adapter;
360
Swen Schilligecf0c772009-11-24 16:53:58 +0100361 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200362 _zfcp_erp_port_forced_reopen(port, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100363 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200364}
365
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100366static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +0200367 void *ref)
368{
369 zfcp_erp_port_block(port, clear);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100370 zfcp_scsi_schedule_rport_block(port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200371
372 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
373 /* ensure propagation of failed status to new devices */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100374 zfcp_erp_port_failed(port, "erpreo1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200375 return -EIO;
376 }
377
378 return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
379 port->adapter, port, NULL, id, ref);
380}
381
382/**
383 * zfcp_erp_port_reopen - trigger remote port recovery
384 * @port: port to recover
385 * @clear_mask: flags in port status to be cleared
386 *
387 * Returns 0 if recovery has been triggered, < 0 if not.
388 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100389int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200390{
Christof Schmitt287ac012008-07-02 10:56:40 +0200391 int retval;
Swen Schilligecf0c772009-11-24 16:53:58 +0100392 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +0200393 struct zfcp_adapter *adapter = port->adapter;
394
Swen Schilligecf0c772009-11-24 16:53:58 +0100395 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200396 retval = _zfcp_erp_port_reopen(port, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100397 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
399 return retval;
400}
401
Christof Schmitt287ac012008-07-02 10:56:40 +0200402static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403{
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100404 zfcp_erp_modify_unit_status(unit, "erublk1", NULL,
Christof Schmitt287ac012008-07-02 10:56:40 +0200405 ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask,
406 ZFCP_CLEAR);
407}
408
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100409static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +0200410 void *ref)
411{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 struct zfcp_adapter *adapter = unit->port->adapter;
413
Christof Schmitt287ac012008-07-02 10:56:40 +0200414 zfcp_erp_unit_block(unit, clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
Christof Schmitt287ac012008-07-02 10:56:40 +0200416 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
417 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Christof Schmitt287ac012008-07-02 10:56:40 +0200419 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT,
420 adapter, unit->port, unit, id, ref);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421}
422
423/**
424 * zfcp_erp_unit_reopen - initiate reopen of a unit
425 * @unit: unit to be reopened
426 * @clear_mask: specifies flags in unit status to be cleared
427 * Return: 0 on success, < 0 on error
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100429void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
430 void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +0200433 struct zfcp_port *port = unit->port;
434 struct zfcp_adapter *adapter = port->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
Swen Schilligecf0c772009-11-24 16:53:58 +0100436 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200437 _zfcp_erp_unit_reopen(unit, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100438 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439}
440
Christof Schmitt287ac012008-07-02 10:56:40 +0200441static int status_change_set(unsigned long mask, atomic_t *status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442{
Christof Schmitt287ac012008-07-02 10:56:40 +0200443 return (atomic_read(status) ^ mask) & mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444}
445
Christof Schmitt287ac012008-07-02 10:56:40 +0200446static int status_change_clear(unsigned long mask, atomic_t *status)
Martin Peschke698ec0162008-03-27 14:22:02 +0100447{
Christof Schmitt287ac012008-07-02 10:56:40 +0200448 return atomic_read(status) & mask;
Martin Peschke698ec0162008-03-27 14:22:02 +0100449}
450
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200451static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
Christof Schmitt287ac012008-07-02 10:56:40 +0200453 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status))
Swen Schillig57717102009-08-18 15:43:21 +0200454 zfcp_dbf_rec_adapter("eraubl1", NULL, adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200455 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456}
457
Christof Schmitt287ac012008-07-02 10:56:40 +0200458static void zfcp_erp_port_unblock(struct zfcp_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459{
Christof Schmitt287ac012008-07-02 10:56:40 +0200460 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status))
Swen Schillig57717102009-08-18 15:43:21 +0200461 zfcp_dbf_rec_port("erpubl1", NULL, port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200462 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463}
464
Christof Schmitt287ac012008-07-02 10:56:40 +0200465static void zfcp_erp_unit_unblock(struct zfcp_unit *unit)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466{
Christof Schmitt287ac012008-07-02 10:56:40 +0200467 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))
Swen Schillig57717102009-08-18 15:43:21 +0200468 zfcp_dbf_rec_unit("eruubl1", NULL, unit);
Christof Schmitt287ac012008-07-02 10:56:40 +0200469 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470}
471
Christof Schmitt287ac012008-07-02 10:56:40 +0200472static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473{
Christof Schmitt287ac012008-07-02 10:56:40 +0200474 list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
Swen Schillig57717102009-08-18 15:43:21 +0200475 zfcp_dbf_rec_action("erator1", erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476}
477
Christof Schmitt287ac012008-07-02 10:56:40 +0200478static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479{
Christof Schmitt287ac012008-07-02 10:56:40 +0200480 struct zfcp_adapter *adapter = act->adapter;
Christof Schmitte60a6d62010-02-17 11:18:49 +0100481 struct zfcp_fsf_req *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
Christof Schmitte60a6d62010-02-17 11:18:49 +0100483 if (!act->fsf_req_id)
Christof Schmitt287ac012008-07-02 10:56:40 +0200484 return;
485
486 spin_lock(&adapter->req_list_lock);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100487 req = zfcp_reqlist_find(adapter, act->fsf_req_id);
488 if (req && req->erp_action == act) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200489 if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
490 ZFCP_STATUS_ERP_TIMEDOUT)) {
Christof Schmitte60a6d62010-02-17 11:18:49 +0100491 req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
Swen Schillig57717102009-08-18 15:43:21 +0200492 zfcp_dbf_rec_action("erscf_1", act);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100493 req->erp_action = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200495 if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
Swen Schillig57717102009-08-18 15:43:21 +0200496 zfcp_dbf_rec_action("erscf_2", act);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100497 if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
498 act->fsf_req_id = 0;
Christof Schmitt287ac012008-07-02 10:56:40 +0200499 } else
Christof Schmitte60a6d62010-02-17 11:18:49 +0100500 act->fsf_req_id = 0;
Christof Schmitt287ac012008-07-02 10:56:40 +0200501 spin_unlock(&adapter->req_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502}
503
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200504/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200505 * zfcp_erp_notify - Trigger ERP action.
506 * @erp_action: ERP action to continue.
507 * @set_mask: ERP action status flags to set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200509void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
511 struct zfcp_adapter *adapter = erp_action->adapter;
512 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
514 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200515 if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
516 erp_action->status |= set_mask;
517 zfcp_erp_action_ready(erp_action);
518 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520}
521
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200522/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200523 * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request
524 * @data: ERP action (from timer data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200526void zfcp_erp_timeout_handler(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527{
Christof Schmitt287ac012008-07-02 10:56:40 +0200528 struct zfcp_erp_action *act = (struct zfcp_erp_action *) data;
529 zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530}
531
Christof Schmitt287ac012008-07-02 10:56:40 +0200532static void zfcp_erp_memwait_handler(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533{
Christof Schmitt287ac012008-07-02 10:56:40 +0200534 zfcp_erp_notify((struct zfcp_erp_action *)data, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535}
536
Christof Schmitt287ac012008-07-02 10:56:40 +0200537static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 init_timer(&erp_action->timer);
540 erp_action->timer.function = zfcp_erp_memwait_handler;
541 erp_action->timer.data = (unsigned long) erp_action;
Christof Schmitt287ac012008-07-02 10:56:40 +0200542 erp_action->timer.expires = jiffies + HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 add_timer(&erp_action->timer);
Christof Schmitt287ac012008-07-02 10:56:40 +0200544}
545
546static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100547 int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200548{
549 struct zfcp_port *port;
550
Swen Schilligecf0c772009-11-24 16:53:58 +0100551 read_lock(&adapter->port_list_lock);
552 list_for_each_entry(port, &adapter->port_list, list)
Swen Schillig5ab944f2008-10-01 12:42:17 +0200553 _zfcp_erp_port_reopen(port, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100554 read_unlock(&adapter->port_list_lock);
Christof Schmitt287ac012008-07-02 10:56:40 +0200555}
556
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100557static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
558 char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200559{
560 struct zfcp_unit *unit;
561
Swen Schilligecf0c772009-11-24 16:53:58 +0100562 read_lock(&port->unit_list_lock);
563 list_for_each_entry(unit, &port->unit_list, list)
Christof Schmitt287ac012008-07-02 10:56:40 +0200564 _zfcp_erp_unit_reopen(unit, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100565 read_unlock(&port->unit_list_lock);
Christof Schmitt287ac012008-07-02 10:56:40 +0200566}
567
Christof Schmitt85600f72009-07-13 15:06:09 +0200568static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
Christof Schmitt287ac012008-07-02 10:56:40 +0200569{
Christof Schmitt287ac012008-07-02 10:56:40 +0200570 switch (act->action) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200571 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitt85600f72009-07-13 15:06:09 +0200572 _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200573 break;
Christof Schmitt287ac012008-07-02 10:56:40 +0200574 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
Christof Schmitt85600f72009-07-13 15:06:09 +0200575 _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200576 break;
Christof Schmitt287ac012008-07-02 10:56:40 +0200577 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitt85600f72009-07-13 15:06:09 +0200578 _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200579 break;
Christof Schmitt287ac012008-07-02 10:56:40 +0200580 case ZFCP_ERP_ACTION_REOPEN_UNIT:
Christof Schmitt85600f72009-07-13 15:06:09 +0200581 _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL);
582 break;
583 }
584}
585
586static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act)
587{
588 switch (act->action) {
589 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
590 _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL);
591 break;
592 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
593 _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL);
594 break;
595 case ZFCP_ERP_ACTION_REOPEN_PORT:
596 _zfcp_erp_unit_reopen_all(act->port, 0, "ersfs_3", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200597 break;
598 }
599}
600
601static void zfcp_erp_wakeup(struct zfcp_adapter *adapter)
602{
603 unsigned long flags;
604
Swen Schilligecf0c772009-11-24 16:53:58 +0100605 read_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200606 if (list_empty(&adapter->erp_ready_head) &&
607 list_empty(&adapter->erp_running_head)) {
608 atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING,
609 &adapter->status);
610 wake_up(&adapter->erp_done_wqh);
611 }
Swen Schilligecf0c772009-11-24 16:53:58 +0100612 read_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200613}
614
615static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
616{
Swen Schillig564e1c82009-08-18 15:43:19 +0200617 struct zfcp_qdio *qdio = act->adapter->qdio;
618
619 if (zfcp_qdio_open(qdio))
Christof Schmitt287ac012008-07-02 10:56:40 +0200620 return ZFCP_ERP_FAILED;
Swen Schillig564e1c82009-08-18 15:43:19 +0200621 init_waitqueue_head(&qdio->req_q_wq);
Christof Schmitt287ac012008-07-02 10:56:40 +0200622 atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status);
623 return ZFCP_ERP_SUCCEEDED;
624}
625
626static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
627{
628 struct zfcp_port *port;
629 port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0,
630 adapter->peer_d_id);
631 if (IS_ERR(port)) /* error or port already attached */
632 return;
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100633 _zfcp_erp_port_reopen(port, 0, "ereptp1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200634}
635
636static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
637{
638 int retries;
639 int sleep = 1;
640 struct zfcp_adapter *adapter = erp_action->adapter;
641
642 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
643
644 for (retries = 7; retries; retries--) {
645 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
646 &adapter->status);
647 write_lock_irq(&adapter->erp_lock);
648 zfcp_erp_action_to_running(erp_action);
649 write_unlock_irq(&adapter->erp_lock);
650 if (zfcp_fsf_exchange_config_data(erp_action)) {
651 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
652 &adapter->status);
653 return ZFCP_ERP_FAILED;
654 }
655
Swen Schillig57717102009-08-18 15:43:21 +0200656 zfcp_dbf_rec_thread_lock("erasfx1", adapter->dbf);
Christof Schmitt347c6a92009-08-18 15:43:25 +0200657 wait_event(adapter->erp_ready_wq,
658 !list_empty(&adapter->erp_ready_head));
Swen Schillig57717102009-08-18 15:43:21 +0200659 zfcp_dbf_rec_thread_lock("erasfx2", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200660 if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
661 break;
662
663 if (!(atomic_read(&adapter->status) &
664 ZFCP_STATUS_ADAPTER_HOST_CON_INIT))
665 break;
666
667 ssleep(sleep);
668 sleep *= 2;
669 }
670
671 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
672 &adapter->status);
673
674 if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK))
675 return ZFCP_ERP_FAILED;
676
677 if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
678 zfcp_erp_enqueue_ptp_port(adapter);
679
680 return ZFCP_ERP_SUCCEEDED;
681}
682
683static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act)
684{
685 int ret;
686 struct zfcp_adapter *adapter = act->adapter;
687
Christof Schmitt287ac012008-07-02 10:56:40 +0200688 write_lock_irq(&adapter->erp_lock);
689 zfcp_erp_action_to_running(act);
690 write_unlock_irq(&adapter->erp_lock);
691
692 ret = zfcp_fsf_exchange_port_data(act);
693 if (ret == -EOPNOTSUPP)
694 return ZFCP_ERP_SUCCEEDED;
695 if (ret)
696 return ZFCP_ERP_FAILED;
697
Swen Schillig57717102009-08-18 15:43:21 +0200698 zfcp_dbf_rec_thread_lock("erasox1", adapter->dbf);
Christof Schmitt347c6a92009-08-18 15:43:25 +0200699 wait_event(adapter->erp_ready_wq,
700 !list_empty(&adapter->erp_ready_head));
Swen Schillig57717102009-08-18 15:43:21 +0200701 zfcp_dbf_rec_thread_lock("erasox2", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200702 if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
703 return ZFCP_ERP_FAILED;
704
705 return ZFCP_ERP_SUCCEEDED;
706}
707
708static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)
709{
710 if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED)
711 return ZFCP_ERP_FAILED;
712
713 if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)
714 return ZFCP_ERP_FAILED;
715
716 atomic_set(&act->adapter->stat_miss, 16);
717 if (zfcp_status_read_refill(act->adapter))
718 return ZFCP_ERP_FAILED;
719
720 return ZFCP_ERP_SUCCEEDED;
721}
722
Swen Schilligcf13c082009-03-02 13:09:03 +0100723static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act)
Christof Schmitt287ac012008-07-02 10:56:40 +0200724{
Christof Schmitt287ac012008-07-02 10:56:40 +0200725 struct zfcp_adapter *adapter = act->adapter;
726
Christof Schmitt287ac012008-07-02 10:56:40 +0200727 /* close queues to ensure that buffers are not accessed by adapter */
Swen Schillig564e1c82009-08-18 15:43:19 +0200728 zfcp_qdio_close(adapter->qdio);
Christof Schmitt287ac012008-07-02 10:56:40 +0200729 zfcp_fsf_req_dismiss_all(adapter);
730 adapter->fsf_req_seq_no = 0;
Christof Schmitt55c770f2009-08-18 15:43:12 +0200731 zfcp_fc_wka_ports_force_offline(adapter->gs);
Christof Schmitt287ac012008-07-02 10:56:40 +0200732 /* all ports and units are closed */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100733 zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL,
Christof Schmitt287ac012008-07-02 10:56:40 +0200734 ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
Swen Schilligcf13c082009-03-02 13:09:03 +0100735
Christof Schmitt287ac012008-07-02 10:56:40 +0200736 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
Swen Schilligcf13c082009-03-02 13:09:03 +0100737 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
738}
739
740static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act)
741{
742 struct zfcp_adapter *adapter = act->adapter;
743
744 if (zfcp_erp_adapter_strategy_open_qdio(act)) {
745 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
746 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
747 &adapter->status);
748 return ZFCP_ERP_FAILED;
749 }
750
751 if (zfcp_erp_adapter_strategy_open_fsf(act)) {
752 zfcp_erp_adapter_strategy_close(act);
753 return ZFCP_ERP_FAILED;
754 }
755
756 atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &adapter->status);
757
758 return ZFCP_ERP_SUCCEEDED;
Christof Schmitt287ac012008-07-02 10:56:40 +0200759}
760
761static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act)
762{
Swen Schilligcf13c082009-03-02 13:09:03 +0100763 struct zfcp_adapter *adapter = act->adapter;
Christof Schmitt287ac012008-07-02 10:56:40 +0200764
Swen Schilligcf13c082009-03-02 13:09:03 +0100765 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN) {
766 zfcp_erp_adapter_strategy_close(act);
767 if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
768 return ZFCP_ERP_EXIT;
769 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200770
Swen Schilligcf13c082009-03-02 13:09:03 +0100771 if (zfcp_erp_adapter_strategy_open(act)) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200772 ssleep(8);
Swen Schilligcf13c082009-03-02 13:09:03 +0100773 return ZFCP_ERP_FAILED;
774 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
Swen Schilligcf13c082009-03-02 13:09:03 +0100776 return ZFCP_ERP_SUCCEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777}
778
Christof Schmitt287ac012008-07-02 10:56:40 +0200779static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780{
Christof Schmitt287ac012008-07-02 10:56:40 +0200781 int retval;
782
783 retval = zfcp_fsf_close_physical_port(act);
784 if (retval == -ENOMEM)
785 return ZFCP_ERP_NOMEM;
786 act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING;
787 if (retval)
788 return ZFCP_ERP_FAILED;
789
790 return ZFCP_ERP_CONTINUES;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791}
792
Christof Schmitt287ac012008-07-02 10:56:40 +0200793static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794{
Christof Schmitta5b11dd2009-03-02 13:08:54 +0100795 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200796}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Christof Schmitt287ac012008-07-02 10:56:40 +0200798static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
799{
800 struct zfcp_port *port = erp_action->port;
801 int status = atomic_read(&port->status);
802
803 switch (erp_action->step) {
804 case ZFCP_ERP_STEP_UNINITIALIZED:
805 zfcp_erp_port_strategy_clearstati(port);
806 if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) &&
807 (status & ZFCP_STATUS_COMMON_OPEN))
808 return zfcp_erp_port_forced_strategy_close(erp_action);
809 else
810 return ZFCP_ERP_FAILED;
811
812 case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
Christof Schmittddb3e0c2009-07-13 15:06:08 +0200813 if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN))
Christof Schmitt287ac012008-07-02 10:56:40 +0200814 return ZFCP_ERP_SUCCEEDED;
815 }
816 return ZFCP_ERP_FAILED;
817}
818
819static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action)
820{
821 int retval;
822
823 retval = zfcp_fsf_close_port(erp_action);
824 if (retval == -ENOMEM)
825 return ZFCP_ERP_NOMEM;
826 erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING;
827 if (retval)
828 return ZFCP_ERP_FAILED;
829 return ZFCP_ERP_CONTINUES;
830}
831
832static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action)
833{
834 int retval;
835
836 retval = zfcp_fsf_open_port(erp_action);
837 if (retval == -ENOMEM)
838 return ZFCP_ERP_NOMEM;
839 erp_action->step = ZFCP_ERP_STEP_PORT_OPENING;
840 if (retval)
841 return ZFCP_ERP_FAILED;
842 return ZFCP_ERP_CONTINUES;
843}
844
Christof Schmitt287ac012008-07-02 10:56:40 +0200845static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
846{
847 struct zfcp_adapter *adapter = act->adapter;
848 struct zfcp_port *port = act->port;
849
850 if (port->wwpn != adapter->peer_wwpn) {
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100851 zfcp_erp_port_failed(port, "eroptp1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200852 return ZFCP_ERP_FAILED;
853 }
854 port->d_id = adapter->peer_d_id;
Christof Schmitt287ac012008-07-02 10:56:40 +0200855 return zfcp_erp_port_strategy_open_port(act);
856}
857
858static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
859{
860 struct zfcp_adapter *adapter = act->adapter;
861 struct zfcp_port *port = act->port;
Christof Schmitt287ac012008-07-02 10:56:40 +0200862 int p_status = atomic_read(&port->status);
863
864 switch (act->step) {
865 case ZFCP_ERP_STEP_UNINITIALIZED:
866 case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
867 case ZFCP_ERP_STEP_PORT_CLOSING:
868 if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
869 return zfcp_erp_open_ptp_port(act);
Christof Schmittb98478d2008-12-19 16:56:59 +0100870 if (!port->d_id) {
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200871 zfcp_fc_trigger_did_lookup(port);
Christof Schmitt799b76d2009-08-18 15:43:20 +0200872 return ZFCP_ERP_EXIT;
Christof Schmitt287ac012008-07-02 10:56:40 +0200873 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200874 return zfcp_erp_port_strategy_open_port(act);
875
876 case ZFCP_ERP_STEP_PORT_OPENING:
877 /* D_ID might have changed during open */
Swen Schillig5ab944f2008-10-01 12:42:17 +0200878 if (p_status & ZFCP_STATUS_COMMON_OPEN) {
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200879 if (!port->d_id) {
880 zfcp_fc_trigger_did_lookup(port);
881 return ZFCP_ERP_EXIT;
Swen Schillig5ab944f2008-10-01 12:42:17 +0200882 }
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200883 return ZFCP_ERP_SUCCEEDED;
Swen Schillig5ab944f2008-10-01 12:42:17 +0200884 }
Swen Schilligea460a82009-05-15 13:18:20 +0200885 if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
886 port->d_id = 0;
887 _zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL);
888 return ZFCP_ERP_EXIT;
889 }
890 /* fall through otherwise */
Christof Schmitt287ac012008-07-02 10:56:40 +0200891 }
892 return ZFCP_ERP_FAILED;
893}
894
Christof Schmitt287ac012008-07-02 10:56:40 +0200895static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
896{
897 struct zfcp_port *port = erp_action->port;
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200898 int p_status = atomic_read(&port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200899
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200900 if ((p_status & ZFCP_STATUS_COMMON_NOESC) &&
901 !(p_status & ZFCP_STATUS_COMMON_OPEN))
Swen Schillig5ab944f2008-10-01 12:42:17 +0200902 goto close_init_done;
903
Christof Schmitt287ac012008-07-02 10:56:40 +0200904 switch (erp_action->step) {
905 case ZFCP_ERP_STEP_UNINITIALIZED:
906 zfcp_erp_port_strategy_clearstati(port);
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200907 if (p_status & ZFCP_STATUS_COMMON_OPEN)
Christof Schmitt287ac012008-07-02 10:56:40 +0200908 return zfcp_erp_port_strategy_close(erp_action);
909 break;
910
911 case ZFCP_ERP_STEP_PORT_CLOSING:
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200912 if (p_status & ZFCP_STATUS_COMMON_OPEN)
Christof Schmitt287ac012008-07-02 10:56:40 +0200913 return ZFCP_ERP_FAILED;
914 break;
915 }
Swen Schillig5ab944f2008-10-01 12:42:17 +0200916
917close_init_done:
Christof Schmitt287ac012008-07-02 10:56:40 +0200918 if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
919 return ZFCP_ERP_EXIT;
Christof Schmitt287ac012008-07-02 10:56:40 +0200920
Swen Schillig5ab944f2008-10-01 12:42:17 +0200921 return zfcp_erp_port_strategy_open_common(erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922}
923
Christof Schmitt287ac012008-07-02 10:56:40 +0200924static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925{
Swen Schillig44cc76f2008-10-01 12:42:16 +0200926 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
Christof Schmitt287ac012008-07-02 10:56:40 +0200927 ZFCP_STATUS_UNIT_SHARED |
928 ZFCP_STATUS_UNIT_READONLY,
929 &unit->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930}
931
Christof Schmitt287ac012008-07-02 10:56:40 +0200932static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action)
933{
934 int retval = zfcp_fsf_close_unit(erp_action);
935 if (retval == -ENOMEM)
936 return ZFCP_ERP_NOMEM;
937 erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING;
938 if (retval)
939 return ZFCP_ERP_FAILED;
940 return ZFCP_ERP_CONTINUES;
941}
942
943static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action)
944{
945 int retval = zfcp_fsf_open_unit(erp_action);
946 if (retval == -ENOMEM)
947 return ZFCP_ERP_NOMEM;
948 erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING;
949 if (retval)
950 return ZFCP_ERP_FAILED;
951 return ZFCP_ERP_CONTINUES;
952}
953
954static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action)
955{
956 struct zfcp_unit *unit = erp_action->unit;
957
958 switch (erp_action->step) {
959 case ZFCP_ERP_STEP_UNINITIALIZED:
960 zfcp_erp_unit_strategy_clearstati(unit);
961 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
962 return zfcp_erp_unit_strategy_close(erp_action);
963 /* already closed, fall through */
964 case ZFCP_ERP_STEP_UNIT_CLOSING:
965 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
966 return ZFCP_ERP_FAILED;
967 if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
968 return ZFCP_ERP_EXIT;
969 return zfcp_erp_unit_strategy_open(erp_action);
970
971 case ZFCP_ERP_STEP_UNIT_OPENING:
972 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
973 return ZFCP_ERP_SUCCEEDED;
974 }
975 return ZFCP_ERP_FAILED;
976}
977
978static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result)
979{
980 switch (result) {
981 case ZFCP_ERP_SUCCEEDED :
982 atomic_set(&unit->erp_counter, 0);
983 zfcp_erp_unit_unblock(unit);
984 break;
985 case ZFCP_ERP_FAILED :
986 atomic_inc(&unit->erp_counter);
Christof Schmittff3b24f2008-10-01 12:42:15 +0200987 if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) {
988 dev_err(&unit->port->adapter->ccw_device->dev,
989 "ERP failed for unit 0x%016Lx on "
990 "port 0x%016Lx\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +0200991 (unsigned long long)unit->fcp_lun,
992 (unsigned long long)unit->port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100993 zfcp_erp_unit_failed(unit, "erusck1", NULL);
Christof Schmittff3b24f2008-10-01 12:42:15 +0200994 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200995 break;
996 }
997
998 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
999 zfcp_erp_unit_block(unit, 0);
1000 result = ZFCP_ERP_EXIT;
1001 }
1002 return result;
1003}
1004
1005static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
1006{
1007 switch (result) {
1008 case ZFCP_ERP_SUCCEEDED :
1009 atomic_set(&port->erp_counter, 0);
1010 zfcp_erp_port_unblock(port);
1011 break;
1012
1013 case ZFCP_ERP_FAILED :
1014 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) {
1015 zfcp_erp_port_block(port, 0);
1016 result = ZFCP_ERP_EXIT;
1017 }
1018 atomic_inc(&port->erp_counter);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001019 if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
1020 dev_err(&port->adapter->ccw_device->dev,
1021 "ERP failed for remote port 0x%016Lx\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001022 (unsigned long long)port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001023 zfcp_erp_port_failed(port, "erpsck1", NULL);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001024 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001025 break;
1026 }
1027
1028 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1029 zfcp_erp_port_block(port, 0);
1030 result = ZFCP_ERP_EXIT;
1031 }
1032 return result;
1033}
1034
1035static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter,
1036 int result)
1037{
1038 switch (result) {
1039 case ZFCP_ERP_SUCCEEDED :
1040 atomic_set(&adapter->erp_counter, 0);
1041 zfcp_erp_adapter_unblock(adapter);
1042 break;
1043
1044 case ZFCP_ERP_FAILED :
1045 atomic_inc(&adapter->erp_counter);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001046 if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) {
1047 dev_err(&adapter->ccw_device->dev,
1048 "ERP cannot recover an error "
1049 "on the FCP device\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001050 zfcp_erp_adapter_failed(adapter, "erasck1", NULL);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001051 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001052 break;
1053 }
1054
1055 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1056 zfcp_erp_adapter_block(adapter, 0);
1057 result = ZFCP_ERP_EXIT;
1058 }
1059 return result;
1060}
1061
1062static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action,
1063 int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064{
1065 struct zfcp_adapter *adapter = erp_action->adapter;
1066 struct zfcp_port *port = erp_action->port;
1067 struct zfcp_unit *unit = erp_action->unit;
1068
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 switch (erp_action->action) {
1070
1071 case ZFCP_ERP_ACTION_REOPEN_UNIT:
1072 result = zfcp_erp_strategy_check_unit(unit, result);
1073 break;
1074
1075 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1076 case ZFCP_ERP_ACTION_REOPEN_PORT:
1077 result = zfcp_erp_strategy_check_port(port, result);
1078 break;
1079
1080 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1081 result = zfcp_erp_strategy_check_adapter(adapter, result);
1082 break;
1083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 return result;
1085}
1086
Christof Schmitt287ac012008-07-02 10:56:40 +02001087static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088{
Christof Schmitt287ac012008-07-02 10:56:40 +02001089 int status = atomic_read(target_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090
Christof Schmitt287ac012008-07-02 10:56:40 +02001091 if ((status & ZFCP_STATUS_COMMON_RUNNING) &&
1092 (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1093 return 1; /* take it online */
1094
1095 if (!(status & ZFCP_STATUS_COMMON_RUNNING) &&
1096 !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1097 return 1; /* take it offline */
1098
1099 return 0;
1100}
1101
1102static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
1103{
1104 int action = act->action;
1105 struct zfcp_adapter *adapter = act->adapter;
1106 struct zfcp_port *port = act->port;
1107 struct zfcp_unit *unit = act->unit;
1108 u32 erp_status = act->status;
1109
1110 switch (action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitt287ac012008-07-02 10:56:40 +02001112 if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) {
1113 _zfcp_erp_adapter_reopen(adapter,
1114 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001115 "ersscg1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001116 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 }
1118 break;
1119
1120 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1121 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitt287ac012008-07-02 10:56:40 +02001122 if (zfcp_erp_strat_change_det(&port->status, erp_status)) {
1123 _zfcp_erp_port_reopen(port,
1124 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001125 "ersscg2", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001126 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 }
1128 break;
1129
1130 case ZFCP_ERP_ACTION_REOPEN_UNIT:
Christof Schmitt287ac012008-07-02 10:56:40 +02001131 if (zfcp_erp_strat_change_det(&unit->status, erp_status)) {
1132 _zfcp_erp_unit_reopen(unit,
1133 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001134 "ersscg3", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001135 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 }
1137 break;
1138 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001139 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140}
1141
Christof Schmitt287ac012008-07-02 10:56:40 +02001142static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
Christof Schmitt287ac012008-07-02 10:56:40 +02001144 struct zfcp_adapter *adapter = erp_action->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
Christof Schmitt287ac012008-07-02 10:56:40 +02001146 adapter->erp_total_count--;
1147 if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1148 adapter->erp_low_mem_count--;
1149 erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 }
1151
Christof Schmitt287ac012008-07-02 10:56:40 +02001152 list_del(&erp_action->list);
Swen Schillig57717102009-08-18 15:43:21 +02001153 zfcp_dbf_rec_action("eractd1", erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154
Christof Schmitt287ac012008-07-02 10:56:40 +02001155 switch (erp_action->action) {
1156 case ZFCP_ERP_ACTION_REOPEN_UNIT:
1157 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1158 &erp_action->unit->status);
1159 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
Christof Schmitt287ac012008-07-02 10:56:40 +02001161 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1162 case ZFCP_ERP_ACTION_REOPEN_PORT:
1163 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1164 &erp_action->port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001166
1167 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1168 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1169 &erp_action->adapter->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 break;
1171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172}
1173
Christof Schmitt287ac012008-07-02 10:56:40 +02001174static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001175{
Christof Schmitt287ac012008-07-02 10:56:40 +02001176 struct zfcp_adapter *adapter = act->adapter;
1177 struct zfcp_port *port = act->port;
1178 struct zfcp_unit *unit = act->unit;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001179
Christof Schmitt287ac012008-07-02 10:56:40 +02001180 switch (act->action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 case ZFCP_ERP_ACTION_REOPEN_UNIT:
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001182 if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) {
Swen Schilligf3450c72009-11-24 16:53:59 +01001183 get_device(&unit->sysfs_device);
Swen Schillig92d51932009-04-17 15:08:04 +02001184 if (scsi_queue_work(unit->port->adapter->scsi_host,
1185 &unit->scsi_work) <= 0)
Swen Schilligf3450c72009-11-24 16:53:59 +01001186 put_device(&unit->sysfs_device);
Andreas Herrmannad58f7d2006-03-10 00:56:16 +01001187 }
Swen Schilligf3450c72009-11-24 16:53:59 +01001188 put_device(&unit->sysfs_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001190
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1192 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001193 if (result == ZFCP_ERP_SUCCEEDED)
1194 zfcp_scsi_schedule_rport_register(port);
Swen Schilligf3450c72009-11-24 16:53:59 +01001195 put_device(&port->sysfs_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001197
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001199 if (result == ZFCP_ERP_SUCCEEDED) {
Christof Schmittbd43a42b72008-12-25 13:38:50 +01001200 register_service_level(&adapter->service_level);
Swen Schillig9eae07e2009-11-24 16:54:06 +01001201 queue_work(adapter->work_queue, &adapter->scan_work);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001202 } else
1203 unregister_service_level(&adapter->service_level);
Swen Schilligf3450c72009-11-24 16:53:59 +01001204 kref_put(&adapter->ref, zfcp_adapter_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 }
1207}
1208
Christof Schmitt287ac012008-07-02 10:56:40 +02001209static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
1210{
1211 switch (erp_action->action) {
1212 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1213 return zfcp_erp_adapter_strategy(erp_action);
1214 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1215 return zfcp_erp_port_forced_strategy(erp_action);
1216 case ZFCP_ERP_ACTION_REOPEN_PORT:
1217 return zfcp_erp_port_strategy(erp_action);
1218 case ZFCP_ERP_ACTION_REOPEN_UNIT:
1219 return zfcp_erp_unit_strategy(erp_action);
1220 }
1221 return ZFCP_ERP_FAILED;
1222}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
Christof Schmitt287ac012008-07-02 10:56:40 +02001224static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
1225{
1226 int retval;
Christof Schmitt287ac012008-07-02 10:56:40 +02001227 unsigned long flags;
Swen Schilligecf0c772009-11-24 16:53:58 +01001228 struct zfcp_adapter *adapter = erp_action->adapter;
Christof Schmitt287ac012008-07-02 10:56:40 +02001229
Swen Schilligf3450c72009-11-24 16:53:59 +01001230 kref_get(&adapter->ref);
Christof Schmitt287ac012008-07-02 10:56:40 +02001231
Swen Schilligf3450c72009-11-24 16:53:59 +01001232 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001233 zfcp_erp_strategy_check_fsfreq(erp_action);
1234
1235 if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
1236 zfcp_erp_action_dequeue(erp_action);
1237 retval = ZFCP_ERP_DISMISSED;
1238 goto unlock;
1239 }
1240
1241 zfcp_erp_action_to_running(erp_action);
1242
1243 /* no lock to allow for blocking operations */
Swen Schilligecf0c772009-11-24 16:53:58 +01001244 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001245 retval = zfcp_erp_strategy_do_action(erp_action);
Swen Schilligecf0c772009-11-24 16:53:58 +01001246 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001247
1248 if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED)
1249 retval = ZFCP_ERP_CONTINUES;
1250
1251 switch (retval) {
1252 case ZFCP_ERP_NOMEM:
1253 if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) {
1254 ++adapter->erp_low_mem_count;
1255 erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
1256 }
1257 if (adapter->erp_total_count == adapter->erp_low_mem_count)
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001258 _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001259 else {
1260 zfcp_erp_strategy_memwait(erp_action);
1261 retval = ZFCP_ERP_CONTINUES;
1262 }
1263 goto unlock;
1264
1265 case ZFCP_ERP_CONTINUES:
1266 if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1267 --adapter->erp_low_mem_count;
1268 erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
1269 }
1270 goto unlock;
1271 }
1272
1273 retval = zfcp_erp_strategy_check_target(erp_action, retval);
1274 zfcp_erp_action_dequeue(erp_action);
1275 retval = zfcp_erp_strategy_statechange(erp_action, retval);
1276 if (retval == ZFCP_ERP_EXIT)
1277 goto unlock;
Christof Schmitt85600f72009-07-13 15:06:09 +02001278 if (retval == ZFCP_ERP_SUCCEEDED)
1279 zfcp_erp_strategy_followup_success(erp_action);
1280 if (retval == ZFCP_ERP_FAILED)
1281 zfcp_erp_strategy_followup_failed(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +02001282
1283 unlock:
Swen Schilligecf0c772009-11-24 16:53:58 +01001284 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001285
1286 if (retval != ZFCP_ERP_CONTINUES)
1287 zfcp_erp_action_cleanup(erp_action, retval);
1288
Swen Schilligf3450c72009-11-24 16:53:59 +01001289 kref_put(&adapter->ref, zfcp_adapter_release);
Christof Schmitt287ac012008-07-02 10:56:40 +02001290 return retval;
1291}
1292
1293static int zfcp_erp_thread(void *data)
1294{
1295 struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
1296 struct list_head *next;
1297 struct zfcp_erp_action *act;
1298 unsigned long flags;
1299
Christof Schmitt347c6a92009-08-18 15:43:25 +02001300 for (;;) {
Swen Schillig57717102009-08-18 15:43:21 +02001301 zfcp_dbf_rec_thread_lock("erthrd1", adapter->dbf);
Christof Schmitt347c6a92009-08-18 15:43:25 +02001302 wait_event_interruptible(adapter->erp_ready_wq,
1303 !list_empty(&adapter->erp_ready_head) ||
1304 kthread_should_stop());
Swen Schillig57717102009-08-18 15:43:21 +02001305 zfcp_dbf_rec_thread_lock("erthrd2", adapter->dbf);
Swen Schillig94ab4b32009-04-17 15:08:06 +02001306
Christof Schmitt347c6a92009-08-18 15:43:25 +02001307 if (kthread_should_stop())
1308 break;
1309
Christof Schmitt287ac012008-07-02 10:56:40 +02001310 write_lock_irqsave(&adapter->erp_lock, flags);
1311 next = adapter->erp_ready_head.next;
1312 write_unlock_irqrestore(&adapter->erp_lock, flags);
1313
1314 if (next != &adapter->erp_ready_head) {
1315 act = list_entry(next, struct zfcp_erp_action, list);
1316
1317 /* there is more to come after dismission, no notify */
1318 if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED)
1319 zfcp_erp_wakeup(adapter);
1320 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001321 }
1322
Christof Schmitt287ac012008-07-02 10:56:40 +02001323 return 0;
1324}
1325
1326/**
1327 * zfcp_erp_thread_setup - Start ERP thread for adapter
1328 * @adapter: Adapter to start the ERP thread for
1329 *
1330 * Returns 0 on success or error code from kernel_thread()
1331 */
1332int zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
1333{
Christof Schmitt347c6a92009-08-18 15:43:25 +02001334 struct task_struct *thread;
Christof Schmitt287ac012008-07-02 10:56:40 +02001335
Christof Schmitt347c6a92009-08-18 15:43:25 +02001336 thread = kthread_run(zfcp_erp_thread, adapter, "zfcperp%s",
1337 dev_name(&adapter->ccw_device->dev));
1338 if (IS_ERR(thread)) {
Christof Schmitt287ac012008-07-02 10:56:40 +02001339 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001340 "Creating an ERP thread for the FCP device failed.\n");
Christof Schmitt347c6a92009-08-18 15:43:25 +02001341 return PTR_ERR(thread);
Christof Schmitt287ac012008-07-02 10:56:40 +02001342 }
Christof Schmitt347c6a92009-08-18 15:43:25 +02001343
1344 adapter->erp_thread = thread;
Christof Schmitt287ac012008-07-02 10:56:40 +02001345 return 0;
1346}
1347
1348/**
1349 * zfcp_erp_thread_kill - Stop ERP thread.
1350 * @adapter: Adapter where the ERP thread should be stopped.
1351 *
1352 * The caller of this routine ensures that the specified adapter has
1353 * been shut down and that this operation has been completed. Thus,
1354 * there are no pending erp_actions which would need to be handled
1355 * here.
1356 */
1357void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
1358{
Christof Schmitt347c6a92009-08-18 15:43:25 +02001359 kthread_stop(adapter->erp_thread);
1360 adapter->erp_thread = NULL;
Christof Schmitt143bb6b2009-08-18 15:43:27 +02001361 WARN_ON(!list_empty(&adapter->erp_ready_head));
1362 WARN_ON(!list_empty(&adapter->erp_running_head));
Christof Schmitt287ac012008-07-02 10:56:40 +02001363}
1364
1365/**
1366 * zfcp_erp_adapter_failed - Set adapter status to failed.
1367 * @adapter: Failed adapter.
1368 * @id: Event id for debug trace.
1369 * @ref: Reference for debug trace.
1370 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001371void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +02001372{
1373 zfcp_erp_modify_adapter_status(adapter, id, ref,
1374 ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
Christof Schmitt287ac012008-07-02 10:56:40 +02001375}
1376
1377/**
1378 * zfcp_erp_port_failed - Set port status to failed.
1379 * @port: Failed port.
1380 * @id: Event id for debug trace.
1381 * @ref: Reference for debug trace.
1382 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001383void zfcp_erp_port_failed(struct zfcp_port *port, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +02001384{
1385 zfcp_erp_modify_port_status(port, id, ref,
1386 ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
Christof Schmitt287ac012008-07-02 10:56:40 +02001387}
1388
1389/**
1390 * zfcp_erp_unit_failed - Set unit status to failed.
1391 * @unit: Failed unit.
1392 * @id: Event id for debug trace.
1393 * @ref: Reference for debug trace.
1394 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001395void zfcp_erp_unit_failed(struct zfcp_unit *unit, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +02001396{
1397 zfcp_erp_modify_unit_status(unit, id, ref,
1398 ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
Christof Schmitt287ac012008-07-02 10:56:40 +02001399}
1400
1401/**
1402 * zfcp_erp_wait - wait for completion of error recovery on an adapter
1403 * @adapter: adapter for which to wait for completion of its error recovery
1404 */
1405void zfcp_erp_wait(struct zfcp_adapter *adapter)
1406{
1407 wait_event(adapter->erp_done_wqh,
1408 !(atomic_read(&adapter->status) &
1409 ZFCP_STATUS_ADAPTER_ERP_PENDING));
1410}
1411
1412/**
1413 * zfcp_erp_modify_adapter_status - change adapter status bits
1414 * @adapter: adapter to change the status
1415 * @id: id for the debug trace
1416 * @ref: reference for the debug trace
1417 * @mask: status bits to change
1418 * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1419 *
1420 * Changes in common status bits are propagated to attached ports and units.
1421 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001422void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +02001423 void *ref, u32 mask, int set_or_clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 struct zfcp_port *port;
Swen Schilligecf0c772009-11-24 16:53:58 +01001426 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +02001427 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428
Christof Schmitt287ac012008-07-02 10:56:40 +02001429 if (set_or_clear == ZFCP_SET) {
1430 if (status_change_set(mask, &adapter->status))
Swen Schillig57717102009-08-18 15:43:21 +02001431 zfcp_dbf_rec_adapter(id, ref, adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +02001432 atomic_set_mask(mask, &adapter->status);
1433 } else {
1434 if (status_change_clear(mask, &adapter->status))
Swen Schillig57717102009-08-18 15:43:21 +02001435 zfcp_dbf_rec_adapter(id, ref, adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +02001436 atomic_clear_mask(mask, &adapter->status);
1437 if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
1438 atomic_set(&adapter->erp_counter, 0);
1439 }
1440
Swen Schilligecf0c772009-11-24 16:53:58 +01001441 if (common_mask) {
1442 read_lock_irqsave(&adapter->port_list_lock, flags);
1443 list_for_each_entry(port, &adapter->port_list, list)
Christof Schmitt287ac012008-07-02 10:56:40 +02001444 zfcp_erp_modify_port_status(port, id, ref, common_mask,
1445 set_or_clear);
Swen Schilligecf0c772009-11-24 16:53:58 +01001446 read_unlock_irqrestore(&adapter->port_list_lock, flags);
1447 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448}
1449
Christof Schmitt287ac012008-07-02 10:56:40 +02001450/**
1451 * zfcp_erp_modify_port_status - change port status bits
1452 * @port: port to change the status bits
1453 * @id: id for the debug trace
1454 * @ref: reference for the debug trace
1455 * @mask: status bits to change
1456 * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1457 *
1458 * Changes in common status bits are propagated to attached units.
1459 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001460void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref,
Christof Schmitt287ac012008-07-02 10:56:40 +02001461 u32 mask, int set_or_clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 struct zfcp_unit *unit;
Swen Schilligecf0c772009-11-24 16:53:58 +01001464 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +02001465 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466
Christof Schmitt287ac012008-07-02 10:56:40 +02001467 if (set_or_clear == ZFCP_SET) {
1468 if (status_change_set(mask, &port->status))
Swen Schillig57717102009-08-18 15:43:21 +02001469 zfcp_dbf_rec_port(id, ref, port);
Christof Schmitt287ac012008-07-02 10:56:40 +02001470 atomic_set_mask(mask, &port->status);
1471 } else {
1472 if (status_change_clear(mask, &port->status))
Swen Schillig57717102009-08-18 15:43:21 +02001473 zfcp_dbf_rec_port(id, ref, port);
Christof Schmitt287ac012008-07-02 10:56:40 +02001474 atomic_clear_mask(mask, &port->status);
1475 if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
1476 atomic_set(&port->erp_counter, 0);
1477 }
1478
Swen Schilligecf0c772009-11-24 16:53:58 +01001479 if (common_mask) {
1480 read_lock_irqsave(&port->unit_list_lock, flags);
1481 list_for_each_entry(unit, &port->unit_list, list)
Christof Schmitt287ac012008-07-02 10:56:40 +02001482 zfcp_erp_modify_unit_status(unit, id, ref, common_mask,
1483 set_or_clear);
Swen Schilligecf0c772009-11-24 16:53:58 +01001484 read_unlock_irqrestore(&port->unit_list_lock, flags);
1485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486}
1487
Christof Schmitt287ac012008-07-02 10:56:40 +02001488/**
1489 * zfcp_erp_modify_unit_status - change unit status bits
1490 * @unit: unit to change the status bits
1491 * @id: id for the debug trace
1492 * @ref: reference for the debug trace
1493 * @mask: status bits to change
1494 * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1495 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001496void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref,
Christof Schmitt287ac012008-07-02 10:56:40 +02001497 u32 mask, int set_or_clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498{
Christof Schmitt287ac012008-07-02 10:56:40 +02001499 if (set_or_clear == ZFCP_SET) {
1500 if (status_change_set(mask, &unit->status))
Swen Schillig57717102009-08-18 15:43:21 +02001501 zfcp_dbf_rec_unit(id, ref, unit);
Christof Schmitt287ac012008-07-02 10:56:40 +02001502 atomic_set_mask(mask, &unit->status);
1503 } else {
1504 if (status_change_clear(mask, &unit->status))
Swen Schillig57717102009-08-18 15:43:21 +02001505 zfcp_dbf_rec_unit(id, ref, unit);
Christof Schmitt287ac012008-07-02 10:56:40 +02001506 atomic_clear_mask(mask, &unit->status);
1507 if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) {
1508 atomic_set(&unit->erp_counter, 0);
1509 }
1510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511}
1512
Christof Schmitt287ac012008-07-02 10:56:40 +02001513/**
1514 * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP
1515 * @port: The "boxed" port.
1516 * @id: The debug trace id.
1517 * @id: Reference for the debug trace.
1518 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001519void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref)
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001520{
Martin Peschke698ec0162008-03-27 14:22:02 +01001521 zfcp_erp_modify_port_status(port, id, ref,
1522 ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
Martin Peschke9467a9b2008-03-27 14:22:03 +01001523 zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001524}
1525
Christof Schmitt287ac012008-07-02 10:56:40 +02001526/**
1527 * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP
1528 * @port: The "boxed" unit.
1529 * @id: The debug trace id.
1530 * @id: Reference for the debug trace.
1531 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001532void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref)
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001533{
Martin Peschke698ec0162008-03-27 14:22:02 +01001534 zfcp_erp_modify_unit_status(unit, id, ref,
1535 ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
Martin Peschke9467a9b2008-03-27 14:22:03 +01001536 zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001537}
1538
Christof Schmitt287ac012008-07-02 10:56:40 +02001539/**
1540 * zfcp_erp_port_access_denied - Adapter denied access to port.
1541 * @port: port where access has been denied
1542 * @id: id for debug trace
1543 * @ref: reference for debug trace
1544 *
1545 * Since the adapter has denied access, stop using the port and the
1546 * attached units.
1547 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001548void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549{
Martin Peschke698ec0162008-03-27 14:22:02 +01001550 zfcp_erp_modify_port_status(port, id, ref,
1551 ZFCP_STATUS_COMMON_ERP_FAILED |
1552 ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553}
1554
Christof Schmitt287ac012008-07-02 10:56:40 +02001555/**
1556 * zfcp_erp_unit_access_denied - Adapter denied access to unit.
1557 * @unit: unit where access has been denied
1558 * @id: id for debug trace
1559 * @ref: reference for debug trace
1560 *
1561 * Since the adapter has denied access, stop using the unit.
1562 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001563void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, char *id, void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564{
Martin Peschke698ec0162008-03-27 14:22:02 +01001565 zfcp_erp_modify_unit_status(unit, id, ref,
1566 ZFCP_STATUS_COMMON_ERP_FAILED |
1567 ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568}
1569
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001570static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +02001571 void *ref)
1572{
1573 int status = atomic_read(&unit->status);
1574 if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
1575 ZFCP_STATUS_COMMON_ACCESS_BOXED)))
1576 return;
1577
1578 zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
1579}
1580
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001581static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +02001582 void *ref)
1583{
1584 struct zfcp_unit *unit;
Swen Schilligecf0c772009-11-24 16:53:58 +01001585 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +02001586 int status = atomic_read(&port->status);
1587
1588 if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
1589 ZFCP_STATUS_COMMON_ACCESS_BOXED))) {
Swen Schilligecf0c772009-11-24 16:53:58 +01001590 read_lock_irqsave(&port->unit_list_lock, flags);
1591 list_for_each_entry(unit, &port->unit_list, list)
Swen Schillig5ab944f2008-10-01 12:42:17 +02001592 zfcp_erp_unit_access_changed(unit, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +01001593 read_unlock_irqrestore(&port->unit_list_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001594 return;
1595 }
1596
1597 zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
1598}
1599
1600/**
1601 * zfcp_erp_adapter_access_changed - Process change in adapter ACT
1602 * @adapter: Adapter where the Access Control Table (ACT) changed
1603 * @id: Id for debug trace
1604 * @ref: Reference for debug trace
1605 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001606void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id,
Martin Peschke1f6f7122008-04-18 12:51:55 +02001607 void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 unsigned long flags;
Swen Schilligecf0c772009-11-24 16:53:58 +01001610 struct zfcp_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001612 if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
1613 return;
1614
Swen Schilligecf0c772009-11-24 16:53:58 +01001615 read_lock_irqsave(&adapter->port_list_lock, flags);
1616 list_for_each_entry(port, &adapter->port_list, list)
Swen Schillig5ab944f2008-10-01 12:42:17 +02001617 zfcp_erp_port_access_changed(port, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +01001618 read_unlock_irqrestore(&adapter->port_list_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619}