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

Add SCSI transport attributes

From: 	Martin Hicks <mort@wildopensource.com>

Transport attributes are classes which can be
attached to by a scsi driver to export (and
later control) transport based properties.
parent b362c0a1
...@@ -196,6 +196,25 @@ config SCSI_LOGGING ...@@ -196,6 +196,25 @@ config SCSI_LOGGING
there should be no noticeable performance impact as long as you have there should be no noticeable performance impact as long as you have
logging turned off. logging turned off.
menu "SCSI Transport Attributes"
depends on SCSI
config SCSI_SPI_ATTRS
tristate "Parallel SCSI (SPI) Transport Attributes"
depends on SCSI
help
If you wish to export transport-specific information about
each attached SCSI device to sysfs, say Y. Otherwise, say N.
config SCSI_FC_ATTRS
tristate "FiberChannel Transport Attributes"
depends on SCSI
help
If you wish to export transport-specific information about
each attached FiberChannel device to sysfs, say Y.
Otherwise, say N.
endmenu
menu "SCSI low-level drivers" menu "SCSI low-level drivers"
depends on SCSI!=n depends on SCSI!=n
......
...@@ -22,6 +22,14 @@ subdir-$(CONFIG_PCMCIA) += pcmcia ...@@ -22,6 +22,14 @@ subdir-$(CONFIG_PCMCIA) += pcmcia
obj-$(CONFIG_SCSI) += scsi_mod.o obj-$(CONFIG_SCSI) += scsi_mod.o
# --- NOTE ORDERING HERE ---
# For kernel non-modular link, transport attributes need to
# be initialised before drivers
# --------------------------
obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.o
obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o
obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o
obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/unistd.h> #include <linux/unistd.h>
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
#include "scsi.h" #include "scsi.h"
#include "scsi_priv.h" #include "scsi_priv.h"
...@@ -222,6 +223,11 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) ...@@ -222,6 +223,11 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
shost->max_id = 8; shost->max_id = 8;
shost->max_lun = 8; shost->max_lun = 8;
/* Give each shost a default transportt if the driver
* doesn't yet support Transport Attributes */
if (!shost->transportt)
shost->transportt = &blank_transport_template;
/* /*
* All drivers right now should be able to handle 12 byte * All drivers right now should be able to handle 12 byte
* commands. Every so often there are requests for 16 byte * commands. Every so often there are requests for 16 byte
......
...@@ -156,6 +156,7 @@ extern int scsi_sysfs_add_sdev(struct scsi_device *); ...@@ -156,6 +156,7 @@ extern int scsi_sysfs_add_sdev(struct scsi_device *);
extern int scsi_sysfs_add_host(struct Scsi_Host *); extern int scsi_sysfs_add_host(struct Scsi_Host *);
extern int scsi_sysfs_register(void); extern int scsi_sysfs_register(void);
extern void scsi_sysfs_unregister(void); extern void scsi_sysfs_unregister(void);
extern struct scsi_transport_template blank_transport_template;
extern struct class sdev_class; extern struct class sdev_class;
extern struct bus_type scsi_bus_type; extern struct bus_type scsi_bus_type;
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <scsi/scsi_driver.h> #include <scsi/scsi_driver.h>
#include <scsi/scsi_devinfo.h> #include <scsi/scsi_devinfo.h>
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
#include "scsi.h" #include "scsi.h"
#include "scsi_priv.h" #include "scsi_priv.h"
...@@ -192,7 +193,7 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, ...@@ -192,7 +193,7 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
struct scsi_device *sdev, *device; struct scsi_device *sdev, *device;
unsigned long flags; unsigned long flags;
sdev = kmalloc(sizeof(*sdev), GFP_ATOMIC); sdev = kmalloc(sizeof(*sdev) + shost->transportt->size, GFP_ATOMIC);
if (!sdev) if (!sdev)
goto out; goto out;
...@@ -237,6 +238,11 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, ...@@ -237,6 +238,11 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
goto out_free_queue; goto out_free_queue;
} }
if (shost->transportt->setup) {
if (shost->transportt->setup(sdev))
goto out_cleanup_slave;
}
if (get_device(&sdev->host->shost_gendev)) { if (get_device(&sdev->host->shost_gendev)) {
device_initialize(&sdev->sdev_gendev); device_initialize(&sdev->sdev_gendev);
...@@ -253,8 +259,15 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, ...@@ -253,8 +259,15 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE, snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE,
"%d:%d:%d:%d", sdev->host->host_no, "%d:%d:%d:%d", sdev->host->host_no,
sdev->channel, sdev->id, sdev->lun); 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->class;
snprintf(sdev->transport_classdev.class_id, BUS_ID_SIZE,
"%d:%d:%d:%d", sdev->host->host_no,
sdev->channel, sdev->id, sdev->lun);
} else } else
goto out_cleanup_slave; goto out_cleanup_transport;
/* /*
* If there are any same target siblings, add this to the * If there are any same target siblings, add this to the
...@@ -283,6 +296,9 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, ...@@ -283,6 +296,9 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
spin_unlock_irqrestore(shost->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
return sdev; return sdev;
out_cleanup_transport:
if (shost->transportt->cleanup)
shost->transportt->cleanup(sdev);
out_cleanup_slave: out_cleanup_slave:
if (shost->hostt->slave_destroy) if (shost->hostt->slave_destroy)
shost->hostt->slave_destroy(sdev); shost->hostt->slave_destroy(sdev);
...@@ -744,6 +760,8 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host, ...@@ -744,6 +760,8 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host,
} else { } else {
if (sdev->host->hostt->slave_destroy) if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev); sdev->host->hostt->slave_destroy(sdev);
if (sdev->host->transportt->cleanup)
sdev->host->transportt->cleanup(sdev);
put_device(&sdev->sdev_gendev); put_device(&sdev->sdev_gendev);
} }
out: out:
...@@ -1300,5 +1318,7 @@ void scsi_free_host_dev(struct scsi_device *sdev) ...@@ -1300,5 +1318,7 @@ void scsi_free_host_dev(struct scsi_device *sdev)
if (sdev->host->hostt->slave_destroy) if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev); sdev->host->hostt->slave_destroy(sdev);
if (sdev->host->transportt->cleanup)
sdev->host->transportt->cleanup(sdev);
put_device(&sdev->sdev_gendev); put_device(&sdev->sdev_gendev);
} }
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
#include "scsi.h" #include "scsi.h"
#include "scsi_priv.h" #include "scsi_priv.h"
...@@ -349,6 +350,7 @@ static int attr_add(struct device *dev, struct device_attribute *attr) ...@@ -349,6 +350,7 @@ static int attr_add(struct device *dev, struct device_attribute *attr)
**/ **/
int scsi_sysfs_add_sdev(struct scsi_device *sdev) int scsi_sysfs_add_sdev(struct scsi_device *sdev)
{ {
struct class_device_attribute **attrs;
int error = -EINVAL, i; int error = -EINVAL, i;
if (sdev->sdev_state != SDEV_CREATED) if (sdev->sdev_state != SDEV_CREATED)
...@@ -368,6 +370,12 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) ...@@ -368,6 +370,12 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
goto clean_device; goto clean_device;
} }
if (sdev->transport_classdev.class) {
error = class_device_add(&sdev->transport_classdev);
if (error)
goto clean_device2;
}
get_device(&sdev->sdev_gendev); get_device(&sdev->sdev_gendev);
if (sdev->host->hostt->sdev_attrs) { if (sdev->host->hostt->sdev_attrs) {
...@@ -393,10 +401,24 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) ...@@ -393,10 +401,24 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
} }
} }
if (sdev->transport_classdev.class) {
attrs = sdev->host->transportt->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;
}
}
}
out: out:
return error; return error;
clean_device: clean_device2:
class_device_del(&sdev->sdev_classdev);
clean_device:
sdev->sdev_state = SDEV_CANCEL; sdev->sdev_state = SDEV_CANCEL;
device_del(&sdev->sdev_gendev); device_del(&sdev->sdev_gendev);
...@@ -414,9 +436,12 @@ void scsi_remove_device(struct scsi_device *sdev) ...@@ -414,9 +436,12 @@ void scsi_remove_device(struct scsi_device *sdev)
if (sdev->sdev_state == SDEV_RUNNING || sdev->sdev_state == SDEV_CANCEL) { if (sdev->sdev_state == SDEV_RUNNING || sdev->sdev_state == SDEV_CANCEL) {
sdev->sdev_state = SDEV_DEL; sdev->sdev_state = SDEV_DEL;
class_device_unregister(&sdev->sdev_classdev); class_device_unregister(&sdev->sdev_classdev);
class_device_unregister(&sdev->transport_classdev);
device_del(&sdev->sdev_gendev); device_del(&sdev->sdev_gendev);
if (sdev->host->hostt->slave_destroy) if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev); sdev->host->hostt->slave_destroy(sdev);
if (sdev->host->transportt->cleanup)
sdev->host->transportt->cleanup(sdev);
put_device(&sdev->sdev_gendev); put_device(&sdev->sdev_gendev);
} }
} }
...@@ -503,3 +528,7 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost) ...@@ -503,3 +528,7 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost)
return 0; return 0;
} }
/* A blank transport template that is used in drivers that don't
* yet implement Transport Attributes */
struct scsi_transport_template blank_transport_template = { 0, };
/*
* FiberChannel transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/init.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_fc.h>
static void transport_class_release(struct class_device *class_dev);
struct class fc_transport_class = {
.name = "fc_transport",
.release = transport_class_release,
};
static __init int fc_transport_init(void)
{
return class_register(&fc_transport_class);
}
static void __exit fc_transport_exit(void)
{
class_unregister(&fc_transport_class);
}
static int fc_setup_transport_attrs(struct scsi_device *sdev)
{
/* FIXME: Callback into the driver */
fc_node_name(sdev) = -1;
fc_port_name(sdev) = -1;
fc_port_id(sdev) = -1;
return 0;
}
static void transport_class_release(struct class_device *class_dev)
{
struct scsi_device *sdev = transport_class_to_sdev(class_dev);
put_device(&sdev->sdev_gendev);
}
#define fc_transport_show_function(field, format_string, cast) \
static ssize_t \
show_fc_transport_##field (struct class_device *cdev, char *buf) \
{ \
struct scsi_device *sdev = transport_class_to_sdev(cdev); \
struct fc_transport_attrs *tp; \
tp = (struct fc_transport_attrs *)&sdev->transport_data; \
return snprintf(buf, 20, format_string, cast tp->field); \
}
#define fc_transport_rd_attr(field, format_string) \
fc_transport_show_function(field, format_string, ) \
static CLASS_DEVICE_ATTR( field, S_IRUGO, show_fc_transport_##field, NULL)
#define fc_transport_rd_attr_cast(field, format_string, cast) \
fc_transport_show_function(field, format_string, (cast)) \
static CLASS_DEVICE_ATTR( field, S_IRUGO, show_fc_transport_##field, NULL)
/* the FiberChannel Tranport Attributes: */
fc_transport_rd_attr_cast(node_name, "0x%llx\n", unsigned long long);
fc_transport_rd_attr_cast(port_name, "0x%llx\n", unsigned long long);
fc_transport_rd_attr(port_id, "0x%06x\n");
struct class_device_attribute *fc_transport_attrs[] = {
&class_device_attr_node_name,
&class_device_attr_port_name,
&class_device_attr_port_id,
NULL
};
struct scsi_transport_template fc_transport_template = {
.attrs = fc_transport_attrs,
.class = &fc_transport_class,
.setup = &fc_setup_transport_attrs,
.cleanup = NULL,
.size = sizeof(struct fc_transport_attrs) - sizeof(unsigned long),
};
EXPORT_SYMBOL(fc_transport_template);
MODULE_AUTHOR("Martin Hicks");
MODULE_DESCRIPTION("FC Transport Attributes");
MODULE_LICENSE("GPL");
module_init(fc_transport_init);
module_exit(fc_transport_exit);
/*
* Parallel SCSI (SPI) transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/init.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_spi.h>
static void transport_class_release(struct class_device *class_dev);
struct class spi_transport_class = {
.name = "spi_transport",
.release = transport_class_release,
};
static __init int spi_transport_init(void)
{
return class_register(&spi_transport_class);
}
static void __exit spi_transport_exit(void)
{
class_unregister(&spi_transport_class);
}
static int spi_setup_transport_attrs(struct scsi_device *sdev)
{
/* FIXME: should callback into the driver to get these values */
spi_period(sdev) = -1;
spi_offset(sdev) = -1;
return 0;
}
static void transport_class_release(struct class_device *class_dev)
{
struct scsi_device *sdev = transport_class_to_sdev(class_dev);
put_device(&sdev->sdev_gendev);
}
#define spi_transport_show_function(field, format_string) \
static ssize_t \
show_spi_transport_##field (struct class_device *cdev, char *buf) \
{ \
struct scsi_device *sdev = transport_class_to_sdev(cdev); \
struct spi_transport_attrs *tp; \
tp = (struct spi_transport_attrs *)&sdev->transport_data; \
return snprintf(buf, 20, format_string, tp->field); \
}
#define spi_transport_rd_attr(field, format_string) \
spi_transport_show_function(field, format_string) \
static CLASS_DEVICE_ATTR( field, S_IRUGO, show_spi_transport_##field, NULL)
/* The Parallel SCSI Tranport Attributes: */
spi_transport_rd_attr(period, "%d\n");
spi_transport_rd_attr(offset, "%d\n");
struct class_device_attribute *spi_transport_attrs[] = {
&class_device_attr_period,
&class_device_attr_offset,
NULL
};
struct scsi_transport_template spi_transport_template = {
.attrs = spi_transport_attrs,
.class = &spi_transport_class,
.setup = &spi_setup_transport_attrs,
.cleanup = NULL,
.size = sizeof(struct spi_transport_attrs) - sizeof(unsigned long),
};
EXPORT_SYMBOL(spi_transport_template);
MODULE_AUTHOR("Martin Hicks");
MODULE_DESCRIPTION("SPI Transport Attributes");
MODULE_LICENSE("GPL");
module_init(spi_transport_init);
module_exit(spi_transport_exit);
...@@ -104,12 +104,17 @@ struct scsi_device { ...@@ -104,12 +104,17 @@ struct scsi_device {
struct device sdev_gendev; struct device sdev_gendev;
struct class_device sdev_classdev; struct class_device sdev_classdev;
struct class_device transport_classdev;
enum scsi_device_state sdev_state; enum scsi_device_state sdev_state;
}; unsigned long transport_data[0];
} __attribute__((aligned(sizeof(unsigned long))));
#define to_scsi_device(d) \ #define to_scsi_device(d) \
container_of(d, struct scsi_device, sdev_gendev) container_of(d, struct scsi_device, sdev_gendev)
#define class_to_sdev(d) \ #define class_to_sdev(d) \
container_of(d, struct scsi_device, sdev_classdev) container_of(d, struct scsi_device, sdev_classdev)
#define transport_class_to_sdev(class_dev) \
container_of(class_dev, struct scsi_device, transport_classdev)
extern struct scsi_device *scsi_add_device(struct Scsi_Host *, extern struct scsi_device *scsi_add_device(struct Scsi_Host *,
uint, uint, uint); uint, uint, uint);
......
...@@ -11,6 +11,7 @@ struct scsi_cmnd; ...@@ -11,6 +11,7 @@ struct scsi_cmnd;
struct scsi_device; struct scsi_device;
struct Scsi_Host; struct Scsi_Host;
struct scsi_host_cmd_pool; struct scsi_host_cmd_pool;
struct scsi_transport_template;
/* /*
...@@ -395,6 +396,7 @@ struct Scsi_Host { ...@@ -395,6 +396,7 @@ struct Scsi_Host {
unsigned int eh_kill:1; /* set when killing the eh thread */ unsigned int eh_kill:1; /* set when killing the eh thread */
wait_queue_head_t host_wait; wait_queue_head_t host_wait;
struct scsi_host_template *hostt; struct scsi_host_template *hostt;
struct scsi_transport_template *transportt;
volatile unsigned short host_busy; /* commands actually active on low-level */ volatile unsigned short host_busy; /* commands actually active on low-level */
volatile unsigned short host_failed; /* commands that failed. */ volatile unsigned short host_failed; /* commands that failed. */
......
/*
* Transport specific attributes.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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 **attrs;
/* The transport class that the device is in */
struct class *class;
/* Constructor/Destructor functions */
int (* setup)(struct scsi_device *);
void (* cleanup)(struct scsi_device *);
/* The size of the specific transport attribute structure (a
* space of this size will be left at the end of the
* scsi_device structure */
int size;
};
#endif /* SCSI_TRANSPORT_H */
/*
* FiberChannel transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SCSI_TRANSPORT_FC_H
#define SCSI_TRANSPORT_FC_H
struct scsi_transport_template;
struct fc_transport_attrs {
int port_id;
uint64_t node_name;
uint64_t port_name;
};
/* accessor functions */
#define fc_port_id(x) (((struct fc_transport_attrs *)&(x)->transport_data)->port_id)
#define fc_node_name(x) (((struct fc_transport_attrs *)&(x)->transport_data)->node_name)
#define fc_port_name(x) (((struct fc_transport_attrs *)&(x)->transport_data)->port_name)
extern struct scsi_transport_template fc_transport_template;
#endif /* SCSI_TRANSPORT_FC_H */
/*
* Parallel SCSI (SPI) transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SCSI_TRANSPORT_SPI_H
#define SCSI_TRANSPORT_SPI_H
#include <linux/config.h>
struct scsi_transport_template;
struct spi_transport_attrs {
int period;
int offset;
};
/* accessor functions */
#define spi_period(x) (((struct spi_transport_attrs *)&(x)->transport_data)->period)
#define spi_offset(x) (((struct spi_transport_attrs *)&(x)->transport_data)->offset)
extern struct scsi_transport_template spi_transport_template;
#endif /* SCSI_TRANSPORT_SPI_H */
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