diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_ccw.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_ccw.c | 179 |
1 files changed, 82 insertions, 97 deletions
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index e08339428ecf..c22cb72a5ae8 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c | |||
@@ -13,28 +13,34 @@ | |||
13 | 13 | ||
14 | #define ZFCP_MODEL_PRIV 0x4 | 14 | #define ZFCP_MODEL_PRIV 0x4 |
15 | 15 | ||
16 | static int zfcp_ccw_suspend(struct ccw_device *cdev) | 16 | static DEFINE_SPINLOCK(zfcp_ccw_adapter_ref_lock); |
17 | 17 | ||
18 | struct zfcp_adapter *zfcp_ccw_adapter_by_cdev(struct ccw_device *cdev) | ||
18 | { | 19 | { |
19 | struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); | 20 | struct zfcp_adapter *adapter; |
20 | 21 | unsigned long flags; | |
21 | if (!adapter) | ||
22 | return 0; | ||
23 | |||
24 | mutex_lock(&zfcp_data.config_mutex); | ||
25 | 22 | ||
26 | zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL); | 23 | spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags); |
27 | zfcp_erp_wait(adapter); | 24 | adapter = dev_get_drvdata(&cdev->dev); |
25 | if (adapter) | ||
26 | kref_get(&adapter->ref); | ||
27 | spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags); | ||
28 | return adapter; | ||
29 | } | ||
28 | 30 | ||
29 | mutex_unlock(&zfcp_data.config_mutex); | 31 | void zfcp_ccw_adapter_put(struct zfcp_adapter *adapter) |
32 | { | ||
33 | unsigned long flags; | ||
30 | 34 | ||
31 | return 0; | 35 | spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags); |
36 | kref_put(&adapter->ref, zfcp_adapter_release); | ||
37 | spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags); | ||
32 | } | 38 | } |
33 | 39 | ||
34 | static int zfcp_ccw_activate(struct ccw_device *cdev) | 40 | static int zfcp_ccw_activate(struct ccw_device *cdev) |
35 | 41 | ||
36 | { | 42 | { |
37 | struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); | 43 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
38 | 44 | ||
39 | if (!adapter) | 45 | if (!adapter) |
40 | return 0; | 46 | return 0; |
@@ -46,6 +52,8 @@ static int zfcp_ccw_activate(struct ccw_device *cdev) | |||
46 | zfcp_erp_wait(adapter); | 52 | zfcp_erp_wait(adapter); |
47 | flush_work(&adapter->scan_work); | 53 | flush_work(&adapter->scan_work); |
48 | 54 | ||
55 | zfcp_ccw_adapter_put(adapter); | ||
56 | |||
49 | return 0; | 57 | return 0; |
50 | } | 58 | } |
51 | 59 | ||
@@ -67,28 +75,28 @@ int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter) | |||
67 | 75 | ||
68 | /** | 76 | /** |
69 | * zfcp_ccw_probe - probe function of zfcp driver | 77 | * zfcp_ccw_probe - probe function of zfcp driver |
70 | * @ccw_device: pointer to belonging ccw device | 78 | * @cdev: pointer to belonging ccw device |
71 | * | 79 | * |
72 | * This function gets called by the common i/o layer for each FCP | 80 | * This function gets called by the common i/o layer for each FCP |
73 | * device found on the current system. This is only a stub to make cio | 81 | * device found on the current system. This is only a stub to make cio |
74 | * work: To only allocate adapter resources for devices actually used, | 82 | * work: To only allocate adapter resources for devices actually used, |
75 | * the allocation is deferred to the first call to ccw_set_online. | 83 | * the allocation is deferred to the first call to ccw_set_online. |
76 | */ | 84 | */ |
77 | static int zfcp_ccw_probe(struct ccw_device *ccw_device) | 85 | static int zfcp_ccw_probe(struct ccw_device *cdev) |
78 | { | 86 | { |
79 | return 0; | 87 | return 0; |
80 | } | 88 | } |
81 | 89 | ||
82 | /** | 90 | /** |
83 | * zfcp_ccw_remove - remove function of zfcp driver | 91 | * zfcp_ccw_remove - remove function of zfcp driver |
84 | * @ccw_device: pointer to belonging ccw device | 92 | * @cdev: pointer to belonging ccw device |
85 | * | 93 | * |
86 | * This function gets called by the common i/o layer and removes an adapter | 94 | * This function gets called by the common i/o layer and removes an adapter |
87 | * from the system. Task of this function is to get rid of all units and | 95 | * from the system. Task of this function is to get rid of all units and |
88 | * ports that belong to this adapter. And in addition all resources of this | 96 | * ports that belong to this adapter. And in addition all resources of this |
89 | * adapter will be freed too. | 97 | * adapter will be freed too. |
90 | */ | 98 | */ |
91 | static void zfcp_ccw_remove(struct ccw_device *ccw_device) | 99 | static void zfcp_ccw_remove(struct ccw_device *cdev) |
92 | { | 100 | { |
93 | struct zfcp_adapter *adapter; | 101 | struct zfcp_adapter *adapter; |
94 | struct zfcp_port *port, *p; | 102 | struct zfcp_port *port, *p; |
@@ -96,49 +104,37 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) | |||
96 | LIST_HEAD(unit_remove_lh); | 104 | LIST_HEAD(unit_remove_lh); |
97 | LIST_HEAD(port_remove_lh); | 105 | LIST_HEAD(port_remove_lh); |
98 | 106 | ||
99 | ccw_device_set_offline(ccw_device); | 107 | ccw_device_set_offline(cdev); |
100 | 108 | ||
101 | mutex_lock(&zfcp_data.config_mutex); | 109 | adapter = zfcp_ccw_adapter_by_cdev(cdev); |
102 | adapter = dev_get_drvdata(&ccw_device->dev); | ||
103 | if (!adapter) | 110 | if (!adapter) |
104 | goto out; | 111 | return; |
105 | mutex_unlock(&zfcp_data.config_mutex); | ||
106 | 112 | ||
107 | cancel_work_sync(&adapter->scan_work); | 113 | write_lock_irq(&adapter->port_list_lock); |
108 | 114 | list_for_each_entry_safe(port, p, &adapter->port_list, list) { | |
109 | mutex_lock(&zfcp_data.config_mutex); | 115 | write_lock(&port->unit_list_lock); |
110 | 116 | list_for_each_entry_safe(unit, u, &port->unit_list, list) | |
111 | /* this also removes the scsi devices, so call it first */ | ||
112 | zfcp_adapter_scsi_unregister(adapter); | ||
113 | |||
114 | write_lock_irq(&zfcp_data.config_lock); | ||
115 | list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { | ||
116 | list_for_each_entry_safe(unit, u, &port->unit_list_head, list) { | ||
117 | list_move(&unit->list, &unit_remove_lh); | 117 | list_move(&unit->list, &unit_remove_lh); |
118 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, | 118 | write_unlock(&port->unit_list_lock); |
119 | &unit->status); | ||
120 | } | ||
121 | list_move(&port->list, &port_remove_lh); | 119 | list_move(&port->list, &port_remove_lh); |
122 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); | ||
123 | } | 120 | } |
124 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); | 121 | write_unlock_irq(&adapter->port_list_lock); |
125 | write_unlock_irq(&zfcp_data.config_lock); | 122 | zfcp_ccw_adapter_put(adapter); /* put from zfcp_ccw_adapter_by_cdev */ |
126 | 123 | ||
127 | list_for_each_entry_safe(port, p, &port_remove_lh, list) { | 124 | list_for_each_entry_safe(unit, u, &unit_remove_lh, list) |
128 | list_for_each_entry_safe(unit, u, &unit_remove_lh, list) | 125 | zfcp_device_unregister(&unit->sysfs_device, |
129 | zfcp_unit_dequeue(unit); | 126 | &zfcp_sysfs_unit_attrs); |
130 | zfcp_port_dequeue(port); | ||
131 | } | ||
132 | wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); | ||
133 | zfcp_adapter_dequeue(adapter); | ||
134 | 127 | ||
135 | out: | 128 | list_for_each_entry_safe(port, p, &port_remove_lh, list) |
136 | mutex_unlock(&zfcp_data.config_mutex); | 129 | zfcp_device_unregister(&port->sysfs_device, |
130 | &zfcp_sysfs_port_attrs); | ||
131 | |||
132 | zfcp_adapter_unregister(adapter); | ||
137 | } | 133 | } |
138 | 134 | ||
139 | /** | 135 | /** |
140 | * zfcp_ccw_set_online - set_online function of zfcp driver | 136 | * zfcp_ccw_set_online - set_online function of zfcp driver |
141 | * @ccw_device: pointer to belonging ccw device | 137 | * @cdev: pointer to belonging ccw device |
142 | * | 138 | * |
143 | * This function gets called by the common i/o layer and sets an | 139 | * This function gets called by the common i/o layer and sets an |
144 | * adapter into state online. The first call will allocate all | 140 | * adapter into state online. The first call will allocate all |
@@ -149,23 +145,20 @@ out: | |||
149 | * the SCSI stack, that the QDIO queues will be set up and that the | 145 | * the SCSI stack, that the QDIO queues will be set up and that the |
150 | * adapter will be opened. | 146 | * adapter will be opened. |
151 | */ | 147 | */ |
152 | static int zfcp_ccw_set_online(struct ccw_device *ccw_device) | 148 | static int zfcp_ccw_set_online(struct ccw_device *cdev) |
153 | { | 149 | { |
154 | struct zfcp_adapter *adapter; | 150 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
155 | int ret = 0; | ||
156 | |||
157 | mutex_lock(&zfcp_data.config_mutex); | ||
158 | adapter = dev_get_drvdata(&ccw_device->dev); | ||
159 | 151 | ||
160 | if (!adapter) { | 152 | if (!adapter) { |
161 | ret = zfcp_adapter_enqueue(ccw_device); | 153 | adapter = zfcp_adapter_enqueue(cdev); |
162 | if (ret) { | 154 | |
163 | dev_err(&ccw_device->dev, | 155 | if (IS_ERR(adapter)) { |
156 | dev_err(&cdev->dev, | ||
164 | "Setting up data structures for the " | 157 | "Setting up data structures for the " |
165 | "FCP adapter failed\n"); | 158 | "FCP adapter failed\n"); |
166 | goto out; | 159 | return PTR_ERR(adapter); |
167 | } | 160 | } |
168 | adapter = dev_get_drvdata(&ccw_device->dev); | 161 | kref_get(&adapter->ref); |
169 | } | 162 | } |
170 | 163 | ||
171 | /* initialize request counter */ | 164 | /* initialize request counter */ |
@@ -177,58 +170,61 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device) | |||
177 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, | 170 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, |
178 | "ccsonl2", NULL); | 171 | "ccsonl2", NULL); |
179 | zfcp_erp_wait(adapter); | 172 | zfcp_erp_wait(adapter); |
180 | out: | 173 | |
181 | mutex_unlock(&zfcp_data.config_mutex); | 174 | flush_work(&adapter->scan_work); |
182 | if (!ret) | 175 | |
183 | flush_work(&adapter->scan_work); | 176 | zfcp_ccw_adapter_put(adapter); |
184 | return ret; | 177 | return 0; |
185 | } | 178 | } |
186 | 179 | ||
187 | /** | 180 | /** |
188 | * zfcp_ccw_set_offline - set_offline function of zfcp driver | 181 | * zfcp_ccw_set_offline - set_offline function of zfcp driver |
189 | * @ccw_device: pointer to belonging ccw device | 182 | * @cdev: pointer to belonging ccw device |
190 | * | 183 | * |
191 | * This function gets called by the common i/o layer and sets an adapter | 184 | * This function gets called by the common i/o layer and sets an adapter |
192 | * into state offline. | 185 | * into state offline. |
193 | */ | 186 | */ |
194 | static int zfcp_ccw_set_offline(struct ccw_device *ccw_device) | 187 | static int zfcp_ccw_set_offline(struct ccw_device *cdev) |
195 | { | 188 | { |
196 | struct zfcp_adapter *adapter; | 189 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
190 | |||
191 | if (!adapter) | ||
192 | return 0; | ||
197 | 193 | ||
198 | mutex_lock(&zfcp_data.config_mutex); | ||
199 | adapter = dev_get_drvdata(&ccw_device->dev); | ||
200 | zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL); | 194 | zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL); |
201 | zfcp_erp_wait(adapter); | 195 | zfcp_erp_wait(adapter); |
202 | mutex_unlock(&zfcp_data.config_mutex); | 196 | |
197 | zfcp_ccw_adapter_put(adapter); | ||
203 | return 0; | 198 | return 0; |
204 | } | 199 | } |
205 | 200 | ||
206 | /** | 201 | /** |
207 | * zfcp_ccw_notify - ccw notify function | 202 | * zfcp_ccw_notify - ccw notify function |
208 | * @ccw_device: pointer to belonging ccw device | 203 | * @cdev: pointer to belonging ccw device |
209 | * @event: indicates if adapter was detached or attached | 204 | * @event: indicates if adapter was detached or attached |
210 | * | 205 | * |
211 | * This function gets called by the common i/o layer if an adapter has gone | 206 | * This function gets called by the common i/o layer if an adapter has gone |
212 | * or reappeared. | 207 | * or reappeared. |
213 | */ | 208 | */ |
214 | static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event) | 209 | static int zfcp_ccw_notify(struct ccw_device *cdev, int event) |
215 | { | 210 | { |
216 | struct zfcp_adapter *adapter = dev_get_drvdata(&ccw_device->dev); | 211 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
212 | |||
213 | if (!adapter) | ||
214 | return 1; | ||
217 | 215 | ||
218 | switch (event) { | 216 | switch (event) { |
219 | case CIO_GONE: | 217 | case CIO_GONE: |
220 | dev_warn(&adapter->ccw_device->dev, | 218 | dev_warn(&cdev->dev, "The FCP device has been detached\n"); |
221 | "The FCP device has been detached\n"); | ||
222 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1", NULL); | 219 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1", NULL); |
223 | break; | 220 | break; |
224 | case CIO_NO_PATH: | 221 | case CIO_NO_PATH: |
225 | dev_warn(&adapter->ccw_device->dev, | 222 | dev_warn(&cdev->dev, |
226 | "The CHPID for the FCP device is offline\n"); | 223 | "The CHPID for the FCP device is offline\n"); |
227 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2", NULL); | 224 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2", NULL); |
228 | break; | 225 | break; |
229 | case CIO_OPER: | 226 | case CIO_OPER: |
230 | dev_info(&adapter->ccw_device->dev, | 227 | dev_info(&cdev->dev, "The FCP device is operational again\n"); |
231 | "The FCP device is operational again\n"); | ||
232 | zfcp_erp_modify_adapter_status(adapter, "ccnoti3", NULL, | 228 | zfcp_erp_modify_adapter_status(adapter, "ccnoti3", NULL, |
233 | ZFCP_STATUS_COMMON_RUNNING, | 229 | ZFCP_STATUS_COMMON_RUNNING, |
234 | ZFCP_SET); | 230 | ZFCP_SET); |
@@ -236,11 +232,13 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event) | |||
236 | "ccnoti4", NULL); | 232 | "ccnoti4", NULL); |
237 | break; | 233 | break; |
238 | case CIO_BOXED: | 234 | case CIO_BOXED: |
239 | dev_warn(&adapter->ccw_device->dev, "The FCP device " | 235 | dev_warn(&cdev->dev, "The FCP device did not respond within " |
240 | "did not respond within the specified time\n"); | 236 | "the specified time\n"); |
241 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL); | 237 | zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL); |
242 | break; | 238 | break; |
243 | } | 239 | } |
240 | |||
241 | zfcp_ccw_adapter_put(adapter); | ||
244 | return 1; | 242 | return 1; |
245 | } | 243 | } |
246 | 244 | ||
@@ -250,18 +248,16 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event) | |||
250 | */ | 248 | */ |
251 | static void zfcp_ccw_shutdown(struct ccw_device *cdev) | 249 | static void zfcp_ccw_shutdown(struct ccw_device *cdev) |
252 | { | 250 | { |
253 | struct zfcp_adapter *adapter; | 251 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
254 | 252 | ||
255 | mutex_lock(&zfcp_data.config_mutex); | ||
256 | adapter = dev_get_drvdata(&cdev->dev); | ||
257 | if (!adapter) | 253 | if (!adapter) |
258 | goto out; | 254 | return; |
259 | 255 | ||
260 | zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL); | 256 | zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL); |
261 | zfcp_erp_wait(adapter); | 257 | zfcp_erp_wait(adapter); |
262 | zfcp_erp_thread_kill(adapter); | 258 | zfcp_erp_thread_kill(adapter); |
263 | out: | 259 | |
264 | mutex_unlock(&zfcp_data.config_mutex); | 260 | zfcp_ccw_adapter_put(adapter); |
265 | } | 261 | } |
266 | 262 | ||
267 | struct ccw_driver zfcp_ccw_driver = { | 263 | struct ccw_driver zfcp_ccw_driver = { |
@@ -274,18 +270,7 @@ struct ccw_driver zfcp_ccw_driver = { | |||
274 | .set_offline = zfcp_ccw_set_offline, | 270 | .set_offline = zfcp_ccw_set_offline, |
275 | .notify = zfcp_ccw_notify, | 271 | .notify = zfcp_ccw_notify, |
276 | .shutdown = zfcp_ccw_shutdown, | 272 | .shutdown = zfcp_ccw_shutdown, |
277 | .freeze = zfcp_ccw_suspend, | 273 | .freeze = zfcp_ccw_set_offline, |
278 | .thaw = zfcp_ccw_activate, | 274 | .thaw = zfcp_ccw_activate, |
279 | .restore = zfcp_ccw_activate, | 275 | .restore = zfcp_ccw_activate, |
280 | }; | 276 | }; |
281 | |||
282 | /** | ||
283 | * zfcp_ccw_register - ccw register function | ||
284 | * | ||
285 | * Registers the driver at the common i/o layer. This function will be called | ||
286 | * at module load time/system start. | ||
287 | */ | ||
288 | int __init zfcp_ccw_register(void) | ||
289 | { | ||
290 | return ccw_driver_register(&zfcp_ccw_driver); | ||
291 | } | ||