blob: 63422c13c7dab28c3da595325c5b877fcfd6e6b2 [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 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;
193 if (!(atomic_read(&zfcp_sdev->status) &
194 ZFCP_STATUS_COMMON_RUNNING))
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200195 act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
Christof Schmitt287ac012008-07-02 10:56:40 +0200196 break;
197
198 case ZFCP_ERP_ACTION_REOPEN_PORT:
199 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
Christof Schmitt615f59e2010-02-17 11:18:56 +0100200 if (!get_device(&port->dev))
Swen Schillig6b1833342009-11-24 16:54:05 +0100201 return NULL;
Christof Schmitt287ac012008-07-02 10:56:40 +0200202 zfcp_erp_action_dismiss_port(port);
203 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
204 erp_action = &port->erp_action;
205 if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200206 act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
Christof Schmitt287ac012008-07-02 10:56:40 +0200207 break;
208
209 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Swen Schilligf3450c72009-11-24 16:53:59 +0100210 kref_get(&adapter->ref);
Christof Schmitt287ac012008-07-02 10:56:40 +0200211 zfcp_erp_action_dismiss_adapter(adapter);
212 atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
213 erp_action = &adapter->erp_action;
214 if (!(atomic_read(&adapter->status) &
215 ZFCP_STATUS_COMMON_RUNNING))
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200216 act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
Christof Schmitt287ac012008-07-02 10:56:40 +0200217 break;
218
219 default:
220 return NULL;
221 }
222
223 memset(erp_action, 0, sizeof(struct zfcp_erp_action));
224 erp_action->adapter = adapter;
225 erp_action->port = port;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200226 erp_action->sdev = sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +0200227 erp_action->action = need;
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200228 erp_action->status = act_status;
Christof Schmitt287ac012008-07-02 10:56:40 +0200229
230 return erp_action;
231}
232
233static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
234 struct zfcp_port *port,
Christof Schmittb62a8d92010-09-08 14:39:55 +0200235 struct scsi_device *sdev,
236 char *id, void *ref, u32 act_status)
Christof Schmitt287ac012008-07-02 10:56:40 +0200237{
238 int retval = 1, need;
239 struct zfcp_erp_action *act = NULL;
240
Christof Schmitt347c6a92009-08-18 15:43:25 +0200241 if (!adapter->erp_thread)
Christof Schmitt287ac012008-07-02 10:56:40 +0200242 return -EIO;
243
Christof Schmittb62a8d92010-09-08 14:39:55 +0200244 need = zfcp_erp_required_act(want, adapter, port, sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +0200245 if (!need)
246 goto out;
247
Christof Schmittb62a8d92010-09-08 14:39:55 +0200248 act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +0200249 if (!act)
250 goto out;
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200251 atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200252 ++adapter->erp_total_count;
253 list_add_tail(&act->list, &adapter->erp_ready_head);
Christof Schmitt347c6a92009-08-18 15:43:25 +0200254 wake_up(&adapter->erp_ready_wq);
Swen Schillig57717102009-08-18 15:43:21 +0200255 zfcp_dbf_rec_thread("eracte1", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200256 retval = 0;
257 out:
Christof Schmittb62a8d92010-09-08 14:39:55 +0200258 zfcp_dbf_rec_trigger(id, ref, want, need, act, adapter, port, sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +0200259 return retval;
260}
261
262static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100263 int clear_mask, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200264{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 zfcp_erp_adapter_block(adapter, clear_mask);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100266 zfcp_scsi_schedule_rports_block(adapter);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
Christof Schmitt287ac012008-07-02 10:56:40 +0200268 /* ensure propagation of failed status to new devices */
269 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
Swen Schilligedaed852010-09-08 14:40:01 +0200270 zfcp_erp_set_adapter_status(adapter,
271 ZFCP_STATUS_COMMON_ERP_FAILED);
Christof Schmitt287ac012008-07-02 10:56:40 +0200272 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200274 return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200275 adapter, NULL, NULL, id, ref, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276}
277
278/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200279 * zfcp_erp_adapter_reopen - Reopen adapter.
280 * @adapter: Adapter to reopen.
281 * @clear: Status flags to clear.
282 * @id: Id for debug trace event.
283 * @ref: Reference for debug trace event.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200285void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100286 char *id, void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
Christof Schmitt287ac012008-07-02 10:56:40 +0200288 unsigned long flags;
289
Swen Schilligecf0c772009-11-24 16:53:58 +0100290 zfcp_erp_adapter_block(adapter, clear);
291 zfcp_scsi_schedule_rports_block(adapter);
292
293 write_lock_irqsave(&adapter->erp_lock, flags);
294 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
Swen Schilligedaed852010-09-08 14:40:01 +0200295 zfcp_erp_set_adapter_status(adapter,
296 ZFCP_STATUS_COMMON_ERP_FAILED);
Swen Schilligecf0c772009-11-24 16:53:58 +0100297 else
298 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200299 NULL, NULL, id, ref, 0);
Swen Schilligecf0c772009-11-24 16:53:58 +0100300 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200301}
302
303/**
304 * zfcp_erp_adapter_shutdown - Shutdown adapter.
305 * @adapter: Adapter to shut down.
306 * @clear: Status flags to clear.
307 * @id: Id for debug trace event.
308 * @ref: Reference for debug trace event.
309 */
310void zfcp_erp_adapter_shutdown(struct zfcp_adapter *adapter, int clear,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100311 char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200312{
313 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
314 zfcp_erp_adapter_reopen(adapter, clear | flags, id, ref);
315}
316
317/**
318 * zfcp_erp_port_shutdown - Shutdown port
319 * @port: Port to shut down.
320 * @clear: Status flags to clear.
321 * @id: Id for debug trace event.
322 * @ref: Reference for debug trace event.
323 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100324void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id,
325 void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200326{
327 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
328 zfcp_erp_port_reopen(port, clear | flags, id, ref);
329}
330
Christof Schmitt287ac012008-07-02 10:56:40 +0200331static void zfcp_erp_port_block(struct zfcp_port *port, int clear)
332{
Swen Schilligedaed852010-09-08 14:40:01 +0200333 zfcp_erp_clear_port_status(port,
334 ZFCP_STATUS_COMMON_UNBLOCKED | clear);
Christof Schmitt287ac012008-07-02 10:56:40 +0200335}
336
337static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100338 int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200339{
340 zfcp_erp_port_block(port, clear);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100341 zfcp_scsi_schedule_rport_block(port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200342
343 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
344 return;
345
346 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200347 port->adapter, port, NULL, id, ref, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +0200348}
349
350/**
351 * zfcp_erp_port_forced_reopen - Forced close of port and open again
352 * @port: Port to force close and to reopen.
353 * @id: Id for debug trace event.
354 * @ref: Reference for debug trace event.
355 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100356void zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +0200357 void *ref)
358{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 unsigned long flags;
360 struct zfcp_adapter *adapter = port->adapter;
361
Swen Schilligecf0c772009-11-24 16:53:58 +0100362 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200363 _zfcp_erp_port_forced_reopen(port, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100364 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200365}
366
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100367static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
Christof Schmitt287ac012008-07-02 10:56:40 +0200368 void *ref)
369{
370 zfcp_erp_port_block(port, clear);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +0100371 zfcp_scsi_schedule_rport_block(port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200372
373 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
374 /* ensure propagation of failed status to new devices */
Swen Schilligedaed852010-09-08 14:40:01 +0200375 zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED);
Christof Schmitt287ac012008-07-02 10:56:40 +0200376 return -EIO;
377 }
378
379 return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT,
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200380 port->adapter, port, NULL, id, ref, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +0200381}
382
383/**
384 * zfcp_erp_port_reopen - trigger remote port recovery
385 * @port: port to recover
386 * @clear_mask: flags in port status to be cleared
387 *
388 * Returns 0 if recovery has been triggered, < 0 if not.
389 */
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100390int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200391{
Christof Schmitt287ac012008-07-02 10:56:40 +0200392 int retval;
Swen Schilligecf0c772009-11-24 16:53:58 +0100393 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +0200394 struct zfcp_adapter *adapter = port->adapter;
395
Swen Schilligecf0c772009-11-24 16:53:58 +0100396 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200397 retval = _zfcp_erp_port_reopen(port, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100398 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
400 return retval;
401}
402
Christof Schmittb62a8d92010-09-08 14:39:55 +0200403static void zfcp_erp_lun_block(struct scsi_device *sdev, int clear_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
Swen Schilligedaed852010-09-08 14:40:01 +0200405 zfcp_erp_clear_lun_status(sdev,
406 ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask);
Christof Schmitt287ac012008-07-02 10:56:40 +0200407}
408
Christof Schmittb62a8d92010-09-08 14:39:55 +0200409static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,
410 void *ref, u32 act_status)
Christof Schmitt287ac012008-07-02 10:56:40 +0200411{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200412 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
413 struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Christof Schmittb62a8d92010-09-08 14:39:55 +0200415 zfcp_erp_lun_block(sdev, clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
Christof Schmittb62a8d92010-09-08 14:39:55 +0200417 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
Christof Schmitt287ac012008-07-02 10:56:40 +0200418 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Christof Schmittb62a8d92010-09-08 14:39:55 +0200420 zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter,
421 zfcp_sdev->port, sdev, id, ref, act_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422}
423
424/**
Christof Schmittb62a8d92010-09-08 14:39:55 +0200425 * zfcp_erp_lun_reopen - initiate reopen of a LUN
426 * @sdev: SCSI device / LUN to be reopened
427 * @clear_mask: specifies flags in LUN status to be cleared
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 * Return: 0 on success, < 0 on error
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 */
Christof Schmittb62a8d92010-09-08 14:39:55 +0200430void zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id,
431 void *ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 unsigned long flags;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200434 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
435 struct zfcp_port *port = zfcp_sdev->port;
Christof Schmitt287ac012008-07-02 10:56:40 +0200436 struct zfcp_adapter *adapter = port->adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
Swen Schilligecf0c772009-11-24 16:53:58 +0100438 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmittb62a8d92010-09-08 14:39:55 +0200439 _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0);
Swen Schilligecf0c772009-11-24 16:53:58 +0100440 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441}
442
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200443/**
Christof Schmittb62a8d92010-09-08 14:39:55 +0200444 * zfcp_erp_lun_shutdown - Shutdown LUN
445 * @sdev: SCSI device / LUN to shut down.
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200446 * @clear: Status flags to clear.
447 * @id: Id for debug trace event.
448 * @ref: Reference for debug trace event.
449 */
Christof Schmittb62a8d92010-09-08 14:39:55 +0200450void zfcp_erp_lun_shutdown(struct scsi_device *sdev, int clear, char *id,
451 void *ref)
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200452{
453 int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200454 zfcp_erp_lun_reopen(sdev, clear | flags, id, ref);
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200455}
456
457/**
Christof Schmittb62a8d92010-09-08 14:39:55 +0200458 * zfcp_erp_lun_shutdown_wait - Shutdown LUN and wait for erp completion
459 * @sdev: SCSI device / LUN to shut down.
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200460 * @id: Id for debug trace event.
461 *
Christof Schmittb62a8d92010-09-08 14:39:55 +0200462 * Do not acquire a reference for the LUN when creating the ERP
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200463 * action. It is safe, because this function waits for the ERP to
Christof Schmittb62a8d92010-09-08 14:39:55 +0200464 * complete first. This allows to shutdown the LUN, even when the SCSI
465 * device is in the state SDEV_DEL when scsi_device_get will fail.
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200466 */
Christof Schmittb62a8d92010-09-08 14:39:55 +0200467void zfcp_erp_lun_shutdown_wait(struct scsi_device *sdev, char *id)
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200468{
469 unsigned long flags;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200470 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
471 struct zfcp_port *port = zfcp_sdev->port;
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200472 struct zfcp_adapter *adapter = port->adapter;
473 int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED;
474
475 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmittb62a8d92010-09-08 14:39:55 +0200476 _zfcp_erp_lun_reopen(sdev, clear, id, NULL, ZFCP_STATUS_ERP_NO_REF);
Christof Schmittfdbd1c52010-09-08 14:39:54 +0200477 write_unlock_irqrestore(&adapter->erp_lock, flags);
478
479 zfcp_erp_wait(adapter);
480}
481
Christof Schmitt287ac012008-07-02 10:56:40 +0200482static int status_change_set(unsigned long mask, atomic_t *status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483{
Christof Schmitt287ac012008-07-02 10:56:40 +0200484 return (atomic_read(status) ^ mask) & mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485}
486
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200487static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488{
Christof Schmitt287ac012008-07-02 10:56:40 +0200489 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status))
Swen Schillig57717102009-08-18 15:43:21 +0200490 zfcp_dbf_rec_adapter("eraubl1", NULL, adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200491 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492}
493
Christof Schmitt287ac012008-07-02 10:56:40 +0200494static void zfcp_erp_port_unblock(struct zfcp_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
Christof Schmitt287ac012008-07-02 10:56:40 +0200496 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status))
Swen Schillig57717102009-08-18 15:43:21 +0200497 zfcp_dbf_rec_port("erpubl1", NULL, port);
Christof Schmitt287ac012008-07-02 10:56:40 +0200498 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499}
500
Christof Schmittb62a8d92010-09-08 14:39:55 +0200501static void zfcp_erp_lun_unblock(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200503 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
504
505 if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status))
506 zfcp_dbf_rec_lun("erlubl1", NULL, sdev);
507 atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508}
509
Christof Schmitt287ac012008-07-02 10:56:40 +0200510static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511{
Christof Schmitt287ac012008-07-02 10:56:40 +0200512 list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
Swen Schillig57717102009-08-18 15:43:21 +0200513 zfcp_dbf_rec_action("erator1", erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514}
515
Christof Schmitt287ac012008-07-02 10:56:40 +0200516static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
Christof Schmitt287ac012008-07-02 10:56:40 +0200518 struct zfcp_adapter *adapter = act->adapter;
Christof Schmitte60a6d62010-02-17 11:18:49 +0100519 struct zfcp_fsf_req *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Christof Schmitte60a6d62010-02-17 11:18:49 +0100521 if (!act->fsf_req_id)
Christof Schmitt287ac012008-07-02 10:56:40 +0200522 return;
523
Christof Schmittb6bd2fb2010-02-17 11:18:50 +0100524 spin_lock(&adapter->req_list->lock);
525 req = _zfcp_reqlist_find(adapter->req_list, act->fsf_req_id);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100526 if (req && req->erp_action == act) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200527 if (act->status & (ZFCP_STATUS_ERP_DISMISSED |
528 ZFCP_STATUS_ERP_TIMEDOUT)) {
Christof Schmitte60a6d62010-02-17 11:18:49 +0100529 req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
Swen Schillig57717102009-08-18 15:43:21 +0200530 zfcp_dbf_rec_action("erscf_1", act);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100531 req->erp_action = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200533 if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
Swen Schillig57717102009-08-18 15:43:21 +0200534 zfcp_dbf_rec_action("erscf_2", act);
Christof Schmitte60a6d62010-02-17 11:18:49 +0100535 if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED)
536 act->fsf_req_id = 0;
Christof Schmitt287ac012008-07-02 10:56:40 +0200537 } else
Christof Schmitte60a6d62010-02-17 11:18:49 +0100538 act->fsf_req_id = 0;
Christof Schmittb6bd2fb2010-02-17 11:18:50 +0100539 spin_unlock(&adapter->req_list->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540}
541
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200542/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200543 * zfcp_erp_notify - Trigger ERP action.
544 * @erp_action: ERP action to continue.
545 * @set_mask: ERP action status flags to set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200547void zfcp_erp_notify(struct zfcp_erp_action *erp_action, unsigned long set_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548{
549 struct zfcp_adapter *adapter = erp_action->adapter;
550 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
552 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200553 if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
554 erp_action->status |= set_mask;
555 zfcp_erp_action_ready(erp_action);
556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 write_unlock_irqrestore(&adapter->erp_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558}
559
Andreas Herrmannf6c0e7a2006-08-02 11:05:52 +0200560/**
Christof Schmitt287ac012008-07-02 10:56:40 +0200561 * zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request
562 * @data: ERP action (from timer data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 */
Christof Schmitt287ac012008-07-02 10:56:40 +0200564void zfcp_erp_timeout_handler(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565{
Christof Schmitt287ac012008-07-02 10:56:40 +0200566 struct zfcp_erp_action *act = (struct zfcp_erp_action *) data;
567 zfcp_erp_notify(act, ZFCP_STATUS_ERP_TIMEDOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568}
569
Christof Schmitt287ac012008-07-02 10:56:40 +0200570static void zfcp_erp_memwait_handler(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571{
Christof Schmitt287ac012008-07-02 10:56:40 +0200572 zfcp_erp_notify((struct zfcp_erp_action *)data, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573}
574
Christof Schmitt287ac012008-07-02 10:56:40 +0200575static void zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 init_timer(&erp_action->timer);
578 erp_action->timer.function = zfcp_erp_memwait_handler;
579 erp_action->timer.data = (unsigned long) erp_action;
Christof Schmitt287ac012008-07-02 10:56:40 +0200580 erp_action->timer.expires = jiffies + HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 add_timer(&erp_action->timer);
Christof Schmitt287ac012008-07-02 10:56:40 +0200582}
583
584static void _zfcp_erp_port_reopen_all(struct zfcp_adapter *adapter,
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100585 int clear, char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200586{
587 struct zfcp_port *port;
588
Swen Schilligecf0c772009-11-24 16:53:58 +0100589 read_lock(&adapter->port_list_lock);
590 list_for_each_entry(port, &adapter->port_list, list)
Swen Schillig5ab944f2008-10-01 12:42:17 +0200591 _zfcp_erp_port_reopen(port, clear, id, ref);
Swen Schilligecf0c772009-11-24 16:53:58 +0100592 read_unlock(&adapter->port_list_lock);
Christof Schmitt287ac012008-07-02 10:56:40 +0200593}
594
Christof Schmittb62a8d92010-09-08 14:39:55 +0200595static void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear,
596 char *id, void *ref)
Christof Schmitt287ac012008-07-02 10:56:40 +0200597{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200598 struct scsi_device *sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +0200599
Christof Schmittb62a8d92010-09-08 14:39:55 +0200600 shost_for_each_device(sdev, port->adapter->scsi_host)
601 if (sdev_to_zfcp(sdev)->port == port)
602 _zfcp_erp_lun_reopen(sdev, clear, id, ref, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +0200603}
604
Christof Schmitt85600f72009-07-13 15:06:09 +0200605static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
Christof Schmitt287ac012008-07-02 10:56:40 +0200606{
Christof Schmitt287ac012008-07-02 10:56:40 +0200607 switch (act->action) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200608 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitt85600f72009-07-13 15:06:09 +0200609 _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200610 break;
Christof Schmitt287ac012008-07-02 10:56:40 +0200611 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
Christof Schmitt85600f72009-07-13 15:06:09 +0200612 _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200613 break;
Christof Schmitt287ac012008-07-02 10:56:40 +0200614 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitt85600f72009-07-13 15:06:09 +0200615 _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200616 break;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200617 case ZFCP_ERP_ACTION_REOPEN_LUN:
618 _zfcp_erp_lun_reopen(act->sdev, 0, "ersff_4", NULL, 0);
Christof Schmitt85600f72009-07-13 15:06:09 +0200619 break;
620 }
621}
622
623static void zfcp_erp_strategy_followup_success(struct zfcp_erp_action *act)
624{
625 switch (act->action) {
626 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
627 _zfcp_erp_port_reopen_all(act->adapter, 0, "ersfs_1", NULL);
628 break;
629 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
630 _zfcp_erp_port_reopen(act->port, 0, "ersfs_2", NULL);
631 break;
632 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmittb62a8d92010-09-08 14:39:55 +0200633 _zfcp_erp_lun_reopen_all(act->port, 0, "ersfs_3", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200634 break;
635 }
636}
637
638static void zfcp_erp_wakeup(struct zfcp_adapter *adapter)
639{
640 unsigned long flags;
641
Swen Schilligecf0c772009-11-24 16:53:58 +0100642 read_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200643 if (list_empty(&adapter->erp_ready_head) &&
644 list_empty(&adapter->erp_running_head)) {
645 atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING,
646 &adapter->status);
647 wake_up(&adapter->erp_done_wqh);
648 }
Swen Schilligecf0c772009-11-24 16:53:58 +0100649 read_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +0200650}
651
652static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
653{
Swen Schillig564e1c82009-08-18 15:43:19 +0200654 struct zfcp_qdio *qdio = act->adapter->qdio;
655
656 if (zfcp_qdio_open(qdio))
Christof Schmitt287ac012008-07-02 10:56:40 +0200657 return ZFCP_ERP_FAILED;
Swen Schillig564e1c82009-08-18 15:43:19 +0200658 init_waitqueue_head(&qdio->req_q_wq);
Christof Schmitt287ac012008-07-02 10:56:40 +0200659 atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &act->adapter->status);
660 return ZFCP_ERP_SUCCEEDED;
661}
662
663static void zfcp_erp_enqueue_ptp_port(struct zfcp_adapter *adapter)
664{
665 struct zfcp_port *port;
666 port = zfcp_port_enqueue(adapter, adapter->peer_wwpn, 0,
667 adapter->peer_d_id);
668 if (IS_ERR(port)) /* error or port already attached */
669 return;
Swen Schillig5ffd51a2009-03-02 13:09:04 +0100670 _zfcp_erp_port_reopen(port, 0, "ereptp1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +0200671}
672
673static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action)
674{
675 int retries;
676 int sleep = 1;
677 struct zfcp_adapter *adapter = erp_action->adapter;
678
679 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
680
681 for (retries = 7; retries; retries--) {
682 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
683 &adapter->status);
684 write_lock_irq(&adapter->erp_lock);
685 zfcp_erp_action_to_running(erp_action);
686 write_unlock_irq(&adapter->erp_lock);
687 if (zfcp_fsf_exchange_config_data(erp_action)) {
688 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
689 &adapter->status);
690 return ZFCP_ERP_FAILED;
691 }
692
Swen Schillig57717102009-08-18 15:43:21 +0200693 zfcp_dbf_rec_thread_lock("erasfx1", adapter->dbf);
Christof Schmitt347c6a92009-08-18 15:43:25 +0200694 wait_event(adapter->erp_ready_wq,
695 !list_empty(&adapter->erp_ready_head));
Swen Schillig57717102009-08-18 15:43:21 +0200696 zfcp_dbf_rec_thread_lock("erasfx2", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200697 if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT)
698 break;
699
700 if (!(atomic_read(&adapter->status) &
701 ZFCP_STATUS_ADAPTER_HOST_CON_INIT))
702 break;
703
704 ssleep(sleep);
705 sleep *= 2;
706 }
707
708 atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
709 &adapter->status);
710
711 if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK))
712 return ZFCP_ERP_FAILED;
713
714 if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
715 zfcp_erp_enqueue_ptp_port(adapter);
716
717 return ZFCP_ERP_SUCCEEDED;
718}
719
720static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *act)
721{
722 int ret;
723 struct zfcp_adapter *adapter = act->adapter;
724
Christof Schmitt287ac012008-07-02 10:56:40 +0200725 write_lock_irq(&adapter->erp_lock);
726 zfcp_erp_action_to_running(act);
727 write_unlock_irq(&adapter->erp_lock);
728
729 ret = zfcp_fsf_exchange_port_data(act);
730 if (ret == -EOPNOTSUPP)
731 return ZFCP_ERP_SUCCEEDED;
732 if (ret)
733 return ZFCP_ERP_FAILED;
734
Swen Schillig57717102009-08-18 15:43:21 +0200735 zfcp_dbf_rec_thread_lock("erasox1", adapter->dbf);
Christof Schmitt347c6a92009-08-18 15:43:25 +0200736 wait_event(adapter->erp_ready_wq,
737 !list_empty(&adapter->erp_ready_head));
Swen Schillig57717102009-08-18 15:43:21 +0200738 zfcp_dbf_rec_thread_lock("erasox2", adapter->dbf);
Christof Schmitt287ac012008-07-02 10:56:40 +0200739 if (act->status & ZFCP_STATUS_ERP_TIMEDOUT)
740 return ZFCP_ERP_FAILED;
741
742 return ZFCP_ERP_SUCCEEDED;
743}
744
745static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)
746{
747 if (zfcp_erp_adapter_strat_fsf_xconf(act) == ZFCP_ERP_FAILED)
748 return ZFCP_ERP_FAILED;
749
750 if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)
751 return ZFCP_ERP_FAILED;
752
Christof Schmitt8d88cf32010-06-21 10:11:33 +0200753 if (mempool_resize(act->adapter->pool.status_read_data,
754 act->adapter->stat_read_buf_num, GFP_KERNEL))
755 return ZFCP_ERP_FAILED;
756
757 if (mempool_resize(act->adapter->pool.status_read_req,
758 act->adapter->stat_read_buf_num, GFP_KERNEL))
759 return ZFCP_ERP_FAILED;
760
Christof Schmitt64deb6e2010-04-30 18:09:36 +0200761 atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num);
Christof Schmitt287ac012008-07-02 10:56:40 +0200762 if (zfcp_status_read_refill(act->adapter))
763 return ZFCP_ERP_FAILED;
764
765 return ZFCP_ERP_SUCCEEDED;
766}
767
Swen Schilligcf13c082009-03-02 13:09:03 +0100768static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act)
Christof Schmitt287ac012008-07-02 10:56:40 +0200769{
Christof Schmitt287ac012008-07-02 10:56:40 +0200770 struct zfcp_adapter *adapter = act->adapter;
771
Christof Schmitt287ac012008-07-02 10:56:40 +0200772 /* close queues to ensure that buffers are not accessed by adapter */
Swen Schillig564e1c82009-08-18 15:43:19 +0200773 zfcp_qdio_close(adapter->qdio);
Christof Schmitt287ac012008-07-02 10:56:40 +0200774 zfcp_fsf_req_dismiss_all(adapter);
775 adapter->fsf_req_seq_no = 0;
Christof Schmitt55c770f2009-08-18 15:43:12 +0200776 zfcp_fc_wka_ports_force_offline(adapter->gs);
Christof Schmittb62a8d92010-09-08 14:39:55 +0200777 /* all ports and LUNs are closed */
Swen Schilligedaed852010-09-08 14:40:01 +0200778 zfcp_erp_clear_adapter_status(adapter, ZFCP_STATUS_COMMON_OPEN);
Swen Schilligcf13c082009-03-02 13:09:03 +0100779
Christof Schmitt287ac012008-07-02 10:56:40 +0200780 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
Swen Schilligcf13c082009-03-02 13:09:03 +0100781 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status);
782}
783
784static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act)
785{
786 struct zfcp_adapter *adapter = act->adapter;
787
788 if (zfcp_erp_adapter_strategy_open_qdio(act)) {
789 atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
790 ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
791 &adapter->status);
792 return ZFCP_ERP_FAILED;
793 }
794
795 if (zfcp_erp_adapter_strategy_open_fsf(act)) {
796 zfcp_erp_adapter_strategy_close(act);
797 return ZFCP_ERP_FAILED;
798 }
799
800 atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &adapter->status);
801
802 return ZFCP_ERP_SUCCEEDED;
Christof Schmitt287ac012008-07-02 10:56:40 +0200803}
804
805static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *act)
806{
Swen Schilligcf13c082009-03-02 13:09:03 +0100807 struct zfcp_adapter *adapter = act->adapter;
Christof Schmitt287ac012008-07-02 10:56:40 +0200808
Swen Schilligcf13c082009-03-02 13:09:03 +0100809 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_OPEN) {
810 zfcp_erp_adapter_strategy_close(act);
811 if (act->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
812 return ZFCP_ERP_EXIT;
813 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200814
Swen Schilligcf13c082009-03-02 13:09:03 +0100815 if (zfcp_erp_adapter_strategy_open(act)) {
Christof Schmitt287ac012008-07-02 10:56:40 +0200816 ssleep(8);
Swen Schilligcf13c082009-03-02 13:09:03 +0100817 return ZFCP_ERP_FAILED;
818 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Swen Schilligcf13c082009-03-02 13:09:03 +0100820 return ZFCP_ERP_SUCCEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821}
822
Christof Schmitt287ac012008-07-02 10:56:40 +0200823static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824{
Christof Schmitt287ac012008-07-02 10:56:40 +0200825 int retval;
826
827 retval = zfcp_fsf_close_physical_port(act);
828 if (retval == -ENOMEM)
829 return ZFCP_ERP_NOMEM;
830 act->step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING;
831 if (retval)
832 return ZFCP_ERP_FAILED;
833
834 return ZFCP_ERP_CONTINUES;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835}
836
Christof Schmitt287ac012008-07-02 10:56:40 +0200837static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838{
Christof Schmitta5b11dd2009-03-02 13:08:54 +0100839 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200840}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
Christof Schmitt287ac012008-07-02 10:56:40 +0200842static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
843{
844 struct zfcp_port *port = erp_action->port;
845 int status = atomic_read(&port->status);
846
847 switch (erp_action->step) {
848 case ZFCP_ERP_STEP_UNINITIALIZED:
849 zfcp_erp_port_strategy_clearstati(port);
850 if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) &&
851 (status & ZFCP_STATUS_COMMON_OPEN))
852 return zfcp_erp_port_forced_strategy_close(erp_action);
853 else
854 return ZFCP_ERP_FAILED;
855
856 case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
Christof Schmittddb3e0c2009-07-13 15:06:08 +0200857 if (!(status & ZFCP_STATUS_PORT_PHYS_OPEN))
Christof Schmitt287ac012008-07-02 10:56:40 +0200858 return ZFCP_ERP_SUCCEEDED;
859 }
860 return ZFCP_ERP_FAILED;
861}
862
863static int zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action)
864{
865 int retval;
866
867 retval = zfcp_fsf_close_port(erp_action);
868 if (retval == -ENOMEM)
869 return ZFCP_ERP_NOMEM;
870 erp_action->step = ZFCP_ERP_STEP_PORT_CLOSING;
871 if (retval)
872 return ZFCP_ERP_FAILED;
873 return ZFCP_ERP_CONTINUES;
874}
875
876static int zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action)
877{
878 int retval;
879
880 retval = zfcp_fsf_open_port(erp_action);
881 if (retval == -ENOMEM)
882 return ZFCP_ERP_NOMEM;
883 erp_action->step = ZFCP_ERP_STEP_PORT_OPENING;
884 if (retval)
885 return ZFCP_ERP_FAILED;
886 return ZFCP_ERP_CONTINUES;
887}
888
Christof Schmitt287ac012008-07-02 10:56:40 +0200889static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act)
890{
891 struct zfcp_adapter *adapter = act->adapter;
892 struct zfcp_port *port = act->port;
893
894 if (port->wwpn != adapter->peer_wwpn) {
Swen Schilligedaed852010-09-08 14:40:01 +0200895 zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED);
Christof Schmitt287ac012008-07-02 10:56:40 +0200896 return ZFCP_ERP_FAILED;
897 }
898 port->d_id = adapter->peer_d_id;
Christof Schmitt287ac012008-07-02 10:56:40 +0200899 return zfcp_erp_port_strategy_open_port(act);
900}
901
902static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act)
903{
904 struct zfcp_adapter *adapter = act->adapter;
905 struct zfcp_port *port = act->port;
Christof Schmitt287ac012008-07-02 10:56:40 +0200906 int p_status = atomic_read(&port->status);
907
908 switch (act->step) {
909 case ZFCP_ERP_STEP_UNINITIALIZED:
910 case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
911 case ZFCP_ERP_STEP_PORT_CLOSING:
912 if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP)
913 return zfcp_erp_open_ptp_port(act);
Christof Schmittb98478d2008-12-19 16:56:59 +0100914 if (!port->d_id) {
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200915 zfcp_fc_trigger_did_lookup(port);
Christof Schmitt799b76d2009-08-18 15:43:20 +0200916 return ZFCP_ERP_EXIT;
Christof Schmitt287ac012008-07-02 10:56:40 +0200917 }
Christof Schmitt287ac012008-07-02 10:56:40 +0200918 return zfcp_erp_port_strategy_open_port(act);
919
920 case ZFCP_ERP_STEP_PORT_OPENING:
921 /* D_ID might have changed during open */
Swen Schillig5ab944f2008-10-01 12:42:17 +0200922 if (p_status & ZFCP_STATUS_COMMON_OPEN) {
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200923 if (!port->d_id) {
924 zfcp_fc_trigger_did_lookup(port);
925 return ZFCP_ERP_EXIT;
Swen Schillig5ab944f2008-10-01 12:42:17 +0200926 }
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200927 return ZFCP_ERP_SUCCEEDED;
Swen Schillig5ab944f2008-10-01 12:42:17 +0200928 }
Swen Schilligea460a82009-05-15 13:18:20 +0200929 if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) {
930 port->d_id = 0;
Christof Schmittf7bd7c32010-07-08 09:53:10 +0200931 return ZFCP_ERP_FAILED;
Swen Schilligea460a82009-05-15 13:18:20 +0200932 }
933 /* fall through otherwise */
Christof Schmitt287ac012008-07-02 10:56:40 +0200934 }
935 return ZFCP_ERP_FAILED;
936}
937
Christof Schmitt287ac012008-07-02 10:56:40 +0200938static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
939{
940 struct zfcp_port *port = erp_action->port;
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200941 int p_status = atomic_read(&port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +0200942
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200943 if ((p_status & ZFCP_STATUS_COMMON_NOESC) &&
944 !(p_status & ZFCP_STATUS_COMMON_OPEN))
Swen Schillig5ab944f2008-10-01 12:42:17 +0200945 goto close_init_done;
946
Christof Schmitt287ac012008-07-02 10:56:40 +0200947 switch (erp_action->step) {
948 case ZFCP_ERP_STEP_UNINITIALIZED:
949 zfcp_erp_port_strategy_clearstati(port);
Christof Schmitt934aeb5872009-10-14 11:00:43 +0200950 if (p_status & ZFCP_STATUS_COMMON_OPEN)
Christof Schmitt287ac012008-07-02 10:56:40 +0200951 return zfcp_erp_port_strategy_close(erp_action);
952 break;
953
954 case ZFCP_ERP_STEP_PORT_CLOSING:
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_FAILED;
957 break;
958 }
Swen Schillig5ab944f2008-10-01 12:42:17 +0200959
960close_init_done:
Christof Schmitt287ac012008-07-02 10:56:40 +0200961 if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
962 return ZFCP_ERP_EXIT;
Christof Schmitt287ac012008-07-02 10:56:40 +0200963
Swen Schillig5ab944f2008-10-01 12:42:17 +0200964 return zfcp_erp_port_strategy_open_common(erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965}
966
Christof Schmittb62a8d92010-09-08 14:39:55 +0200967static void zfcp_erp_lun_strategy_clearstati(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200969 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
970
Swen Schillig44cc76f2008-10-01 12:42:16 +0200971 atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
Christof Schmittb62a8d92010-09-08 14:39:55 +0200972 ZFCP_STATUS_LUN_SHARED | ZFCP_STATUS_LUN_READONLY,
973 &zfcp_sdev->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974}
975
Christof Schmittb62a8d92010-09-08 14:39:55 +0200976static int zfcp_erp_lun_strategy_close(struct zfcp_erp_action *erp_action)
Christof Schmitt287ac012008-07-02 10:56:40 +0200977{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200978 int retval = zfcp_fsf_close_lun(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +0200979 if (retval == -ENOMEM)
980 return ZFCP_ERP_NOMEM;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200981 erp_action->step = ZFCP_ERP_STEP_LUN_CLOSING;
Christof Schmitt287ac012008-07-02 10:56:40 +0200982 if (retval)
983 return ZFCP_ERP_FAILED;
984 return ZFCP_ERP_CONTINUES;
985}
986
Christof Schmittb62a8d92010-09-08 14:39:55 +0200987static int zfcp_erp_lun_strategy_open(struct zfcp_erp_action *erp_action)
Christof Schmitt287ac012008-07-02 10:56:40 +0200988{
Christof Schmittb62a8d92010-09-08 14:39:55 +0200989 int retval = zfcp_fsf_open_lun(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +0200990 if (retval == -ENOMEM)
991 return ZFCP_ERP_NOMEM;
Christof Schmittb62a8d92010-09-08 14:39:55 +0200992 erp_action->step = ZFCP_ERP_STEP_LUN_OPENING;
Christof Schmitt287ac012008-07-02 10:56:40 +0200993 if (retval)
994 return ZFCP_ERP_FAILED;
995 return ZFCP_ERP_CONTINUES;
996}
997
Christof Schmittb62a8d92010-09-08 14:39:55 +0200998static int zfcp_erp_lun_strategy(struct zfcp_erp_action *erp_action)
Christof Schmitt287ac012008-07-02 10:56:40 +0200999{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001000 struct scsi_device *sdev = erp_action->sdev;
1001 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +02001002
1003 switch (erp_action->step) {
1004 case ZFCP_ERP_STEP_UNINITIALIZED:
Christof Schmittb62a8d92010-09-08 14:39:55 +02001005 zfcp_erp_lun_strategy_clearstati(sdev);
1006 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
1007 return zfcp_erp_lun_strategy_close(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +02001008 /* already closed, fall through */
Christof Schmittb62a8d92010-09-08 14:39:55 +02001009 case ZFCP_ERP_STEP_LUN_CLOSING:
1010 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
Christof Schmitt287ac012008-07-02 10:56:40 +02001011 return ZFCP_ERP_FAILED;
1012 if (erp_action->status & ZFCP_STATUS_ERP_CLOSE_ONLY)
1013 return ZFCP_ERP_EXIT;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001014 return zfcp_erp_lun_strategy_open(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +02001015
Christof Schmittb62a8d92010-09-08 14:39:55 +02001016 case ZFCP_ERP_STEP_LUN_OPENING:
1017 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_OPEN)
Christof Schmitt287ac012008-07-02 10:56:40 +02001018 return ZFCP_ERP_SUCCEEDED;
1019 }
1020 return ZFCP_ERP_FAILED;
1021}
1022
Christof Schmittb62a8d92010-09-08 14:39:55 +02001023static int zfcp_erp_strategy_check_lun(struct scsi_device *sdev, int result)
Christof Schmitt287ac012008-07-02 10:56:40 +02001024{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001025 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
1026
Christof Schmitt287ac012008-07-02 10:56:40 +02001027 switch (result) {
1028 case ZFCP_ERP_SUCCEEDED :
Christof Schmittb62a8d92010-09-08 14:39:55 +02001029 atomic_set(&zfcp_sdev->erp_counter, 0);
1030 zfcp_erp_lun_unblock(sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +02001031 break;
1032 case ZFCP_ERP_FAILED :
Christof Schmittb62a8d92010-09-08 14:39:55 +02001033 atomic_inc(&zfcp_sdev->erp_counter);
1034 if (atomic_read(&zfcp_sdev->erp_counter) > ZFCP_MAX_ERPS) {
1035 dev_err(&zfcp_sdev->port->adapter->ccw_device->dev,
1036 "ERP failed for LUN 0x%016Lx on "
Christof Schmittff3b24f2008-10-01 12:42:15 +02001037 "port 0x%016Lx\n",
Christof Schmittb62a8d92010-09-08 14:39:55 +02001038 (unsigned long long)zfcp_scsi_dev_lun(sdev),
1039 (unsigned long long)zfcp_sdev->port->wwpn);
Swen Schilligedaed852010-09-08 14:40:01 +02001040 zfcp_erp_set_lun_status(sdev,
1041 ZFCP_STATUS_COMMON_ERP_FAILED);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001042 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001043 break;
1044 }
1045
Christof Schmittb62a8d92010-09-08 14:39:55 +02001046 if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1047 zfcp_erp_lun_block(sdev, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +02001048 result = ZFCP_ERP_EXIT;
1049 }
1050 return result;
1051}
1052
1053static int zfcp_erp_strategy_check_port(struct zfcp_port *port, int result)
1054{
1055 switch (result) {
1056 case ZFCP_ERP_SUCCEEDED :
1057 atomic_set(&port->erp_counter, 0);
1058 zfcp_erp_port_unblock(port);
1059 break;
1060
1061 case ZFCP_ERP_FAILED :
1062 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC) {
1063 zfcp_erp_port_block(port, 0);
1064 result = ZFCP_ERP_EXIT;
1065 }
1066 atomic_inc(&port->erp_counter);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001067 if (atomic_read(&port->erp_counter) > ZFCP_MAX_ERPS) {
1068 dev_err(&port->adapter->ccw_device->dev,
1069 "ERP failed for remote port 0x%016Lx\n",
Swen Schillig7ba58c92008-10-01 12:42:18 +02001070 (unsigned long long)port->wwpn);
Swen Schilligedaed852010-09-08 14:40:01 +02001071 zfcp_erp_set_port_status(port,
1072 ZFCP_STATUS_COMMON_ERP_FAILED);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001073 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001074 break;
1075 }
1076
1077 if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1078 zfcp_erp_port_block(port, 0);
1079 result = ZFCP_ERP_EXIT;
1080 }
1081 return result;
1082}
1083
1084static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter,
1085 int result)
1086{
1087 switch (result) {
1088 case ZFCP_ERP_SUCCEEDED :
1089 atomic_set(&adapter->erp_counter, 0);
1090 zfcp_erp_adapter_unblock(adapter);
1091 break;
1092
1093 case ZFCP_ERP_FAILED :
1094 atomic_inc(&adapter->erp_counter);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001095 if (atomic_read(&adapter->erp_counter) > ZFCP_MAX_ERPS) {
1096 dev_err(&adapter->ccw_device->dev,
1097 "ERP cannot recover an error "
1098 "on the FCP device\n");
Swen Schilligedaed852010-09-08 14:40:01 +02001099 zfcp_erp_set_adapter_status(adapter,
1100 ZFCP_STATUS_COMMON_ERP_FAILED);
Christof Schmittff3b24f2008-10-01 12:42:15 +02001101 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001102 break;
1103 }
1104
1105 if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) {
1106 zfcp_erp_adapter_block(adapter, 0);
1107 result = ZFCP_ERP_EXIT;
1108 }
1109 return result;
1110}
1111
1112static int zfcp_erp_strategy_check_target(struct zfcp_erp_action *erp_action,
1113 int result)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114{
1115 struct zfcp_adapter *adapter = erp_action->adapter;
1116 struct zfcp_port *port = erp_action->port;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001117 struct scsi_device *sdev = erp_action->sdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 switch (erp_action->action) {
1120
Christof Schmittb62a8d92010-09-08 14:39:55 +02001121 case ZFCP_ERP_ACTION_REOPEN_LUN:
1122 result = zfcp_erp_strategy_check_lun(sdev, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 break;
1124
1125 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1126 case ZFCP_ERP_ACTION_REOPEN_PORT:
1127 result = zfcp_erp_strategy_check_port(port, result);
1128 break;
1129
1130 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1131 result = zfcp_erp_strategy_check_adapter(adapter, result);
1132 break;
1133 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 return result;
1135}
1136
Christof Schmitt287ac012008-07-02 10:56:40 +02001137static int zfcp_erp_strat_change_det(atomic_t *target_status, u32 erp_status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138{
Christof Schmitt287ac012008-07-02 10:56:40 +02001139 int status = atomic_read(target_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
Christof Schmitt287ac012008-07-02 10:56:40 +02001141 if ((status & ZFCP_STATUS_COMMON_RUNNING) &&
1142 (erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1143 return 1; /* take it online */
1144
1145 if (!(status & ZFCP_STATUS_COMMON_RUNNING) &&
1146 !(erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY))
1147 return 1; /* take it offline */
1148
1149 return 0;
1150}
1151
1152static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret)
1153{
1154 int action = act->action;
1155 struct zfcp_adapter *adapter = act->adapter;
1156 struct zfcp_port *port = act->port;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001157 struct scsi_device *sdev = act->sdev;
1158 struct zfcp_scsi_dev *zfcp_sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +02001159 u32 erp_status = act->status;
1160
1161 switch (action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitt287ac012008-07-02 10:56:40 +02001163 if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) {
1164 _zfcp_erp_adapter_reopen(adapter,
1165 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001166 "ersscg1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001167 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 }
1169 break;
1170
1171 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1172 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitt287ac012008-07-02 10:56:40 +02001173 if (zfcp_erp_strat_change_det(&port->status, erp_status)) {
1174 _zfcp_erp_port_reopen(port,
1175 ZFCP_STATUS_COMMON_ERP_FAILED,
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001176 "ersscg2", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001177 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 }
1179 break;
1180
Christof Schmittb62a8d92010-09-08 14:39:55 +02001181 case ZFCP_ERP_ACTION_REOPEN_LUN:
1182 zfcp_sdev = sdev_to_zfcp(sdev);
1183 if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) {
1184 _zfcp_erp_lun_reopen(sdev,
1185 ZFCP_STATUS_COMMON_ERP_FAILED,
1186 "ersscg3", NULL, 0);
Christof Schmitt287ac012008-07-02 10:56:40 +02001187 return ZFCP_ERP_EXIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 }
1189 break;
1190 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001191 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192}
1193
Christof Schmitt287ac012008-07-02 10:56:40 +02001194static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195{
Christof Schmitt287ac012008-07-02 10:56:40 +02001196 struct zfcp_adapter *adapter = erp_action->adapter;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001197 struct zfcp_scsi_dev *zfcp_sdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
Christof Schmitt287ac012008-07-02 10:56:40 +02001199 adapter->erp_total_count--;
1200 if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1201 adapter->erp_low_mem_count--;
1202 erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 }
1204
Christof Schmitt287ac012008-07-02 10:56:40 +02001205 list_del(&erp_action->list);
Swen Schillig57717102009-08-18 15:43:21 +02001206 zfcp_dbf_rec_action("eractd1", erp_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
Christof Schmitt287ac012008-07-02 10:56:40 +02001208 switch (erp_action->action) {
Christof Schmittb62a8d92010-09-08 14:39:55 +02001209 case ZFCP_ERP_ACTION_REOPEN_LUN:
1210 zfcp_sdev = sdev_to_zfcp(erp_action->sdev);
Christof Schmitt287ac012008-07-02 10:56:40 +02001211 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
Christof Schmittb62a8d92010-09-08 14:39:55 +02001212 &zfcp_sdev->status);
Christof Schmitt287ac012008-07-02 10:56:40 +02001213 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214
Christof Schmitt287ac012008-07-02 10:56:40 +02001215 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1216 case ZFCP_ERP_ACTION_REOPEN_PORT:
1217 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1218 &erp_action->port->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001220
1221 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1222 atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
1223 &erp_action->adapter->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 break;
1225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226}
1227
Christof Schmitt287ac012008-07-02 10:56:40 +02001228static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001229{
Christof Schmitt287ac012008-07-02 10:56:40 +02001230 struct zfcp_adapter *adapter = act->adapter;
1231 struct zfcp_port *port = act->port;
Christof Schmittb62a8d92010-09-08 14:39:55 +02001232 struct scsi_device *sdev = act->sdev;
Maxim Shchetyninaef4a982005-09-13 21:51:16 +02001233
Christof Schmitt287ac012008-07-02 10:56:40 +02001234 switch (act->action) {
Christof Schmittb62a8d92010-09-08 14:39:55 +02001235 case ZFCP_ERP_ACTION_REOPEN_LUN:
Christof Schmittfdbd1c52010-09-08 14:39:54 +02001236 if (!(act->status & ZFCP_STATUS_ERP_NO_REF))
Christof Schmittb62a8d92010-09-08 14:39:55 +02001237 scsi_device_put(sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001239
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 case ZFCP_ERP_ACTION_REOPEN_PORT:
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001241 if (result == ZFCP_ERP_SUCCEEDED)
1242 zfcp_scsi_schedule_rport_register(port);
Christof Schmitt57676202010-07-08 09:53:05 +02001243 /* fall through */
1244 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
Christof Schmitt615f59e2010-02-17 11:18:56 +01001245 put_device(&port->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 break;
Christof Schmitt287ac012008-07-02 10:56:40 +02001247
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001249 if (result == ZFCP_ERP_SUCCEEDED) {
Christof Schmittbd43a42b72008-12-25 13:38:50 +01001250 register_service_level(&adapter->service_level);
Swen Schillig9eae07e2009-11-24 16:54:06 +01001251 queue_work(adapter->work_queue, &adapter->scan_work);
Christof Schmitta2fa0ae2009-03-02 13:09:08 +01001252 } else
1253 unregister_service_level(&adapter->service_level);
Swen Schilligf3450c72009-11-24 16:53:59 +01001254 kref_put(&adapter->ref, zfcp_adapter_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 }
1257}
1258
Christof Schmitt287ac012008-07-02 10:56:40 +02001259static int zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
1260{
1261 switch (erp_action->action) {
1262 case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
1263 return zfcp_erp_adapter_strategy(erp_action);
1264 case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
1265 return zfcp_erp_port_forced_strategy(erp_action);
1266 case ZFCP_ERP_ACTION_REOPEN_PORT:
1267 return zfcp_erp_port_strategy(erp_action);
Christof Schmittb62a8d92010-09-08 14:39:55 +02001268 case ZFCP_ERP_ACTION_REOPEN_LUN:
1269 return zfcp_erp_lun_strategy(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +02001270 }
1271 return ZFCP_ERP_FAILED;
1272}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
Christof Schmitt287ac012008-07-02 10:56:40 +02001274static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
1275{
1276 int retval;
Christof Schmitt287ac012008-07-02 10:56:40 +02001277 unsigned long flags;
Swen Schilligecf0c772009-11-24 16:53:58 +01001278 struct zfcp_adapter *adapter = erp_action->adapter;
Christof Schmitt287ac012008-07-02 10:56:40 +02001279
Swen Schilligf3450c72009-11-24 16:53:59 +01001280 kref_get(&adapter->ref);
Christof Schmitt287ac012008-07-02 10:56:40 +02001281
Swen Schilligf3450c72009-11-24 16:53:59 +01001282 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001283 zfcp_erp_strategy_check_fsfreq(erp_action);
1284
1285 if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
1286 zfcp_erp_action_dequeue(erp_action);
1287 retval = ZFCP_ERP_DISMISSED;
1288 goto unlock;
1289 }
1290
Christof Schmitt9c785d92010-07-08 09:53:09 +02001291 if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
1292 retval = ZFCP_ERP_FAILED;
1293 goto check_target;
1294 }
1295
Christof Schmitt287ac012008-07-02 10:56:40 +02001296 zfcp_erp_action_to_running(erp_action);
1297
1298 /* no lock to allow for blocking operations */
Swen Schilligecf0c772009-11-24 16:53:58 +01001299 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001300 retval = zfcp_erp_strategy_do_action(erp_action);
Swen Schilligecf0c772009-11-24 16:53:58 +01001301 write_lock_irqsave(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001302
1303 if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED)
1304 retval = ZFCP_ERP_CONTINUES;
1305
1306 switch (retval) {
1307 case ZFCP_ERP_NOMEM:
1308 if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) {
1309 ++adapter->erp_low_mem_count;
1310 erp_action->status |= ZFCP_STATUS_ERP_LOWMEM;
1311 }
1312 if (adapter->erp_total_count == adapter->erp_low_mem_count)
Swen Schillig5ffd51a2009-03-02 13:09:04 +01001313 _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL);
Christof Schmitt287ac012008-07-02 10:56:40 +02001314 else {
1315 zfcp_erp_strategy_memwait(erp_action);
1316 retval = ZFCP_ERP_CONTINUES;
1317 }
1318 goto unlock;
1319
1320 case ZFCP_ERP_CONTINUES:
1321 if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) {
1322 --adapter->erp_low_mem_count;
1323 erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM;
1324 }
1325 goto unlock;
1326 }
1327
Christof Schmitt9c785d92010-07-08 09:53:09 +02001328check_target:
Christof Schmitt287ac012008-07-02 10:56:40 +02001329 retval = zfcp_erp_strategy_check_target(erp_action, retval);
1330 zfcp_erp_action_dequeue(erp_action);
1331 retval = zfcp_erp_strategy_statechange(erp_action, retval);
1332 if (retval == ZFCP_ERP_EXIT)
1333 goto unlock;
Christof Schmitt85600f72009-07-13 15:06:09 +02001334 if (retval == ZFCP_ERP_SUCCEEDED)
1335 zfcp_erp_strategy_followup_success(erp_action);
1336 if (retval == ZFCP_ERP_FAILED)
1337 zfcp_erp_strategy_followup_failed(erp_action);
Christof Schmitt287ac012008-07-02 10:56:40 +02001338
1339 unlock:
Swen Schilligecf0c772009-11-24 16:53:58 +01001340 write_unlock_irqrestore(&adapter->erp_lock, flags);
Christof Schmitt287ac012008-07-02 10:56:40 +02001341
1342 if (retval != ZFCP_ERP_CONTINUES)
1343 zfcp_erp_action_cleanup(erp_action, retval);
1344
Swen Schilligf3450c72009-11-24 16:53:59 +01001345 kref_put(&adapter->ref, zfcp_adapter_release);
Christof Schmitt287ac012008-07-02 10:56:40 +02001346 return retval;
1347}
1348
1349static int zfcp_erp_thread(void *data)
1350{
1351 struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
1352 struct list_head *next;
1353 struct zfcp_erp_action *act;
1354 unsigned long flags;
1355
Christof Schmitt347c6a92009-08-18 15:43:25 +02001356 for (;;) {
Swen Schillig57717102009-08-18 15:43:21 +02001357 zfcp_dbf_rec_thread_lock("erthrd1", adapter->dbf);
Christof Schmitt347c6a92009-08-18 15:43:25 +02001358 wait_event_interruptible(adapter->erp_ready_wq,
1359 !list_empty(&adapter->erp_ready_head) ||
1360 kthread_should_stop());
Swen Schillig57717102009-08-18 15:43:21 +02001361 zfcp_dbf_rec_thread_lock("erthrd2", adapter->dbf);
Swen Schillig94ab4b32009-04-17 15:08:06 +02001362
Christof Schmitt347c6a92009-08-18 15:43:25 +02001363 if (kthread_should_stop())
1364 break;
1365
Christof Schmitt287ac012008-07-02 10:56:40 +02001366 write_lock_irqsave(&adapter->erp_lock, flags);
1367 next = adapter->erp_ready_head.next;
1368 write_unlock_irqrestore(&adapter->erp_lock, flags);
1369
1370 if (next != &adapter->erp_ready_head) {
1371 act = list_entry(next, struct zfcp_erp_action, list);
1372
1373 /* there is more to come after dismission, no notify */
1374 if (zfcp_erp_strategy(act) != ZFCP_ERP_DISMISSED)
1375 zfcp_erp_wakeup(adapter);
1376 }
Christof Schmitt287ac012008-07-02 10:56:40 +02001377 }
1378
Christof Schmitt287ac012008-07-02 10:56:40 +02001379 return 0;
1380}
1381
1382/**
1383 * zfcp_erp_thread_setup - Start ERP thread for adapter
1384 * @adapter: Adapter to start the ERP thread for
1385 *
1386 * Returns 0 on success or error code from kernel_thread()
1387 */
1388int zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
1389{
Christof Schmitt347c6a92009-08-18 15:43:25 +02001390 struct task_struct *thread;
Christof Schmitt287ac012008-07-02 10:56:40 +02001391
Christof Schmitt347c6a92009-08-18 15:43:25 +02001392 thread = kthread_run(zfcp_erp_thread, adapter, "zfcperp%s",
1393 dev_name(&adapter->ccw_device->dev));
1394 if (IS_ERR(thread)) {
Christof Schmitt287ac012008-07-02 10:56:40 +02001395 dev_err(&adapter->ccw_device->dev,
Christof Schmittff3b24f2008-10-01 12:42:15 +02001396 "Creating an ERP thread for the FCP device failed.\n");
Christof Schmitt347c6a92009-08-18 15:43:25 +02001397 return PTR_ERR(thread);
Christof Schmitt287ac012008-07-02 10:56:40 +02001398 }
Christof Schmitt347c6a92009-08-18 15:43:25 +02001399
1400 adapter->erp_thread = thread;
Christof Schmitt287ac012008-07-02 10:56:40 +02001401 return 0;
1402}
1403
1404/**
1405 * zfcp_erp_thread_kill - Stop ERP thread.
1406 * @adapter: Adapter where the ERP thread should be stopped.
1407 *
1408 * The caller of this routine ensures that the specified adapter has
1409 * been shut down and that this operation has been completed. Thus,
1410 * there are no pending erp_actions which would need to be handled
1411 * here.
1412 */
1413void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
1414{
Christof Schmitt347c6a92009-08-18 15:43:25 +02001415 kthread_stop(adapter->erp_thread);
1416 adapter->erp_thread = NULL;
Christof Schmitt143bb6b2009-08-18 15:43:27 +02001417 WARN_ON(!list_empty(&adapter->erp_ready_head));
1418 WARN_ON(!list_empty(&adapter->erp_running_head));
Christof Schmitt287ac012008-07-02 10:56:40 +02001419}
1420
1421/**
Christof Schmitt287ac012008-07-02 10:56:40 +02001422 * zfcp_erp_wait - wait for completion of error recovery on an adapter
1423 * @adapter: adapter for which to wait for completion of its error recovery
1424 */
1425void zfcp_erp_wait(struct zfcp_adapter *adapter)
1426{
1427 wait_event(adapter->erp_done_wqh,
1428 !(atomic_read(&adapter->status) &
1429 ZFCP_STATUS_ADAPTER_ERP_PENDING));
1430}
1431
1432/**
Swen Schilligedaed852010-09-08 14:40:01 +02001433 * zfcp_erp_set_adapter_status - set adapter status bits
Christof Schmitt287ac012008-07-02 10:56:40 +02001434 * @adapter: adapter to change the status
Christof Schmitt287ac012008-07-02 10:56:40 +02001435 * @mask: status bits to change
Christof Schmitt287ac012008-07-02 10:56:40 +02001436 *
Christof Schmittb62a8d92010-09-08 14:39:55 +02001437 * Changes in common status bits are propagated to attached ports and LUNs.
Christof Schmitt287ac012008-07-02 10:56:40 +02001438 */
Swen Schilligedaed852010-09-08 14:40:01 +02001439void zfcp_erp_set_adapter_status(struct zfcp_adapter *adapter, u32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 struct zfcp_port *port;
Swen Schilligedaed852010-09-08 14:40:01 +02001442 struct scsi_device *sdev;
Swen Schilligecf0c772009-11-24 16:53:58 +01001443 unsigned long flags;
Christof Schmitt287ac012008-07-02 10:56:40 +02001444 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445
Swen Schilligedaed852010-09-08 14:40:01 +02001446 atomic_set_mask(mask, &adapter->status);
Christof Schmitt287ac012008-07-02 10:56:40 +02001447
Swen Schilligedaed852010-09-08 14:40:01 +02001448 if (!common_mask)
1449 return;
1450
1451 read_lock_irqsave(&adapter->port_list_lock, flags);
1452 list_for_each_entry(port, &adapter->port_list, list)
1453 atomic_set_mask(common_mask, &port->status);
1454 read_unlock_irqrestore(&adapter->port_list_lock, flags);
1455
1456 shost_for_each_device(sdev, adapter->scsi_host)
1457 atomic_set_mask(common_mask, &sdev_to_zfcp(sdev)->status);
1458}
1459
1460/**
1461 * zfcp_erp_clear_adapter_status - clear adapter status bits
1462 * @adapter: adapter to change the status
1463 * @mask: status bits to change
1464 *
1465 * Changes in common status bits are propagated to attached ports and LUNs.
1466 */
1467void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask)
1468{
1469 struct zfcp_port *port;
1470 struct scsi_device *sdev;
1471 unsigned long flags;
1472 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
1473 u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED;
1474
1475 atomic_clear_mask(mask, &adapter->status);
1476
1477 if (!common_mask)
1478 return;
1479
1480 if (clear_counter)
1481 atomic_set(&adapter->erp_counter, 0);
1482
1483 read_lock_irqsave(&adapter->port_list_lock, flags);
1484 list_for_each_entry(port, &adapter->port_list, list) {
1485 atomic_clear_mask(common_mask, &port->status);
1486 if (clear_counter)
1487 atomic_set(&port->erp_counter, 0);
1488 }
1489 read_unlock_irqrestore(&adapter->port_list_lock, flags);
1490
1491 shost_for_each_device(sdev, adapter->scsi_host) {
1492 atomic_clear_mask(common_mask, &sdev_to_zfcp(sdev)->status);
1493 if (clear_counter)
1494 atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
Swen Schilligecf0c772009-11-24 16:53:58 +01001495 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496}
1497
Christof Schmitt287ac012008-07-02 10:56:40 +02001498/**
Swen Schilligedaed852010-09-08 14:40:01 +02001499 * zfcp_erp_set_port_status - set port status bits
1500 * @port: port to change the status
Christof Schmitt287ac012008-07-02 10:56:40 +02001501 * @mask: status bits to change
Christof Schmitt287ac012008-07-02 10:56:40 +02001502 *
Christof Schmittb62a8d92010-09-08 14:39:55 +02001503 * Changes in common status bits are propagated to attached LUNs.
Christof Schmitt287ac012008-07-02 10:56:40 +02001504 */
Swen Schilligedaed852010-09-08 14:40:01 +02001505void zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001507 struct scsi_device *sdev;
Christof Schmitt287ac012008-07-02 10:56:40 +02001508 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509
Swen Schilligedaed852010-09-08 14:40:01 +02001510 atomic_set_mask(mask, &port->status);
Christof Schmitt287ac012008-07-02 10:56:40 +02001511
Swen Schilligedaed852010-09-08 14:40:01 +02001512 if (!common_mask)
1513 return;
1514
1515 shost_for_each_device(sdev, port->adapter->scsi_host)
1516 if (sdev_to_zfcp(sdev)->port == port)
1517 atomic_set_mask(common_mask,
1518 &sdev_to_zfcp(sdev)->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519}
1520
Christof Schmitt287ac012008-07-02 10:56:40 +02001521/**
Swen Schilligedaed852010-09-08 14:40:01 +02001522 * zfcp_erp_clear_port_status - clear port status bits
1523 * @port: adapter to change the status
Christof Schmitt287ac012008-07-02 10:56:40 +02001524 * @mask: status bits to change
Swen Schilligedaed852010-09-08 14:40:01 +02001525 *
1526 * Changes in common status bits are propagated to attached LUNs.
Christof Schmitt287ac012008-07-02 10:56:40 +02001527 */
Swen Schilligedaed852010-09-08 14:40:01 +02001528void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask)
1529{
1530 struct scsi_device *sdev;
1531 u32 common_mask = mask & ZFCP_COMMON_FLAGS;
1532 u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED;
1533
1534 atomic_clear_mask(mask, &port->status);
1535
1536 if (!common_mask)
1537 return;
1538
1539 if (clear_counter)
1540 atomic_set(&port->erp_counter, 0);
1541
1542 shost_for_each_device(sdev, port->adapter->scsi_host)
1543 if (sdev_to_zfcp(sdev)->port == port) {
1544 atomic_clear_mask(common_mask,
1545 &sdev_to_zfcp(sdev)->status);
1546 if (clear_counter)
1547 atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
1548 }
1549}
1550
1551/**
1552 * zfcp_erp_set_lun_status - set lun status bits
1553 * @sdev: SCSI device / lun to set the status bits
1554 * @mask: status bits to change
1555 */
1556void zfcp_erp_set_lun_status(struct scsi_device *sdev, u32 mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557{
Christof Schmittb62a8d92010-09-08 14:39:55 +02001558 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
1559
Swen Schilligedaed852010-09-08 14:40:01 +02001560 atomic_set_mask(mask, &zfcp_sdev->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561}
1562
Christof Schmitt287ac012008-07-02 10:56:40 +02001563/**
Swen Schilligedaed852010-09-08 14:40:01 +02001564 * zfcp_erp_clear_lun_status - clear lun status bits
1565 * @sdev: SCSi device / lun to clear the status bits
1566 * @mask: status bits to change
Christof Schmitt287ac012008-07-02 10:56:40 +02001567 */
Swen Schilligedaed852010-09-08 14:40:01 +02001568void zfcp_erp_clear_lun_status(struct scsi_device *sdev, u32 mask)
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001569{
Swen Schilligedaed852010-09-08 14:40:01 +02001570 struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
1571
1572 atomic_clear_mask(mask, &zfcp_sdev->status);
1573
1574 if (mask & ZFCP_STATUS_COMMON_ERP_FAILED)
1575 atomic_set(&zfcp_sdev->erp_counter, 0);
Andreas Herrmannd736a27b2005-06-13 13:23:57 +02001576}
1577