Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit de3dc572 authored by Swen Schillig's avatar Swen Schillig Committed by James Bottomley
Browse files

[SCSI] zfcp: Remove global config_mutex



The global config_mutex was required for the serialization of a
configuration change within the zfcp driver.  This global locking is
now obsolete and can be removed.  The requirement of serializing the
access to a zfcp_adapter reference via a ccw_device is realized wth a
static spinlock.

Signed-off-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 f3450c7b
Loading
Loading
Loading
Loading
+40 −46
Original line number Diff line number Diff line
@@ -80,23 +80,21 @@ int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)

static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun)
{
	struct ccw_device *ccwdev;
	struct ccw_device *cdev;
	struct zfcp_adapter *adapter;
	struct zfcp_port *port;
	struct zfcp_unit *unit;

	ccwdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
	if (!ccwdev)
	cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
	if (!cdev)
		return;

	if (ccw_device_set_online(ccwdev))
		goto out_ccwdev;
	if (ccw_device_set_online(cdev))
		goto out_ccw_device;

	mutex_lock(&zfcp_data.config_mutex);
	adapter = dev_get_drvdata(&ccwdev->dev);
	adapter = zfcp_ccw_adapter_by_cdev(cdev);
	if (!adapter)
		goto out_unlock;
	kref_get(&adapter->ref);
		goto out_ccw_device;

	port = zfcp_get_port_by_wwpn(adapter, wwpn);
	if (!port)
@@ -105,21 +103,17 @@ static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun)
	unit = zfcp_unit_enqueue(port, lun);
	if (IS_ERR(unit))
		goto out_unit;
	mutex_unlock(&zfcp_data.config_mutex);

	zfcp_erp_unit_reopen(unit, 0, "auidc_1", NULL);
	zfcp_erp_wait(adapter);
	flush_work(&unit->scsi_work);

	mutex_lock(&zfcp_data.config_mutex);
out_unit:
	put_device(&port->sysfs_device);
out_port:
	kref_put(&adapter->ref, zfcp_adapter_release);
out_unlock:
	mutex_unlock(&zfcp_data.config_mutex);
out_ccwdev:
	put_device(&ccwdev->dev);
	zfcp_ccw_adapter_put(adapter);
out_ccw_device:
	put_device(&cdev->dev);
	return;
}

@@ -184,8 +178,6 @@ static int __init zfcp_module_init(void)
	if (!zfcp_data.gid_pn_cache)
		goto out_gid_cache;

	mutex_init(&zfcp_data.config_mutex);

	zfcp_data.scsi_transport_template =
		fc_attach_transport(&zfcp_transport_functions);
	if (!zfcp_data.scsi_transport_template)
@@ -296,7 +288,6 @@ static void zfcp_unit_release(struct device *dev)
 * @port: pointer to port where unit is added
 * @fcp_lun: FCP LUN of unit to be enqueued
 * Returns: pointer to enqueued unit on success, ERR_PTR on error
 * Locks: config_mutex must be held to serialize changes to the unit list
 *
 * Sets up some unit internal structures and creates sysfs entry.
 */
@@ -371,7 +362,6 @@ err_out:

static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
{
	/* must only be called with zfcp_data.config_mutex taken */
	adapter->pool.erp_req =
		mempool_create_kmalloc_pool(1, sizeof(struct zfcp_fsf_req));
	if (!adapter->pool.erp_req)
@@ -419,7 +409,6 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)

