aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorChristof Schmitt <christof.schmitt@de.ibm.com>2009-08-18 09:43:27 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-09-05 09:49:41 -0400
commit143bb6bfe36d20618d8bf667915fe14d14b8ae2f (patch)
treec0c1dad94d0ec49f25b3652581931f2b499b5f07 /drivers/s390
parent98fc4d5c8cd9bd1a412cca922feecb54c1c22d8e (diff)
[SCSI] zfcp: Defer resource allocation to first ccw_set_online call
So far, zfcp allocated all resources required for FCP adapters/subchannels when the device was discovered in the ccw_probe callback. If there are lots of unused FCP subchannels attached to a system, this is a waste of resources. To alleviate this, defer the resource allocation to the first call to ccw_set_online. To avoid disruptions during possible following calls to ccw_set_offline and then ccw_set_online, keep the adapter resources until the device is finally being removed via ccw_remove. While doing this, also manage the zfcp erp thread together with all other adapter resources in zfcp_adapter_enqueue/dequeue. Reviewed-by: Swen Schillig <swen@vnet.ibm.com> Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/scsi/zfcp_aux.c6
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c74
-rw-r--r--drivers/s390/scsi/zfcp_erp.c5
3 files changed, 54 insertions, 31 deletions
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index e8f39f02bc3..d1e75d36ed1 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -541,6 +541,9 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
541 rwlock_init(&adapter->erp_lock); 541 rwlock_init(&adapter->erp_lock);
542 rwlock_init(&adapter->abort_lock); 542 rwlock_init(&adapter->abort_lock);
543 543
544 if (zfcp_erp_thread_setup(adapter))
545 goto erp_thread_failed;
546
544 INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); 547 INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler);
545 INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later); 548 INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later);
546 549
@@ -561,6 +564,8 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
561 return 0; 564 return 0;
562 565
563sysfs_failed: 566sysfs_failed:
567 zfcp_erp_thread_kill(adapter);
568erp_thread_failed:
564 zfcp_fc_gs_destroy(adapter); 569 zfcp_fc_gs_destroy(adapter);
565generic_services_failed: 570generic_services_failed:
566 zfcp_destroy_adapter_work_queue(adapter); 571 zfcp_destroy_adapter_work_queue(adapter);
@@ -602,6 +607,7 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
602 return; 607 return;
603 608
604 zfcp_fc_gs_destroy(adapter); 609 zfcp_fc_gs_destroy(adapter);
610 zfcp_erp_thread_kill(adapter);
605 zfcp_destroy_adapter_work_queue(adapter); 611 zfcp_destroy_adapter_work_queue(adapter);
606 zfcp_dbf_adapter_unregister(adapter->dbf); 612 zfcp_dbf_adapter_unregister(adapter->dbf);
607 zfcp_free_low_mem_buffers(adapter); 613 zfcp_free_low_mem_buffers(adapter);
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index d9da5c42ccb..82ae6ed7ef8 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -18,6 +18,9 @@ static int zfcp_ccw_suspend(struct ccw_device *cdev)
18{ 18{
19 struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); 19 struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
20 20
21 if (!adapter)
22 return 0;
23
21 down(&zfcp_data.config_sema); 24 down(&zfcp_data.config_sema);
22 25
23 zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL); 26 zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL);
@@ -33,6 +36,9 @@ static int zfcp_ccw_activate(struct ccw_device *cdev)
33{ 36{
34 struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); 37 struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
35 38
39 if (!adapter)
40 return 0;
41
36 zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL, 42 zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL,
37 ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); 43 ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
38 zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 44 zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
@@ -63,25 +69,14 @@ int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter)
63 * zfcp_ccw_probe - probe function of zfcp driver 69 * zfcp_ccw_probe - probe function of zfcp driver
64 * @ccw_device: pointer to belonging ccw device 70 * @ccw_device: pointer to belonging ccw device
65 * 71 *
66 * This function gets called by the common i/o layer and sets up the initial 72 * This function gets called by the common i/o layer for each FCP
67 * data structures for each fcp adapter, which was detected by the system. 73 * device found on the current system. This is only a stub to make cio
68 * Also the sysfs files for this adapter will be created by this function. 74 * work: To only allocate adapter resources for devices actually used,
69 * In addition the nameserver port will be added to the ports of the adapter 75 * the allocation is deferred to the first call to ccw_set_online.
70 * and its sysfs representation will be created too.
71 */ 76 */
72static int zfcp_ccw_probe(struct ccw_device *ccw_device) 77static int zfcp_ccw_probe(struct ccw_device *ccw_device)
73{ 78{
74 int retval = 0; 79 return 0;
75
76 down(&zfcp_data.config_sema);
77 if (zfcp_adapter_enqueue(ccw_device)) {
78 dev_err(&ccw_device->dev,
79 "Setting up data structures for the "
80 "FCP adapter failed\n");
81 retval = -EINVAL;
82 }
83 up(&zfcp_data.config_sema);
84 return retval;
85} 80}
86 81
87/** 82/**
@@ -102,8 +97,11 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
102 LIST_HEAD(port_remove_lh); 97 LIST_HEAD(port_remove_lh);
103 98
104 ccw_device_set_offline(ccw_device); 99 ccw_device_set_offline(ccw_device);
100
105 down(&zfcp_data.config_sema); 101 down(&zfcp_data.config_sema);
106 adapter = dev_get_drvdata(&ccw_device->dev); 102 adapter = dev_get_drvdata(&ccw_device->dev);
103 if (!adapter)
104 goto out;
107 105
108 write_lock_irq(&zfcp_data.config_lock); 106 write_lock_irq(&zfcp_data.config_lock);
109 list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { 107 list_for_each_entry_safe(port, p, &adapter->port_list_head, list) {
@@ -129,6 +127,7 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
129 wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); 127 wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
130 zfcp_adapter_dequeue(adapter); 128 zfcp_adapter_dequeue(adapter);
131 129
130out:
132 up(&zfcp_data.config_sema); 131 up(&zfcp_data.config_sema);
133} 132}
134 133
@@ -136,22 +135,33 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
136 * zfcp_ccw_set_online - set_online function of zfcp driver 135 * zfcp_ccw_set_online - set_online function of zfcp driver
137 * @ccw_device: pointer to belonging ccw device 136 * @ccw_device: pointer to belonging ccw device
138 * 137 *
139 * This function gets called by the common i/o layer and sets an adapter 138 * This function gets called by the common i/o layer and sets an
140 * into state online. Setting an fcp device online means that it will be 139 * adapter into state online. The first call will allocate all
141 * registered with the SCSI stack, that the QDIO queues will be set up 140 * adapter resources that will be retained until the device is removed
142 * and that the adapter will be opened (asynchronously). 141 * via zfcp_ccw_remove.
142 *
143 * Setting an fcp device online means that it will be registered with
144 * the SCSI stack, that the QDIO queues will be set up and that the
145 * adapter will be opened.
143 */ 146 */
144static int zfcp_ccw_set_online(struct ccw_device *ccw_device) 147static int zfcp_ccw_set_online(struct ccw_device *ccw_device)
145{ 148{
146 struct zfcp_adapter *adapter; 149 struct zfcp_adapter *adapter;
147 int retval; 150 int ret = 0;
148 151
149 down(&zfcp_data.config_sema); 152 down(&zfcp_data.config_sema);
150 adapter = dev_get_drvdata(&ccw_device->dev); 153 adapter = dev_get_drvdata(&ccw_device->dev);
151 154
152 retval = zfcp_erp_thread_setup(adapter); 155 if (!adapter) {
153 if (retval) 156 ret = zfcp_adapter_enqueue(ccw_device);
154 goto out; 157 if (ret) {
158 dev_err(&ccw_device->dev,
159 "Setting up data structures for the "
160 "FCP adapter failed\n");
161 goto out;
162 }
163 adapter = dev_get_drvdata(&ccw_device->dev);
164 }
155 165
156 /* initialize request counter */ 166 /* initialize request counter */
157 BUG_ON(!zfcp_reqlist_isempty(adapter)); 167 BUG_ON(!zfcp_reqlist_isempty(adapter));
@@ -162,13 +172,11 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device)
162 zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 172 zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
163 "ccsonl2", NULL); 173 "ccsonl2", NULL);
164 zfcp_erp_wait(adapter); 174 zfcp_erp_wait(adapter);
175out:
165 up(&zfcp_data.config_sema); 176 up(&zfcp_data.config_sema);
166 flush_work(&adapter->scan_work); 177 if (!ret)
167 return 0; 178 flush_work(&adapter->scan_work);
168 179 return ret;
169 out:
170 up(&zfcp_data.config_sema);
171 return retval;
172} 180}
173 181
174/** 182/**
@@ -184,10 +192,13 @@ static int zfcp_ccw_set_offline(struct ccw_device *ccw_device)
184 192
185 down(&zfcp_data.config_sema); 193 down(&zfcp_data.config_sema);
186 adapter = dev_get_drvdata(&ccw_device->dev); 194 adapter = dev_get_drvdata(&ccw_device->dev);
195 if (!adapter)
196 goto out;
197
187 zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL); 198 zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL);
188 zfcp_erp_wait(adapter); 199 zfcp_erp_wait(adapter);
189 zfcp_erp_thread_kill(adapter);
190 up(&zfcp_data.config_sema); 200 up(&zfcp_data.config_sema);
201out:
191 return 0; 202 return 0;
192} 203}
193 204
@@ -244,6 +255,7 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev)
244 adapter = dev_get_drvdata(&cdev->dev); 255 adapter = dev_get_drvdata(&cdev->dev);
245 zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL); 256 zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL);
246 zfcp_erp_wait(adapter); 257 zfcp_erp_wait(adapter);
258 zfcp_erp_thread_kill(adapter);
247 up(&zfcp_data.config_sema); 259 up(&zfcp_data.config_sema);
248} 260}
249 261
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 577e1570859..73d366ba31e 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -150,6 +150,9 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
150 a_status = atomic_read(&adapter->status); 150 a_status = atomic_read(&adapter->status);
151 if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE) 151 if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
152 return 0; 152 return 0;
153 if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) &&
154 !(a_status & ZFCP_STATUS_COMMON_OPEN))
155 return 0; /* shutdown requested for closed adapter */
153 } 156 }
154 157
155 return need; 158 return need;
@@ -1349,6 +1352,8 @@ void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
1349{ 1352{
1350 kthread_stop(adapter->erp_thread); 1353 kthread_stop(adapter->erp_thread);
1351 adapter->erp_thread = NULL; 1354 adapter->erp_thread = NULL;
1355 WARN_ON(!list_empty(&adapter->erp_ready_head));
1356 WARN_ON(!list_empty(&adapter->erp_running_head));
1352} 1357}
1353 1358
1354/** 1359/**