Commit d0a7e574 authored by James Bottomley's avatar James Bottomley Committed by James Bottomley

[SCSI] correct transport class abstraction to work outside SCSI

I recently tried to construct a totally generic transport class and
found there were certain features missing from the current abstract
transport class.  Most notable is that you have to hang the data on the
class_device but most of the API is framed in terms of the generic
device, not the class_device.

These changes are two fold

- Provide the class_device to all of the setup and configure APIs
- Provide and extra API to take the device and the attribute class and
  return the corresponding class_device
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 10c1b889
...@@ -58,6 +58,7 @@ attribute_container_register(struct attribute_container *cont) ...@@ -58,6 +58,7 @@ attribute_container_register(struct attribute_container *cont)
{ {
INIT_LIST_HEAD(&cont->node); INIT_LIST_HEAD(&cont->node);
INIT_LIST_HEAD(&cont->containers); INIT_LIST_HEAD(&cont->containers);
spin_lock_init(&cont->containers_lock);
down(&attribute_container_mutex); down(&attribute_container_mutex);
list_add_tail(&cont->node, &attribute_container_list); list_add_tail(&cont->node, &attribute_container_list);
...@@ -77,11 +78,13 @@ attribute_container_unregister(struct attribute_container *cont) ...@@ -77,11 +78,13 @@ attribute_container_unregister(struct attribute_container *cont)
{ {
int retval = -EBUSY; int retval = -EBUSY;
down(&attribute_container_mutex); down(&attribute_container_mutex);
spin_lock(&cont->containers_lock);
if (!list_empty(&cont->containers)) if (!list_empty(&cont->containers))
goto out; goto out;
retval = 0; retval = 0;
list_del(&cont->node); list_del(&cont->node);
out: out:
spin_unlock(&cont->containers_lock);
up(&attribute_container_mutex); up(&attribute_container_mutex);
return retval; return retval;
...@@ -151,7 +154,9 @@ attribute_container_add_device(struct device *dev, ...@@ -151,7 +154,9 @@ attribute_container_add_device(struct device *dev,
fn(cont, dev, &ic->classdev); fn(cont, dev, &ic->classdev);
else else
attribute_container_add_class_device(&ic->classdev); attribute_container_add_class_device(&ic->classdev);
spin_lock(&cont->containers_lock);
list_add_tail(&ic->node, &cont->containers); list_add_tail(&ic->node, &cont->containers);
spin_unlock(&cont->containers_lock);
} }
up(&attribute_container_mutex); up(&attribute_container_mutex);
} }
...@@ -189,6 +194,7 @@ attribute_container_remove_device(struct device *dev, ...@@ -189,6 +194,7 @@ attribute_container_remove_device(struct device *dev,
if (!cont->match(cont, dev)) if (!cont->match(cont, dev))
continue; continue;
spin_lock(&cont->containers_lock);
list_for_each_entry_safe(ic, tmp, &cont->containers, node) { list_for_each_entry_safe(ic, tmp, &cont->containers, node) {
if (dev != ic->classdev.dev) if (dev != ic->classdev.dev)
continue; continue;
...@@ -200,6 +206,7 @@ attribute_container_remove_device(struct device *dev, ...@@ -200,6 +206,7 @@ attribute_container_remove_device(struct device *dev,
class_device_unregister(&ic->classdev); class_device_unregister(&ic->classdev);
} }
} }
spin_unlock(&cont->containers_lock);
} }
up(&attribute_container_mutex); up(&attribute_container_mutex);
} }
...@@ -230,10 +237,12 @@ attribute_container_device_trigger(struct device *dev, ...@@ -230,10 +237,12 @@ attribute_container_device_trigger(struct device *dev,
if (!cont->match(cont, dev)) if (!cont->match(cont, dev))
continue; continue;
spin_lock(&cont->containers_lock);
list_for_each_entry_safe(ic, tmp, &cont->containers, node) { list_for_each_entry_safe(ic, tmp, &cont->containers, node) {
if (dev == ic->classdev.dev) if (dev == ic->classdev.dev)
fn(cont, dev, &ic->classdev); fn(cont, dev, &ic->classdev);
} }
spin_unlock(&cont->containers_lock);
} }
up(&attribute_container_mutex); up(&attribute_container_mutex);
} }
...@@ -368,6 +377,35 @@ attribute_container_class_device_del(struct class_device *classdev) ...@@ -368,6 +377,35 @@ attribute_container_class_device_del(struct class_device *classdev)
} }
EXPORT_SYMBOL_GPL(attribute_container_class_device_del); EXPORT_SYMBOL_GPL(attribute_container_class_device_del);
/**
* attribute_container_find_class_device - find the corresponding class_device
*
* @cont: the container
* @dev: the generic device
*
* Looks up the device in the container's list of class devices and returns
* the corresponding class_device.
*/
struct class_device *
attribute_container_find_class_device(struct attribute_container *cont,
struct device *dev)
{
struct class_device *cdev = NULL;
struct internal_container *ic;
spin_lock(&cont->containers_lock);
list_for_each_entry(ic, &cont->containers, node) {
if (ic->classdev.dev == dev) {
cdev = &ic->classdev;
break;
}
}
spin_unlock(&cont->containers_lock);
return cdev;
}
EXPORT_SYMBOL_GPL(attribute_container_find_class_device);
int __init int __init
attribute_container_init(void) attribute_container_init(void)
{ {
......
...@@ -64,7 +64,9 @@ void transport_class_unregister(struct transport_class *tclass) ...@@ -64,7 +64,9 @@ void transport_class_unregister(struct transport_class *tclass)
} }
EXPORT_SYMBOL_GPL(transport_class_unregister); EXPORT_SYMBOL_GPL(transport_class_unregister);
static int anon_transport_dummy_function(struct device *dev) static int anon_transport_dummy_function(struct transport_container *tc,
struct device *dev,
struct class_device *cdev)
{ {
/* do nothing */ /* do nothing */
return 0; return 0;
...@@ -115,9 +117,10 @@ static int transport_setup_classdev(struct attribute_container *cont, ...@@ -115,9 +117,10 @@ static int transport_setup_classdev(struct attribute_container *cont,
struct class_device *classdev) struct class_device *classdev)
{ {
struct transport_class *tclass = class_to_transport_class(cont->class); struct transport_class *tclass = class_to_transport_class(cont->class);
struct transport_container *tcont = attribute_container_to_transport_container(cont);
if (tclass->setup) if (tclass->setup)
tclass->setup(dev); tclass->setup(tcont, dev, classdev);
return 0; return 0;
} }
...@@ -178,12 +181,14 @@ void transport_add_device(struct device *dev) ...@@ -178,12 +181,14 @@ void transport_add_device(struct device *dev)
EXPORT_SYMBOL_GPL(transport_add_device); EXPORT_SYMBOL_GPL(transport_add_device);
static int transport_configure(struct attribute_container *cont, static int transport_configure(struct attribute_container *cont,
struct device *dev) struct device *dev,
struct class_device *cdev)
{ {
struct transport_class *tclass = class_to_transport_class(cont->class); struct transport_class *tclass = class_to_transport_class(cont->class);
struct transport_container *tcont = attribute_container_to_transport_container(cont);
if (tclass->configure) if (tclass->configure)
tclass->configure(dev); tclass->configure(tcont, dev, cdev);
return 0; return 0;
} }
...@@ -202,7 +207,7 @@ static int transport_configure(struct attribute_container *cont, ...@@ -202,7 +207,7 @@ static int transport_configure(struct attribute_container *cont,
*/ */
void transport_configure_device(struct device *dev) void transport_configure_device(struct device *dev)
{ {
attribute_container_trigger(dev, transport_configure); attribute_container_device_trigger(dev, transport_configure);
} }
EXPORT_SYMBOL_GPL(transport_configure_device); EXPORT_SYMBOL_GPL(transport_configure_device);
...@@ -215,7 +220,7 @@ static int transport_remove_classdev(struct attribute_container *cont, ...@@ -215,7 +220,7 @@ static int transport_remove_classdev(struct attribute_container *cont,
struct transport_class *tclass = class_to_transport_class(cont->class); struct transport_class *tclass = class_to_transport_class(cont->class);
if (tclass->remove) if (tclass->remove)
tclass->remove(dev); tclass->remove(tcont, dev, classdev);
if (tclass->remove != anon_transport_dummy_function) { if (tclass->remove != anon_transport_dummy_function) {
if (tcont->statistics) if (tcont->statistics)
......
...@@ -252,7 +252,8 @@ struct fc_internal { ...@@ -252,7 +252,8 @@ struct fc_internal {
#define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t) #define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t)
static int fc_target_setup(struct device *dev) static int fc_target_setup(struct transport_container *tc, struct device *dev,
struct class_device *cdev)
{ {
struct scsi_target *starget = to_scsi_target(dev); struct scsi_target *starget = to_scsi_target(dev);
struct fc_rport *rport = starget_to_rport(starget); struct fc_rport *rport = starget_to_rport(starget);
...@@ -281,7 +282,8 @@ static DECLARE_TRANSPORT_CLASS(fc_transport_class, ...@@ -281,7 +282,8 @@ static DECLARE_TRANSPORT_CLASS(fc_transport_class,
NULL, NULL,
NULL); NULL);
static int fc_host_setup(struct device *dev) static int fc_host_setup(struct transport_container *tc, struct device *dev,
struct class_device *cdev)
{ {
struct Scsi_Host *shost = dev_to_shost(dev); struct Scsi_Host *shost = dev_to_shost(dev);
......
...@@ -162,7 +162,8 @@ static inline enum spi_signal_type spi_signal_to_value(const char *name) ...@@ -162,7 +162,8 @@ static inline enum spi_signal_type spi_signal_to_value(const char *name)
return SPI_SIGNAL_UNKNOWN; return SPI_SIGNAL_UNKNOWN;
} }
static int spi_host_setup(struct device *dev) static int spi_host_setup(struct transport_container *tc, struct device *dev,
struct class_device *cdev)
{ {
struct Scsi_Host *shost = dev_to_shost(dev); struct Scsi_Host *shost = dev_to_shost(dev);
...@@ -196,7 +197,9 @@ static int spi_host_match(struct attribute_container *cont, ...@@ -196,7 +197,9 @@ static int spi_host_match(struct attribute_container *cont,
return &i->t.host_attrs.ac == cont; return &i->t.host_attrs.ac == cont;
} }
static int spi_device_configure(struct device *dev) static int spi_device_configure(struct transport_container *tc,
struct device *dev,
struct class_device *cdev)
{ {
struct scsi_device *sdev = to_scsi_device(dev); struct scsi_device *sdev = to_scsi_device(dev);
struct scsi_target *starget = sdev->sdev_target; struct scsi_target *starget = sdev->sdev_target;
...@@ -214,7 +217,9 @@ static int spi_device_configure(struct device *dev) ...@@ -214,7 +217,9 @@ static int spi_device_configure(struct device *dev)
return 0; return 0;
} }
static int spi_setup_transport_attrs(struct device *dev) static int spi_setup_transport_attrs(struct transport_container *tc,
struct device *dev,
struct class_device *cdev)
{ {
struct scsi_target *starget = to_scsi_target(dev); struct scsi_target *starget = to_scsi_target(dev);
......
...@@ -11,10 +11,12 @@ ...@@ -11,10 +11,12 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/spinlock.h>
struct attribute_container { struct attribute_container {
struct list_head node; struct list_head node;
struct list_head containers; struct list_head containers;
spinlock_t containers_lock;
struct class *class; struct class *class;
struct class_device_attribute **attrs; struct class_device_attribute **attrs;
int (*match)(struct attribute_container *, struct device *); int (*match)(struct attribute_container *, struct device *);
...@@ -62,12 +64,7 @@ int attribute_container_add_class_device_adapter(struct attribute_container *con ...@@ -62,12 +64,7 @@ int attribute_container_add_class_device_adapter(struct attribute_container *con
struct class_device *classdev); struct class_device *classdev);
void attribute_container_remove_attrs(struct class_device *classdev); void attribute_container_remove_attrs(struct class_device *classdev);
void attribute_container_class_device_del(struct class_device *classdev); void attribute_container_class_device_del(struct class_device *classdev);
struct class_device *attribute_container_find_class_device(struct attribute_container *, struct device *);
struct class_device_attribute **attribute_container_classdev_to_attrs(const struct class_device *classdev); struct class_device_attribute **attribute_container_classdev_to_attrs(const struct class_device *classdev);
#endif #endif
...@@ -12,11 +12,16 @@ ...@@ -12,11 +12,16 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/attribute_container.h> #include <linux/attribute_container.h>
struct transport_container;
struct transport_class { struct transport_class {
struct class class; struct class class;
int (*setup)(struct device *); int (*setup)(struct transport_container *, struct device *,
int (*configure)(struct device *); struct class_device *);
int (*remove)(struct device *); int (*configure)(struct transport_container *, struct device *,
struct class_device *);
int (*remove)(struct transport_container *, struct device *,
struct class_device *);
}; };
#define DECLARE_TRANSPORT_CLASS(cls, nm, su, rm, cfg) \ #define DECLARE_TRANSPORT_CLASS(cls, nm, su, rm, cfg) \
......
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