static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
{
	/* zfcp_data.config_mutex must be held */
	if (adapter->pool.erp_req)
		mempool_destroy(adapter->pool.erp_req);
	if (adapter->pool.scsi_req)
@@ -501,24 +490,22 @@ static void zfcp_destroy_adapter_work_queue(struct zfcp_adapter *adapter)
 * zfcp_adapter_enqueue - enqueue a new adapter to the list
 * @ccw_device: pointer to the struct cc_device
 *
 * Returns:	0             if a new adapter was successfully enqueued
 *		-ENOMEM       if alloc failed
 * Returns:	struct zfcp_adapter*
 * Enqueues an adapter at the end of the adapter list in the driver data.
 * All adapter internal structures are set up.
 * Proc-fs entries are also created.
 * locks: config_mutex must be held to serialize changes to the adapter list
 */
int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
{
	struct zfcp_adapter *adapter;

	if (!get_device(&ccw_device->dev))
		return -ENODEV;
		return ERR_PTR(-ENODEV);

	adapter = kzalloc(sizeof(struct zfcp_adapter), GFP_KERNEL);
	if (!adapter) {
		put_device(&ccw_device->dev);
		return -ENOMEM;
		return ERR_PTR(-ENOMEM);
	}

	kref_init(&adapter->ref);
@@ -578,11 +565,30 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device)
	atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);

	if (!zfcp_adapter_scsi_register(adapter))
		return 0;
		return adapter;

failed:
	kref_put(&adapter->ref, zfcp_adapter_release);
	return -ENOMEM;
	zfcp_adapter_unregister(adapter);
	return ERR_PTR(-ENOMEM);
}

void zfcp_adapter_unregister(struct zfcp_adapter *adapter)
{
	struct ccw_device *cdev = adapter->ccw_device;

	cancel_work_sync(&adapter->scan_work);
	cancel_work_sync(&adapter->stat_work);
	zfcp_destroy_adapter_work_queue(adapter);

	zfcp_fc_wka_ports_force_offline(adapter->gs);
	zfcp_adapter_scsi_unregister(adapter);
	sysfs_remove_group(&cdev->dev.kobj, &zfcp_sysfs_adapter_attrs);

	zfcp_erp_thread_kill(adapter);
	zfcp_dbf_adapter_unregister(adapter->dbf);
	zfcp_qdio_destroy(adapter->qdio);

	zfcp_ccw_adapter_put(adapter); /* final put to release */
}

/**
@@ -594,27 +600,16 @@ void zfcp_adapter_release(struct kref *ref)
{
	struct zfcp_adapter *adapter = container_of(ref, struct zfcp_adapter,
						    ref);
	struct ccw_device *ccw_device = adapter->ccw_device;

	cancel_work_sync(&adapter->stat_work);

	zfcp_fc_wka_ports_force_offline(adapter->gs);
	sysfs_remove_group(&ccw_device->dev.kobj, &zfcp_sysfs_adapter_attrs);

	dev_set_drvdata(&ccw_device->dev, NULL);
	struct ccw_device *cdev = adapter->ccw_device;

	dev_set_drvdata(&adapter->ccw_device->dev, NULL);
	zfcp_fc_gs_destroy(adapter);
	zfcp_erp_thread_kill(adapter);
	zfcp_destroy_adapter_work_queue(adapter);
	zfcp_dbf_adapter_unregister(adapter->dbf);
	zfcp_free_low_mem_buffers(adapter);
	zfcp_qdio_destroy(adapter->qdio);
	kfree(adapter->req_list);
	kfree(adapter->fc_stats);
	kfree(adapter->stats_reset_data);
	kfree(adapter);
	put_device(&ccw_device->dev);
	put_device(&cdev->dev);
}

/**
@@ -636,7 +631,7 @@ static void zfcp_port_release(struct device *dev)
	struct zfcp_port *port = container_of(dev, struct zfcp_port,
					      sysfs_device);

	kref_put(&port->adapter->ref, zfcp_adapter_release);
	zfcp_ccw_adapter_put(port->adapter);
	kfree(port);
}

@@ -647,7 +642,6 @@ static void zfcp_port_release(struct device *dev)
 * @status: initial status for the port
 * @d_id: destination id of the remote port to be enqueued
 * Returns: pointer to enqueued port on success, ERR_PTR on error
 * Locks: config_mutex must be held to serialize changes to the port list
 *
 * All port internal structures are set up and the sysfs entry is generated.
 * d_id is used to enqueue ports with a well known address like the Directory
@@ -718,7 +712,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
err_out_put:
	device_unregister(&port->sysfs_device);
err_out:
	kref_put(&adapter->ref, zfcp_adapter_release);
	zfcp_ccw_adapter_put(adapter);
	return ERR_PTR(retval);
}

+76 −62
Original line number Diff line number Diff line
@@ -13,20 +13,42 @@

#define ZFCP_MODEL_PRIV 0x4

static DEFINE_SPINLOCK(zfcp_ccw_adapter_ref_lock);

struct zfcp_adapter *zfcp_ccw_adapter_by_cdev(struct ccw_device *cdev)
{
	struct zfcp_adapter *adapter;
	unsigned long flags;

	spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags);
	adapter = dev_get_drvdata(&cdev->dev);
	if (adapter)
		kref_get(&adapter->ref);
	spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags);
	return adapter;
}

void zfcp_ccw_adapter_put(struct zfcp_adapter *adapter)
{
	unsigned long flags;

	spin_lock_irqsave(&zfcp_ccw_adapter_ref_lock, flags);
	kref_put(&adapter->ref, zfcp_adapter_release);
	spin_unlock_irqrestore(&zfcp_ccw_adapter_ref_lock, flags);
}

static int zfcp_ccw_suspend(struct ccw_device *cdev)

{
	struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);

	if (!adapter)
		return 0;

	mutex_lock(&zfcp_data.config_mutex);

	zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL);
	zfcp_erp_wait(adapter);

	mutex_unlock(&zfcp_data.config_mutex);
	zfcp_ccw_adapter_put(adapter);

	return 0;
}
@@ -34,7 +56,7 @@ static int zfcp_ccw_suspend(struct ccw_device *cdev)
static int zfcp_ccw_activate(struct ccw_device *cdev)

{
	struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);

	if (!adapter)
		return 0;
@@ -46,6 +68,8 @@ static int zfcp_ccw_activate(struct ccw_device *cdev)
	zfcp_erp_wait(adapter);
	flush_work(&adapter->scan_work);

	zfcp_ccw_adapter_put(adapter);

	return 0;
}

@@ -67,28 +91,28 @@ int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter)

/**
 * zfcp_ccw_probe - probe function of zfcp driver
 * @ccw_device: pointer to belonging ccw device
 * @cdev: pointer to belonging ccw device
 *
 * 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)
static int zfcp_ccw_probe(struct ccw_device *cdev)
{
	return 0;
}

/**
 * zfcp_ccw_remove - remove function of zfcp driver
 * @ccw_device: pointer to belonging ccw device
 * @cdev: pointer to belonging ccw device
 *
 * This function gets called by the common i/o layer and removes an adapter
 * from the system. Task of this function is to get rid of all units and
 * ports that belong to this adapter. And in addition all resources of this
 * adapter will be freed too.
 */
static void zfcp_ccw_remove(struct ccw_device *ccw_device)
static void zfcp_ccw_remove(struct ccw_device *cdev)
{
	struct zfcp_adapter *adapter;
	struct zfcp_port *port, *p;
@@ -96,22 +120,12 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
	LIST_HEAD(unit_remove_lh);
	LIST_HEAD(port_remove_lh);

	ccw_device_set_offline(ccw_device);

	mutex_lock(&zfcp_data.config_mutex);
	adapter = dev_get_drvdata(&ccw_device->dev);
	mutex_unlock(&zfcp_data.config_mutex);
	ccw_device_set_offline(cdev);

	adapter = zfcp_ccw_adapter_by_cdev(cdev);
	if (!adapter)
		return;

	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(&adapter->port_list_lock);
	list_for_each_entry_safe(port, p, &adapter->port_list, list) {
		write_lock(&port->unit_list_lock);
@@ -126,7 +140,7 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
	}
	atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
	write_unlock_irq(&adapter->port_list_lock);
	mutex_unlock(&zfcp_data.config_mutex);
	zfcp_ccw_adapter_put(adapter); /* put from zfcp_ccw_adapter_by_cdev */

	list_for_each_entry_safe(unit, u, &unit_remove_lh, list)
		zfcp_device_unregister(&unit->sysfs_device,
@@ -136,12 +150,12 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
		zfcp_device_unregister(&port->sysfs_device,
				       &zfcp_sysfs_port_attrs);

	kref_put(&adapter->ref, zfcp_adapter_release);
	zfcp_adapter_unregister(adapter);
}

/**
 * zfcp_ccw_set_online - set_online function of zfcp driver
 * @ccw_device: pointer to belonging ccw device
 * @cdev: pointer to belonging ccw device
 *
 * This function gets called by the common i/o layer and sets an
 * adapter into state online.  The first call will allocate all
@@ -152,23 +166,20 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
 * 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 *cdev)
{
	struct zfcp_adapter *adapter;
	int ret = 0;

	mutex_lock(&zfcp_data.config_mutex);
	adapter = dev_get_drvdata(&ccw_device->dev);
	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);

	if (!adapter) {
		ret = zfcp_adapter_enqueue(ccw_device);
		if (ret) {
			dev_err(&ccw_device->dev,
		adapter = zfcp_adapter_enqueue(cdev);

		if (IS_ERR(adapter)) {
			dev_err(&cdev->dev,
				"Setting up data structures for the "
				"FCP adapter failed\n");
			goto out;
			return PTR_ERR(adapter);
		}
		adapter = dev_get_drvdata(&ccw_device->dev);
		kref_get(&adapter->ref);
	}

	/* initialize request counter */
@@ -180,58 +191,61 @@ 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:
	mutex_unlock(&zfcp_data.config_mutex);
	if (!ret)

	flush_work(&adapter->scan_work);
	return ret;

	zfcp_ccw_adapter_put(adapter);
	return 0;
}

/**
 * zfcp_ccw_set_offline - set_offline function of zfcp driver
 * @ccw_device: pointer to belonging ccw device
 * @cdev: pointer to belonging ccw device
 *
 * This function gets called by the common i/o layer and sets an adapter
 * into state offline.
 */
static int zfcp_ccw_set_offline(struct ccw_device *ccw_device)
static int zfcp_ccw_set_offline(struct ccw_device *cdev)
{
	struct zfcp_adapter *adapter;
	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);

	if (!adapter)
		return 0;

	mutex_lock(&zfcp_data.config_mutex);
	adapter = dev_get_drvdata(&ccw_device->dev);
	zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL);
	zfcp_erp_wait(adapter);
	mutex_unlock(&zfcp_data.config_mutex);

	zfcp_ccw_adapter_put(adapter);
	return 0;
}

/**
 * zfcp_ccw_notify - ccw notify function
 * @ccw_device: pointer to belonging ccw device
 * @cdev: pointer to belonging ccw device
 * @event: indicates if adapter was detached or attached
 *
 * This function gets called by the common i/o layer if an adapter has gone
 * or reappeared.
 */
static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
static int zfcp_ccw_notify(struct ccw_device *cdev, int event)
{
	struct zfcp_adapter *adapter = dev_get_drvdata(&ccw_device->dev);
	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);

	if (!adapter)
		return 1;

	switch (event) {
	case CIO_GONE:
		dev_warn(&adapter->ccw_device->dev,
			 "The FCP device has been detached\n");
		dev_warn(&cdev->dev, "The FCP device has been detached\n");
		zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1", NULL);
		break;
	case CIO_NO_PATH:
		dev_warn(&adapter->ccw_device->dev,
		dev_warn(&cdev->dev,
			 "The CHPID for the FCP device is offline\n");
		zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2", NULL);
		break;
	case CIO_OPER:
		dev_info(&adapter->ccw_device->dev,
			 "The FCP device is operational again\n");
		dev_info(&cdev->dev, "The FCP device is operational again\n");
		zfcp_erp_modify_adapter_status(adapter, "ccnoti3", NULL,
					       ZFCP_STATUS_COMMON_RUNNING,
					       ZFCP_SET);
@@ -239,11 +253,13 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
					"ccnoti4", NULL);
		break;
	case CIO_BOXED:
		dev_warn(&adapter->ccw_device->dev, "The FCP device "
			 "did not respond within the specified time\n");
		dev_warn(&cdev->dev, "The FCP device did not respond within "
				     "the specified time\n");
		zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL);
		break;
	}

	zfcp_ccw_adapter_put(adapter);
	return 1;
}

