Commit 143bb6bf authored by Christof Schmitt's avatar Christof Schmitt Committed by James Bottomley

[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: default avatarSwen Schillig <swen@vnet.ibm.com>
Signed-off-by: default avatarChristof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 98fc4d5c
...@@ -541,6 +541,9 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) ...@@ -541,6 +541,9 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
rwlock_init(&adapter->erp_lock); rwlock_init(&adapter->erp_lock);
rwlock_init(&adapter->abort_lock); rwlock_init(&adapter->abort_lock);
if (zfcp_erp_thread_setup(adapter))
goto erp_thread_failed;
INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler);
INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later); INIT_WORK(&adapter->scan_work, _zfcp_fc_scan_ports_later);
...@@ -561,6 +564,8 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) ...@@ -561,6 +564,8 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
return 0; return 0;
sysfs_failed: sysfs_failed:
zfcp_erp_thread_kill(adapter);
erp_thread_failed:
zfcp_fc_gs_destroy(adapter); zfcp_fc_gs_destroy(adapter);
generic_services_failed: generic_services_failed:
zfcp_destroy_adapter_work_queue(adapter); zfcp_destroy_adapter_work_queue(adapter);
...@@ -602,6 +607,7 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) ...@@ -602,6 +607,7 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
return; return;
zfcp_fc_gs_destroy(adapter); zfcp_fc_gs_destroy(adapter);
zfcp_erp_thread_kill(adapter);
zfcp_destroy_adapter_work_queue(adapter); zfcp_destroy_adapter_work_queue(adapter);
zfcp_dbf_adapter_unregister(adapter->dbf); zfcp_dbf_adapter_unregister(adapter->dbf);
zfcp_free_low_mem_buffers(adapter); zfcp_free_low_mem_buffers(adapter);
......
...@@ -18,6 +18,9 @@ static int zfcp_ccw_suspend(struct ccw_device *cdev) ...@@ -18,6 +18,9 @@ static int zfcp_ccw_suspend(struct ccw_device *cdev)
{ {
struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
if (!adapter)
return 0;
down(&zfcp_data.config_sema); down(&zfcp_data.config_sema);
zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL); zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL);
...@@ -33,6 +36,9 @@ static int zfcp_ccw_activate(struct ccw_device *cdev) ...@@ -33,6 +36,9 @@ static int zfcp_ccw_activate(struct ccw_device *cdev)
{ {
struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
if (!adapter)
return 0;
zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL, zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL,
ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
...@@ -63,25 +69,14 @@ int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter) ...@@ -63,25 +69,14 @@ int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter)
* zfcp_ccw_probe - probe function of zfcp driver * zfcp_ccw_probe - probe function of zfcp driver
* @ccw_device: pointer to belonging ccw device * @ccw_device: pointer to belonging ccw device
* *
* This function gets called by the common i/o layer and sets up the initial * This function gets called by the common i/o layer for each FCP
* data structures for each fcp adapter, which was detected by the system. * device found on the current system. This is only a stub to make cio
* Also the sysfs files for this adapter will be created by this function. * work: To only allocate adapter resources for devices actually used,
* In addition the nameserver port will be added to the ports of the adapter * the allocation is deferred to the first call to ccw_set_online.
* and its sysfs representation will be created too.
*/ */
static int zfcp_ccw_probe(struct ccw_device *ccw_device) static int zfcp_ccw_probe(struct ccw_device *ccw_device)
{ {
int retval = 0; return 0;
down(&zfcp_data.config_sema);
if (zfcp_adapter_enqueue(ccw_device)) {
dev_err(&ccw_device->dev,
"Setting up data structures for the "
"FCP adapter failed\n");
retval = -EINVAL;
}
up(&zfcp_data.config_sema);
return retval;
} }
/** /**
...@@ -102,8 +97,11 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) ...@@ -102,8 +97,11 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
LIST_HEAD(port_remove_lh); LIST_HEAD(port_remove_lh);
ccw_device_set_offline(ccw_device); ccw_device_set_offline(ccw_device);
down(&zfcp_data.config_sema); down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev); adapter = dev_get_drvdata(&ccw_device->dev);
if (!adapter)
goto out;
write_lock_irq(&zfcp_data.config_lock); write_lock_irq(&zfcp_data.config_lock);
list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { 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,6 +127,7 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
zfcp_adapter_dequeue(adapter); zfcp_adapter_dequeue(adapter);
out:
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
} }
...@@ -136,22 +135,33 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device) ...@@ -136,22 +135,33 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
* zfcp_ccw_set_online - set_online function of zfcp driver * zfcp_ccw_set_online - set_online function of zfcp driver
* @ccw_device: pointer to belonging ccw device * @ccw_device: pointer to belonging ccw device
* *
* This function gets called by the common i/o layer and sets an adapter * This function gets called by the common i/o layer and sets an
* into state online. Setting an fcp device online means that it will be * adapter into state online. The first call will allocate all
* registered with the SCSI stack, that the QDIO queues will be set up * adapter resources that will be retained until the device is removed
* and that the adapter will be opened (asynchronously). * via zfcp_ccw_remove.
*
* Setting an fcp device online means that it will be registered with
* the SCSI stack, that the QDIO queues will be set up and that the
* adapter will be opened.
*/ */
static int zfcp_ccw_set_online(struct ccw_device *ccw_device) static int zfcp_ccw_set_online(struct ccw_device *ccw_device)
{ {
struct zfcp_adapter *adapter; struct zfcp_adapter *adapter;
int retval; int ret = 0;
down(&zfcp_data.config_sema); down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev); adapter = dev_get_drvdata(&ccw_device->dev);
retval = zfcp_erp_thread_setup(adapter); if (!adapter) {
if (retval) ret = zfcp_adapter_enqueue(ccw_device);
if (ret) {
dev_err(&ccw_device->dev,
"Setting up data structures for the "
"FCP adapter failed\n");
goto out; goto out;
}
adapter = dev_get_drvdata(&ccw_device->dev);
}
/* initialize request counter */ /* initialize request counter */
BUG_ON(!zfcp_reqlist_isempty(adapter)); BUG_ON(!zfcp_reqlist_isempty(adapter));
...@@ -162,13 +172,11 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device) ...@@ -162,13 +172,11 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device)
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
"ccsonl2", NULL); "ccsonl2", NULL);
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
out:
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
if (!ret)
flush_work(&adapter->scan_work); flush_work(&adapter->scan_work);
return 0; return ret;
out:
up(&zfcp_data.config_sema);
return retval;
} }
/** /**
...@@ -184,10 +192,13 @@ static int zfcp_ccw_set_offline(struct ccw_device *ccw_device) ...@@ -184,10 +192,13 @@ static int zfcp_ccw_set_offline(struct ccw_device *ccw_device)
down(&zfcp_data.config_sema); down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev); adapter = dev_get_drvdata(&ccw_device->dev);
if (!adapter)
goto out;
zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL); zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL);
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
zfcp_erp_thread_kill(adapter);
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
out:
return 0; return 0;
} }
...@@ -244,6 +255,7 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev) ...@@ -244,6 +255,7 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev)
adapter = dev_get_drvdata(&cdev->dev); adapter = dev_get_drvdata(&cdev->dev);
zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL); zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL);
zfcp_erp_wait(adapter); zfcp_erp_wait(adapter);
zfcp_erp_thread_kill(adapter);
up(&zfcp_data.config_sema); up(&zfcp_data.config_sema);
} }
......
...@@ -150,6 +150,9 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, ...@@ -150,6 +150,9 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
a_status = atomic_read(&adapter->status); a_status = atomic_read(&adapter->status);
if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE) if (a_status & ZFCP_STATUS_COMMON_ERP_INUSE)
return 0; return 0;
if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) &&
!(a_status & ZFCP_STATUS_COMMON_OPEN))
return 0; /* shutdown requested for closed adapter */
} }
return need; return need;
...@@ -1349,6 +1352,8 @@ void zfcp_erp_thread_kill(struct zfcp_adapter *adapter) ...@@ -1349,6 +1352,8 @@ void zfcp_erp_thread_kill(struct zfcp_adapter *adapter)
{ {
kthread_stop(adapter->erp_thread); kthread_stop(adapter->erp_thread);
adapter->erp_thread = NULL; adapter->erp_thread = NULL;
WARN_ON(!list_empty(&adapter->erp_ready_head));
WARN_ON(!list_empty(&adapter->erp_running_head));
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment