Commit b23c1202 authored by James Bottomley's avatar James Bottomley

move the SCSI transport classes over to the generic transport class

This converts the three transport classes (SPI, FC and iSCSI) over to
the generic transport class code.

It also converts the internals of the SCSI mid-layer to use generic
transport class trigger points and pulls out some of the duplicated code.
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 14cb343c
......@@ -28,6 +28,7 @@
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/transport_class.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
......@@ -79,15 +80,8 @@ void scsi_remove_host(struct Scsi_Host *shost)
set_bit(SHOST_DEL, &shost->shost_state);
if (shost->transportt->host_destroy)
shost->transportt->host_destroy(shost);
transport_unregister_device(&shost->shost_gendev);
class_device_unregister(&shost->shost_classdev);
if (shost->transport_classdev.class) {
if (shost->transportt->host_statistics)
sysfs_remove_group(&shost->transport_classdev.kobj,
shost->transportt->host_statistics);
class_device_unregister(&shost->transport_classdev);
}
device_del(&shost->shost_gendev);
}
EXPORT_SYMBOL(scsi_remove_host);
......@@ -135,9 +129,6 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
GFP_KERNEL)) == NULL)
goto out_del_classdev;
if (shost->transportt->host_setup)
shost->transportt->host_setup(shost);
error = scsi_sysfs_add_host(shost);
if (error)
goto out_destroy_host;
......@@ -146,8 +137,6 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
return error;
out_destroy_host:
if (shost->transportt->host_destroy)
shost->transportt->host_destroy(shost);
out_del_classdev:
class_device_del(&shost->shost_classdev);
out_del_gendev:
......@@ -397,3 +386,9 @@ void scsi_exit_hosts(void)
{
class_unregister(&shost_class);
}
int scsi_is_host_device(const struct device *dev)
{
return dev->release == scsi_host_dev_release;
}
EXPORT_SYMBOL(scsi_is_host_device);
......@@ -146,7 +146,7 @@ extern int scsi_sysfs_add_sdev(struct scsi_device *);
extern int scsi_sysfs_add_host(struct Scsi_Host *);
extern int scsi_sysfs_register(void);
extern void scsi_sysfs_unregister(void);
extern int scsi_sysfs_device_initialize(struct scsi_device *);
extern void scsi_sysfs_device_initialize(struct scsi_device *);
extern int scsi_sysfs_target_initialize(struct scsi_device *);
extern struct scsi_transport_template blank_transport_template;
......
......@@ -254,10 +254,7 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
sdev->request_queue->queuedata = sdev;
scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
if (shost->transportt->device_setup) {
if (shost->transportt->device_setup(sdev))
goto out_free_queue;
}
scsi_sysfs_device_initialize(sdev);
if (shost->hostt->slave_alloc) {
ret = shost->hostt->slave_alloc(sdev);
......@@ -272,10 +269,6 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
}
}
if (scsi_sysfs_device_initialize(sdev) != 0)
goto out_cleanup_slave;
/* NOTE: this target initialisation code depends critically on
* lun scanning being sequential. */
if (scsi_sysfs_target_initialize(sdev))
......@@ -288,13 +281,11 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
list_del(&sdev->siblings);
list_del(&sdev->same_target_siblings);
spin_unlock_irqrestore(shost->host_lock, flags);
out_cleanup_slave:
if (shost->hostt->slave_destroy)
shost->hostt->slave_destroy(sdev);
out_device_destroy:
if (shost->transportt->device_destroy)
shost->transportt->device_destroy(sdev);
out_free_queue:
transport_destroy_device(&sdev->sdev_gendev);
scsi_free_queue(sdev->request_queue);
out_free_dev:
kfree(sdev);
......@@ -629,8 +620,7 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
if (*bflags & BLIST_NOT_LOCKABLE)
sdev->lockable = 0;
if (sdev->host->transportt->device_configure)
sdev->host->transportt->device_configure(sdev);
transport_configure_device(&sdev->sdev_gendev);
if (sdev->host->hostt->slave_configure)
sdev->host->hostt->slave_configure(sdev);
......@@ -749,8 +739,7 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host,
} else {
if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev);
if (sdev->host->transportt->device_destroy)
sdev->host->transportt->device_destroy(sdev);
transport_destroy_device(&sdev->sdev_gendev);
put_device(&sdev->sdev_gendev);
}
out:
......@@ -1330,8 +1319,7 @@ void scsi_free_host_dev(struct scsi_device *sdev)
if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev);
if (sdev->host->transportt->device_destroy)
sdev->host->transportt->device_destroy(sdev);
transport_destroy_device(&sdev->sdev_gendev);
put_device(&sdev->sdev_gendev);
}
EXPORT_SYMBOL(scsi_free_host_dev);
......
......@@ -170,14 +170,12 @@ void scsi_device_dev_release(struct device *dev)
if (delete) {
struct scsi_target *starget = to_scsi_target(parent);
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
if (!starget->create) {
if (shost->transportt->target_destroy)
shost->transportt->target_destroy(starget);
transport_remove_device(&starget->dev);
device_del(parent);
if (starget->transport_classdev.class)
class_device_unregister(&starget->transport_classdev);
}
transport_destroy_device(&starget->dev);
put_device(parent);
}
if (sdev->request_queue)
......@@ -553,7 +551,6 @@ static void scsi_target_dev_release(struct device *dev)
**/
int scsi_sysfs_add_sdev(struct scsi_device *sdev)
{
struct class_device_attribute **attrs;
struct scsi_target *starget = sdev->sdev_target;
struct Scsi_Host *shost = sdev->host;
int error, i, create;
......@@ -570,31 +567,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
printk(KERN_ERR "Target device_add failed\n");
return error;
}
if (starget->transport_classdev.class) {
int i;
struct class_device_attribute **attrs =
sdev->host->transportt->target_attrs;
error = class_device_add(&starget->transport_classdev);
if (error) {
dev_printk(KERN_ERR, &starget->dev,
"Target transport add failed\n");
return error;
}
/* take a reference for the transport_classdev; this
* is released by the transport_class .release */
get_device(&starget->dev);
for (i = 0; attrs[i]; i++) {
error = class_device_create_file(&starget->transport_classdev,
attrs[i]);
if (error) {
dev_printk(KERN_ERR, &starget->dev,
"Target transport attr add failed\n");
return error;
}
}
}
transport_add_device(&starget->dev);
}
if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0)
......@@ -606,25 +579,15 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
printk(KERN_INFO "error 1\n");
return error;
}
error = class_device_add(&sdev->sdev_classdev);
if (error) {
printk(KERN_INFO "error 2\n");
goto clean_device;
}
/* take a reference for the sdev_classdev; this is
* released by the sdev_class .release */
get_device(&sdev->sdev_gendev);
if (sdev->transport_classdev.class) {
error = class_device_add(&sdev->transport_classdev);
if (error)
goto clean_device2;
/* take a reference for the transport_classdev; this
* is released by the transport_class .release */
get_device(&sdev->sdev_gendev);
}
if (sdev->host->hostt->sdev_attrs) {
for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {
error = attr_add(&sdev->sdev_gendev,
......@@ -650,27 +613,16 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
}
}
if (sdev->transport_classdev.class) {
attrs = sdev->host->transportt->device_attrs;
for (i = 0; attrs[i]; i++) {
error = class_device_create_file(&sdev->transport_classdev,
attrs[i]);
if (error) {
scsi_remove_device(sdev);
goto out;
}
}
}
transport_add_device(&sdev->sdev_gendev);
out:
return error;
clean_device2:
class_device_del(&sdev->sdev_classdev);
clean_device:
scsi_device_set_state(sdev, SDEV_CANCEL);
device_del(&sdev->sdev_gendev);
transport_destroy_device(&sdev->sdev_gendev);
put_device(&sdev->sdev_gendev);
return error;
......@@ -689,14 +641,11 @@ void scsi_remove_device(struct scsi_device *sdev)
goto out;
class_device_unregister(&sdev->sdev_classdev);
if (sdev->transport_classdev.class)
class_device_unregister(&sdev->transport_classdev);
device_del(&sdev->sdev_gendev);
scsi_device_set_state(sdev, SDEV_DEL);
if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev);
if (sdev->host->transportt->device_destroy)
sdev->host->transportt->device_destroy(sdev);
transport_unregister_device(&sdev->sdev_gendev);
put_device(&sdev->sdev_gendev);
out:
......@@ -786,41 +735,11 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost)
}
}
class_device_initialize(&shost->transport_classdev);
shost->transport_classdev.class = shost->transportt->host_class;
shost->transport_classdev.dev = &shost->shost_gendev;
snprintf(shost->transport_classdev.class_id, BUS_ID_SIZE,
"host%d", shost->host_no);
if (shost->transport_classdev.class) {
struct class_device_attribute **attrs =
shost->transportt->host_attrs;
error = class_device_add(&shost->transport_classdev);
if (error)
return error;
/* take a reference for the transport_classdev; this
* is released by the transport_class .release */
get_device(&shost->shost_gendev);
for (i = 0; attrs[i]; i++) {
error = class_device_create_file(&shost->transport_classdev,
attrs[i]);
if (error)
return error;
}
if (shost->transportt->host_statistics) {
error = sysfs_create_group(
&shost->transport_classdev.kobj,
shost->transportt->host_statistics);
if (error)
return error;
}
}
transport_register_device(&shost->shost_gendev);
return 0;
}
int scsi_sysfs_device_initialize(struct scsi_device *sdev)
void scsi_sysfs_device_initialize(struct scsi_device *sdev)
{
device_initialize(&sdev->sdev_gendev);
sdev->sdev_gendev.bus = &scsi_bus_type;
......@@ -836,14 +755,14 @@ int scsi_sysfs_device_initialize(struct scsi_device *sdev)
"%d:%d:%d:%d", sdev->host->host_no,
sdev->channel, sdev->id, sdev->lun);
class_device_initialize(&sdev->transport_classdev);
sdev->transport_classdev.dev = &sdev->sdev_gendev;
sdev->transport_classdev.class = sdev->host->transportt->device_class;
snprintf(sdev->transport_classdev.class_id, BUS_ID_SIZE,
"%d:%d:%d:%d", sdev->host->host_no,
sdev->channel, sdev->id, sdev->lun);
return 0;
transport_setup_device(&sdev->sdev_gendev);
}
int scsi_is_sdev_device(const struct device *dev)
{
return dev->release == scsi_device_dev_release;
}
EXPORT_SYMBOL(scsi_is_sdev_device);
int scsi_sysfs_target_initialize(struct scsi_device *sdev)
{
......@@ -886,12 +805,6 @@ int scsi_sysfs_target_initialize(struct scsi_device *sdev)
dev->release = scsi_target_dev_release;
sprintf(dev->bus_id, "target%d:%d:%d",
shost->host_no, sdev->channel, sdev->id);
class_device_initialize(&starget->transport_classdev);
starget->transport_classdev.dev = &starget->dev;
starget->transport_classdev.class = shost->transportt->target_class;
snprintf(starget->transport_classdev.class_id, BUS_ID_SIZE,
"target%d:%d:%d",
shost->host_no, sdev->channel, sdev->id);
starget->id = sdev->id;
starget->channel = sdev->channel;
create = starget->create = 1;
......@@ -907,11 +820,17 @@ int scsi_sysfs_target_initialize(struct scsi_device *sdev)
sdev->sdev_target = starget;
list_add_tail(&sdev->siblings, &shost->__devices);
spin_unlock_irqrestore(shost->host_lock, flags);
if (create && shost->transportt->target_setup)
shost->transportt->target_setup(starget);
if (create)
transport_setup_device(&starget->dev);
return 0;
}
int scsi_is_target_device(const struct device *dev)
{
return dev->release == scsi_target_dev_release;
}
EXPORT_SYMBOL(scsi_is_target_device);
/* A blank transport template that is used in drivers that don't
* yet implement Transport Attributes */
struct scsi_transport_template blank_transport_template = { NULL, };
......@@ -180,8 +180,6 @@ show_fc_fc4s (char *buf, u8 *fc4_list)
static void transport_class_release(struct class_device *class_dev);
static void host_class_release(struct class_device *class_dev);
static void fc_timeout_blocked_host(void *data);
static void fc_timeout_blocked_tgt(void *data);
......@@ -207,32 +205,9 @@ struct fc_internal {
#define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t)
struct class fc_transport_class = {
.name = "fc_transport",
.release = transport_class_release,
};
struct class fc_host_class = {
.name = "fc_host",
.release = host_class_release,
};
static __init int fc_transport_init(void)
{
int error = class_register(&fc_host_class);
if (error)
return error;
return class_register(&fc_transport_class);
}
static void __exit fc_transport_exit(void)
{
class_unregister(&fc_transport_class);
class_unregister(&fc_host_class);
}
static int fc_setup_starget_transport_attrs(struct scsi_target *starget)
static int fc_add_target(struct device *dev)
{
struct scsi_target *starget = to_scsi_target(dev);
/*
* Set default values easily detected by the midlayer as
* failure cases. The scsi lldd is responsible for initializing
......@@ -247,15 +222,24 @@ static int fc_setup_starget_transport_attrs(struct scsi_target *starget)
return 0;
}
static void fc_destroy_starget(struct scsi_target *starget)
static int fc_remove_target(struct device *dev)
{
struct scsi_target *starget = to_scsi_target(dev);
/* Stop the target timer */
if (cancel_delayed_work(&fc_starget_dev_loss_work(starget)))
flush_scheduled_work();
return 0;
}
static int fc_setup_host_transport_attrs(struct Scsi_Host *shost)
static DECLARE_TRANSPORT_CLASS(fc_transport_class,
"fc_transport",
fc_add_target,
fc_remove_target,
NULL);
static int fc_add_host(struct device *dev)
{
struct Scsi_Host *shost = dev_to_shost(dev);
/*
* Set default values easily detected by the midlayer as
* failure cases. The scsi lldd is responsible for initializing
......@@ -297,26 +281,35 @@ static int fc_setup_host_transport_attrs(struct Scsi_Host *shost)
return 0;
}
static void fc_destroy_host(struct Scsi_Host *shost)
static int fc_remove_host(struct device *dev)
{
struct Scsi_Host *shost = dev_to_shost(dev);
/* Stop the host timer */
if (cancel_delayed_work(&fc_host_link_down_work(shost)))
flush_scheduled_work();
return 0;
}
static void transport_class_release(struct class_device *class_dev)
static DECLARE_TRANSPORT_CLASS(fc_host_class,
"fc_host",
fc_add_host,
fc_remove_host,
NULL);
static __init int fc_transport_init(void)
{
struct scsi_target *starget = transport_class_to_starget(class_dev);
put_device(&starget->dev);
int error = transport_class_register(&fc_host_class);
if (error)
return error;
return transport_class_register(&fc_transport_class);
}
static void host_class_release(struct class_device *class_dev)
static void __exit fc_transport_exit(void)
{
struct Scsi_Host *shost = transport_class_to_shost(class_dev);
put_device(&shost->shost_gendev);
transport_class_unregister(&fc_transport_class);
transport_class_unregister(&fc_host_class);
}
/*
* Remote Port (Target) Attribute Management
*/
......@@ -731,6 +724,35 @@ static struct attribute_group fc_statistics_group = {
.attrs = fc_statistics_attrs,
};
static int fc_host_match(struct attribute_container *cont,
struct device *dev)
{
struct Scsi_Host *shost;
if (!scsi_is_host_device(dev))
return 0;
shost = dev_to_shost(dev);
if (!shost->transportt || shost->transportt->host_attrs.class
!= &fc_host_class.class)
return 0;
return 1;
}
static int fc_target_match(struct attribute_container *cont,
struct device *dev)
{
struct Scsi_Host *shost;
if (!scsi_is_target_device(dev))
return 0;
shost = dev_to_shost(dev->parent);
if (!shost->transportt || shost->transportt->host_attrs.class
!= &fc_host_class.class)
return 0;
return 1;
}
struct scsi_transport_template *
......@@ -745,16 +767,16 @@ fc_attach_transport(struct fc_function_template *ft)
memset(i, 0, sizeof(struct fc_internal));
i->t.target_attrs = &i->starget_attrs[0];
i->t.target_class = &fc_transport_class;
i->t.target_setup = &fc_setup_starget_transport_attrs;
i->t.target_destroy = &fc_destroy_starget;
i->t.target_attrs.attrs = &i->starget_attrs[0];
i->t.target_attrs.class = &fc_transport_class.class;
i->t.target_attrs.match = fc_target_match;
attribute_container_register(&i->t.target_attrs);
i->t.target_size = sizeof(struct fc_starget_attrs);
i->t.host_attrs = &i->host_attrs[0];
i->t.host_class = &fc_host_class;
i->t.host_setup = &fc_setup_host_transport_attrs;
i->t.host_destroy = &fc_destroy_host;
i->t.host_attrs.attrs = &i->host_attrs[0];
i->t.host_attrs.class = &fc_host_class.class;
i->t.host_attrs.match = fc_host_match;
attribute_container_register(&i->t.host_attrs);
i->t.host_size = sizeof(struct fc_host_attrs);
if (ft->get_fc_host_stats)
......
......@@ -40,28 +40,17 @@ struct iscsi_internal {
#define to_iscsi_internal(tmpl) container_of(tmpl, struct iscsi_internal, t)
static void iscsi_transport_class_release(struct class_device *class_dev)
{
struct scsi_target *starget = transport_class_to_starget(class_dev);
put_device(&starget->dev);
}
struct class iscsi_transport_class = {
.name = "iscsi_transport_class",
.release = iscsi_transport_class_release,
};
static void iscsi_host_class_release(struct class_device *class_dev)
{
struct Scsi_Host *shost = transport_class_to_shost(class_dev);
put_device(&shost->shost_gendev);
}
struct class iscsi_host_class = {
.name = "iscsi_host",
.release = iscsi_host_class_release,
};
static DECLARE_TRANSPORT_CLASS(iscsi_transport_class,
"iscsi_transport",
NULL,
NULL,
NULL);
static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
"iscsi_host",
NULL,
NULL,
NULL);
/*
* iSCSI target and session attrs
*/
......@@ -265,6 +254,36 @@ iscsi_host_rd_str_attr(initiator_alias);
count++; \
}
static int iscsi_host_match(struct attribute_container *cont,
struct device *dev)
{
struct Scsi_Host *shost;
if (!scsi_is_host_device(dev))
return 0;
shost = dev_to_shost(dev);
if (!shost->transportt || shost->transportt->host_attrs.class
!= &iscsi_host_class.class)
return 0;
return 1;
}
static int iscsi_target_match(struct attribute_container *cont,
struct device *dev)
{
struct Scsi_Host *shost;
if (!scsi_is_target_device(dev))
return 0;
shost = dev_to_shost(dev->parent);
if (!shost->transportt || shost->transportt->host_attrs.class
!= &iscsi_host_class.class)
return 0;
return 1;
}
struct scsi_transport_template *
iscsi_attach_transport(struct iscsi_function_template *fnt)
{
......@@ -278,9 +297,10 @@ iscsi_attach_transport(struct iscsi_function_template *fnt)
memset(i, 0, sizeof(struct iscsi_internal));
i->fnt = fnt;
i->t.target_attrs = &i->session_attrs[0];
i->t.target_class = &iscsi_transport_class;
i->t.target_setup = NULL;
i->t.target_attrs.attrs = &i->session_attrs[0];
i->t.target_attrs.class = &iscsi_transport_class.class;
i->t.target_attrs.match = iscsi_target_match;
attribute_container_register(&i->t.target_attrs);
i->t.target_size = sizeof(struct iscsi_class_session);
SETUP_SESSION_RD_ATTR(tsih);
......@@ -307,9 +327,10 @@ iscsi_attach_transport(struct iscsi_function_template *fnt)
BUG_ON(count > ISCSI_SESSION_ATTRS);
i->session_attrs[count] = NULL;
i->t.host_attrs = &i->host_attrs[0];
i->t.host_class = &iscsi_host_class;
i->t.host_setup = NULL;
i->t.host_attrs.attrs = &i->host_attrs[0];
i->t.host_attrs.class = &iscsi_host_class.class;
i->t.host_attrs.match = iscsi_host_match;
attribute_container_register(&i->t.host_attrs);
i->t.host_size = 0;
count = 0;
......@@ -334,17 +355,17 @@ EXPORT_SYMBOL(iscsi_release_transport);
static __init int iscsi_transport_init(void)
{
int err = class_register(&iscsi_transport_class);
int err = transport_class_register(&iscsi_transport_class);
if (err)
return err;
return class_register(&iscsi_host_class);
return transport_class_register(&iscsi_host_class);
}
static void __exit iscsi_transport_exit(void)
{
class_unregister(&iscsi_host_class);
class_unregister(&iscsi_transport_class);
transport_class_unregister(&iscsi_host_class);
transport_class_unregister(&iscsi_transport_class);
}
module_init(iscsi_transport_init);
......
......@@ -2,6 +2,7 @@
* Parallel SCSI (SPI) transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
* Copyright (c) 2004, 2005 James Bottomley <James.Bottomley@SteelEye.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -37,9 +38,6 @@
#define SPI_PRINTK(x, l, f, a...) dev_printk(l, &(x)->dev, f , ##a)
static void transport_class_release(struct class_device *class_dev);
static void host_class_release(struct class_device *class_dev);
#define SPI_NUM_ATTRS 10 /* increase this if you add attributes */
#define SPI_OTHER_ATTRS 1 /* Increase this if you add "always
* on" attributes */
......@@ -119,40 +117,39 @@ static inline enum spi_signal_type spi_signal_to_value(const char *name)
return SPI_SIGNAL_UNKNOWN;
}
static int spi_host_setup(struct device *dev)
{
struct Scsi_Host *shost = dev_to_shost(dev);
struct class spi_transport_class = {
.name = "spi_transport",
.release = transport_class_release,
};
struct class spi_host_class = {
.name = "spi_host",
.release = host_class_release,
};
spi_signalling(shost) = SPI_SIGNAL_UNKNOWN;
static __init int spi_transport_init(void)
{
int error = class_register(&spi_host_class);
if (error)
return error;
return class_register(&spi_transport_class);
return 0;
}
static void __exit spi_transport_exit(void)
{
class_unregister(&spi_transport_class);
class_unregister(&spi_host_class);
}
static DECLARE_TRANSPORT_CLASS(spi_host_class,
"spi_host",
spi_host_setup,
NULL,
NULL);
static int spi_setup_host_attrs(struct Scsi_Host *shost)
static int spi_host_match(struct attribute_container *cont,
struct device *dev)
{
spi_signalling(shost) = SPI_SIGNAL_UNKNOWN;
struct Scsi_Host *shost;
if (!scsi_is_host_device(dev))
return 0;
shost = dev_to_shost(dev);
if (!shost->transportt || shost->transportt->host_attrs.class
!= &spi_host_class.class)
return 0;
return 1;
}
static int spi_configure_device(struct scsi_device *sdev)
static int spi_device_configure(struct device *dev)
{
struct scsi_device *sdev = to_scsi_device(dev);
struct scsi_target *starget = sdev->sdev_target;
/* Populate the target capability fields with the values
......@@ -168,8 +165,10 @@ static int spi_configure_device(struct scsi_device *sdev)
return 0;
}
static int spi_setup_transport_attrs(struct scsi_target *starget)
static int spi_setup_transport_attrs(struct device *dev)
{
struct scsi_target *starget = to_scsi_target(dev);
spi_period(starget) = -1; /* illegal value */
spi_offset(starget) = 0; /* async */
spi_width(starget) = 0; /* narrow */
......@@ -187,18 +186,6 @@ static int spi_setup_transport_attrs(struct scsi_target *starget)
return 0;
}
static void transport_class_release(struct class_device *class_dev)
{
struct scsi_target *starget = transport_class_to_starget(class_dev);
put_device(&starget->dev);
}
static void host_class_release(struct class_device *class_dev)
{
struct Scsi_Host *shost = transport_class_to_shost(class_dev);
put_device(&shost->shost_gendev);
}
#define spi_transport_show_function(field, format_string) \
\
static ssize_t \
......@@ -823,6 +810,48 @@ EXPORT_SYMBOL(spi_schedule_dv_device);
i->host_attrs[count] = &i->private_host_attrs[count]; \
count++
static int spi_device_match(struct attribute_container *cont,
struct device *dev)
{
struct scsi_device *sdev;
struct Scsi_Host *shost;
if (!scsi_is_sdev_device(dev))
return 0;
sdev = to_scsi_device(dev);
shost = sdev->host;
if (!shost->transportt || shost->transportt->host_attrs.class
!= &spi_host_class.class)
return 0;
return 1;
}
static int spi_target_match(struct attribute_container *cont,
struct device *dev)
{
struct Scsi_Host *shost;
if (!scsi_is_target_device(dev))
return 0;
shost = dev_to_shost(dev->parent);
if (!shost->transportt || shost->transportt->host_attrs.class
!= &spi_host_class.class)
return 0;
return 1;
}
static DECLARE_TRANSPORT_CLASS(spi_transport_class,
"spi_transport",
spi_setup_transport_attrs,
NULL,
NULL);
static DECLARE_ANON_TRANSPORT_CLASS(spi_device_class,
spi_device_match,
spi_device_configure);
struct scsi_transport_template *
spi_attach_transport(struct spi_function_template *ft)
{
......@@ -835,14 +864,15 @@ spi_attach_transport(struct spi_function_template *ft)
memset(i, 0, sizeof(struct spi_internal));
i->t.target_attrs = &i->attrs[0];
i->t.target_class = &spi_transport_class;
i->t.target_setup = &spi_setup_transport_attrs;
i->t.device_configure = &spi_configure_device;
i->t.target_attrs.class = &spi_transport_class.class;
i->t.target_attrs.attrs = &i->attrs[0];
i->t.target_attrs.match = spi_target_match;
attribute_container_register(&i->t.target_attrs);
i->t.target_size = sizeof(struct spi_transport_attrs);
i->t.host_attrs = &i->host_attrs[0];
i->t.host_class = &spi_host_class;
i->t.host_setup = &spi_setup_host_attrs;
i->t.host_attrs.class = &spi_host_class.class;
i->t.host_attrs.attrs = &i->host_attrs[0];
i->t.host_attrs.match = spi_host_match;
attribute_container_register(&i->t.host_attrs);
i->t.host_size = sizeof(struct spi_host_attrs);
i->f = ft;
......@@ -884,6 +914,21 @@ void spi_release_transport(struct scsi_transport_template *t)
}
EXPORT_SYMBOL(spi_release_transport);
static __init int spi_transport_init(void)
{
int error = transport_class_register(&spi_transport_class);
if (error)
return error;
error = anon_transport_class_register(&spi_device_class);
return transport_class_register(&spi_host_class);
}
static void __exit spi_transport_exit(void)
{
transport_class_unregister(&spi_transport_class);
anon_transport_class_unregister(&spi_device_class);
transport_class_unregister(&spi_host_class);
}
MODULE_AUTHOR("Martin Hicks");
MODULE_DESCRIPTION("SPI Transport Attributes");
......
......@@ -123,8 +123,6 @@ struct scsi_device {
struct device sdev_gendev;
struct class_device sdev_classdev;
struct class_device transport_classdev;
enum scsi_device_state sdev_state;
unsigned long sdev_data[0];
} __attribute__((aligned(sizeof(unsigned long))));
......@@ -133,7 +131,7 @@ struct scsi_device {
#define class_to_sdev(d) \
container_of(d, struct scsi_device, sdev_classdev)
#define transport_class_to_sdev(class_dev) \
container_of(class_dev, struct scsi_device, transport_classdev)
to_scsi_device(class_dev->dev)
/*
* scsi_target: representation of a scsi target, for now, this is only
......@@ -146,7 +144,6 @@ struct scsi_target {
unsigned int channel;
unsigned int id; /* target id ... replace
* scsi_device.id eventually */
struct class_device transport_classdev;
unsigned long create:1; /* signal that it needs to be added */
unsigned long starget_data[0];
} __attribute__((aligned(sizeof(unsigned long))));
......@@ -157,7 +154,7 @@ static inline struct scsi_target *scsi_target(struct scsi_device *sdev)
return to_scsi_target(sdev->sdev_gendev.parent);
}
#define transport_class_to_starget(class_dev) \
container_of(class_dev, struct scsi_target, transport_classdev)
to_scsi_target(class_dev->dev)
extern struct scsi_device *__scsi_add_device(struct Scsi_Host *,
uint, uint, uint, void *hostdata);
......@@ -226,6 +223,8 @@ extern void scsi_device_resume(struct scsi_device *sdev);
extern void scsi_target_quiesce(struct scsi_target *);
extern void scsi_target_resume(struct scsi_target *);
extern const char *scsi_device_state_name(enum scsi_device_state);
extern int scsi_is_sdev_device(const struct device *);
extern int scsi_is_target_device(const struct device *);
static inline int scsi_device_online(struct scsi_device *sdev)
{
return sdev->sdev_state != SDEV_OFFLINE;
......
......@@ -528,7 +528,6 @@ struct Scsi_Host {
* separately
*/
void *shost_data;
struct class_device transport_classdev;
/*
* We should ensure that this is aligned, both for better performance
......@@ -542,8 +541,6 @@ struct Scsi_Host {
container_of(d, struct Scsi_Host, shost_gendev)
#define class_to_shost(d) \
container_of(d, struct Scsi_Host, shost_classdev)
#define transport_class_to_shost(class_dev) \
container_of(class_dev, struct Scsi_Host, transport_classdev)
extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int);
......@@ -578,6 +575,7 @@ static inline struct device *scsi_get_device(struct Scsi_Host *shost)
extern void scsi_unblock_requests(struct Scsi_Host *);
extern void scsi_block_requests(struct Scsi_Host *);
struct class_container;
/*
* These two functions are used to allocate and free a pseudo device
* which will connect to the host adapter itself rather than any
......@@ -587,6 +585,8 @@ extern void scsi_block_requests(struct Scsi_Host *);
*/
extern void scsi_free_host_dev(struct scsi_device *);
extern struct scsi_device *scsi_get_host_dev(struct Scsi_Host *);
int scsi_is_host_device(const struct device *);
/* legacy interfaces */
extern struct Scsi_Host *scsi_register(struct scsi_host_template *, int);
......
......@@ -20,31 +20,16 @@
#ifndef SCSI_TRANSPORT_H
#define SCSI_TRANSPORT_H
struct scsi_transport_template {
/* The NULL terminated list of transport attributes
* that should be exported.
*/
struct class_device_attribute **device_attrs;
struct class_device_attribute **target_attrs;
struct class_device_attribute **host_attrs;
#include <linux/transport_class.h>
/* The transport class that the device is in */
struct class *device_class;
struct class *target_class;
struct class *host_class;
struct scsi_transport_template {
/* The statistics attached to the host class only */
struct attribute_group *host_statistics;
/* Constructor functions */
int (*device_setup)(struct scsi_device *);
int (*device_configure)(struct scsi_device *);
int (*target_setup)(struct scsi_target *);
int (*host_setup)(struct Scsi_Host *);
/* Destructor functions */
void (*device_destroy)(struct scsi_device *);
void (*target_destroy)(struct scsi_target *);
void (*host_destroy)(struct Scsi_Host *);
/* the attribute containers */
struct attribute_container host_attrs;
struct attribute_container target_attrs;
struct attribute_container device_attrs;
/* The size of the specific transport attribute structure (a
* space of this size will be left at the end of the
......@@ -54,4 +39,8 @@ struct scsi_transport_template {
int host_size;
};
#define transport_class_to_shost(tc) \
dev_to_shost((tc)->dev)
#endif /* SCSI_TRANSPORT_H */
......@@ -21,6 +21,7 @@
#define SCSI_TRANSPORT_SPI_H
#include <linux/config.h>
#include <linux/transport_class.h>
struct scsi_transport_template;
......
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