1
2
3
4
5
6
7
8
9
10#define KMSG_COMPONENT "zfcp"
11#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
12
13#include <linux/module.h>
14#include "zfcp_ext.h"
15#include "zfcp_reqlist.h"
16
17#define ZFCP_MODEL_PRIV 0x4
18
19static DEFINE_SPINLOCK(zfcp_ccw_adapter_ref_lock);
20
21struct zfcp_adapter *zfcp_ccw_adapter_by_cdev(struct ccw_device *cdev)
22{
23 struct zfcp_adapter *adapter;
24 unsigned long flags;
25
26 spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags);
27 adapter = dev_get_drvdata(&cdev->dev);
28 if (adapter)
29 kref_get(&adapter->ref);
30 spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags);
31 return adapter;
32}
33
34void zfcp_ccw_adapter_put(struct zfcp_adapter *adapter)
35{
36 unsigned long flags;
37
38 spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags);
39 kref_put(&adapter->ref, zfcp_adapter_release);
40 spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags);
41}
42
43
44
45
46
47
48
49static int zfcp_ccw_activate(struct ccw_device *cdev, int clear, char *tag)
50{
51 struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
52
53 if (!adapter)
54 return 0;
55
56 zfcp_erp_clear_adapter_status(adapter, clear);
57 zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING);
58 zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
59 tag);
60
61
62
63
64
65
66
67
68
69
70
71
72
73 msleep(zfcp_fc_port_scan_backoff());
74 zfcp_erp_wait(adapter);
75 flush_delayed_work(&adapter->scan_work);
76
77 zfcp_ccw_adapter_put(adapter);
78
79 return 0;
80}
81
82static struct ccw_device_id zfcp_ccw_device_id[] = {
83 { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) },
84 { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, ZFCP_MODEL_PRIV) },
85 {},
86};
87MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
88
89
90
91
92
93
94
95
96
97
98static int zfcp_ccw_probe(struct ccw_device *cdev)
99{
100 return 0;
101}
102
103
104
105
106
107
108
109
110
111
112static void zfcp_ccw_remove(struct ccw_device *cdev)
113{
114 struct zfcp_adapter *adapter;
115 struct zfcp_port *port, *p;
116 struct zfcp_unit *unit, *u;
117 LIST_HEAD(unit_remove_lh);
118 LIST_HEAD(port_remove_lh);
119
120 ccw_device_set_offline(cdev);
121
122 adapter = zfcp_ccw_adapter_by_cdev(cdev);
123 if (!adapter)
124 return;
125
126 write_lock_irq(&adapter->port_list_lock);
127 list_for_each_entry_safe(port, p, &adapter->port_list, list) {
128 write_lock(&port->unit_list_lock);
129 list_for_each_entry_safe(unit, u, &port->unit_list, list)
130 list_move(&unit->list, &unit_remove_lh);
131 write_unlock(&port->unit_list_lock);
132 list_move(&port->list, &port_remove_lh);
133 }
134 write_unlock_irq(&adapter->port_list_lock);
135 zfcp_ccw_adapter_put(adapter);
136
137 list_for_each_entry_safe(unit, u, &unit_remove_lh, list)
138 device_unregister(&unit->dev);
139
140 list_for_each_entry_safe(port, p, &port_remove_lh, list)
141 device_unregister(&port->dev);
142
143 zfcp_adapter_unregister(adapter);
144}
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159static int zfcp_ccw_set_online(struct ccw_device *cdev)
160{
161 struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
162
163 if (!adapter) {
164 adapter = zfcp_adapter_enqueue(cdev);
165
166 if (IS_ERR(adapter)) {
167 dev_err(&cdev->dev,
168 "Setting up data structures for the "
169 "FCP adapter failed\n");
170 return PTR_ERR(adapter);
171 }
172 kref_get(&adapter->ref);
173 }
174
175
176 BUG_ON(!zfcp_reqlist_isempty(adapter->req_list));
177 adapter->req_no = 0;
178
179 zfcp_ccw_activate(cdev, 0, "ccsonl1");
180
181
182
183
184
185
186
187
188
189
190
191 zfcp_fc_inverse_conditional_port_scan(adapter);
192 flush_delayed_work(&adapter->scan_work);
193 zfcp_ccw_adapter_put(adapter);
194 return 0;
195}
196
197
198
199
200
201
202
203
204
205
206static int zfcp_ccw_offline_sync(struct ccw_device *cdev, int set, char *tag)
207{
208 struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
209
210 if (!adapter)
211 return 0;
212
213 zfcp_erp_set_adapter_status(adapter, set);
214 zfcp_erp_adapter_shutdown(adapter, 0, tag);
215 zfcp_erp_wait(adapter);
216
217 zfcp_ccw_adapter_put(adapter);
218 return 0;
219}
220
221
222
223
224
225
226
227
228static int zfcp_ccw_set_offline(struct ccw_device *cdev)
229{
230 return zfcp_ccw_offline_sync(cdev, 0, "ccsoff1");
231}
232
233
234
235
236
237
238
239
240
241static int zfcp_ccw_notify(struct ccw_device *cdev, int event)
242{
243 struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
244
245 if (!adapter)
246 return 1;
247
248 switch (event) {
249 case CIO_GONE:
250 if (atomic_read(&adapter->status) &
251 ZFCP_STATUS_ADAPTER_SUSPENDED) {
252 zfcp_dbf_hba_basic("ccnigo1", adapter);
253 break;
254 }
255 dev_warn(&cdev->dev, "The FCP device has been detached\n");
256 zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1");
257 break;
258 case CIO_NO_PATH:
259 dev_warn(&cdev->dev,
260 "The CHPID for the FCP device is offline\n");
261 zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2");
262 break;
263 case CIO_OPER:
264 if (atomic_read(&adapter->status) &
265 ZFCP_STATUS_ADAPTER_SUSPENDED) {
266 zfcp_dbf_hba_basic("ccniop1", adapter);
267 break;
268 }
269 dev_info(&cdev->dev, "The FCP device is operational again\n");
270 zfcp_erp_set_adapter_status(adapter,
271 ZFCP_STATUS_COMMON_RUNNING);
272 zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
273 "ccnoti4");
274 break;
275 case CIO_BOXED:
276 dev_warn(&cdev->dev, "The FCP device did not respond within "
277 "the specified time\n");
278 zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5");
279 break;
280 }
281
282 zfcp_ccw_adapter_put(adapter);
283 return 1;
284}
285
286
287
288
289
290static void zfcp_ccw_shutdown(struct ccw_device *cdev)
291{
292 struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
293
294 if (!adapter)
295 return;
296
297 zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1");
298 zfcp_erp_wait(adapter);
299 zfcp_erp_thread_kill(adapter);
300
301 zfcp_ccw_adapter_put(adapter);
302}
303
304static int zfcp_ccw_suspend(struct ccw_device *cdev)
305{
306 zfcp_ccw_offline_sync(cdev, ZFCP_STATUS_ADAPTER_SUSPENDED, "ccsusp1");
307 return 0;
308}
309
310static int zfcp_ccw_thaw(struct ccw_device *cdev)
311{
312
313
314
315
316 zfcp_ccw_activate(cdev, 0, "ccthaw1");
317 return 0;
318}
319
320static int zfcp_ccw_resume(struct ccw_device *cdev)
321{
322 zfcp_ccw_activate(cdev, ZFCP_STATUS_ADAPTER_SUSPENDED, "ccresu1");
323 return 0;
324}
325
326struct ccw_driver zfcp_ccw_driver = {
327 .driver = {
328 .owner = THIS_MODULE,
329 .name = "zfcp",
330 },
331 .ids = zfcp_ccw_device_id,
332 .probe = zfcp_ccw_probe,
333 .remove = zfcp_ccw_remove,
334 .set_online = zfcp_ccw_set_online,
335 .set_offline = zfcp_ccw_set_offline,
336 .notify = zfcp_ccw_notify,
337 .shutdown = zfcp_ccw_shutdown,
338 .freeze = zfcp_ccw_suspend,
339 .thaw = zfcp_ccw_thaw,
340 .restore = zfcp_ccw_resume,
341};
342