aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 */