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