blob: 734fc838931fd0edd8b21758d7ec4b0c08121458 [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 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,
Christof Schmittb62a8d92010-09-08 14:39:55 +020033 ZFCP_ERP_STEP_LUN_CLOSING = 0x1000,
34 ZFCP_ERP_STEP_LUN_OPENING = 0x2000,
Christof Schmitt287ac012008-07-02 10:56:40 +020035};
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Christof Schmitt287ac012008-07-02 10:56:40 +020037enum zfcp_erp_act_type {
Christof Schmittb62a8d92010-09-08 14:39:55 +020038 ZFCP_ERP_ACTION_REOPEN_LUN = 1,
Christof Schmitt287ac012008-07-02 10:56:40 +020039 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 Schmittb62a8d92010-09-08 14:39:55 +020092static void zfcp_erp_action_dismiss_lun(struct scsi_device *sdev)
Christof Schmitt287ac012008-07-02 10:56:40 +020093{
Christof Schmittb62a8d92010-09-08 14:39:55 +020094 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
95
96 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
97 zfcp_erp_action_dismiss(&zfcp_sdev->erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +020098}
99
100static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
101{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200102 struct scsi_device *sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +0200103
104 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
105 zfcp_erp_action_dismiss(&port->erp_action);
Christof Schmittb62a8d92010-09-08 14:39:55 +0200106 else
107 shost_for_each_device(sdev, port->adapter->scsi_host)
108 if (sdev_to_zfcp(sdev)->port == port)
109 zfcp_erp_action_dismiss_lun(sdev);
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,
Christof Schmittb62a8d92010-09-08 14:39:55 +0200128 struct scsi_device *sdev)
Christof Schmitt287ac012008-07-02 10:56:40 +0200129{
130 int need = want;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200131 int l_status, p_status, a_status;
132 struct zfcp_scsi_dev *zfcp_sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +0200133
134 switch (want) {
Christof Schmittb62a8d92010-09-08 14:39:55 +0200135 case ZFCP_ERP_ACTION_REOPEN_LUN:
136 zfcp_sdev = sdev_to_zfcp(sdev);
137 l_status = atomic_read(&zfcp_sdev->status);
138 if (l_status & ZFCP_STATUS_COMMON_ERP_INUSE)
Christof Schmitt287ac012008-07-02 10:56:40 +0200139 return 0;
140 p_status = atomic_read(&port->status);
141 if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) ||
142 p_status & ZFCP_STATUS_COMMON_ERP_FAILED)
143 return 0;
144 if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
145 need = ZFCP_ERP_ACTION_REOPEN_PORT;
146 /* fall through */
Christof Schmitt287ac012008-07-02 10:56:40 +0200147 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
148 p_status = atomic_read(&port->status);
Christof Schmitt097ef3b2010-07-08 09:53:06 +0200149 if (!(p_status & ZFCP_STATUS_COMMON_OPEN))
150 need = ZFCP_ERP_ACTION_REOPEN_PORT;
151 /* fall through */
152 case ZFCP_ERP_ACTION_REOPEN_PORT:
153 p_status = atomic_read(&port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200154 if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
155 return 0;
156 a_status = atomic_read(&adapter->status);
157 if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) ||
158 a_status & ZFCP_STATUS_COMMON_ERP_FAILED)
159 return 0;
160 if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))
161 need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
162 /* fall through */
163 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
164 a_status = atomic_read(&adapter->status);
165 if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
166 return 0;
Christof Schmitt143bb6b2009-08-18 15:43:27 +0200167 if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) &&
168 !(a_status & ZFCP_STATUS_COMMON_OPEN))
169 return 0; /* shutdown requested for closed adapter */
Christof Schmitt287ac012008-07-02 10:56:40 +0200170 }
171
172 return need;
173}
174
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200175static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
Christof Schmitt287ac012008-07-02 10:56:40 +0200176 struct zfcp_adapter *adapter,
177 struct zfcp_port *port,
Christof Schmittb62a8d92010-09-08 14:39:55 +0200178 struct scsi_device *sdev)
Christof Schmitt287ac012008-07-02 10:56:40 +0200179{
180 struct zfcp_erp_action *erp_action;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200181 struct zfcp_scsi_dev *zfcp_sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +0200182
183 switch (need) {
Christof Schmittb62a8d92010-09-08 14:39:55 +0200184 case ZFCP_ERP_ACTION_REOPEN_LUN:
185 zfcp_sdev = sdev_to_zfcp(sdev);
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200186 if (!(act_status & ZFCP_STATUS_ERP_NO_REF))
Christof Schmittb62a8d92010-09-08 14:39:55 +0200187 if (scsi_device_get(sdev))
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200188 return NULL;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200189 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
190 &zfcp_sdev->status);
191 erp_action = &zfcp_sdev->erp_action;
192 if (!(atomic_read(&zfcp_sdev->status) &
193 ZFCP_STATUS_COMMON_RUNNING))
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200194 act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
Christof Schmitt287ac012008-07-02 10:56:40 +0200195 break;
196
197 case ZFCP_ERP_ACTION_REOPEN_PORT:
198 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
Christof Schmitt615f59e2010-02-17 11:18:56 +0100199 if (!get_device(&port->dev))
Swen Schillig6b183332009-11-24 16:54:05 +0100200 return NULL;
Christof Schmitt287ac012008-07-02 10:56:40 +0200201 zfcp_erp_action_dismiss_port(port);
202 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
203 erp_action = &port->erp_action;
204 if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200205 act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
Christof Schmitt287ac012008-07-02 10:56:40 +0200206 break;
207
208 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Swen Schilligf3450c72009-11-24 16:53:59 +0100209 kref_get(&adapter->ref);
Christof Schmitt287ac012008-07-02 10:56:40 +0200210 zfcp_erp_action_dismiss_adapter(adapter);
211 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
212 erp_action = &adapter->erp_action;
213 if (!(atomic_read(&adapter->status) &
214 ZFCP_STATUS_COMMON_RUNNING))
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200215 act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
Christof Schmitt287ac012008-07-02 10:56:40 +0200216 break;
217
218 default:
219 return NULL;
220 }
221
222 memset(erp_action, 0, sizeof(struct zfcp_erp_action));
223 erp_action->adapter = adapter;
224 erp_action->port = port;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200225 erp_action->sdev = sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +0200226 erp_action->action = need;
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200227 erp_action->status = act_status;
Christof Schmitt287ac012008-07-02 10:56:40 +0200228
229 return erp_action;
230}
231
232static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
233 struct zfcp_port *port,
Christof Schmittb62a8d92010-09-08 14:39:55 +0200234 struct scsi_device *sdev,
235 char *id, void *ref, u32 act_status)
Christof Schmitt287ac012008-07-02 10:56:40 +0200236{
237 int retval = 1, need;
238 struct zfcp_erp_action *act = NULL;
239
Christof Schmitt347c6a92009-08-18 15:43:25 +0200240 if (!adapter->erp_thread)
Christof Schmitt287ac012008-07-02 10:56:40 +0200241 return -EIO;
242
Christof Schmittb62a8d92010-09-08 14:39:55 +0200243 need = zfcp_erp_required_act(want, adapter, port, sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +0200244 if (!need)
245 goto out;
246
Christof Schmittb62a8d92010-09-08 14:39:55 +0200247 act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +0200248 if (!act)
249 goto out;
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200250 atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200251 ++adapter->erp_total_count;
252 list_add_tail(&act->list, &adapter->erp_ready_head);
Christof Schmitt347c6a92009-08-18 15:43:25 +0200253 wake_up(&adapter->erp_ready_wq);
Swen Schillig57717102009-08-18 15:43:21 +0200254 zfcp_dbf_rec_thread("eracte1", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200255 retval = 0;
256 out:
Christof Schmittb62a8d92010-09-08 14:39:55 +0200257 zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +0200258 return retval;
259}
260
261static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100262 int clear_mask, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200263{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 zfcp_erp_adapter_block(adapter, clear_mask);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100265 zfcp_scsi_schedule_rports_block(adapter);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Christof Schmitt287ac012008-07-02 10:56:40 +0200267 /* ensure propagation of failed status to new devices */
268 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100269 zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200270 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200272 return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200273 adapter, NULL, NULL, id, ref, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274}
275
276/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200277 * zfcp_erp_adapter_reopen - Reopen adapter.
278 * @adapter: Adapter to reopen.
279 * @clear: Status flags to clear.
280 * @id: Id for debug trace event.
281 * @ref: Reference for debug trace event.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200283void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100284 char *id, void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285{
Christof Schmitt287ac012008-07-02 10:56:40 +0200286 unsigned long flags;
287
Swen Schilligecf0c772009-11-24 16:53:58 +0100288 zfcp_erp_adapter_block(adapter, clear);
289 zfcp_scsi_schedule_rports_block(adapter);
290
291 write_lock_irqsave(&adapter->erp_lock, flags);
292 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
293 zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
294 else
295 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200296 NULL, NULL, id, ref, 0);
Swen Schilligecf0c772009-11-24 16:53:58 +0100297 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200298}
299
300/**
301 * zfcp_erp_adapter_shutdown - Shutdown adapter.
302 * @adapter: Adapter to shut down.
303 * @clear: Status flags to clear.
304 * @id: Id for debug trace event.
305 * @ref: Reference for debug trace event.
306 */
307void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100308 char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200309{
310 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
311 zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref);
312}
313
314/**
315 * zfcp_erp_port_shutdown - Shutdown port
316 * @port: Port to shut down.
317 * @clear: Status flags to clear.
318 * @id: Id for debug trace event.
319 * @ref: Reference for debug trace event.
320 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100321void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id,
322 void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200323{
324 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
325 zfcp_erp_port_reopen(port, clear | flags, id, ref);
326}
327
Christof Schmitt287ac012008-07-02 10:56:40 +0200328static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
329{
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100330 zfcp_erp_modify_port_status(port, "erpblk1", NULL,
Christof Schmitt287ac012008-07-02 10:56:40 +0200331 ZFCP_STATUS_COMMON_UNBLOCKED | clear,
332 ZFCP_CLEAR);
333}
334
335static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100336 int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200337{
338 zfcp_erp_port_block(port, clear);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100339 zfcp_scsi_schedule_rport_block(port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200340
341 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
342 return;
343
344 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200345 port->adapter, port, NULL, id, ref, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +0200346}
347
348/**
349 * zfcp_erp_port_forced_reopen - Forced close of port and open again
350 * @port: Port to force close and to reopen.
351 * @id: Id for debug trace event.
352 * @ref: Reference for debug trace event.
353 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100354void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +0200355 void *ref)
356{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 unsigned long flags;
358 struct zfcp_adapter *adapter = port->adapter;
359
Swen Schilligecf0c772009-11-24 16:53:58 +0100360 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200361 _zfcp_erp_port_forced_reopen(port, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100362 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200363}
364
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100365static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +0200366 void *ref)
367{
368 zfcp_erp_port_block(port, clear);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100369 zfcp_scsi_schedule_rport_block(port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200370
371 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
372 /* ensure propagation of failed status to new devices */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100373 zfcp_erp_port_failed(port, "erpreo1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200374 return -EIO;
375 }
376
377 return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200378 port->adapter, port, NULL, id, ref, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +0200379}
380
381/**
382 * zfcp_erp_port_reopen - trigger remote port recovery
383 * @port: port to recover
384 * @clear_mask: flags in port status to be cleared
385 *
386 * Returns 0 if recovery has been triggered, < 0 if not.
387 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100388int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200389{
Christof Schmitt287ac012008-07-02 10:56:40 +0200390 int retval;
Swen Schilligecf0c772009-11-24 16:53:58 +0100391 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +0200392 struct zfcp_adapter *adapter = port->adapter;
393
Swen Schilligecf0c772009-11-24 16:53:58 +0100394 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200395 retval = _zfcp_erp_port_reopen(port, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100396 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
398 return retval;
399}
400
Christof Schmittb62a8d92010-09-08 14:39:55 +0200401static void zfcp_erp_lun_block(struct scsi_device *sdev, int clear_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200403 zfcp_erp_modify_lun_status(sdev, "erlblk1", NULL,
404 ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask,
405 ZFCP_CLEAR);
Christof Schmitt287ac012008-07-02 10:56:40 +0200406}
407
Christof Schmittb62a8d92010-09-08 14:39:55 +0200408static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,
409 void *ref, u32 act_status)
Christof Schmitt287ac012008-07-02 10:56:40 +0200410{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200411 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
412 struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
Christof Schmittb62a8d92010-09-08 14:39:55 +0200414 zfcp_erp_lun_block(sdev, clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
Christof Schmittb62a8d92010-09-08 14:39:55 +0200416 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
Christof Schmitt287ac012008-07-02 10:56:40 +0200417 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Christof Schmittb62a8d92010-09-08 14:39:55 +0200419 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter,
420 zfcp_sdev->port, sdev, id, ref, act_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421}
422
423/**
Christof Schmittb62a8d92010-09-08 14:39:55 +0200424 * zfcp_erp_lun_reopen - initiate reopen of a LUN
425 * @sdev: SCSI device / LUN to be reopened
426 * @clear_mask: specifies flags in LUN status to be cleared
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 * Return: 0 on success, < 0 on error
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 */
Christof Schmittb62a8d92010-09-08 14:39:55 +0200429void zfcp_erp_lun_reopen(struct scsi_device *sdev, 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 Schmittb62a8d92010-09-08 14:39:55 +0200433 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
434 struct zfcp_port *port = zfcp_sdev->port;
Christof Schmitt287ac012008-07-02 10:56:40 +0200435 struct zfcp_adapter *adapter = port->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
Swen Schilligecf0c772009-11-24 16:53:58 +0100437 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmittb62a8d92010-09-08 14:39:55 +0200438 _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0);
Swen Schilligecf0c772009-11-24 16:53:58 +0100439 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440}
441
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200442/**
Christof Schmittb62a8d92010-09-08 14:39:55 +0200443 * zfcp_erp_lun_shutdown - Shutdown LUN
444 * @sdev: SCSI device / LUN to shut down.
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200445 * @clear: Status flags to clear.
446 * @id: Id for debug trace event.
447 * @ref: Reference for debug trace event.
448 */
Christof Schmittb62a8d92010-09-08 14:39:55 +0200449void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id,
450 void *ref)
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200451{
452 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200453 zfcp_erp_lun_reopen(sdev, clear | flags, id, ref);
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200454}
455
456/**
Christof Schmittb62a8d92010-09-08 14:39:55 +0200457 * zfcp_erp_lun_shutdown_wait - Shutdown LUN and wait for erp completion
458 * @sdev: SCSI device / LUN to shut down.
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200459 * @id: Id for debug trace event.
460 *
Christof Schmittb62a8d92010-09-08 14:39:55 +0200461 * Do not acquire a reference for the LUN when creating the ERP
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200462 * action. It is safe, because this function waits for the ERP to
Christof Schmittb62a8d92010-09-08 14:39:55 +0200463 * complete first. This allows to shutdown the LUN, even when the SCSI
464 * device is in the state SDEV_DEL when scsi_device_get will fail.
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200465 */
Christof Schmittb62a8d92010-09-08 14:39:55 +0200466void zfcp_erp_lun_shutdown_wait(struct scsi_device *sdev, char *id)
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200467{
468 unsigned long flags;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200469 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
470 struct zfcp_port *port = zfcp_sdev->port;
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200471 struct zfcp_adapter *adapter = port->adapter;
472 int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
473
474 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmittb62a8d92010-09-08 14:39:55 +0200475 _zfcp_erp_lun_reopen(sdev, clear, id, NULL, ZFCP_STATUS_ERP_NO_REF);
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200476 write_unlock_irqrestore(&adapter->erp_lock, flags);
477
478 zfcp_erp_wait(adapter);
479}
480
Christof Schmitt287ac012008-07-02 10:56:40 +0200481static int status_change_set(unsigned long mask, atomic_t *status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
Christof Schmitt287ac012008-07-02 10:56:40 +0200483 return (atomic_read(status) ^ mask) & mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484}
485
Christof Schmitt287ac012008-07-02 10:56:40 +0200486static int status_change_clear(unsigned long mask, atomic_t *status)
Martin Peschke698ec0162008-03-27 14:22:02 +0100487{
Christof Schmitt287ac012008-07-02 10:56:40 +0200488 return atomic_read(status) & mask;
Martin Peschke698ec0162008-03-27 14:22:02 +0100489}
490
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200491static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492{
Christof Schmitt287ac012008-07-02 10:56:40 +0200493 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status))
Swen Schillig57717102009-08-18 15:43:21 +0200494 zfcp_dbf_rec_adapter("eraubl1", NULL, adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200495 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496}
497
Christof Schmitt287ac012008-07-02 10:56:40 +0200498static void zfcp_erp_port_unblock(struct zfcp_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
Christof Schmitt287ac012008-07-02 10:56:40 +0200500 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status))
Swen Schillig57717102009-08-18 15:43:21 +0200501 zfcp_dbf_rec_port("erpubl1", NULL, port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200502 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503}
504
Christof Schmittb62a8d92010-09-08 14:39:55 +0200505static void zfcp_erp_lun_unblock(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200507 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
508
509 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status))
510 zfcp_dbf_rec_lun("erlubl1", NULL, sdev);
511 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512}
513
Christof Schmitt287ac012008-07-02 10:56:40 +0200514static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515{
Christof Schmitt287ac012008-07-02 10:56:40 +0200516 list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
Swen Schillig57717102009-08-18 15:43:21 +0200517 zfcp_dbf_rec_action("erator1", erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518}
519
Christof Schmitt287ac012008-07-02 10:56:40 +0200520static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521{
Christof Schmitt287ac012008-07-02 10:56:40 +0200522 struct zfcp_adapter *adapter = act->adapter;
Christof Schmitte60a6d62010-02-17 11:18:49 +0100523 struct zfcp_fsf_req *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Christof Schmitte60a6d62010-02-17 11:18:49 +0100525 if (!act->fsf_req_id)
Christof Schmitt287ac012008-07-02 10:56:40 +0200526 return;
527
Christof Schmittb6bd2fb2010-02-17 11:18:50 +0100528 spin_lock(&adapter->req_list->lock);
529 req = _zfcp_reqlist_find(adapter->req_list, act->fsf_req_id);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100530 if (req && req->erp_action == act) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200531 if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
532 ZFCP_STATUS_ERP_TIMEDOUT)) {
Christof Schmitte60a6d62010-02-17 11:18:49 +0100533 req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
Swen Schillig57717102009-08-18 15:43:21 +0200534 zfcp_dbf_rec_action("erscf_1", act);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100535 req->erp_action = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200537 if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
Swen Schillig57717102009-08-18 15:43:21 +0200538 zfcp_dbf_rec_action("erscf_2", act);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100539 if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
540 act->fsf_req_id = 0;
Christof Schmitt287ac012008-07-02 10:56:40 +0200541 } else
Christof Schmitte60a6d62010-02-17 11:18:49 +0100542 act->fsf_req_id = 0;
Christof Schmittb6bd2fb2010-02-17 11:18:50 +0100543 spin_unlock(&adapter->req_list->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544}
545
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200546/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200547 * zfcp_erp_notify - Trigger ERP action.
548 * @erp_action: ERP action to continue.
549 * @set_mask: ERP action status flags to set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200551void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552{
553 struct zfcp_adapter *adapter = erp_action->adapter;
554 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200557 if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
558 erp_action->status |= set_mask;
559 zfcp_erp_action_ready(erp_action);
560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562}
563
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200564/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200565 * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request
566 * @data: ERP action (from timer data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200568void zfcp_erp_timeout_handler(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569{
Christof Schmitt287ac012008-07-02 10:56:40 +0200570 struct zfcp_erp_action *act = (struct zfcp_erp_action *) data;
571 zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572}
573
Christof Schmitt287ac012008-07-02 10:56:40 +0200574static void zfcp_erp_memwait_handler(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575{
Christof Schmitt287ac012008-07-02 10:56:40 +0200576 zfcp_erp_notify((struct zfcp_erp_action *)data, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577}
578
Christof Schmitt287ac012008-07-02 10:56:40 +0200579static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 init_timer(&erp_action->timer);
582 erp_action->timer.function = zfcp_erp_memwait_handler;
583 erp_action->timer.data = (unsigned long) erp_action;
Christof Schmitt287ac012008-07-02 10:56:40 +0200584 erp_action->timer.expires = jiffies + HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 add_timer(&erp_action->timer);
Christof Schmitt287ac012008-07-02 10:56:40 +0200586}
587
588static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100589 int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200590{
591 struct zfcp_port *port;
592
Swen Schilligecf0c772009-11-24 16:53:58 +0100593 read_lock(&adapter->port_list_lock);
594 list_for_each_entry(port, &adapter->port_list, list)
Swen Schillig5ab944f2008-10-01 12:42:17 +0200595 _zfcp_erp_port_reopen(port, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100596 read_unlock(&adapter->port_list_lock);
Christof Schmitt287ac012008-07-02 10:56:40 +0200597}
598
Christof Schmittb62a8d92010-09-08 14:39:55 +0200599static void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear,
600 char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200601{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200602 struct scsi_device *sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +0200603
Christof Schmittb62a8d92010-09-08 14:39:55 +0200604 shost_for_each_device(sdev, port->adapter->scsi_host)
605 if (sdev_to_zfcp(sdev)->port == port)
606 _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +0200607}
608
Christof Schmitt85600f72009-07-13 15:06:09 +0200609static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
Christof Schmitt287ac012008-07-02 10:56:40 +0200610{
Christof Schmitt287ac012008-07-02 10:56:40 +0200611 switch (act->action) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200612 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitt85600f72009-07-13 15:06:09 +0200613 _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200614 break;
Christof Schmitt287ac012008-07-02 10:56:40 +0200615 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
Christof Schmitt85600f72009-07-13 15:06:09 +0200616 _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200617 break;
Christof Schmitt287ac012008-07-02 10:56:40 +0200618 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitt85600f72009-07-13 15:06:09 +0200619 _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200620 break;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200621 case ZFCP_ERP_ACTION_REOPEN_LUN:
622 _zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", NULL, 0);
Christof Schmitt85600f72009-07-13 15:06:09 +0200623 break;
624 }
625}
626
627static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act)
628{
629 switch (act->action) {
630 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
631 _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL);
632 break;
633 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
634 _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL);
635 break;
636 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmittb62a8d92010-09-08 14:39:55 +0200637 _zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200638 break;
639 }
640}
641
642static void zfcp_erp_wakeup(struct zfcp_adapter *adapter)
643{
644 unsigned long flags;
645
Swen Schilligecf0c772009-11-24 16:53:58 +0100646 read_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200647 if (list_empty(&adapter->erp_ready_head) &&
648 list_empty(&adapter->erp_running_head)) {
649 atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING,
650 &adapter->status);
651 wake_up(&adapter->erp_done_wqh);
652 }
Swen Schilligecf0c772009-11-24 16:53:58 +0100653 read_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200654}
655
656static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
657{
Swen Schillig564e1c82009-08-18 15:43:19 +0200658 struct zfcp_qdio *qdio = act->adapter->qdio;
659
660 if (zfcp_qdio_open(qdio))
Christof Schmitt287ac012008-07-02 10:56:40 +0200661 return ZFCP_ERP_FAILED;
Swen Schillig564e1c82009-08-18 15:43:19 +0200662 init_waitqueue_head(&qdio->req_q_wq);
Christof Schmitt287ac012008-07-02 10:56:40 +0200663 atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status);
664 return ZFCP_ERP_SUCCEEDED;
665}
666
667static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
668{
669 struct zfcp_port *port;
670 port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0,
671 adapter->peer_d_id);
672 if (IS_ERR(port)) /* error or port already attached */
673 return;
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100674 _zfcp_erp_port_reopen(port, 0, "ereptp1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200675}
676
677static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
678{
679 int retries;
680 int sleep = 1;
681 struct zfcp_adapter *adapter = erp_action->adapter;
682
683 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
684
685 for (retries = 7; retries; retries--) {
686 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
687 &adapter->status);
688 write_lock_irq(&adapter->erp_lock);
689 zfcp_erp_action_to_running(erp_action);
690 write_unlock_irq(&adapter->erp_lock);
691 if (zfcp_fsf_exchange_config_data(erp_action)) {
692 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
693 &adapter->status);
694 return ZFCP_ERP_FAILED;
695 }
696
Swen Schillig57717102009-08-18 15:43:21 +0200697 zfcp_dbf_rec_thread_lock("erasfx1", adapter->dbf);
Christof Schmitt347c6a92009-08-18 15:43:25 +0200698 wait_event(adapter->erp_ready_wq,
699 !list_empty(&adapter->erp_ready_head));
Swen Schillig57717102009-08-18 15:43:21 +0200700 zfcp_dbf_rec_thread_lock("erasfx2", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200701 if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
702 break;
703
704 if (!(atomic_read(&adapter->status) &
705 ZFCP_STATUS_ADAPTER_HOST_CON_INIT))
706 break;
707
708 ssleep(sleep);
709 sleep *= 2;
710 }
711
712 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
713 &adapter->status);
714
715 if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK))
716 return ZFCP_ERP_FAILED;
717
718 if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
719 zfcp_erp_enqueue_ptp_port(adapter);
720
721 return ZFCP_ERP_SUCCEEDED;
722}
723
724static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act)
725{
726 int ret;
727 struct zfcp_adapter *adapter = act->adapter;
728
Christof Schmitt287ac012008-07-02 10:56:40 +0200729 write_lock_irq(&adapter->erp_lock);
730 zfcp_erp_action_to_running(act);
731 write_unlock_irq(&adapter->erp_lock);
732
733 ret = zfcp_fsf_exchange_port_data(act);
734 if (ret == -EOPNOTSUPP)
735 return ZFCP_ERP_SUCCEEDED;
736 if (ret)
737 return ZFCP_ERP_FAILED;
738
Swen Schillig57717102009-08-18 15:43:21 +0200739 zfcp_dbf_rec_thread_lock("erasox1", adapter->dbf);
Christof Schmitt347c6a92009-08-18 15:43:25 +0200740 wait_event(adapter->erp_ready_wq,
741 !list_empty(&adapter->erp_ready_head));
Swen Schillig57717102009-08-18 15:43:21 +0200742 zfcp_dbf_rec_thread_lock("erasox2", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200743 if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
744 return ZFCP_ERP_FAILED;
745
746 return ZFCP_ERP_SUCCEEDED;
747}
748
749static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)
750{
751 if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED)
752 return ZFCP_ERP_FAILED;
753
754 if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)
755 return ZFCP_ERP_FAILED;
756
Christof Schmitt8d88cf32010-06-21 10:11:33 +0200757 if (mempool_resize(act->adapter->pool.status_read_data,
758 act->adapter->stat_read_buf_num, GFP_KERNEL))
759 return ZFCP_ERP_FAILED;
760
761 if (mempool_resize(act->adapter->pool.status_read_req,
762 act->adapter->stat_read_buf_num, GFP_KERNEL))
763 return ZFCP_ERP_FAILED;
764
Christof Schmitt64deb6e2010-04-30 18:09:36 +0200765 atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num);
Christof Schmitt287ac012008-07-02 10:56:40 +0200766 if (zfcp_status_read_refill(act->adapter))
767 return ZFCP_ERP_FAILED;
768
769 return ZFCP_ERP_SUCCEEDED;
770}
771
Swen Schilligcf13c082009-03-02 13:09:03 +0100772static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act)
Christof Schmitt287ac012008-07-02 10:56:40 +0200773{
Christof Schmitt287ac012008-07-02 10:56:40 +0200774 struct zfcp_adapter *adapter = act->adapter;
775
Christof Schmitt287ac012008-07-02 10:56:40 +0200776 /* close queues to ensure that buffers are not accessed by adapter */
Swen Schillig564e1c82009-08-18 15:43:19 +0200777 zfcp_qdio_close(adapter->qdio);
Christof Schmitt287ac012008-07-02 10:56:40 +0200778 zfcp_fsf_req_dismiss_all(adapter);
779 adapter->fsf_req_seq_no = 0;
Christof Schmitt55c770f2009-08-18 15:43:12 +0200780 zfcp_fc_wka_ports_force_offline(adapter->gs);
Christof Schmittb62a8d92010-09-08 14:39:55 +0200781 /* all ports and LUNs are closed */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100782 zfcp_erp_modify_adapter_status(adapter, "erascl1", NULL,
Christof Schmitt287ac012008-07-02 10:56:40 +0200783 ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
Swen Schilligcf13c082009-03-02 13:09:03 +0100784
Christof Schmitt287ac012008-07-02 10:56:40 +0200785 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
Swen Schilligcf13c082009-03-02 13:09:03 +0100786 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
787}
788
789static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act)
790{
791 struct zfcp_adapter *adapter = act->adapter;
792
793 if (zfcp_erp_adapter_strategy_open_qdio(act)) {
794 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
795 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
796 &adapter->status);
797 return ZFCP_ERP_FAILED;
798 }
799
800 if (zfcp_erp_adapter_strategy_open_fsf(act)) {
801 zfcp_erp_adapter_strategy_close(act);
802 return ZFCP_ERP_FAILED;
803 }
804
805 atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &adapter->status);
806
807 return ZFCP_ERP_SUCCEEDED;
Christof Schmitt287ac012008-07-02 10:56:40 +0200808}
809
810static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act)
811{
Swen Schilligcf13c082009-03-02 13:09:03 +0100812 struct zfcp_adapter *adapter = act->adapter;
Christof Schmitt287ac012008-07-02 10:56:40 +0200813
Swen Schilligcf13c082009-03-02 13:09:03 +0100814 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN) {
815 zfcp_erp_adapter_strategy_close(act);
816 if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
817 return ZFCP_ERP_EXIT;
818 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200819
Swen Schilligcf13c082009-03-02 13:09:03 +0100820 if (zfcp_erp_adapter_strategy_open(act)) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200821 ssleep(8);
Swen Schilligcf13c082009-03-02 13:09:03 +0100822 return ZFCP_ERP_FAILED;
823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
Swen Schilligcf13c082009-03-02 13:09:03 +0100825 return ZFCP_ERP_SUCCEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826}
827
Christof Schmitt287ac012008-07-02 10:56:40 +0200828static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829{
Christof Schmitt287ac012008-07-02 10:56:40 +0200830 int retval;
831
832 retval = zfcp_fsf_close_physical_port(act);
833 if (retval == -ENOMEM)
834 return ZFCP_ERP_NOMEM;
835 act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING;
836 if (retval)
837 return ZFCP_ERP_FAILED;
838
839 return ZFCP_ERP_CONTINUES;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840}
841
Christof Schmitt287ac012008-07-02 10:56:40 +0200842static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843{
Christof Schmitta5b11dd2009-03-02 13:08:54 +0100844 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200845}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Christof Schmitt287ac012008-07-02 10:56:40 +0200847static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
848{
849 struct zfcp_port *port = erp_action->port;
850 int status = atomic_read(&port->status);
851
852 switch (erp_action->step) {
853 case ZFCP_ERP_STEP_UNINITIALIZED:
854 zfcp_erp_port_strategy_clearstati(port);
855 if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) &&
856 (status & ZFCP_STATUS_COMMON_OPEN))
857 return zfcp_erp_port_forced_strategy_close(erp_action);
858 else
859 return ZFCP_ERP_FAILED;
860
861 case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
Christof Schmittddb3e0c2009-07-13 15:06:08 +0200862 if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN))
Christof Schmitt287ac012008-07-02 10:56:40 +0200863 return ZFCP_ERP_SUCCEEDED;
864 }
865 return ZFCP_ERP_FAILED;
866}
867
868static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action)
869{
870 int retval;
871
872 retval = zfcp_fsf_close_port(erp_action);
873 if (retval == -ENOMEM)
874 return ZFCP_ERP_NOMEM;
875 erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING;
876 if (retval)
877 return ZFCP_ERP_FAILED;
878 return ZFCP_ERP_CONTINUES;
879}
880
881static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action)
882{
883 int retval;
884
885 retval = zfcp_fsf_open_port(erp_action);
886 if (retval == -ENOMEM)
887 return ZFCP_ERP_NOMEM;
888 erp_action->step = ZFCP_ERP_STEP_PORT_OPENING;
889 if (retval)
890 return ZFCP_ERP_FAILED;
891 return ZFCP_ERP_CONTINUES;
892}
893
Christof Schmitt287ac012008-07-02 10:56:40 +0200894static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
895{
896 struct zfcp_adapter *adapter = act->adapter;
897 struct zfcp_port *port = act->port;
898
899 if (port->wwpn != adapter->peer_wwpn) {
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100900 zfcp_erp_port_failed(port, "eroptp1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200901 return ZFCP_ERP_FAILED;
902 }
903 port->d_id = adapter->peer_d_id;
Christof Schmitt287ac012008-07-02 10:56:40 +0200904 return zfcp_erp_port_strategy_open_port(act);
905}
906
907static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
908{
909 struct zfcp_adapter *adapter = act->adapter;
910 struct zfcp_port *port = act->port;
Christof Schmitt287ac012008-07-02 10:56:40 +0200911 int p_status = atomic_read(&port->status);
912
913 switch (act->step) {
914 case ZFCP_ERP_STEP_UNINITIALIZED:
915 case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
916 case ZFCP_ERP_STEP_PORT_CLOSING:
917 if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
918 return zfcp_erp_open_ptp_port(act);
Christof Schmittb98478d2008-12-19 16:56:59 +0100919 if (!port->d_id) {
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200920 zfcp_fc_trigger_did_lookup(port);
Christof Schmitt799b76d2009-08-18 15:43:20 +0200921 return ZFCP_ERP_EXIT;
Christof Schmitt287ac012008-07-02 10:56:40 +0200922 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200923 return zfcp_erp_port_strategy_open_port(act);
924
925 case ZFCP_ERP_STEP_PORT_OPENING:
926 /* D_ID might have changed during open */
Swen Schillig5ab944f2008-10-01 12:42:17 +0200927 if (p_status & ZFCP_STATUS_COMMON_OPEN) {
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200928 if (!port->d_id) {
929 zfcp_fc_trigger_did_lookup(port);
930 return ZFCP_ERP_EXIT;
Swen Schillig5ab944f2008-10-01 12:42:17 +0200931 }
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200932 return ZFCP_ERP_SUCCEEDED;
Swen Schillig5ab944f2008-10-01 12:42:17 +0200933 }
Swen Schilligea460a82009-05-15 13:18:20 +0200934 if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
935 port->d_id = 0;
Christof Schmittf7bd7c32010-07-08 09:53:10 +0200936 return ZFCP_ERP_FAILED;
Swen Schilligea460a82009-05-15 13:18:20 +0200937 }
938 /* fall through otherwise */
Christof Schmitt287ac012008-07-02 10:56:40 +0200939 }
940 return ZFCP_ERP_FAILED;
941}
942
Christof Schmitt287ac012008-07-02 10:56:40 +0200943static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
944{
945 struct zfcp_port *port = erp_action->port;
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200946 int p_status = atomic_read(&port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200947
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200948 if ((p_status & ZFCP_STATUS_COMMON_NOESC) &&
949 !(p_status & ZFCP_STATUS_COMMON_OPEN))
Swen Schillig5ab944f2008-10-01 12:42:17 +0200950 goto close_init_done;
951
Christof Schmitt287ac012008-07-02 10:56:40 +0200952 switch (erp_action->step) {
953 case ZFCP_ERP_STEP_UNINITIALIZED:
954 zfcp_erp_port_strategy_clearstati(port);
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200955 if (p_status & ZFCP_STATUS_COMMON_OPEN)
Christof Schmitt287ac012008-07-02 10:56:40 +0200956 return zfcp_erp_port_strategy_close(erp_action);
957 break;
958
959 case ZFCP_ERP_STEP_PORT_CLOSING:
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200960 if (p_status & ZFCP_STATUS_COMMON_OPEN)
Christof Schmitt287ac012008-07-02 10:56:40 +0200961 return ZFCP_ERP_FAILED;
962 break;
963 }
Swen Schillig5ab944f2008-10-01 12:42:17 +0200964
965close_init_done:
Christof Schmitt287ac012008-07-02 10:56:40 +0200966 if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
967 return ZFCP_ERP_EXIT;
Christof Schmitt287ac012008-07-02 10:56:40 +0200968
Swen Schillig5ab944f2008-10-01 12:42:17 +0200969 return zfcp_erp_port_strategy_open_common(erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970}
971
Christof Schmittb62a8d92010-09-08 14:39:55 +0200972static void zfcp_erp_lun_strategy_clearstati(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200974 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
975
Swen Schillig44cc76f2008-10-01 12:42:16 +0200976 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
Christof Schmittb62a8d92010-09-08 14:39:55 +0200977 ZFCP_STATUS_LUN_SHARED | ZFCP_STATUS_LUN_READONLY,
978 &zfcp_sdev->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979}
980
Christof Schmittb62a8d92010-09-08 14:39:55 +0200981static int zfcp_erp_lun_strategy_close(struct zfcp_erp_action *erp_action)
Christof Schmitt287ac012008-07-02 10:56:40 +0200982{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200983 int retval = zfcp_fsf_close_lun(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +0200984 if (retval == -ENOMEM)
985 return ZFCP_ERP_NOMEM;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200986 erp_action->step = ZFCP_ERP_STEP_LUN_CLOSING;
Christof Schmitt287ac012008-07-02 10:56:40 +0200987 if (retval)
988 return ZFCP_ERP_FAILED;
989 return ZFCP_ERP_CONTINUES;
990}
991
Christof Schmittb62a8d92010-09-08 14:39:55 +0200992static int zfcp_erp_lun_strategy_open(struct zfcp_erp_action *erp_action)
Christof Schmitt287ac012008-07-02 10:56:40 +0200993{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200994 int retval = zfcp_fsf_open_lun(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +0200995 if (retval == -ENOMEM)
996 return ZFCP_ERP_NOMEM;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200997 erp_action->step = ZFCP_ERP_STEP_LUN_OPENING;
Christof Schmitt287ac012008-07-02 10:56:40 +0200998 if (retval)
999 return ZFCP_ERP_FAILED;
1000 return ZFCP_ERP_CONTINUES;
1001}
1002
Christof Schmittb62a8d92010-09-08 14:39:55 +02001003static int zfcp_erp_lun_strategy(struct zfcp_erp_action *erp_action)
Christof Schmitt287ac012008-07-02 10:56:40 +02001004{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001005 struct scsi_device *sdev = erp_action->sdev;
1006 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +02001007
1008 switch (erp_action->step) {
1009 case ZFCP_ERP_STEP_UNINITIALIZED:
Christof Schmittb62a8d92010-09-08 14:39:55 +02001010 zfcp_erp_lun_strategy_clearstati(sdev);
1011 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
1012 return zfcp_erp_lun_strategy_close(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +02001013 /* already closed, fall through */
Christof Schmittb62a8d92010-09-08 14:39:55 +02001014 case ZFCP_ERP_STEP_LUN_CLOSING:
1015 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
Christof Schmitt287ac012008-07-02 10:56:40 +02001016 return ZFCP_ERP_FAILED;
1017 if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
1018 return ZFCP_ERP_EXIT;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001019 return zfcp_erp_lun_strategy_open(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +02001020
Christof Schmittb62a8d92010-09-08 14:39:55 +02001021 case ZFCP_ERP_STEP_LUN_OPENING:
1022 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
Christof Schmitt287ac012008-07-02 10:56:40 +02001023 return ZFCP_ERP_SUCCEEDED;
1024 }
1025 return ZFCP_ERP_FAILED;
1026}
1027
Christof Schmittb62a8d92010-09-08 14:39:55 +02001028static int zfcp_erp_strategy_check_lun(struct scsi_device *sdev, int result)
Christof Schmitt287ac012008-07-02 10:56:40 +02001029{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001030 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
1031
Christof Schmitt287ac012008-07-02 10:56:40 +02001032 switch (result) {
1033 case ZFCP_ERP_SUCCEEDED :
Christof Schmittb62a8d92010-09-08 14:39:55 +02001034 atomic_set(&zfcp_sdev->erp_counter, 0);
1035 zfcp_erp_lun_unblock(sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +02001036 break;
1037 case ZFCP_ERP_FAILED :
Christof Schmittb62a8d92010-09-08 14:39:55 +02001038 atomic_inc(&zfcp_sdev->erp_counter);
1039 if (atomic_read(&zfcp_sdev->erp_counter) > ZFCP_MAX_ERPS) {
1040 dev_err(&zfcp_sdev->port->adapter->ccw_device->dev,
1041 "ERP failed for LUN 0x%016Lx on "
Christof Schmittff3b24f2008-10-01 12:42:15 +02001042 "port 0x%016Lx\n",
Christof Schmittb62a8d92010-09-08 14:39:55 +02001043 (unsigned long long)zfcp_scsi_dev_lun(sdev),
1044 (unsigned long long)zfcp_sdev->port->wwpn);
1045 zfcp_erp_lun_failed(sdev, "ersckl1", NULL);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001046 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001047 break;
1048 }
1049
Christof Schmittb62a8d92010-09-08 14:39:55 +02001050 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1051 zfcp_erp_lun_block(sdev, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +02001052 result = ZFCP_ERP_EXIT;
1053 }
1054 return result;
1055}
1056
1057static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
1058{
1059 switch (result) {
1060 case ZFCP_ERP_SUCCEEDED :
1061 atomic_set(&port->erp_counter, 0);
1062 zfcp_erp_port_unblock(port);
1063 break;
1064
1065 case ZFCP_ERP_FAILED :
1066 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) {
1067 zfcp_erp_port_block(port, 0);
1068 result = ZFCP_ERP_EXIT;
1069 }
1070 atomic_inc(&port->erp_counter);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001071 if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
1072 dev_err(&port->adapter->ccw_device->dev,
1073 "ERP failed for remote port 0x%016Lx\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001074 (unsigned long long)port->wwpn);
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001075 zfcp_erp_port_failed(port, "erpsck1", NULL);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001076 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001077 break;
1078 }
1079
1080 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1081 zfcp_erp_port_block(port, 0);
1082 result = ZFCP_ERP_EXIT;
1083 }
1084 return result;
1085}
1086
1087static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter,
1088 int result)
1089{
1090 switch (result) {
1091 case ZFCP_ERP_SUCCEEDED :
1092 atomic_set(&adapter->erp_counter, 0);
1093 zfcp_erp_adapter_unblock(adapter);
1094 break;
1095
1096 case ZFCP_ERP_FAILED :
1097 atomic_inc(&adapter->erp_counter);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001098 if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) {
1099 dev_err(&adapter->ccw_device->dev,
1100 "ERP cannot recover an error "
1101 "on the FCP device\n");
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001102 zfcp_erp_adapter_failed(adapter, "erasck1", NULL);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001103 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001104 break;
1105 }
1106
1107 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1108 zfcp_erp_adapter_block(adapter, 0);
1109 result = ZFCP_ERP_EXIT;
1110 }
1111 return result;
1112}
1113
1114static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action,
1115 int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116{
1117 struct zfcp_adapter *adapter = erp_action->adapter;
1118 struct zfcp_port *port = erp_action->port;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001119 struct scsi_device *sdev = erp_action->sdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 switch (erp_action->action) {
1122
Christof Schmittb62a8d92010-09-08 14:39:55 +02001123 case ZFCP_ERP_ACTION_REOPEN_LUN:
1124 result = zfcp_erp_strategy_check_lun(sdev, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 break;
1126
1127 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1128 case ZFCP_ERP_ACTION_REOPEN_PORT:
1129 result = zfcp_erp_strategy_check_port(port, result);
1130 break;
1131
1132 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1133 result = zfcp_erp_strategy_check_adapter(adapter, result);
1134 break;
1135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 return result;
1137}
1138
Christof Schmitt287ac012008-07-02 10:56:40 +02001139static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140{
Christof Schmitt287ac012008-07-02 10:56:40 +02001141 int status = atomic_read(target_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
Christof Schmitt287ac012008-07-02 10:56:40 +02001143 if ((status & ZFCP_STATUS_COMMON_RUNNING) &&
1144 (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1145 return 1; /* take it online */
1146
1147 if (!(status & ZFCP_STATUS_COMMON_RUNNING) &&
1148 !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1149 return 1; /* take it offline */
1150
1151 return 0;
1152}
1153
1154static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
1155{
1156 int action = act->action;
1157 struct zfcp_adapter *adapter = act->adapter;
1158 struct zfcp_port *port = act->port;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001159 struct scsi_device *sdev = act->sdev;
1160 struct zfcp_scsi_dev *zfcp_sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +02001161 u32 erp_status = act->status;
1162
1163 switch (action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitt287ac012008-07-02 10:56:40 +02001165 if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) {
1166 _zfcp_erp_adapter_reopen(adapter,
1167 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001168 "ersscg1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001169 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 }
1171 break;
1172
1173 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1174 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitt287ac012008-07-02 10:56:40 +02001175 if (zfcp_erp_strat_change_det(&port->status, erp_status)) {
1176 _zfcp_erp_port_reopen(port,
1177 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001178 "ersscg2", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001179 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 }
1181 break;
1182
Christof Schmittb62a8d92010-09-08 14:39:55 +02001183 case ZFCP_ERP_ACTION_REOPEN_LUN:
1184 zfcp_sdev = sdev_to_zfcp(sdev);
1185 if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) {
1186 _zfcp_erp_lun_reopen(sdev,
1187 ZFCP_STATUS_COMMON_ERP_FAILED,
1188 "ersscg3", NULL, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +02001189 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 }
1191 break;
1192 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001193 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194}
1195
Christof Schmitt287ac012008-07-02 10:56:40 +02001196static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197{
Christof Schmitt287ac012008-07-02 10:56:40 +02001198 struct zfcp_adapter *adapter = erp_action->adapter;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001199 struct zfcp_scsi_dev *zfcp_sdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
Christof Schmitt287ac012008-07-02 10:56:40 +02001201 adapter->erp_total_count--;
1202 if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1203 adapter->erp_low_mem_count--;
1204 erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 }
1206
Christof Schmitt287ac012008-07-02 10:56:40 +02001207 list_del(&erp_action->list);
Swen Schillig57717102009-08-18 15:43:21 +02001208 zfcp_dbf_rec_action("eractd1", erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209
Christof Schmitt287ac012008-07-02 10:56:40 +02001210 switch (erp_action->action) {
Christof Schmittb62a8d92010-09-08 14:39:55 +02001211 case ZFCP_ERP_ACTION_REOPEN_LUN:
1212 zfcp_sdev = sdev_to_zfcp(erp_action->sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +02001213 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
Christof Schmittb62a8d92010-09-08 14:39:55 +02001214 &zfcp_sdev->status);
Christof Schmitt287ac012008-07-02 10:56:40 +02001215 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
Christof Schmitt287ac012008-07-02 10:56:40 +02001217 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1218 case ZFCP_ERP_ACTION_REOPEN_PORT:
1219 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1220 &erp_action->port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001222
1223 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1224 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1225 &erp_action->adapter->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 break;
1227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228}
1229
Christof Schmitt287ac012008-07-02 10:56:40 +02001230static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001231{
Christof Schmitt287ac012008-07-02 10:56:40 +02001232 struct zfcp_adapter *adapter = act->adapter;
1233 struct zfcp_port *port = act->port;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001234 struct scsi_device *sdev = act->sdev;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001235
Christof Schmitt287ac012008-07-02 10:56:40 +02001236 switch (act->action) {
Christof Schmittb62a8d92010-09-08 14:39:55 +02001237 case ZFCP_ERP_ACTION_REOPEN_LUN:
Christof Schmittfdbd1c52010-09-08 14:39:54 +02001238 if (!(act->status & ZFCP_STATUS_ERP_NO_REF))
Christof Schmittb62a8d92010-09-08 14:39:55 +02001239 scsi_device_put(sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001241
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001243 if (result == ZFCP_ERP_SUCCEEDED)
1244 zfcp_scsi_schedule_rport_register(port);
Christof Schmitt57676202010-07-08 09:53:05 +02001245 /* fall through */
1246 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
Christof Schmitt615f59e2010-02-17 11:18:56 +01001247 put_device(&port->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001249
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001251 if (result == ZFCP_ERP_SUCCEEDED) {
Christof Schmittbd43a422008-12-25 13:38:50 +01001252 register_service_level(&adapter->service_level);
Swen Schillig9eae07e2009-11-24 16:54:06 +01001253 queue_work(adapter->work_queue, &adapter->scan_work);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001254 } else
1255 unregister_service_level(&adapter->service_level);
Swen Schilligf3450c72009-11-24 16:53:59 +01001256 kref_put(&adapter->ref, zfcp_adapter_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 }
1259}
1260
Christof Schmitt287ac012008-07-02 10:56:40 +02001261static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
1262{
1263 switch (erp_action->action) {
1264 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1265 return zfcp_erp_adapter_strategy(erp_action);
1266 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1267 return zfcp_erp_port_forced_strategy(erp_action);
1268 case ZFCP_ERP_ACTION_REOPEN_PORT:
1269 return zfcp_erp_port_strategy(erp_action);
Christof Schmittb62a8d92010-09-08 14:39:55 +02001270 case ZFCP_ERP_ACTION_REOPEN_LUN:
1271 return zfcp_erp_lun_strategy(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +02001272 }
1273 return ZFCP_ERP_FAILED;
1274}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275
Christof Schmitt287ac012008-07-02 10:56:40 +02001276static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
1277{
1278 int retval;
Christof Schmitt287ac012008-07-02 10:56:40 +02001279 unsigned long flags;
Swen Schilligecf0c772009-11-24 16:53:58 +01001280 struct zfcp_adapter *adapter = erp_action->adapter;
Christof Schmitt287ac012008-07-02 10:56:40 +02001281
Swen Schilligf3450c72009-11-24 16:53:59 +01001282 kref_get(&adapter->ref);
Christof Schmitt287ac012008-07-02 10:56:40 +02001283
Swen Schilligf3450c72009-11-24 16:53:59 +01001284 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001285 zfcp_erp_strategy_check_fsfreq(erp_action);
1286
1287 if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
1288 zfcp_erp_action_dequeue(erp_action);
1289 retval = ZFCP_ERP_DISMISSED;
1290 goto unlock;
1291 }
1292
Christof Schmitt9c785d92010-07-08 09:53:09 +02001293 if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
1294 retval = ZFCP_ERP_FAILED;
1295 goto check_target;
1296 }
1297
Christof Schmitt287ac012008-07-02 10:56:40 +02001298 zfcp_erp_action_to_running(erp_action);
1299
1300 /* no lock to allow for blocking operations */
Swen Schilligecf0c772009-11-24 16:53:58 +01001301 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001302 retval = zfcp_erp_strategy_do_action(erp_action);
Swen Schilligecf0c772009-11-24 16:53:58 +01001303 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001304
1305 if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED)
1306 retval = ZFCP_ERP_CONTINUES;
1307
1308 switch (retval) {
1309 case ZFCP_ERP_NOMEM:
1310 if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) {
1311 ++adapter->erp_low_mem_count;
1312 erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
1313 }
1314 if (adapter->erp_total_count == adapter->erp_low_mem_count)
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001315 _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001316 else {
1317 zfcp_erp_strategy_memwait(erp_action);
1318 retval = ZFCP_ERP_CONTINUES;
1319 }
1320 goto unlock;
1321
1322 case ZFCP_ERP_CONTINUES:
1323 if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1324 --adapter->erp_low_mem_count;
1325 erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
1326 }
1327 goto unlock;
1328 }
1329
Christof Schmitt9c785d92010-07-08 09:53:09 +02001330check_target:
Christof Schmitt287ac012008-07-02 10:56:40 +02001331 retval = zfcp_erp_strategy_check_target(erp_action, retval);
1332 zfcp_erp_action_dequeue(erp_action);
1333 retval = zfcp_erp_strategy_statechange(erp_action, retval);
1334 if (retval == ZFCP_ERP_EXIT)
1335 goto unlock;
Christof Schmitt85600f72009-07-13 15:06:09 +02001336 if (retval == ZFCP_ERP_SUCCEEDED)
1337 zfcp_erp_strategy_followup_success(erp_action);
1338 if (retval == ZFCP_ERP_FAILED)
1339 zfcp_erp_strategy_followup_failed(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +02001340
1341 unlock:
Swen Schilligecf0c772009-11-24 16:53:58 +01001342 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001343
1344 if (retval != ZFCP_ERP_CONTINUES)
1345 zfcp_erp_action_cleanup(erp_action, retval);
1346
Swen Schilligf3450c72009-11-24 16:53:59 +01001347 kref_put(&adapter->ref, zfcp_adapter_release);
Christof Schmitt287ac012008-07-02 10:56:40 +02001348 return retval;
1349}
1350
1351static int zfcp_erp_thread(void *data)
1352{
1353 struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
1354 struct list_head *next;
1355 struct zfcp_erp_action *act;
1356 unsigned long flags;
1357
Christof Schmitt347c6a92009-08-18 15:43:25 +02001358 for (;;) {
Swen Schillig57717102009-08-18 15:43:21 +02001359 zfcp_dbf_rec_thread_lock("erthrd1", adapter->dbf);
Christof Schmitt347c6a92009-08-18 15:43:25 +02001360 wait_event_interruptible(adapter->erp_ready_wq,
1361 !list_empty(&adapter->erp_ready_head) ||
1362 kthread_should_stop());
Swen Schillig57717102009-08-18 15:43:21 +02001363 zfcp_dbf_rec_thread_lock("erthrd2", adapter->dbf);
Swen Schillig94ab4b32009-04-17 15:08:06 +02001364
Christof Schmitt347c6a92009-08-18 15:43:25 +02001365 if (kthread_should_stop())
1366 break;
1367
Christof Schmitt287ac012008-07-02 10:56:40 +02001368 write_lock_irqsave(&adapter->erp_lock, flags);
1369 next = adapter->erp_ready_head.next;
1370 write_unlock_irqrestore(&adapter->erp_lock, flags);
1371
1372 if (next != &adapter->erp_ready_head) {
1373 act = list_entry(next, struct zfcp_erp_action, list);
1374
1375 /* there is more to come after dismission, no notify */
1376 if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED)
1377 zfcp_erp_wakeup(adapter);
1378 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001379 }
1380
Christof Schmitt287ac012008-07-02 10:56:40 +02001381 return 0;
1382}
1383
1384/**
1385 * zfcp_erp_thread_setup - Start ERP thread for adapter
1386 * @adapter: Adapter to start the ERP thread for
1387 *
1388 * Returns 0 on success or error code from kernel_thread()
1389 */
1390int zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
1391{
Christof Schmitt347c6a92009-08-18 15:43:25 +02001392 struct task_struct *thread;
Christof Schmitt287ac012008-07-02 10:56:40 +02001393
Christof Schmitt347c6a92009-08-18 15:43:25 +02001394 thread = kthread_run(zfcp_erp_thread, adapter, "zfcperp%s",
1395 dev_name(&adapter->ccw_device->dev));
1396 if (IS_ERR(thread)) {
Christof Schmitt287ac012008-07-02 10:56:40 +02001397 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001398 "Creating an ERP thread for the FCP device failed.\n");
Christof Schmitt347c6a92009-08-18 15:43:25 +02001399 return PTR_ERR(thread);
Christof Schmitt287ac012008-07-02 10:56:40 +02001400 }
Christof Schmitt347c6a92009-08-18 15:43:25 +02001401
1402 adapter->erp_thread = thread;
Christof Schmitt287ac012008-07-02 10:56:40 +02001403 return 0;
1404}
1405
1406/**
1407 * zfcp_erp_thread_kill - Stop ERP thread.
1408 * @adapter: Adapter where the ERP thread should be stopped.
1409 *
1410 * The caller of this routine ensures that the specified adapter has
1411 * been shut down and that this operation has been completed. Thus,
1412 * there are no pending erp_actions which would need to be handled
1413 * here.
1414 */
1415void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
1416{
Christof Schmitt347c6a92009-08-18 15:43:25 +02001417 kthread_stop(adapter->erp_thread);
1418 adapter->erp_thread = NULL;
Christof Schmitt143bb6b2009-08-18 15:43:27 +02001419 WARN_ON(!list_empty(&adapter->erp_ready_head));
1420 WARN_ON(!list_empty(&adapter->erp_running_head));
Christof Schmitt287ac012008-07-02 10:56:40 +02001421}
1422
1423/**
1424 * zfcp_erp_adapter_failed - Set adapter status to failed.
1425 * @adapter: Failed adapter.
1426 * @id: Event id for debug trace.
1427 * @ref: Reference for debug trace.
1428 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001429void zfcp_erp_adapter_failed(struct zfcp_adapter *adapter, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +02001430{
1431 zfcp_erp_modify_adapter_status(adapter, id, ref,
1432 ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
Christof Schmitt287ac012008-07-02 10:56:40 +02001433}
1434
1435/**
1436 * zfcp_erp_port_failed - Set port status to failed.
1437 * @port: Failed port.
1438 * @id: Event id for debug trace.
1439 * @ref: Reference for debug trace.
1440 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001441void zfcp_erp_port_failed(struct zfcp_port *port, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +02001442{
1443 zfcp_erp_modify_port_status(port, id, ref,
1444 ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
Christof Schmitt287ac012008-07-02 10:56:40 +02001445}
1446
1447/**
Christof Schmittb62a8d92010-09-08 14:39:55 +02001448 * zfcp_erp_lun_failed - Set LUN status to failed.
1449 * @sdev: Failed SCSI device / LUN
Christof Schmitt287ac012008-07-02 10:56:40 +02001450 * @id: Event id for debug trace.
1451 * @ref: Reference for debug trace.
1452 */
Christof Schmittb62a8d92010-09-08 14:39:55 +02001453void zfcp_erp_lun_failed(struct scsi_device *sdev, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +02001454{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001455 zfcp_erp_modify_lun_status(sdev, id, ref,
1456 ZFCP_STATUS_COMMON_ERP_FAILED, ZFCP_SET);
Christof Schmitt287ac012008-07-02 10:56:40 +02001457}
1458
1459/**
1460 * zfcp_erp_wait - wait for completion of error recovery on an adapter
1461 * @adapter: adapter for which to wait for completion of its error recovery
1462 */
1463void zfcp_erp_wait(struct zfcp_adapter *adapter)
1464{
1465 wait_event(adapter->erp_done_wqh,
1466 !(atomic_read(&adapter->status) &
1467 ZFCP_STATUS_ADAPTER_ERP_PENDING));
1468}
1469
1470/**
1471 * zfcp_erp_modify_adapter_status - change adapter status bits
1472 * @adapter: adapter to change the status
1473 * @id: id for the debug trace
1474 * @ref: reference for the debug trace
1475 * @mask: status bits to change
1476 * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1477 *
Christof Schmittb62a8d92010-09-08 14:39:55 +02001478 * Changes in common status bits are propagated to attached ports and LUNs.
Christof Schmitt287ac012008-07-02 10:56:40 +02001479 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001480void zfcp_erp_modify_adapter_status(struct zfcp_adapter *adapter, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +02001481 void *ref, u32 mask, int set_or_clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 struct zfcp_port *port;
Swen Schilligecf0c772009-11-24 16:53:58 +01001484 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +02001485 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
Christof Schmitt287ac012008-07-02 10:56:40 +02001487 if (set_or_clear == ZFCP_SET) {
1488 if (status_change_set(mask, &adapter->status))
Swen Schillig57717102009-08-18 15:43:21 +02001489 zfcp_dbf_rec_adapter(id, ref, adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +02001490 atomic_set_mask(mask, &adapter->status);
1491 } else {
1492 if (status_change_clear(mask, &adapter->status))
Swen Schillig57717102009-08-18 15:43:21 +02001493 zfcp_dbf_rec_adapter(id, ref, adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +02001494 atomic_clear_mask(mask, &adapter->status);
1495 if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
1496 atomic_set(&adapter->erp_counter, 0);
1497 }
1498
Swen Schilligecf0c772009-11-24 16:53:58 +01001499 if (common_mask) {
1500 read_lock_irqsave(&adapter->port_list_lock, flags);
1501 list_for_each_entry(port, &adapter->port_list, list)
Christof Schmitt287ac012008-07-02 10:56:40 +02001502 zfcp_erp_modify_port_status(port, id, ref, common_mask,
1503 set_or_clear);
Swen Schilligecf0c772009-11-24 16:53:58 +01001504 read_unlock_irqrestore(&adapter->port_list_lock, flags);
1505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506}
1507
Christof Schmitt287ac012008-07-02 10:56:40 +02001508/**
1509 * zfcp_erp_modify_port_status - change port status bits
1510 * @port: port to change the status bits
1511 * @id: id for the debug trace
1512 * @ref: reference for the debug trace
1513 * @mask: status bits to change
1514 * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1515 *
Christof Schmittb62a8d92010-09-08 14:39:55 +02001516 * Changes in common status bits are propagated to attached LUNs.
Christof Schmitt287ac012008-07-02 10:56:40 +02001517 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001518void zfcp_erp_modify_port_status(struct zfcp_port *port, char *id, void *ref,
Christof Schmitt287ac012008-07-02 10:56:40 +02001519 u32 mask, int set_or_clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001521 struct scsi_device *sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +02001522 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523
Christof Schmitt287ac012008-07-02 10:56:40 +02001524 if (set_or_clear == ZFCP_SET) {
1525 if (status_change_set(mask, &port->status))
Swen Schillig57717102009-08-18 15:43:21 +02001526 zfcp_dbf_rec_port(id, ref, port);
Christof Schmitt287ac012008-07-02 10:56:40 +02001527 atomic_set_mask(mask, &port->status);
1528 } else {
1529 if (status_change_clear(mask, &port->status))
Swen Schillig57717102009-08-18 15:43:21 +02001530 zfcp_dbf_rec_port(id, ref, port);
Christof Schmitt287ac012008-07-02 10:56:40 +02001531 atomic_clear_mask(mask, &port->status);
1532 if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
1533 atomic_set(&port->erp_counter, 0);
1534 }
1535
Christof Schmittb62a8d92010-09-08 14:39:55 +02001536 if (common_mask)
1537 shost_for_each_device(sdev, port->adapter->scsi_host)
1538 if (sdev_to_zfcp(sdev)->port == port)
1539 zfcp_erp_modify_lun_status(sdev, id, ref,
1540 common_mask,
1541 set_or_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542}
1543
Christof Schmitt287ac012008-07-02 10:56:40 +02001544/**
Christof Schmittb62a8d92010-09-08 14:39:55 +02001545 * zfcp_erp_modify_lun_status - change LUN status bits
1546 * @sdev: SCSI device / LUN where to change the status bits
Christof Schmitt287ac012008-07-02 10:56:40 +02001547 * @id: id for the debug trace
1548 * @ref: reference for the debug trace
1549 * @mask: status bits to change
1550 * @set_or_clear: ZFCP_SET or ZFCP_CLEAR
1551 */
Christof Schmittb62a8d92010-09-08 14:39:55 +02001552void zfcp_erp_modify_lun_status(struct scsi_device *sdev, char *id, void *ref,
1553 u32 mask, int set_or_clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001555 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
1556
Christof Schmitt287ac012008-07-02 10:56:40 +02001557 if (set_or_clear == ZFCP_SET) {
Christof Schmittb62a8d92010-09-08 14:39:55 +02001558 if (status_change_set(mask, &zfcp_sdev->status))
1559 zfcp_dbf_rec_lun(id, ref, sdev);
1560 atomic_set_mask(mask, &zfcp_sdev->status);
Christof Schmitt287ac012008-07-02 10:56:40 +02001561 } else {
Christof Schmittb62a8d92010-09-08 14:39:55 +02001562 if (status_change_clear(mask, &zfcp_sdev->status))
1563 zfcp_dbf_rec_lun(id, ref, sdev);
1564 atomic_clear_mask(mask, &zfcp_sdev->status);
Christof Schmitt287ac012008-07-02 10:56:40 +02001565 if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) {
Christof Schmittb62a8d92010-09-08 14:39:55 +02001566 atomic_set(&zfcp_sdev->erp_counter, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +02001567 }
1568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569}
1570
Christof Schmitt287ac012008-07-02 10:56:40 +02001571/**
1572 * zfcp_erp_port_boxed - Mark port as "boxed" and start ERP
1573 * @port: The "boxed" port.
1574 * @id: The debug trace id.
1575 * @id: Reference for the debug trace.
1576 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001577void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref)
Andreas Herrmannd736a272005-06-13 13:23:57 +02001578{
Martin Peschke698ec0162008-03-27 14:22:02 +01001579 zfcp_erp_modify_port_status(port, id, ref,
1580 ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
Martin Peschke9467a9b2008-03-27 14:22:03 +01001581 zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
Andreas Herrmannd736a272005-06-13 13:23:57 +02001582}
1583
Christof Schmitt287ac012008-07-02 10:56:40 +02001584/**
Christof Schmittb62a8d92010-09-08 14:39:55 +02001585 * zfcp_erp_lun_boxed - Mark LUN as "boxed" and start ERP
1586 * @sdev: The "boxed" SCSI device / LUN.
Christof Schmitt287ac012008-07-02 10:56:40 +02001587 * @id: The debug trace id.
Christof Schmittb62a8d92010-09-08 14:39:55 +02001588 * @ref: Reference for the debug trace.
Christof Schmitt287ac012008-07-02 10:56:40 +02001589 */
Christof Schmittb62a8d92010-09-08 14:39:55 +02001590void zfcp_erp_lun_boxed(struct scsi_device *sdev, char *id, void *ref)
Andreas Herrmannd736a272005-06-13 13:23:57 +02001591{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001592 zfcp_erp_modify_lun_status(sdev, id, ref,
1593 ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
1594 zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
Andreas Herrmannd736a272005-06-13 13:23:57 +02001595}
1596
Christof Schmitt287ac012008-07-02 10:56:40 +02001597/**
1598 * zfcp_erp_port_access_denied - Adapter denied access to port.
1599 * @port: port where access has been denied
1600 * @id: id for debug trace
1601 * @ref: reference for debug trace
1602 *
1603 * Since the adapter has denied access, stop using the port and the
Christof Schmittb62a8d92010-09-08 14:39:55 +02001604 * attached LUNs.
Christof Schmitt287ac012008-07-02 10:56:40 +02001605 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001606void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607{
Martin Peschke698ec0162008-03-27 14:22:02 +01001608 zfcp_erp_modify_port_status(port, id, ref,
1609 ZFCP_STATUS_COMMON_ERP_FAILED |
1610 ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611}
1612
Christof Schmitt287ac012008-07-02 10:56:40 +02001613/**
Christof Schmittb62a8d92010-09-08 14:39:55 +02001614 * zfcp_erp_lun_access_denied - Adapter denied access to LUN.
1615 * @sdev: SCSI device / LUN where access has been denied
Christof Schmitt287ac012008-07-02 10:56:40 +02001616 * @id: id for debug trace
1617 * @ref: reference for debug trace
1618 *
Christof Schmittb62a8d92010-09-08 14:39:55 +02001619 * Since the adapter has denied access, stop using the LUN.
Christof Schmitt287ac012008-07-02 10:56:40 +02001620 */
Christof Schmittb62a8d92010-09-08 14:39:55 +02001621void zfcp_erp_lun_access_denied(struct scsi_device *sdev, char *id, void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001623 zfcp_erp_modify_lun_status(sdev, id, ref,
1624 ZFCP_STATUS_COMMON_ERP_FAILED |
1625 ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626}
1627
Christof Schmittb62a8d92010-09-08 14:39:55 +02001628static void zfcp_erp_lun_access_changed(struct scsi_device *sdev, char *id,
1629 void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +02001630{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001631 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
1632 int status = atomic_read(&zfcp_sdev->status);
1633
Christof Schmitt287ac012008-07-02 10:56:40 +02001634 if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
1635 ZFCP_STATUS_COMMON_ACCESS_BOXED)))
1636 return;
1637
Christof Schmittb62a8d92010-09-08 14:39:55 +02001638 zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
Christof Schmitt287ac012008-07-02 10:56:40 +02001639}
1640
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001641static void zfcp_erp_port_access_changed(struct zfcp_port *port, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +02001642 void *ref)
1643{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001644 struct scsi_device *sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +02001645 int status = atomic_read(&port->status);
1646
1647 if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
1648 ZFCP_STATUS_COMMON_ACCESS_BOXED))) {
Christof Schmittb62a8d92010-09-08 14:39:55 +02001649 shost_for_each_device(sdev, port->adapter->scsi_host)
1650 if (sdev_to_zfcp(sdev)->port == port)
1651 zfcp_erp_lun_access_changed(sdev, id, ref);
Christof Schmitt287ac012008-07-02 10:56:40 +02001652 return;
1653 }
1654
1655 zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
1656}
1657
1658/**
1659 * zfcp_erp_adapter_access_changed - Process change in adapter ACT
1660 * @adapter: Adapter where the Access Control Table (ACT) changed
1661 * @id: Id for debug trace
1662 * @ref: Reference for debug trace
1663 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001664void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id,
Martin Peschke1f6f7122008-04-18 12:51:55 +02001665 void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 unsigned long flags;
Swen Schilligecf0c772009-11-24 16:53:58 +01001668 struct zfcp_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001670 if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
1671 return;
1672
Swen Schilligecf0c772009-11-24 16:53:58 +01001673 read_lock_irqsave(&adapter->port_list_lock, flags);
1674 list_for_each_entry(port, &adapter->port_list, list)
Swen Schillig5ab944f2008-10-01 12:42:17 +02001675 zfcp_erp_port_access_changed(port, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +01001676 read_unlock_irqrestore(&adapter->port_list_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677}