diff options
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 231 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ccw.c | 16 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_cfdc.c | 5 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.c | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 53 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 20 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 6 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.c | 42 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 12 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 23 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_sysfs.c | 44 |
11 files changed, 196 insertions, 258 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 883e13948ace..8492ceac1409 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c | |||
@@ -96,13 +96,12 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) | |||
96 | adapter = dev_get_drvdata(&ccwdev->dev); | 96 | adapter = dev_get_drvdata(&ccwdev->dev); |
97 | if (!adapter) | 97 | if (!adapter) |
98 | goto out_unlock; | 98 | goto out_unlock; |
99 | zfcp_adapter_get(adapter); | 99 | kref_get(&adapter->ref); |
100 | 100 | ||
101 | port = zfcp_get_port_by_wwpn(adapter, wwpn); | 101 | port = zfcp_get_port_by_wwpn(adapter, wwpn); |
102 | if (!port) | 102 | if (!port) |
103 | goto out_port; | 103 | goto out_port; |
104 | 104 | ||
105 | zfcp_port_get(port); | ||
106 | unit = zfcp_unit_enqueue(port, lun); | 105 | unit = zfcp_unit_enqueue(port, lun); |
107 | if (IS_ERR(unit)) | 106 | if (IS_ERR(unit)) |
108 | goto out_unit; | 107 | goto out_unit; |
@@ -113,11 +112,10 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) | |||
113 | flush_work(&unit->scsi_work); | 112 | flush_work(&unit->scsi_work); |
114 | 113 | ||
115 | mutex_lock(&zfcp_data.config_mutex); | 114 | mutex_lock(&zfcp_data.config_mutex); |
116 | zfcp_unit_put(unit); | ||
117 | out_unit: | 115 | out_unit: |
118 | zfcp_port_put(port); | 116 | put_device(&port->sysfs_device); |
119 | out_port: | 117 | out_port: |
120 | zfcp_adapter_put(adapter); | 118 | kref_put(&adapter->ref, zfcp_adapter_release); |
121 | out_unlock: | 119 | out_unlock: |
122 | mutex_unlock(&zfcp_data.config_mutex); | 120 | mutex_unlock(&zfcp_data.config_mutex); |
123 | out_ccwdev: | 121 | out_ccwdev: |
@@ -244,7 +242,7 @@ struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *port, u64 fcp_lun) | |||
244 | list_for_each_entry(unit, &port->unit_list, list) | 242 | list_for_each_entry(unit, &port->unit_list, list) |
245 | if ((unit->fcp_lun == fcp_lun) && | 243 | if ((unit->fcp_lun == fcp_lun) && |
246 | !(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE)) { | 244 | !(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_REMOVE)) { |
247 | zfcp_unit_get(unit); | 245 | get_device(&unit->sysfs_device); |
248 | read_unlock_irqrestore(&port->unit_list_lock, flags); | 246 | read_unlock_irqrestore(&port->unit_list_lock, flags); |
249 | return unit; | 247 | return unit; |
250 | } | 248 | } |
@@ -269,7 +267,7 @@ struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, | |||
269 | list_for_each_entry(port, &adapter->port_list, list) | 267 | list_for_each_entry(port, &adapter->port_list, list) |
270 | if ((port->wwpn == wwpn) && | 268 | if ((port->wwpn == wwpn) && |
271 | !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE)) { | 269 | !(atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE)) { |
272 | zfcp_port_get(port); | 270 | get_device(&port->sysfs_device); |
273 | read_unlock_irqrestore(&adapter->port_list_lock, flags); | 271 | read_unlock_irqrestore(&adapter->port_list_lock, flags); |
274 | return port; | 272 | return port; |
275 | } | 273 | } |
@@ -277,9 +275,20 @@ struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *adapter, | |||
277 | return NULL; | 275 | return NULL; |
278 | } | 276 | } |
279 | 277 | ||
280 | static void zfcp_sysfs_unit_release(struct device *dev) | 278 | /** |
279 | * zfcp_unit_release - dequeue unit | ||
280 | * @dev: pointer to device | ||
281 | * | ||
282 | * waits until all work is done on unit and removes it then from the unit->list | ||
283 | * of the associated port. | ||
284 | */ | ||
285 | static void zfcp_unit_release(struct device *dev) | ||
281 | { | 286 | { |
282 | kfree(container_of(dev, struct zfcp_unit, sysfs_device)); | 287 | struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, |
288 | sysfs_device); | ||
289 | |||
290 | put_device(&unit->port->sysfs_device); | ||
291 | kfree(unit); | ||
283 | } | 292 | } |
284 | 293 | ||
285 | /** | 294 | /** |
@@ -294,36 +303,39 @@ static void zfcp_sysfs_unit_release(struct device *dev) | |||
294 | struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) | 303 | struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) |
295 | { | 304 | { |
296 | struct zfcp_unit *unit; | 305 | struct zfcp_unit *unit; |
306 | int retval = -ENOMEM; | ||
307 | |||
308 | get_device(&port->sysfs_device); | ||
297 | 309 | ||
298 | unit = zfcp_get_unit_by_lun(port, fcp_lun); | 310 | unit = zfcp_get_unit_by_lun(port, fcp_lun); |
299 | if (unit) { | 311 | if (unit) { |
300 | zfcp_unit_put(unit); | 312 | put_device(&unit->sysfs_device); |
301 | return ERR_PTR(-EINVAL); | 313 | retval = -EEXIST; |
314 | goto err_out; | ||
302 | } | 315 | } |
303 | 316 | ||
304 | unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); | 317 | unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL); |
305 | if (!unit) | 318 | if (!unit) |
306 | return ERR_PTR(-ENOMEM); | 319 | goto err_out; |
307 | |||
308 | atomic_set(&unit->refcount, 0); | ||
309 | init_waitqueue_head(&unit->remove_wq); | ||
310 | INIT_WORK(&unit->scsi_work, zfcp_scsi_scan); | ||
311 | 320 | ||
312 | unit->port = port; | 321 | unit->port = port; |
313 | unit->fcp_lun = fcp_lun; | 322 | unit->fcp_lun = fcp_lun; |
323 | unit->sysfs_device.parent = &port->sysfs_device; | ||
324 | unit->sysfs_device.release = zfcp_unit_release; | ||
314 | 325 | ||
315 | if (dev_set_name(&unit->sysfs_device, "0x%016llx", | 326 | if (dev_set_name(&unit->sysfs_device, "0x%016llx", |
316 | (unsigned long long) fcp_lun)) { | 327 | (unsigned long long) fcp_lun)) { |
317 | kfree(unit); | 328 | kfree(unit); |
318 | return ERR_PTR(-ENOMEM); | 329 | goto err_out; |
319 | } | 330 | } |
320 | unit->sysfs_device.parent = &port->sysfs_device; | ||
321 | unit->sysfs_device.release = zfcp_sysfs_unit_release; | ||
322 | dev_set_drvdata(&unit->sysfs_device, unit); | 331 | dev_set_drvdata(&unit->sysfs_device, unit); |
332 | retval = -EINVAL; | ||
323 | 333 | ||
324 | /* mark unit unusable as long as sysfs registration is not complete */ | 334 | /* mark unit unusable as long as sysfs registration is not complete */ |
325 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | 335 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); |
326 | 336 | ||
337 | INIT_WORK(&unit->scsi_work, zfcp_scsi_scan); | ||
338 | |||
327 | spin_lock_init(&unit->latencies.lock); | 339 | spin_lock_init(&unit->latencies.lock); |
328 | unit->latencies.write.channel.min = 0xFFFFFFFF; | 340 | unit->latencies.write.channel.min = 0xFFFFFFFF; |
329 | unit->latencies.write.fabric.min = 0xFFFFFFFF; | 341 | unit->latencies.write.fabric.min = 0xFFFFFFFF; |
@@ -334,16 +346,12 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) | |||
334 | 346 | ||
335 | if (device_register(&unit->sysfs_device)) { | 347 | if (device_register(&unit->sysfs_device)) { |
336 | put_device(&unit->sysfs_device); | 348 | put_device(&unit->sysfs_device); |
337 | return ERR_PTR(-EINVAL); | 349 | goto err_out; |
338 | } | 350 | } |
339 | 351 | ||
340 | if (sysfs_create_group(&unit->sysfs_device.kobj, | 352 | if (sysfs_create_group(&unit->sysfs_device.kobj, |
341 | &zfcp_sysfs_unit_attrs)) { | 353 | &zfcp_sysfs_unit_attrs)) |
342 | device_unregister(&unit->sysfs_device); | 354 | goto err_out_put; |
343 | return ERR_PTR(-EINVAL); | ||
344 | } | ||
345 | |||
346 | zfcp_unit_get(unit); | ||
347 | 355 | ||
348 | write_lock_irq(&port->unit_list_lock); | 356 | write_lock_irq(&port->unit_list_lock); |
349 | list_add_tail(&unit->list, &port->unit_list); | 357 | list_add_tail(&unit->list, &port->unit_list); |
@@ -352,27 +360,13 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) | |||
352 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | 360 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); |
353 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); | 361 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status); |
354 | 362 | ||
355 | zfcp_port_get(port); | ||
356 | |||
357 | return unit; | 363 | return unit; |
358 | } | ||
359 | |||
360 | /** | ||
361 | * zfcp_unit_dequeue - dequeue unit | ||
362 | * @unit: pointer to zfcp_unit | ||
363 | * | ||
364 | * waits until all work is done on unit and removes it then from the unit->list | ||
365 | * of the associated port. | ||
366 | */ | ||
367 | void zfcp_unit_dequeue(struct zfcp_unit *unit) | ||
368 | { | ||
369 | struct zfcp_port *port = unit->port; | ||
370 | 364 | ||
371 | wait_event(unit->remove_wq, atomic_read(&unit->refcount) == 0); | 365 | err_out_put: |
372 | list_del(&unit->list); /* no list locking required */ | ||
373 | zfcp_port_put(port); | ||
374 | sysfs_remove_group(&unit->sysfs_device.kobj, &zfcp_sysfs_unit_attrs); | ||
375 | device_unregister(&unit->sysfs_device); | 366 | device_unregister(&unit->sysfs_device); |
367 | err_out: | ||
368 | put_device(&port->sysfs_device); | ||
369 | return ERR_PTR(retval); | ||
376 | } | 370 | } |
377 | 371 | ||
378 | static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) | 372 | static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter) |
@@ -518,41 +512,44 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
518 | { | 512 | { |
519 | struct zfcp_adapter *adapter; | 513 | struct zfcp_adapter *adapter; |
520 | 514 | ||
521 | /* | 515 | if (!get_device(&ccw_device->dev)) |
522 | * Note: It is safe to release the list_lock, as any list changes | 516 | return -ENODEV; |
523 | * are protected by the config_mutex, which must be held to get here | ||
524 | */ | ||
525 | 517 | ||
526 | adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL); | 518 | adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL); |
527 | if (!adapter) | 519 | if (!adapter) { |
520 | put_device(&ccw_device->dev); | ||
528 | return -ENOMEM; | 521 | return -ENOMEM; |
522 | } | ||
523 | |||
524 | kref_init(&adapter->ref); | ||
529 | 525 | ||
530 | ccw_device->handler = NULL; | 526 | ccw_device->handler = NULL; |
531 | adapter->ccw_device = ccw_device; | 527 | adapter->ccw_device = ccw_device; |
532 | atomic_set(&adapter->refcount, 0); | 528 | |
529 | INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); | ||
530 | INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later); | ||
533 | 531 | ||
534 | if (zfcp_qdio_setup(adapter)) | 532 | if (zfcp_qdio_setup(adapter)) |
535 | goto qdio_failed; | 533 | goto failed; |
536 | 534 | ||
537 | if (zfcp_allocate_low_mem_buffers(adapter)) | 535 | if (zfcp_allocate_low_mem_buffers(adapter)) |
538 | goto low_mem_buffers_failed; | 536 | goto failed; |
539 | 537 | ||
540 | if (zfcp_reqlist_alloc(adapter)) | 538 | if (zfcp_reqlist_alloc(adapter)) |
541 | goto low_mem_buffers_failed; | 539 | goto failed; |
542 | 540 | ||
543 | if (zfcp_dbf_adapter_register(adapter)) | 541 | if (zfcp_dbf_adapter_register(adapter)) |
544 | goto debug_register_failed; | 542 | goto failed; |
545 | 543 | ||
546 | if (zfcp_setup_adapter_work_queue(adapter)) | 544 | if (zfcp_setup_adapter_work_queue(adapter)) |
547 | goto work_queue_failed; | 545 | goto failed; |
548 | 546 | ||
549 | if (zfcp_fc_gs_setup(adapter)) | 547 | if (zfcp_fc_gs_setup(adapter)) |
550 | goto generic_services_failed; | 548 | goto failed; |
551 | 549 | ||
552 | rwlock_init(&adapter->port_list_lock); | 550 | rwlock_init(&adapter->port_list_lock); |
553 | INIT_LIST_HEAD(&adapter->port_list); | 551 | INIT_LIST_HEAD(&adapter->port_list); |
554 | 552 | ||
555 | init_waitqueue_head(&adapter->remove_wq); | ||
556 | init_waitqueue_head(&adapter->erp_ready_wq); | 553 | init_waitqueue_head(&adapter->erp_ready_wq); |
557 | init_waitqueue_head(&adapter->erp_done_wqh); | 554 | init_waitqueue_head(&adapter->erp_done_wqh); |
558 | 555 | ||
@@ -565,10 +562,7 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
565 | rwlock_init(&adapter->abort_lock); | 562 | rwlock_init(&adapter->abort_lock); |
566 | 563 | ||
567 | if (zfcp_erp_thread_setup(adapter)) | 564 | if (zfcp_erp_thread_setup(adapter)) |
568 | goto erp_thread_failed; | 565 | goto failed; |
569 | |||
570 | INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); | ||
571 | INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later); | ||
572 | 566 | ||
573 | adapter->service_level.seq_print = zfcp_print_sl; | 567 | adapter->service_level.seq_print = zfcp_print_sl; |
574 | 568 | ||
@@ -579,54 +573,37 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) | |||
579 | 573 | ||
580 | if (sysfs_create_group(&ccw_device->dev.kobj, | 574 | if (sysfs_create_group(&ccw_device->dev.kobj, |
581 | &zfcp_sysfs_adapter_attrs)) | 575 | &zfcp_sysfs_adapter_attrs)) |
582 | goto sysfs_failed; | 576 | goto failed; |
583 | 577 | ||
584 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); | 578 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); |
585 | 579 | ||
586 | if (!zfcp_adapter_scsi_register(adapter)) | 580 | if (!zfcp_adapter_scsi_register(adapter)) |
587 | return 0; | 581 | return 0; |
588 | 582 | ||
589 | sysfs_failed: | 583 | failed: |
590 | zfcp_erp_thread_kill(adapter); | 584 | kref_put(&adapter->ref, zfcp_adapter_release); |
591 | erp_thread_failed: | ||
592 | zfcp_fc_gs_destroy(adapter); | ||
593 | generic_services_failed: | ||
594 | zfcp_destroy_adapter_work_queue(adapter); | ||
595 | work_queue_failed: | ||
596 | zfcp_dbf_adapter_unregister(adapter->dbf); | ||
597 | debug_register_failed: | ||
598 | dev_set_drvdata(&ccw_device->dev, NULL); | ||
599 | kfree(adapter->req_list); | ||
600 | low_mem_buffers_failed: | ||
601 | zfcp_free_low_mem_buffers(adapter); | ||
602 | qdio_failed: | ||
603 | zfcp_qdio_destroy(adapter->qdio); | ||
604 | kfree(adapter); | ||
605 | return -ENOMEM; | 585 | return -ENOMEM; |
606 | } | 586 | } |
607 | 587 | ||
608 | /** | 588 | /** |
609 | * zfcp_adapter_dequeue - remove the adapter from the resource list | 589 | * zfcp_adapter_release - remove the adapter from the resource list |
610 | * @adapter: pointer to struct zfcp_adapter which should be removed | 590 | * @ref: pointer to struct kref |
611 | * locks: adapter list write lock is assumed to be held by caller | 591 | * locks: adapter list write lock is assumed to be held by caller |
612 | */ | 592 | */ |
613 | void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | 593 | void zfcp_adapter_release(struct kref *ref) |
614 | { | 594 | { |
615 | int retval = 0; | 595 | struct zfcp_adapter *adapter = container_of(ref, struct zfcp_adapter, |
616 | unsigned long flags; | 596 | ref); |
597 | struct ccw_device *ccw_device = adapter->ccw_device; | ||
617 | 598 | ||
618 | cancel_work_sync(&adapter->stat_work); | 599 | cancel_work_sync(&adapter->stat_work); |
600 | |||
619 | zfcp_fc_wka_ports_force_offline(adapter->gs); | 601 | zfcp_fc_wka_ports_force_offline(adapter->gs); |
620 | sysfs_remove_group(&adapter->ccw_device->dev.kobj, | 602 | sysfs_remove_group(&ccw_device->dev.kobj, &zfcp_sysfs_adapter_attrs); |
621 | &zfcp_sysfs_adapter_attrs); | 603 | |
622 | dev_set_drvdata(&adapter->ccw_device->dev, NULL); | 604 | dev_set_drvdata(&ccw_device->dev, NULL); |
623 | /* sanity check: no pending FSF requests */ | ||
624 | spin_lock_irqsave(&adapter->req_list_lock, flags); | ||
625 | retval = zfcp_reqlist_isempty(adapter); | ||
626 | spin_unlock_irqrestore(&adapter->req_list_lock, flags); | ||
627 | if (!retval) | ||
628 | return; | ||
629 | 605 | ||
606 | dev_set_drvdata(&adapter->ccw_device->dev, NULL); | ||
630 | zfcp_fc_gs_destroy(adapter); | 607 | zfcp_fc_gs_destroy(adapter); |
631 | zfcp_erp_thread_kill(adapter); | 608 | zfcp_erp_thread_kill(adapter); |
632 | zfcp_destroy_adapter_work_queue(adapter); | 609 | zfcp_destroy_adapter_work_queue(adapter); |
@@ -637,11 +614,30 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) | |||
637 | kfree(adapter->fc_stats); | 614 | kfree(adapter->fc_stats); |
638 | kfree(adapter->stats_reset_data); | 615 | kfree(adapter->stats_reset_data); |
639 | kfree(adapter); | 616 | kfree(adapter); |
617 | put_device(&ccw_device->dev); | ||
618 | } | ||
619 | |||
620 | /** | ||
621 | * zfcp_device_unregister - remove port, unit from system | ||
622 | * @dev: reference to device which is to be removed | ||
623 | * @grp: related reference to attribute group | ||
624 | * | ||
625 | * Helper function to unregister port, unit from system | ||
626 | */ | ||
627 | void zfcp_device_unregister(struct device *dev, | ||
628 | const struct attribute_group *grp) | ||
629 | { | ||
630 | sysfs_remove_group(&dev->kobj, grp); | ||
631 | device_unregister(dev); | ||
640 | } | 632 | } |
641 | 633 | ||
642 | static void zfcp_sysfs_port_release(struct device *dev) | 634 | static void zfcp_port_release(struct device *dev) |
643 | { | 635 | { |
644 | kfree(container_of(dev, struct zfcp_port, sysfs_device)); | 636 | struct zfcp_port *port = container_of(dev, struct zfcp_port, |
637 | sysfs_device); | ||
638 | |||
639 | kref_put(&port->adapter->ref, zfcp_adapter_release); | ||
640 | kfree(port); | ||
645 | } | 641 | } |
646 | 642 | ||
647 | /** | 643 | /** |
@@ -661,21 +657,24 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, | |||
661 | u32 status, u32 d_id) | 657 | u32 status, u32 d_id) |
662 | { | 658 | { |
663 | struct zfcp_port *port; | 659 | struct zfcp_port *port; |
660 | int retval = -ENOMEM; | ||
661 | |||
662 | kref_get(&adapter->ref); | ||
664 | 663 | ||
665 | port = zfcp_get_port_by_wwpn(adapter, wwpn); | 664 | port = zfcp_get_port_by_wwpn(adapter, wwpn); |
666 | if (port) { | 665 | if (port) { |
667 | zfcp_port_put(port); | 666 | put_device(&port->sysfs_device); |
668 | return ERR_PTR(-EEXIST); | 667 | retval = -EEXIST; |
668 | goto err_out; | ||
669 | } | 669 | } |
670 | 670 | ||
671 | port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); | 671 | port = kzalloc(sizeof(struct zfcp_port), GFP_KERNEL); |
672 | if (!port) | 672 | if (!port) |
673 | return ERR_PTR(-ENOMEM); | 673 | goto err_out; |
674 | 674 | ||
675 | rwlock_init(&port->unit_list_lock); | 675 | rwlock_init(&port->unit_list_lock); |
676 | INIT_LIST_HEAD(&port->unit_list); | 676 | INIT_LIST_HEAD(&port->unit_list); |
677 | 677 | ||
678 | init_waitqueue_head(&port->remove_wq); | ||
679 | INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup); | 678 | INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup); |
680 | INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); | 679 | INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work); |
681 | INIT_WORK(&port->rport_work, zfcp_scsi_rport_work); | 680 | INIT_WORK(&port->rport_work, zfcp_scsi_rport_work); |
@@ -684,32 +683,28 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, | |||
684 | port->d_id = d_id; | 683 | port->d_id = d_id; |
685 | port->wwpn = wwpn; | 684 | port->wwpn = wwpn; |
686 | port->rport_task = RPORT_NONE; | 685 | port->rport_task = RPORT_NONE; |
686 | port->sysfs_device.parent = &adapter->ccw_device->dev; | ||
687 | port->sysfs_device.release = zfcp_port_release; | ||
687 | 688 | ||
688 | /* mark port unusable as long as sysfs registration is not complete */ | 689 | /* mark port unusable as long as sysfs registration is not complete */ |
689 | atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); | 690 | atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); |
690 | atomic_set(&port->refcount, 0); | ||
691 | 691 | ||
692 | if (dev_set_name(&port->sysfs_device, "0x%016llx", | 692 | if (dev_set_name(&port->sysfs_device, "0x%016llx", |
693 | (unsigned long long)wwpn)) { | 693 | (unsigned long long)wwpn)) { |
694 | kfree(port); | 694 | kfree(port); |
695 | return ERR_PTR(-ENOMEM); | 695 | goto err_out; |
696 | } | 696 | } |
697 | port->sysfs_device.parent = &adapter->ccw_device->dev; | ||
698 | port->sysfs_device.release = zfcp_sysfs_port_release; | ||
699 | dev_set_drvdata(&port->sysfs_device, port); | 697 | dev_set_drvdata(&port->sysfs_device, port); |
698 | retval = -EINVAL; | ||
700 | 699 | ||
701 | if (device_register(&port->sysfs_device)) { | 700 | if (device_register(&port->sysfs_device)) { |
702 | put_device(&port->sysfs_device); | 701 | put_device(&port->sysfs_device); |
703 | return ERR_PTR(-EINVAL); | 702 | goto err_out; |
704 | } | 703 | } |
705 | 704 | ||
706 | if (sysfs_create_group(&port->sysfs_device.kobj, | 705 | if (sysfs_create_group(&port->sysfs_device.kobj, |
707 | &zfcp_sysfs_port_attrs)) { | 706 | &zfcp_sysfs_port_attrs)) |
708 | device_unregister(&port->sysfs_device); | 707 | goto err_out_put; |
709 | return ERR_PTR(-EINVAL); | ||
710 | } | ||
711 | |||
712 | zfcp_port_get(port); | ||
713 | 708 | ||
714 | write_lock_irq(&adapter->port_list_lock); | 709 | write_lock_irq(&adapter->port_list_lock); |
715 | list_add_tail(&port->list, &adapter->port_list); | 710 | list_add_tail(&port->list, &adapter->port_list); |
@@ -718,23 +713,13 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, | |||
718 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); | 713 | atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); |
719 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status); | 714 | atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status); |
720 | 715 | ||
721 | zfcp_adapter_get(adapter); | ||
722 | return port; | 716 | return port; |
723 | } | ||
724 | 717 | ||
725 | /** | 718 | err_out_put: |
726 | * zfcp_port_dequeue - dequeues a port from the port list of the adapter | ||
727 | * @port: pointer to struct zfcp_port which should be removed | ||
728 | */ | ||
729 | void zfcp_port_dequeue(struct zfcp_port *port) | ||
730 | { | ||
731 | struct zfcp_adapter *adapter = port->adapter; | ||
732 | |||
733 | list_del(&port->list); /* no list locking required here */ | ||
734 | wait_event(port->remove_wq, atomic_read(&port->refcount) == 0); | ||
735 | zfcp_adapter_put(adapter); | ||
736 | sysfs_remove_group(&port->sysfs_device.kobj, &zfcp_sysfs_port_attrs); | ||
737 | device_unregister(&port->sysfs_device); | 719 | device_unregister(&port->sysfs_device); |
720 | err_out: | ||
721 | kref_put(&adapter->ref, zfcp_adapter_release); | ||
722 | return ERR_PTR(retval); | ||
738 | } | 723 | } |
739 | 724 | ||
740 | /** | 725 | /** |
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index aca2047dc2d5..c89dbe250377 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c | |||
@@ -128,13 +128,15 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) | |||
128 | write_unlock_irq(&adapter->port_list_lock); | 128 | write_unlock_irq(&adapter->port_list_lock); |
129 | mutex_unlock(&zfcp_data.config_mutex); | 129 | mutex_unlock(&zfcp_data.config_mutex); |
130 | 130 | ||
131 | list_for_each_entry_safe(port, p, &port_remove_lh, list) { | 131 | list_for_each_entry_safe(unit, u, &unit_remove_lh, list) |
132 | list_for_each_entry_safe(unit, u, &unit_remove_lh, list) | 132 | zfcp_device_unregister(&unit->sysfs_device, |
133 | zfcp_unit_dequeue(unit); | 133 | &zfcp_sysfs_unit_attrs); |
134 | zfcp_port_dequeue(port); | 134 | |
135 | } | 135 | list_for_each_entry_safe(port, p, &port_remove_lh, list) |
136 | wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); | 136 | zfcp_device_unregister(&port->sysfs_device, |
137 | zfcp_adapter_dequeue(adapter); | 137 | &zfcp_sysfs_port_attrs); |
138 | |||
139 | kref_put(&adapter->ref, zfcp_adapter_release); | ||
138 | } | 140 | } |
139 | 141 | ||
140 | /** | 142 | /** |
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index ef681dfed0cc..856f82dbcb1b 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c | |||
@@ -98,7 +98,7 @@ static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno) | |||
98 | if (!adapter) | 98 | if (!adapter) |
99 | goto out_put; | 99 | goto out_put; |
100 | 100 | ||
101 | zfcp_adapter_get(adapter); | 101 | kref_get(&adapter->ref); |
102 | out_put: | 102 | out_put: |
103 | put_device(&ccwdev->dev); | 103 | put_device(&ccwdev->dev); |
104 | out: | 104 | out: |
@@ -212,7 +212,6 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, | |||
212 | retval = -ENXIO; | 212 | retval = -ENXIO; |
213 | goto free_buffer; | 213 | goto free_buffer; |
214 | } | 214 | } |
215 | zfcp_adapter_get(adapter); | ||
216 | 215 | ||
217 | retval = zfcp_cfdc_sg_setup(data->command, fsf_cfdc->sg, | 216 | retval = zfcp_cfdc_sg_setup(data->command, fsf_cfdc->sg, |
218 | data_user->control_file); | 217 | data_user->control_file); |
@@ -245,7 +244,7 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, | |||
245 | free_sg: | 244 | free_sg: |
246 | zfcp_sg_free_table(fsf_cfdc->sg, ZFCP_CFDC_PAGES); | 245 | zfcp_sg_free_table(fsf_cfdc->sg, ZFCP_CFDC_PAGES); |
247 | adapter_put: | 246 | adapter_put: |
248 | zfcp_adapter_put(adapter); | 247 | kref_put(&adapter->ref, zfcp_adapter_release); |
249 | free_buffer: | 248 | free_buffer: |
250 | kfree(data); | 249 | kfree(data); |
251 | no_mem_sense: | 250 | no_mem_sense: |
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 215b70749e95..fe818cd29dc1 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c | |||
@@ -1067,6 +1067,8 @@ err_out: | |||
1067 | */ | 1067 | */ |
1068 | void zfcp_dbf_adapter_unregister(struct zfcp_dbf *dbf) | 1068 | void zfcp_dbf_adapter_unregister(struct zfcp_dbf *dbf) |
1069 | { | 1069 | { |
1070 | if (!dbf) | ||
1071 | return; | ||
1070 | debug_unregister(dbf->scsi); | 1072 | debug_unregister(dbf->scsi); |
1071 | debug_unregister(dbf->san); | 1073 | debug_unregister(dbf->san); |
1072 | debug_unregister(dbf->hba); | 1074 | debug_unregister(dbf->hba); |
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index e45a08d6c98e..55dc402c3aec 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -446,9 +446,7 @@ struct zfcp_qdio { | |||
446 | }; | 446 | }; |
447 | 447 | ||
448 | struct zfcp_adapter { | 448 | struct zfcp_adapter { |
449 | atomic_t refcount; /* reference count */ | 449 | struct kref ref; |
450 | wait_queue_head_t remove_wq; /* can be used to wait for | ||
451 | refcount drop to zero */ | ||
452 | u64 peer_wwnn; /* P2P peer WWNN */ | 450 | u64 peer_wwnn; /* P2P peer WWNN */ |
453 | u64 peer_wwpn; /* P2P peer WWPN */ | 451 | u64 peer_wwpn; /* P2P peer WWPN */ |
454 | u32 peer_d_id; /* P2P peer D_ID */ | 452 | u32 peer_d_id; /* P2P peer D_ID */ |
@@ -501,9 +499,6 @@ struct zfcp_port { | |||
501 | struct device sysfs_device; /* sysfs device */ | 499 | struct device sysfs_device; /* sysfs device */ |
502 | struct fc_rport *rport; /* rport of fc transport class */ | 500 | struct fc_rport *rport; /* rport of fc transport class */ |
503 | struct list_head list; /* list of remote ports */ | 501 | struct list_head list; /* list of remote ports */ |
504 | atomic_t refcount; /* reference count */ | ||
505 | wait_queue_head_t remove_wq; /* can be used to wait for | ||
506 | refcount drop to zero */ | ||
507 | struct zfcp_adapter *adapter; /* adapter used to access port */ | 502 | struct zfcp_adapter *adapter; /* adapter used to access port */ |
508 | struct list_head unit_list; /* head of logical unit list */ | 503 | struct list_head unit_list; /* head of logical unit list */ |
509 | rwlock_t unit_list_lock; /* unit list lock */ | 504 | rwlock_t unit_list_lock; /* unit list lock */ |
@@ -525,9 +520,6 @@ struct zfcp_port { | |||
525 | struct zfcp_unit { | 520 | struct zfcp_unit { |
526 | struct device sysfs_device; /* sysfs device */ | 521 | struct device sysfs_device; /* sysfs device */ |
527 | struct list_head list; /* list of logical units */ | 522 | struct list_head list; /* list of logical units */ |
528 | atomic_t refcount; /* reference count */ | ||
529 | wait_queue_head_t remove_wq; /* can be used to wait for | ||
530 | refcount drop to zero */ | ||
531 | struct zfcp_port *port; /* remote port of unit */ | 523 | struct zfcp_port *port; /* remote port of unit */ |
532 | atomic_t status; /* status of this logical unit */ | 524 | atomic_t status; /* status of this logical unit */ |
533 | u64 fcp_lun; /* own FCP_LUN */ | 525 | u64 fcp_lun; /* own FCP_LUN */ |
@@ -656,47 +648,4 @@ zfcp_reqlist_find_safe(struct zfcp_adapter *adapter, struct zfcp_fsf_req *req) | |||
656 | return NULL; | 648 | return NULL; |
657 | } | 649 | } |
658 | 650 | ||
659 | /* | ||
660 | * functions needed for reference/usage counting | ||
661 | */ | ||
662 | |||
663 | static inline void | ||
664 | zfcp_unit_get(struct zfcp_unit *unit) | ||
665 | { | ||
666 | atomic_inc(&unit->refcount); | ||
667 | } | ||
668 | |||
669 | static inline void | ||
670 | zfcp_unit_put(struct zfcp_unit *unit) | ||
671 | { | ||
672 | if (atomic_dec_return(&unit->refcount) == 0) | ||
673 | wake_up(&unit->remove_wq); | ||
674 | } | ||
675 | |||
676 | static inline void | ||
677 | zfcp_port_get(struct zfcp_port *port) | ||
678 | { | ||
679 | atomic_inc(&port->refcount); | ||
680 | } | ||
681 | |||
682 | static inline void | ||
683 | zfcp_port_put(struct zfcp_port *port) | ||
684 | { | ||
685 | if (atomic_dec_return(&port->refcount) == 0) | ||
686 | wake_up(&port->remove_wq); | ||
687 | } | ||
688 | |||
689 | static inline void | ||
690 | zfcp_adapter_get(struct zfcp_adapter *adapter) | ||
691 | { | ||
692 | atomic_inc(&adapter->refcount); | ||
693 | } | ||
694 | |||
695 | static inline void | ||
696 | zfcp_adapter_put(struct zfcp_adapter *adapter) | ||
697 | { | ||
698 | if (atomic_dec_return(&adapter->refcount) == 0) | ||
699 | wake_up(&adapter->remove_wq); | ||
700 | } | ||
701 | |||
702 | #endif /* ZFCP_DEF_H */ | 651 | #endif /* ZFCP_DEF_H */ |
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 464f0473877a..788fd3a4cd23 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -174,7 +174,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, | |||
174 | 174 | ||
175 | switch (need) { | 175 | switch (need) { |
176 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | 176 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
177 | zfcp_unit_get(unit); | 177 | get_device(&unit->sysfs_device); |
178 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); | 178 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); |
179 | erp_action = &unit->erp_action; | 179 | erp_action = &unit->erp_action; |
180 | if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING)) | 180 | if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING)) |
@@ -183,7 +183,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, | |||
183 | 183 | ||
184 | case ZFCP_ERP_ACTION_REOPEN_PORT: | 184 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
185 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | 185 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
186 | zfcp_port_get(port); | 186 | get_device(&port->sysfs_device); |
187 | zfcp_erp_action_dismiss_port(port); | 187 | zfcp_erp_action_dismiss_port(port); |
188 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); | 188 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); |
189 | erp_action = &port->erp_action; | 189 | erp_action = &port->erp_action; |
@@ -192,7 +192,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, | |||
192 | break; | 192 | break; |
193 | 193 | ||
194 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 194 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
195 | zfcp_adapter_get(adapter); | 195 | kref_get(&adapter->ref); |
196 | zfcp_erp_action_dismiss_adapter(adapter); | 196 | zfcp_erp_action_dismiss_adapter(adapter); |
197 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); | 197 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); |
198 | erp_action = &adapter->erp_action; | 198 | erp_action = &adapter->erp_action; |
@@ -1177,19 +1177,19 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) | |||
1177 | switch (act->action) { | 1177 | switch (act->action) { |
1178 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | 1178 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
1179 | if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { | 1179 | if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { |
1180 | zfcp_unit_get(unit); | 1180 | get_device(&unit->sysfs_device); |
1181 | if (scsi_queue_work(unit->port->adapter->scsi_host, | 1181 | if (scsi_queue_work(unit->port->adapter->scsi_host, |
1182 | &unit->scsi_work) <= 0) | 1182 | &unit->scsi_work) <= 0) |
1183 | zfcp_unit_put(unit); | 1183 | put_device(&unit->sysfs_device); |
1184 | } | 1184 | } |
1185 | zfcp_unit_put(unit); | 1185 | put_device(&unit->sysfs_device); |
1186 | break; | 1186 | break; |
1187 | 1187 | ||
1188 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: | 1188 | case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: |
1189 | case ZFCP_ERP_ACTION_REOPEN_PORT: | 1189 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
1190 | if (result == ZFCP_ERP_SUCCEEDED) | 1190 | if (result == ZFCP_ERP_SUCCEEDED) |
1191 | zfcp_scsi_schedule_rport_register(port); | 1191 | zfcp_scsi_schedule_rport_register(port); |
1192 | zfcp_port_put(port); | 1192 | put_device(&port->sysfs_device); |
1193 | break; | 1193 | break; |
1194 | 1194 | ||
1195 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 1195 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
@@ -1198,7 +1198,7 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) | |||
1198 | schedule_work(&adapter->scan_work); | 1198 | schedule_work(&adapter->scan_work); |
1199 | } else | 1199 | } else |
1200 | unregister_service_level(&adapter->service_level); | 1200 | unregister_service_level(&adapter->service_level); |
1201 | zfcp_adapter_put(adapter); | 1201 | kref_put(&adapter->ref, zfcp_adapter_release); |
1202 | break; | 1202 | break; |
1203 | } | 1203 | } |
1204 | } | 1204 | } |
@@ -1224,8 +1224,9 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) | |||
1224 | unsigned long flags; | 1224 | unsigned long flags; |
1225 | struct zfcp_adapter *adapter = erp_action->adapter; | 1225 | struct zfcp_adapter *adapter = erp_action->adapter; |
1226 | 1226 | ||
1227 | write_lock_irqsave(&adapter->erp_lock, flags); | 1227 | kref_get(&adapter->ref); |
1228 | 1228 | ||
1229 | write_lock_irqsave(&adapter->erp_lock, flags); | ||
1229 | zfcp_erp_strategy_check_fsfreq(erp_action); | 1230 | zfcp_erp_strategy_check_fsfreq(erp_action); |
1230 | 1231 | ||
1231 | if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { | 1232 | if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { |
@@ -1282,6 +1283,7 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) | |||
1282 | if (retval != ZFCP_ERP_CONTINUES) | 1283 | if (retval != ZFCP_ERP_CONTINUES) |
1283 | zfcp_erp_action_cleanup(erp_action, retval); | 1284 | zfcp_erp_action_cleanup(erp_action, retval); |
1284 | 1285 | ||
1286 | kref_put(&adapter->ref, zfcp_adapter_release); | ||
1285 | return retval; | 1287 | return retval; |
1286 | } | 1288 | } |
1287 | 1289 | ||
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index b3f28deb4505..3106c3be6395 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -15,15 +15,15 @@ | |||
15 | extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, u64); | 15 | extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, u64); |
16 | extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, u64); | 16 | extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, u64); |
17 | extern int zfcp_adapter_enqueue(struct ccw_device *); | 17 | extern int zfcp_adapter_enqueue(struct ccw_device *); |
18 | extern void zfcp_adapter_dequeue(struct zfcp_adapter *); | ||
19 | extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32, | 18 | extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32, |
20 | u32); | 19 | u32); |
21 | extern void zfcp_port_dequeue(struct zfcp_port *); | ||
22 | extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, u64); | 20 | extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, u64); |
23 | extern void zfcp_unit_dequeue(struct zfcp_unit *); | ||
24 | extern int zfcp_reqlist_isempty(struct zfcp_adapter *); | 21 | extern int zfcp_reqlist_isempty(struct zfcp_adapter *); |
25 | extern void zfcp_sg_free_table(struct scatterlist *, int); | 22 | extern void zfcp_sg_free_table(struct scatterlist *, int); |
26 | extern int zfcp_sg_setup_table(struct scatterlist *, int); | 23 | extern int zfcp_sg_setup_table(struct scatterlist *, int); |
24 | extern void zfcp_device_unregister(struct device *, | ||
25 | const struct attribute_group *); | ||
26 | extern void zfcp_adapter_release(struct kref *); | ||
27 | 27 | ||
28 | /* zfcp_ccw.c */ | 28 | /* zfcp_ccw.c */ |
29 | extern int zfcp_ccw_register(void); | 29 | extern int zfcp_ccw_register(void); |
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index c7efdc51df63..6fa1bcbec0a9 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c | |||
@@ -134,6 +134,8 @@ static void zfcp_fc_wka_port_force_offline(struct zfcp_wka_port *wka) | |||
134 | 134 | ||
135 | void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *gs) | 135 | void zfcp_fc_wka_ports_force_offline(struct zfcp_wka_ports *gs) |
136 | { | 136 | { |
137 | if (!gs) | ||
138 | return; | ||
137 | zfcp_fc_wka_port_force_offline(&gs->ms); | 139 | zfcp_fc_wka_port_force_offline(&gs->ms); |
138 | zfcp_fc_wka_port_force_offline(&gs->ts); | 140 | zfcp_fc_wka_port_force_offline(&gs->ts); |
139 | zfcp_fc_wka_port_force_offline(&gs->ds); | 141 | zfcp_fc_wka_port_force_offline(&gs->ds); |
@@ -356,7 +358,7 @@ void zfcp_fc_port_did_lookup(struct work_struct *work) | |||
356 | 358 | ||
357 | zfcp_erp_port_reopen(port, 0, "fcgpn_3", NULL); | 359 | zfcp_erp_port_reopen(port, 0, "fcgpn_3", NULL); |
358 | out: | 360 | out: |
359 | zfcp_port_put(port); | 361 | put_device(&port->sysfs_device); |
360 | } | 362 | } |
361 | 363 | ||
362 | /** | 364 | /** |
@@ -365,9 +367,9 @@ out: | |||
365 | */ | 367 | */ |
366 | void zfcp_fc_trigger_did_lookup(struct zfcp_port *port) | 368 | void zfcp_fc_trigger_did_lookup(struct zfcp_port *port) |
367 | { | 369 | { |
368 | zfcp_port_get(port); | 370 | get_device(&port->sysfs_device); |
369 | if (!queue_work(port->adapter->work_queue, &port->gid_pn_work)) | 371 | if (!queue_work(port->adapter->work_queue, &port->gid_pn_work)) |
370 | zfcp_port_put(port); | 372 | put_device(&port->sysfs_device); |
371 | } | 373 | } |
372 | 374 | ||
373 | /** | 375 | /** |
@@ -426,7 +428,7 @@ static void zfcp_fc_adisc_handler(unsigned long data) | |||
426 | zfcp_scsi_schedule_rport_register(port); | 428 | zfcp_scsi_schedule_rport_register(port); |
427 | out: | 429 | out: |
428 | atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); | 430 | atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); |
429 | zfcp_port_put(port); | 431 | put_device(&port->sysfs_device); |
430 | kfree(adisc); | 432 | kfree(adisc); |
431 | } | 433 | } |
432 | 434 | ||
@@ -468,7 +470,7 @@ void zfcp_fc_link_test_work(struct work_struct *work) | |||
468 | container_of(work, struct zfcp_port, test_link_work); | 470 | container_of(work, struct zfcp_port, test_link_work); |
469 | int retval; | 471 | int retval; |
470 | 472 | ||
471 | zfcp_port_get(port); | 473 | get_device(&port->sysfs_device); |
472 | port->rport_task = RPORT_DEL; | 474 | port->rport_task = RPORT_DEL; |
473 | zfcp_scsi_rport_work(&port->rport_work); | 475 | zfcp_scsi_rport_work(&port->rport_work); |
474 | 476 | ||
@@ -487,7 +489,7 @@ void zfcp_fc_link_test_work(struct work_struct *work) | |||
487 | zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL); | 489 | zfcp_erp_port_forced_reopen(port, 0, "fcltwk1", NULL); |
488 | 490 | ||
489 | out: | 491 | out: |
490 | zfcp_port_put(port); | 492 | put_device(&port->sysfs_device); |
491 | } | 493 | } |
492 | 494 | ||
493 | /** | 495 | /** |
@@ -500,9 +502,9 @@ out: | |||
500 | */ | 502 | */ |
501 | void zfcp_fc_test_link(struct zfcp_port *port) | 503 | void zfcp_fc_test_link(struct zfcp_port *port) |
502 | { | 504 | { |
503 | zfcp_port_get(port); | 505 | get_device(&port->sysfs_device); |
504 | if (!queue_work(port->adapter->work_queue, &port->test_link_work)) | 506 | if (!queue_work(port->adapter->work_queue, &port->test_link_work)) |
505 | zfcp_port_put(port); | 507 | put_device(&port->sysfs_device); |
506 | } | 508 | } |
507 | 509 | ||
508 | static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) | 510 | static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) |
@@ -576,7 +578,7 @@ static int zfcp_fc_send_gpn_ft(struct zfcp_gpn_ft *gpn_ft, | |||
576 | return ret; | 578 | return ret; |
577 | } | 579 | } |
578 | 580 | ||
579 | static void zfcp_fc_validate_port(struct zfcp_port *port) | 581 | static void zfcp_fc_validate_port(struct zfcp_port *port, struct list_head *lh) |
580 | { | 582 | { |
581 | if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC)) | 583 | if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC)) |
582 | return; | 584 | return; |
@@ -584,13 +586,11 @@ static void zfcp_fc_validate_port(struct zfcp_port *port) | |||
584 | atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status); | 586 | atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status); |
585 | 587 | ||
586 | if ((port->supported_classes != 0) || | 588 | if ((port->supported_classes != 0) || |
587 | !list_empty(&port->unit_list)) { | 589 | !list_empty(&port->unit_list)) |
588 | zfcp_port_put(port); | ||
589 | return; | 590 | return; |
590 | } | 591 | |
591 | zfcp_erp_port_shutdown(port, 0, "fcpval1", NULL); | 592 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); |
592 | zfcp_port_put(port); | 593 | list_move_tail(&port->list, lh); |
593 | zfcp_port_dequeue(port); | ||
594 | } | 594 | } |
595 | 595 | ||
596 | static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) | 596 | static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) |
@@ -602,6 +602,7 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) | |||
602 | struct zfcp_adapter *adapter = ct->wka_port->adapter; | 602 | struct zfcp_adapter *adapter = ct->wka_port->adapter; |
603 | struct zfcp_port *port, *tmp; | 603 | struct zfcp_port *port, *tmp; |
604 | unsigned long flags; | 604 | unsigned long flags; |
605 | LIST_HEAD(remove_lh); | ||
605 | u32 d_id; | 606 | u32 d_id; |
606 | int ret = 0, x, last = 0; | 607 | int ret = 0, x, last = 0; |
607 | 608 | ||
@@ -652,9 +653,16 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) | |||
652 | zfcp_erp_wait(adapter); | 653 | zfcp_erp_wait(adapter); |
653 | write_lock_irqsave(&adapter->port_list_lock, flags); | 654 | write_lock_irqsave(&adapter->port_list_lock, flags); |
654 | list_for_each_entry_safe(port, tmp, &adapter->port_list, list) | 655 | list_for_each_entry_safe(port, tmp, &adapter->port_list, list) |
655 | zfcp_fc_validate_port(port); | 656 | zfcp_fc_validate_port(port, &remove_lh); |
656 | write_unlock_irqrestore(&adapter->port_list_lock, flags); | 657 | write_unlock_irqrestore(&adapter->port_list_lock, flags); |
657 | mutex_unlock(&zfcp_data.config_mutex); | 658 | mutex_unlock(&zfcp_data.config_mutex); |
659 | |||
660 | list_for_each_entry_safe(port, tmp, &remove_lh, list) { | ||
661 | zfcp_erp_port_shutdown(port, 0, "fcegpf2", NULL); | ||
662 | zfcp_device_unregister(&port->sysfs_device, | ||
663 | &zfcp_sysfs_port_attrs); | ||
664 | } | ||
665 | |||
658 | return ret; | 666 | return ret; |
659 | } | 667 | } |
660 | 668 | ||
@@ -763,7 +771,7 @@ int zfcp_fc_execute_els_fc_job(struct fc_bsg_job *job) | |||
763 | } | 771 | } |
764 | 772 | ||
765 | els_fc_job->els.d_id = port->d_id; | 773 | els_fc_job->els.d_id = port->d_id; |
766 | zfcp_port_put(port); | 774 | put_device(&port->sysfs_device); |
767 | } else { | 775 | } else { |
768 | port_did = job->request->rqst_data.h_els.port_id; | 776 | port_did = job->request->rqst_data.h_els.port_id; |
769 | els_fc_job->els.d_id = (port_did[0] << 16) + | 777 | els_fc_job->els.d_id = (port_did[0] << 16) + |
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 9df62f686812..3aad70916289 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -1492,7 +1492,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) | |||
1492 | } | 1492 | } |
1493 | 1493 | ||
1494 | out: | 1494 | out: |
1495 | zfcp_port_put(port); | 1495 | put_device(&port->sysfs_device); |
1496 | } | 1496 | } |
1497 | 1497 | ||
1498 | /** | 1498 | /** |
@@ -1530,14 +1530,14 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) | |||
1530 | req->data = port; | 1530 | req->data = port; |
1531 | req->erp_action = erp_action; | 1531 | req->erp_action = erp_action; |
1532 | erp_action->fsf_req = req; | 1532 | erp_action->fsf_req = req; |
1533 | zfcp_port_get(port); | 1533 | get_device(&port->sysfs_device); |
1534 | 1534 | ||
1535 | zfcp_fsf_start_erp_timer(req); | 1535 | zfcp_fsf_start_erp_timer(req); |
1536 | retval = zfcp_fsf_req_send(req); | 1536 | retval = zfcp_fsf_req_send(req); |
1537 | if (retval) { | 1537 | if (retval) { |
1538 | zfcp_fsf_req_free(req); | 1538 | zfcp_fsf_req_free(req); |
1539 | erp_action->fsf_req = NULL; | 1539 | erp_action->fsf_req = NULL; |
1540 | zfcp_port_put(port); | 1540 | put_device(&port->sysfs_device); |
1541 | } | 1541 | } |
1542 | out: | 1542 | out: |
1543 | spin_unlock_bh(&qdio->req_q_lock); | 1543 | spin_unlock_bh(&qdio->req_q_lock); |
@@ -2335,7 +2335,7 @@ skip_fsfstatus: | |||
2335 | else { | 2335 | else { |
2336 | zfcp_fsf_send_fcp_command_task_handler(req); | 2336 | zfcp_fsf_send_fcp_command_task_handler(req); |
2337 | req->unit = NULL; | 2337 | req->unit = NULL; |
2338 | zfcp_unit_put(unit); | 2338 | put_device(&unit->sysfs_device); |
2339 | } | 2339 | } |
2340 | } | 2340 | } |
2341 | 2341 | ||
@@ -2387,7 +2387,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, | |||
2387 | } | 2387 | } |
2388 | 2388 | ||
2389 | req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; | 2389 | req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; |
2390 | zfcp_unit_get(unit); | 2390 | get_device(&unit->sysfs_device); |
2391 | req->unit = unit; | 2391 | req->unit = unit; |
2392 | req->data = scsi_cmnd; | 2392 | req->data = scsi_cmnd; |
2393 | req->handler = zfcp_fsf_send_fcp_command_handler; | 2393 | req->handler = zfcp_fsf_send_fcp_command_handler; |
@@ -2463,7 +2463,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, | |||
2463 | goto out; | 2463 | goto out; |
2464 | 2464 | ||
2465 | failed_scsi_cmnd: | 2465 | failed_scsi_cmnd: |
2466 | zfcp_unit_put(unit); | 2466 | put_device(&unit->sysfs_device); |
2467 | zfcp_fsf_req_free(req); | 2467 | zfcp_fsf_req_free(req); |
2468 | scsi_cmnd->host_scribble = NULL; | 2468 | scsi_cmnd->host_scribble = NULL; |
2469 | out: | 2469 | out: |
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 6feece3b2e36..39a621d729e9 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c | |||
@@ -52,7 +52,7 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) | |||
52 | { | 52 | { |
53 | struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; | 53 | struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; |
54 | unit->device = NULL; | 54 | unit->device = NULL; |
55 | zfcp_unit_put(unit); | 55 | put_device(&unit->sysfs_device); |
56 | } | 56 | } |
57 | 57 | ||
58 | static int zfcp_scsi_slave_configure(struct scsi_device *sdp) | 58 | static int zfcp_scsi_slave_configure(struct scsi_device *sdp) |
@@ -335,8 +335,7 @@ void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) | |||
335 | 335 | ||
336 | read_lock_irq(&adapter->port_list_lock); | 336 | read_lock_irq(&adapter->port_list_lock); |
337 | list_for_each_entry(port, &adapter->port_list, list) | 337 | list_for_each_entry(port, &adapter->port_list, list) |
338 | if (port->rport) | 338 | port->rport = NULL; |
339 | port->rport = NULL; | ||
340 | read_unlock_irq(&adapter->port_list_lock); | 339 | read_unlock_irq(&adapter->port_list_lock); |
341 | 340 | ||
342 | fc_remove_host(shost); | 341 | fc_remove_host(shost); |
@@ -356,7 +355,7 @@ zfcp_init_fc_host_stats(struct zfcp_adapter *adapter) | |||
356 | fc_stats = kmalloc(sizeof(*fc_stats), GFP_KERNEL); | 355 | fc_stats = kmalloc(sizeof(*fc_stats), GFP_KERNEL); |
357 | if (!fc_stats) | 356 | if (!fc_stats) |
358 | return NULL; | 357 | return NULL; |
359 | adapter->fc_stats = fc_stats; /* freed in adater_dequeue */ | 358 | adapter->fc_stats = fc_stats; /* freed in adapter_release */ |
360 | } | 359 | } |
361 | memset(adapter->fc_stats, 0, sizeof(*adapter->fc_stats)); | 360 | memset(adapter->fc_stats, 0, sizeof(*adapter->fc_stats)); |
362 | return adapter->fc_stats; | 361 | return adapter->fc_stats; |
@@ -472,7 +471,7 @@ static void zfcp_reset_fc_host_stats(struct Scsi_Host *shost) | |||
472 | adapter->stats_reset = jiffies/HZ; | 471 | adapter->stats_reset = jiffies/HZ; |
473 | kfree(adapter->stats_reset_data); | 472 | kfree(adapter->stats_reset_data); |
474 | adapter->stats_reset_data = data; /* finally freed in | 473 | adapter->stats_reset_data = data; /* finally freed in |
475 | adapter_dequeue */ | 474 | adapter_release */ |
476 | } | 475 | } |
477 | } | 476 | } |
478 | 477 | ||
@@ -517,7 +516,7 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) | |||
517 | 516 | ||
518 | if (port) { | 517 | if (port) { |
519 | zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL); | 518 | zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL); |
520 | zfcp_port_put(port); | 519 | put_device(&port->sysfs_device); |
521 | } | 520 | } |
522 | } | 521 | } |
523 | 522 | ||
@@ -559,23 +558,23 @@ static void zfcp_scsi_rport_block(struct zfcp_port *port) | |||
559 | 558 | ||
560 | void zfcp_scsi_schedule_rport_register(struct zfcp_port *port) | 559 | void zfcp_scsi_schedule_rport_register(struct zfcp_port *port) |
561 | { | 560 | { |
562 | zfcp_port_get(port); | 561 | get_device(&port->sysfs_device); |
563 | port->rport_task = RPORT_ADD; | 562 | port->rport_task = RPORT_ADD; |
564 | 563 | ||
565 | if (!queue_work(port->adapter->work_queue, &port->rport_work)) | 564 | if (!queue_work(port->adapter->work_queue, &port->rport_work)) |
566 | zfcp_port_put(port); | 565 | put_device(&port->sysfs_device); |
567 | } | 566 | } |
568 | 567 | ||
569 | void zfcp_scsi_schedule_rport_block(struct zfcp_port *port) | 568 | void zfcp_scsi_schedule_rport_block(struct zfcp_port *port) |
570 | { | 569 | { |
571 | zfcp_port_get(port); | 570 | get_device(&port->sysfs_device); |
572 | port->rport_task = RPORT_DEL; | 571 | port->rport_task = RPORT_DEL; |
573 | 572 | ||
574 | if (port->rport && queue_work(port->adapter->work_queue, | 573 | if (port->rport && queue_work(port->adapter->work_queue, |
575 | &port->rport_work)) | 574 | &port->rport_work)) |
576 | return; | 575 | return; |
577 | 576 | ||
578 | zfcp_port_put(port); | 577 | put_device(&port->sysfs_device); |
579 | } | 578 | } |
580 | 579 | ||
581 | void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter) | 580 | void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter) |
@@ -604,7 +603,7 @@ void zfcp_scsi_rport_work(struct work_struct *work) | |||
604 | } | 603 | } |
605 | } | 604 | } |
606 | 605 | ||
607 | zfcp_port_put(port); | 606 | put_device(&port->sysfs_device); |
608 | } | 607 | } |
609 | 608 | ||
610 | 609 | ||
@@ -622,7 +621,7 @@ void zfcp_scsi_scan(struct work_struct *work) | |||
622 | scsilun_to_int((struct scsi_lun *) | 621 | scsilun_to_int((struct scsi_lun *) |
623 | &unit->fcp_lun), 0); | 622 | &unit->fcp_lun), 0); |
624 | 623 | ||
625 | zfcp_unit_put(unit); | 624 | put_device(&unit->sysfs_device); |
626 | } | 625 | } |
627 | 626 | ||
628 | static int zfcp_execute_fc_job(struct fc_bsg_job *job) | 627 | static int zfcp_execute_fc_job(struct fc_bsg_job *job) |
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 8430b518357e..b4a7e17932c5 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * sysfs attributes. | 4 | * sysfs attributes. |
5 | * | 5 | * |
6 | * Copyright IBM Corporation 2008 | 6 | * Copyright IBM Corporation 2008, 2009 |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #define KMSG_COMPONENT "zfcp" | 9 | #define KMSG_COMPONENT "zfcp" |
@@ -140,7 +140,6 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, | |||
140 | struct zfcp_port *port; | 140 | struct zfcp_port *port; |
141 | u64 wwpn; | 141 | u64 wwpn; |
142 | int retval = 0; | 142 | int retval = 0; |
143 | LIST_HEAD(port_remove_lh); | ||
144 | 143 | ||
145 | mutex_lock(&zfcp_data.config_mutex); | 144 | mutex_lock(&zfcp_data.config_mutex); |
146 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { | 145 | if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_REMOVE) { |
@@ -154,23 +153,21 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, | |||
154 | } | 153 | } |
155 | 154 | ||
156 | port = zfcp_get_port_by_wwpn(adapter, wwpn); | 155 | port = zfcp_get_port_by_wwpn(adapter, wwpn); |
157 | if (port && (atomic_read(&port->refcount) == 1)) { | ||
158 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); | ||
159 | write_lock_irq(&adapter->port_list_lock); | ||
160 | list_move(&port->list, &port_remove_lh); | ||
161 | write_unlock_irq(&adapter->port_list_lock); | ||
162 | } else | ||
163 | port = NULL; | ||
164 | |||
165 | if (!port) { | 156 | if (!port) { |
166 | retval = -ENXIO; | 157 | retval = -ENXIO; |
167 | goto out; | 158 | goto out; |
168 | } | 159 | } |
169 | 160 | ||
161 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); | ||
162 | |||
163 | write_lock_irq(&adapter->port_list_lock); | ||
164 | list_del(&port->list); | ||
165 | write_unlock_irq(&adapter->port_list_lock); | ||
166 | |||
167 | put_device(&port->sysfs_device); | ||
168 | |||
170 | zfcp_erp_port_shutdown(port, 0, "syprs_1", NULL); | 169 | zfcp_erp_port_shutdown(port, 0, "syprs_1", NULL); |
171 | zfcp_erp_wait(adapter); | 170 | zfcp_device_unregister(&port->sysfs_device, &zfcp_sysfs_port_attrs); |
172 | zfcp_port_put(port); | ||
173 | zfcp_port_dequeue(port); | ||
174 | out: | 171 | out: |
175 | mutex_unlock(&zfcp_data.config_mutex); | 172 | mutex_unlock(&zfcp_data.config_mutex); |
176 | return retval ? retval : (ssize_t) count; | 173 | return retval ? retval : (ssize_t) count; |
@@ -224,7 +221,6 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, | |||
224 | zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL); | 221 | zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL); |
225 | zfcp_erp_wait(unit->port->adapter); | 222 | zfcp_erp_wait(unit->port->adapter); |
226 | flush_work(&unit->scsi_work); | 223 | flush_work(&unit->scsi_work); |
227 | zfcp_unit_put(unit); | ||
228 | out: | 224 | out: |
229 | mutex_unlock(&zfcp_data.config_mutex); | 225 | mutex_unlock(&zfcp_data.config_mutex); |
230 | return retval ? retval : (ssize_t) count; | 226 | return retval ? retval : (ssize_t) count; |
@@ -239,7 +235,6 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, | |||
239 | struct zfcp_unit *unit; | 235 | struct zfcp_unit *unit; |
240 | u64 fcp_lun; | 236 | u64 fcp_lun; |
241 | int retval = 0; | 237 | int retval = 0; |
242 | LIST_HEAD(unit_remove_lh); | ||
243 | 238 | ||
244 | mutex_lock(&zfcp_data.config_mutex); | 239 | mutex_lock(&zfcp_data.config_mutex); |
245 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { | 240 | if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { |
@@ -261,19 +256,16 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, | |||
261 | /* wait for possible timeout during SCSI probe */ | 256 | /* wait for possible timeout during SCSI probe */ |
262 | flush_work(&unit->scsi_work); | 257 | flush_work(&unit->scsi_work); |
263 | 258 | ||
264 | if (atomic_read(&unit->refcount) == 1) { | 259 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); |
265 | atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); | 260 | |
261 | write_lock_irq(&port->unit_list_lock); | ||
262 | list_del(&unit->list); | ||
263 | write_unlock_irq(&port->unit_list_lock); | ||
266 | 264 | ||
267 | write_lock_irq(&port->unit_list_lock); | 265 | put_device(&unit->sysfs_device); |
268 | list_move(&unit->list, &unit_remove_lh); | ||
269 | write_unlock_irq(&port->unit_list_lock); | ||
270 | 266 | ||
271 | zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); | 267 | zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); |
272 | zfcp_erp_wait(unit->port->adapter); | 268 | zfcp_device_unregister(&unit->sysfs_device, &zfcp_sysfs_unit_attrs); |
273 | zfcp_unit_put(unit); | ||
274 | zfcp_unit_dequeue(unit); | ||
275 | } else | ||
276 | zfcp_unit_put(unit); | ||
277 | out: | 269 | out: |
278 | mutex_unlock(&zfcp_data.config_mutex); | 270 | mutex_unlock(&zfcp_data.config_mutex); |
279 | return retval ? retval : (ssize_t) count; | 271 | return retval ? retval : (ssize_t) count; |