@@ -253,18 +269,16 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
 */
static void zfcp_ccw_shutdown(struct ccw_device *cdev)
{
	struct zfcp_adapter *adapter;
	struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);

	mutex_lock(&zfcp_data.config_mutex);
	adapter = dev_get_drvdata(&cdev->dev);
	if (!adapter)
		goto out;
		return;

	zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL);
	zfcp_erp_wait(adapter);
	zfcp_erp_thread_kill(adapter);
out:
	mutex_unlock(&zfcp_data.config_mutex);

	zfcp_ccw_adapter_put(adapter);
}

struct ccw_driver zfcp_ccw_driver = {
+10 −15
Original line number Diff line number Diff line
@@ -86,22 +86,17 @@ static int zfcp_cfdc_copy_to_user(void __user *user_buffer,
static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno)
{
	char busid[9];
	struct ccw_device *ccwdev;
	struct zfcp_adapter *adapter = NULL;
	struct ccw_device *cdev;
	struct zfcp_adapter *adapter;

	snprintf(busid, sizeof(busid), "0.0.%04x", devno);
	ccwdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
	if (!ccwdev)
		goto out;

	adapter = dev_get_drvdata(&ccwdev->dev);
	if (!adapter)
		goto out_put;

	kref_get(&adapter->ref);
out_put:
	put_device(&ccwdev->dev);
out:
	cdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
	if (!cdev)
		return NULL;

	adapter = zfcp_ccw_adapter_by_cdev(cdev);

	put_device(&cdev->dev);
	return adapter;
}

@@ -244,7 +239,7 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
 free_sg:
	zfcp_sg_free_table(fsf_cfdc->sg, ZFCP_CFDC_PAGES);
 adapter_put:
	kref_put(&adapter->ref, zfcp_adapter_release);
	zfcp_ccw_adapter_put(adapter);
 free_buffer:
	kfree(data);
 no_mem_sense:
+0 −1
Original line number Diff line number Diff line
@@ -595,7 +595,6 @@ struct zfcp_fsf_req {
struct zfcp_data {
	struct scsi_host_template scsi_host_template;
	struct scsi_transport_template *scsi_transport_template;
	struct mutex		config_mutex;
	struct kmem_cache	*gpn_ft_cache;
	struct kmem_cache	*qtcb_cache;
	struct kmem_cache	*sr_buffer_cache;
+4 −1
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
/* zfcp_aux.c */
extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *, u64);
extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *, u64);
extern int zfcp_adapter_enqueue(struct ccw_device *);
extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *);
extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32,
					   u32);
extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, u64);
@@ -24,11 +24,14 @@ extern int zfcp_sg_setup_table(struct scatterlist *, int);
extern void zfcp_device_unregister(struct device *,
				   const struct attribute_group *);
extern void zfcp_adapter_release(struct kref *);
extern void zfcp_adapter_unregister(struct zfcp_adapter *);

/* zfcp_ccw.c */
extern int zfcp_ccw_register(void);
extern int zfcp_ccw_priv_sch(struct zfcp_adapter *);
extern struct ccw_driver zfcp_ccw_driver;
extern struct zfcp_adapter *zfcp_ccw_adapter_by_cdev(struct ccw_device *);
extern void zfcp_ccw_adapter_put(struct zfcp_adapter *);

/* zfcp_cfdc.c */
extern struct miscdevice zfcp_cfdc_misc;
Loading