blob: 0bcd5806bd9a616df1f919f77c7e6a741e44533e [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 Schmittb6bd2fb92010-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 Schilligedaed852010-09-08 14:40:01 +020060 zfcp_erp_clear_adapter_status(adapter,
61 ZFCP_STATUS_COMMON_UNBLOCKED | mask);
Andreas Herrmann2abbe862006-09-18 22:29:56 +020062}
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Christof Schmitt287ac012008-07-02 10:56:40 +020064static int zfcp_erp_action_exists(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -070065{
Christof Schmitt287ac012008-07-02 10:56:40 +020066 struct zfcp_erp_action *curr_act;
67
68 list_for_each_entry(curr_act, &act->adapter->erp_running_head, list)
69 if (act == curr_act)
70 return ZFCP_ERP_ACTION_RUNNING;
71 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070072}
73
Christof Schmitt287ac012008-07-02 10:56:40 +020074static void zfcp_erp_action_ready(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -070075{
Christof Schmitt287ac012008-07-02 10:56:40 +020076 struct zfcp_adapter *adapter = act->adapter;
77
78 list_move(&act->list, &act->adapter->erp_ready_head);
Swen Schillig57717102009-08-18 15:43:21 +020079 zfcp_dbf_rec_action("erardy1", act);
Christof Schmitt347c6a92009-08-18 15:43:25 +020080 wake_up(&adapter->erp_ready_wq);
Swen Schillig57717102009-08-18 15:43:21 +020081 zfcp_dbf_rec_thread("erardy2", adapter->dbf);
Linus Torvalds1da177e2005-04-16 15:20:36 -070082}
83
Christof Schmitt287ac012008-07-02 10:56:40 +020084static void zfcp_erp_action_dismiss(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -070085{
Christof Schmitt287ac012008-07-02 10:56:40 +020086 act->status |= ZFCP_STATUS_ERP_DISMISSED;
87 if (zfcp_erp_action_exists(act) == ZFCP_ERP_ACTION_RUNNING)
88 zfcp_erp_action_ready(act);
89}
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
Christof Schmittb62a8d92010-09-08 14:39:55 +020091static void zfcp_erp_action_dismiss_lun(struct scsi_device *sdev)
Christof Schmitt287ac012008-07-02 10:56:40 +020092{
Christof Schmittb62a8d92010-09-08 14:39:55 +020093 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
94
95 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
96 zfcp_erp_action_dismiss(&zfcp_sdev->erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +020097}
98
99static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
100{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200101 struct scsi_device *sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +0200102
103 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
104 zfcp_erp_action_dismiss(&port->erp_action);
Christof Schmittb62a8d92010-09-08 14:39:55 +0200105 else
106 shost_for_each_device(sdev, port->adapter->scsi_host)
107 if (sdev_to_zfcp(sdev)->port == port)
108 zfcp_erp_action_dismiss_lun(sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +0200109}
110
111static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
112{
113 struct zfcp_port *port;
114
115 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
116 zfcp_erp_action_dismiss(&adapter->erp_action);
Swen Schilligecf0c772009-11-24 16:53:58 +0100117 else {
118 read_lock(&adapter->port_list_lock);
119 list_for_each_entry(port, &adapter->port_list, list)
Christof Schmitt287ac012008-07-02 10:56:40 +0200120 zfcp_erp_action_dismiss_port(port);
Swen Schilligecf0c772009-11-24 16:53:58 +0100121 read_unlock(&adapter->port_list_lock);
122 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200123}
124
125static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
126 struct zfcp_port *port,
Christof Schmittb62a8d92010-09-08 14:39:55 +0200127 struct scsi_device *sdev)
Christof Schmitt287ac012008-07-02 10:56:40 +0200128{
129 int need = want;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200130 int l_status, p_status, a_status;
131 struct zfcp_scsi_dev *zfcp_sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +0200132
133 switch (want) {
Christof Schmittb62a8d92010-09-08 14:39:55 +0200134 case ZFCP_ERP_ACTION_REOPEN_LUN:
135 zfcp_sdev = sdev_to_zfcp(sdev);
136 l_status = atomic_read(&zfcp_sdev->status);
137 if (l_status & ZFCP_STATUS_COMMON_ERP_INUSE)
Christof Schmitt287ac012008-07-02 10:56:40 +0200138 return 0;
139 p_status = atomic_read(&port->status);
140 if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) ||
141 p_status & ZFCP_STATUS_COMMON_ERP_FAILED)
142 return 0;
143 if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED))
144 need = ZFCP_ERP_ACTION_REOPEN_PORT;
145 /* fall through */
Christof Schmitt287ac012008-07-02 10:56:40 +0200146 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
147 p_status = atomic_read(&port->status);
Christof Schmitt097ef3b2010-07-08 09:53:06 +0200148 if (!(p_status & ZFCP_STATUS_COMMON_OPEN))
149 need = ZFCP_ERP_ACTION_REOPEN_PORT;
150 /* fall through */
151 case ZFCP_ERP_ACTION_REOPEN_PORT:
152 p_status = atomic_read(&port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200153 if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE)
154 return 0;
155 a_status = atomic_read(&adapter->status);
156 if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) ||
157 a_status & ZFCP_STATUS_COMMON_ERP_FAILED)
158 return 0;
Swen Schilligd3e10882010-11-17 14:23:42 +0100159 if (p_status & ZFCP_STATUS_COMMON_NOESC)
160 return need;
Christof Schmitt287ac012008-07-02 10:56:40 +0200161 if (!(a_status & ZFCP_STATUS_COMMON_UNBLOCKED))
162 need = ZFCP_ERP_ACTION_REOPEN_ADAPTER;
163 /* fall through */
164 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
165 a_status = atomic_read(&adapter->status);
166 if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
167 return 0;
Christof Schmitt143bb6b2009-08-18 15:43:27 +0200168 if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) &&
169 !(a_status & ZFCP_STATUS_COMMON_OPEN))
170 return 0; /* shutdown requested for closed adapter */
Christof Schmitt287ac012008-07-02 10:56:40 +0200171 }
172
173 return need;
174}
175
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200176static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
Christof Schmitt287ac012008-07-02 10:56:40 +0200177 struct zfcp_adapter *adapter,
178 struct zfcp_port *port,
Christof Schmittb62a8d92010-09-08 14:39:55 +0200179 struct scsi_device *sdev)
Christof Schmitt287ac012008-07-02 10:56:40 +0200180{
181 struct zfcp_erp_action *erp_action;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200182 struct zfcp_scsi_dev *zfcp_sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +0200183
184 switch (need) {
Christof Schmittb62a8d92010-09-08 14:39:55 +0200185 case ZFCP_ERP_ACTION_REOPEN_LUN:
186 zfcp_sdev = sdev_to_zfcp(sdev);
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200187 if (!(act_status & ZFCP_STATUS_ERP_NO_REF))
Christof Schmittb62a8d92010-09-08 14:39:55 +0200188 if (scsi_device_get(sdev))
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200189 return NULL;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200190 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
191 &zfcp_sdev->status);
192 erp_action = &zfcp_sdev->erp_action;
Swen Schillig14718e32010-11-17 14:23:43 +0100193 memset(erp_action, 0, sizeof(struct zfcp_erp_action));
194 erp_action->port = port;
195 erp_action->sdev = sdev;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200196 if (!(atomic_read(&zfcp_sdev->status) &
197 ZFCP_STATUS_COMMON_RUNNING))
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200198 act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
Christof Schmitt287ac012008-07-02 10:56:40 +0200199 break;
200
201 case ZFCP_ERP_ACTION_REOPEN_PORT:
202 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
Christof Schmitt615f59e2010-02-17 11:18:56 +0100203 if (!get_device(&port->dev))
Swen Schillig6b1833342009-11-24 16:54:05 +0100204 return NULL;
Christof Schmitt287ac012008-07-02 10:56:40 +0200205 zfcp_erp_action_dismiss_port(port);
206 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
207 erp_action = &port->erp_action;
Swen Schillig14718e32010-11-17 14:23:43 +0100208 memset(erp_action, 0, sizeof(struct zfcp_erp_action));
209 erp_action->port = port;
Christof Schmitt287ac012008-07-02 10:56:40 +0200210 if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200211 act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
Christof Schmitt287ac012008-07-02 10:56:40 +0200212 break;
213
214 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Swen Schilligf3450c72009-11-24 16:53:59 +0100215 kref_get(&adapter->ref);
Christof Schmitt287ac012008-07-02 10:56:40 +0200216 zfcp_erp_action_dismiss_adapter(adapter);
217 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
218 erp_action = &adapter->erp_action;
Swen Schillig14718e32010-11-17 14:23:43 +0100219 memset(erp_action, 0, sizeof(struct zfcp_erp_action));
Christof Schmitt287ac012008-07-02 10:56:40 +0200220 if (!(atomic_read(&adapter->status) &
221 ZFCP_STATUS_COMMON_RUNNING))
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200222 act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
Christof Schmitt287ac012008-07-02 10:56:40 +0200223 break;
224
225 default:
226 return NULL;
227 }
228
Christof Schmitt287ac012008-07-02 10:56:40 +0200229 erp_action->adapter = adapter;
Christof Schmitt287ac012008-07-02 10:56:40 +0200230 erp_action->action = need;
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200231 erp_action->status = act_status;
Christof Schmitt287ac012008-07-02 10:56:40 +0200232
233 return erp_action;
234}
235
236static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
237 struct zfcp_port *port,
Christof Schmittb62a8d92010-09-08 14:39:55 +0200238 struct scsi_device *sdev,
239 char *id, void *ref, u32 act_status)
Christof Schmitt287ac012008-07-02 10:56:40 +0200240{
241 int retval = 1, need;
242 struct zfcp_erp_action *act = NULL;
243
Christof Schmitt347c6a92009-08-18 15:43:25 +0200244 if (!adapter->erp_thread)
Christof Schmitt287ac012008-07-02 10:56:40 +0200245 return -EIO;
246
Christof Schmittb62a8d92010-09-08 14:39:55 +0200247 need = zfcp_erp_required_act(want, adapter, port, sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +0200248 if (!need)
249 goto out;
250
Christof Schmittb62a8d92010-09-08 14:39:55 +0200251 act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +0200252 if (!act)
253 goto out;
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200254 atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200255 ++adapter->erp_total_count;
256 list_add_tail(&act->list, &adapter->erp_ready_head);
Christof Schmitt347c6a92009-08-18 15:43:25 +0200257 wake_up(&adapter->erp_ready_wq);
Swen Schillig57717102009-08-18 15:43:21 +0200258 zfcp_dbf_rec_thread("eracte1", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200259 retval = 0;
260 out:
Christof Schmittb62a8d92010-09-08 14:39:55 +0200261 zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +0200262 return retval;
263}
264
265static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100266 int clear_mask, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200267{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 zfcp_erp_adapter_block(adapter, clear_mask);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100269 zfcp_scsi_schedule_rports_block(adapter);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
Christof Schmitt287ac012008-07-02 10:56:40 +0200271 /* ensure propagation of failed status to new devices */
272 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
Swen Schilligedaed852010-09-08 14:40:01 +0200273 zfcp_erp_set_adapter_status(adapter,
274 ZFCP_STATUS_COMMON_ERP_FAILED);
Christof Schmitt287ac012008-07-02 10:56:40 +0200275 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200277 return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200278 adapter, NULL, NULL, id, ref, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279}
280
281/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200282 * zfcp_erp_adapter_reopen - Reopen adapter.
283 * @adapter: Adapter to reopen.
284 * @clear: Status flags to clear.
285 * @id: Id for debug trace event.
286 * @ref: Reference for debug trace event.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200288void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100289 char *id, void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290{
Christof Schmitt287ac012008-07-02 10:56:40 +0200291 unsigned long flags;
292
Swen Schilligecf0c772009-11-24 16:53:58 +0100293 zfcp_erp_adapter_block(adapter, clear);
294 zfcp_scsi_schedule_rports_block(adapter);
295
296 write_lock_irqsave(&adapter->erp_lock, flags);
297 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
Swen Schilligedaed852010-09-08 14:40:01 +0200298 zfcp_erp_set_adapter_status(adapter,
299 ZFCP_STATUS_COMMON_ERP_FAILED);
Swen Schilligecf0c772009-11-24 16:53:58 +0100300 else
301 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200302 NULL, NULL, id, ref, 0);
Swen Schilligecf0c772009-11-24 16:53:58 +0100303 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200304}
305
306/**
307 * zfcp_erp_adapter_shutdown - Shutdown adapter.
308 * @adapter: Adapter to shut down.
309 * @clear: Status flags to clear.
310 * @id: Id for debug trace event.
311 * @ref: Reference for debug trace event.
312 */
313void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100314 char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200315{
316 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
317 zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref);
318}
319
320/**
321 * zfcp_erp_port_shutdown - Shutdown port
322 * @port: Port to shut down.
323 * @clear: Status flags to clear.
324 * @id: Id for debug trace event.
325 * @ref: Reference for debug trace event.
326 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100327void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id,
328 void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200329{
330 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
331 zfcp_erp_port_reopen(port, clear | flags, id, ref);
332}
333
Christof Schmitt287ac012008-07-02 10:56:40 +0200334static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
335{
Swen Schilligedaed852010-09-08 14:40:01 +0200336 zfcp_erp_clear_port_status(port,
337 ZFCP_STATUS_COMMON_UNBLOCKED | clear);
Christof Schmitt287ac012008-07-02 10:56:40 +0200338}
339
340static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100341 int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200342{
343 zfcp_erp_port_block(port, clear);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100344 zfcp_scsi_schedule_rport_block(port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200345
346 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
347 return;
348
349 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200350 port->adapter, port, NULL, id, ref, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +0200351}
352
353/**
354 * zfcp_erp_port_forced_reopen - Forced close of port and open again
355 * @port: Port to force close and to reopen.
356 * @id: Id for debug trace event.
357 * @ref: Reference for debug trace event.
358 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100359void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +0200360 void *ref)
361{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 unsigned long flags;
363 struct zfcp_adapter *adapter = port->adapter;
364
Swen Schilligecf0c772009-11-24 16:53:58 +0100365 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200366 _zfcp_erp_port_forced_reopen(port, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100367 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200368}
369
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100370static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +0200371 void *ref)
372{
373 zfcp_erp_port_block(port, clear);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100374 zfcp_scsi_schedule_rport_block(port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200375
376 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
377 /* ensure propagation of failed status to new devices */
Swen Schilligedaed852010-09-08 14:40:01 +0200378 zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED);
Christof Schmitt287ac012008-07-02 10:56:40 +0200379 return -EIO;
380 }
381
382 return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200383 port->adapter, port, NULL, id, ref, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +0200384}
385
386/**
387 * zfcp_erp_port_reopen - trigger remote port recovery
388 * @port: port to recover
389 * @clear_mask: flags in port status to be cleared
390 *
391 * Returns 0 if recovery has been triggered, < 0 if not.
392 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100393int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200394{
Christof Schmitt287ac012008-07-02 10:56:40 +0200395 int retval;
Swen Schilligecf0c772009-11-24 16:53:58 +0100396 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +0200397 struct zfcp_adapter *adapter = port->adapter;
398
Swen Schilligecf0c772009-11-24 16:53:58 +0100399 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200400 retval = _zfcp_erp_port_reopen(port, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100401 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
403 return retval;
404}
405
Christof Schmittb62a8d92010-09-08 14:39:55 +0200406static void zfcp_erp_lun_block(struct scsi_device *sdev, int clear_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407{
Swen Schilligedaed852010-09-08 14:40:01 +0200408 zfcp_erp_clear_lun_status(sdev,
409 ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask);
Christof Schmitt287ac012008-07-02 10:56:40 +0200410}
411
Christof Schmittb62a8d92010-09-08 14:39:55 +0200412static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,
413 void *ref, u32 act_status)
Christof Schmitt287ac012008-07-02 10:56:40 +0200414{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200415 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
416 struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
Christof Schmittb62a8d92010-09-08 14:39:55 +0200418 zfcp_erp_lun_block(sdev, clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Christof Schmittb62a8d92010-09-08 14:39:55 +0200420 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
Christof Schmitt287ac012008-07-02 10:56:40 +0200421 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
Christof Schmittb62a8d92010-09-08 14:39:55 +0200423 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter,
424 zfcp_sdev->port, sdev, id, ref, act_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425}
426
427/**
Christof Schmittb62a8d92010-09-08 14:39:55 +0200428 * zfcp_erp_lun_reopen - initiate reopen of a LUN
429 * @sdev: SCSI device / LUN to be reopened
430 * @clear_mask: specifies flags in LUN status to be cleared
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 * Return: 0 on success, < 0 on error
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 */
Christof Schmittb62a8d92010-09-08 14:39:55 +0200433void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,
434 void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 unsigned long flags;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200437 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
438 struct zfcp_port *port = zfcp_sdev->port;
Christof Schmitt287ac012008-07-02 10:56:40 +0200439 struct zfcp_adapter *adapter = port->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Swen Schilligecf0c772009-11-24 16:53:58 +0100441 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmittb62a8d92010-09-08 14:39:55 +0200442 _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0);
Swen Schilligecf0c772009-11-24 16:53:58 +0100443 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444}
445
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200446/**
Christof Schmittb62a8d92010-09-08 14:39:55 +0200447 * zfcp_erp_lun_shutdown - Shutdown LUN
448 * @sdev: SCSI device / LUN to shut down.
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200449 * @clear: Status flags to clear.
450 * @id: Id for debug trace event.
451 * @ref: Reference for debug trace event.
452 */
Christof Schmittb62a8d92010-09-08 14:39:55 +0200453void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id,
454 void *ref)
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200455{
456 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200457 zfcp_erp_lun_reopen(sdev, clear | flags, id, ref);
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200458}
459
460/**
Christof Schmittb62a8d92010-09-08 14:39:55 +0200461 * zfcp_erp_lun_shutdown_wait - Shutdown LUN and wait for erp completion
462 * @sdev: SCSI device / LUN to shut down.
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200463 * @id: Id for debug trace event.
464 *
Christof Schmittb62a8d92010-09-08 14:39:55 +0200465 * Do not acquire a reference for the LUN when creating the ERP
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200466 * action. It is safe, because this function waits for the ERP to
Christof Schmittb62a8d92010-09-08 14:39:55 +0200467 * complete first. This allows to shutdown the LUN, even when the SCSI
468 * device is in the state SDEV_DEL when scsi_device_get will fail.
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200469 */
Christof Schmittb62a8d92010-09-08 14:39:55 +0200470void zfcp_erp_lun_shutdown_wait(struct scsi_device *sdev, char *id)
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200471{
472 unsigned long flags;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200473 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
474 struct zfcp_port *port = zfcp_sdev->port;
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200475 struct zfcp_adapter *adapter = port->adapter;
476 int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
477
478 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmittb62a8d92010-09-08 14:39:55 +0200479 _zfcp_erp_lun_reopen(sdev, clear, id, NULL, ZFCP_STATUS_ERP_NO_REF);
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200480 write_unlock_irqrestore(&adapter->erp_lock, flags);
481
482 zfcp_erp_wait(adapter);
483}
484
Christof Schmitt287ac012008-07-02 10:56:40 +0200485static int status_change_set(unsigned long mask, atomic_t *status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
Christof Schmitt287ac012008-07-02 10:56:40 +0200487 return (atomic_read(status) ^ mask) & mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488}
489
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200490static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
Christof Schmitt287ac012008-07-02 10:56:40 +0200492 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status))
Swen Schillig57717102009-08-18 15:43:21 +0200493 zfcp_dbf_rec_adapter("eraubl1", NULL, adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200494 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495}
496
Christof Schmitt287ac012008-07-02 10:56:40 +0200497static void zfcp_erp_port_unblock(struct zfcp_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498{
Christof Schmitt287ac012008-07-02 10:56:40 +0200499 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status))
Swen Schillig57717102009-08-18 15:43:21 +0200500 zfcp_dbf_rec_port("erpubl1", NULL, port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200501 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502}
503
Christof Schmittb62a8d92010-09-08 14:39:55 +0200504static void zfcp_erp_lun_unblock(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200506 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
507
508 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status))
509 zfcp_dbf_rec_lun("erlubl1", NULL, sdev);
510 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511}
512
Christof Schmitt287ac012008-07-02 10:56:40 +0200513static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514{
Christof Schmitt287ac012008-07-02 10:56:40 +0200515 list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
Swen Schillig57717102009-08-18 15:43:21 +0200516 zfcp_dbf_rec_action("erator1", erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517}
518
Christof Schmitt287ac012008-07-02 10:56:40 +0200519static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520{
Christof Schmitt287ac012008-07-02 10:56:40 +0200521 struct zfcp_adapter *adapter = act->adapter;
Christof Schmitte60a6d62010-02-17 11:18:49 +0100522 struct zfcp_fsf_req *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Christof Schmitte60a6d62010-02-17 11:18:49 +0100524 if (!act->fsf_req_id)
Christof Schmitt287ac012008-07-02 10:56:40 +0200525 return;
526
Christof Schmittb6bd2fb92010-02-17 11:18:50 +0100527 spin_lock(&adapter->req_list->lock);
528 req = _zfcp_reqlist_find(adapter->req_list, act->fsf_req_id);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100529 if (req && req->erp_action == act) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200530 if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
531 ZFCP_STATUS_ERP_TIMEDOUT)) {
Christof Schmitte60a6d62010-02-17 11:18:49 +0100532 req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
Swen Schillig57717102009-08-18 15:43:21 +0200533 zfcp_dbf_rec_action("erscf_1", act);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100534 req->erp_action = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200536 if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
Swen Schillig57717102009-08-18 15:43:21 +0200537 zfcp_dbf_rec_action("erscf_2", act);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100538 if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
539 act->fsf_req_id = 0;
Christof Schmitt287ac012008-07-02 10:56:40 +0200540 } else
Christof Schmitte60a6d62010-02-17 11:18:49 +0100541 act->fsf_req_id = 0;
Christof Schmittb6bd2fb92010-02-17 11:18:50 +0100542 spin_unlock(&adapter->req_list->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543}
544
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200545/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200546 * zfcp_erp_notify - Trigger ERP action.
547 * @erp_action: ERP action to continue.
548 * @set_mask: ERP action status flags to set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200550void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551{
552 struct zfcp_adapter *adapter = erp_action->adapter;
553 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200556 if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
557 erp_action->status |= set_mask;
558 zfcp_erp_action_ready(erp_action);
559 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561}
562
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200563/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200564 * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request
565 * @data: ERP action (from timer data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200567void zfcp_erp_timeout_handler(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568{
Christof Schmitt287ac012008-07-02 10:56:40 +0200569 struct zfcp_erp_action *act = (struct zfcp_erp_action *) data;
570 zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571}
572
Christof Schmitt287ac012008-07-02 10:56:40 +0200573static void zfcp_erp_memwait_handler(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574{
Christof Schmitt287ac012008-07-02 10:56:40 +0200575 zfcp_erp_notify((struct zfcp_erp_action *)data, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576}
577
Christof Schmitt287ac012008-07-02 10:56:40 +0200578static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 init_timer(&erp_action->timer);
581 erp_action->timer.function = zfcp_erp_memwait_handler;
582 erp_action->timer.data = (unsigned long) erp_action;
Christof Schmitt287ac012008-07-02 10:56:40 +0200583 erp_action->timer.expires = jiffies + HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 add_timer(&erp_action->timer);
Christof Schmitt287ac012008-07-02 10:56:40 +0200585}
586
587static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100588 int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200589{
590 struct zfcp_port *port;
591
Swen Schilligecf0c772009-11-24 16:53:58 +0100592 read_lock(&adapter->port_list_lock);
593 list_for_each_entry(port, &adapter->port_list, list)
Swen Schillig5ab944f2008-10-01 12:42:17 +0200594 _zfcp_erp_port_reopen(port, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100595 read_unlock(&adapter->port_list_lock);
Christof Schmitt287ac012008-07-02 10:56:40 +0200596}
597
Christof Schmittb62a8d92010-09-08 14:39:55 +0200598static void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear,
599 char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200600{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200601 struct scsi_device *sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +0200602
Christof Schmittb62a8d92010-09-08 14:39:55 +0200603 shost_for_each_device(sdev, port->adapter->scsi_host)
604 if (sdev_to_zfcp(sdev)->port == port)
605 _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +0200606}
607
Christof Schmitt85600f72009-07-13 15:06:09 +0200608static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
Christof Schmitt287ac012008-07-02 10:56:40 +0200609{
Christof Schmitt287ac012008-07-02 10:56:40 +0200610 switch (act->action) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200611 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitt85600f72009-07-13 15:06:09 +0200612 _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200613 break;
Christof Schmitt287ac012008-07-02 10:56:40 +0200614 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
Christof Schmitt85600f72009-07-13 15:06:09 +0200615 _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200616 break;
Christof Schmitt287ac012008-07-02 10:56:40 +0200617 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitt85600f72009-07-13 15:06:09 +0200618 _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200619 break;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200620 case ZFCP_ERP_ACTION_REOPEN_LUN:
621 _zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", NULL, 0);
Christof Schmitt85600f72009-07-13 15:06:09 +0200622 break;
623 }
624}
625
626static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act)
627{
628 switch (act->action) {
629 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
630 _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL);
631 break;
632 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
633 _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL);
634 break;
635 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmittb62a8d92010-09-08 14:39:55 +0200636 _zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200637 break;
638 }
639}
640
641static void zfcp_erp_wakeup(struct zfcp_adapter *adapter)
642{
643 unsigned long flags;
644
Swen Schilligecf0c772009-11-24 16:53:58 +0100645 read_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200646 if (list_empty(&adapter->erp_ready_head) &&
647 list_empty(&adapter->erp_running_head)) {
648 atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING,
649 &adapter->status);
650 wake_up(&adapter->erp_done_wqh);
651 }
Swen Schilligecf0c772009-11-24 16:53:58 +0100652 read_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200653}
654
655static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
656{
Swen Schillig564e1c82009-08-18 15:43:19 +0200657 struct zfcp_qdio *qdio = act->adapter->qdio;
658
659 if (zfcp_qdio_open(qdio))
Christof Schmitt287ac012008-07-02 10:56:40 +0200660 return ZFCP_ERP_FAILED;
Swen Schillig564e1c82009-08-18 15:43:19 +0200661 init_waitqueue_head(&qdio->req_q_wq);
Christof Schmitt287ac012008-07-02 10:56:40 +0200662 atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status);
663 return ZFCP_ERP_SUCCEEDED;
664}
665
666static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
667{
668 struct zfcp_port *port;
669 port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0,
670 adapter->peer_d_id);
671 if (IS_ERR(port)) /* error or port already attached */
672 return;
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100673 _zfcp_erp_port_reopen(port, 0, "ereptp1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200674}
675
676static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
677{
678 int retries;
679 int sleep = 1;
680 struct zfcp_adapter *adapter = erp_action->adapter;
681
682 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
683
684 for (retries = 7; retries; retries--) {
685 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
686 &adapter->status);
687 write_lock_irq(&adapter->erp_lock);
688 zfcp_erp_action_to_running(erp_action);
689 write_unlock_irq(&adapter->erp_lock);
690 if (zfcp_fsf_exchange_config_data(erp_action)) {
691 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
692 &adapter->status);
693 return ZFCP_ERP_FAILED;
694 }
695
Swen Schillig57717102009-08-18 15:43:21 +0200696 zfcp_dbf_rec_thread_lock("erasfx1", adapter->dbf);
Christof Schmitt347c6a92009-08-18 15:43:25 +0200697 wait_event(adapter->erp_ready_wq,
698 !list_empty(&adapter->erp_ready_head));
Swen Schillig57717102009-08-18 15:43:21 +0200699 zfcp_dbf_rec_thread_lock("erasfx2", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200700 if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
701 break;
702
703 if (!(atomic_read(&adapter->status) &
704 ZFCP_STATUS_ADAPTER_HOST_CON_INIT))
705 break;
706
707 ssleep(sleep);
708 sleep *= 2;
709 }
710
711 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
712 &adapter->status);
713
714 if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK))
715 return ZFCP_ERP_FAILED;
716
717 if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
718 zfcp_erp_enqueue_ptp_port(adapter);
719
720 return ZFCP_ERP_SUCCEEDED;
721}
722
723static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act)
724{
725 int ret;
726 struct zfcp_adapter *adapter = act->adapter;
727
Christof Schmitt287ac012008-07-02 10:56:40 +0200728 write_lock_irq(&adapter->erp_lock);
729 zfcp_erp_action_to_running(act);
730 write_unlock_irq(&adapter->erp_lock);
731
732 ret = zfcp_fsf_exchange_port_data(act);
733 if (ret == -EOPNOTSUPP)
734 return ZFCP_ERP_SUCCEEDED;
735 if (ret)
736 return ZFCP_ERP_FAILED;
737
Swen Schillig57717102009-08-18 15:43:21 +0200738 zfcp_dbf_rec_thread_lock("erasox1", adapter->dbf);
Christof Schmitt347c6a92009-08-18 15:43:25 +0200739 wait_event(adapter->erp_ready_wq,
740 !list_empty(&adapter->erp_ready_head));
Swen Schillig57717102009-08-18 15:43:21 +0200741 zfcp_dbf_rec_thread_lock("erasox2", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200742 if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
743 return ZFCP_ERP_FAILED;
744
745 return ZFCP_ERP_SUCCEEDED;
746}
747
748static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)
749{
750 if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED)
751 return ZFCP_ERP_FAILED;
752
753 if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)
754 return ZFCP_ERP_FAILED;
755
Christof Schmitt8d88cf32010-06-21 10:11:33 +0200756 if (mempool_resize(act->adapter->pool.status_read_data,
757 act->adapter->stat_read_buf_num, GFP_KERNEL))
758 return ZFCP_ERP_FAILED;
759
760 if (mempool_resize(act->adapter->pool.status_read_req,
761 act->adapter->stat_read_buf_num, GFP_KERNEL))
762 return ZFCP_ERP_FAILED;
763
Christof Schmitt64deb6e2010-04-30 18:09:36 +0200764 atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num);
Christof Schmitt287ac012008-07-02 10:56:40 +0200765 if (zfcp_status_read_refill(act->adapter))
766 return ZFCP_ERP_FAILED;
767
768 return ZFCP_ERP_SUCCEEDED;
769}
770
Swen Schilligcf13c082009-03-02 13:09:03 +0100771static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act)
Christof Schmitt287ac012008-07-02 10:56:40 +0200772{
Christof Schmitt287ac012008-07-02 10:56:40 +0200773 struct zfcp_adapter *adapter = act->adapter;
774
Christof Schmitt287ac012008-07-02 10:56:40 +0200775 /* close queues to ensure that buffers are not accessed by adapter */
Swen Schillig564e1c82009-08-18 15:43:19 +0200776 zfcp_qdio_close(adapter->qdio);
Christof Schmitt287ac012008-07-02 10:56:40 +0200777 zfcp_fsf_req_dismiss_all(adapter);
778 adapter->fsf_req_seq_no = 0;
Christof Schmitt55c770f2009-08-18 15:43:12 +0200779 zfcp_fc_wka_ports_force_offline(adapter->gs);
Christof Schmittb62a8d92010-09-08 14:39:55 +0200780 /* all ports and LUNs are closed */
Swen Schilligedaed852010-09-08 14:40:01 +0200781 zfcp_erp_clear_adapter_status(adapter, ZFCP_STATUS_COMMON_OPEN);
Swen Schilligcf13c082009-03-02 13:09:03 +0100782
Christof Schmitt287ac012008-07-02 10:56:40 +0200783 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
Swen Schilligcf13c082009-03-02 13:09:03 +0100784 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
785}
786
787static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act)
788{
789 struct zfcp_adapter *adapter = act->adapter;
790
791 if (zfcp_erp_adapter_strategy_open_qdio(act)) {
792 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
793 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
794 &adapter->status);
795 return ZFCP_ERP_FAILED;
796 }
797
798 if (zfcp_erp_adapter_strategy_open_fsf(act)) {
799 zfcp_erp_adapter_strategy_close(act);
800 return ZFCP_ERP_FAILED;
801 }
802
803 atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &adapter->status);
804
805 return ZFCP_ERP_SUCCEEDED;
Christof Schmitt287ac012008-07-02 10:56:40 +0200806}
807
808static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act)
809{
Swen Schilligcf13c082009-03-02 13:09:03 +0100810 struct zfcp_adapter *adapter = act->adapter;
Christof Schmitt287ac012008-07-02 10:56:40 +0200811
Swen Schilligcf13c082009-03-02 13:09:03 +0100812 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN) {
813 zfcp_erp_adapter_strategy_close(act);
814 if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
815 return ZFCP_ERP_EXIT;
816 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200817
Swen Schilligcf13c082009-03-02 13:09:03 +0100818 if (zfcp_erp_adapter_strategy_open(act)) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200819 ssleep(8);
Swen Schilligcf13c082009-03-02 13:09:03 +0100820 return ZFCP_ERP_FAILED;
821 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
Swen Schilligcf13c082009-03-02 13:09:03 +0100823 return ZFCP_ERP_SUCCEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824}
825
Christof Schmitt287ac012008-07-02 10:56:40 +0200826static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827{
Christof Schmitt287ac012008-07-02 10:56:40 +0200828 int retval;
829
830 retval = zfcp_fsf_close_physical_port(act);
831 if (retval == -ENOMEM)
832 return ZFCP_ERP_NOMEM;
833 act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING;
834 if (retval)
835 return ZFCP_ERP_FAILED;
836
837 return ZFCP_ERP_CONTINUES;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838}
839
Christof Schmitt287ac012008-07-02 10:56:40 +0200840static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841{
Christof Schmitta5b11dd2009-03-02 13:08:54 +0100842 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200843}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
Christof Schmitt287ac012008-07-02 10:56:40 +0200845static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
846{
847 struct zfcp_port *port = erp_action->port;
848 int status = atomic_read(&port->status);
849
850 switch (erp_action->step) {
851 case ZFCP_ERP_STEP_UNINITIALIZED:
852 zfcp_erp_port_strategy_clearstati(port);
853 if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) &&
854 (status & ZFCP_STATUS_COMMON_OPEN))
855 return zfcp_erp_port_forced_strategy_close(erp_action);
856 else
857 return ZFCP_ERP_FAILED;
858
859 case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
Christof Schmittddb3e0c2009-07-13 15:06:08 +0200860 if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN))
Christof Schmitt287ac012008-07-02 10:56:40 +0200861 return ZFCP_ERP_SUCCEEDED;
862 }
863 return ZFCP_ERP_FAILED;
864}
865
866static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action)
867{
868 int retval;
869
870 retval = zfcp_fsf_close_port(erp_action);
871 if (retval == -ENOMEM)
872 return ZFCP_ERP_NOMEM;
873 erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING;
874 if (retval)
875 return ZFCP_ERP_FAILED;
876 return ZFCP_ERP_CONTINUES;
877}
878
879static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action)
880{
881 int retval;
882
883 retval = zfcp_fsf_open_port(erp_action);
884 if (retval == -ENOMEM)
885 return ZFCP_ERP_NOMEM;
886 erp_action->step = ZFCP_ERP_STEP_PORT_OPENING;
887 if (retval)
888 return ZFCP_ERP_FAILED;
889 return ZFCP_ERP_CONTINUES;
890}
891
Christof Schmitt287ac012008-07-02 10:56:40 +0200892static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
893{
894 struct zfcp_adapter *adapter = act->adapter;
895 struct zfcp_port *port = act->port;
896
897 if (port->wwpn != adapter->peer_wwpn) {
Swen Schilligedaed852010-09-08 14:40:01 +0200898 zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED);
Christof Schmitt287ac012008-07-02 10:56:40 +0200899 return ZFCP_ERP_FAILED;
900 }
901 port->d_id = adapter->peer_d_id;
Christof Schmitt287ac012008-07-02 10:56:40 +0200902 return zfcp_erp_port_strategy_open_port(act);
903}
904
905static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
906{
907 struct zfcp_adapter *adapter = act->adapter;
908 struct zfcp_port *port = act->port;
Christof Schmitt287ac012008-07-02 10:56:40 +0200909 int p_status = atomic_read(&port->status);
910
911 switch (act->step) {
912 case ZFCP_ERP_STEP_UNINITIALIZED:
913 case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
914 case ZFCP_ERP_STEP_PORT_CLOSING:
915 if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
916 return zfcp_erp_open_ptp_port(act);
Christof Schmittb98478d2008-12-19 16:56:59 +0100917 if (!port->d_id) {
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200918 zfcp_fc_trigger_did_lookup(port);
Christof Schmitt799b76d2009-08-18 15:43:20 +0200919 return ZFCP_ERP_EXIT;
Christof Schmitt287ac012008-07-02 10:56:40 +0200920 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200921 return zfcp_erp_port_strategy_open_port(act);
922
923 case ZFCP_ERP_STEP_PORT_OPENING:
924 /* D_ID might have changed during open */
Swen Schillig5ab944f2008-10-01 12:42:17 +0200925 if (p_status & ZFCP_STATUS_COMMON_OPEN) {
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200926 if (!port->d_id) {
927 zfcp_fc_trigger_did_lookup(port);
928 return ZFCP_ERP_EXIT;
Swen Schillig5ab944f2008-10-01 12:42:17 +0200929 }
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200930 return ZFCP_ERP_SUCCEEDED;
Swen Schillig5ab944f2008-10-01 12:42:17 +0200931 }
Swen Schilligea460a82009-05-15 13:18:20 +0200932 if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
933 port->d_id = 0;
Christof Schmittf7bd7c32010-07-08 09:53:10 +0200934 return ZFCP_ERP_FAILED;
Swen Schilligea460a82009-05-15 13:18:20 +0200935 }
936 /* fall through otherwise */
Christof Schmitt287ac012008-07-02 10:56:40 +0200937 }
938 return ZFCP_ERP_FAILED;
939}
940
Christof Schmitt287ac012008-07-02 10:56:40 +0200941static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
942{
943 struct zfcp_port *port = erp_action->port;
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200944 int p_status = atomic_read(&port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200945
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200946 if ((p_status & ZFCP_STATUS_COMMON_NOESC) &&
947 !(p_status & ZFCP_STATUS_COMMON_OPEN))
Swen Schillig5ab944f2008-10-01 12:42:17 +0200948 goto close_init_done;
949
Christof Schmitt287ac012008-07-02 10:56:40 +0200950 switch (erp_action->step) {
951 case ZFCP_ERP_STEP_UNINITIALIZED:
952 zfcp_erp_port_strategy_clearstati(port);
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200953 if (p_status & ZFCP_STATUS_COMMON_OPEN)
Christof Schmitt287ac012008-07-02 10:56:40 +0200954 return zfcp_erp_port_strategy_close(erp_action);
955 break;
956
957 case ZFCP_ERP_STEP_PORT_CLOSING:
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200958 if (p_status & ZFCP_STATUS_COMMON_OPEN)
Christof Schmitt287ac012008-07-02 10:56:40 +0200959 return ZFCP_ERP_FAILED;
960 break;
961 }
Swen Schillig5ab944f2008-10-01 12:42:17 +0200962
963close_init_done:
Christof Schmitt287ac012008-07-02 10:56:40 +0200964 if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
965 return ZFCP_ERP_EXIT;
Christof Schmitt287ac012008-07-02 10:56:40 +0200966
Swen Schillig5ab944f2008-10-01 12:42:17 +0200967 return zfcp_erp_port_strategy_open_common(erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968}
969
Christof Schmittb62a8d92010-09-08 14:39:55 +0200970static void zfcp_erp_lun_strategy_clearstati(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200972 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
973
Swen Schillig44cc76f2008-10-01 12:42:16 +0200974 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
Christof Schmittb62a8d92010-09-08 14:39:55 +0200975 ZFCP_STATUS_LUN_SHARED | ZFCP_STATUS_LUN_READONLY,
976 &zfcp_sdev->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977}
978
Christof Schmittb62a8d92010-09-08 14:39:55 +0200979static int zfcp_erp_lun_strategy_close(struct zfcp_erp_action *erp_action)
Christof Schmitt287ac012008-07-02 10:56:40 +0200980{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200981 int retval = zfcp_fsf_close_lun(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +0200982 if (retval == -ENOMEM)
983 return ZFCP_ERP_NOMEM;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200984 erp_action->step = ZFCP_ERP_STEP_LUN_CLOSING;
Christof Schmitt287ac012008-07-02 10:56:40 +0200985 if (retval)
986 return ZFCP_ERP_FAILED;
987 return ZFCP_ERP_CONTINUES;
988}
989
Christof Schmittb62a8d92010-09-08 14:39:55 +0200990static int zfcp_erp_lun_strategy_open(struct zfcp_erp_action *erp_action)
Christof Schmitt287ac012008-07-02 10:56:40 +0200991{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200992 int retval = zfcp_fsf_open_lun(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +0200993 if (retval == -ENOMEM)
994 return ZFCP_ERP_NOMEM;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200995 erp_action->step = ZFCP_ERP_STEP_LUN_OPENING;
Christof Schmitt287ac012008-07-02 10:56:40 +0200996 if (retval)
997 return ZFCP_ERP_FAILED;
998 return ZFCP_ERP_CONTINUES;
999}
1000
Christof Schmittb62a8d92010-09-08 14:39:55 +02001001static int zfcp_erp_lun_strategy(struct zfcp_erp_action *erp_action)
Christof Schmitt287ac012008-07-02 10:56:40 +02001002{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001003 struct scsi_device *sdev = erp_action->sdev;
1004 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +02001005
1006 switch (erp_action->step) {
1007 case ZFCP_ERP_STEP_UNINITIALIZED:
Christof Schmittb62a8d92010-09-08 14:39:55 +02001008 zfcp_erp_lun_strategy_clearstati(sdev);
1009 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
1010 return zfcp_erp_lun_strategy_close(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +02001011 /* already closed, fall through */
Christof Schmittb62a8d92010-09-08 14:39:55 +02001012 case ZFCP_ERP_STEP_LUN_CLOSING:
1013 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
Christof Schmitt287ac012008-07-02 10:56:40 +02001014 return ZFCP_ERP_FAILED;
1015 if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
1016 return ZFCP_ERP_EXIT;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001017 return zfcp_erp_lun_strategy_open(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +02001018
Christof Schmittb62a8d92010-09-08 14:39:55 +02001019 case ZFCP_ERP_STEP_LUN_OPENING:
1020 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
Christof Schmitt287ac012008-07-02 10:56:40 +02001021 return ZFCP_ERP_SUCCEEDED;
1022 }
1023 return ZFCP_ERP_FAILED;
1024}
1025
Christof Schmittb62a8d92010-09-08 14:39:55 +02001026static int zfcp_erp_strategy_check_lun(struct scsi_device *sdev, int result)
Christof Schmitt287ac012008-07-02 10:56:40 +02001027{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001028 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
1029
Christof Schmitt287ac012008-07-02 10:56:40 +02001030 switch (result) {
1031 case ZFCP_ERP_SUCCEEDED :
Christof Schmittb62a8d92010-09-08 14:39:55 +02001032 atomic_set(&zfcp_sdev->erp_counter, 0);
1033 zfcp_erp_lun_unblock(sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +02001034 break;
1035 case ZFCP_ERP_FAILED :
Christof Schmittb62a8d92010-09-08 14:39:55 +02001036 atomic_inc(&zfcp_sdev->erp_counter);
1037 if (atomic_read(&zfcp_sdev->erp_counter) > ZFCP_MAX_ERPS) {
1038 dev_err(&zfcp_sdev->port->adapter->ccw_device->dev,
1039 "ERP failed for LUN 0x%016Lx on "
Christof Schmittff3b24f2008-10-01 12:42:15 +02001040 "port 0x%016Lx\n",
Christof Schmittb62a8d92010-09-08 14:39:55 +02001041 (unsigned long long)zfcp_scsi_dev_lun(sdev),
1042 (unsigned long long)zfcp_sdev->port->wwpn);
Swen Schilligedaed852010-09-08 14:40:01 +02001043 zfcp_erp_set_lun_status(sdev,
1044 ZFCP_STATUS_COMMON_ERP_FAILED);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001045 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001046 break;
1047 }
1048
Christof Schmittb62a8d92010-09-08 14:39:55 +02001049 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1050 zfcp_erp_lun_block(sdev, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +02001051 result = ZFCP_ERP_EXIT;
1052 }
1053 return result;
1054}
1055
1056static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
1057{
1058 switch (result) {
1059 case ZFCP_ERP_SUCCEEDED :
1060 atomic_set(&port->erp_counter, 0);
1061 zfcp_erp_port_unblock(port);
1062 break;
1063
1064 case ZFCP_ERP_FAILED :
1065 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) {
1066 zfcp_erp_port_block(port, 0);
1067 result = ZFCP_ERP_EXIT;
1068 }
1069 atomic_inc(&port->erp_counter);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001070 if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
1071 dev_err(&port->adapter->ccw_device->dev,
1072 "ERP failed for remote port 0x%016Lx\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001073 (unsigned long long)port->wwpn);
Swen Schilligedaed852010-09-08 14:40:01 +02001074 zfcp_erp_set_port_status(port,
1075 ZFCP_STATUS_COMMON_ERP_FAILED);
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 Schilligedaed852010-09-08 14:40:01 +02001102 zfcp_erp_set_adapter_status(adapter,
1103 ZFCP_STATUS_COMMON_ERP_FAILED);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001104 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001105 break;
1106 }
1107
1108 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1109 zfcp_erp_adapter_block(adapter, 0);
1110 result = ZFCP_ERP_EXIT;
1111 }
1112 return result;
1113}
1114
1115static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action,
1116 int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117{
1118 struct zfcp_adapter *adapter = erp_action->adapter;
1119 struct zfcp_port *port = erp_action->port;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001120 struct scsi_device *sdev = erp_action->sdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 switch (erp_action->action) {
1123
Christof Schmittb62a8d92010-09-08 14:39:55 +02001124 case ZFCP_ERP_ACTION_REOPEN_LUN:
1125 result = zfcp_erp_strategy_check_lun(sdev, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 break;
1127
1128 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1129 case ZFCP_ERP_ACTION_REOPEN_PORT:
1130 result = zfcp_erp_strategy_check_port(port, result);
1131 break;
1132
1133 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1134 result = zfcp_erp_strategy_check_adapter(adapter, result);
1135 break;
1136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 return result;
1138}
1139
Christof Schmitt287ac012008-07-02 10:56:40 +02001140static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141{
Christof Schmitt287ac012008-07-02 10:56:40 +02001142 int status = atomic_read(target_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Christof Schmitt287ac012008-07-02 10:56:40 +02001144 if ((status & ZFCP_STATUS_COMMON_RUNNING) &&
1145 (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1146 return 1; /* take it online */
1147
1148 if (!(status & ZFCP_STATUS_COMMON_RUNNING) &&
1149 !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1150 return 1; /* take it offline */
1151
1152 return 0;
1153}
1154
1155static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
1156{
1157 int action = act->action;
1158 struct zfcp_adapter *adapter = act->adapter;
1159 struct zfcp_port *port = act->port;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001160 struct scsi_device *sdev = act->sdev;
1161 struct zfcp_scsi_dev *zfcp_sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +02001162 u32 erp_status = act->status;
1163
1164 switch (action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitt287ac012008-07-02 10:56:40 +02001166 if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) {
1167 _zfcp_erp_adapter_reopen(adapter,
1168 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001169 "ersscg1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001170 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 }
1172 break;
1173
1174 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1175 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitt287ac012008-07-02 10:56:40 +02001176 if (zfcp_erp_strat_change_det(&port->status, erp_status)) {
1177 _zfcp_erp_port_reopen(port,
1178 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001179 "ersscg2", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001180 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 }
1182 break;
1183
Christof Schmittb62a8d92010-09-08 14:39:55 +02001184 case ZFCP_ERP_ACTION_REOPEN_LUN:
1185 zfcp_sdev = sdev_to_zfcp(sdev);
1186 if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) {
1187 _zfcp_erp_lun_reopen(sdev,
1188 ZFCP_STATUS_COMMON_ERP_FAILED,
1189 "ersscg3", NULL, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +02001190 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 }
1192 break;
1193 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001194 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195}
1196
Christof Schmitt287ac012008-07-02 10:56:40 +02001197static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198{
Christof Schmitt287ac012008-07-02 10:56:40 +02001199 struct zfcp_adapter *adapter = erp_action->adapter;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001200 struct zfcp_scsi_dev *zfcp_sdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201
Christof Schmitt287ac012008-07-02 10:56:40 +02001202 adapter->erp_total_count--;
1203 if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1204 adapter->erp_low_mem_count--;
1205 erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 }
1207
Christof Schmitt287ac012008-07-02 10:56:40 +02001208 list_del(&erp_action->list);
Swen Schillig57717102009-08-18 15:43:21 +02001209 zfcp_dbf_rec_action("eractd1", erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
Christof Schmitt287ac012008-07-02 10:56:40 +02001211 switch (erp_action->action) {
Christof Schmittb62a8d92010-09-08 14:39:55 +02001212 case ZFCP_ERP_ACTION_REOPEN_LUN:
1213 zfcp_sdev = sdev_to_zfcp(erp_action->sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +02001214 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
Christof Schmittb62a8d92010-09-08 14:39:55 +02001215 &zfcp_sdev->status);
Christof Schmitt287ac012008-07-02 10:56:40 +02001216 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
Christof Schmitt287ac012008-07-02 10:56:40 +02001218 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1219 case ZFCP_ERP_ACTION_REOPEN_PORT:
1220 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1221 &erp_action->port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001223
1224 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1225 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1226 &erp_action->adapter->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 break;
1228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229}
1230
Christof Schmitt287ac012008-07-02 10:56:40 +02001231static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001232{
Christof Schmitt287ac012008-07-02 10:56:40 +02001233 struct zfcp_adapter *adapter = act->adapter;
1234 struct zfcp_port *port = act->port;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001235 struct scsi_device *sdev = act->sdev;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001236
Christof Schmitt287ac012008-07-02 10:56:40 +02001237 switch (act->action) {
Christof Schmittb62a8d92010-09-08 14:39:55 +02001238 case ZFCP_ERP_ACTION_REOPEN_LUN:
Christof Schmittfdbd1c52010-09-08 14:39:54 +02001239 if (!(act->status & ZFCP_STATUS_ERP_NO_REF))
Christof Schmittb62a8d92010-09-08 14:39:55 +02001240 scsi_device_put(sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001242
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001244 if (result == ZFCP_ERP_SUCCEEDED)
1245 zfcp_scsi_schedule_rport_register(port);
Christof Schmitt57676202010-07-08 09:53:05 +02001246 /* fall through */
1247 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
Christof Schmitt615f59e2010-02-17 11:18:56 +01001248 put_device(&port->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001250
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001252 if (result == ZFCP_ERP_SUCCEEDED) {
Christof Schmittbd43a42b72008-12-25 13:38:50 +01001253 register_service_level(&adapter->service_level);
Swen Schillig9eae07e2009-11-24 16:54:06 +01001254 queue_work(adapter->work_queue, &adapter->scan_work);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001255 } else
1256 unregister_service_level(&adapter->service_level);
Swen Schilligf3450c72009-11-24 16:53:59 +01001257 kref_put(&adapter->ref, zfcp_adapter_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 }
1260}
1261
Christof Schmitt287ac012008-07-02 10:56:40 +02001262static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
1263{
1264 switch (erp_action->action) {
1265 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1266 return zfcp_erp_adapter_strategy(erp_action);
1267 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1268 return zfcp_erp_port_forced_strategy(erp_action);
1269 case ZFCP_ERP_ACTION_REOPEN_PORT:
1270 return zfcp_erp_port_strategy(erp_action);
Christof Schmittb62a8d92010-09-08 14:39:55 +02001271 case ZFCP_ERP_ACTION_REOPEN_LUN:
1272 return zfcp_erp_lun_strategy(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +02001273 }
1274 return ZFCP_ERP_FAILED;
1275}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276
Christof Schmitt287ac012008-07-02 10:56:40 +02001277static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
1278{
1279 int retval;
Christof Schmitt287ac012008-07-02 10:56:40 +02001280 unsigned long flags;
Swen Schilligecf0c772009-11-24 16:53:58 +01001281 struct zfcp_adapter *adapter = erp_action->adapter;
Christof Schmitt287ac012008-07-02 10:56:40 +02001282
Swen Schilligf3450c72009-11-24 16:53:59 +01001283 kref_get(&adapter->ref);
Christof Schmitt287ac012008-07-02 10:56:40 +02001284
Swen Schilligf3450c72009-11-24 16:53:59 +01001285 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001286 zfcp_erp_strategy_check_fsfreq(erp_action);
1287
1288 if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
1289 zfcp_erp_action_dequeue(erp_action);
1290 retval = ZFCP_ERP_DISMISSED;
1291 goto unlock;
1292 }
1293
Christof Schmitt9c785d92010-07-08 09:53:09 +02001294 if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
1295 retval = ZFCP_ERP_FAILED;
1296 goto check_target;
1297 }
1298
Christof Schmitt287ac012008-07-02 10:56:40 +02001299 zfcp_erp_action_to_running(erp_action);
1300
1301 /* no lock to allow for blocking operations */
Swen Schilligecf0c772009-11-24 16:53:58 +01001302 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001303 retval = zfcp_erp_strategy_do_action(erp_action);
Swen Schilligecf0c772009-11-24 16:53:58 +01001304 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001305
1306 if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED)
1307 retval = ZFCP_ERP_CONTINUES;
1308
1309 switch (retval) {
1310 case ZFCP_ERP_NOMEM:
1311 if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) {
1312 ++adapter->erp_low_mem_count;
1313 erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
1314 }
1315 if (adapter->erp_total_count == adapter->erp_low_mem_count)
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001316 _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001317 else {
1318 zfcp_erp_strategy_memwait(erp_action);
1319 retval = ZFCP_ERP_CONTINUES;
1320 }
1321 goto unlock;
1322
1323 case ZFCP_ERP_CONTINUES:
1324 if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1325 --adapter->erp_low_mem_count;
1326 erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
1327 }
1328 goto unlock;
1329 }
1330
Christof Schmitt9c785d92010-07-08 09:53:09 +02001331check_target:
Christof Schmitt287ac012008-07-02 10:56:40 +02001332 retval = zfcp_erp_strategy_check_target(erp_action, retval);
1333 zfcp_erp_action_dequeue(erp_action);
1334 retval = zfcp_erp_strategy_statechange(erp_action, retval);
1335 if (retval == ZFCP_ERP_EXIT)
1336 goto unlock;
Christof Schmitt85600f72009-07-13 15:06:09 +02001337 if (retval == ZFCP_ERP_SUCCEEDED)
1338 zfcp_erp_strategy_followup_success(erp_action);
1339 if (retval == ZFCP_ERP_FAILED)
1340 zfcp_erp_strategy_followup_failed(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +02001341
1342 unlock:
Swen Schilligecf0c772009-11-24 16:53:58 +01001343 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001344
1345 if (retval != ZFCP_ERP_CONTINUES)
1346 zfcp_erp_action_cleanup(erp_action, retval);
1347
Swen Schilligf3450c72009-11-24 16:53:59 +01001348 kref_put(&adapter->ref, zfcp_adapter_release);
Christof Schmitt287ac012008-07-02 10:56:40 +02001349 return retval;
1350}
1351
1352static int zfcp_erp_thread(void *data)
1353{
1354 struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
1355 struct list_head *next;
1356 struct zfcp_erp_action *act;
1357 unsigned long flags;
1358
Christof Schmitt347c6a92009-08-18 15:43:25 +02001359 for (;;) {
Swen Schillig57717102009-08-18 15:43:21 +02001360 zfcp_dbf_rec_thread_lock("erthrd1", adapter->dbf);
Christof Schmitt347c6a92009-08-18 15:43:25 +02001361 wait_event_interruptible(adapter->erp_ready_wq,
1362 !list_empty(&adapter->erp_ready_head) ||
1363 kthread_should_stop());
Swen Schillig57717102009-08-18 15:43:21 +02001364 zfcp_dbf_rec_thread_lock("erthrd2", adapter->dbf);
Swen Schillig94ab4b32009-04-17 15:08:06 +02001365
Christof Schmitt347c6a92009-08-18 15:43:25 +02001366 if (kthread_should_stop())
1367 break;
1368
Christof Schmitt287ac012008-07-02 10:56:40 +02001369 write_lock_irqsave(&adapter->erp_lock, flags);
1370 next = adapter->erp_ready_head.next;
1371 write_unlock_irqrestore(&adapter->erp_lock, flags);
1372
1373 if (next != &adapter->erp_ready_head) {
1374 act = list_entry(next, struct zfcp_erp_action, list);
1375
1376 /* there is more to come after dismission, no notify */
1377 if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED)
1378 zfcp_erp_wakeup(adapter);
1379 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001380 }
1381
Christof Schmitt287ac012008-07-02 10:56:40 +02001382 return 0;
1383}
1384
1385/**
1386 * zfcp_erp_thread_setup - Start ERP thread for adapter
1387 * @adapter: Adapter to start the ERP thread for
1388 *
1389 * Returns 0 on success or error code from kernel_thread()
1390 */
1391int zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
1392{
Christof Schmitt347c6a92009-08-18 15:43:25 +02001393 struct task_struct *thread;
Christof Schmitt287ac012008-07-02 10:56:40 +02001394
Christof Schmitt347c6a92009-08-18 15:43:25 +02001395 thread = kthread_run(zfcp_erp_thread, adapter, "zfcperp%s",
1396 dev_name(&adapter->ccw_device->dev));
1397 if (IS_ERR(thread)) {
Christof Schmitt287ac012008-07-02 10:56:40 +02001398 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001399 "Creating an ERP thread for the FCP device failed.\n");
Christof Schmitt347c6a92009-08-18 15:43:25 +02001400 return PTR_ERR(thread);
Christof Schmitt287ac012008-07-02 10:56:40 +02001401 }
Christof Schmitt347c6a92009-08-18 15:43:25 +02001402
1403 adapter->erp_thread = thread;
Christof Schmitt287ac012008-07-02 10:56:40 +02001404 return 0;
1405}
1406
1407/**
1408 * zfcp_erp_thread_kill - Stop ERP thread.
1409 * @adapter: Adapter where the ERP thread should be stopped.
1410 *
1411 * The caller of this routine ensures that the specified adapter has
1412 * been shut down and that this operation has been completed. Thus,
1413 * there are no pending erp_actions which would need to be handled
1414 * here.
1415 */
1416void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
1417{
Christof Schmitt347c6a92009-08-18 15:43:25 +02001418 kthread_stop(adapter->erp_thread);
1419 adapter->erp_thread = NULL;
Christof Schmitt143bb6b2009-08-18 15:43:27 +02001420 WARN_ON(!list_empty(&adapter->erp_ready_head));
1421 WARN_ON(!list_empty(&adapter->erp_running_head));
Christof Schmitt287ac012008-07-02 10:56:40 +02001422}
1423
1424/**
Christof Schmitt287ac012008-07-02 10:56:40 +02001425 * zfcp_erp_wait - wait for completion of error recovery on an adapter
1426 * @adapter: adapter for which to wait for completion of its error recovery
1427 */
1428void zfcp_erp_wait(struct zfcp_adapter *adapter)
1429{
1430 wait_event(adapter->erp_done_wqh,
1431 !(atomic_read(&adapter->status) &
1432 ZFCP_STATUS_ADAPTER_ERP_PENDING));
1433}
1434
1435/**
Swen Schilligedaed852010-09-08 14:40:01 +02001436 * zfcp_erp_set_adapter_status - set adapter status bits
Christof Schmitt287ac012008-07-02 10:56:40 +02001437 * @adapter: adapter to change the status
Christof Schmitt287ac012008-07-02 10:56:40 +02001438 * @mask: status bits to change
Christof Schmitt287ac012008-07-02 10:56:40 +02001439 *
Christof Schmittb62a8d92010-09-08 14:39:55 +02001440 * Changes in common status bits are propagated to attached ports and LUNs.
Christof Schmitt287ac012008-07-02 10:56:40 +02001441 */
Swen Schilligedaed852010-09-08 14:40:01 +02001442void zfcp_erp_set_adapter_status(struct zfcp_adapter *adapter, u32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 struct zfcp_port *port;
Swen Schilligedaed852010-09-08 14:40:01 +02001445 struct scsi_device *sdev;
Swen Schilligecf0c772009-11-24 16:53:58 +01001446 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +02001447 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
Swen Schilligedaed852010-09-08 14:40:01 +02001449 atomic_set_mask(mask, &adapter->status);
Christof Schmitt287ac012008-07-02 10:56:40 +02001450
Swen Schilligedaed852010-09-08 14:40:01 +02001451 if (!common_mask)
1452 return;
1453
1454 read_lock_irqsave(&adapter->port_list_lock, flags);
1455 list_for_each_entry(port, &adapter->port_list, list)
1456 atomic_set_mask(common_mask, &port->status);
1457 read_unlock_irqrestore(&adapter->port_list_lock, flags);
1458
1459 shost_for_each_device(sdev, adapter->scsi_host)
1460 atomic_set_mask(common_mask, &sdev_to_zfcp(sdev)->status);
1461}
1462
1463/**
1464 * zfcp_erp_clear_adapter_status - clear adapter status bits
1465 * @adapter: adapter to change the status
1466 * @mask: status bits to change
1467 *
1468 * Changes in common status bits are propagated to attached ports and LUNs.
1469 */
1470void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask)
1471{
1472 struct zfcp_port *port;
1473 struct scsi_device *sdev;
1474 unsigned long flags;
1475 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
1476 u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED;
1477
1478 atomic_clear_mask(mask, &adapter->status);
1479
1480 if (!common_mask)
1481 return;
1482
1483 if (clear_counter)
1484 atomic_set(&adapter->erp_counter, 0);
1485
1486 read_lock_irqsave(&adapter->port_list_lock, flags);
1487 list_for_each_entry(port, &adapter->port_list, list) {
1488 atomic_clear_mask(common_mask, &port->status);
1489 if (clear_counter)
1490 atomic_set(&port->erp_counter, 0);
1491 }
1492 read_unlock_irqrestore(&adapter->port_list_lock, flags);
1493
1494 shost_for_each_device(sdev, adapter->scsi_host) {
1495 atomic_clear_mask(common_mask, &sdev_to_zfcp(sdev)->status);
1496 if (clear_counter)
1497 atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
Swen Schilligecf0c772009-11-24 16:53:58 +01001498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499}
1500
Christof Schmitt287ac012008-07-02 10:56:40 +02001501/**
Swen Schilligedaed852010-09-08 14:40:01 +02001502 * zfcp_erp_set_port_status - set port status bits
1503 * @port: port to change the status
Christof Schmitt287ac012008-07-02 10:56:40 +02001504 * @mask: status bits to change
Christof Schmitt287ac012008-07-02 10:56:40 +02001505 *
Christof Schmittb62a8d92010-09-08 14:39:55 +02001506 * Changes in common status bits are propagated to attached LUNs.
Christof Schmitt287ac012008-07-02 10:56:40 +02001507 */
Swen Schilligedaed852010-09-08 14:40:01 +02001508void zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001510 struct scsi_device *sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +02001511 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512
Swen Schilligedaed852010-09-08 14:40:01 +02001513 atomic_set_mask(mask, &port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +02001514
Swen Schilligedaed852010-09-08 14:40:01 +02001515 if (!common_mask)
1516 return;
1517
1518 shost_for_each_device(sdev, port->adapter->scsi_host)
1519 if (sdev_to_zfcp(sdev)->port == port)
1520 atomic_set_mask(common_mask,
1521 &sdev_to_zfcp(sdev)->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522}
1523
Christof Schmitt287ac012008-07-02 10:56:40 +02001524/**
Swen Schilligedaed852010-09-08 14:40:01 +02001525 * zfcp_erp_clear_port_status - clear port status bits
1526 * @port: adapter to change the status
Christof Schmitt287ac012008-07-02 10:56:40 +02001527 * @mask: status bits to change
Swen Schilligedaed852010-09-08 14:40:01 +02001528 *
1529 * Changes in common status bits are propagated to attached LUNs.
Christof Schmitt287ac012008-07-02 10:56:40 +02001530 */
Swen Schilligedaed852010-09-08 14:40:01 +02001531void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask)
1532{
1533 struct scsi_device *sdev;
1534 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
1535 u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED;
1536
1537 atomic_clear_mask(mask, &port->status);
1538
1539 if (!common_mask)
1540 return;
1541
1542 if (clear_counter)
1543 atomic_set(&port->erp_counter, 0);
1544
1545 shost_for_each_device(sdev, port->adapter->scsi_host)
1546 if (sdev_to_zfcp(sdev)->port == port) {
1547 atomic_clear_mask(common_mask,
1548 &sdev_to_zfcp(sdev)->status);
1549 if (clear_counter)
1550 atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
1551 }
1552}
1553
1554/**
1555 * zfcp_erp_set_lun_status - set lun status bits
1556 * @sdev: SCSI device / lun to set the status bits
1557 * @mask: status bits to change
1558 */
1559void zfcp_erp_set_lun_status(struct scsi_device *sdev, u32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001561 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
1562
Swen Schilligedaed852010-09-08 14:40:01 +02001563 atomic_set_mask(mask, &zfcp_sdev->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564}
1565
Christof Schmitt287ac012008-07-02 10:56:40 +02001566/**
Swen Schilligedaed852010-09-08 14:40:01 +02001567 * zfcp_erp_clear_lun_status - clear lun status bits
1568 * @sdev: SCSi device / lun to clear the status bits
1569 * @mask: status bits to change
Christof Schmitt287ac012008-07-02 10:56:40 +02001570 */
Swen Schilligedaed852010-09-08 14:40:01 +02001571void zfcp_erp_clear_lun_status(struct scsi_device *sdev, u32 mask)
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001572{
Swen Schilligedaed852010-09-08 14:40:01 +02001573 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
1574
1575 atomic_clear_mask(mask, &zfcp_sdev->status);
1576
1577 if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
1578 atomic_set(&zfcp_sdev->erp_counter, 0);
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001579}
1580