From c5afd81e5d7ebacc9dd23954e169ac79a34fe399 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 24 Sep 2009 10:23:22 +0200 Subject: [SCSI] zfcp: Fix initial device and cfdc for delayed adapter allocation With the change for delaying the allocation of zfcp_adapter, the initial device parameter function has to first call ccw_device_set_online which allocates the zfcp_adapter structure. Change this and adapt the cfdc part accordingly. Reviewed-by: Felix Beck Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_ccw.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) (limited to 'drivers/s390/scsi/zfcp_ccw.c') diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 0c90f8e71605..ef5282dcdbb4 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -259,7 +259,7 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev) mutex_unlock(&zfcp_data.config_mutex); } -static struct ccw_driver zfcp_ccw_driver = { +struct ccw_driver zfcp_ccw_driver = { .owner = THIS_MODULE, .name = "zfcp", .ids = zfcp_ccw_device_id, @@ -284,20 +284,3 @@ int __init zfcp_ccw_register(void) { return ccw_driver_register(&zfcp_ccw_driver); } - -/** - * zfcp_get_adapter_by_busid - find zfcp_adapter struct - * @busid: bus id string of zfcp adapter to find - */ -struct zfcp_adapter *zfcp_get_adapter_by_busid(char *busid) -{ - struct ccw_device *ccw_device; - struct zfcp_adapter *adapter = NULL; - - ccw_device = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); - if (ccw_device) { - adapter = dev_get_drvdata(&ccw_device->dev); - put_device(&ccw_device->dev); - } - return adapter; -} -- cgit v1.2.3 From 1f99bd4cbfa50be144aee24905befc1209d90d47 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 24 Sep 2009 10:23:23 +0200 Subject: [SCSI] zfcp: Fix oops during shutdown of offline device With the change that the zfcp_adapter struct is only allocated when the device is set online, the shutdown handler has to check for a non-existing zfcp_adapter struct. On the other hand, this check is not necessary in the offline callback, since an online device has the zfcp_adapter allocated and we go through the offline callback before removing the ccw device. Reviewed-by: Felix Beck Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_ccw.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/s390/scsi/zfcp_ccw.c') diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index ef5282dcdbb4..95644b71836e 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -192,13 +192,9 @@ static int zfcp_ccw_set_offline(struct ccw_device *ccw_device) mutex_lock(&zfcp_data.config_mutex); adapter = dev_get_drvdata(&ccw_device->dev); - if (!adapter) - goto out; - zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL); zfcp_erp_wait(adapter); mutex_unlock(&zfcp_data.config_mutex); -out: return 0; } @@ -253,9 +249,13 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev) mutex_lock(&zfcp_data.config_mutex); adapter = dev_get_drvdata(&cdev->dev); + if (!adapter) + goto out; + zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL); zfcp_erp_wait(adapter); zfcp_erp_thread_kill(adapter); +out: mutex_unlock(&zfcp_data.config_mutex); } -- cgit v1.2.3 From f45a54214a0770582af06bb1e807493d1b7268ab Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 24 Sep 2009 10:23:24 +0200 Subject: [SCSI] zfcp: Fix lockdep warning when offlining device with offline chpid ======================================================= [ INFO: possible circular locking dependency detected ] 2.6.31-39.x.20090917-s390xdefault #1 ------------------------------------------------------- kslowcrw/83 is trying to acquire lock: (&adapter->scan_work){+.+.+.}, at: [<0000000000169c5c>] __cancel_work_timer+0x64/0x3d4 but task is already holding lock: (&zfcp_data.config_mutex){+.+.+.}, at: [<00000000004671ea>] zfcp_ccw_remove+0x66/0x384 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (&zfcp_data.config_mutex){+.+.+.}: [<0000000000189962>] __lock_acquire+0xe26/0x1834 [<000000000018a4b6>] lock_acquire+0x146/0x178 [<000000000058cb5a>] mutex_lock_nested+0x82/0x3ec [<0000000000477170>] zfcp_fc_scan_ports+0x3ec/0x728 [<0000000000168e34>] worker_thread+0x278/0x3a8 [<000000000016ff08>] kthread+0x9c/0xa4 [<0000000000109ebe>] kernel_thread_starter+0x6/0xc [<0000000000109eb8>] kernel_thread_starter+0x0/0xc -> #0 (&adapter->scan_work){+.+.+.}: [<0000000000189e60>] __lock_acquire+0x1324/0x1834 [<000000000018a4b6>] lock_acquire+0x146/0x178 [<0000000000169c9a>] __cancel_work_timer+0xa2/0x3d4 [<0000000000465cb2>] zfcp_adapter_dequeue+0x32/0x14c [<00000000004673e4>] zfcp_ccw_remove+0x260/0x384 [<00000000004250f6>] ccw_device_remove+0x42/0x1ac [<00000000003cb6be>] __device_release_driver+0x9a/0x10c [<00000000003cb856>] device_release_driver+0x3a/0x4c [<00000000003ca94c>] bus_remove_device+0xcc/0x114 [<00000000003c8506>] device_del+0x162/0x21c [<0000000000425ff2>] ccw_device_unregister+0x5e/0x7c [<000000000042607e>] io_subchannel_remove+0x6e/0x9c [<000000000041ff9a>] css_remove+0x3e/0x7c [<00000000003cb6be>] __device_release_driver+0x9a/0x10c [<00000000003cb856>] device_release_driver+0x3a/0x4c [<00000000003ca94c>] bus_remove_device+0xcc/0x114 [<00000000003c8506>] device_del+0x162/0x21c [<00000000003c85e8>] device_unregister+0x28/0x38 [<0000000000420152>] css_sch_device_unregister+0x46/0x58 [<00000000004276a6>] io_subchannel_sch_event+0x28e/0x794 [<0000000000420442>] css_evaluate_known_subchannel+0x46/0xd0 [<0000000000420ebc>] slow_eval_known_fn+0x88/0xa0 [<00000000003caffa>] bus_for_each_dev+0x7e/0xd0 [<000000000042188c>] for_each_subchannel_staged+0x6c/0xd4 [<0000000000421a00>] css_slow_path_func+0x54/0xd8 [<0000000000168e34>] worker_thread+0x278/0x3a8 [<000000000016ff08>] kthread+0x9c/0xa4 [<0000000000109ebe>] kernel_thread_starter+0x6/0xc [<0000000000109eb8>] kernel_thread_starter+0x0/0xc cancel_work_sync is called while holding the config_mutex. But the work that is being cancelled or flushed also uses the config_mutex. Fix the resulting deadlock possibility by calling cancel_work_sync earlier without holding the mutex. The best place to do is is after offlining the device. No new port scan work will be scheduled for the offline device, so this is a safe place to call cancel_work_sync. Reviewed-by: Felix Beck Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 1 - drivers/s390/scsi/zfcp_ccw.c | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/s390/scsi/zfcp_ccw.c') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 351d2e711ec5..5dcac24a7a1b 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -602,7 +602,6 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) int retval = 0; unsigned long flags; - cancel_work_sync(&adapter->scan_work); cancel_work_sync(&adapter->stat_work); zfcp_fc_wka_ports_force_offline(adapter->gs); zfcp_adapter_scsi_unregister(adapter); diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 95644b71836e..9fe32f7ec8d2 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -102,7 +102,11 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) adapter = dev_get_drvdata(&ccw_device->dev); if (!adapter) goto out; + mutex_unlock(&zfcp_data.config_mutex); + + cancel_work_sync(&adapter->scan_work); + mutex_lock(&zfcp_data.config_mutex); write_lock_irq(&zfcp_data.config_lock); list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { list_for_each_entry_safe(unit, u, &port->unit_list_head, list) { -- cgit v1.2.3 From d74cf7c3e9c4a6a659e0442aafb550b162d15e72 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 24 Sep 2009 10:23:25 +0200 Subject: [SCSI] zfcp: Fix hang when offlining device with offline chpid Running chchp --vary 0 and chccwdev -d on a FCP device with scsi devices attached can lead to this thread hanging: ================================================================ STACK TRACE FOR TASK: 0x2fbfcc00 (kslowcrw) STACK: 0 schedule+1136 [0x45f99c] 1 schedule_timeout+534 [0x46054e] 2 wait_for_common+374 [0x45f442] 3 blk_execute_rq+160 [0x217a2c] 4 scsi_execute+278 [0x26daf2] 5 scsi_execute_req+150 [0x26dc86] 6 sd_sync_cache+138 [0x28460a] 7 sd_shutdown+130 [0x28486a] 8 sd_remove+104 [0x284c84] 9 __device_release_driver+152 [0x257430] 10 device_release_driver+56 [0x2575c8] 11 bus_remove_device+214 [0x25672a] 12 device_del+352 [0x25456c] 13 __scsi_remove_device+108 [0x272630] 14 scsi_remove_device+66 [0x2726ba] 15 zfcp_ccw_remove+824 [0x335558] 16 ccw_device_remove+62 [0x2b3f2a] 17 __device_release_driver+152 [0x257430] 18 device_release_driver+56 [0x2575c8] 19 bus_remove_device+214 [0x25672a] 20 device_del+352 [0x25456c] 21 ccw_device_unregister+92 [0x2b48c4] 22 io_subchannel_remove+108 [0x2b4950] 23 css_remove+62 [0x2af7ee] 24 __device_release_driver+152 [0x257430] 25 device_release_driver+56 [0x2575c8] 26 bus_remove_device+214 [0x25672a] 27 device_del+352 [0x25456c] 28 device_unregister+38 [0x25464a] 29 css_sch_device_unregister+68 [0x2af97c] 30 ccw_device_call_sch_unregister+78 [0x2b581e] 31 worker_thread+604 [0x69eb0] 32 kthread+154 [0x6ff42] 33 kernel_thread_starter+6 [0x1c952] ================================================================ The problem is that the chchp --vary 0 leads to zfcp first calling fc_remote_port_delete which blocks all scsi devices on the remote port. Calling scsi_remove_device later lets the sd driver issue a SYNCHRONIZE_CACHE command. This command stays on the "stopped" request requeue because the SCSI device is blocked. Fix this by first removing the scsi and fc hosts which removes all scsi devices and do not use scsi_remove_device. Reviewed-by: Felix Beck Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 1 - drivers/s390/scsi/zfcp_ccw.c | 9 +++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/s390/scsi/zfcp_ccw.c') diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 5dcac24a7a1b..0f79f3af4f54 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -604,7 +604,6 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) cancel_work_sync(&adapter->stat_work); zfcp_fc_wka_ports_force_offline(adapter->gs); - zfcp_adapter_scsi_unregister(adapter); sysfs_remove_group(&adapter->ccw_device->dev.kobj, &zfcp_sysfs_adapter_attrs); dev_set_drvdata(&adapter->ccw_device->dev, NULL); diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 9fe32f7ec8d2..e08339428ecf 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -107,6 +107,10 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) cancel_work_sync(&adapter->scan_work); mutex_lock(&zfcp_data.config_mutex); + + /* this also removes the scsi devices, so call it first */ + zfcp_adapter_scsi_unregister(adapter); + write_lock_irq(&zfcp_data.config_lock); list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { list_for_each_entry_safe(unit, u, &port->unit_list_head, list) { @@ -121,11 +125,8 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) write_unlock_irq(&zfcp_data.config_lock); list_for_each_entry_safe(port, p, &port_remove_lh, list) { - list_for_each_entry_safe(unit, u, &unit_remove_lh, list) { - if (unit->device) - scsi_remove_device(unit->device); + list_for_each_entry_safe(unit, u, &unit_remove_lh, list) zfcp_unit_dequeue(unit); - } zfcp_port_dequeue(port); } wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); -- cgit v1.2.3