aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@steeleye.com>2006-03-13 14:50:04 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-03-14 13:36:19 -0500
commit79cb1819e231f811211133a09a5382cb89d7ec67 (patch)
tree2bc36e3165fe15614283f628e825e9320ca7ab8e
parentc829c394165f981d49f05a9be228404d7a9398d4 (diff)
[SCSI] add preliminary expander support to the sas transport class
This patch makes expanders appear as labelled objects with properties in the SAS tree. I've also modified the phy code to make expander phys appear labelled by host number, expander number and phy index. So, for my current config, you see something like this in sysfs: /sys/class/scsi_host/host1/device/phy-1:4/expander-1:0/phy-1-0:12/rphy-1:0-12/target1:0:1 And the expander properties are: jejb@sparkweed> cd /sys/class/sas_expander/expander-1\:0/ jejb@sparkweed> for f in *; do echo -n $f ": "; cat $f; done component_id : 29024 component_revision_id : 4 component_vendor_id : VITESSE device : cat: device: Is a directory level : 0 product_id : VSC7160 Eval Brd product_rev : 4 uevent : cat: uevent: Permission denied vendor_id : VITESSE Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/scsi_transport_sas.c141
-rw-r--r--include/scsi/scsi_transport_sas.h31
2 files changed, 166 insertions, 6 deletions
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 3eb11a175904..5a70d04352cc 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -40,6 +40,7 @@
40#define SAS_PORT_ATTRS 17 40#define SAS_PORT_ATTRS 17
41#define SAS_RPORT_ATTRS 7 41#define SAS_RPORT_ATTRS 7
42#define SAS_END_DEV_ATTRS 3 42#define SAS_END_DEV_ATTRS 3
43#define SAS_EXPANDER_ATTRS 7
43 44
44struct sas_internal { 45struct sas_internal {
45 struct scsi_transport_template t; 46 struct scsi_transport_template t;
@@ -49,10 +50,12 @@ struct sas_internal {
49 struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS]; 50 struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS];
50 struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS]; 51 struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS];
51 struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS]; 52 struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS];
53 struct class_device_attribute private_expander_attrs[SAS_EXPANDER_ATTRS];
52 54
53 struct transport_container phy_attr_cont; 55 struct transport_container phy_attr_cont;
54 struct transport_container rphy_attr_cont; 56 struct transport_container rphy_attr_cont;
55 struct transport_container end_dev_attr_cont; 57 struct transport_container end_dev_attr_cont;
58 struct transport_container expander_attr_cont;
56 59
57 /* 60 /*
58 * The array of null terminated pointers to attributes 61 * The array of null terminated pointers to attributes
@@ -62,6 +65,7 @@ struct sas_internal {
62 struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1]; 65 struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1];
63 struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1]; 66 struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1];
64 struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1]; 67 struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1];
68 struct class_device_attribute *expander_attrs[SAS_EXPANDER_ATTRS + 1];
65}; 69};
66#define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t) 70#define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t)
67 71
@@ -69,6 +73,7 @@ struct sas_host_attrs {
69 struct list_head rphy_list; 73 struct list_head rphy_list;
70 struct mutex lock; 74 struct mutex lock;
71 u32 next_target_id; 75 u32 next_target_id;
76 u32 next_expander_id;
72}; 77};
73#define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data) 78#define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data)
74 79
@@ -173,6 +178,7 @@ static int sas_host_setup(struct transport_container *tc, struct device *dev,
173 INIT_LIST_HEAD(&sas_host->rphy_list); 178 INIT_LIST_HEAD(&sas_host->rphy_list);
174 mutex_init(&sas_host->lock); 179 mutex_init(&sas_host->lock);
175 sas_host->next_target_id = 0; 180 sas_host->next_target_id = 0;
181 sas_host->next_expander_id = 0;
176 return 0; 182 return 0;
177} 183}
178 184
@@ -407,7 +413,12 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number)
407 device_initialize(&phy->dev); 413 device_initialize(&phy->dev);
408 phy->dev.parent = get_device(parent); 414 phy->dev.parent = get_device(parent);
409 phy->dev.release = sas_phy_release; 415 phy->dev.release = sas_phy_release;
410 sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number); 416 if (scsi_is_sas_expander_device(parent)) {
417 struct sas_rphy *rphy = dev_to_rphy(parent);
418 sprintf(phy->dev.bus_id, "phy-%d-%d:%d", shost->host_no,
419 rphy->scsi_target_id, number);
420 } else
421 sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number);
411 422
412 transport_setup_device(&phy->dev); 423 transport_setup_device(&phy->dev);
413 424
@@ -635,6 +646,9 @@ int sas_read_port_mode_page(struct scsi_device *sdev)
635} 646}
636EXPORT_SYMBOL(sas_read_port_mode_page); 647EXPORT_SYMBOL(sas_read_port_mode_page);
637 648
649static DECLARE_TRANSPORT_CLASS(sas_end_dev_class,
650 "sas_end_device", NULL, NULL, NULL);
651
638#define sas_end_dev_show_simple(field, name, format_string, cast) \ 652#define sas_end_dev_show_simple(field, name, format_string, cast) \
639static ssize_t \ 653static ssize_t \
640show_sas_end_dev_##name(struct class_device *cdev, char *buf) \ 654show_sas_end_dev_##name(struct class_device *cdev, char *buf) \
@@ -656,8 +670,33 @@ sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout,
656sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout, 670sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout,
657 "%d\n", int); 671 "%d\n", int);
658 672
659static DECLARE_TRANSPORT_CLASS(sas_end_dev_class, 673static DECLARE_TRANSPORT_CLASS(sas_expander_class,
660 "sas_end_device", NULL, NULL, NULL); 674 "sas_expander", NULL, NULL, NULL);
675
676#define sas_expander_show_simple(field, name, format_string, cast) \
677static ssize_t \
678show_sas_expander_##name(struct class_device *cdev, char *buf) \
679{ \
680 struct sas_rphy *rphy = transport_class_to_rphy(cdev); \
681 struct sas_expander_device *edev = rphy_to_expander_device(rphy); \
682 \
683 return snprintf(buf, 20, format_string, cast edev->field); \
684}
685
686#define sas_expander_simple_attr(field, name, format_string, type) \
687 sas_expander_show_simple(field, name, format_string, (type)) \
688static SAS_CLASS_DEVICE_ATTR(expander, name, S_IRUGO, \
689 show_sas_expander_##name, NULL)
690
691sas_expander_simple_attr(vendor_id, vendor_id, "%s\n", char *);
692sas_expander_simple_attr(product_id, product_id, "%s\n", char *);
693sas_expander_simple_attr(product_rev, product_rev, "%s\n", char *);
694sas_expander_simple_attr(component_vendor_id, component_vendor_id,
695 "%s\n", char *);
696sas_expander_simple_attr(component_id, component_id, "%u\n", unsigned int);
697sas_expander_simple_attr(component_revision_id, component_revision_id, "%u\n",
698 unsigned int);
699sas_expander_simple_attr(level, level, "%d\n", int);
661 700
662static DECLARE_TRANSPORT_CLASS(sas_rphy_class, 701static DECLARE_TRANSPORT_CLASS(sas_rphy_class,
663 "sas_rphy", NULL, NULL, NULL); 702 "sas_rphy", NULL, NULL, NULL);
@@ -706,6 +745,32 @@ static int sas_end_dev_match(struct attribute_container *cont,
706 rphy->contained; 745 rphy->contained;
707} 746}
708 747
748static int sas_expander_match(struct attribute_container *cont,
749 struct device *dev)
750{
751 struct Scsi_Host *shost;
752 struct sas_internal *i;
753 struct sas_rphy *rphy;
754
755 if (!scsi_is_sas_rphy(dev))
756 return 0;
757 shost = dev_to_shost(dev->parent->parent);
758 rphy = dev_to_rphy(dev);
759
760 if (!shost->transportt)
761 return 0;
762 if (shost->transportt->host_attrs.ac.class !=
763 &sas_host_class.class)
764 return 0;
765
766 i = to_sas_internal(shost->transportt);
767 return &i->expander_attr_cont.ac == cont &&
768 (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
769 rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) &&
770 /* FIXME: remove contained eventually */
771 rphy->contained;
772}
773
709static void sas_rphy_release(struct device *dev) 774static void sas_rphy_release(struct device *dev)
710{ 775{
711 struct sas_rphy *rphy = dev_to_rphy(dev); 776 struct sas_rphy *rphy = dev_to_rphy(dev);
@@ -778,6 +843,46 @@ struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent)
778} 843}
779EXPORT_SYMBOL(sas_end_device_alloc); 844EXPORT_SYMBOL(sas_end_device_alloc);
780 845
846/**
847 * sas_expander_alloc - allocate an rphy for an end device
848 *
849 * Allocates an SAS remote PHY structure, connected to @parent.
850 *
851 * Returns:
852 * SAS PHY allocated or %NULL if the allocation failed.
853 */
854struct sas_rphy *sas_expander_alloc(struct sas_phy *parent,
855 enum sas_device_type type)
856{
857 struct Scsi_Host *shost = dev_to_shost(&parent->dev);
858 struct sas_expander_device *rdev;
859 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
860
861 BUG_ON(type != SAS_EDGE_EXPANDER_DEVICE &&
862 type != SAS_FANOUT_EXPANDER_DEVICE);
863
864 rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
865 if (!rdev) {
866 put_device(&parent->dev);
867 return NULL;
868 }
869
870 device_initialize(&rdev->rphy.dev);
871 rdev->rphy.dev.parent = get_device(&parent->dev);
872 rdev->rphy.dev.release = sas_rphy_release;
873 mutex_lock(&sas_host->lock);
874 rdev->rphy.scsi_target_id = sas_host->next_expander_id++;
875 mutex_unlock(&sas_host->lock);
876 sprintf(rdev->rphy.dev.bus_id, "expander-%d:%d",
877 shost->host_no, rdev->rphy.scsi_target_id);
878 rdev->rphy.identify.device_type = type;
879 /* FIXME: mark the rphy as being contained in a larger structure */
880 rdev->rphy.contained = 1;
881 transport_setup_device(&rdev->rphy.dev);
882
883 return &rdev->rphy;
884}
885EXPORT_SYMBOL(sas_expander_alloc);
781 886
782/** 887/**
783 * sas_rphy_add -- add a SAS remote PHY to the device hierachy 888 * sas_rphy_add -- add a SAS remote PHY to the device hierachy
@@ -809,11 +914,10 @@ int sas_rphy_add(struct sas_rphy *rphy)
809 (identify->target_port_protocols & 914 (identify->target_port_protocols &
810 (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA))) 915 (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA)))
811 rphy->scsi_target_id = sas_host->next_target_id++; 916 rphy->scsi_target_id = sas_host->next_target_id++;
812 else
813 rphy->scsi_target_id = -1;
814 mutex_unlock(&sas_host->lock); 917 mutex_unlock(&sas_host->lock);
815 918
816 if (rphy->scsi_target_id != -1) { 919 if (identify->device_type == SAS_END_DEVICE &&
920 rphy->scsi_target_id != -1) {
817 scsi_scan_target(&rphy->dev, parent->port_identifier, 921 scsi_scan_target(&rphy->dev, parent->port_identifier,
818 rphy->scsi_target_id, ~0, 0); 922 rphy->scsi_target_id, ~0, 0);
819 } 923 }
@@ -967,6 +1071,9 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
967#define SETUP_END_DEV_ATTRIBUTE(field) \ 1071#define SETUP_END_DEV_ATTRIBUTE(field) \
968 SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1) 1072 SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1)
969 1073
1074#define SETUP_EXPANDER_ATTRIBUTE(field) \
1075 SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1)
1076
970/** 1077/**
971 * sas_attach_transport -- instantiate SAS transport template 1078 * sas_attach_transport -- instantiate SAS transport template
972 * @ft: SAS transport class function template 1079 * @ft: SAS transport class function template
@@ -1004,6 +1111,11 @@ sas_attach_transport(struct sas_function_template *ft)
1004 i->end_dev_attr_cont.ac.match = sas_end_dev_match; 1111 i->end_dev_attr_cont.ac.match = sas_end_dev_match;
1005 transport_container_register(&i->end_dev_attr_cont); 1112 transport_container_register(&i->end_dev_attr_cont);
1006 1113
1114 i->expander_attr_cont.ac.class = &sas_expander_class.class;
1115 i->expander_attr_cont.ac.attrs = &i->expander_attrs[0];
1116 i->expander_attr_cont.ac.match = sas_expander_match;
1117 transport_container_register(&i->expander_attr_cont);
1118
1007 i->f = ft; 1119 i->f = ft;
1008 1120
1009 count = 0; 1121 count = 0;
@@ -1048,6 +1160,16 @@ sas_attach_transport(struct sas_function_template *ft)
1048 SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout); 1160 SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout);
1049 i->end_dev_attrs[count] = NULL; 1161 i->end_dev_attrs[count] = NULL;
1050 1162
1163 count = 0;
1164 SETUP_EXPANDER_ATTRIBUTE(vendor_id);
1165 SETUP_EXPANDER_ATTRIBUTE(product_id);
1166 SETUP_EXPANDER_ATTRIBUTE(product_rev);
1167 SETUP_EXPANDER_ATTRIBUTE(component_vendor_id);
1168 SETUP_EXPANDER_ATTRIBUTE(component_id);
1169 SETUP_EXPANDER_ATTRIBUTE(component_revision_id);
1170 SETUP_EXPANDER_ATTRIBUTE(level);
1171 i->expander_attrs[count] = NULL;
1172
1051 return &i->t; 1173 return &i->t;
1052} 1174}
1053EXPORT_SYMBOL(sas_attach_transport); 1175EXPORT_SYMBOL(sas_attach_transport);
@@ -1064,6 +1186,7 @@ void sas_release_transport(struct scsi_transport_template *t)
1064 transport_container_unregister(&i->phy_attr_cont); 1186 transport_container_unregister(&i->phy_attr_cont);
1065 transport_container_unregister(&i->rphy_attr_cont); 1187 transport_container_unregister(&i->rphy_attr_cont);
1066 transport_container_unregister(&i->end_dev_attr_cont); 1188 transport_container_unregister(&i->end_dev_attr_cont);
1189 transport_container_unregister(&i->expander_attr_cont);
1067 1190
1068 kfree(i); 1191 kfree(i);
1069} 1192}
@@ -1085,9 +1208,14 @@ static __init int sas_transport_init(void)
1085 error = transport_class_register(&sas_end_dev_class); 1208 error = transport_class_register(&sas_end_dev_class);
1086 if (error) 1209 if (error)
1087 goto out_unregister_rphy; 1210 goto out_unregister_rphy;
1211 error = transport_class_register(&sas_expander_class);
1212 if (error)
1213 goto out_unregister_end_dev;
1088 1214
1089 return 0; 1215 return 0;
1090 1216
1217 out_unregister_end_dev:
1218 transport_class_unregister(&sas_end_dev_class);
1091 out_unregister_rphy: 1219 out_unregister_rphy:
1092 transport_class_unregister(&sas_rphy_class); 1220 transport_class_unregister(&sas_rphy_class);
1093 out_unregister_phy: 1221 out_unregister_phy:
@@ -1105,6 +1233,7 @@ static void __exit sas_transport_exit(void)
1105 transport_class_unregister(&sas_phy_class); 1233 transport_class_unregister(&sas_phy_class);
1106 transport_class_unregister(&sas_rphy_class); 1234 transport_class_unregister(&sas_rphy_class);
1107 transport_class_unregister(&sas_end_dev_class); 1235 transport_class_unregister(&sas_end_dev_class);
1236 transport_class_unregister(&sas_expander_class);
1108} 1237}
1109 1238
1110MODULE_AUTHOR("Christoph Hellwig"); 1239MODULE_AUTHOR("Christoph Hellwig");
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
index 8fded431cf46..2943ccc22a43 100644
--- a/include/scsi/scsi_transport_sas.h
+++ b/include/scsi/scsi_transport_sas.h
@@ -108,6 +108,25 @@ struct sas_end_device {
108#define rphy_to_end_device(r) \ 108#define rphy_to_end_device(r) \
109 container_of((r), struct sas_end_device, rphy) 109 container_of((r), struct sas_end_device, rphy)
110 110
111struct sas_expander_device {
112 int level;
113
114 #define SAS_EXPANDER_VENDOR_ID_LEN 8
115 char vendor_id[SAS_EXPANDER_VENDOR_ID_LEN+1];
116 #define SAS_EXPANDER_PRODUCT_ID_LEN 16
117 char product_id[SAS_EXPANDER_PRODUCT_ID_LEN+1];
118 #define SAS_EXPANDER_PRODUCT_REV_LEN 4
119 char product_rev[SAS_EXPANDER_PRODUCT_REV_LEN+1];
120 #define SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN 8
121 char component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN+1];
122 u16 component_id;
123 u8 component_revision_id;
124
125 struct sas_rphy rphy;
126
127};
128#define rphy_to_expander_device(r) \
129 container_of((r), struct sas_expander_device, rphy)
111 130
112/* The functions by which the transport class and the driver communicate */ 131/* The functions by which the transport class and the driver communicate */
113struct sas_function_template { 132struct sas_function_template {
@@ -128,6 +147,7 @@ extern int scsi_is_sas_phy(const struct device *);
128 147
129extern struct sas_rphy *sas_rphy_alloc(struct sas_phy *); 148extern struct sas_rphy *sas_rphy_alloc(struct sas_phy *);
130extern struct sas_rphy *sas_end_device_alloc(struct sas_phy *); 149extern struct sas_rphy *sas_end_device_alloc(struct sas_phy *);
150extern struct sas_rphy *sas_expander_alloc(struct sas_phy *, enum sas_device_type);
131void sas_rphy_free(struct sas_rphy *); 151void sas_rphy_free(struct sas_rphy *);
132extern int sas_rphy_add(struct sas_rphy *); 152extern int sas_rphy_add(struct sas_rphy *);
133extern void sas_rphy_delete(struct sas_rphy *); 153extern void sas_rphy_delete(struct sas_rphy *);
@@ -138,4 +158,15 @@ sas_attach_transport(struct sas_function_template *);
138extern void sas_release_transport(struct scsi_transport_template *); 158extern void sas_release_transport(struct scsi_transport_template *);
139int sas_read_port_mode_page(struct scsi_device *); 159int sas_read_port_mode_page(struct scsi_device *);
140 160
161static inline int
162scsi_is_sas_expander_device(struct device *dev)
163{
164 struct sas_rphy *rphy;
165 if (!scsi_is_sas_rphy(dev))
166 return 0;
167 rphy = dev_to_rphy(dev);
168 return rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE ||
169 rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE;
170}
171
141#endif /* SCSI_TRANSPORT_SAS_H */ 172#endif /* SCSI_TRANSPORT_SAS_H */