* [PATCH] SAS transport class
@ 2005-09-04 23:50 Christoph Hellwig
0 siblings, 0 replies; 9+ messages in thread
From: Christoph Hellwig @ 2005-09-04 23:50 UTC (permalink / raw)
To: linux-scsi
New version of the SAS transport class. This now introduces the concept
of remote ports as suggested by James Smart. Also ports can be layer
ontop of remote ports in addition to scsi hosts to support extenders,
although that functionality is rather theoretical as I didn't manage to
update the Fusion driver for that support yet. I've also improved the
handling of ports quite a bit, there's a sas_remove_host now that gets
rid of all ports and remote ports, and the API to create ports makes
much more sense.
There's still quite a few review comments I haven't addresses but I
wanted to get a snapshot with support for extenders out.
Index: scsi-misc-2.6/drivers/scsi/Kconfig
===================================================================
--- scsi-misc-2.6.orig/drivers/scsi/Kconfig 2005-09-05 01:52:48.000000000 +0200
+++ scsi-misc-2.6/drivers/scsi/Kconfig 2005-09-05 01:53:55.000000000 +0200
@@ -235,6 +235,13 @@
each attached iSCSI device to sysfs, say Y.
Otherwise, say N.
+config SCSI_SAS_ATTRS
+ tristate "SAS Transport Attributes"
+ depends on SCSI
+ help
+ If you wish to export transport-specific information about
+ each attached SAS device to sysfs, say Y.
+
endmenu
menu "SCSI low-level drivers"
Index: scsi-misc-2.6/drivers/scsi/Makefile
===================================================================
--- scsi-misc-2.6.orig/drivers/scsi/Makefile 2005-09-05 01:52:48.000000000 +0200
+++ scsi-misc-2.6/drivers/scsi/Makefile 2005-09-05 01:53:55.000000000 +0200
@@ -31,6 +31,7 @@
obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.o
obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o
obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o
+obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o
obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o
obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
Index: scsi-misc-2.6/drivers/scsi/scsi_transport_sas.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ scsi-misc-2.6/drivers/scsi/scsi_transport_sas.c 2005-09-05 01:55:07.000000000 +0200
@@ -0,0 +1,795 @@
+/*
+ * Copyright (C) 2005 Dell Inc.
+ * Released under GPL v2.
+ *
+ * Serial Attached SCSI (SAS) transport class.
+ *
+ * The SAS transport class contains common code to deal with SAS HBAs,
+ * an aproximated representation of SAS topologies in the driver model,
+ * and various sysfs attributes to expose these topologies and managment
+ * interfaces to userspace.
+ *
+ * In addition to the basic SCSI core objects this transport class
+ * introduces two additional intermediate objects: The SAS port
+ * as represented by struct sas_port defines an "outgoing" port on
+ * a SAS HBA or Expander, and the SAS remote port represented by
+ * struct sas_rport defines an "incoming" port on a SAS Expander or
+ * End device. Note that this is purely a software concept, the
+ * underlying hardware for ports and remote ports is the same.
+ *
+ * We also have a sas_host class, but that one doesn't serve any purpose
+ * except giving us a per-host handle that allows us to match devices
+ * that we want to claim.
+ *
+ * Note: Currently this code does not deal with wide ports at all,
+ * thus there is no distinction between ports and phys. This
+ * will be fixed very soon.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/err.h>
+
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+
+
+#define SAS_HOST_ATTRS 0
+#define SAS_PORT_ATTRS 11
+#define SAS_RPORT_ATTRS 5
+
+struct sas_internal {
+ struct scsi_transport_template t;
+ struct sas_function_template *f;
+
+ struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS];
+ struct class_device_attribute private_port_attrs[SAS_PORT_ATTRS];
+ struct class_device_attribute private_rport_attrs[SAS_RPORT_ATTRS];
+
+ struct transport_container port_attr_cont;
+ struct transport_container rport_attr_cont;
+
+ /*
+ * The array of null terminated pointers to attributes
+ * needed by scsi_sysfs.c
+ */
+ struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1];
+ struct class_device_attribute *port_attrs[SAS_PORT_ATTRS + 1];
+ struct class_device_attribute *rport_attrs[SAS_RPORT_ATTRS + 1];
+};
+#define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t)
+
+struct sas_host_attrs {
+};
+#define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data)
+
+
+/*
+ * Hack to allow attributes of the same name in different objects.
+ */
+#define SAS_CLASS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \
+ struct class_device_attribute class_device_attr_##_prefix##_##_name = \
+ __ATTR(_name,_mode,_show,_store)
+
+
+/*
+ * Pretty printing helpers
+ */
+
+#define sas_bitfield_name_match(title, table) \
+static ssize_t \
+get_sas_##title##_names(u32 table_key, char *buf) \
+{ \
+ char *prefix = ""; \
+ ssize_t len = 0; \
+ int i; \
+ \
+ for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) { \
+ if (table[i].value & table_key) { \
+ len += sprintf(buf + len, "%s%s", \
+ prefix, table[i].name); \
+ prefix = ", "; \
+ } \
+ } \
+ len += sprintf(buf + len, "\n"); \
+ return len; \
+}
+
+#define sas_bitfield_name_search(title, table) \
+static ssize_t \
+get_sas_##title##_names(u32 table_key, char *buf) \
+{ \
+ ssize_t len = 0; \
+ int i; \
+ \
+ for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) { \
+ if (table[i].value == table_key) { \
+ len += sprintf(buf + len, "%s", \
+ table[i].name); \
+ break; \
+ } \
+ } \
+ len += sprintf(buf + len, "\n"); \
+ return len; \
+}
+
+static struct {
+ u32 value;
+ char *name;
+} sas_device_type_names[] = {
+ { SAS_PHY_UNUSED, "unused" },
+ { SAS_END_DEVICE, "end device" },
+ { SAS_EDGE_EXPANDER_DEVICE, "edge expander" },
+ { SAS_FANOUT_EXPANDER_DEVICE, "fanout expander" },
+};
+sas_bitfield_name_search(device_type, sas_device_type_names)
+
+
+static struct {
+ u32 value;
+ char *name;
+} sas_protocol_names[] = {
+ { SAS_PROTOCOL_SATA, "sata" },
+ { SAS_PROTOCOL_SMP, "smp" },
+ { SAS_PROTOCOL_STP, "stp" },
+ { SAS_PROTOCOL_SSP, "ssp" },
+};
+sas_bitfield_name_match(protocol, sas_protocol_names)
+
+static struct {
+ u32 value;
+ char *name;
+} sas_linkspeed_names[] = {
+ { SAS_LINK_RATE_UNKNOWN, "Unknown" },
+ { SAS_PHY_DISABLED, "Phy disabled" },
+ { SAS_LINK_RATE_FAILED, "Link Rate failed" },
+ { SAS_SATA_SPINUP_HOLD, "Spin-up hold" },
+ { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" },
+ { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" },
+};
+sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
+
+
+/*
+ * SAS host attributes
+ */
+
+static DECLARE_TRANSPORT_CLASS(sas_host_class,
+ "sas_host", NULL, NULL, NULL);
+
+static int sas_host_match(struct attribute_container *cont,
+ struct device *dev)
+{
+ struct Scsi_Host *shost;
+ struct sas_internal *i;
+
+ if (!scsi_is_host_device(dev))
+ return 0;
+ shost = dev_to_shost(dev);
+
+ if (!shost->transportt)
+ return 0;
+ if (shost->transportt->host_attrs.ac.class !=
+ &sas_host_class.class)
+ return 0;
+
+ i = to_sas_internal(shost->transportt);
+ return &i->t.host_attrs.ac == cont;
+}
+
+static int do_sas_port_delete(struct device *dev, void *data)
+{
+ if (scsi_is_sas_port(dev))
+ sas_port_delete(dev_to_port(dev));
+ return 0;
+}
+
+/**
+ * sas_remove_host -- tear down a Scsi_Host's SAS data structures
+ * @shost: Scsi Host that is torn down
+ *
+ * Removes all SAS ports and remote ports for a given Scsi_Host.
+ * Must be called just before scsi_remove_host for SAS HBAs.
+ */
+void sas_remove_host(struct Scsi_Host *shost)
+{
+ device_for_each_child(&shost->shost_gendev, NULL, do_sas_port_delete);
+}
+EXPORT_SYMBOL(sas_remove_host);
+
+/*
+ * SAS Port attributes
+ */
+
+#define sas_port_show_simple(field, name, format_string) \
+static ssize_t \
+show_sas_port_##name(struct class_device *cdev, char *buf) \
+{ \
+ struct sas_port *port = transport_class_to_port(cdev); \
+ \
+ return snprintf(buf, 20, format_string, port->field); \
+}
+
+#define sas_port_simple_attr(field, name, format_string) \
+ sas_port_show_simple(field, name, format_string) \
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL)
+
+#define sas_port_show_protocol(field, name) \
+static ssize_t \
+show_sas_port_##name(struct class_device *cdev, char *buf) \
+{ \
+ struct sas_port *port = transport_class_to_port(cdev); \
+ \
+ if (!port->field) \
+ return snprintf(buf, 20, "none\n"); \
+ return get_sas_protocol_names(port->field, buf); \
+}
+
+#define sas_port_protocol_attr(field, name) \
+ sas_port_show_protocol(field, name) \
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL)
+
+#define sas_port_show_linkspeed(field) \
+static ssize_t \
+show_sas_port_##field(struct class_device *cdev, char *buf) \
+{ \
+ struct sas_port *port = transport_class_to_port(cdev); \
+ \
+ return get_sas_linkspeed_names(port->field, buf); \
+}
+
+#define sas_port_linkspeed_attr(field) \
+ sas_port_show_linkspeed(field) \
+static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_port_##field, NULL)
+
+static ssize_t
+show_sas_device_type(struct class_device *cdev, char *buf)
+{
+ struct sas_port *port = transport_class_to_port(cdev);
+
+ if (!port->identify.device_type)
+ return snprintf(buf, 20, "none\n");
+ return get_sas_device_type_names(port->identify.device_type, buf);
+}
+
+static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL);
+
+sas_port_protocol_attr(identify.initiator_port_protocols,
+ initiator_port_protocols);
+sas_port_protocol_attr(identify.target_port_protocols,
+ target_port_protocols);
+sas_port_simple_attr(identify.sas_address,
+ sas_address, "0x%016llx\n");
+sas_port_simple_attr(identify.phy_identifier,
+ phy_identifier, "%d\n");
+sas_port_simple_attr(port_identifier, port_identifier, "%d\n");
+sas_port_linkspeed_attr(negotiated_linkrate);
+sas_port_linkspeed_attr(minimum_linkrate_hw);
+sas_port_linkspeed_attr(minimum_linkrate);
+sas_port_linkspeed_attr(maximum_linkrate_hw);
+sas_port_linkspeed_attr(maximum_linkrate);
+
+
+static DECLARE_TRANSPORT_CLASS(sas_port_class,
+ "sas_port", NULL, NULL, NULL);
+
+static int sas_port_match(struct attribute_container *cont, struct device *dev)
+{
+ struct Scsi_Host *shost;
+ struct sas_internal *i;
+
+ if (!scsi_is_sas_port(dev))
+ return 0;
+ shost = dev_to_shost(dev->parent);
+
+ if (!shost->transportt)
+ return 0;
+ if (shost->transportt->host_attrs.ac.class !=
+ &sas_host_class.class)
+ return 0;
+
+ i = to_sas_internal(shost->transportt);
+ return &i->port_attr_cont.ac == cont;
+}
+
+static void sas_port_release(struct device *dev)
+{
+ struct sas_port *port = dev_to_port(dev);
+
+ put_device(dev->parent);
+ kfree(port);
+}
+
+/**
+ * sas_port_alloc -- allocates and initialize a SAS port structure
+ * @parent: Parent device
+ * @number: Port number
+ *
+ * Allocates an SAS port structure. It will be added in the device tree
+ * below the device specified by @parent, which has to be either a Scsi_Host
+ * or sas_rport.
+ *
+ * Returns:
+ * SAS port allocated or %NULL if the allocation failed.
+ */
+struct sas_port *sas_port_alloc(struct device *parent, int number)
+{
+ struct Scsi_Host *shost = dev_to_shost(parent);
+ struct sas_port *port;
+
+ port = kmalloc(sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return NULL;
+ memset(port, 0, sizeof(*port));
+
+ get_device(parent);
+
+ port->number = number;
+
+ device_initialize(&port->dev);
+ port->dev.parent = get_device(parent);
+ port->dev.release = sas_port_release;
+ sprintf(port->dev.bus_id, "port-%d:%d",
+ shost->host_no, number);
+
+ transport_setup_device(&port->dev);
+
+ return port;
+}
+EXPORT_SYMBOL(sas_port_alloc);
+
+/**
+ * sas_port_add -- add a SAS port to the device hierachy
+ * @port: The port to be added
+ *
+ * Publishes a SAS port to the rest of the system.
+ */
+void sas_port_add(struct sas_port *port)
+{
+ int error;
+
+ error = device_add(&port->dev);
+ if (error)
+ goto out_transport_destroy;
+ transport_add_device(&port->dev);
+ transport_configure_device(&port->dev);
+ return;
+
+ out_transport_destroy:
+ transport_destroy_device(&port->dev);
+ put_device(port->dev.parent);
+ put_device(port->dev.parent);
+ put_device(port->dev.parent);
+ kfree(port);
+}
+EXPORT_SYMBOL(sas_port_add);
+
+/**
+ * sas_port_delete -- remove SAS port
+ * @port: SAS port to remove
+ *
+ * Removes the specified SAS port. If the SAS port has an
+ * associated remote port it is removed before.
+ */
+void
+sas_port_delete(struct sas_port *port)
+{
+ struct device *dev = &port->dev;
+
+ if (port->rport)
+ sas_rport_delete(port->rport);
+
+ transport_remove_device(dev);
+ device_del(dev);
+ transport_destroy_device(dev);
+ put_device(dev->parent);
+}
+EXPORT_SYMBOL(sas_port_delete);
+
+/**
+ * scsi_is_sas_port -- check if a struct device represents a SAS port
+ * @dev: device to check
+ *
+ * Returns:
+ * %1 if the device represents a SAS port, %0 else
+ */
+int scsi_is_sas_port(const struct device *dev)
+{
+ return dev->release == sas_port_release;
+}
+EXPORT_SYMBOL(scsi_is_sas_port);
+
+/* copied from drivers/base/core.c */
+static struct device *next_device(struct klist_iter * i)
+{
+ struct klist_node * n = klist_next(i);
+ return n ? container_of(n, struct device, knode_parent) : NULL;
+}
+
+/* should move to drivers/base/core.c */
+static struct device *device_lookup(struct device *parent, void *data,
+ int (*match)(struct device *, void *))
+
+{
+ struct device *child;
+ struct klist_iter i;
+
+ klist_iter_init(&parent->klist_children, &i);
+ while ((child = next_device(&i))) {
+ if (match(child, data)) {
+ get_device(child);
+ klist_iter_exit(&i);
+ return child;
+ }
+ }
+ klist_iter_exit(&i);
+
+ return NULL;
+}
+
+static int sas_port_lookup_match(struct device *dev, void *data)
+{
+ return scsi_is_sas_port(dev) &&
+ dev_to_port(dev)->number == *((int *)data);
+}
+
+static struct sas_port *sas_port_lookup(struct device *parent, int number)
+{
+ struct device *found;
+
+ found = device_lookup(parent, &number, sas_port_lookup_match);
+ if (!found)
+ return NULL;
+ return dev_to_port(found);
+}
+
+/*
+ * SAS remote port attributes.
+ */
+
+#define sas_rport_show_simple(field, name, format_string) \
+static ssize_t \
+show_sas_rport_##name(struct class_device *cdev, char *buf) \
+{ \
+ struct sas_rport *rport = transport_class_to_rport(cdev); \
+ \
+ return snprintf(buf, 20, format_string, rport->field); \
+}
+
+#define sas_rport_simple_attr(field, name, format_string) \
+ sas_rport_show_simple(field, name, format_string) \
+static SAS_CLASS_DEVICE_ATTR(rport, name, S_IRUGO, \
+ show_sas_rport_##name, NULL)
+
+#define sas_rport_show_protocol(field, name) \
+static ssize_t \
+show_sas_rport_##name(struct class_device *cdev, char *buf) \
+{ \
+ struct sas_rport *rport = transport_class_to_rport(cdev); \
+ \
+ if (!rport->field) \
+ return snprintf(buf, 20, "none\n"); \
+ return get_sas_protocol_names(rport->field, buf); \
+}
+
+#define sas_rport_protocol_attr(field, name) \
+ sas_rport_show_protocol(field, name) \
+static SAS_CLASS_DEVICE_ATTR(rport, name, S_IRUGO, \
+ show_sas_rport_##name, NULL)
+
+static ssize_t
+show_sas_rport_device_type(struct class_device *cdev, char *buf)
+{
+ struct sas_rport *rport = transport_class_to_rport(cdev);
+
+ if (!rport->identify.device_type)
+ return snprintf(buf, 20, "none\n");
+ return get_sas_device_type_names(
+ rport->identify.device_type, buf);
+}
+
+static SAS_CLASS_DEVICE_ATTR(rport, device_type, S_IRUGO,
+ show_sas_rport_device_type, NULL);
+
+sas_rport_protocol_attr(identify.initiator_port_protocols,
+ initiator_port_protocols);
+sas_rport_protocol_attr(identify.target_port_protocols,
+ target_port_protocols);
+sas_rport_simple_attr(identify.sas_address,
+ sas_address, "0x%016llx\n");
+sas_rport_simple_attr(identify.phy_identifier,
+ phy_identifier, "%d\n");
+
+static DECLARE_TRANSPORT_CLASS(sas_rport_class,
+ "sas_rport", NULL, NULL, NULL);
+
+static int sas_rport_match(struct attribute_container *cont, struct device *dev)
+{
+ struct Scsi_Host *shost;
+ struct sas_internal *i;
+
+ if (!scsi_is_sas_rport(dev))
+ return 0;
+ shost = dev_to_shost(dev->parent->parent);
+
+ if (!shost->transportt)
+ return 0;
+ if (shost->transportt->host_attrs.ac.class !=
+ &sas_host_class.class)
+ return 0;
+
+ i = to_sas_internal(shost->transportt);
+ return &i->rport_attr_cont.ac == cont;
+}
+
+static void sas_rport_release(struct device *dev)
+{
+ struct sas_rport *rport = dev_to_rport(dev);
+
+ put_device(dev->parent);
+ kfree(rport);
+}
+
+/**
+ * sas_rport_alloc -- allocates and initialize a SAS remote port structure
+ * @grandparent: Parent device of the parent SAS port
+ * @port: Port number of the parent SAS port
+ * @channel: SCSI Core channel number
+ * @id: SCSI Core target id
+ *
+ * Allocates an SAS remote port structure, connected to the port @port of the
+ * Scsi_Host or sas_rport specified by @grandparent.
+ *
+ * Note:
+ * @channel and @id only make sense for sas ports that support protocols
+ * support by the SCSI subsystem (ssp, stp or direct attached sata).
+ *
+ * @id will go away soon, and there will be no visible SPI-ish target
+ * ID visible to SAS LLDDs.
+ *
+ * Returns:
+ * SAS port allocated or %NULL if the allocation failed.
+ */
+struct sas_rport *sas_rport_alloc(struct device *grandparent,
+ int port, uint channel, uint id)
+{
+ struct Scsi_Host *shost = dev_to_shost(grandparent);
+ struct sas_port *parent;
+ struct sas_rport *rport;
+
+ parent = sas_port_lookup(grandparent, port);
+ if (!parent)
+ return NULL;
+
+ rport = kmalloc(sizeof(*rport), GFP_KERNEL);
+ if (!rport) {
+ put_device(&parent->dev);
+ return NULL;
+ }
+ memset(rport, 0, sizeof(*rport));
+
+ rport->channel = channel;
+ rport->id = id;
+
+ device_initialize(&rport->dev);
+ rport->dev.parent = get_device(&parent->dev);
+ rport->dev.release = sas_rport_release;
+ sprintf(rport->dev.bus_id, "rport-%d:%d",
+ shost->host_no, parent->number);
+ transport_setup_device(&rport->dev);
+
+ return rport;
+}
+EXPORT_SYMBOL(sas_rport_alloc);
+
+/**
+ * sas_rport_add -- add a SAS remote port to the device hierachy
+ * @rport: The remote port to be added
+ *
+ * Publishes a SAS remote port to the rest of the system.
+ */
+void sas_rport_add(struct sas_rport *rport)
+{
+ struct sas_port *parent = dev_to_port(rport->dev.parent);
+ struct sas_identify *identify = &rport->identify;
+ int error;
+
+ if (parent->rport)
+ return;
+ parent->rport = rport;
+
+ error = device_add(&rport->dev);
+ if (error)
+ goto out_transport_destroy;
+ transport_add_device(&rport->dev);
+ transport_configure_device(&rport->dev);
+
+ if (identify->device_type == SAS_END_DEVICE &&
+ (identify->target_port_protocols &
+ (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA)))
+ scsi_scan_target(&rport->dev, rport->channel,
+ rport->id, ~0, 0);
+
+ return;
+
+ out_transport_destroy:
+ transport_destroy_device(&rport->dev);
+ put_device(rport->dev.parent);
+ put_device(rport->dev.parent);
+ put_device(rport->dev.parent);
+ kfree(rport);
+}
+EXPORT_SYMBOL(sas_rport_add);
+
+/**
+ * sas_rport_delete -- remove SAS remote port
+ * @rport: SAS remote port to remove
+ *
+ * Removes the specified SAS remote port.
+ */
+void
+sas_rport_delete(struct sas_rport *rport)
+{
+ struct device *dev = &rport->dev;
+ struct sas_port *parent = dev_to_port(dev->parent);
+
+ scsi_remove_target(&rport->dev);
+
+ transport_remove_device(dev);
+ device_del(dev);
+ transport_destroy_device(dev);
+ put_device(&parent->dev);
+}
+EXPORT_SYMBOL(sas_rport_delete);
+
+/**
+ * scsi_is_sas_rport -- check if a struct device represents a SAS remote port
+ * @dev: device to check
+ *
+ * Returns:
+ * %1 if the device represents a SAS remote port, %0 else
+ */
+int scsi_is_sas_rport(const struct device *dev)
+{
+ return dev->release == sas_rport_release;
+}
+EXPORT_SYMBOL(scsi_is_sas_rport);
+
+
+/*
+ * Setup / Teardown code
+ */
+
+#define SETUP_RPORT_ATTRIBUTE(field) \
+ i->private_rport_attrs[count] = class_device_attr_##field; \
+ i->private_rport_attrs[count].attr.mode = S_IRUGO; \
+ i->private_rport_attrs[count].store = NULL; \
+ i->rport_attrs[count] = &i->private_rport_attrs[count]; \
+ count++
+
+#define SETUP_PORT_ATTRIBUTE(field) \
+ i->private_port_attrs[count] = class_device_attr_##field; \
+ i->private_port_attrs[count].attr.mode = S_IRUGO; \
+ i->private_port_attrs[count].store = NULL; \
+ i->port_attrs[count] = &i->private_port_attrs[count]; \
+ count++
+
+
+/**
+ * sas_attach_transport -- instantiate SAS transport template
+ * @ft: SAS transport class function template
+ */
+struct scsi_transport_template *
+sas_attach_transport(struct sas_function_template *ft)
+{
+ struct sas_internal *i;
+ int count;
+
+ i = kmalloc(sizeof(struct sas_internal), GFP_KERNEL);
+ if (!i)
+ return NULL;
+ memset(i, 0, sizeof(struct sas_internal));
+
+ i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+ i->t.host_attrs.ac.class = &sas_host_class.class;
+ i->t.host_attrs.ac.match = sas_host_match;
+ transport_container_register(&i->t.host_attrs);
+ i->t.host_size = sizeof(struct sas_host_attrs);
+
+ i->port_attr_cont.ac.class = &sas_port_class.class;
+ i->port_attr_cont.ac.attrs = &i->port_attrs[0];
+ i->port_attr_cont.ac.match = sas_port_match;
+ transport_container_register(&i->port_attr_cont);
+
+ i->rport_attr_cont.ac.class = &sas_rport_class.class;
+ i->rport_attr_cont.ac.attrs = &i->rport_attrs[0];
+ i->rport_attr_cont.ac.match = sas_rport_match;
+ transport_container_register(&i->rport_attr_cont);
+
+ i->f = ft;
+
+ count = 0;
+ i->host_attrs[count] = NULL;
+
+ count = 0;
+ SETUP_PORT_ATTRIBUTE(initiator_port_protocols);
+ SETUP_PORT_ATTRIBUTE(target_port_protocols);
+ SETUP_PORT_ATTRIBUTE(device_type);
+ SETUP_PORT_ATTRIBUTE(sas_address);
+ SETUP_PORT_ATTRIBUTE(phy_identifier);
+ SETUP_PORT_ATTRIBUTE(port_identifier);
+ SETUP_PORT_ATTRIBUTE(negotiated_linkrate);
+ SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw);
+ SETUP_PORT_ATTRIBUTE(minimum_linkrate);
+ SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw);
+ SETUP_PORT_ATTRIBUTE(maximum_linkrate);
+ i->port_attrs[count] = NULL;
+
+ count = 0;
+ SETUP_RPORT_ATTRIBUTE(rport_initiator_port_protocols);
+ SETUP_RPORT_ATTRIBUTE(rport_target_port_protocols);
+ SETUP_RPORT_ATTRIBUTE(rport_device_type);
+ SETUP_RPORT_ATTRIBUTE(rport_sas_address);
+ SETUP_RPORT_ATTRIBUTE(rport_phy_identifier);
+ i->rport_attrs[count] = NULL;
+
+ return &i->t;
+}
+EXPORT_SYMBOL(sas_attach_transport);
+
+/**
+ * sas_release_transport -- release SAS transport template instance
+ * @t: transport template instance
+ */
+void sas_release_transport(struct scsi_transport_template *t)
+{
+ struct sas_internal *i = to_sas_internal(t);
+
+ transport_container_unregister(&i->t.host_attrs);
+ transport_container_unregister(&i->port_attr_cont);
+ transport_container_unregister(&i->rport_attr_cont);
+
+ kfree(i);
+}
+EXPORT_SYMBOL(sas_release_transport);
+
+static __init int sas_transport_init(void)
+{
+ int error;
+
+ error = transport_class_register(&sas_host_class);
+ if (error)
+ goto out;
+ error = transport_class_register(&sas_port_class);
+ if (error)
+ goto out_unregister_transport;
+ error = transport_class_register(&sas_rport_class);
+ if (error)
+ goto out_unregister_port;
+
+ return 0;
+
+ out_unregister_port:
+ transport_class_unregister(&sas_port_class);
+ out_unregister_transport:
+ transport_class_unregister(&sas_host_class);
+ out:
+ return error;
+
+}
+
+static void __exit sas_transport_exit(void)
+{
+ transport_class_unregister(&sas_host_class);
+ transport_class_unregister(&sas_port_class);
+ transport_class_unregister(&sas_rport_class);
+}
+
+MODULE_AUTHOR("Christoph Hellwig");
+MODULE_DESCRIPTION("SAS Transport Attributes");
+MODULE_LICENSE("GPL");
+
+module_init(sas_transport_init);
+module_exit(sas_transport_exit);
Index: scsi-misc-2.6/include/scsi/scsi_transport_sas.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ scsi-misc-2.6/include/scsi/scsi_transport_sas.h 2005-09-05 01:54:02.000000000 +0200
@@ -0,0 +1,101 @@
+#ifndef SCSI_TRANSPORT_SAS_H
+#define SCSI_TRANSPORT_SAS_H
+
+#include <linux/transport_class.h>
+#include <linux/types.h>
+
+struct scsi_transport_template;
+struct sas_rport;
+
+
+enum sas_device_type {
+ SAS_PHY_UNUSED = 0x00,
+ SAS_END_DEVICE = 0x10,
+ SAS_EDGE_EXPANDER_DEVICE = 0x20,
+ SAS_FANOUT_EXPANDER_DEVICE = 0x30,
+};
+
+enum sas_protocol {
+ SAS_PROTOCOL_SATA = 0x01,
+ SAS_PROTOCOL_SMP = 0x02,
+ SAS_PROTOCOL_STP = 0x04,
+ SAS_PROTOCOL_SSP = 0x08,
+};
+
+enum sas_linkrate {
+ SAS_LINK_RATE_UNKNOWN = 0x00,
+ SAS_PHY_DISABLED = 0x01,
+ SAS_LINK_RATE_FAILED = 0x02,
+ SAS_SATA_SPINUP_HOLD = 0x03,
+ SAS_SATA_PORT_SELECTOR = 0x04,
+ SAS_LINK_RATE_1_5_GBPS = 0x08,
+ SAS_LINK_RATE_3_0_GBPS = 0x09,
+ SAS_LINK_VIRTUAL = 0x10,
+};
+
+struct sas_identify {
+ enum sas_device_type device_type;
+ enum sas_protocol initiator_port_protocols;
+ enum sas_protocol target_port_protocols;
+ u64 sas_address;
+ u8 phy_identifier;
+};
+
+/* The functions by which the transport class and the driver communicate */
+struct sas_function_template {
+};
+
+struct sas_port {
+ struct device dev;
+ int number;
+
+ struct sas_rport *rport;
+
+ struct sas_identify identify;
+ enum sas_linkrate negotiated_linkrate;
+ enum sas_linkrate minimum_linkrate_hw;
+ enum sas_linkrate minimum_linkrate;
+ enum sas_linkrate maximum_linkrate_hw;
+ enum sas_linkrate maximum_linkrate;
+ u8 port_identifier;
+};
+
+#define dev_to_port(d) \
+ container_of((d), struct sas_port, dev)
+#define transport_class_to_port(cdev) \
+ dev_to_port((cdev)->dev)
+#define port_to_shost(port) \
+ dev_to_shost((port)->dev.parent)
+
+struct sas_rport {
+ struct device dev;
+ int number;
+ uint channel;
+ uint id;
+ struct sas_identify identify;
+};
+
+#define dev_to_rport(d) \
+ container_of((d), struct sas_rport, dev)
+#define transport_class_to_rport(cdev) \
+ dev_to_rport((cdev)->dev)
+#define rport_to_shost(rport) \
+ dev_to_shost((rport)->dev.parent)
+
+extern void sas_remove_host(struct Scsi_Host *);
+
+extern struct sas_port *sas_port_alloc(struct device *, int);
+extern void sas_port_add(struct sas_port *);
+extern void sas_port_delete(struct sas_port *);
+extern int scsi_is_sas_port(const struct device *);
+
+extern struct sas_rport *sas_rport_alloc(struct device *, int, uint, uint);
+extern void sas_rport_add(struct sas_rport *);
+extern void sas_rport_delete(struct sas_rport *);
+extern int scsi_is_sas_rport(const struct device *);
+
+extern struct scsi_transport_template *
+sas_attach_transport(struct sas_function_template *);
+extern void sas_release_transport(struct scsi_transport_template *);
+
+#endif /* SCSI_TRANSPORT_SAS_H */
^ permalink raw reply [flat|nested] 9+ messages in thread
* RE: [PATCH] SAS transport class
@ 2005-09-06 13:40 James.Smart
2005-09-06 14:00 ` Christoph Hellwig
2005-09-06 16:00 ` Stefan Richter
0 siblings, 2 replies; 9+ messages in thread
From: James.Smart @ 2005-09-06 13:40 UTC (permalink / raw)
To: hch, linux-scsi
> +/**
> + * sas_rport_alloc -- allocates and initialize a SAS
> remote port structure
> + * @grandparent: Parent device of the parent SAS port
> + * @port: Port number of the parent SAS port
> + * @channel: SCSI Core channel number
> + * @id: SCSI Core target id
> + *
> + * Allocates an SAS remote port structure, connected to the
> port @port of the
> + * Scsi_Host or sas_rport specified by @grandparent.
> + *
> + * Note:
> + * @channel and @id only make sense for sas ports that
> support protocols
> + * support by the SCSI subsystem (ssp, stp or direct
> attached sata).
> + *
> + * @id will go away soon, and there will be no visible
> SPI-ish target
> + * ID visible to SAS LLDDs.
> + *
> + * Returns:
> + * SAS port allocated or %NULL if the allocation failed.
> + */
> +struct sas_rport *sas_rport_alloc(struct device *grandparent,
> + int port, uint channel, uint id)
> +{
> + struct Scsi_Host *shost = dev_to_shost(grandparent);
> + struct sas_port *parent;
> + struct sas_rport *rport;
> +
> + parent = sas_port_lookup(grandparent, port);
> + if (!parent)
> + return NULL;
So this is odd... grandparent ? why pass in port # (you should
know the object already)? why is channel skipping over / not
associated with the local port ?
What I would have expected is :
- sas_port_alloc() to either:
a) also have a "channel" argument, which gets saved in the local
port.
-or-
b) The port # is actually used as the channel #.
- sas_rport_alloc() becomes:
sas_rport_alloc(struct device *parent, uint id)
Where parent is the local port. You can still obtain the shost
via dev_to_shost(parent), and you can kill all that port searching
logic.
I'll point out, but not delve into - that you've avoided the target
id bindings again, thus forcing the lldd's/adapters to maintain tables
of port#/SASaddr to target id (if they care, and I believe enterprise
storage will care!). I can understand if you're going to eventually
insert a generic abstraction layer for scsi's b/c/t/l addressing
scheme, but since it's not here today, I expect you to hold SAS to the
same "code sharing" level as FC.
Also, to deal with cable pulls, SAS reconfiguration and rescanning,
I expect that you will need to add in the block/unblock functionality
that the FC transport has. [Note: we've seen an issue in the current
FC design, so expect a transport update].
> +void sas_rport_add(struct sas_rport *rport)
> +{
> ....
> + if (identify->device_type == SAS_END_DEVICE &&
> + (identify->target_port_protocols &
> + (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA)))
> + scsi_scan_target(&rport->dev, rport->channel,
> + rport->id, ~0, 0);
I highly recommend the use of workqueues for the scan function as we
did in the fc transport.
-- james s
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] SAS transport class
2005-09-06 13:40 [PATCH] SAS transport class James.Smart
@ 2005-09-06 14:00 ` Christoph Hellwig
2005-09-06 16:00 ` Stefan Richter
1 sibling, 0 replies; 9+ messages in thread
From: Christoph Hellwig @ 2005-09-06 14:00 UTC (permalink / raw)
To: James.Smart; +Cc: linux-scsi
On Tue, Sep 06, 2005 at 09:40:43AM -0400, James.Smart@Emulex.Com wrote:
> > + parent = sas_port_lookup(grandparent, port);
> > + if (!parent)
> > + return NULL;
>
> So this is odd... grandparent ? why pass in port # (you should
> know the object already)? why is channel skipping over / not
> associated with the local port ?
I didn't really want to need the drivers to keep around arrays
or lists of sas_port objects.
> What I would have expected is :
>
> - sas_port_alloc() to either:
> a) also have a "channel" argument, which gets saved in the local
> port.
> -or-
> b) The port # is actually used as the channel #.
I'm probably going to be with b). It's on my TODO list for the same
time when I'm switching over to not pass in a target ID anymore in
favour of allocating one internal to the transport class.
> - sas_rport_alloc() becomes:
> sas_rport_alloc(struct device *parent, uint id)
> Where parent is the local port. You can still obtain the shost
> via dev_to_shost(parent), and you can kill all that port searching
> logic.
Actually the id will also go away.
> I'll point out, but not delve into - that you've avoided the target
> id bindings again, thus forcing the lldd's/adapters to maintain tables
> of port#/SASaddr to target id (if they care, and I believe enterprise
> storage will care!). I can understand if you're going to eventually
> insert a generic abstraction layer for scsi's b/c/t/l addressing
> scheme, but since it's not here today, I expect you to hold SAS to the
> same "code sharing" level as FC.
Expect some updates in that area with the next code drop.
> Also, to deal with cable pulls, SAS reconfiguration and rescanning,
> I expect that you will need to add in the block/unblock functionality
> that the FC transport has. [Note: we've seen an issue in the current
> FC design, so expect a transport update].
yes, this will be added. Primary goal for this first stage of work
is to support a basic topology representation. Stage two will be support
for all kinds of runtime-events, aka addition of new devices, remove of
devices including the unplug timer bits, and stage3 will support for a
full managment interface. I hope parallel to that or shortly after
Adaptec or someone else will provide support for full host-base SAS
discovery aswell.
> > +void sas_rport_add(struct sas_rport *rport)
> > +{
> > ....
> > + if (identify->device_type == SAS_END_DEVICE &&
> > + (identify->target_port_protocols &
> > + (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA)))
> > + scsi_scan_target(&rport->dev, rport->channel,
> > + rport->id, ~0, 0);
>
> I highly recommend the use of workqueues for the scan function as we
> did in the fc transport.
This will happen in stage two, as part of the support for run-time
addition of devices.
^ permalink raw reply [flat|nested] 9+ messages in thread
* RE: [PATCH] SAS transport class
@ 2005-09-06 14:24 James.Smart
0 siblings, 0 replies; 9+ messages in thread
From: James.Smart @ 2005-09-06 14:24 UTC (permalink / raw)
To: hch; +Cc: linux-scsi
> > So this is odd... grandparent ? why pass in port # (you should
> > know the object already)? why is channel skipping over / not
> > associated with the local port ?
>
> I didn't really want to need the drivers to keep around arrays
> or lists of sas_port objects.
They're going to have to if they ever need to call xxx_delete() (or
perhaps block functions, etc)... which is all likely once the mgmt
interface is in place, or you start dealing with run-time events.
Everything else sounds good...
-- james s
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] SAS transport class
2005-09-06 13:40 [PATCH] SAS transport class James.Smart
2005-09-06 14:00 ` Christoph Hellwig
@ 2005-09-06 16:00 ` Stefan Richter
1 sibling, 0 replies; 9+ messages in thread
From: Stefan Richter @ 2005-09-06 16:00 UTC (permalink / raw)
To: linux-scsi; +Cc: James.Smart, hch
James Smart wrote:
> I'll point out, but not delve into - that you've avoided the target
> id bindings again, thus forcing the lldd's/adapters to maintain tables
> of port#/SASaddr to target id (if they care, and I believe enterprise
> storage will care!). I can understand if you're going to eventually
> insert a generic abstraction layer for scsi's b/c/t/l addressing
> scheme, but since it's not here today, I expect you to hold SAS to the
> same "code sharing" level as FC.
b/c/t/l has no place in layers below scsi core (except in SPI low-level
where it has actual meaning).
I don't understand exactly what should be accomplished by a table of
WWNs to target IDs --- but any kind of mapping between WWN and device
file (and thereby between WWN and a faked b/c/t/l) belongs into
userspace, not into the kernel.
Furthermore, there cannot be an "abstraction layer for scsi's b/c/t/l
addressing scheme". It is impossible to abstract something which is
without meaning.
--
Stefan Richter
-=====-=-=-= =--= --==-
http://arcgraph.de/sr/
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH] SAS transport class
@ 2005-09-09 14:22 Christoph Hellwig
2005-09-09 14:35 ` James Bottomley
2005-09-09 23:38 ` James Bottomley
0 siblings, 2 replies; 9+ messages in thread
From: Christoph Hellwig @ 2005-09-09 14:22 UTC (permalink / raw)
To: jejb; +Cc: linux-scsi
The SAS transport class contains common code to deal with SAS HBAs, an
aproximated representation of SAS topologies in the driver model,
and various sysfs attributes to expose these topologies and managment
interfaces to userspace.
In addition to the basic SCSI core objects this transport class introduces
two additional intermediate objects: The SAS PHY as represented by struct
sas_phy defines an "outgoing" PHY on a SAS HBA or Expander, and the SAS
remote PHY represented by struct sas_rphy defines an "incoming" PHY on a
SAS Expander or end device. Note that this is purely a software concept, the
underlying hardware for a PHY and a remote PHY is the exactly the same.
There is no concept of a SAS port in this code, users can see what PHYs
form a wide port based on the port_identifier attribute, which is the same
for all PHYs in a port.
This submission doesn't handle hot-plug addition or removal of SAS devices
and thus doesn't do scanning in a workqueue yet, that will be added in
phase2 after this submission. In a third phase I will add additional
managment infrastructure.
I think this submission is ready for 2.6.14, but additional comments are
of course very welcome.
I'd like to thanks James Smart a lot for his very useful input on the
design.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Index: xfs-2.6.x/drivers/scsi/Kconfig
===================================================================
--- xfs-2.6.x.orig/drivers/scsi/Kconfig 2005-09-09 16:23:01.000000000 +0200
+++ xfs-2.6.x/drivers/scsi/Kconfig 2005-09-09 16:23:38.000000000 +0200
@@ -229,6 +229,13 @@
each attached iSCSI device to sysfs, say Y.
Otherwise, say N.
+config SCSI_SAS_ATTRS
+ tristate "SAS Transport Attributes"
+ depends on SCSI
+ help
+ If you wish to export transport-specific information about
+ each attached SAS device to sysfs, say Y.
+
endmenu
menu "SCSI low-level drivers"
Index: xfs-2.6.x/drivers/scsi/Makefile
===================================================================
--- xfs-2.6.x.orig/drivers/scsi/Makefile 2005-09-09 16:23:01.000000000 +0200
+++ xfs-2.6.x/drivers/scsi/Makefile 2005-09-09 16:23:38.000000000 +0200
@@ -29,6 +29,7 @@
obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.o
obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o
obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o
+obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o
obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o
obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
Index: xfs-2.6.x/drivers/scsi/scsi_transport_sas.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ xfs-2.6.x/drivers/scsi/scsi_transport_sas.c 2005-09-09 16:23:38.000000000 +0200
@@ -0,0 +1,819 @@
+/*
+ * Copyright (C) 2005 Dell Inc.
+ * Released under GPL v2.
+ *
+ * Serial Attached SCSI (SAS) transport class.
+ *
+ * The SAS transport class contains common code to deal with SAS HBAs,
+ * an aproximated representation of SAS topologies in the driver model,
+ * and various sysfs attributes to expose these topologies and managment
+ * interfaces to userspace.
+ *
+ * In addition to the basic SCSI core objects this transport class
+ * introduces two additional intermediate objects: The SAS PHY
+ * as represented by struct sas_phy defines an "outgoing" PHY on
+ * a SAS HBA or Expander, and the SAS remote PHY represented by
+ * struct sas_rphy defines an "incoming" PHY on a SAS Expander or
+ * end device. Note that this is purely a software concept, the
+ * underlying hardware for a PHY and a remote PHY is the exactly
+ * the same.
+ *
+ * There is no concept of a SAS port in this code, users can see
+ * what PHYs form a wide port based on the port_identifier attribute,
+ * which is the same for all PHYs in a port.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/err.h>
+
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+
+
+#define SAS_HOST_ATTRS 0
+#define SAS_PORT_ATTRS 11
+#define SAS_RPORT_ATTRS 5
+
+struct sas_internal {
+ struct scsi_transport_template t;
+ struct sas_function_template *f;
+
+ struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS];
+ struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS];
+ struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS];
+
+ struct transport_container phy_attr_cont;
+ struct transport_container rphy_attr_cont;
+
+ /*
+ * The array of null terminated pointers to attributes
+ * needed by scsi_sysfs.c
+ */
+ struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1];
+ struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1];
+ struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1];
+};
+#define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t)
+
+struct sas_host_attrs {
+ struct list_head rphy_list;
+ spinlock_t lock;
+ u32 next_target_id;
+};
+#define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data)
+
+
+/*
+ * Hack to allow attributes of the same name in different objects.
+ */
+#define SAS_CLASS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \
+ struct class_device_attribute class_device_attr_##_prefix##_##_name = \
+ __ATTR(_name,_mode,_show,_store)
+
+
+/*
+ * Pretty printing helpers
+ */
+
+#define sas_bitfield_name_match(title, table) \
+static ssize_t \
+get_sas_##title##_names(u32 table_key, char *buf) \
+{ \
+ char *prefix = ""; \
+ ssize_t len = 0; \
+ int i; \
+ \
+ for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) { \
+ if (table[i].value & table_key) { \
+ len += sprintf(buf + len, "%s%s", \
+ prefix, table[i].name); \
+ prefix = ", "; \
+ } \
+ } \
+ len += sprintf(buf + len, "\n"); \
+ return len; \
+}
+
+#define sas_bitfield_name_search(title, table) \
+static ssize_t \
+get_sas_##title##_names(u32 table_key, char *buf) \
+{ \
+ ssize_t len = 0; \
+ int i; \
+ \
+ for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) { \
+ if (table[i].value == table_key) { \
+ len += sprintf(buf + len, "%s", \
+ table[i].name); \
+ break; \
+ } \
+ } \
+ len += sprintf(buf + len, "\n"); \
+ return len; \
+}
+
+static struct {
+ u32 value;
+ char *name;
+} sas_device_type_names[] = {
+ { SAS_PHY_UNUSED, "unused" },
+ { SAS_END_DEVICE, "end device" },
+ { SAS_EDGE_EXPANDER_DEVICE, "edge expander" },
+ { SAS_FANOUT_EXPANDER_DEVICE, "fanout expander" },
+};
+sas_bitfield_name_search(device_type, sas_device_type_names)
+
+
+static struct {
+ u32 value;
+ char *name;
+} sas_protocol_names[] = {
+ { SAS_PROTOCOL_SATA, "sata" },
+ { SAS_PROTOCOL_SMP, "smp" },
+ { SAS_PROTOCOL_STP, "stp" },
+ { SAS_PROTOCOL_SSP, "ssp" },
+};
+sas_bitfield_name_match(protocol, sas_protocol_names)
+
+static struct {
+ u32 value;
+ char *name;
+} sas_linkspeed_names[] = {
+ { SAS_LINK_RATE_UNKNOWN, "Unknown" },
+ { SAS_PHY_DISABLED, "Phy disabled" },
+ { SAS_LINK_RATE_FAILED, "Link Rate failed" },
+ { SAS_SATA_SPINUP_HOLD, "Spin-up hold" },
+ { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" },
+ { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" },
+};
+sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
+
+
+/*
+ * SAS host attributes
+ */
+
+static int sas_host_setup(struct device *dev)
+{
+ struct Scsi_Host *shost = dev_to_shost(dev);
+ struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+
+ INIT_LIST_HEAD(&sas_host->rphy_list);
+ spin_lock_init(&sas_host->lock);
+ sas_host->next_target_id = 0;
+ return 0;
+}
+
+static DECLARE_TRANSPORT_CLASS(sas_host_class,
+ "sas_host", sas_host_setup, NULL, NULL);
+
+static int sas_host_match(struct attribute_container *cont,
+ struct device *dev)
+{
+ struct Scsi_Host *shost;
+ struct sas_internal *i;
+
+ if (!scsi_is_host_device(dev))
+ return 0;
+ shost = dev_to_shost(dev);
+
+ if (!shost->transportt)
+ return 0;
+ if (shost->transportt->host_attrs.ac.class !=
+ &sas_host_class.class)
+ return 0;
+
+ i = to_sas_internal(shost->transportt);
+ return &i->t.host_attrs.ac == cont;
+}
+
+static int do_sas_phy_delete(struct device *dev, void *data)
+{
+ if (scsi_is_sas_phy(dev))
+ sas_phy_delete(dev_to_phy(dev));
+ return 0;
+}
+
+/**
+ * sas_remove_host -- tear down a Scsi_Host's SAS data structures
+ * @shost: Scsi Host that is torn down
+ *
+ * Removes all SAS PHYs and remote PHYs for a given Scsi_Host.
+ * Must be called just before scsi_remove_host for SAS HBAs.
+ */
+void sas_remove_host(struct Scsi_Host *shost)
+{
+ device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete);
+}
+EXPORT_SYMBOL(sas_remove_host);
+
+
+/*
+ * SAS Port attributes
+ */
+
+#define sas_phy_show_simple(field, name, format_string, cast) \
+static ssize_t \
+show_sas_phy_##name(struct class_device *cdev, char *buf) \
+{ \
+ struct sas_phy *phy = transport_class_to_phy(cdev); \
+ \
+ return snprintf(buf, 20, format_string, cast phy->field); \
+}
+
+#define sas_phy_simple_attr(field, name, format_string, type) \
+ sas_phy_show_simple(field, name, format_string, (type)) \
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
+
+#define sas_phy_show_protocol(field, name) \
+static ssize_t \
+show_sas_phy_##name(struct class_device *cdev, char *buf) \
+{ \
+ struct sas_phy *phy = transport_class_to_phy(cdev); \
+ \
+ if (!phy->field) \
+ return snprintf(buf, 20, "none\n"); \
+ return get_sas_protocol_names(phy->field, buf); \
+}
+
+#define sas_phy_protocol_attr(field, name) \
+ sas_phy_show_protocol(field, name) \
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
+
+#define sas_phy_show_linkspeed(field) \
+static ssize_t \
+show_sas_phy_##field(struct class_device *cdev, char *buf) \
+{ \
+ struct sas_phy *phy = transport_class_to_phy(cdev); \
+ \
+ return get_sas_linkspeed_names(phy->field, buf); \
+}
+
+#define sas_phy_linkspeed_attr(field) \
+ sas_phy_show_linkspeed(field) \
+static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
+
+static ssize_t
+show_sas_device_type(struct class_device *cdev, char *buf)
+{
+ struct sas_phy *phy = transport_class_to_phy(cdev);
+
+ if (!phy->identify.device_type)
+ return snprintf(buf, 20, "none\n");
+ return get_sas_device_type_names(phy->identify.device_type, buf);
+}
+
+static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL);
+
+sas_phy_protocol_attr(identify.initiator_port_protocols,
+ initiator_port_protocols);
+sas_phy_protocol_attr(identify.target_port_protocols,
+ target_port_protocols);
+sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
+ unsigned long long);
+sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
+sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8);
+sas_phy_linkspeed_attr(negotiated_linkrate);
+sas_phy_linkspeed_attr(minimum_linkrate_hw);
+sas_phy_linkspeed_attr(minimum_linkrate);
+sas_phy_linkspeed_attr(maximum_linkrate_hw);
+sas_phy_linkspeed_attr(maximum_linkrate);
+
+
+static DECLARE_TRANSPORT_CLASS(sas_phy_class,
+ "sas_phy", NULL, NULL, NULL);
+
+static int sas_phy_match(struct attribute_container *cont, struct device *dev)
+{
+ struct Scsi_Host *shost;
+ struct sas_internal *i;
+
+ if (!scsi_is_sas_phy(dev))
+ return 0;
+ shost = dev_to_shost(dev->parent);
+
+ if (!shost->transportt)
+ return 0;
+ if (shost->transportt->host_attrs.ac.class !=
+ &sas_host_class.class)
+ return 0;
+
+ i = to_sas_internal(shost->transportt);
+ return &i->phy_attr_cont.ac == cont;
+}
+
+static void sas_phy_release(struct device *dev)
+{
+ struct sas_phy *phy = dev_to_phy(dev);
+
+ put_device(dev->parent);
+ kfree(phy);
+}
+
+/**
+ * sas_phy_alloc -- allocates and initialize a SAS PHY structure
+ * @parent: Parent device
+ * @number: Port number
+ *
+ * Allocates an SAS PHY structure. It will be added in the device tree
+ * below the device specified by @parent, which has to be either a Scsi_Host
+ * or sas_rphy.
+ *
+ * Returns:
+ * SAS PHY allocated or %NULL if the allocation failed.
+ */
+struct sas_phy *sas_phy_alloc(struct device *parent, int number)
+{
+ struct Scsi_Host *shost = dev_to_shost(parent);
+ struct sas_phy *phy;
+
+ phy = kmalloc(sizeof(*phy), GFP_KERNEL);
+ if (!phy)
+ return NULL;
+ memset(phy, 0, sizeof(*phy));
+
+ get_device(parent);
+
+ phy->number = number;
+
+ device_initialize(&phy->dev);
+ phy->dev.parent = get_device(parent);
+ phy->dev.release = sas_phy_release;
+ sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number);
+
+ transport_setup_device(&phy->dev);
+
+ return phy;
+}
+EXPORT_SYMBOL(sas_phy_alloc);
+
+/**
+ * sas_phy_add -- add a SAS PHY to the device hierachy
+ * @phy: The PHY to be added
+ *
+ * Publishes a SAS PHY to the rest of the system.
+ */
+int sas_phy_add(struct sas_phy *phy)
+{
+ int error;
+
+ error = device_add(&phy->dev);
+ if (!error) {
+ transport_add_device(&phy->dev);
+ transport_configure_device(&phy->dev);
+ }
+
+ return error;
+}
+EXPORT_SYMBOL(sas_phy_add);
+
+/**
+ * sas_phy_free -- free a SAS PHY
+ * @phy: SAS PHY to free
+ *
+ * Frees the specified SAS PHY.
+ *
+ * Note:
+ * This function must only be called on a PHY that has not
+ * sucessfully been added using sas_phy_add().
+ */
+void sas_phy_free(struct sas_phy *phy)
+{
+ transport_destroy_device(&phy->dev);
+ put_device(phy->dev.parent);
+ put_device(phy->dev.parent);
+ put_device(phy->dev.parent);
+ kfree(phy);
+}
+EXPORT_SYMBOL(sas_phy_free);
+
+/**
+ * sas_phy_delete -- remove SAS PHY
+ * @phy: SAS PHY to remove
+ *
+ * Removes the specified SAS PHY. If the SAS PHY has an
+ * associated remote PHY it is removed before.
+ */
+void
+sas_phy_delete(struct sas_phy *phy)
+{
+ struct device *dev = &phy->dev;
+
+ if (phy->rphy)
+ sas_rphy_delete(phy->rphy);
+
+ transport_remove_device(dev);
+ device_del(dev);
+ transport_destroy_device(dev);
+ put_device(dev->parent);
+}
+EXPORT_SYMBOL(sas_phy_delete);
+
+/**
+ * scsi_is_sas_phy -- check if a struct device represents a SAS PHY
+ * @dev: device to check
+ *
+ * Returns:
+ * %1 if the device represents a SAS PHY, %0 else
+ */
+int scsi_is_sas_phy(const struct device *dev)
+{
+ return dev->release == sas_phy_release;
+}
+EXPORT_SYMBOL(scsi_is_sas_phy);
+
+/*
+ * SAS remote PHY attributes.
+ */
+
+#define sas_rphy_show_simple(field, name, format_string, cast) \
+static ssize_t \
+show_sas_rphy_##name(struct class_device *cdev, char *buf) \
+{ \
+ struct sas_rphy *rphy = transport_class_to_rphy(cdev); \
+ \
+ return snprintf(buf, 20, format_string, cast rphy->field); \
+}
+
+#define sas_rphy_simple_attr(field, name, format_string, type) \
+ sas_rphy_show_simple(field, name, format_string, (type)) \
+static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \
+ show_sas_rphy_##name, NULL)
+
+#define sas_rphy_show_protocol(field, name) \
+static ssize_t \
+show_sas_rphy_##name(struct class_device *cdev, char *buf) \
+{ \
+ struct sas_rphy *rphy = transport_class_to_rphy(cdev); \
+ \
+ if (!rphy->field) \
+ return snprintf(buf, 20, "none\n"); \
+ return get_sas_protocol_names(rphy->field, buf); \
+}
+
+#define sas_rphy_protocol_attr(field, name) \
+ sas_rphy_show_protocol(field, name) \
+static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \
+ show_sas_rphy_##name, NULL)
+
+static ssize_t
+show_sas_rphy_device_type(struct class_device *cdev, char *buf)
+{
+ struct sas_rphy *rphy = transport_class_to_rphy(cdev);
+
+ if (!rphy->identify.device_type)
+ return snprintf(buf, 20, "none\n");
+ return get_sas_device_type_names(
+ rphy->identify.device_type, buf);
+}
+
+static SAS_CLASS_DEVICE_ATTR(rphy, device_type, S_IRUGO,
+ show_sas_rphy_device_type, NULL);
+
+sas_rphy_protocol_attr(identify.initiator_port_protocols,
+ initiator_port_protocols);
+sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols);
+sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
+ unsigned long long);
+sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
+
+static DECLARE_TRANSPORT_CLASS(sas_rphy_class,
+ "sas_rphy", NULL, NULL, NULL);
+
+static int sas_rphy_match(struct attribute_container *cont, struct device *dev)
+{
+ struct Scsi_Host *shost;
+ struct sas_internal *i;
+
+ if (!scsi_is_sas_rphy(dev))
+ return 0;
+ shost = dev_to_shost(dev->parent->parent);
+
+ if (!shost->transportt)
+ return 0;
+ if (shost->transportt->host_attrs.ac.class !=
+ &sas_host_class.class)
+ return 0;
+
+ i = to_sas_internal(shost->transportt);
+ return &i->rphy_attr_cont.ac == cont;
+}
+
+static void sas_rphy_release(struct device *dev)
+{
+ struct sas_rphy *rphy = dev_to_rphy(dev);
+
+ put_device(dev->parent);
+ kfree(rphy);
+}
+
+/**
+ * sas_rphy_alloc -- allocates and initialize a SAS remote PHY structure
+ * @parent: SAS PHY this remote PHY is conneted to
+ *
+ * Allocates an SAS remote PHY structure, connected to @parent.
+ *
+ * Returns:
+ * SAS PHY allocated or %NULL if the allocation failed.
+ */
+struct sas_rphy *sas_rphy_alloc(struct sas_phy *parent)
+{
+ struct Scsi_Host *shost = dev_to_shost(&parent->dev);
+ struct sas_rphy *rphy;
+
+ rphy = kmalloc(sizeof(*rphy), GFP_KERNEL);
+ if (!rphy) {
+ put_device(&parent->dev);
+ return NULL;
+ }
+ memset(rphy, 0, sizeof(*rphy));
+
+ device_initialize(&rphy->dev);
+ rphy->dev.parent = get_device(&parent->dev);
+ rphy->dev.release = sas_rphy_release;
+ sprintf(rphy->dev.bus_id, "rphy-%d:%d",
+ shost->host_no, parent->number);
+ transport_setup_device(&rphy->dev);
+
+ return rphy;
+}
+EXPORT_SYMBOL(sas_rphy_alloc);
+
+/**
+ * sas_rphy_add -- add a SAS remote PHY to the device hierachy
+ * @rphy: The remote PHY to be added
+ *
+ * Publishes a SAS remote PHY to the rest of the system.
+ */
+int sas_rphy_add(struct sas_rphy *rphy)
+{
+ struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
+ struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
+ struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+ struct sas_identify *identify = &rphy->identify;
+ int error;
+
+ if (parent->rphy)
+ return -ENXIO;
+ parent->rphy = rphy;
+
+ error = device_add(&rphy->dev);
+ if (error)
+ return error;
+ transport_add_device(&rphy->dev);
+ transport_configure_device(&rphy->dev);
+
+ spin_lock(&sas_host->lock);
+ list_add_tail(&rphy->list, &sas_host->rphy_list);
+ if (identify->device_type == SAS_END_DEVICE &&
+ (identify->target_port_protocols &
+ (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA)))
+ rphy->scsi_target_id = sas_host->next_target_id++;
+ else
+ rphy->scsi_target_id = -1;
+ spin_unlock(&sas_host->lock);
+
+ if (rphy->scsi_target_id != -1) {
+ scsi_scan_target(&rphy->dev, parent->number,
+ rphy->scsi_target_id, ~0, 0);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(sas_rphy_add);
+
+/**
+ * sas_rphy_free -- free a SAS remote PHY
+ * @rphy SAS remote PHY to free
+ *
+ * Frees the specified SAS remote PHY.
+ *
+ * Note:
+ * This function must only be called on a remote
+ * PHY that has not sucessfully been added using
+ * sas_rphy_add().
+ */
+void sas_rphy_free(struct sas_rphy *rphy)
+{
+ struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
+ struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+
+ spin_lock(&sas_host->lock);
+ list_del(&rphy->list);
+ spin_unlock(&sas_host->lock);
+
+ transport_destroy_device(&rphy->dev);
+ put_device(rphy->dev.parent);
+ put_device(rphy->dev.parent);
+ put_device(rphy->dev.parent);
+ kfree(rphy);
+}
+EXPORT_SYMBOL(sas_rphy_free);
+
+/**
+ * sas_rphy_delete -- remove SAS remote PHY
+ * @rphy: SAS remote PHY to remove
+ *
+ * Removes the specified SAS remote PHY.
+ */
+void
+sas_rphy_delete(struct sas_rphy *rphy)
+{
+ struct device *dev = &rphy->dev;
+ struct sas_phy *parent = dev_to_phy(dev->parent);
+ struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
+ struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+
+ transport_destroy_device(&rphy->dev);
+
+ scsi_remove_target(&rphy->dev);
+
+ spin_lock(&sas_host->lock);
+ list_del(&rphy->list);
+ spin_unlock(&sas_host->lock);
+
+ transport_remove_device(dev);
+ device_del(dev);
+ transport_destroy_device(dev);
+ put_device(&parent->dev);
+}
+EXPORT_SYMBOL(sas_rphy_delete);
+
+/**
+ * scsi_is_sas_rphy -- check if a struct device represents a SAS remote PHY
+ * @dev: device to check
+ *
+ * Returns:
+ * %1 if the device represents a SAS remote PHY, %0 else
+ */
+int scsi_is_sas_rphy(const struct device *dev)
+{
+ return dev->release == sas_rphy_release;
+}
+EXPORT_SYMBOL(scsi_is_sas_rphy);
+
+
+/*
+ * SCSI scan helper
+ */
+
+static struct device *sas_target_parent(struct Scsi_Host *shost,
+ int channel, uint id)
+{
+ struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+ struct sas_rphy *rphy;
+ struct device *dev = NULL;
+
+ spin_lock(&sas_host->lock);
+ list_for_each_entry(rphy, &sas_host->rphy_list, list) {
+ struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
+ if (parent->number == channel &&
+ rphy->scsi_target_id == id)
+ dev = &rphy->dev;
+ }
+ spin_unlock(&sas_host->lock);
+
+ return dev;
+}
+
+
+/*
+ * Setup / Teardown code
+ */
+
+#define SETUP_RPORT_ATTRIBUTE(field) \
+ i->private_rphy_attrs[count] = class_device_attr_##field; \
+ i->private_rphy_attrs[count].attr.mode = S_IRUGO; \
+ i->private_rphy_attrs[count].store = NULL; \
+ i->rphy_attrs[count] = &i->private_rphy_attrs[count]; \
+ count++
+
+#define SETUP_PORT_ATTRIBUTE(field) \
+ i->private_phy_attrs[count] = class_device_attr_##field; \
+ i->private_phy_attrs[count].attr.mode = S_IRUGO; \
+ i->private_phy_attrs[count].store = NULL; \
+ i->phy_attrs[count] = &i->private_phy_attrs[count]; \
+ count++
+
+
+/**
+ * sas_attach_transport -- instantiate SAS transport template
+ * @ft: SAS transport class function template
+ */
+struct scsi_transport_template *
+sas_attach_transport(struct sas_function_template *ft)
+{
+ struct sas_internal *i;
+ int count;
+
+ i = kmalloc(sizeof(struct sas_internal), GFP_KERNEL);
+ if (!i)
+ return NULL;
+ memset(i, 0, sizeof(struct sas_internal));
+
+ i->t.target_parent = sas_target_parent;
+
+ i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+ i->t.host_attrs.ac.class = &sas_host_class.class;
+ i->t.host_attrs.ac.match = sas_host_match;
+ transport_container_register(&i->t.host_attrs);
+ i->t.host_size = sizeof(struct sas_host_attrs);
+
+ i->phy_attr_cont.ac.class = &sas_phy_class.class;
+ i->phy_attr_cont.ac.attrs = &i->phy_attrs[0];
+ i->phy_attr_cont.ac.match = sas_phy_match;
+ transport_container_register(&i->phy_attr_cont);
+
+ i->rphy_attr_cont.ac.class = &sas_rphy_class.class;
+ i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0];
+ i->rphy_attr_cont.ac.match = sas_rphy_match;
+ transport_container_register(&i->rphy_attr_cont);
+
+ i->f = ft;
+
+ count = 0;
+ i->host_attrs[count] = NULL;
+
+ count = 0;
+ SETUP_PORT_ATTRIBUTE(initiator_port_protocols);
+ SETUP_PORT_ATTRIBUTE(target_port_protocols);
+ SETUP_PORT_ATTRIBUTE(device_type);
+ SETUP_PORT_ATTRIBUTE(sas_address);
+ SETUP_PORT_ATTRIBUTE(phy_identifier);
+ SETUP_PORT_ATTRIBUTE(port_identifier);
+ SETUP_PORT_ATTRIBUTE(negotiated_linkrate);
+ SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw);
+ SETUP_PORT_ATTRIBUTE(minimum_linkrate);
+ SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw);
+ SETUP_PORT_ATTRIBUTE(maximum_linkrate);
+ i->phy_attrs[count] = NULL;
+
+ count = 0;
+ SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols);
+ SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols);
+ SETUP_RPORT_ATTRIBUTE(rphy_device_type);
+ SETUP_RPORT_ATTRIBUTE(rphy_sas_address);
+ SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier);
+ i->rphy_attrs[count] = NULL;
+
+ return &i->t;
+}
+EXPORT_SYMBOL(sas_attach_transport);
+
+/**
+ * sas_release_transport -- release SAS transport template instance
+ * @t: transport template instance
+ */
+void sas_release_transport(struct scsi_transport_template *t)
+{
+ struct sas_internal *i = to_sas_internal(t);
+
+ transport_container_unregister(&i->t.host_attrs);
+ transport_container_unregister(&i->phy_attr_cont);
+ transport_container_unregister(&i->rphy_attr_cont);
+
+ kfree(i);
+}
+EXPORT_SYMBOL(sas_release_transport);
+
+static __init int sas_transport_init(void)
+{
+ int error;
+
+ error = transport_class_register(&sas_host_class);
+ if (error)
+ goto out;
+ error = transport_class_register(&sas_phy_class);
+ if (error)
+ goto out_unregister_transport;
+ error = transport_class_register(&sas_rphy_class);
+ if (error)
+ goto out_unregister_phy;
+
+ return 0;
+
+ out_unregister_phy:
+ transport_class_unregister(&sas_phy_class);
+ out_unregister_transport:
+ transport_class_unregister(&sas_host_class);
+ out:
+ return error;
+
+}
+
+static void __exit sas_transport_exit(void)
+{
+ transport_class_unregister(&sas_host_class);
+ transport_class_unregister(&sas_phy_class);
+ transport_class_unregister(&sas_rphy_class);
+}
+
+MODULE_AUTHOR("Christoph Hellwig");
+MODULE_DESCRIPTION("SAS Transphy Attributes");
+MODULE_LICENSE("GPL");
+
+module_init(sas_transport_init);
+module_exit(sas_transport_exit);
Index: xfs-2.6.x/include/scsi/scsi_transport_sas.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ xfs-2.6.x/include/scsi/scsi_transport_sas.h 2005-09-09 16:23:38.000000000 +0200
@@ -0,0 +1,100 @@
+#ifndef SCSI_TRANSPORT_SAS_H
+#define SCSI_TRANSPORT_SAS_H
+
+#include <linux/transport_class.h>
+#include <linux/types.h>
+
+struct scsi_transport_template;
+struct sas_rphy;
+
+
+enum sas_device_type {
+ SAS_PHY_UNUSED,
+ SAS_END_DEVICE,
+ SAS_EDGE_EXPANDER_DEVICE,
+ SAS_FANOUT_EXPANDER_DEVICE,
+};
+
+enum sas_protocol {
+ SAS_PROTOCOL_SATA = 0x01,
+ SAS_PROTOCOL_SMP = 0x02,
+ SAS_PROTOCOL_STP = 0x04,
+ SAS_PROTOCOL_SSP = 0x08,
+};
+
+enum sas_linkrate {
+ SAS_LINK_RATE_UNKNOWN,
+ SAS_PHY_DISABLED,
+ SAS_LINK_RATE_FAILED,
+ SAS_SATA_SPINUP_HOLD,
+ SAS_SATA_PORT_SELECTOR,
+ SAS_LINK_RATE_1_5_GBPS,
+ SAS_LINK_RATE_3_0_GBPS,
+ SAS_LINK_VIRTUAL,
+};
+
+struct sas_identify {
+ enum sas_device_type device_type;
+ enum sas_protocol initiator_port_protocols;
+ enum sas_protocol target_port_protocols;
+ u64 sas_address;
+ u8 phy_identifier;
+};
+
+/* The functions by which the transport class and the driver communicate */
+struct sas_function_template {
+};
+
+struct sas_phy {
+ struct device dev;
+ int number;
+ struct sas_identify identify;
+ enum sas_linkrate negotiated_linkrate;
+ enum sas_linkrate minimum_linkrate_hw;
+ enum sas_linkrate minimum_linkrate;
+ enum sas_linkrate maximum_linkrate_hw;
+ enum sas_linkrate maximum_linkrate;
+ u8 port_identifier;
+ struct sas_rphy *rphy;
+};
+
+#define dev_to_phy(d) \
+ container_of((d), struct sas_phy, dev)
+#define transport_class_to_phy(cdev) \
+ dev_to_phy((cdev)->dev)
+#define phy_to_shost(phy) \
+ dev_to_shost((phy)->dev.parent)
+
+struct sas_rphy {
+ struct device dev;
+ struct sas_identify identify;
+ struct list_head list;
+ u32 scsi_target_id;
+};
+
+#define dev_to_rphy(d) \
+ container_of((d), struct sas_rphy, dev)
+#define transport_class_to_rphy(cdev) \
+ dev_to_rphy((cdev)->dev)
+#define rphy_to_shost(rphy) \
+ dev_to_shost((rphy)->dev.parent)
+
+extern void sas_remove_host(struct Scsi_Host *);
+
+extern struct sas_phy *sas_phy_alloc(struct device *, int);
+extern void sas_phy_free(struct sas_phy *);
+extern int sas_phy_add(struct sas_phy *);
+extern void sas_phy_delete(struct sas_phy *);
+extern int scsi_is_sas_phy(const struct device *);
+
+extern struct sas_rphy *sas_rphy_alloc(struct sas_phy *);
+void sas_rphy_free(struct sas_rphy *);
+extern int sas_rphy_add(struct sas_rphy *);
+extern void sas_rphy_delete(struct sas_rphy *);
+extern int scsi_is_sas_rphy(const struct device *);
+
+extern struct scsi_transport_template *
+sas_attach_transport(struct sas_function_template *);
+extern void sas_release_transport(struct scsi_transport_template *);
+
+#endif /* SCSI_TRANSPORT_SAS_H */
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] SAS transport class
2005-09-09 14:22 Christoph Hellwig
@ 2005-09-09 14:35 ` James Bottomley
2005-09-09 14:38 ` Christoph Hellwig
2005-09-09 23:38 ` James Bottomley
1 sibling, 1 reply; 9+ messages in thread
From: James Bottomley @ 2005-09-09 14:35 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: SCSI Mailing List
On Fri, 2005-09-09 at 16:22 +0200, Christoph Hellwig wrote:
> In addition to the basic SCSI core objects this transport class introduces
> two additional intermediate objects: The SAS PHY as represented by struct
> sas_phy defines an "outgoing" PHY on a SAS HBA or Expander, and the SAS
> remote PHY represented by struct sas_rphy defines an "incoming" PHY on a
> SAS Expander or end device. Note that this is purely a software concept, the
> underlying hardware for a PHY and a remote PHY is the exactly the same.
My only real comment is that an outgoing PHY should probably exist in a
separate class because that concept is common to SATA, so the class
should be shareable between sas/sata.
What you call a sas_rphy, when it's an expander input is the thing we're
going to want to attach an SMP tap to for the management tools
(eventually).
> I think this submission is ready for 2.6.14, but additional comments are
> of course very welcome.
Hmm ... OK ... we can try this in rc-fixes at first.
James
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] SAS transport class
2005-09-09 14:35 ` James Bottomley
@ 2005-09-09 14:38 ` Christoph Hellwig
0 siblings, 0 replies; 9+ messages in thread
From: Christoph Hellwig @ 2005-09-09 14:38 UTC (permalink / raw)
To: James Bottomley; +Cc: Christoph Hellwig, SCSI Mailing List
On Fri, Sep 09, 2005 at 09:35:36AM -0500, James Bottomley wrote:
> On Fri, 2005-09-09 at 16:22 +0200, Christoph Hellwig wrote:
> > In addition to the basic SCSI core objects this transport class introduces
> > two additional intermediate objects: The SAS PHY as represented by struct
> > sas_phy defines an "outgoing" PHY on a SAS HBA or Expander, and the SAS
> > remote PHY represented by struct sas_rphy defines an "incoming" PHY on a
> > SAS Expander or end device. Note that this is purely a software concept, the
> > underlying hardware for a PHY and a remote PHY is the exactly the same.
>
> My only real comment is that an outgoing PHY should probably exist in a
> separate class because that concept is common to SATA, so the class
> should be shareable between sas/sata.
The code should be sharable with SATA pretty much as-is. But instead
of creating ivory towers I'd say just split the code out once someone
uses it for SATA. In fact I'll probably done thay once I'm done with
the paid SAS work.
> What you call a sas_rphy, when it's an expander input is the thing we're
> going to want to attach an SMP tap to for the management tools
> (eventually).
Yes, that's the plan. I expect to work on that starting late next week
or the week after.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] SAS transport class
2005-09-09 14:22 Christoph Hellwig
2005-09-09 14:35 ` James Bottomley
@ 2005-09-09 23:38 ` James Bottomley
1 sibling, 0 replies; 9+ messages in thread
From: James Bottomley @ 2005-09-09 23:38 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: SCSI Mailing List
On Fri, 2005-09-09 at 16:22 +0200, Christoph Hellwig wrote:
> I think this submission is ready for 2.6.14, but additional comments are
> of course very welcome.
Actually, you missed a prototype change for the class functions.
James
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -156,7 +156,8 @@ sas_bitfield_name_search(linkspeed, sas_
* SAS host attributes
*/
-static int sas_host_setup(struct device *dev)
+static int sas_host_setup(struct transport_container *tc, struct device *dev,
+ struct class_device *cdev)
{
struct Scsi_Host *shost = dev_to_shost(dev);
struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2005-09-09 23:38 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-09-06 13:40 [PATCH] SAS transport class James.Smart
2005-09-06 14:00 ` Christoph Hellwig
2005-09-06 16:00 ` Stefan Richter
-- strict thread matches above, loose matches on Subject: below --
2005-09-09 14:22 Christoph Hellwig
2005-09-09 14:35 ` James Bottomley
2005-09-09 14:38 ` Christoph Hellwig
2005-09-09 23:38 ` James Bottomley
2005-09-06 14:24 James.Smart
2005-09-04 23:50 Christoph Hellwig
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox