|
@@ -18,6 +18,9 @@ static int zfcp_ccw_suspend(struct ccw_device *cdev)
|
|
|
{
|
|
|
struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
|
|
|
|
|
|
+ if (!adapter)
|
|
|
+ return 0;
|
|
|
+
|
|
|
down(&zfcp_data.config_sema);
|
|
|
|
|
|
zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL);
|
|
@@ -33,6 +36,9 @@ static int zfcp_ccw_activate(struct ccw_device *cdev)
|
|
|
{
|
|
|
struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
|
|
|
|
|
|
+ if (!adapter)
|
|
|
+ return 0;
|
|
|
+
|
|
|
zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL,
|
|
|
ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
|
|
|
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
|
|
@@ -63,25 +69,14 @@ int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter)
|
|
|
* zfcp_ccw_probe - probe function of zfcp driver
|
|
|
* @ccw_device: pointer to belonging ccw device
|
|
|
*
|
|
|
- * This function gets called by the common i/o layer and sets up the initial
|
|
|
- * data structures for each fcp adapter, which was detected by the system.
|
|
|
- * Also the sysfs files for this adapter will be created by this function.
|
|
|
- * In addition the nameserver port will be added to the ports of the adapter
|
|
|
- * and its sysfs representation will be created too.
|
|
|
+ * This function gets called by the common i/o layer for each FCP
|
|
|
+ * device found on the current system. This is only a stub to make cio
|
|
|
+ * work: To only allocate adapter resources for devices actually used,
|
|
|
+ * the allocation is deferred to the first call to ccw_set_online.
|
|
|
*/
|
|
|
static int zfcp_ccw_probe(struct ccw_device *ccw_device)
|
|
|
{
|
|
|
- int retval = 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;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -102,8 +97,11 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
|
|
|
LIST_HEAD(port_remove_lh);
|
|
|
|
|
|
ccw_device_set_offline(ccw_device);
|
|
|
+
|
|
|
down(&zfcp_data.config_sema);
|
|
|
adapter = dev_get_drvdata(&ccw_device->dev);
|
|
|
+ if (!adapter)
|
|
|
+ goto out;
|
|
|
|
|
|
write_lock_irq(&zfcp_data.config_lock);
|
|
|
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)
|
|
|
wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
|
|
|
zfcp_adapter_dequeue(adapter);
|
|
|
|
|
|
+out:
|
|
|
up(&zfcp_data.config_sema);
|
|
|
}
|
|
|
|
|
@@ -136,22 +135,33 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
|
|
|
* zfcp_ccw_set_online - set_online function of zfcp driver
|
|
|
* @ccw_device: pointer to belonging ccw device
|
|
|
*
|
|
|
- * This function gets called by the common i/o layer and sets an adapter
|
|
|
- * into state online. 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 (asynchronously).
|
|
|
+ * This function gets called by the common i/o layer and sets an
|
|
|
+ * adapter into state online. The first call will allocate all
|
|
|
+ * adapter resources that will be retained until the device is removed
|
|
|
+ * 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)
|
|
|
{
|
|
|
struct zfcp_adapter *adapter;
|
|
|
- int retval;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
down(&zfcp_data.config_sema);
|
|
|
adapter = dev_get_drvdata(&ccw_device->dev);
|
|
|
|
|
|
- retval = zfcp_erp_thread_setup(adapter);
|
|
|
- if (retval)
|
|
|
- goto out;
|
|
|
+ if (!adapter) {
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ adapter = dev_get_drvdata(&ccw_device->dev);
|
|
|
+ }
|
|
|
|
|
|
/* initialize request counter */
|
|
|
BUG_ON(!zfcp_reqlist_isempty(adapter));
|
|
@@ -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,
|
|
|
"ccsonl2", NULL);
|
|
|
zfcp_erp_wait(adapter);
|
|
|
+out:
|
|
|
up(&zfcp_data.config_sema);
|
|
|
- flush_work(&adapter->scan_work);
|
|
|
- return 0;
|
|
|
-
|
|
|
- out:
|
|
|
- up(&zfcp_data.config_sema);
|
|
|
- return retval;
|
|
|
+ if (!ret)
|
|
|
+ flush_work(&adapter->scan_work);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -184,10 +192,13 @@ static int zfcp_ccw_set_offline(struct ccw_device *ccw_device)
|
|
|
|
|
|
down(&zfcp_data.config_sema);
|
|
|
adapter = dev_get_drvdata(&ccw_device->dev);
|
|
|
+ if (!adapter)
|
|
|
+ goto out;
|
|
|
+
|
|
|
zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL);
|
|
|
zfcp_erp_wait(adapter);
|
|
|
- zfcp_erp_thread_kill(adapter);
|
|
|
up(&zfcp_data.config_sema);
|
|
|
+out:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -244,6 +255,7 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev)
|
|
|
adapter = dev_get_drvdata(&cdev->dev);
|
|
|
zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL);
|
|
|
zfcp_erp_wait(adapter);
|
|
|
+ zfcp_erp_thread_kill(adapter);
|
|
|
up(&zfcp_data.config_sema);
|
|
|
}
|
|
|
|