blob: 50514b4c8732f039466b71163982f3c0e29d301a [file] [log] [blame]
Swen Schillig41fa2ada2007-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 Schillig41fa2ada2007-09-07 09:15:31 +02005 *
Christof Schmitt615f59e2010-02-17 11:18:56 +01006 * Copyright IBM Corporation 2002, 2010
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"
Christof Schmittb6bd2fb2010-02-17 11:18:50 +010014#include "zfcp_reqlist.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070015
Christof Schmitt287ac012008-07-02 10:56:40 +020016#define ZFCP_MAX_ERPS 3
Linus Torvalds1da177e2005-04-16 15:20:36 -070017
Christof Schmitt287ac012008-07-02 10:56:40 +020018enum zfcp_erp_act_flags {
19 ZFCP_STATUS_ERP_TIMEDOUT = 0x10000000,
20 ZFCP_STATUS_ERP_CLOSE_ONLY = 0x01000000,
21 ZFCP_STATUS_ERP_DISMISSING = 0x00100000,
22 ZFCP_STATUS_ERP_DISMISSED = 0x00200000,
23 ZFCP_STATUS_ERP_LOWMEM = 0x00400000,
Christof Schmittfdbd1c52010-09-08 14:39:54 +020024 ZFCP_STATUS_ERP_NO_REF = 0x00800000,
Christof Schmitt287ac012008-07-02 10:56:40 +020025};
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
Christof Schmitt287ac012008-07-02 10:56:40 +020027enum zfcp_erp_steps {
28 ZFCP_ERP_STEP_UNINITIALIZED = 0x0000,
29 ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001,
30 ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010,
31 ZFCP_ERP_STEP_PORT_CLOSING = 0x0100,
Christof Schmitt287ac012008-07-02 10:56:40 +020032 ZFCP_ERP_STEP_PORT_OPENING = 0x0800,
33 ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000,
34 ZFCP_ERP_STEP_UNIT_OPENING = 0x2000,
35};
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Christof Schmitt287ac012008-07-02 10:56:40 +020037enum zfcp_erp_act_type {
38 ZFCP_ERP_ACTION_REOPEN_UNIT = 1,
39 ZFCP_ERP_ACTION_REOPEN_PORT = 2,
40 ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3,
41 ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4,
42};
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
Christof Schmitt287ac012008-07-02 10:56:40 +020044enum zfcp_erp_act_state {
45 ZFCP_ERP_ACTION_RUNNING = 1,
46 ZFCP_ERP_ACTION_READY = 2,
47};
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
Christof Schmitt287ac012008-07-02 10:56:40 +020049enum zfcp_erp_act_result {
50 ZFCP_ERP_SUCCEEDED = 0,
51 ZFCP_ERP_FAILED = 1,
52 ZFCP_ERP_CONTINUES = 2,
53 ZFCP_ERP_EXIT = 3,
54 ZFCP_ERP_DISMISSED = 4,
55 ZFCP_ERP_NOMEM = 5,
56};
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Christof Schmitt287ac012008-07-02 10:56:40 +020058static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int mask)
Andreas Herrmann2abbe862006-09-18 22:29:56 +020059{
Swen Schillig5ffd51a2009-03-02 13:09:04 +010060 zfcp_erp_modify_adapter_status(adapter, "erablk1", NULL,
Christof Schmitt287ac012008-07-02 10:56:40 +020061 ZFCP_STATUS_COMMON_UNBLOCKED | mask,
62 ZFCP_CLEAR);
Andreas Herrmann2abbe862006-09-18 22:29:56 +020063}
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Christof Schmitt287ac012008-07-02 10:56:40 +020065static int zfcp_erp_action_exists(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -070066{
Christof Schmitt287ac012008-07-02 10:56:40 +020067 struct zfcp_erp_action *curr_act;
68
69 list_for_each_entry(curr_act, &act->adapter->erp_running_head, list)
70 if (act == curr_act)
71 return ZFCP_ERP_ACTION_RUNNING;
72 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070073}
74
Christof Schmitt287ac012008-07-02 10:56:40 +020075static void zfcp_erp_action_ready(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -070076{
Christof Schmitt287ac012008-07-02 10:56:40 +020077 struct zfcp_adapter *adapter = act->adapter;
78
79 list_move(&act->list, &act->adapter->erp_ready_head);
Swen Schillig57717102009-08-18 15:43:21 +020080 zfcp_dbf_rec_action("erardy1", act);
Christof Schmitt347c6a92009-08-18 15:43:25 +020081 wake_up(&adapter->erp_ready_wq);
Swen Schillig57717102009-08-18 15:43:21 +020082 zfcp_dbf_rec_thread("erardy2", adapter->dbf);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083}
84
Christof Schmitt287ac012008-07-02 10:56:40 +020085static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -070086{
Christof Schmitt287ac012008-07-02 10:56:40 +020087 act->status |= ZFCP_STATUS_ERP_DISMISSED;
88 if (zfcp_erp_action_exists(act) == ZFCP_ERP_ACTION_RUNNING)
89 zfcp_erp_action_ready(act);
90}
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Christof Schmitt287ac012008-07-02 10:56:40 +020092static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
93{
94 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
95 zfcp_erp_action_dismiss(&unit->erp_action);
96}
97
98static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
99{
100 struct zfcp_unit *unit;
101
102 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
103 zfcp_erp_action_dismiss(&port->erp_action);
Swen Schilligecf0c772009-11-24 16:53:58 +0100104 else {
105 read_lock(&port->unit_list_lock);
106 list_for_each_entry(unit, &port->unit_list, list)
107 zfcp_erp_action_dismiss_unit(unit);
108 read_unlock(&port->unit_list_lock);
109 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200110}
111
112static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
113{
114 struct zfcp_port *port;
115
116 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
117 zfcp_erp_action_dismiss(&adapter->erp_action);
Swen Schilligecf0c772009-11-24 16:53:58 +0100118 else {
119 read_lock(&adapter->port_list_lock);
120 list_for_each_entry(port, &adapter->port_list, list)
Christof Schmitt287ac012008-07-02 10:56:40 +0200121 zfcp_erp_action_dismiss_port(port);
Swen Schilligecf0c772009-11-24 16:53:58 +0100122 read_unlock(&adapter->port_list_lock);
123 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200124}
125
126static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
127 struct zfcp_port *port,
128 struct zfcp_unit *unit)
129{
130 int need = want;
131 int u_status, p_status, a_status;
132
133 switch (want) {
134 case ZFCP_ERP_ACTION_REOPEN_UNIT:
135 u_status = atomic_read(&unit->status);
136 if (u_status & ZFCP_STATUS_COMMON_ERP_INUSE)
137 return 0;
138 p_status = atomic_read(&port->status);
139 if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) ||
140 p_status & ZFCP_STATUS_COMMON_ERP_FAILED)
141 return 0;
142 if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
143 need = ZFCP_ERP_ACTION_REOPEN_PORT;
144 /* fall through */
Christof Schmitt287ac012008-07-02 10:56:40 +0200145 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
146 p_status = atomic_read(&port->status);
Christof Schmitt097ef3b2010-07-08 09:53:06 +0200147 if (!(p_status & ZFCP_STATUS_COMMON_OPEN))
148 need = ZFCP_ERP_ACTION_REOPEN_PORT;
149 /* fall through */
150 case ZFCP_ERP_ACTION_REOPEN_PORT:
151 p_status = atomic_read(&port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200152 if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
153 return 0;
154 a_status = atomic_read(&adapter->status);
155 if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) ||
156 a_status & ZFCP_STATUS_COMMON_ERP_FAILED)
157 return 0;
158 if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))
159 need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
160 /* fall through */
161 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
162 a_status = atomic_read(&adapter->status);
163 if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
164 return 0;
Christof Schmitt143bb6b2009-08-18 15:43:27 +0200165 if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) &&
166 !(a_status & ZFCP_STATUS_COMMON_OPEN))
167 return 0; /* shutdown requested for closed adapter */
Christof Schmitt287ac012008-07-02 10:56:40 +0200168 }
169
170 return need;
171}
172
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200173static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
Christof Schmitt287ac012008-07-02 10:56:40 +0200174 struct zfcp_adapter *adapter,
175 struct zfcp_port *port,
176 struct zfcp_unit *unit)
177{
178 struct zfcp_erp_action *erp_action;
Christof Schmitt287ac012008-07-02 10:56:40 +0200179
180 switch (need) {
181 case ZFCP_ERP_ACTION_REOPEN_UNIT:
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200182 if (!(act_status & ZFCP_STATUS_ERP_NO_REF))
183 if (!get_device(&unit->dev))
184 return NULL;
Christof Schmitt287ac012008-07-02 10:56:40 +0200185 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status);
186 erp_action = &unit->erp_action;
187 if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING))
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200188 act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
Christof Schmitt287ac012008-07-02 10:56:40 +0200189 break;
190
191 case ZFCP_ERP_ACTION_REOPEN_PORT:
192 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
Christof Schmitt615f59e2010-02-17 11:18:56 +0100193 if (!get_device(&port->dev))
Swen Schillig6b1833342009-11-24 16:54:05 +0100194 return NULL;
Christof Schmitt287ac012008-07-02 10:56:40 +0200195 zfcp_erp_action_dismiss_port(port);
196 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
197 erp_action = &port->erp_action;
198 if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200199 act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
Christof Schmitt287ac012008-07-02 10:56:40 +0200200 break;
201
202 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Swen Schilligf3450c72009-11-24 16:53:59 +0100203 kref_get(&adapter->ref);
Christof Schmitt287ac012008-07-02 10:56:40 +0200204 zfcp_erp_action_dismiss_adapter(adapter);
205 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
206 erp_action = &adapter->erp_action;
207 if (!(atomic_read(&adapter->status) &
208 ZFCP_STATUS_COMMON_RUNNING))
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200209 act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
Christof Schmitt287ac012008-07-02 10:56:40 +0200210 break;
211
212 default:
213 return NULL;
214 }
215
216 memset(erp_action, 0, sizeof(struct zfcp_erp_action));
217 erp_action->adapter = adapter;
218 erp_action->port = port;
219 erp_action->unit = unit;
220 erp_action->action = need;
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200221 erp_action->status = act_status;
Christof Schmitt287ac012008-07-02 10:56:40 +0200222
223 return erp_action;
224}
225
226static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
227 struct zfcp_port *port,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200228 struct zfcp_unit *unit, char *id, void *ref,
229 u32 act_status)
Christof Schmitt287ac012008-07-02 10:56:40 +0200230{
231 int retval = 1, need;
232 struct zfcp_erp_action *act = NULL;
233
Christof Schmitt347c6a92009-08-18 15:43:25 +0200234 if (!adapter->erp_thread)
Christof Schmitt287ac012008-07-02 10:56:40 +0200235 return -EIO;
236
237 need = zfcp_erp_required_act(want, adapter, port, unit);
238 if (!need)
239 goto out;
240
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200241 act = zfcp_erp_setup_act(need, act_status, adapter, port, unit);
Christof Schmitt287ac012008-07-02 10:56:40 +0200242 if (!act)
243 goto out;
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200244 atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200245 ++adapter->erp_total_count;
246 list_add_tail(&act->list, &adapter->erp_ready_head);
Christof Schmitt347c6a92009-08-18 15:43:25 +0200247 wake_up(&adapter->erp_ready_wq);
Swen Schillig57717102009-08-18 15:43:21 +0200248 zfcp_dbf_rec_thread("eracte1", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200249 retval = 0;
250 out:
Swen Schillig57717102009-08-18 15:43:21 +0200251 zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, unit);
Christof Schmitt287ac012008-07-02 10:56:40 +0200252 return retval;
253}
254
255static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100256 int clear_mask, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200257{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 zfcp_erp_adapter_block(adapter, clear_mask);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100259 zfcp_scsi_schedule_rports_block(adapter);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
Christof Schmitt287ac012008-07-02 10:56:40 +0200261 /* ensure propagation of failed status to new devices */
262 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100263 zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200264 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200266 return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200267 adapter, NULL, NULL, id, ref, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268}
269
270/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200271 * zfcp_erp_adapter_reopen - Reopen adapter.
272 * @adapter: Adapter to reopen.
273 * @clear: Status flags to clear.
274 * @id: Id for debug trace event.
275 * @ref: Reference for debug trace event.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200277void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100278 char *id, void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279{
Christof Schmitt287ac012008-07-02 10:56:40 +0200280 unsigned long flags;
281
Swen Schilligecf0c772009-11-24 16:53:58 +0100282 zfcp_erp_adapter_block(adapter, clear);
283 zfcp_scsi_schedule_rports_block(adapter);
284
285 write_lock_irqsave(&adapter->erp_lock, flags);
286 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
287 zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
288 else
289 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200290 NULL, NULL, id, ref, 0);
Swen Schilligecf0c772009-11-24 16:53:58 +0100291 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200292}
293
294/**
295 * zfcp_erp_adapter_shutdown - Shutdown adapter.
296 * @adapter: Adapter to shut down.
297 * @clear: Status flags to clear.
298 * @id: Id for debug trace event.
299 * @ref: Reference for debug trace event.
300 */
301void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100302 char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200303{
304 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
305 zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref);
306}
307
308/**
309 * zfcp_erp_port_shutdown - Shutdown port
310 * @port: Port to shut down.
311 * @clear: Status flags to clear.
312 * @id: Id for debug trace event.
313 * @ref: Reference for debug trace event.
314 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100315void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id,
316 void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200317{
318 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
319 zfcp_erp_port_reopen(port, clear | flags, id, ref);
320}
321
Christof Schmitt287ac012008-07-02 10:56:40 +0200322static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
323{
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100324 zfcp_erp_modify_port_status(port, "erpblk1", NULL,
Christof Schmitt287ac012008-07-02 10:56:40 +0200325 ZFCP_STATUS_COMMON_UNBLOCKED | clear,
326 ZFCP_CLEAR);
327}
328
329static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100330 int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200331{
332 zfcp_erp_port_block(port, clear);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100333 zfcp_scsi_schedule_rport_block(port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200334
335 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
336 return;
337
338 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200339 port->adapter, port, NULL, id, ref, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +0200340}
341
342/**
343 * zfcp_erp_port_forced_reopen - Forced close of port and open again
344 * @port: Port to force close and to reopen.
345 * @id: Id for debug trace event.
346 * @ref: Reference for debug trace event.
347 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100348void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +0200349 void *ref)
350{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 unsigned long flags;
352 struct zfcp_adapter *adapter = port->adapter;
353
Swen Schilligecf0c772009-11-24 16:53:58 +0100354 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200355 _zfcp_erp_port_forced_reopen(port, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100356 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200357}
358
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100359static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +0200360 void *ref)
361{
362 zfcp_erp_port_block(port, clear);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100363 zfcp_scsi_schedule_rport_block(port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200364
365 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
366 /* ensure propagation of failed status to new devices */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100367 zfcp_erp_port_failed(port, "erpreo1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200368 return -EIO;
369 }
370
371 return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200372 port->adapter, port, NULL, id, ref, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +0200373}
374
375/**
376 * zfcp_erp_port_reopen - trigger remote port recovery
377 * @port: port to recover
378 * @clear_mask: flags in port status to be cleared
379 *
380 * Returns 0 if recovery has been triggered, < 0 if not.
381 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100382int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200383{
Christof Schmitt287ac012008-07-02 10:56:40 +0200384 int retval;
Swen Schilligecf0c772009-11-24 16:53:58 +0100385 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +0200386 struct zfcp_adapter *adapter = port->adapter;
387
Swen Schilligecf0c772009-11-24 16:53:58 +0100388 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200389 retval = _zfcp_erp_port_reopen(port, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100390 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
392 return retval;
393}
394
Christof Schmitt287ac012008-07-02 10:56:40 +0200395static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396{
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100397 zfcp_erp_modify_unit_status(unit, "erublk1", NULL,
Christof Schmitt287ac012008-07-02 10:56:40 +0200398 ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask,
399 ZFCP_CLEAR);
400}
401
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100402static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200403 void *ref, u32 act_status)
Christof Schmitt287ac012008-07-02 10:56:40 +0200404{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 struct zfcp_adapter *adapter = unit->port->adapter;
406
Christof Schmitt287ac012008-07-02 10:56:40 +0200407 zfcp_erp_unit_block(unit, clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
Christof Schmitt287ac012008-07-02 10:56:40 +0200409 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
410 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
Christof Schmitt287ac012008-07-02 10:56:40 +0200412 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200413 adapter, unit->port, unit, id, ref, act_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414}
415
416/**
417 * zfcp_erp_unit_reopen - initiate reopen of a unit
418 * @unit: unit to be reopened
419 * @clear_mask: specifies flags in unit status to be cleared
420 * Return: 0 on success, < 0 on error
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100422void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id,
423 void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +0200426 struct zfcp_port *port = unit->port;
427 struct zfcp_adapter *adapter = port->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
Swen Schilligecf0c772009-11-24 16:53:58 +0100429 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200430 _zfcp_erp_unit_reopen(unit, clear, id, ref, 0);
Swen Schilligecf0c772009-11-24 16:53:58 +0100431 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432}
433
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200434/**
435 * zfcp_erp_unit_shutdown - Shutdown unit
436 * @unit: Unit to shut down.
437 * @clear: Status flags to clear.
438 * @id: Id for debug trace event.
439 * @ref: Reference for debug trace event.
440 */
441void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, char *id,
442 void *ref)
443{
444 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
445 zfcp_erp_unit_reopen(unit, clear | flags, id, ref);
446}
447
448/**
449 * zfcp_erp_unit_shutdown_wait - Shutdown unit and wait for erp completion
450 * @unit: Unit to shut down.
451 * @id: Id for debug trace event.
452 *
453 * Do not acquire a reference for the unit when creating the ERP
454 * action. It is safe, because this function waits for the ERP to
455 * complete first.
456 */
457void zfcp_erp_unit_shutdown_wait(struct zfcp_unit *unit, char *id)
458{
459 unsigned long flags;
460 struct zfcp_port *port = unit->port;
461 struct zfcp_adapter *adapter = port->adapter;
462 int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
463
464 write_lock_irqsave(&adapter->erp_lock, flags);
465 _zfcp_erp_unit_reopen(unit, clear, id, NULL, ZFCP_STATUS_ERP_NO_REF);
466 write_unlock_irqrestore(&adapter->erp_lock, flags);
467
468 zfcp_erp_wait(adapter);
469}
470
Christof Schmitt287ac012008-07-02 10:56:40 +0200471static int status_change_set(unsigned long mask, atomic_t *status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
Christof Schmitt287ac012008-07-02 10:56:40 +0200473 return (atomic_read(status) ^ mask) & mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474}
475
Christof Schmitt287ac012008-07-02 10:56:40 +0200476static int status_change_clear(unsigned long mask, atomic_t *status)
Martin Peschke698ec0162008-03-27 14:22:02 +0100477{
Christof Schmitt287ac012008-07-02 10:56:40 +0200478 return atomic_read(status) & mask;
Martin Peschke698ec0162008-03-27 14:22:02 +0100479}
480
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200481static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
Christof Schmitt287ac012008-07-02 10:56:40 +0200483 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status))
Swen Schillig57717102009-08-18 15:43:21 +0200484 zfcp_dbf_rec_adapter("eraubl1", NULL, adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200485 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486}
487
Christof Schmitt287ac012008-07-02 10:56:40 +0200488static void zfcp_erp_port_unblock(struct zfcp_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489{
Christof Schmitt287ac012008-07-02 10:56:40 +0200490 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status))
Swen Schillig57717102009-08-18 15:43:21 +0200491 zfcp_dbf_rec_port("erpubl1", NULL, port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200492 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493}
494
Christof Schmitt287ac012008-07-02 10:56:40 +0200495static void zfcp_erp_unit_unblock(struct zfcp_unit *unit)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496{
Christof Schmitt287ac012008-07-02 10:56:40 +0200497 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))
Swen Schillig57717102009-08-18 15:43:21 +0200498 zfcp_dbf_rec_unit("eruubl1", NULL, unit);
Christof Schmitt287ac012008-07-02 10:56:40 +0200499 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500}
501
Christof Schmitt287ac012008-07-02 10:56:40 +0200502static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503{
Christof Schmitt287ac012008-07-02 10:56:40 +0200504 list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
Swen Schillig57717102009-08-18 15:43:21 +0200505 zfcp_dbf_rec_action("erator1", erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506}
507
Christof Schmitt287ac012008-07-02 10:56:40 +0200508static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509{
Christof Schmitt287ac012008-07-02 10:56:40 +0200510 struct zfcp_adapter *adapter = act->adapter;
Christof Schmitte60a6d62010-02-17 11:18:49 +0100511 struct zfcp_fsf_req *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
Christof Schmitte60a6d62010-02-17 11:18:49 +0100513 if (!act->fsf_req_id)
Christof Schmitt287ac012008-07-02 10:56:40 +0200514 return;
515
Christof Schmittb6bd2fb2010-02-17 11:18:50 +0100516 spin_lock(&adapter->req_list->lock);
517 req = _zfcp_reqlist_find(adapter->req_list, act->fsf_req_id);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100518 if (req && req->erp_action == act) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200519 if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
520 ZFCP_STATUS_ERP_TIMEDOUT)) {
Christof Schmitte60a6d62010-02-17 11:18:49 +0100521 req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
Swen Schillig57717102009-08-18 15:43:21 +0200522 zfcp_dbf_rec_action("erscf_1", act);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100523 req->erp_action = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200525 if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
Swen Schillig57717102009-08-18 15:43:21 +0200526 zfcp_dbf_rec_action("erscf_2", act);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100527 if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
528 act->fsf_req_id = 0;
Christof Schmitt287ac012008-07-02 10:56:40 +0200529 } else
Christof Schmitte60a6d62010-02-17 11:18:49 +0100530 act->fsf_req_id = 0;
Christof Schmittb6bd2fb2010-02-17 11:18:50 +0100531 spin_unlock(&adapter->req_list->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532}
533
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200534/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200535 * zfcp_erp_notify - Trigger ERP action.
536 * @erp_action: ERP action to continue.
537 * @set_mask: ERP action status flags to set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200539void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540{
541 struct zfcp_adapter *adapter = erp_action->adapter;
542 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
544 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200545 if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
546 erp_action->status |= set_mask;
547 zfcp_erp_action_ready(erp_action);
548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550}
551
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200552/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200553 * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request
554 * @data: ERP action (from timer data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200556void zfcp_erp_timeout_handler(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557{
Christof Schmitt287ac012008-07-02 10:56:40 +0200558 struct zfcp_erp_action *act = (struct zfcp_erp_action *) data;
559 zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560}
561
Christof Schmitt287ac012008-07-02 10:56:40 +0200562static void zfcp_erp_memwait_handler(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
Christof Schmitt287ac012008-07-02 10:56:40 +0200564 zfcp_erp_notify((struct zfcp_erp_action *)data, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565}
566
Christof Schmitt287ac012008-07-02 10:56:40 +0200567static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 init_timer(&erp_action->timer);
570 erp_action->timer.function = zfcp_erp_memwait_handler;
571 erp_action->timer.data = (unsigned long) erp_action;
Christof Schmitt287ac012008-07-02 10:56:40 +0200572 erp_action->timer.expires = jiffies + HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 add_timer(&erp_action->timer);
Christof Schmitt287ac012008-07-02 10:56:40 +0200574}
575
576static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100577 int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200578{
579 struct zfcp_port *port;
580
Swen Schilligecf0c772009-11-24 16:53:58 +0100581 read_lock(&adapter->port_list_lock);
582 list_for_each_entry(port, &adapter->port_list, list)
Swen Schillig5ab944f2008-10-01 12:42:17 +0200583 _zfcp_erp_port_reopen(port, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100584 read_unlock(&adapter->port_list_lock);
Christof Schmitt287ac012008-07-02 10:56:40 +0200585}
586
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100587static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
588 char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200589{
590 struct zfcp_unit *unit;
591
Swen Schilligecf0c772009-11-24 16:53:58 +0100592 read_lock(&port->unit_list_lock);
593 list_for_each_entry(unit, &port->unit_list, list)
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200594 _zfcp_erp_unit_reopen(unit, clear, id, ref, 0);
Swen Schilligecf0c772009-11-24 16:53:58 +0100595 read_unlock(&port->unit_list_lock);
Christof Schmitt287ac012008-07-02 10:56:40 +0200596}
597
Christof Schmitt85600f72009-07-13 15:06:09 +0200598static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
Christof Schmitt287ac012008-07-02 10:56:40 +0200599{
Christof Schmitt287ac012008-07-02 10:56:40 +0200600 switch (act->action) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200601 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitt85600f72009-07-13 15:06:09 +0200602 _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200603 break;
Christof Schmitt287ac012008-07-02 10:56:40 +0200604 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
Christof Schmitt85600f72009-07-13 15:06:09 +0200605 _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200606 break;
Christof Schmitt287ac012008-07-02 10:56:40 +0200607 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitt85600f72009-07-13 15:06:09 +0200608 _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200609 break;
Christof Schmitt287ac012008-07-02 10:56:40 +0200610 case ZFCP_ERP_ACTION_REOPEN_UNIT:
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200611 _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL, 0);
Christof Schmitt85600f72009-07-13 15:06:09 +0200612 break;
613 }
614}
615
616static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act)
617{
618 switch (act->action) {
619 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
620 _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL);
621 break;
622 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
623 _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL);
624 break;
625 case ZFCP_ERP_ACTION_REOPEN_PORT:
626 _zfcp_erp_unit_reopen_all(act->port, 0, "ersfs_3", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200627 break;
628 }
629}
630
631static void zfcp_erp_wakeup(struct zfcp_adapter *adapter)
632{
633 unsigned long flags;
634
Swen Schilligecf0c772009-11-24 16:53:58 +0100635 read_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200636 if (list_empty(&adapter->erp_ready_head) &&
637 list_empty(&adapter->erp_running_head)) {
638 atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING,
639 &adapter->status);
640 wake_up(&adapter->erp_done_wqh);
641 }
Swen Schilligecf0c772009-11-24 16:53:58 +0100642 read_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200643}
644
645static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
646{
Swen Schillig564e1c82009-08-18 15:43:19 +0200647 struct zfcp_qdio *qdio = act->adapter->qdio;
648
649 if (zfcp_qdio_open(qdio))
Christof Schmitt287ac012008-07-02 10:56:40 +0200650 return ZFCP_ERP_FAILED;
Swen Schillig564e1c82009-08-18 15:43:19 +0200651 init_waitqueue_head(&qdio->req_q_wq);
Christof Schmitt287ac012008-07-02 10:56:40 +0200652 atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status);
653 return ZFCP_ERP_SUCCEEDED;
654}
655
656static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
657{
658 struct zfcp_port *port;
659 port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0,
660 adapter->peer_d_id);
661 if (IS_ERR(port)) /* error or port already attached */
662 return;
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100663 _zfcp_erp_port_reopen(port, 0, "ereptp1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200664}
665
666static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
667{
668 int retries;
669 int sleep = 1;
670 struct zfcp_adapter *adapter = erp_action->adapter;
671
672 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
673
674 for (retries = 7; retries; retries--) {
675 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
676 &adapter->status);
677 write_lock_irq(&adapter->erp_lock);
678 zfcp_erp_action_to_running(erp_action);
679 write_unlock_irq(&adapter->erp_lock);
680 if (zfcp_fsf_exchange_config_data(erp_action)) {
681 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
682 &adapter->status);
683 return ZFCP_ERP_FAILED;
684 }
685
Swen Schillig57717102009-08-18 15:43:21 +0200686 zfcp_dbf_rec_thread_lock("erasfx1", adapter->dbf);
Christof Schmitt347c6a92009-08-18 15:43:25 +0200687 wait_event(adapter->erp_ready_wq,
688 !list_empty(&adapter->erp_ready_head));
Swen Schillig57717102009-08-18 15:43:21 +0200689 zfcp_dbf_rec_thread_lock("erasfx2", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200690 if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
691 break;
692
693 if (!(atomic_read(&adapter->status) &
694 ZFCP_STATUS_ADAPTER_HOST_CON_INIT))
695 break;
696
697 ssleep(sleep);
698 sleep *= 2;
699 }
700
701 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
702 &adapter->status);
703
704 if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK))
705 return ZFCP_ERP_FAILED;
706
707 if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
708 zfcp_erp_enqueue_ptp_port(adapter);
709
710 return ZFCP_ERP_SUCCEEDED;
711}
712
713static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act)
714{
715 int ret;
716 struct zfcp_adapter *adapter = act->adapter;
717
Christof Schmitt287ac012008-07-02 10:56:40 +0200718 write_lock_irq(&adapter->erp_lock);
719 zfcp_erp_action_to_running(act);
720 write_unlock_irq(&adapter->erp_lock);
721
722 ret = zfcp_fsf_exchange_port_data(act);
723 if (ret == -EOPNOTSUPP)
724 return ZFCP_ERP_SUCCEEDED;
725 if (ret)
726 return ZFCP_ERP_FAILED;
727
Swen Schillig57717102009-08-18 15:43:21 +0200728 zfcp_dbf_rec_thread_lock("erasox1", adapter->dbf);
Christof Schmitt347c6a92009-08-18 15:43:25 +0200729 wait_event(adapter->erp_ready_wq,
730 !list_empty(&adapter->erp_ready_head));
Swen Schillig57717102009-08-18 15:43:21 +0200731 zfcp_dbf_rec_thread_lock("erasox2", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200732 if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
733 return ZFCP_ERP_FAILED;
734
735 return ZFCP_ERP_SUCCEEDED;
736}
737
738static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)
739{
740 if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED)
741 return ZFCP_ERP_FAILED;
742
743 if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)
744 return ZFCP_ERP_FAILED;
745
Christof Schmitt8d88cf32010-06-21 10:11:33 +0200746 if (mempool_resize(act->adapter->pool.status_read_data,
747 act->adapter->stat_read_buf_num, GFP_KERNEL))
748 return ZFCP_ERP_FAILED;
749
750 if (mempool_resize(act->adapter->pool.status_read_req,
751 act->adapter->stat_read_buf_num, GFP_KERNEL))
752 return ZFCP_ERP_FAILED;
753
Christof Schmitt64deb6e2010-04-30 18:09:36 +0200754 atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num);
Christof Schmitt287ac012008-07-02 10:56:40 +0200755 if (zfcp_status_read_refill(act->adapter))
756 return ZFCP_ERP_FAILED;
757
758 return ZFCP_ERP_SUCCEEDED;
759}
760
Swen Schilligcf13c082009-03-02 13:09:03 +0100761static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act)
Christof Schmitt287ac012008-07-02 10:56:40 +0200762{
Christof Schmitt287ac012008-07-02 10:56:40 +0200763 struct zfcp_adapter *adapter = act->adapter;
764
Christof Schmitt287ac012008-07-02 10:56:40 +0200765 /* close queues to ensure that buffers are not accessed by adapter */
Swen Schillig564e1c82009-08-18 15:43:19 +0200766 zfcp_qdio_close(adapter->qdio);
Christof Schmitt287ac012008-07-02 10:56:40 +0200767 zfcp_fsf_req_dismiss_all(adapter);
768 adapter->fsf_req_seq_no = 0;
Christof Schmitt55c770f2009-08-18 15:43:12 +0200769 zfcp_fc_wka_ports_force_offline(adapter->gs);
Christof Schmitt287ac012008-07-02 10:56:40 +0200770 /* all ports and units are closed */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100771 zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL,
Christof Schmitt287ac012008-07-02 10:56:40 +0200772 ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
Swen Schilligcf13c082009-03-02 13:09:03 +0100773
Christof Schmitt287ac012008-07-02 10:56:40 +0200774 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
Swen Schilligcf13c082009-03-02 13:09:03 +0100775 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
776}
777
778static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act)
779{
780 struct zfcp_adapter *adapter = act->adapter;
781
782 if (zfcp_erp_adapter_strategy_open_qdio(act)) {
783 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
784 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
785 &adapter->status);
786 return ZFCP_ERP_FAILED;
787 }
788
789 if (zfcp_erp_adapter_strategy_open_fsf(act)) {
790 zfcp_erp_adapter_strategy_close(act);
791 return ZFCP_ERP_FAILED;
792 }
793
794 atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &adapter->status);
795
796 return ZFCP_ERP_SUCCEEDED;
Christof Schmitt287ac012008-07-02 10:56:40 +0200797}
798
799static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act)
800{
Swen Schilligcf13c082009-03-02 13:09:03 +0100801 struct zfcp_adapter *adapter = act->adapter;
Christof Schmitt287ac012008-07-02 10:56:40 +0200802
Swen Schilligcf13c082009-03-02 13:09:03 +0100803 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN) {
804 zfcp_erp_adapter_strategy_close(act);
805 if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
806 return ZFCP_ERP_EXIT;
807 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200808
Swen Schilligcf13c082009-03-02 13:09:03 +0100809 if (zfcp_erp_adapter_strategy_open(act)) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200810 ssleep(8);
Swen Schilligcf13c082009-03-02 13:09:03 +0100811 return ZFCP_ERP_FAILED;
812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
Swen Schilligcf13c082009-03-02 13:09:03 +0100814 return ZFCP_ERP_SUCCEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815}
816
Christof Schmitt287ac012008-07-02 10:56:40 +0200817static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818{
Christof Schmitt287ac012008-07-02 10:56:40 +0200819 int retval;
820
821 retval = zfcp_fsf_close_physical_port(act);
822 if (retval == -ENOMEM)
823 return ZFCP_ERP_NOMEM;
824 act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING;
825 if (retval)
826 return ZFCP_ERP_FAILED;
827
828 return ZFCP_ERP_CONTINUES;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829}
830
Christof Schmitt287ac012008-07-02 10:56:40 +0200831static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832{
Christof Schmitta5b11dd2009-03-02 13:08:54 +0100833 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200834}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
Christof Schmitt287ac012008-07-02 10:56:40 +0200836static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
837{
838 struct zfcp_port *port = erp_action->port;
839 int status = atomic_read(&port->status);
840
841 switch (erp_action->step) {
842 case ZFCP_ERP_STEP_UNINITIALIZED:
843 zfcp_erp_port_strategy_clearstati(port);
844 if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) &&
845 (status & ZFCP_STATUS_COMMON_OPEN))
846 return zfcp_erp_port_forced_strategy_close(erp_action);
847 else
848 return ZFCP_ERP_FAILED;
849
850 case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
Christof Schmittddb3e0c2009-07-13 15:06:08 +0200851 if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN))
Christof Schmitt287ac012008-07-02 10:56:40 +0200852 return ZFCP_ERP_SUCCEEDED;
853 }
854 return ZFCP_ERP_FAILED;
855}
856
857static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action)
858{
859 int retval;
860
861 retval = zfcp_fsf_close_port(erp_action);
862 if (retval == -ENOMEM)
863 return ZFCP_ERP_NOMEM;
864 erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING;
865 if (retval)
866 return ZFCP_ERP_FAILED;
867 return ZFCP_ERP_CONTINUES;
868}
869
870static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action)
871{
872 int retval;
873
874 retval = zfcp_fsf_open_port(erp_action);
875 if (retval == -ENOMEM)
876 return ZFCP_ERP_NOMEM;
877 erp_action->step = ZFCP_ERP_STEP_PORT_OPENING;
878 if (retval)
879 return ZFCP_ERP_FAILED;
880 return ZFCP_ERP_CONTINUES;
881}
882
Christof Schmitt287ac012008-07-02 10:56:40 +0200883static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
884{
885 struct zfcp_adapter *adapter = act->adapter;
886 struct zfcp_port *port = act->port;
887
888 if (port->wwpn != adapter->peer_wwpn) {
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100889 zfcp_erp_port_failed(port, "eroptp1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200890 return ZFCP_ERP_FAILED;
891 }
892 port->d_id = adapter->peer_d_id;
Christof Schmitt287ac012008-07-02 10:56:40 +0200893 return zfcp_erp_port_strategy_open_port(act);
894}
895
896static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
897{
898 struct zfcp_adapter *adapter = act->adapter;
899 struct zfcp_port *port = act->port;
Christof Schmitt287ac012008-07-02 10:56:40 +0200900 int p_status = atomic_read(&port->status);
901
902 switch (act->step) {
903 case ZFCP_ERP_STEP_UNINITIALIZED:
904 case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
905 case ZFCP_ERP_STEP_PORT_CLOSING:
906 if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
907 return zfcp_erp_open_ptp_port(act);
Christof Schmittb98478d2008-12-19 16:56:59 +0100908 if (!port->d_id) {
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200909 zfcp_fc_trigger_did_lookup(port);
Christof Schmitt799b76d2009-08-18 15:43:20 +0200910 return ZFCP_ERP_EXIT;
Christof Schmitt287ac012008-07-02 10:56:40 +0200911 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200912 return zfcp_erp_port_strategy_open_port(act);
913
914 case ZFCP_ERP_STEP_PORT_OPENING:
915 /* D_ID might have changed during open */
Swen Schillig5ab944f2008-10-01 12:42:17 +0200916 if (p_status & ZFCP_STATUS_COMMON_OPEN) {
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200917 if (!port->d_id) {
918 zfcp_fc_trigger_did_lookup(port);
919 return ZFCP_ERP_EXIT;
Swen Schillig5ab944f2008-10-01 12:42:17 +0200920 }
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200921 return ZFCP_ERP_SUCCEEDED;
Swen Schillig5ab944f2008-10-01 12:42:17 +0200922 }
Swen Schilligea460a82009-05-15 13:18:20 +0200923 if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
924 port->d_id = 0;
Christof Schmittf7bd7c32010-07-08 09:53:10 +0200925 return ZFCP_ERP_FAILED;
Swen Schilligea460a82009-05-15 13:18:20 +0200926 }
927 /* fall through otherwise */
Christof Schmitt287ac012008-07-02 10:56:40 +0200928 }
929 return ZFCP_ERP_FAILED;
930}
931
Christof Schmitt287ac012008-07-02 10:56:40 +0200932static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
933{
934 struct zfcp_port *port = erp_action->port;
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200935 int p_status = atomic_read(&port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200936
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200937 if ((p_status & ZFCP_STATUS_COMMON_NOESC) &&
938 !(p_status & ZFCP_STATUS_COMMON_OPEN))
Swen Schillig5ab944f2008-10-01 12:42:17 +0200939 goto close_init_done;
940
Christof Schmitt287ac012008-07-02 10:56:40 +0200941 switch (erp_action->step) {
942 case ZFCP_ERP_STEP_UNINITIALIZED:
943 zfcp_erp_port_strategy_clearstati(port);
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200944 if (p_status & ZFCP_STATUS_COMMON_OPEN)
Christof Schmitt287ac012008-07-02 10:56:40 +0200945 return zfcp_erp_port_strategy_close(erp_action);
946 break;
947
948 case ZFCP_ERP_STEP_PORT_CLOSING:
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200949 if (p_status & ZFCP_STATUS_COMMON_OPEN)
Christof Schmitt287ac012008-07-02 10:56:40 +0200950 return ZFCP_ERP_FAILED;
951 break;
952 }
Swen Schillig5ab944f2008-10-01 12:42:17 +0200953
954close_init_done:
Christof Schmitt287ac012008-07-02 10:56:40 +0200955 if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
956 return ZFCP_ERP_EXIT;
Christof Schmitt287ac012008-07-02 10:56:40 +0200957
Swen Schillig5ab944f2008-10-01 12:42:17 +0200958 return zfcp_erp_port_strategy_open_common(erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959}
960
Christof Schmitt287ac012008-07-02 10:56:40 +0200961static void zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
Swen Schillig44cc76f2008-10-01 12:42:16 +0200963 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
Christof Schmitt287ac012008-07-02 10:56:40 +0200964 ZFCP_STATUS_UNIT_SHARED |
965 ZFCP_STATUS_UNIT_READONLY,
966 &unit->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967}
968
Christof Schmitt287ac012008-07-02 10:56:40 +0200969static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action)
970{
971 int retval = zfcp_fsf_close_unit(erp_action);
972 if (retval == -ENOMEM)
973 return ZFCP_ERP_NOMEM;
974 erp_action->step = ZFCP_ERP_STEP_UNIT_CLOSING;
975 if (retval)
976 return ZFCP_ERP_FAILED;
977 return ZFCP_ERP_CONTINUES;
978}
979
980static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action)
981{
982 int retval = zfcp_fsf_open_unit(erp_action);
983 if (retval == -ENOMEM)
984 return ZFCP_ERP_NOMEM;
985 erp_action->step = ZFCP_ERP_STEP_UNIT_OPENING;
986 if (retval)
987 return ZFCP_ERP_FAILED;
988 return ZFCP_ERP_CONTINUES;
989}
990
991static int zfcp_erp_unit_strategy(struct zfcp_erp_action *erp_action)
992{
993 struct zfcp_unit *unit = erp_action->unit;
994
995 switch (erp_action->step) {
996 case ZFCP_ERP_STEP_UNINITIALIZED:
997 zfcp_erp_unit_strategy_clearstati(unit);
998 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
999 return zfcp_erp_unit_strategy_close(erp_action);
1000 /* already closed, fall through */
1001 case ZFCP_ERP_STEP_UNIT_CLOSING:
1002 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
1003 return ZFCP_ERP_FAILED;
1004 if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
1005 return ZFCP_ERP_EXIT;
1006 return zfcp_erp_unit_strategy_open(erp_action);
1007
1008 case ZFCP_ERP_STEP_UNIT_OPENING:
1009 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_OPEN)
1010 return ZFCP_ERP_SUCCEEDED;
1011 }
1012 return ZFCP_ERP_FAILED;
1013}
1014
1015static int zfcp_erp_strategy_check_unit(struct zfcp_unit *unit, int result)
1016{
1017 switch (result) {
1018 case ZFCP_ERP_SUCCEEDED :
1019 atomic_set(&unit->erp_counter, 0);
1020 zfcp_erp_unit_unblock(unit);
1021 break;
1022 case ZFCP_ERP_FAILED :
1023 atomic_inc(&unit->erp_counter);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001024 if (atomic_read(&unit->erp_counter) > ZFCP_MAX_ERPS) {
1025 dev_err(&unit->port->adapter->ccw_device->dev,
1026 "ERP failed for unit 0x%016Lx on "
1027 "port 0x%016Lx\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001028 (unsigned long long)unit->fcp_lun,
1029 (unsigned long long)unit->port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001030 zfcp_erp_unit_failed(unit, "erusck1", NULL);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001031 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001032 break;
1033 }
1034
1035 if (atomic_read(&unit->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1036 zfcp_erp_unit_block(unit, 0);
1037 result = ZFCP_ERP_EXIT;
1038 }
1039 return result;
1040}
1041
1042static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
1043{
1044 switch (result) {
1045 case ZFCP_ERP_SUCCEEDED :
1046 atomic_set(&port->erp_counter, 0);
1047 zfcp_erp_port_unblock(port);
1048 break;
1049
1050 case ZFCP_ERP_FAILED :
1051 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) {
1052 zfcp_erp_port_block(port, 0);
1053 result = ZFCP_ERP_EXIT;
1054 }
1055 atomic_inc(&port->erp_counter);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001056 if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
1057 dev_err(&port->adapter->ccw_device->dev,
1058 "ERP failed for remote port 0x%016Lx\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001059 (unsigned long long)port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001060 zfcp_erp_port_failed(port, "erpsck1", NULL);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001061 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001062 break;
1063 }
1064
1065 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1066 zfcp_erp_port_block(port, 0);
1067 result = ZFCP_ERP_EXIT;
1068 }
1069 return result;
1070}
1071
1072static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter,
1073 int result)
1074{
1075 switch (result) {
1076 case ZFCP_ERP_SUCCEEDED :
1077 atomic_set(&adapter->erp_counter, 0);
1078 zfcp_erp_adapter_unblock(adapter);
1079 break;
1080
1081 case ZFCP_ERP_FAILED :
1082 atomic_inc(&adapter->erp_counter);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001083 if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) {
1084 dev_err(&adapter->ccw_device->dev,
1085 "ERP cannot recover an error "
1086 "on the FCP device\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001087 zfcp_erp_adapter_failed(adapter, "erasck1", NULL);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001088 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001089 break;
1090 }
1091
1092 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1093 zfcp_erp_adapter_block(adapter, 0);
1094 result = ZFCP_ERP_EXIT;
1095 }
1096 return result;
1097}
1098
1099static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action,
1100 int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101{
1102 struct zfcp_adapter *adapter = erp_action->adapter;
1103 struct zfcp_port *port = erp_action->port;
1104 struct zfcp_unit *unit = erp_action->unit;
1105
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 switch (erp_action->action) {
1107
1108 case ZFCP_ERP_ACTION_REOPEN_UNIT:
1109 result = zfcp_erp_strategy_check_unit(unit, result);
1110 break;
1111
1112 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1113 case ZFCP_ERP_ACTION_REOPEN_PORT:
1114 result = zfcp_erp_strategy_check_port(port, result);
1115 break;
1116
1117 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1118 result = zfcp_erp_strategy_check_adapter(adapter, result);
1119 break;
1120 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 return result;
1122}
1123
Christof Schmitt287ac012008-07-02 10:56:40 +02001124static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125{
Christof Schmitt287ac012008-07-02 10:56:40 +02001126 int status = atomic_read(target_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
Christof Schmitt287ac012008-07-02 10:56:40 +02001128 if ((status & ZFCP_STATUS_COMMON_RUNNING) &&
1129 (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1130 return 1; /* take it online */
1131
1132 if (!(status & ZFCP_STATUS_COMMON_RUNNING) &&
1133 !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1134 return 1; /* take it offline */
1135
1136 return 0;
1137}
1138
1139static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
1140{
1141 int action = act->action;
1142 struct zfcp_adapter *adapter = act->adapter;
1143 struct zfcp_port *port = act->port;
1144 struct zfcp_unit *unit = act->unit;
1145 u32 erp_status = act->status;
1146
1147 switch (action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitt287ac012008-07-02 10:56:40 +02001149 if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) {
1150 _zfcp_erp_adapter_reopen(adapter,
1151 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001152 "ersscg1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001153 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 }
1155 break;
1156
1157 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1158 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitt287ac012008-07-02 10:56:40 +02001159 if (zfcp_erp_strat_change_det(&port->status, erp_status)) {
1160 _zfcp_erp_port_reopen(port,
1161 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001162 "ersscg2", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001163 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 }
1165 break;
1166
1167 case ZFCP_ERP_ACTION_REOPEN_UNIT:
Christof Schmitt287ac012008-07-02 10:56:40 +02001168 if (zfcp_erp_strat_change_det(&unit->status, erp_status)) {
1169 _zfcp_erp_unit_reopen(unit,
1170 ZFCP_STATUS_COMMON_ERP_FAILED,
Christof Schmittfdbd1c52010-09-08 14:39:54 +02001171 "ersscg3", NULL, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +02001172 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 }
1174 break;
1175 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001176 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177}
1178
Christof Schmitt287ac012008-07-02 10:56:40 +02001179static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180{
Christof Schmitt287ac012008-07-02 10:56:40 +02001181 struct zfcp_adapter *adapter = erp_action->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182
Christof Schmitt287ac012008-07-02 10:56:40 +02001183 adapter->erp_total_count--;
1184 if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1185 adapter->erp_low_mem_count--;
1186 erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 }
1188
Christof Schmitt287ac012008-07-02 10:56:40 +02001189 list_del(&erp_action->list);
Swen Schillig57717102009-08-18 15:43:21 +02001190 zfcp_dbf_rec_action("eractd1", erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
Christof Schmitt287ac012008-07-02 10:56:40 +02001192 switch (erp_action->action) {
1193 case ZFCP_ERP_ACTION_REOPEN_UNIT:
1194 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1195 &erp_action->unit->status);
1196 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197
Christof Schmitt287ac012008-07-02 10:56:40 +02001198 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1199 case ZFCP_ERP_ACTION_REOPEN_PORT:
1200 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1201 &erp_action->port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001203
1204 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1205 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1206 &erp_action->adapter->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 break;
1208 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209}
1210
Christof Schmitt287ac012008-07-02 10:56:40 +02001211static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001212{
Christof Schmitt287ac012008-07-02 10:56:40 +02001213 struct zfcp_adapter *adapter = act->adapter;
1214 struct zfcp_port *port = act->port;
1215 struct zfcp_unit *unit = act->unit;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001216
Christof Schmitt287ac012008-07-02 10:56:40 +02001217 switch (act->action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 case ZFCP_ERP_ACTION_REOPEN_UNIT:
Christof Schmittfdbd1c52010-09-08 14:39:54 +02001219 if (!(act->status & ZFCP_STATUS_ERP_NO_REF))
1220 put_device(&unit->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001222
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001224 if (result == ZFCP_ERP_SUCCEEDED)
1225 zfcp_scsi_schedule_rport_register(port);
Christof Schmitt57676202010-07-08 09:53:05 +02001226 /* fall through */
1227 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
Christof Schmitt615f59e2010-02-17 11:18:56 +01001228 put_device(&port->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001230
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001232 if (result == ZFCP_ERP_SUCCEEDED) {
Christof Schmittbd43a42b72008-12-25 13:38:50 +01001233 register_service_level(&adapter->service_level);
Swen Schillig9eae07e2009-11-24 16:54:06 +01001234 queue_work(adapter->work_queue, &adapter->scan_work);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001235 } else
1236 unregister_service_level(&adapter->service_level);
Swen Schilligf3450c72009-11-24 16:53:59 +01001237 kref_put(&adapter->ref, zfcp_adapter_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 }
1240}
1241
Christof Schmitt287ac012008-07-02 10:56:40 +02001242static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
1243{
1244 switch (erp_action->action) {
1245 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1246 return zfcp_erp_adapter_strategy(erp_action);
1247 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1248 return zfcp_erp_port_forced_strategy(erp_action);
1249 case ZFCP_ERP_ACTION_REOPEN_PORT:
1250 return zfcp_erp_port_strategy(erp_action);
1251 case ZFCP_ERP_ACTION_REOPEN_UNIT:
1252 return zfcp_erp_unit_strategy(erp_action);
1253 }
1254 return ZFCP_ERP_FAILED;
1255}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
Christof Schmitt287ac012008-07-02 10:56:40 +02001257static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
1258{
1259 int retval;
Christof Schmitt287ac012008-07-02 10:56:40 +02001260 unsigned long flags;
Swen Schilligecf0c772009-11-24 16:53:58 +01001261 struct zfcp_adapter *adapter = erp_action->adapter;
Christof Schmitt287ac012008-07-02 10:56:40 +02001262
Swen Schilligf3450c72009-11-24 16:53:59 +01001263 kref_get(&adapter->ref);
Christof Schmitt287ac012008-07-02 10:56:40 +02001264
Swen Schilligf3450c72009-11-24 16:53:59 +01001265 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001266 zfcp_erp_strategy_check_fsfreq(erp_action);
1267
1268 if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
1269 zfcp_erp_action_dequeue(erp_action);
1270 retval = ZFCP_ERP_DISMISSED;
1271 goto unlock;
1272 }
1273
Christof Schmitt9c785d92010-07-08 09:53:09 +02001274 if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
1275 retval = ZFCP_ERP_FAILED;
1276 goto check_target;
1277 }
1278
Christof Schmitt287ac012008-07-02 10:56:40 +02001279 zfcp_erp_action_to_running(erp_action);
1280
1281 /* no lock to allow for blocking operations */
Swen Schilligecf0c772009-11-24 16:53:58 +01001282 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001283 retval = zfcp_erp_strategy_do_action(erp_action);
Swen Schilligecf0c772009-11-24 16:53:58 +01001284 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001285
1286 if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED)
1287 retval = ZFCP_ERP_CONTINUES;
1288
1289 switch (retval) {
1290 case ZFCP_ERP_NOMEM:
1291 if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) {
1292 ++adapter->erp_low_mem_count;
1293 erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
1294 }
1295 if (adapter->erp_total_count == adapter->erp_low_mem_count)
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001296 _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001297 else {
1298 zfcp_erp_strategy_memwait(erp_action);
1299 retval = ZFCP_ERP_CONTINUES;
1300 }
1301 goto unlock;
1302
1303 case ZFCP_ERP_CONTINUES:
1304 if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1305 --adapter->erp_low_mem_count;
1306 erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
1307 }
1308 goto unlock;
1309 }
1310
Christof Schmitt9c785d92010-07-08 09:53:09 +02001311check_target:
Christof Schmitt287ac012008-07-02 10:56:40 +02001312 retval = zfcp_erp_strategy_check_target(erp_action, retval);
1313 zfcp_erp_action_dequeue(erp_action);
1314 retval = zfcp_erp_strategy_statechange(erp_action, retval);
1315 if (retval == ZFCP_ERP_EXIT)
1316 goto unlock;
Christof Schmitt85600f72009-07-13 15:06:09 +02001317 if (retval == ZFCP_ERP_SUCCEEDED)
1318 zfcp_erp_strategy_followup_success(erp_action);
1319 if (retval == ZFCP_ERP_FAILED)
1320 zfcp_erp_strategy_followup_failed(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +02001321
1322 unlock:
Swen Schilligecf0c772009-11-24 16:53:58 +01001323 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001324
1325 if (retval != ZFCP_ERP_CONTINUES)
1326 zfcp_erp_action_cleanup(erp_action, retval);
1327
Swen Schilligf3450c72009-11-24 16:53:59 +01001328 kref_put(&adapter->ref, zfcp_adapter_release);
Christof Schmitt287ac012008-07-02 10:56:40 +02001329 return retval;
1330}
1331
1332static int zfcp_erp_thread(void *data)
1333{
1334 struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
1335 struct list_head *next;
1336 struct zfcp_erp_action *act;
1337 unsigned long flags;
1338
Christof Schmitt347c6a92009-08-18 15:43:25 +02001339 for (;;) {
Swen Schillig57717102009-08-18 15:43:21 +02001340 zfcp_dbf_rec_thread_lock("erthrd1", adapter->dbf);
Christof Schmitt347c6a92009-08-18 15:43:25 +02001341 wait_event_interruptible(adapter->erp_ready_wq,
1342 !list_empty(&adapter->erp_ready_head) ||
1343 kthread_should_stop());
Swen Schillig57717102009-08-18 15:43:21 +02001344 zfcp_dbf_rec_thread_lock("erthrd2", adapter->dbf);
Swen Schillig94ab4b32009-04-17 15:08:06 +02001345
Christof Schmitt347c6a92009-08-18 15:43:25 +02001346 if (kthread_should_stop())
1347 break;
1348
Christof Schmitt287ac012008-07-02 10:56:40 +02001349 write_lock_irqsave(&adapter->erp_lock, flags);
1350 next = adapter->erp_ready_head.next;
1351 write_unlock_irqrestore(&adapter->erp_lock, flags);
1352
1353 if (next != &adapter->erp_ready_head) {
1354 act = list_entry(next, struct zfcp_erp_action, list);
1355
1356 /* there is more to come after dismission, no notify */
1357 if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED)
1358 zfcp_erp_wakeup(adapter);
1359 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001360 }
1361
Christof Schmitt287ac012008-07-02 10:56:40 +02001362 return 0;
1363}
1364
1365/**
1366 * zfcp_erp_thread_setup - Start ERP thread for adapter
1367 * @adapter: Adapter to start the ERP thread for
1368 *
1369 * Returns 0 on success or error code from kernel_thread()
1370 */
1371int zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
1372{
Christof Schmitt347c6a92009-08-18 15:43:25 +02001373 struct task_struct *thread;
Christof Schmitt287ac012008-07-02 10:56:40 +02001374
Christof Schmitt347c6a92009-08-18 15:43:25 +02001375 thread = kthread_run(zfcp_erp_thread, adapter, "zfcperp%s",
1376 dev_name(&adapter->ccw_device->dev));
1377 if (IS_ERR(thread)) {
Christof Schmitt287ac012008-07-02 10:56:40 +02001378 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001379 "Creating an ERP thread for the FCP device failed.\n");
Christof Schmitt347c6a92009-08-18 15:43:25 +02001380 return PTR_ERR(thread);
Christof Schmitt287ac012008-07-02 10:56:40 +02001381 }
Christof Schmitt347c6a92009-08-18 15:43:25 +02001382
1383 adapter->erp_thread = thread;
Christof Schmitt287ac012008-07-02 10:56:40 +02001384 return 0;
1385}
1386
1387/**
1388 * zfcp_erp_thread_kill - Stop ERP thread.
1389 * @adapter: Adapter where the ERP thread should be stopped.
1390 *
1391 * The caller of this routine ensures that the specified adapter has
1392 * been shut down and that this operation has been completed. Thus,
1393 * there are no pending erp_actions which would need to be handled
1394 * here.
1395 */
1396void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
1397{
Christof Schmitt347c6a92009-08-18 15:43:25 +02001398 kthread_stop(adapter->erp_thread);
1399 adapter->erp_thread = NULL;
Christof Schmitt143bb6b2009-08-18 15:43:27 +02001400 WARN_ON(!list_empty(&adapter->erp_ready_head));
1401 WARN_ON(!list_empty(&adapter->erp_running_head));
Christof Schmitt287ac012008-07-02 10:56:40 +02001402}
1403
1404/**
1405 * zfcp_erp_adapter_failed - Set adapter status to failed.
1406 * @adapter: Failed adapter.
1407 * @id: Event id for debug trace.
1408 * @ref: Reference for debug trace.
1409 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001410void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +02001411{
1412 zfcp_erp_modify_adapter_status(adapter, id, ref,
1413 ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
Christof Schmitt287ac012008-07-02 10:56:40 +02001414}
1415
1416/**
1417 * zfcp_erp_port_failed - Set port status to failed.
1418 * @port: Failed port.
1419 * @id: Event id for debug trace.
1420 * @ref: Reference for debug trace.
1421 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001422void zfcp_erp_port_failed(struct zfcp_port *port, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +02001423{
1424 zfcp_erp_modify_port_status(port, id, ref,
1425 ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
Christof Schmitt287ac012008-07-02 10:56:40 +02001426}
1427
1428/**
1429 * zfcp_erp_unit_failed - Set unit status to failed.
1430 * @unit: Failed unit.
1431 * @id: Event id for debug trace.
1432 * @ref: Reference for debug trace.
1433 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001434void zfcp_erp_unit_failed(struct zfcp_unit *unit, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +02001435{
1436 zfcp_erp_modify_unit_status(unit, id, ref,
1437 ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
Christof Schmitt287ac012008-07-02 10:56:40 +02001438}
1439
1440/**
1441 * zfcp_erp_wait - wait for completion of error recovery on an adapter
1442 * @adapter: adapter for which to wait for completion of its error recovery
1443 */
1444void zfcp_erp_wait(struct zfcp_adapter *adapter)
1445{
1446 wait_event(adapter->erp_done_wqh,
1447 !(atomic_read(&adapter->status) &
1448 ZFCP_STATUS_ADAPTER_ERP_PENDING));
1449}
1450
1451/**
1452 * zfcp_erp_modify_adapter_status - change adapter status bits
1453 * @adapter: adapter to change the status
1454 * @id: id for the debug trace
1455 * @ref: reference for the debug trace
1456 * @mask: status bits to change
1457 * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1458 *
1459 * Changes in common status bits are propagated to attached ports and units.
1460 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001461void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +02001462 void *ref, u32 mask, int set_or_clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 struct zfcp_port *port;
Swen Schilligecf0c772009-11-24 16:53:58 +01001465 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +02001466 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
Christof Schmitt287ac012008-07-02 10:56:40 +02001468 if (set_or_clear == ZFCP_SET) {
1469 if (status_change_set(mask, &adapter->status))
Swen Schillig57717102009-08-18 15:43:21 +02001470 zfcp_dbf_rec_adapter(id, ref, adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +02001471 atomic_set_mask(mask, &adapter->status);
1472 } else {
1473 if (status_change_clear(mask, &adapter->status))
Swen Schillig57717102009-08-18 15:43:21 +02001474 zfcp_dbf_rec_adapter(id, ref, adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +02001475 atomic_clear_mask(mask, &adapter->status);
1476 if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
1477 atomic_set(&adapter->erp_counter, 0);
1478 }
1479
Swen Schilligecf0c772009-11-24 16:53:58 +01001480 if (common_mask) {
1481 read_lock_irqsave(&adapter->port_list_lock, flags);
1482 list_for_each_entry(port, &adapter->port_list, list)
Christof Schmitt287ac012008-07-02 10:56:40 +02001483 zfcp_erp_modify_port_status(port, id, ref, common_mask,
1484 set_or_clear);
Swen Schilligecf0c772009-11-24 16:53:58 +01001485 read_unlock_irqrestore(&adapter->port_list_lock, flags);
1486 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487}
1488
Christof Schmitt287ac012008-07-02 10:56:40 +02001489/**
1490 * zfcp_erp_modify_port_status - change port status bits
1491 * @port: port to change the status bits
1492 * @id: id for the debug trace
1493 * @ref: reference for the debug trace
1494 * @mask: status bits to change
1495 * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1496 *
1497 * Changes in common status bits are propagated to attached units.
1498 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001499void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref,
Christof Schmitt287ac012008-07-02 10:56:40 +02001500 u32 mask, int set_or_clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 struct zfcp_unit *unit;
Swen Schilligecf0c772009-11-24 16:53:58 +01001503 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +02001504 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505
Christof Schmitt287ac012008-07-02 10:56:40 +02001506 if (set_or_clear == ZFCP_SET) {
1507 if (status_change_set(mask, &port->status))
Swen Schillig57717102009-08-18 15:43:21 +02001508 zfcp_dbf_rec_port(id, ref, port);
Christof Schmitt287ac012008-07-02 10:56:40 +02001509 atomic_set_mask(mask, &port->status);
1510 } else {
1511 if (status_change_clear(mask, &port->status))
Swen Schillig57717102009-08-18 15:43:21 +02001512 zfcp_dbf_rec_port(id, ref, port);
Christof Schmitt287ac012008-07-02 10:56:40 +02001513 atomic_clear_mask(mask, &port->status);
1514 if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
1515 atomic_set(&port->erp_counter, 0);
1516 }
1517
Swen Schilligecf0c772009-11-24 16:53:58 +01001518 if (common_mask) {
1519 read_lock_irqsave(&port->unit_list_lock, flags);
1520 list_for_each_entry(unit, &port->unit_list, list)
Christof Schmitt287ac012008-07-02 10:56:40 +02001521 zfcp_erp_modify_unit_status(unit, id, ref, common_mask,
1522 set_or_clear);
Swen Schilligecf0c772009-11-24 16:53:58 +01001523 read_unlock_irqrestore(&port->unit_list_lock, flags);
1524 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525}
1526
Christof Schmitt287ac012008-07-02 10:56:40 +02001527/**
1528 * zfcp_erp_modify_unit_status - change unit status bits
1529 * @unit: unit to change the status bits
1530 * @id: id for the debug trace
1531 * @ref: reference for the debug trace
1532 * @mask: status bits to change
1533 * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1534 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001535void zfcp_erp_modify_unit_status(struct zfcp_unit *unit, char *id, void *ref,
Christof Schmitt287ac012008-07-02 10:56:40 +02001536 u32 mask, int set_or_clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537{
Christof Schmitt287ac012008-07-02 10:56:40 +02001538 if (set_or_clear == ZFCP_SET) {
1539 if (status_change_set(mask, &unit->status))
Swen Schillig57717102009-08-18 15:43:21 +02001540 zfcp_dbf_rec_unit(id, ref, unit);
Christof Schmitt287ac012008-07-02 10:56:40 +02001541 atomic_set_mask(mask, &unit->status);
1542 } else {
1543 if (status_change_clear(mask, &unit->status))
Swen Schillig57717102009-08-18 15:43:21 +02001544 zfcp_dbf_rec_unit(id, ref, unit);
Christof Schmitt287ac012008-07-02 10:56:40 +02001545 atomic_clear_mask(mask, &unit->status);
1546 if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) {
1547 atomic_set(&unit->erp_counter, 0);
1548 }
1549 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550}
1551
Christof Schmitt287ac012008-07-02 10:56:40 +02001552/**
1553 * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP
1554 * @port: The "boxed" port.
1555 * @id: The debug trace id.
1556 * @id: Reference for the debug trace.
1557 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001558void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref)
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001559{
Martin Peschke698ec0162008-03-27 14:22:02 +01001560 zfcp_erp_modify_port_status(port, id, ref,
1561 ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
Martin Peschke9467a9b2008-03-27 14:22:03 +01001562 zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001563}
1564
Christof Schmitt287ac012008-07-02 10:56:40 +02001565/**
1566 * zfcp_erp_unit_boxed - Mark unit as "boxed" and start ERP
1567 * @port: The "boxed" unit.
1568 * @id: The debug trace id.
1569 * @id: Reference for the debug trace.
1570 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001571void zfcp_erp_unit_boxed(struct zfcp_unit *unit, char *id, void *ref)
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001572{
Martin Peschke698ec0162008-03-27 14:22:02 +01001573 zfcp_erp_modify_unit_status(unit, id, ref,
1574 ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
Martin Peschke9467a9b2008-03-27 14:22:03 +01001575 zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001576}
1577
Christof Schmitt287ac012008-07-02 10:56:40 +02001578/**
1579 * zfcp_erp_port_access_denied - Adapter denied access to port.
1580 * @port: port where access has been denied
1581 * @id: id for debug trace
1582 * @ref: reference for debug trace
1583 *
1584 * Since the adapter has denied access, stop using the port and the
1585 * attached units.
1586 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001587void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588{
Martin Peschke698ec0162008-03-27 14:22:02 +01001589 zfcp_erp_modify_port_status(port, id, ref,
1590 ZFCP_STATUS_COMMON_ERP_FAILED |
1591 ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592}
1593
Christof Schmitt287ac012008-07-02 10:56:40 +02001594/**
1595 * zfcp_erp_unit_access_denied - Adapter denied access to unit.
1596 * @unit: unit where access has been denied
1597 * @id: id for debug trace
1598 * @ref: reference for debug trace
1599 *
1600 * Since the adapter has denied access, stop using the unit.
1601 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001602void zfcp_erp_unit_access_denied(struct zfcp_unit *unit, char *id, void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603{
Martin Peschke698ec0162008-03-27 14:22:02 +01001604 zfcp_erp_modify_unit_status(unit, id, ref,
1605 ZFCP_STATUS_COMMON_ERP_FAILED |
1606 ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607}
1608
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001609static void zfcp_erp_unit_access_changed(struct zfcp_unit *unit, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +02001610 void *ref)
1611{
1612 int status = atomic_read(&unit->status);
1613 if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
1614 ZFCP_STATUS_COMMON_ACCESS_BOXED)))
1615 return;
1616
1617 zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
1618}
1619
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001620static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +02001621 void *ref)
1622{
1623 struct zfcp_unit *unit;
Swen Schilligecf0c772009-11-24 16:53:58 +01001624 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +02001625 int status = atomic_read(&port->status);
1626
1627 if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
1628 ZFCP_STATUS_COMMON_ACCESS_BOXED))) {
Swen Schilligecf0c772009-11-24 16:53:58 +01001629 read_lock_irqsave(&port->unit_list_lock, flags);
1630 list_for_each_entry(unit, &port->unit_list, list)
Swen Schillig5ab944f2008-10-01 12:42:17 +02001631 zfcp_erp_unit_access_changed(unit, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +01001632 read_unlock_irqrestore(&port->unit_list_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001633 return;
1634 }
1635
1636 zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
1637}
1638
1639/**
1640 * zfcp_erp_adapter_access_changed - Process change in adapter ACT
1641 * @adapter: Adapter where the Access Control Table (ACT) changed
1642 * @id: Id for debug trace
1643 * @ref: Reference for debug trace
1644 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001645void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id,
Martin Peschke1f6f7122008-04-18 12:51:55 +02001646 void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 unsigned long flags;
Swen Schilligecf0c772009-11-24 16:53:58 +01001649 struct zfcp_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001651 if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
1652 return;
1653
Swen Schilligecf0c772009-11-24 16:53:58 +01001654 read_lock_irqsave(&adapter->port_list_lock, flags);
1655 list_for_each_entry(port, &adapter->port_list, list)
Swen Schillig5ab944f2008-10-01 12:42:17 +02001656 zfcp_erp_port_access_changed(port, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +01001657 read_unlock_irqrestore(&adapter->port_list_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658}