diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_aux.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 388 |
1 files changed, 193 insertions, 195 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 2889e5f2dfd3..9d0c941b7d33 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/miscdevice.h> | 31 | #include <linux/miscdevice.h> |
32 | #include <linux/seq_file.h> | 32 | #include <linux/seq_file.h> |
33 | #include "zfcp_ext.h" | 33 | #include "zfcp_ext.h" |
34 | #include "zfcp_fc.h" | ||
34 | 35 | ||
35 | #define ZFCP_BUS_ID_SIZE 20 | 36 | #define ZFCP_BUS_ID_SIZE 20 |
36 | 37 | ||
@@ -80,48 +81,40 @@ int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) | |||
80 | 81 | ||
81 | static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) | 82 | static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) |
82 | { | 83 | { |
83 | struct ccw_device *ccwdev; | 84 | struct ccw_device *cdev; |
84 | struct zfcp_adapter *adapter; | 85 | struct zfcp_adapter *adapter; |
85 | struct zfcp_port *port; | 86 | struct zfcp_port *port; |
86 | struct zfcp_unit *unit; | 87 | struct zfcp_unit *unit; |
87 | 88 | ||
88 | ccwdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); | 89 | cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); |
89 | if (!ccwdev) | 90 | if (!cdev) |
90 | return; | 91 | return; |
91 | 92 | ||
92 | if (ccw_device_set_online(ccwdev)) | 93 | if (ccw_device_set_online(cdev)) |
93 | goto out_ccwdev; | 94 | goto out_ccw_device; |
94 | 95 | ||
95 | mutex_lock(&zfcp_data.config_mutex); | 96 | adapter = zfcp_ccw_adapter_by_cdev(cdev); |
96 | adapter = dev_get_drvdata(&ccwdev->dev); | ||
97 | if (!adapter) | 97 | if (!adapter) |
98 | goto out_unlock; | 98 | goto out_ccw_device; |
99 | zfcp_adapter_get(adapter); | ||
100 | 99 | ||
101 | port = zfcp_get_port_by_wwpn(adapter, wwpn); | 100 | port = zfcp_get_port_by_wwpn(adapter, wwpn); |
102 | if (!port) | 101 | if (!port) |
103 | goto out_port; | 102 | goto out_port; |
104 | 103 | ||
105 | zfcp_port_get(port); | ||
106 | unit = zfcp_unit_enqueue(port, lun); | 104 | unit = zfcp_unit_enqueue(port, lun); |
107 | if (IS_ERR(unit)) | 105 | if (IS_ERR(unit)) |
108 | goto out_unit; | 106 | goto out_unit; |
109 | mutex_unlock(&zfcp_data.config_mutex); | ||
110 | 107 | ||
111 | zfcp_erp_unit_reopen(unit, 0, "auidc_1", NULL); | 108 | zfcp_erp_unit_reopen(unit, 0, "auidc_1", NULL); |
112 | zfcp_erp_wait(adapter); | 109 | zfcp_erp_wait(adapter); |
113 | flush_work(&unit->scsi_work); | 110 | flush_work(&unit->scsi_work); |
114 | 111 | ||
115 | mutex_lock(&zfcp_data.config_mutex); | ||
116 | zfcp_unit_put(unit); | ||
117 | out_unit: | 112 | out_unit: |
118 | zfcp_port_put(port); | 113 | put_device(&port->sysfs_device); |
119 | out_port: | 114 | out_port: |
120 | zfcp_adapter_put(adapter); | 115 | zfcp_ccw_adapter_put(adapter); |
121 | out_unlock: | 116 | out_ccw_device: |
122 | mutex_unlock(&zfcp_data.config_mutex); | 117 | put_device(&cdev->dev); |
123 | out_ccwdev: | ||
124 | put_device(&ccwdev->dev); | ||
125 | return; | 118 | return; |
126 | } | 119 | } |
127 | 120 | ||
@@ -167,7 +160,7 @@ static int __init zfcp_module_init(void) | |||
167 | int retval = -ENOMEM; | 160 | int retval = -ENOMEM; |
168 | 161 | ||
169 | zfcp_data.gpn_ft_cache = zfcp_cache_hw_align("zfcp_gpn", | 162 | zfcp_data.gpn_ft_cache = zfcp_cache_hw_align("zfcp_gpn", |
170 | sizeof(struct ct_iu_gpn_ft_req)); | 163 | sizeof(struct zfcp_fc_gpn_ft_req)); |
171 | if (!zfcp_data.gpn_ft_cache) | 164 | if (!zfcp_data.gpn_ft_cache) |
172 | goto out; | 165 | goto out; |
173 | 166 | ||
@@ -182,12 +175,14 @@ static int __init zfcp_module_init(void) | |||
182 | goto out_sr_cache; | 175 | goto out_sr_cache; |
183 | 176 | ||
184 | zfcp_data.gid_pn_cache = zfcp_cache_hw_align("zfcp_gid", | 177 | zfcp_data.gid_pn_cache = zfcp_cache_hw_align("zfcp_gid", |
185 | sizeof(struct zfcp_gid_pn_data)); | 178 | sizeof(struct zfcp_fc_gid_pn)); |
186 | if (!zfcp_data.gid_pn_cache) | 179 | if (!zfcp_data.gid_pn_cache) |
187 | goto out_gid_cache; | 180 | goto out_gid_cache; |
188 | 181 | ||
189 | mutex_init(&zfcp_data.config_mutex); | 182 | zfcp_data.adisc_cache = zfcp_cache_hw_align("zfcp_adisc", |
190 | rwlock_init(&zfcp_data.config_lock); | 183 | sizeof(struct zfcp_fc_els_adisc)); |
184 | if (!zfcp_data.adisc_cache) | ||
185 | goto out_adisc_cache; | ||
191 | 186 | ||
192 | zfcp_data.scsi_transport_template = | 187 | zfcp_data.scsi_transport_template = |
193 | fc_attach_transport(&zfcp_transport_functions); | 188 | fc_attach_transport(&zfcp_transport_functions); |
@@ -200,7 +195,7 @@ static int __init zfcp_module_init(void) | |||
200 | goto out_misc; | 195 | goto out_misc; |
201 | } | 196 | } |
202 | 197 | ||
203 | retval = zfcp_ccw_register(); | 198 | retval = ccw_driver_register(&zfcp_ccw_driver); |
204 | if (retval) { | 199 | if (retval) { |
205 | pr_err("The zfcp device driver could not register with " | 200 | pr_err("The zfcp device driver could not register with " |
206 | "the common I/O layer\n"); | 201 | "the common I/O layer\n"); |
@@ -216,6 +211,8 @@ out_ccw_register: | |||
216 | out_misc: | 211 | out_misc: |
217 | fc_release_transport(zfcp_data.scsi_transport_template); | 212 | fc_release_transport(zfcp_data.scsi_transport_template); |
218 | out_transport: | 213 | out_transport: |
214 | kmem_cache_destroy(zfcp_data.adisc_cache); | ||
215 | out_adisc_cache: | ||
219 | kmem_cache_destroy(zfcp_data.gid_pn_cache); | 216 | kmem_cache_destroy(zfcp_data.gid_pn_cache); |
220 | out_gid_cache: | 217 | out_gid_cache: |
221 | kmem_cache_destroy(zfcp_data.sr_buffer_cache); | 218 | kmem_cache_destroy(zfcp_data.sr_buffer_cache); |
@@ -229,6 +226,20 @@ out: | |||
229 | 226 | ||
230 | module_init(zfcp_module_init); | 227 | module_init(zfcp_module_init); |
231 | 228 | ||
229 | static void __exit zfcp_module_exit(void) | ||
230 | { | ||
231 | ccw_driver_unregister(&zfcp_ccw_driver); | ||
232 | misc_deregister(&zfcp_cfdc_misc); | ||
233 | fc_release_transport(zfcp_data.scsi_transport_template); | ||
234 | kmem_cache_destroy(zfcp_data.adisc_cache); | ||
235 | kmem_cache_destroy(zfcp_data.gid_pn_cache); | ||
236 | kmem_cache_destroy(zfcp_data.sr_buffer_cache); | ||
237 | kmem_cache_destroy(zfcp_data.qtcb_cache); | ||
238 | kmem_cache_destroy(zfcp_data.gpn_ft_cache); | ||
239 | } | ||
240 | |||
241 | module_exit(zfcp_module_exit); | ||
242 | |||
232 | /** | 243 | /** |
233 | * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN | 244 | * zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN |
234 | * @port: pointer to port to search for unit | 245 | * @port: pointer to port to search for unit |
@@ -238,12 +249,18 @@ module_init(zfcp_module_init); | |||
238 | */ | 249 | */ |
239 | struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) | 250 | struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) |
240 | { | 251 | { |
252 | unsigned long flags; | ||
241 | struct zfcp_unit *unit; | 253 | struct zfcp_unit *unit; |
242 | 254 | ||
243 | list_for_each_entry(unit, &port->unit_list_head, list) | 255 | read_lock_irqsave(&port->unit_list_lock, flags); |
244 | if ((unit->fcp_lun == fcp_lun) && | 256 | list_for_each_entry(unit, &port->unit_list, list) |
245 | !(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE)) | 257 | if (unit->fcp_lun == fcp_lun) { |
246 | return unit; | 258 | if (!get_device(&unit->sysfs_device)) |
259 | unit = NULL; | ||
260 | read_unlock_irqrestore(&port->unit_list_lock, flags); | ||
261 | return unit; | ||
262 | } | ||
263 | read_unlock_irqrestore(&port->unit_list_lock, flags); | ||
247 | return NULL; | 264 | return NULL; |
248 | } | 265 | } |
249 | 266 | ||
@@ -257,18 +274,35 @@ struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) | |||
257 | struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, | 274 | struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, |
258 | u64 wwpn) | 275 | u64 wwpn) |
259 | { | 276 | { |
277 | unsigned long flags; | ||
260 | struct zfcp_port *port; | 278 | struct zfcp_port *port; |
261 | 279 | ||
262 | list_for_each_entry(port, &adapter->port_list_head, list) | 280 | read_lock_irqsave(&adapter->port_list_lock, flags); |
263 | if ((port->wwpn == wwpn) && | 281 | list_for_each_entry(port, &adapter->port_list, list) |
264 | !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE)) | 282 | if (port->wwpn == wwpn) { |
283 | if (!get_device(&port->sysfs_device)) | ||
284 | port = NULL; | ||
285 | read_unlock_irqrestore(&adapter->port_list_lock, flags); | ||
265 | return port; | 286 | return port; |
287 | } | ||
288 | read_unlock_irqrestore(&adapter->port_list_lock, flags); | ||
266 | return NULL; | 289 | return NULL; |
267 | } | 290 | } |
268 | 291 | ||
269 | static void zfcp_sysfs_unit_release(struct device *dev) | 292 | /** |
293 | * zfcp_unit_release - dequeue unit | ||
294 | * @dev: pointer to device | ||
295 | * | ||
296 | * waits until all work is done on unit and removes it then from the unit->list | ||
297 | * of the associated port. | ||
298 | */ | ||
299 | static void zfcp_unit_release(struct device *dev) | ||
270 | { | 300 | { |
271 | kfree(container_of(dev, struct zfcp_unit, sysfs_device)); | 301 | struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, |
302 | sysfs_device); | ||
303 | |||
304 | put_device(&unit->port->sysfs_device); | ||
305 | kfree(unit); | ||
272 | } | 306 | } |
273 | 307 | ||
274 | /** | 308 | /** |
@@ -276,43 +310,40 @@ static void zfcp_sysfs_unit_release(struct device *dev) | |||
276 | * @port: pointer to port where unit is added | 310 | * @port: pointer to port where unit is added |
277 | * @fcp_lun: FCP LUN of unit to be enqueued | 311 | * @fcp_lun: FCP LUN of unit to be enqueued |
278 | * Returns: pointer to enqueued unit on success, ERR_PTR on error | 312 | * Returns: pointer to enqueued unit on success, ERR_PTR on error |
279 | * Locks: config_mutex must be held to serialize changes to the unit list | ||
280 | * | 313 | * |
281 | * Sets up some unit internal structures and creates sysfs entry. | 314 | * Sets up some unit internal structures and creates sysfs entry. |
282 | */ | 315 | */ |
283 | struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) | 316 | struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) |
284 | { | 317 | { |
285 | struct zfcp_unit *unit; | 318 | struct zfcp_unit *unit; |
319 | int retval = -ENOMEM; | ||
286 | 320 | ||
287 | read_lock_irq(&zfcp_data.config_lock); | 321 | get_device(&port->sysfs_device); |
288 | if (zfcp_get_unit_by_lun(port, fcp_lun)) { | 322 | |
289 | read_unlock_irq(&zfcp_data.config_lock); | 323 | unit = zfcp_get_unit_by_lun(port, fcp_lun); |
290 | return ERR_PTR(-EINVAL); | 324 | if (unit) { |
325 | put_device(&unit->sysfs_device); | ||
326 | retval = -EEXIST; | ||
327 | goto err_out; | ||
291 | } | 328 | } |
292 | read_unlock_irq(&zfcp_data.config_lock); | ||
293 | 329 | ||
294 | unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); | 330 | unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); |
295 | if (!unit) | 331 | if (!unit) |
296 | return ERR_PTR(-ENOMEM); | 332 | goto err_out; |
297 | |||
298 | atomic_set(&unit->refcount, 0); | ||
299 | init_waitqueue_head(&unit->remove_wq); | ||
300 | INIT_WORK(&unit->scsi_work, zfcp_scsi_scan); | ||
301 | 333 | ||
302 | unit->port = port; | 334 | unit->port = port; |
303 | unit->fcp_lun = fcp_lun; | 335 | unit->fcp_lun = fcp_lun; |
336 | unit->sysfs_device.parent = &port->sysfs_device; | ||
337 | unit->sysfs_device.release = zfcp_unit_release; | ||
304 | 338 | ||
305 | if (dev_set_name(&unit->sysfs_device, "0x%016llx", | 339 | if (dev_set_name(&unit->sysfs_device, "0x%016llx", |
306 | (unsigned long long) fcp_lun)) { | 340 | (unsigned long long) fcp_lun)) { |
307 | kfree(unit); | 341 | kfree(unit); |
308 | return ERR_PTR(-ENOMEM); | 342 | goto err_out; |
309 | } | 343 | } |
310 | unit->sysfs_device.parent = &port->sysfs_device; | 344 | retval = -EINVAL; |
311 | unit->sysfs_device.release = zfcp_sysfs_unit_release; | ||
312 | dev_set_drvdata(&unit->sysfs_device, unit); | ||
313 | 345 | ||
314 | /* mark unit unusable as long as sysfs registration is not complete */ | 346 | INIT_WORK(&unit->scsi_work, zfcp_scsi_scan); |
315 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | ||
316 | 347 | ||
317 | spin_lock_init(&unit->latencies.lock); | 348 | spin_lock_init(&unit->latencies.lock); |
318 | unit->latencies.write.channel.min = 0xFFFFFFFF; | 349 | unit->latencies.write.channel.min = 0xFFFFFFFF; |
@@ -324,50 +355,30 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) | |||
324 | 355 | ||
325 | if (device_register(&unit->sysfs_device)) { | 356 | if (device_register(&unit->sysfs_device)) { |
326 | put_device(&unit->sysfs_device); | 357 | put_device(&unit->sysfs_device); |
327 | return ERR_PTR(-EINVAL); | 358 | goto err_out; |
328 | } | 359 | } |
329 | 360 | ||
330 | if (sysfs_create_group(&unit->sysfs_device.kobj, | 361 | if (sysfs_create_group(&unit->sysfs_device.kobj, |
331 | &zfcp_sysfs_unit_attrs)) { | 362 | &zfcp_sysfs_unit_attrs)) |
332 | device_unregister(&unit->sysfs_device); | 363 | goto err_out_put; |
333 | return ERR_PTR(-EINVAL); | ||
334 | } | ||
335 | 364 | ||
336 | zfcp_unit_get(unit); | 365 | write_lock_irq(&port->unit_list_lock); |
366 | list_add_tail(&unit->list, &port->unit_list); | ||
367 | write_unlock_irq(&port->unit_list_lock); | ||
337 | 368 | ||
338 | write_lock_irq(&zfcp_data.config_lock); | ||
339 | list_add_tail(&unit->list, &port->unit_list_head); | ||
340 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | ||
341 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); | 369 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); |
342 | 370 | ||
343 | write_unlock_irq(&zfcp_data.config_lock); | ||
344 | |||
345 | zfcp_port_get(port); | ||
346 | |||
347 | return unit; | 371 | return unit; |
348 | } | ||
349 | 372 | ||
350 | /** | 373 | err_out_put: |
351 | * zfcp_unit_dequeue - dequeue unit | ||
352 | * @unit: pointer to zfcp_unit | ||
353 | * | ||
354 | * waits until all work is done on unit and removes it then from the unit->list | ||
355 | * of the associated port. | ||
356 | */ | ||
357 | void zfcp_unit_dequeue(struct zfcp_unit *unit) | ||
358 | { | ||
359 | wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0); | ||
360 | write_lock_irq(&zfcp_data.config_lock); | ||
361 | list_del(&unit->list); | ||
362 | write_unlock_irq(&zfcp_data.config_lock); | ||
363 | zfcp_port_put(unit->port); | ||
364 | sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs); | ||
365 | device_unregister(&unit->sysfs_device); | 374 | device_unregister(&unit->sysfs_device); |
375 | err_out: | ||
376 | put_device(&port->sysfs_device); | ||
377 | return ERR_PTR(retval); | ||
366 | } | 378 | } |
367 | 379 | ||
368 | static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) | 380 | static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) |
369 | { | 381 | { |
370 | /* must only be called with zfcp_data.config_mutex taken */ | ||
371 | adapter->pool.erp_req = | 382 | adapter->pool.erp_req = |
372 | mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req)); | 383 | mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req)); |
373 | if (!adapter->pool.erp_req) | 384 | if (!adapter->pool.erp_req) |
@@ -405,9 +416,9 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) | |||
405 | if (!adapter->pool.status_read_data) | 416 | if (!adapter->pool.status_read_data) |
406 | return -ENOMEM; | 417 | return -ENOMEM; |
407 | 418 | ||
408 | adapter->pool.gid_pn_data = | 419 | adapter->pool.gid_pn = |
409 | mempool_create_slab_pool(1, zfcp_data.gid_pn_cache); | 420 | mempool_create_slab_pool(1, zfcp_data.gid_pn_cache); |
410 | if (!adapter->pool.gid_pn_data) | 421 | if (!adapter->pool.gid_pn) |
411 | return -ENOMEM; | 422 | return -ENOMEM; |
412 | 423 | ||
413 | return 0; | 424 | return 0; |
@@ -415,7 +426,6 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) | |||
415 | 426 | ||
416 | static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) | 427 | static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) |
417 | { | 428 | { |
418 | /* zfcp_data.config_mutex must be held */ | ||
419 | if (adapter->pool.erp_req) | 429 | if (adapter->pool.erp_req) |
420 | mempool_destroy(adapter->pool.erp_req); | 430 | mempool_destroy(adapter->pool.erp_req); |
421 | if (adapter->pool.scsi_req) | 431 | if (adapter->pool.scsi_req) |
@@ -428,8 +438,8 @@ static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) | |||
428 | mempool_destroy(adapter->pool.status_read_req); | 438 | mempool_destroy(adapter->pool.status_read_req); |
429 | if (adapter->pool.status_read_data) | 439 | if (adapter->pool.status_read_data) |
430 | mempool_destroy(adapter->pool.status_read_data); | 440 | mempool_destroy(adapter->pool.status_read_data); |
431 | if (adapter->pool.gid_pn_data) | 441 | if (adapter->pool.gid_pn) |
432 | mempool_destroy(adapter->pool.gid_pn_data); | 442 | mempool_destroy(adapter->pool.gid_pn); |
433 | } | 443 | } |
434 | 444 | ||
435 | /** | 445 | /** |
@@ -497,53 +507,56 @@ static void zfcp_destroy_adapter_work_queue(struct zfcp_adapter *adapter) | |||
497 | * zfcp_adapter_enqueue - enqueue a new adapter to the list | 507 | * zfcp_adapter_enqueue - enqueue a new adapter to the list |
498 | * @ccw_device: pointer to the struct cc_device | 508 | * @ccw_device: pointer to the struct cc_device |
499 | * | 509 | * |
500 | * Returns: 0 if a new adapter was successfully enqueued | 510 | * Returns: struct zfcp_adapter* |
501 | * -ENOMEM if alloc failed | ||
502 | * Enqueues an adapter at the end of the adapter list in the driver data. | 511 | * Enqueues an adapter at the end of the adapter list in the driver data. |
503 | * All adapter internal structures are set up. | 512 | * All adapter internal structures are set up. |
504 | * Proc-fs entries are also created. | 513 | * Proc-fs entries are also created. |
505 | * locks: config_mutex must be held to serialize changes to the adapter list | ||
506 | */ | 514 | */ |
507 | int zfcp_adapter_enqueue(struct ccw_device *ccw_device) | 515 | struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device) |
508 | { | 516 | { |
509 | struct zfcp_adapter *adapter; | 517 | struct zfcp_adapter *adapter; |
510 | 518 | ||
511 | /* | 519 | if (!get_device(&ccw_device->dev)) |
512 | * Note: It is safe to release the list_lock, as any list changes | 520 | return ERR_PTR(-ENODEV); |
513 | * are protected by the config_mutex, which must be held to get here | ||
514 | */ | ||
515 | 521 | ||
516 | adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL); | 522 | adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL); |
517 | if (!adapter) | 523 | if (!adapter) { |
518 | return -ENOMEM; | 524 | put_device(&ccw_device->dev); |
525 | return ERR_PTR(-ENOMEM); | ||
526 | } | ||
527 | |||
528 | kref_init(&adapter->ref); | ||
519 | 529 | ||
520 | ccw_device->handler = NULL; | 530 | ccw_device->handler = NULL; |
521 | adapter->ccw_device = ccw_device; | 531 | adapter->ccw_device = ccw_device; |
522 | atomic_set(&adapter->refcount, 0); | 532 | |
533 | INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); | ||
534 | INIT_WORK(&adapter->scan_work, zfcp_fc_scan_ports); | ||
523 | 535 | ||
524 | if (zfcp_qdio_setup(adapter)) | 536 | if (zfcp_qdio_setup(adapter)) |
525 | goto qdio_failed; | 537 | goto failed; |
526 | 538 | ||
527 | if (zfcp_allocate_low_mem_buffers(adapter)) | 539 | if (zfcp_allocate_low_mem_buffers(adapter)) |
528 | goto low_mem_buffers_failed; | 540 | goto failed; |
529 | 541 | ||
530 | if (zfcp_reqlist_alloc(adapter)) | 542 | if (zfcp_reqlist_alloc(adapter)) |
531 | goto low_mem_buffers_failed; | 543 | goto failed; |
532 | 544 | ||
533 | if (zfcp_dbf_adapter_register(adapter)) | 545 | if (zfcp_dbf_adapter_register(adapter)) |
534 | goto debug_register_failed; | 546 | goto failed; |
535 | 547 | ||
536 | if (zfcp_setup_adapter_work_queue(adapter)) | 548 | if (zfcp_setup_adapter_work_queue(adapter)) |
537 | goto work_queue_failed; | 549 | goto failed; |
538 | 550 | ||
539 | if (zfcp_fc_gs_setup(adapter)) | 551 | if (zfcp_fc_gs_setup(adapter)) |
540 | goto generic_services_failed; | 552 | goto failed; |
553 | |||
554 | rwlock_init(&adapter->port_list_lock); | ||
555 | INIT_LIST_HEAD(&adapter->port_list); | ||
541 | 556 | ||
542 | init_waitqueue_head(&adapter->remove_wq); | ||
543 | init_waitqueue_head(&adapter->erp_ready_wq); | 557 | init_waitqueue_head(&adapter->erp_ready_wq); |
544 | init_waitqueue_head(&adapter->erp_done_wqh); | 558 | init_waitqueue_head(&adapter->erp_done_wqh); |
545 | 559 | ||
546 | INIT_LIST_HEAD(&adapter->port_list_head); | ||
547 | INIT_LIST_HEAD(&adapter->erp_ready_head); | 560 | INIT_LIST_HEAD(&adapter->erp_ready_head); |
548 | INIT_LIST_HEAD(&adapter->erp_running_head); | 561 | INIT_LIST_HEAD(&adapter->erp_running_head); |
549 | 562 | ||
@@ -553,83 +566,85 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
553 | rwlock_init(&adapter->abort_lock); | 566 | rwlock_init(&adapter->abort_lock); |
554 | 567 | ||
555 | if (zfcp_erp_thread_setup(adapter)) | 568 | if (zfcp_erp_thread_setup(adapter)) |
556 | goto erp_thread_failed; | 569 | goto failed; |
557 | |||
558 | INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); | ||
559 | INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later); | ||
560 | 570 | ||
561 | adapter->service_level.seq_print = zfcp_print_sl; | 571 | adapter->service_level.seq_print = zfcp_print_sl; |
562 | 572 | ||
563 | /* mark adapter unusable as long as sysfs registration is not complete */ | ||
564 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); | ||
565 | |||
566 | dev_set_drvdata(&ccw_device->dev, adapter); | 573 | dev_set_drvdata(&ccw_device->dev, adapter); |
567 | 574 | ||
568 | if (sysfs_create_group(&ccw_device->dev.kobj, | 575 | if (sysfs_create_group(&ccw_device->dev.kobj, |
569 | &zfcp_sysfs_adapter_attrs)) | 576 | &zfcp_sysfs_adapter_attrs)) |
570 | goto sysfs_failed; | 577 | goto failed; |
571 | |||
572 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); | ||
573 | 578 | ||
574 | if (!zfcp_adapter_scsi_register(adapter)) | 579 | if (!zfcp_adapter_scsi_register(adapter)) |
575 | return 0; | 580 | return adapter; |
576 | 581 | ||
577 | sysfs_failed: | 582 | failed: |
578 | zfcp_erp_thread_kill(adapter); | 583 | zfcp_adapter_unregister(adapter); |
579 | erp_thread_failed: | 584 | return ERR_PTR(-ENOMEM); |
580 | zfcp_fc_gs_destroy(adapter); | 585 | } |
581 | generic_services_failed: | 586 | |
587 | void zfcp_adapter_unregister(struct zfcp_adapter *adapter) | ||
588 | { | ||
589 | struct ccw_device *cdev = adapter->ccw_device; | ||
590 | |||
591 | cancel_work_sync(&adapter->scan_work); | ||
592 | cancel_work_sync(&adapter->stat_work); | ||
582 | zfcp_destroy_adapter_work_queue(adapter); | 593 | zfcp_destroy_adapter_work_queue(adapter); |
583 | work_queue_failed: | 594 | |
595 | zfcp_fc_wka_ports_force_offline(adapter->gs); | ||
596 | zfcp_adapter_scsi_unregister(adapter); | ||
597 | sysfs_remove_group(&cdev->dev.kobj, &zfcp_sysfs_adapter_attrs); | ||
598 | |||
599 | zfcp_erp_thread_kill(adapter); | ||
584 | zfcp_dbf_adapter_unregister(adapter->dbf); | 600 | zfcp_dbf_adapter_unregister(adapter->dbf); |
585 | debug_register_failed: | ||
586 | dev_set_drvdata(&ccw_device->dev, NULL); | ||
587 | kfree(adapter->req_list); | ||
588 | low_mem_buffers_failed: | ||
589 | zfcp_free_low_mem_buffers(adapter); | ||
590 | qdio_failed: | ||
591 | zfcp_qdio_destroy(adapter->qdio); | 601 | zfcp_qdio_destroy(adapter->qdio); |
592 | kfree(adapter); | 602 | |
593 | return -ENOMEM; | 603 | zfcp_ccw_adapter_put(adapter); /* final put to release */ |
594 | } | 604 | } |
595 | 605 | ||
596 | /** | 606 | /** |
597 | * zfcp_adapter_dequeue - remove the adapter from the resource list | 607 | * zfcp_adapter_release - remove the adapter from the resource list |
598 | * @adapter: pointer to struct zfcp_adapter which should be removed | 608 | * @ref: pointer to struct kref |
599 | * locks: adapter list write lock is assumed to be held by caller | 609 | * locks: adapter list write lock is assumed to be held by caller |
600 | */ | 610 | */ |
601 | void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | 611 | void zfcp_adapter_release(struct kref *ref) |
602 | { | 612 | { |
603 | int retval = 0; | 613 | struct zfcp_adapter *adapter = container_of(ref, struct zfcp_adapter, |
604 | unsigned long flags; | 614 | ref); |
615 | struct ccw_device *cdev = adapter->ccw_device; | ||
605 | 616 | ||
606 | cancel_work_sync(&adapter->stat_work); | ||
607 | zfcp_fc_wka_ports_force_offline(adapter->gs); | ||
608 | sysfs_remove_group(&adapter->ccw_device->dev.kobj, | ||
609 | &zfcp_sysfs_adapter_attrs); | ||
610 | dev_set_drvdata(&adapter->ccw_device->dev, NULL); | 617 | dev_set_drvdata(&adapter->ccw_device->dev, NULL); |
611 | /* sanity check: no pending FSF requests */ | ||
612 | spin_lock_irqsave(&adapter->req_list_lock, flags); | ||
613 | retval = zfcp_reqlist_isempty(adapter); | ||
614 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); | ||
615 | if (!retval) | ||
616 | return; | ||
617 | |||
618 | zfcp_fc_gs_destroy(adapter); | 618 | zfcp_fc_gs_destroy(adapter); |
619 | zfcp_erp_thread_kill(adapter); | ||
620 | zfcp_destroy_adapter_work_queue(adapter); | ||
621 | zfcp_dbf_adapter_unregister(adapter->dbf); | ||
622 | zfcp_free_low_mem_buffers(adapter); | 619 | zfcp_free_low_mem_buffers(adapter); |
623 | zfcp_qdio_destroy(adapter->qdio); | ||
624 | kfree(adapter->req_list); | 620 | kfree(adapter->req_list); |
625 | kfree(adapter->fc_stats); | 621 | kfree(adapter->fc_stats); |
626 | kfree(adapter->stats_reset_data); | 622 | kfree(adapter->stats_reset_data); |
627 | kfree(adapter); | 623 | kfree(adapter); |
624 | put_device(&cdev->dev); | ||
628 | } | 625 | } |
629 | 626 | ||
630 | static void zfcp_sysfs_port_release(struct device *dev) | 627 | /** |
628 | * zfcp_device_unregister - remove port, unit from system | ||
629 | * @dev: reference to device which is to be removed | ||
630 | * @grp: related reference to attribute group | ||
631 | * | ||
632 | * Helper function to unregister port, unit from system | ||
633 | */ | ||
634 | void zfcp_device_unregister(struct device *dev, | ||
635 | const struct attribute_group *grp) | ||
631 | { | 636 | { |
632 | kfree(container_of(dev, struct zfcp_port, sysfs_device)); | 637 | sysfs_remove_group(&dev->kobj, grp); |
638 | device_unregister(dev); | ||
639 | } | ||
640 | |||
641 | static void zfcp_port_release(struct device *dev) | ||
642 | { | ||
643 | struct zfcp_port *port = container_of(dev, struct zfcp_port, | ||
644 | sysfs_device); | ||
645 | |||
646 | zfcp_ccw_adapter_put(port->adapter); | ||
647 | kfree(port); | ||
633 | } | 648 | } |
634 | 649 | ||
635 | /** | 650 | /** |
@@ -639,7 +654,6 @@ static void zfcp_sysfs_port_release(struct device *dev) | |||
639 | * @status: initial status for the port | 654 | * @status: initial status for the port |
640 | * @d_id: destination id of the remote port to be enqueued | 655 | * @d_id: destination id of the remote port to be enqueued |
641 | * Returns: pointer to enqueued port on success, ERR_PTR on error | 656 | * Returns: pointer to enqueued port on success, ERR_PTR on error |
642 | * Locks: config_mutex must be held to serialize changes to the port list | ||
643 | * | 657 | * |
644 | * All port internal structures are set up and the sysfs entry is generated. | 658 | * All port internal structures are set up and the sysfs entry is generated. |
645 | * d_id is used to enqueue ports with a well known address like the Directory | 659 | * d_id is used to enqueue ports with a well known address like the Directory |
@@ -649,20 +663,24 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, | |||
649 | u32 status, u32 d_id) | 663 | u32 status, u32 d_id) |
650 | { | 664 | { |
651 | struct zfcp_port *port; | 665 | struct zfcp_port *port; |
666 | int retval = -ENOMEM; | ||
652 | 667 | ||
653 | read_lock_irq(&zfcp_data.config_lock); | 668 | kref_get(&adapter->ref); |
654 | if (zfcp_get_port_by_wwpn(adapter, wwpn)) { | 669 | |
655 | read_unlock_irq(&zfcp_data.config_lock); | 670 | port = zfcp_get_port_by_wwpn(adapter, wwpn); |
656 | return ERR_PTR(-EINVAL); | 671 | if (port) { |
672 | put_device(&port->sysfs_device); | ||
673 | retval = -EEXIST; | ||
674 | goto err_out; | ||
657 | } | 675 | } |
658 | read_unlock_irq(&zfcp_data.config_lock); | ||
659 | 676 | ||
660 | port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); | 677 | port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); |
661 | if (!port) | 678 | if (!port) |
662 | return ERR_PTR(-ENOMEM); | 679 | goto err_out; |
680 | |||
681 | rwlock_init(&port->unit_list_lock); | ||
682 | INIT_LIST_HEAD(&port->unit_list); | ||
663 | 683 | ||
664 | init_waitqueue_head(&port->remove_wq); | ||
665 | INIT_LIST_HEAD(&port->unit_list_head); | ||
666 | INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup); | 684 | INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup); |
667 | INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); | 685 | INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); |
668 | INIT_WORK(&port->rport_work, zfcp_scsi_rport_work); | 686 | INIT_WORK(&port->rport_work, zfcp_scsi_rport_work); |
@@ -671,58 +689,38 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, | |||
671 | port->d_id = d_id; | 689 | port->d_id = d_id; |
672 | port->wwpn = wwpn; | 690 | port->wwpn = wwpn; |
673 | port->rport_task = RPORT_NONE; | 691 | port->rport_task = RPORT_NONE; |
674 | 692 | port->sysfs_device.parent = &adapter->ccw_device->dev; | |
675 | /* mark port unusable as long as sysfs registration is not complete */ | 693 | port->sysfs_device.release = zfcp_port_release; |
676 | atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); | ||
677 | atomic_set(&port->refcount, 0); | ||
678 | 694 | ||
679 | if (dev_set_name(&port->sysfs_device, "0x%016llx", | 695 | if (dev_set_name(&port->sysfs_device, "0x%016llx", |
680 | (unsigned long long)wwpn)) { | 696 | (unsigned long long)wwpn)) { |
681 | kfree(port); | 697 | kfree(port); |
682 | return ERR_PTR(-ENOMEM); | 698 | goto err_out; |
683 | } | 699 | } |
684 | port->sysfs_device.parent = &adapter->ccw_device->dev; | 700 | retval = -EINVAL; |
685 | port->sysfs_device.release = zfcp_sysfs_port_release; | ||
686 | dev_set_drvdata(&port->sysfs_device, port); | ||
687 | 701 | ||
688 | if (device_register(&port->sysfs_device)) { | 702 | if (device_register(&port->sysfs_device)) { |
689 | put_device(&port->sysfs_device); | 703 | put_device(&port->sysfs_device); |
690 | return ERR_PTR(-EINVAL); | 704 | goto err_out; |
691 | } | 705 | } |
692 | 706 | ||
693 | if (sysfs_create_group(&port->sysfs_device.kobj, | 707 | if (sysfs_create_group(&port->sysfs_device.kobj, |
694 | &zfcp_sysfs_port_attrs)) { | 708 | &zfcp_sysfs_port_attrs)) |
695 | device_unregister(&port->sysfs_device); | 709 | goto err_out_put; |
696 | return ERR_PTR(-EINVAL); | ||
697 | } | ||
698 | 710 | ||
699 | zfcp_port_get(port); | 711 | write_lock_irq(&adapter->port_list_lock); |
712 | list_add_tail(&port->list, &adapter->port_list); | ||
713 | write_unlock_irq(&adapter->port_list_lock); | ||
700 | 714 | ||
701 | write_lock_irq(&zfcp_data.config_lock); | 715 | atomic_set_mask(status | ZFCP_STATUS_COMMON_RUNNING, &port->status); |
702 | list_add_tail(&port->list, &adapter->port_list_head); | ||
703 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); | ||
704 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status); | ||
705 | 716 | ||
706 | write_unlock_irq(&zfcp_data.config_lock); | ||
707 | |||
708 | zfcp_adapter_get(adapter); | ||
709 | return port; | 717 | return port; |
710 | } | ||
711 | 718 | ||
712 | /** | 719 | err_out_put: |
713 | * zfcp_port_dequeue - dequeues a port from the port list of the adapter | ||
714 | * @port: pointer to struct zfcp_port which should be removed | ||
715 | */ | ||
716 | void zfcp_port_dequeue(struct zfcp_port *port) | ||
717 | { | ||
718 | write_lock_irq(&zfcp_data.config_lock); | ||
719 | list_del(&port->list); | ||
720 | write_unlock_irq(&zfcp_data.config_lock); | ||
721 | wait_event(port->remove_wq, atomic_read(&port->refcount) == 0); | ||
722 | cancel_work_sync(&port->rport_work); /* usually not necessary */ | ||
723 | zfcp_adapter_put(port->adapter); | ||
724 | sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs); | ||
725 | device_unregister(&port->sysfs_device); | 720 | device_unregister(&port->sysfs_device); |
721 | err_out: | ||
722 | zfcp_ccw_adapter_put(adapter); | ||
723 | return ERR_PTR(retval); | ||
726 | } | 724 | } |
727 | 725 | ||
728 | /** | 726 | /** |