1c7ebbbceSChristoph Hellwig /*
2c7ebbbceSChristoph Hellwig  * Copyright (C) 2005 Dell Inc.
3c7ebbbceSChristoph Hellwig  *	Released under GPL v2.
4c7ebbbceSChristoph Hellwig  *
5c7ebbbceSChristoph Hellwig  * Serial Attached SCSI (SAS) transport class.
6c7ebbbceSChristoph Hellwig  *
7c7ebbbceSChristoph Hellwig  * The SAS transport class contains common code to deal with SAS HBAs,
8c7ebbbceSChristoph Hellwig  * an aproximated representation of SAS topologies in the driver model,
9c7ebbbceSChristoph Hellwig  * and various sysfs attributes to expose these topologies and managment
10c7ebbbceSChristoph Hellwig  * interfaces to userspace.
11c7ebbbceSChristoph Hellwig  *
12c7ebbbceSChristoph Hellwig  * In addition to the basic SCSI core objects this transport class
13c7ebbbceSChristoph Hellwig  * introduces two additional intermediate objects:  The SAS PHY
14c7ebbbceSChristoph Hellwig  * as represented by struct sas_phy defines an "outgoing" PHY on
15c7ebbbceSChristoph Hellwig  * a SAS HBA or Expander, and the SAS remote PHY represented by
16c7ebbbceSChristoph Hellwig  * struct sas_rphy defines an "incoming" PHY on a SAS Expander or
17c7ebbbceSChristoph Hellwig  * end device.  Note that this is purely a software concept, the
18c7ebbbceSChristoph Hellwig  * underlying hardware for a PHY and a remote PHY is the exactly
19c7ebbbceSChristoph Hellwig  * the same.
20c7ebbbceSChristoph Hellwig  *
21c7ebbbceSChristoph Hellwig  * There is no concept of a SAS port in this code, users can see
22c7ebbbceSChristoph Hellwig  * what PHYs form a wide port based on the port_identifier attribute,
23c7ebbbceSChristoph Hellwig  * which is the same for all PHYs in a port.
24c7ebbbceSChristoph Hellwig  */
25c7ebbbceSChristoph Hellwig 
26c7ebbbceSChristoph Hellwig #include <linux/init.h>
27c7ebbbceSChristoph Hellwig #include <linux/module.h>
28c7ebbbceSChristoph Hellwig #include <linux/err.h>
298c65b4a6STim Schmielau #include <linux/slab.h>
308c65b4a6STim Schmielau #include <linux/string.h>
31c7ebbbceSChristoph Hellwig 
32e02f3f59SChristoph Hellwig #include <scsi/scsi.h>
33c7ebbbceSChristoph Hellwig #include <scsi/scsi_device.h>
34c7ebbbceSChristoph Hellwig #include <scsi/scsi_host.h>
35c7ebbbceSChristoph Hellwig #include <scsi/scsi_transport.h>
36c7ebbbceSChristoph Hellwig #include <scsi/scsi_transport_sas.h>
37c7ebbbceSChristoph Hellwig 
38c7ebbbceSChristoph Hellwig 
39c7ebbbceSChristoph Hellwig #define SAS_HOST_ATTRS		0
4007ba3a95SChristoph Hellwig #define SAS_PORT_ATTRS		17
41c7ebbbceSChristoph Hellwig #define SAS_RPORT_ATTRS		5
42c7ebbbceSChristoph Hellwig 
43c7ebbbceSChristoph Hellwig struct sas_internal {
44c7ebbbceSChristoph Hellwig 	struct scsi_transport_template t;
45c7ebbbceSChristoph Hellwig 	struct sas_function_template *f;
46c7ebbbceSChristoph Hellwig 
47c7ebbbceSChristoph Hellwig 	struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS];
48c7ebbbceSChristoph Hellwig 	struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS];
49c7ebbbceSChristoph Hellwig 	struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS];
50c7ebbbceSChristoph Hellwig 
51c7ebbbceSChristoph Hellwig 	struct transport_container phy_attr_cont;
52c7ebbbceSChristoph Hellwig 	struct transport_container rphy_attr_cont;
53c7ebbbceSChristoph Hellwig 
54c7ebbbceSChristoph Hellwig 	/*
55c7ebbbceSChristoph Hellwig 	 * The array of null terminated pointers to attributes
56c7ebbbceSChristoph Hellwig 	 * needed by scsi_sysfs.c
57c7ebbbceSChristoph Hellwig 	 */
58c7ebbbceSChristoph Hellwig 	struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1];
59c7ebbbceSChristoph Hellwig 	struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1];
60c7ebbbceSChristoph Hellwig 	struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1];
61c7ebbbceSChristoph Hellwig };
62c7ebbbceSChristoph Hellwig #define to_sas_internal(tmpl)	container_of(tmpl, struct sas_internal, t)
63c7ebbbceSChristoph Hellwig 
64c7ebbbceSChristoph Hellwig struct sas_host_attrs {
65c7ebbbceSChristoph Hellwig 	struct list_head rphy_list;
66e02f3f59SChristoph Hellwig 	struct mutex lock;
67c7ebbbceSChristoph Hellwig 	u32 next_target_id;
68c7ebbbceSChristoph Hellwig };
69c7ebbbceSChristoph Hellwig #define to_sas_host_attrs(host)	((struct sas_host_attrs *)(host)->shost_data)
70c7ebbbceSChristoph Hellwig 
71c7ebbbceSChristoph Hellwig 
72c7ebbbceSChristoph Hellwig /*
73c7ebbbceSChristoph Hellwig  * Hack to allow attributes of the same name in different objects.
74c7ebbbceSChristoph Hellwig  */
75c7ebbbceSChristoph Hellwig #define SAS_CLASS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \
76c7ebbbceSChristoph Hellwig 	struct class_device_attribute class_device_attr_##_prefix##_##_name = \
77c7ebbbceSChristoph Hellwig 	__ATTR(_name,_mode,_show,_store)
78c7ebbbceSChristoph Hellwig 
79c7ebbbceSChristoph Hellwig 
80c7ebbbceSChristoph Hellwig /*
81c7ebbbceSChristoph Hellwig  * Pretty printing helpers
82c7ebbbceSChristoph Hellwig  */
83c7ebbbceSChristoph Hellwig 
84c7ebbbceSChristoph Hellwig #define sas_bitfield_name_match(title, table)			\
85c7ebbbceSChristoph Hellwig static ssize_t							\
86c7ebbbceSChristoph Hellwig get_sas_##title##_names(u32 table_key, char *buf)		\
87c7ebbbceSChristoph Hellwig {								\
88c7ebbbceSChristoph Hellwig 	char *prefix = "";					\
89c7ebbbceSChristoph Hellwig 	ssize_t len = 0;					\
90c7ebbbceSChristoph Hellwig 	int i;							\
91c7ebbbceSChristoph Hellwig 								\
92c7ebbbceSChristoph Hellwig 	for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) {	\
93c7ebbbceSChristoph Hellwig 		if (table[i].value & table_key) {		\
94c7ebbbceSChristoph Hellwig 			len += sprintf(buf + len, "%s%s",	\
95c7ebbbceSChristoph Hellwig 				prefix, table[i].name);		\
96c7ebbbceSChristoph Hellwig 			prefix = ", ";				\
97c7ebbbceSChristoph Hellwig 		}						\
98c7ebbbceSChristoph Hellwig 	}							\
99c7ebbbceSChristoph Hellwig 	len += sprintf(buf + len, "\n");			\
100c7ebbbceSChristoph Hellwig 	return len;						\
101c7ebbbceSChristoph Hellwig }
102c7ebbbceSChristoph Hellwig 
103c7ebbbceSChristoph Hellwig #define sas_bitfield_name_search(title, table)			\
104c7ebbbceSChristoph Hellwig static ssize_t							\
105c7ebbbceSChristoph Hellwig get_sas_##title##_names(u32 table_key, char *buf)		\
106c7ebbbceSChristoph Hellwig {								\
107c7ebbbceSChristoph Hellwig 	ssize_t len = 0;					\
108c7ebbbceSChristoph Hellwig 	int i;							\
109c7ebbbceSChristoph Hellwig 								\
110c7ebbbceSChristoph Hellwig 	for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) {	\
111c7ebbbceSChristoph Hellwig 		if (table[i].value == table_key) {		\
112c7ebbbceSChristoph Hellwig 			len += sprintf(buf + len, "%s",		\
113c7ebbbceSChristoph Hellwig 				table[i].name);			\
114c7ebbbceSChristoph Hellwig 			break;					\
115c7ebbbceSChristoph Hellwig 		}						\
116c7ebbbceSChristoph Hellwig 	}							\
117c7ebbbceSChristoph Hellwig 	len += sprintf(buf + len, "\n");			\
118c7ebbbceSChristoph Hellwig 	return len;						\
119c7ebbbceSChristoph Hellwig }
120c7ebbbceSChristoph Hellwig 
121c7ebbbceSChristoph Hellwig static struct {
122c7ebbbceSChristoph Hellwig 	u32		value;
123c7ebbbceSChristoph Hellwig 	char		*name;
124c7ebbbceSChristoph Hellwig } sas_device_type_names[] = {
125c7ebbbceSChristoph Hellwig 	{ SAS_PHY_UNUSED,		"unused" },
126c7ebbbceSChristoph Hellwig 	{ SAS_END_DEVICE,		"end device" },
127c7ebbbceSChristoph Hellwig 	{ SAS_EDGE_EXPANDER_DEVICE,	"edge expander" },
128c7ebbbceSChristoph Hellwig 	{ SAS_FANOUT_EXPANDER_DEVICE,	"fanout expander" },
129c7ebbbceSChristoph Hellwig };
130c7ebbbceSChristoph Hellwig sas_bitfield_name_search(device_type, sas_device_type_names)
131c7ebbbceSChristoph Hellwig 
132c7ebbbceSChristoph Hellwig 
133c7ebbbceSChristoph Hellwig static struct {
134c7ebbbceSChristoph Hellwig 	u32		value;
135c7ebbbceSChristoph Hellwig 	char		*name;
136c7ebbbceSChristoph Hellwig } sas_protocol_names[] = {
137c7ebbbceSChristoph Hellwig 	{ SAS_PROTOCOL_SATA,		"sata" },
138c7ebbbceSChristoph Hellwig 	{ SAS_PROTOCOL_SMP,		"smp" },
139c7ebbbceSChristoph Hellwig 	{ SAS_PROTOCOL_STP,		"stp" },
140c7ebbbceSChristoph Hellwig 	{ SAS_PROTOCOL_SSP,		"ssp" },
141c7ebbbceSChristoph Hellwig };
142c7ebbbceSChristoph Hellwig sas_bitfield_name_match(protocol, sas_protocol_names)
143c7ebbbceSChristoph Hellwig 
144c7ebbbceSChristoph Hellwig static struct {
145c7ebbbceSChristoph Hellwig 	u32		value;
146c7ebbbceSChristoph Hellwig 	char		*name;
147c7ebbbceSChristoph Hellwig } sas_linkspeed_names[] = {
148c7ebbbceSChristoph Hellwig 	{ SAS_LINK_RATE_UNKNOWN,	"Unknown" },
149c7ebbbceSChristoph Hellwig 	{ SAS_PHY_DISABLED,		"Phy disabled" },
150c7ebbbceSChristoph Hellwig 	{ SAS_LINK_RATE_FAILED,		"Link Rate failed" },
151c7ebbbceSChristoph Hellwig 	{ SAS_SATA_SPINUP_HOLD,		"Spin-up hold" },
152c7ebbbceSChristoph Hellwig 	{ SAS_LINK_RATE_1_5_GBPS,	"1.5 Gbit" },
153c7ebbbceSChristoph Hellwig 	{ SAS_LINK_RATE_3_0_GBPS,	"3.0 Gbit" },
154c7ebbbceSChristoph Hellwig };
155c7ebbbceSChristoph Hellwig sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
156c7ebbbceSChristoph Hellwig 
157c7ebbbceSChristoph Hellwig 
158c7ebbbceSChristoph Hellwig /*
159c7ebbbceSChristoph Hellwig  * SAS host attributes
160c7ebbbceSChristoph Hellwig  */
161c7ebbbceSChristoph Hellwig 
16237be6eebSJames Bottomley static int sas_host_setup(struct transport_container *tc, struct device *dev,
16337be6eebSJames Bottomley 			  struct class_device *cdev)
164c7ebbbceSChristoph Hellwig {
165c7ebbbceSChristoph Hellwig 	struct Scsi_Host *shost = dev_to_shost(dev);
166c7ebbbceSChristoph Hellwig 	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
167c7ebbbceSChristoph Hellwig 
168c7ebbbceSChristoph Hellwig 	INIT_LIST_HEAD(&sas_host->rphy_list);
169e02f3f59SChristoph Hellwig 	mutex_init(&sas_host->lock);
170c7ebbbceSChristoph Hellwig 	sas_host->next_target_id = 0;
171c7ebbbceSChristoph Hellwig 	return 0;
172c7ebbbceSChristoph Hellwig }
173c7ebbbceSChristoph Hellwig 
174c7ebbbceSChristoph Hellwig static DECLARE_TRANSPORT_CLASS(sas_host_class,
175c7ebbbceSChristoph Hellwig 		"sas_host", sas_host_setup, NULL, NULL);
176c7ebbbceSChristoph Hellwig 
177c7ebbbceSChristoph Hellwig static int sas_host_match(struct attribute_container *cont,
178c7ebbbceSChristoph Hellwig 			    struct device *dev)
179c7ebbbceSChristoph Hellwig {
180c7ebbbceSChristoph Hellwig 	struct Scsi_Host *shost;
181c7ebbbceSChristoph Hellwig 	struct sas_internal *i;
182c7ebbbceSChristoph Hellwig 
183c7ebbbceSChristoph Hellwig 	if (!scsi_is_host_device(dev))
184c7ebbbceSChristoph Hellwig 		return 0;
185c7ebbbceSChristoph Hellwig 	shost = dev_to_shost(dev);
186c7ebbbceSChristoph Hellwig 
187c7ebbbceSChristoph Hellwig 	if (!shost->transportt)
188c7ebbbceSChristoph Hellwig 		return 0;
189c7ebbbceSChristoph Hellwig 	if (shost->transportt->host_attrs.ac.class !=
190c7ebbbceSChristoph Hellwig 			&sas_host_class.class)
191c7ebbbceSChristoph Hellwig 		return 0;
192c7ebbbceSChristoph Hellwig 
193c7ebbbceSChristoph Hellwig 	i = to_sas_internal(shost->transportt);
194c7ebbbceSChristoph Hellwig 	return &i->t.host_attrs.ac == cont;
195c7ebbbceSChristoph Hellwig }
196c7ebbbceSChristoph Hellwig 
197c7ebbbceSChristoph Hellwig static int do_sas_phy_delete(struct device *dev, void *data)
198c7ebbbceSChristoph Hellwig {
199c7ebbbceSChristoph Hellwig 	if (scsi_is_sas_phy(dev))
200c7ebbbceSChristoph Hellwig 		sas_phy_delete(dev_to_phy(dev));
201c7ebbbceSChristoph Hellwig 	return 0;
202c7ebbbceSChristoph Hellwig }
203c7ebbbceSChristoph Hellwig 
204c7ebbbceSChristoph Hellwig /**
205c7ebbbceSChristoph Hellwig  * sas_remove_host  --  tear down a Scsi_Host's SAS data structures
206c7ebbbceSChristoph Hellwig  * @shost:	Scsi Host that is torn down
207c7ebbbceSChristoph Hellwig  *
208c7ebbbceSChristoph Hellwig  * Removes all SAS PHYs and remote PHYs for a given Scsi_Host.
209c7ebbbceSChristoph Hellwig  * Must be called just before scsi_remove_host for SAS HBAs.
210c7ebbbceSChristoph Hellwig  */
211c7ebbbceSChristoph Hellwig void sas_remove_host(struct Scsi_Host *shost)
212c7ebbbceSChristoph Hellwig {
213c7ebbbceSChristoph Hellwig 	device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete);
214c7ebbbceSChristoph Hellwig }
215c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_remove_host);
216c7ebbbceSChristoph Hellwig 
217c7ebbbceSChristoph Hellwig 
218c7ebbbceSChristoph Hellwig /*
219c7ebbbceSChristoph Hellwig  * SAS Port attributes
220c7ebbbceSChristoph Hellwig  */
221c7ebbbceSChristoph Hellwig 
222c7ebbbceSChristoph Hellwig #define sas_phy_show_simple(field, name, format_string, cast)		\
223c7ebbbceSChristoph Hellwig static ssize_t								\
224c7ebbbceSChristoph Hellwig show_sas_phy_##name(struct class_device *cdev, char *buf)		\
225c7ebbbceSChristoph Hellwig {									\
226c7ebbbceSChristoph Hellwig 	struct sas_phy *phy = transport_class_to_phy(cdev);		\
227c7ebbbceSChristoph Hellwig 									\
228c7ebbbceSChristoph Hellwig 	return snprintf(buf, 20, format_string, cast phy->field);	\
229c7ebbbceSChristoph Hellwig }
230c7ebbbceSChristoph Hellwig 
231c7ebbbceSChristoph Hellwig #define sas_phy_simple_attr(field, name, format_string, type)		\
232c7ebbbceSChristoph Hellwig 	sas_phy_show_simple(field, name, format_string, (type))	\
233c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
234c7ebbbceSChristoph Hellwig 
235c7ebbbceSChristoph Hellwig #define sas_phy_show_protocol(field, name)				\
236c7ebbbceSChristoph Hellwig static ssize_t								\
237c7ebbbceSChristoph Hellwig show_sas_phy_##name(struct class_device *cdev, char *buf)		\
238c7ebbbceSChristoph Hellwig {									\
239c7ebbbceSChristoph Hellwig 	struct sas_phy *phy = transport_class_to_phy(cdev);		\
240c7ebbbceSChristoph Hellwig 									\
241c7ebbbceSChristoph Hellwig 	if (!phy->field)						\
242c7ebbbceSChristoph Hellwig 		return snprintf(buf, 20, "none\n");			\
243c7ebbbceSChristoph Hellwig 	return get_sas_protocol_names(phy->field, buf);		\
244c7ebbbceSChristoph Hellwig }
245c7ebbbceSChristoph Hellwig 
246c7ebbbceSChristoph Hellwig #define sas_phy_protocol_attr(field, name)				\
247c7ebbbceSChristoph Hellwig 	sas_phy_show_protocol(field, name)				\
248c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
249c7ebbbceSChristoph Hellwig 
250c7ebbbceSChristoph Hellwig #define sas_phy_show_linkspeed(field)					\
251c7ebbbceSChristoph Hellwig static ssize_t								\
252c7ebbbceSChristoph Hellwig show_sas_phy_##field(struct class_device *cdev, char *buf)		\
253c7ebbbceSChristoph Hellwig {									\
254c7ebbbceSChristoph Hellwig 	struct sas_phy *phy = transport_class_to_phy(cdev);		\
255c7ebbbceSChristoph Hellwig 									\
256c7ebbbceSChristoph Hellwig 	return get_sas_linkspeed_names(phy->field, buf);		\
257c7ebbbceSChristoph Hellwig }
258c7ebbbceSChristoph Hellwig 
259c7ebbbceSChristoph Hellwig #define sas_phy_linkspeed_attr(field)					\
260c7ebbbceSChristoph Hellwig 	sas_phy_show_linkspeed(field)					\
261c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
262c7ebbbceSChristoph Hellwig 
263c3ee74c4SChristoph Hellwig #define sas_phy_show_linkerror(field)					\
264c3ee74c4SChristoph Hellwig static ssize_t								\
265c3ee74c4SChristoph Hellwig show_sas_phy_##field(struct class_device *cdev, char *buf)		\
266c3ee74c4SChristoph Hellwig {									\
267c3ee74c4SChristoph Hellwig 	struct sas_phy *phy = transport_class_to_phy(cdev);		\
268c3ee74c4SChristoph Hellwig 	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);	\
269c3ee74c4SChristoph Hellwig 	struct sas_internal *i = to_sas_internal(shost->transportt);	\
270c3ee74c4SChristoph Hellwig 	int error;							\
271c3ee74c4SChristoph Hellwig 									\
272ac01bbbdSChristoph Hellwig 	if (!phy->local_attached)					\
273ac01bbbdSChristoph Hellwig 		return -EINVAL;						\
274ac01bbbdSChristoph Hellwig 									\
275c3ee74c4SChristoph Hellwig 	error = i->f->get_linkerrors(phy);				\
276c3ee74c4SChristoph Hellwig 	if (error)							\
277c3ee74c4SChristoph Hellwig 		return error;						\
278c3ee74c4SChristoph Hellwig 	return snprintf(buf, 20, "%u\n", phy->field);			\
279c3ee74c4SChristoph Hellwig }
280c3ee74c4SChristoph Hellwig 
281c3ee74c4SChristoph Hellwig #define sas_phy_linkerror_attr(field)					\
282c3ee74c4SChristoph Hellwig 	sas_phy_show_linkerror(field)					\
283c3ee74c4SChristoph Hellwig static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
284c3ee74c4SChristoph Hellwig 
285c3ee74c4SChristoph Hellwig 
286c7ebbbceSChristoph Hellwig static ssize_t
287c7ebbbceSChristoph Hellwig show_sas_device_type(struct class_device *cdev, char *buf)
288c7ebbbceSChristoph Hellwig {
289c7ebbbceSChristoph Hellwig 	struct sas_phy *phy = transport_class_to_phy(cdev);
290c7ebbbceSChristoph Hellwig 
291c7ebbbceSChristoph Hellwig 	if (!phy->identify.device_type)
292c7ebbbceSChristoph Hellwig 		return snprintf(buf, 20, "none\n");
293c7ebbbceSChristoph Hellwig 	return get_sas_device_type_names(phy->identify.device_type, buf);
294c7ebbbceSChristoph Hellwig }
295c7ebbbceSChristoph Hellwig static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL);
296c7ebbbceSChristoph Hellwig 
29707ba3a95SChristoph Hellwig static ssize_t do_sas_phy_reset(struct class_device *cdev,
29807ba3a95SChristoph Hellwig 		size_t count, int hard_reset)
29907ba3a95SChristoph Hellwig {
30007ba3a95SChristoph Hellwig 	struct sas_phy *phy = transport_class_to_phy(cdev);
30107ba3a95SChristoph Hellwig 	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
30207ba3a95SChristoph Hellwig 	struct sas_internal *i = to_sas_internal(shost->transportt);
30307ba3a95SChristoph Hellwig 	int error;
30407ba3a95SChristoph Hellwig 
30507ba3a95SChristoph Hellwig 	if (!phy->local_attached)
30607ba3a95SChristoph Hellwig 		return -EINVAL;
30707ba3a95SChristoph Hellwig 
30807ba3a95SChristoph Hellwig 	error = i->f->phy_reset(phy, hard_reset);
30907ba3a95SChristoph Hellwig 	if (error)
31007ba3a95SChristoph Hellwig 		return error;
31107ba3a95SChristoph Hellwig 	return count;
31207ba3a95SChristoph Hellwig };
31307ba3a95SChristoph Hellwig 
31407ba3a95SChristoph Hellwig static ssize_t store_sas_link_reset(struct class_device *cdev,
31507ba3a95SChristoph Hellwig 		const char *buf, size_t count)
31607ba3a95SChristoph Hellwig {
31707ba3a95SChristoph Hellwig 	return do_sas_phy_reset(cdev, count, 0);
31807ba3a95SChristoph Hellwig }
31907ba3a95SChristoph Hellwig static CLASS_DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset);
32007ba3a95SChristoph Hellwig 
32107ba3a95SChristoph Hellwig static ssize_t store_sas_hard_reset(struct class_device *cdev,
32207ba3a95SChristoph Hellwig 		const char *buf, size_t count)
32307ba3a95SChristoph Hellwig {
32407ba3a95SChristoph Hellwig 	return do_sas_phy_reset(cdev, count, 1);
32507ba3a95SChristoph Hellwig }
32607ba3a95SChristoph Hellwig static CLASS_DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset);
32707ba3a95SChristoph Hellwig 
328c7ebbbceSChristoph Hellwig sas_phy_protocol_attr(identify.initiator_port_protocols,
329c7ebbbceSChristoph Hellwig 		initiator_port_protocols);
330c7ebbbceSChristoph Hellwig sas_phy_protocol_attr(identify.target_port_protocols,
331c7ebbbceSChristoph Hellwig 		target_port_protocols);
332c7ebbbceSChristoph Hellwig sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
333c7ebbbceSChristoph Hellwig 		unsigned long long);
334c7ebbbceSChristoph Hellwig sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
335c7ebbbceSChristoph Hellwig sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8);
336c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(negotiated_linkrate);
337c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(minimum_linkrate_hw);
338c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(minimum_linkrate);
339c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(maximum_linkrate_hw);
340c7ebbbceSChristoph Hellwig sas_phy_linkspeed_attr(maximum_linkrate);
341c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(invalid_dword_count);
342c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(running_disparity_error_count);
343c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(loss_of_dword_sync_count);
344c3ee74c4SChristoph Hellwig sas_phy_linkerror_attr(phy_reset_problem_count);
345c7ebbbceSChristoph Hellwig 
346c7ebbbceSChristoph Hellwig 
347c7ebbbceSChristoph Hellwig static DECLARE_TRANSPORT_CLASS(sas_phy_class,
348c7ebbbceSChristoph Hellwig 		"sas_phy", NULL, NULL, NULL);
349c7ebbbceSChristoph Hellwig 
350c7ebbbceSChristoph Hellwig static int sas_phy_match(struct attribute_container *cont, struct device *dev)
351c7ebbbceSChristoph Hellwig {
352c7ebbbceSChristoph Hellwig 	struct Scsi_Host *shost;
353c7ebbbceSChristoph Hellwig 	struct sas_internal *i;
354c7ebbbceSChristoph Hellwig 
355c7ebbbceSChristoph Hellwig 	if (!scsi_is_sas_phy(dev))
356c7ebbbceSChristoph Hellwig 		return 0;
357c7ebbbceSChristoph Hellwig 	shost = dev_to_shost(dev->parent);
358c7ebbbceSChristoph Hellwig 
359c7ebbbceSChristoph Hellwig 	if (!shost->transportt)
360c7ebbbceSChristoph Hellwig 		return 0;
361c7ebbbceSChristoph Hellwig 	if (shost->transportt->host_attrs.ac.class !=
362c7ebbbceSChristoph Hellwig 			&sas_host_class.class)
363c7ebbbceSChristoph Hellwig 		return 0;
364c7ebbbceSChristoph Hellwig 
365c7ebbbceSChristoph Hellwig 	i = to_sas_internal(shost->transportt);
366c7ebbbceSChristoph Hellwig 	return &i->phy_attr_cont.ac == cont;
367c7ebbbceSChristoph Hellwig }
368c7ebbbceSChristoph Hellwig 
369c7ebbbceSChristoph Hellwig static void sas_phy_release(struct device *dev)
370c7ebbbceSChristoph Hellwig {
371c7ebbbceSChristoph Hellwig 	struct sas_phy *phy = dev_to_phy(dev);
372c7ebbbceSChristoph Hellwig 
373c7ebbbceSChristoph Hellwig 	put_device(dev->parent);
374c7ebbbceSChristoph Hellwig 	kfree(phy);
375c7ebbbceSChristoph Hellwig }
376c7ebbbceSChristoph Hellwig 
377c7ebbbceSChristoph Hellwig /**
378c7ebbbceSChristoph Hellwig  * sas_phy_alloc  --  allocates and initialize a SAS PHY structure
379c7ebbbceSChristoph Hellwig  * @parent:	Parent device
380c7ebbbceSChristoph Hellwig  * @number:	Port number
381c7ebbbceSChristoph Hellwig  *
382c7ebbbceSChristoph Hellwig  * Allocates an SAS PHY structure.  It will be added in the device tree
383c7ebbbceSChristoph Hellwig  * below the device specified by @parent, which has to be either a Scsi_Host
384c7ebbbceSChristoph Hellwig  * or sas_rphy.
385c7ebbbceSChristoph Hellwig  *
386c7ebbbceSChristoph Hellwig  * Returns:
387c7ebbbceSChristoph Hellwig  *	SAS PHY allocated or %NULL if the allocation failed.
388c7ebbbceSChristoph Hellwig  */
389c7ebbbceSChristoph Hellwig struct sas_phy *sas_phy_alloc(struct device *parent, int number)
390c7ebbbceSChristoph Hellwig {
391c7ebbbceSChristoph Hellwig 	struct Scsi_Host *shost = dev_to_shost(parent);
392c7ebbbceSChristoph Hellwig 	struct sas_phy *phy;
393c7ebbbceSChristoph Hellwig 
394c7ebbbceSChristoph Hellwig 	phy = kmalloc(sizeof(*phy), GFP_KERNEL);
395c7ebbbceSChristoph Hellwig 	if (!phy)
396c7ebbbceSChristoph Hellwig 		return NULL;
397c7ebbbceSChristoph Hellwig 	memset(phy, 0, sizeof(*phy));
398c7ebbbceSChristoph Hellwig 
399c7ebbbceSChristoph Hellwig 	get_device(parent);
400c7ebbbceSChristoph Hellwig 
401c7ebbbceSChristoph Hellwig 	phy->number = number;
402c7ebbbceSChristoph Hellwig 
403c7ebbbceSChristoph Hellwig 	device_initialize(&phy->dev);
404c7ebbbceSChristoph Hellwig 	phy->dev.parent = get_device(parent);
405c7ebbbceSChristoph Hellwig 	phy->dev.release = sas_phy_release;
406c7ebbbceSChristoph Hellwig 	sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number);
407c7ebbbceSChristoph Hellwig 
408c7ebbbceSChristoph Hellwig 	transport_setup_device(&phy->dev);
409c7ebbbceSChristoph Hellwig 
410c7ebbbceSChristoph Hellwig 	return phy;
411c7ebbbceSChristoph Hellwig }
412c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_alloc);
413c7ebbbceSChristoph Hellwig 
414c7ebbbceSChristoph Hellwig /**
415c7ebbbceSChristoph Hellwig  * sas_phy_add  --  add a SAS PHY to the device hierachy
416c7ebbbceSChristoph Hellwig  * @phy:	The PHY to be added
417c7ebbbceSChristoph Hellwig  *
418c7ebbbceSChristoph Hellwig  * Publishes a SAS PHY to the rest of the system.
419c7ebbbceSChristoph Hellwig  */
420c7ebbbceSChristoph Hellwig int sas_phy_add(struct sas_phy *phy)
421c7ebbbceSChristoph Hellwig {
422c7ebbbceSChristoph Hellwig 	int error;
423c7ebbbceSChristoph Hellwig 
424c7ebbbceSChristoph Hellwig 	error = device_add(&phy->dev);
425c7ebbbceSChristoph Hellwig 	if (!error) {
426c7ebbbceSChristoph Hellwig 		transport_add_device(&phy->dev);
427c7ebbbceSChristoph Hellwig 		transport_configure_device(&phy->dev);
428c7ebbbceSChristoph Hellwig 	}
429c7ebbbceSChristoph Hellwig 
430c7ebbbceSChristoph Hellwig 	return error;
431c7ebbbceSChristoph Hellwig }
432c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_add);
433c7ebbbceSChristoph Hellwig 
434c7ebbbceSChristoph Hellwig /**
435c7ebbbceSChristoph Hellwig  * sas_phy_free  --  free a SAS PHY
436c7ebbbceSChristoph Hellwig  * @phy:	SAS PHY to free
437c7ebbbceSChristoph Hellwig  *
438c7ebbbceSChristoph Hellwig  * Frees the specified SAS PHY.
439c7ebbbceSChristoph Hellwig  *
440c7ebbbceSChristoph Hellwig  * Note:
441c7ebbbceSChristoph Hellwig  *   This function must only be called on a PHY that has not
442c7ebbbceSChristoph Hellwig  *   sucessfully been added using sas_phy_add().
443c7ebbbceSChristoph Hellwig  */
444c7ebbbceSChristoph Hellwig void sas_phy_free(struct sas_phy *phy)
445c7ebbbceSChristoph Hellwig {
446c7ebbbceSChristoph Hellwig 	transport_destroy_device(&phy->dev);
447c7ebbbceSChristoph Hellwig 	put_device(phy->dev.parent);
448c7ebbbceSChristoph Hellwig 	put_device(phy->dev.parent);
449c7ebbbceSChristoph Hellwig 	put_device(phy->dev.parent);
450c7ebbbceSChristoph Hellwig 	kfree(phy);
451c7ebbbceSChristoph Hellwig }
452c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_free);
453c7ebbbceSChristoph Hellwig 
454c7ebbbceSChristoph Hellwig /**
455c7ebbbceSChristoph Hellwig  * sas_phy_delete  --  remove SAS PHY
456c7ebbbceSChristoph Hellwig  * @phy:	SAS PHY to remove
457c7ebbbceSChristoph Hellwig  *
458c7ebbbceSChristoph Hellwig  * Removes the specified SAS PHY.  If the SAS PHY has an
459c7ebbbceSChristoph Hellwig  * associated remote PHY it is removed before.
460c7ebbbceSChristoph Hellwig  */
461c7ebbbceSChristoph Hellwig void
462c7ebbbceSChristoph Hellwig sas_phy_delete(struct sas_phy *phy)
463c7ebbbceSChristoph Hellwig {
464c7ebbbceSChristoph Hellwig 	struct device *dev = &phy->dev;
465c7ebbbceSChristoph Hellwig 
466c7ebbbceSChristoph Hellwig 	if (phy->rphy)
467c7ebbbceSChristoph Hellwig 		sas_rphy_delete(phy->rphy);
468c7ebbbceSChristoph Hellwig 
469c7ebbbceSChristoph Hellwig 	transport_remove_device(dev);
470c7ebbbceSChristoph Hellwig 	device_del(dev);
471c7ebbbceSChristoph Hellwig 	transport_destroy_device(dev);
472c7ebbbceSChristoph Hellwig 	put_device(dev->parent);
473c7ebbbceSChristoph Hellwig }
474c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_phy_delete);
475c7ebbbceSChristoph Hellwig 
476c7ebbbceSChristoph Hellwig /**
477c7ebbbceSChristoph Hellwig  * scsi_is_sas_phy  --  check if a struct device represents a SAS PHY
478c7ebbbceSChristoph Hellwig  * @dev:	device to check
479c7ebbbceSChristoph Hellwig  *
480c7ebbbceSChristoph Hellwig  * Returns:
481c7ebbbceSChristoph Hellwig  *	%1 if the device represents a SAS PHY, %0 else
482c7ebbbceSChristoph Hellwig  */
483c7ebbbceSChristoph Hellwig int scsi_is_sas_phy(const struct device *dev)
484c7ebbbceSChristoph Hellwig {
485c7ebbbceSChristoph Hellwig 	return dev->release == sas_phy_release;
486c7ebbbceSChristoph Hellwig }
487c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(scsi_is_sas_phy);
488c7ebbbceSChristoph Hellwig 
489c7ebbbceSChristoph Hellwig /*
490c7ebbbceSChristoph Hellwig  * SAS remote PHY attributes.
491c7ebbbceSChristoph Hellwig  */
492c7ebbbceSChristoph Hellwig 
493c7ebbbceSChristoph Hellwig #define sas_rphy_show_simple(field, name, format_string, cast)		\
494c7ebbbceSChristoph Hellwig static ssize_t								\
495c7ebbbceSChristoph Hellwig show_sas_rphy_##name(struct class_device *cdev, char *buf)		\
496c7ebbbceSChristoph Hellwig {									\
497c7ebbbceSChristoph Hellwig 	struct sas_rphy *rphy = transport_class_to_rphy(cdev);	\
498c7ebbbceSChristoph Hellwig 									\
499c7ebbbceSChristoph Hellwig 	return snprintf(buf, 20, format_string, cast rphy->field);	\
500c7ebbbceSChristoph Hellwig }
501c7ebbbceSChristoph Hellwig 
502c7ebbbceSChristoph Hellwig #define sas_rphy_simple_attr(field, name, format_string, type)		\
503c7ebbbceSChristoph Hellwig 	sas_rphy_show_simple(field, name, format_string, (type))	\
504c7ebbbceSChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, 			\
505c7ebbbceSChristoph Hellwig 		show_sas_rphy_##name, NULL)
506c7ebbbceSChristoph Hellwig 
507c7ebbbceSChristoph Hellwig #define sas_rphy_show_protocol(field, name)				\
508c7ebbbceSChristoph Hellwig static ssize_t								\
509c7ebbbceSChristoph Hellwig show_sas_rphy_##name(struct class_device *cdev, char *buf)		\
510c7ebbbceSChristoph Hellwig {									\
511c7ebbbceSChristoph Hellwig 	struct sas_rphy *rphy = transport_class_to_rphy(cdev);	\
512c7ebbbceSChristoph Hellwig 									\
513c7ebbbceSChristoph Hellwig 	if (!rphy->field)					\
514c7ebbbceSChristoph Hellwig 		return snprintf(buf, 20, "none\n");			\
515c7ebbbceSChristoph Hellwig 	return get_sas_protocol_names(rphy->field, buf);	\
516c7ebbbceSChristoph Hellwig }
517c7ebbbceSChristoph Hellwig 
518c7ebbbceSChristoph Hellwig #define sas_rphy_protocol_attr(field, name)				\
519c7ebbbceSChristoph Hellwig 	sas_rphy_show_protocol(field, name)				\
520c7ebbbceSChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO,			\
521c7ebbbceSChristoph Hellwig 		show_sas_rphy_##name, NULL)
522c7ebbbceSChristoph Hellwig 
523c7ebbbceSChristoph Hellwig static ssize_t
524c7ebbbceSChristoph Hellwig show_sas_rphy_device_type(struct class_device *cdev, char *buf)
525c7ebbbceSChristoph Hellwig {
526c7ebbbceSChristoph Hellwig 	struct sas_rphy *rphy = transport_class_to_rphy(cdev);
527c7ebbbceSChristoph Hellwig 
528c7ebbbceSChristoph Hellwig 	if (!rphy->identify.device_type)
529c7ebbbceSChristoph Hellwig 		return snprintf(buf, 20, "none\n");
530c7ebbbceSChristoph Hellwig 	return get_sas_device_type_names(
531c7ebbbceSChristoph Hellwig 			rphy->identify.device_type, buf);
532c7ebbbceSChristoph Hellwig }
533c7ebbbceSChristoph Hellwig 
534c7ebbbceSChristoph Hellwig static SAS_CLASS_DEVICE_ATTR(rphy, device_type, S_IRUGO,
535c7ebbbceSChristoph Hellwig 		show_sas_rphy_device_type, NULL);
536c7ebbbceSChristoph Hellwig 
537c7ebbbceSChristoph Hellwig sas_rphy_protocol_attr(identify.initiator_port_protocols,
538c7ebbbceSChristoph Hellwig 		initiator_port_protocols);
539c7ebbbceSChristoph Hellwig sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols);
540c7ebbbceSChristoph Hellwig sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
541c7ebbbceSChristoph Hellwig 		unsigned long long);
542c7ebbbceSChristoph Hellwig sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
543c7ebbbceSChristoph Hellwig 
544c7ebbbceSChristoph Hellwig static DECLARE_TRANSPORT_CLASS(sas_rphy_class,
545c7ebbbceSChristoph Hellwig 		"sas_rphy", NULL, NULL, NULL);
546c7ebbbceSChristoph Hellwig 
547c7ebbbceSChristoph Hellwig static int sas_rphy_match(struct attribute_container *cont, struct device *dev)
548c7ebbbceSChristoph Hellwig {
549c7ebbbceSChristoph Hellwig 	struct Scsi_Host *shost;
550c7ebbbceSChristoph Hellwig 	struct sas_internal *i;
551c7ebbbceSChristoph Hellwig 
552c7ebbbceSChristoph Hellwig 	if (!scsi_is_sas_rphy(dev))
553c7ebbbceSChristoph Hellwig 		return 0;
554c7ebbbceSChristoph Hellwig 	shost = dev_to_shost(dev->parent->parent);
555c7ebbbceSChristoph Hellwig 
556c7ebbbceSChristoph Hellwig 	if (!shost->transportt)
557c7ebbbceSChristoph Hellwig 		return 0;
558c7ebbbceSChristoph Hellwig 	if (shost->transportt->host_attrs.ac.class !=
559c7ebbbceSChristoph Hellwig 			&sas_host_class.class)
560c7ebbbceSChristoph Hellwig 		return 0;
561c7ebbbceSChristoph Hellwig 
562c7ebbbceSChristoph Hellwig 	i = to_sas_internal(shost->transportt);
563c7ebbbceSChristoph Hellwig 	return &i->rphy_attr_cont.ac == cont;
564c7ebbbceSChristoph Hellwig }
565c7ebbbceSChristoph Hellwig 
566c7ebbbceSChristoph Hellwig static void sas_rphy_release(struct device *dev)
567c7ebbbceSChristoph Hellwig {
568c7ebbbceSChristoph Hellwig 	struct sas_rphy *rphy = dev_to_rphy(dev);
569c7ebbbceSChristoph Hellwig 
570c7ebbbceSChristoph Hellwig 	put_device(dev->parent);
571c7ebbbceSChristoph Hellwig 	kfree(rphy);
572c7ebbbceSChristoph Hellwig }
573c7ebbbceSChristoph Hellwig 
574c7ebbbceSChristoph Hellwig /**
575c7ebbbceSChristoph Hellwig  * sas_rphy_alloc  --  allocates and initialize a SAS remote PHY structure
576c7ebbbceSChristoph Hellwig  * @parent:		SAS PHY this remote PHY is conneted to
577c7ebbbceSChristoph Hellwig  *
578c7ebbbceSChristoph Hellwig  * Allocates an SAS remote PHY structure, connected to @parent.
579c7ebbbceSChristoph Hellwig  *
580c7ebbbceSChristoph Hellwig  * Returns:
581c7ebbbceSChristoph Hellwig  *	SAS PHY allocated or %NULL if the allocation failed.
582c7ebbbceSChristoph Hellwig  */
583c7ebbbceSChristoph Hellwig struct sas_rphy *sas_rphy_alloc(struct sas_phy *parent)
584c7ebbbceSChristoph Hellwig {
585c7ebbbceSChristoph Hellwig 	struct Scsi_Host *shost = dev_to_shost(&parent->dev);
586c7ebbbceSChristoph Hellwig 	struct sas_rphy *rphy;
587c7ebbbceSChristoph Hellwig 
588c7ebbbceSChristoph Hellwig 	rphy = kmalloc(sizeof(*rphy), GFP_KERNEL);
589c7ebbbceSChristoph Hellwig 	if (!rphy) {
590c7ebbbceSChristoph Hellwig 		put_device(&parent->dev);
591c7ebbbceSChristoph Hellwig 		return NULL;
592c7ebbbceSChristoph Hellwig 	}
593c7ebbbceSChristoph Hellwig 	memset(rphy, 0, sizeof(*rphy));
594c7ebbbceSChristoph Hellwig 
595c7ebbbceSChristoph Hellwig 	device_initialize(&rphy->dev);
596c7ebbbceSChristoph Hellwig 	rphy->dev.parent = get_device(&parent->dev);
597c7ebbbceSChristoph Hellwig 	rphy->dev.release = sas_rphy_release;
598c7ebbbceSChristoph Hellwig 	sprintf(rphy->dev.bus_id, "rphy-%d:%d",
599c7ebbbceSChristoph Hellwig 		shost->host_no, parent->number);
600c7ebbbceSChristoph Hellwig 	transport_setup_device(&rphy->dev);
601c7ebbbceSChristoph Hellwig 
602c7ebbbceSChristoph Hellwig 	return rphy;
603c7ebbbceSChristoph Hellwig }
604c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_alloc);
605c7ebbbceSChristoph Hellwig 
606c7ebbbceSChristoph Hellwig /**
607c7ebbbceSChristoph Hellwig  * sas_rphy_add  --  add a SAS remote PHY to the device hierachy
608c7ebbbceSChristoph Hellwig  * @rphy:	The remote PHY to be added
609c7ebbbceSChristoph Hellwig  *
610c7ebbbceSChristoph Hellwig  * Publishes a SAS remote PHY to the rest of the system.
611c7ebbbceSChristoph Hellwig  */
612c7ebbbceSChristoph Hellwig int sas_rphy_add(struct sas_rphy *rphy)
613c7ebbbceSChristoph Hellwig {
614c7ebbbceSChristoph Hellwig 	struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
615c7ebbbceSChristoph Hellwig 	struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
616c7ebbbceSChristoph Hellwig 	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
617c7ebbbceSChristoph Hellwig 	struct sas_identify *identify = &rphy->identify;
618c7ebbbceSChristoph Hellwig 	int error;
619c7ebbbceSChristoph Hellwig 
620c7ebbbceSChristoph Hellwig 	if (parent->rphy)
621c7ebbbceSChristoph Hellwig 		return -ENXIO;
622c7ebbbceSChristoph Hellwig 	parent->rphy = rphy;
623c7ebbbceSChristoph Hellwig 
624c7ebbbceSChristoph Hellwig 	error = device_add(&rphy->dev);
625c7ebbbceSChristoph Hellwig 	if (error)
626c7ebbbceSChristoph Hellwig 		return error;
627c7ebbbceSChristoph Hellwig 	transport_add_device(&rphy->dev);
628c7ebbbceSChristoph Hellwig 	transport_configure_device(&rphy->dev);
629c7ebbbceSChristoph Hellwig 
630e02f3f59SChristoph Hellwig 	mutex_lock(&sas_host->lock);
631c7ebbbceSChristoph Hellwig 	list_add_tail(&rphy->list, &sas_host->rphy_list);
632c7ebbbceSChristoph Hellwig 	if (identify->device_type == SAS_END_DEVICE &&
633c7ebbbceSChristoph Hellwig 	    (identify->target_port_protocols &
634c7ebbbceSChristoph Hellwig 	     (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA)))
635c7ebbbceSChristoph Hellwig 		rphy->scsi_target_id = sas_host->next_target_id++;
636c7ebbbceSChristoph Hellwig 	else
637c7ebbbceSChristoph Hellwig 		rphy->scsi_target_id = -1;
638e02f3f59SChristoph Hellwig 	mutex_unlock(&sas_host->lock);
639c7ebbbceSChristoph Hellwig 
640c7ebbbceSChristoph Hellwig 	if (rphy->scsi_target_id != -1) {
641e6bc863cSMoore, Eric 		scsi_scan_target(&rphy->dev, parent->port_identifier,
642c7ebbbceSChristoph Hellwig 				rphy->scsi_target_id, ~0, 0);
643c7ebbbceSChristoph Hellwig 	}
644c7ebbbceSChristoph Hellwig 
645c7ebbbceSChristoph Hellwig 	return 0;
646c7ebbbceSChristoph Hellwig }
647c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_add);
648c7ebbbceSChristoph Hellwig 
649c7ebbbceSChristoph Hellwig /**
650c7ebbbceSChristoph Hellwig  * sas_rphy_free  --  free a SAS remote PHY
651c7ebbbceSChristoph Hellwig  * @rphy	SAS remote PHY to free
652c7ebbbceSChristoph Hellwig  *
653c7ebbbceSChristoph Hellwig  * Frees the specified SAS remote PHY.
654c7ebbbceSChristoph Hellwig  *
655c7ebbbceSChristoph Hellwig  * Note:
656c7ebbbceSChristoph Hellwig  *   This function must only be called on a remote
657c7ebbbceSChristoph Hellwig  *   PHY that has not sucessfully been added using
658c7ebbbceSChristoph Hellwig  *   sas_rphy_add().
659c7ebbbceSChristoph Hellwig  */
660c7ebbbceSChristoph Hellwig void sas_rphy_free(struct sas_rphy *rphy)
661c7ebbbceSChristoph Hellwig {
662c7ebbbceSChristoph Hellwig 	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
663c7ebbbceSChristoph Hellwig 	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
664c7ebbbceSChristoph Hellwig 
665e02f3f59SChristoph Hellwig 	mutex_lock(&sas_host->lock);
666c7ebbbceSChristoph Hellwig 	list_del(&rphy->list);
667e02f3f59SChristoph Hellwig 	mutex_unlock(&sas_host->lock);
668c7ebbbceSChristoph Hellwig 
669c7ebbbceSChristoph Hellwig 	transport_destroy_device(&rphy->dev);
670c7ebbbceSChristoph Hellwig 	put_device(rphy->dev.parent);
671c7ebbbceSChristoph Hellwig 	put_device(rphy->dev.parent);
672c7ebbbceSChristoph Hellwig 	put_device(rphy->dev.parent);
673c7ebbbceSChristoph Hellwig 	kfree(rphy);
674c7ebbbceSChristoph Hellwig }
675c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_free);
676c7ebbbceSChristoph Hellwig 
677c7ebbbceSChristoph Hellwig /**
678c7ebbbceSChristoph Hellwig  * sas_rphy_delete  --  remove SAS remote PHY
679c7ebbbceSChristoph Hellwig  * @rphy:	SAS remote PHY to remove
680c7ebbbceSChristoph Hellwig  *
681c7ebbbceSChristoph Hellwig  * Removes the specified SAS remote PHY.
682c7ebbbceSChristoph Hellwig  */
683c7ebbbceSChristoph Hellwig void
684c7ebbbceSChristoph Hellwig sas_rphy_delete(struct sas_rphy *rphy)
685c7ebbbceSChristoph Hellwig {
686c7ebbbceSChristoph Hellwig 	struct device *dev = &rphy->dev;
687c7ebbbceSChristoph Hellwig 	struct sas_phy *parent = dev_to_phy(dev->parent);
688c7ebbbceSChristoph Hellwig 	struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
689c7ebbbceSChristoph Hellwig 	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
690c7ebbbceSChristoph Hellwig 
691d4054239SChristoph Hellwig 	switch (rphy->identify.device_type) {
692d4054239SChristoph Hellwig 	case SAS_END_DEVICE:
693fe8b2304SChristoph Hellwig 		scsi_remove_target(dev);
694d4054239SChristoph Hellwig 		break;
695d4054239SChristoph Hellwig 	case SAS_EDGE_EXPANDER_DEVICE:
696d4054239SChristoph Hellwig 	case SAS_FANOUT_EXPANDER_DEVICE:
697d4054239SChristoph Hellwig 		device_for_each_child(dev, NULL, do_sas_phy_delete);
698d4054239SChristoph Hellwig 		break;
699d4054239SChristoph Hellwig 	default:
700d4054239SChristoph Hellwig 		break;
701d4054239SChristoph Hellwig 	}
702c7ebbbceSChristoph Hellwig 
703fe8b2304SChristoph Hellwig 	transport_remove_device(dev);
704fe8b2304SChristoph Hellwig 	device_del(dev);
705fe8b2304SChristoph Hellwig 	transport_destroy_device(dev);
706c7ebbbceSChristoph Hellwig 
707e02f3f59SChristoph Hellwig 	mutex_lock(&sas_host->lock);
708c7ebbbceSChristoph Hellwig 	list_del(&rphy->list);
709e02f3f59SChristoph Hellwig 	mutex_unlock(&sas_host->lock);
710c7ebbbceSChristoph Hellwig 
71133b114e9SChristoph Hellwig 	parent->rphy = NULL;
71233b114e9SChristoph Hellwig 
713c7ebbbceSChristoph Hellwig 	put_device(&parent->dev);
714c7ebbbceSChristoph Hellwig }
715c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_rphy_delete);
716c7ebbbceSChristoph Hellwig 
717c7ebbbceSChristoph Hellwig /**
718c7ebbbceSChristoph Hellwig  * scsi_is_sas_rphy  --  check if a struct device represents a SAS remote PHY
719c7ebbbceSChristoph Hellwig  * @dev:	device to check
720c7ebbbceSChristoph Hellwig  *
721c7ebbbceSChristoph Hellwig  * Returns:
722c7ebbbceSChristoph Hellwig  *	%1 if the device represents a SAS remote PHY, %0 else
723c7ebbbceSChristoph Hellwig  */
724c7ebbbceSChristoph Hellwig int scsi_is_sas_rphy(const struct device *dev)
725c7ebbbceSChristoph Hellwig {
726c7ebbbceSChristoph Hellwig 	return dev->release == sas_rphy_release;
727c7ebbbceSChristoph Hellwig }
728c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(scsi_is_sas_rphy);
729c7ebbbceSChristoph Hellwig 
730c7ebbbceSChristoph Hellwig 
731c7ebbbceSChristoph Hellwig /*
732c7ebbbceSChristoph Hellwig  * SCSI scan helper
733c7ebbbceSChristoph Hellwig  */
734c7ebbbceSChristoph Hellwig 
735e02f3f59SChristoph Hellwig static int sas_user_scan(struct Scsi_Host *shost, uint channel,
736e02f3f59SChristoph Hellwig 		uint id, uint lun)
737c7ebbbceSChristoph Hellwig {
738c7ebbbceSChristoph Hellwig 	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
739c7ebbbceSChristoph Hellwig 	struct sas_rphy *rphy;
740c7ebbbceSChristoph Hellwig 
741e02f3f59SChristoph Hellwig 	mutex_lock(&sas_host->lock);
742c7ebbbceSChristoph Hellwig 	list_for_each_entry(rphy, &sas_host->rphy_list, list) {
743c7ebbbceSChristoph Hellwig 		struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
744c7ebbbceSChristoph Hellwig 
745e02f3f59SChristoph Hellwig 		if (rphy->scsi_target_id == -1)
746e02f3f59SChristoph Hellwig 			continue;
747e02f3f59SChristoph Hellwig 
748e6bc863cSMoore, Eric 		if ((channel == SCAN_WILD_CARD || channel == parent->port_identifier) &&
749e02f3f59SChristoph Hellwig 		    (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) {
750e6bc863cSMoore, Eric 			scsi_scan_target(&rphy->dev, parent->port_identifier,
751e02f3f59SChristoph Hellwig 					 rphy->scsi_target_id, lun, 1);
752e02f3f59SChristoph Hellwig 		}
753e02f3f59SChristoph Hellwig 	}
754e02f3f59SChristoph Hellwig 	mutex_unlock(&sas_host->lock);
755e02f3f59SChristoph Hellwig 
756e02f3f59SChristoph Hellwig 	return 0;
757c7ebbbceSChristoph Hellwig }
758c7ebbbceSChristoph Hellwig 
759c7ebbbceSChristoph Hellwig 
760c7ebbbceSChristoph Hellwig /*
761c7ebbbceSChristoph Hellwig  * Setup / Teardown code
762c7ebbbceSChristoph Hellwig  */
763c7ebbbceSChristoph Hellwig 
764c7ebbbceSChristoph Hellwig #define SETUP_RPORT_ATTRIBUTE(field)					\
765c7ebbbceSChristoph Hellwig 	i->private_rphy_attrs[count] = class_device_attr_##field;	\
766c7ebbbceSChristoph Hellwig 	i->private_rphy_attrs[count].attr.mode = S_IRUGO;		\
767c7ebbbceSChristoph Hellwig 	i->private_rphy_attrs[count].store = NULL;			\
768c7ebbbceSChristoph Hellwig 	i->rphy_attrs[count] = &i->private_rphy_attrs[count];	\
769c7ebbbceSChristoph Hellwig 	count++
770c7ebbbceSChristoph Hellwig 
771c7ebbbceSChristoph Hellwig #define SETUP_PORT_ATTRIBUTE(field)					\
772c7ebbbceSChristoph Hellwig 	i->private_phy_attrs[count] = class_device_attr_##field;	\
773c7ebbbceSChristoph Hellwig         i->private_phy_attrs[count].attr.mode = S_IRUGO;		\
774c7ebbbceSChristoph Hellwig         i->private_phy_attrs[count].store = NULL;			\
775c7ebbbceSChristoph Hellwig         i->phy_attrs[count] = &i->private_phy_attrs[count];		\
776c7ebbbceSChristoph Hellwig 	count++
777c7ebbbceSChristoph Hellwig 
77807ba3a95SChristoph Hellwig #define SETUP_PORT_ATTRIBUTE_WRONLY(field)				\
77907ba3a95SChristoph Hellwig 	i->private_phy_attrs[count] = class_device_attr_##field;	\
78007ba3a95SChristoph Hellwig 	i->private_phy_attrs[count].attr.mode = S_IWUGO;		\
78107ba3a95SChristoph Hellwig 	i->private_phy_attrs[count].show = NULL;			\
78207ba3a95SChristoph Hellwig 	i->phy_attrs[count] = &i->private_phy_attrs[count];		\
78307ba3a95SChristoph Hellwig 	count++
78407ba3a95SChristoph Hellwig 
785c7ebbbceSChristoph Hellwig 
786c7ebbbceSChristoph Hellwig /**
787c7ebbbceSChristoph Hellwig  * sas_attach_transport  --  instantiate SAS transport template
788c7ebbbceSChristoph Hellwig  * @ft:		SAS transport class function template
789c7ebbbceSChristoph Hellwig  */
790c7ebbbceSChristoph Hellwig struct scsi_transport_template *
791c7ebbbceSChristoph Hellwig sas_attach_transport(struct sas_function_template *ft)
792c7ebbbceSChristoph Hellwig {
793c7ebbbceSChristoph Hellwig 	struct sas_internal *i;
794c7ebbbceSChristoph Hellwig 	int count;
795c7ebbbceSChristoph Hellwig 
796c7ebbbceSChristoph Hellwig 	i = kmalloc(sizeof(struct sas_internal), GFP_KERNEL);
797c7ebbbceSChristoph Hellwig 	if (!i)
798c7ebbbceSChristoph Hellwig 		return NULL;
799c7ebbbceSChristoph Hellwig 	memset(i, 0, sizeof(struct sas_internal));
800c7ebbbceSChristoph Hellwig 
801e02f3f59SChristoph Hellwig 	i->t.user_scan = sas_user_scan;
802c7ebbbceSChristoph Hellwig 
803c7ebbbceSChristoph Hellwig 	i->t.host_attrs.ac.attrs = &i->host_attrs[0];
804c7ebbbceSChristoph Hellwig 	i->t.host_attrs.ac.class = &sas_host_class.class;
805c7ebbbceSChristoph Hellwig 	i->t.host_attrs.ac.match = sas_host_match;
806c7ebbbceSChristoph Hellwig 	transport_container_register(&i->t.host_attrs);
807c7ebbbceSChristoph Hellwig 	i->t.host_size = sizeof(struct sas_host_attrs);
808c7ebbbceSChristoph Hellwig 
809c7ebbbceSChristoph Hellwig 	i->phy_attr_cont.ac.class = &sas_phy_class.class;
810c7ebbbceSChristoph Hellwig 	i->phy_attr_cont.ac.attrs = &i->phy_attrs[0];
811c7ebbbceSChristoph Hellwig 	i->phy_attr_cont.ac.match = sas_phy_match;
812c7ebbbceSChristoph Hellwig 	transport_container_register(&i->phy_attr_cont);
813c7ebbbceSChristoph Hellwig 
814c7ebbbceSChristoph Hellwig 	i->rphy_attr_cont.ac.class = &sas_rphy_class.class;
815c7ebbbceSChristoph Hellwig 	i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0];
816c7ebbbceSChristoph Hellwig 	i->rphy_attr_cont.ac.match = sas_rphy_match;
817c7ebbbceSChristoph Hellwig 	transport_container_register(&i->rphy_attr_cont);
818c7ebbbceSChristoph Hellwig 
819c7ebbbceSChristoph Hellwig 	i->f = ft;
820c7ebbbceSChristoph Hellwig 
821c7ebbbceSChristoph Hellwig 	count = 0;
822c7ebbbceSChristoph Hellwig 	i->host_attrs[count] = NULL;
823c7ebbbceSChristoph Hellwig 
824c7ebbbceSChristoph Hellwig 	count = 0;
825c7ebbbceSChristoph Hellwig 	SETUP_PORT_ATTRIBUTE(initiator_port_protocols);
826c7ebbbceSChristoph Hellwig 	SETUP_PORT_ATTRIBUTE(target_port_protocols);
827c7ebbbceSChristoph Hellwig 	SETUP_PORT_ATTRIBUTE(device_type);
828c7ebbbceSChristoph Hellwig 	SETUP_PORT_ATTRIBUTE(sas_address);
829c7ebbbceSChristoph Hellwig 	SETUP_PORT_ATTRIBUTE(phy_identifier);
830c7ebbbceSChristoph Hellwig 	SETUP_PORT_ATTRIBUTE(port_identifier);
831c7ebbbceSChristoph Hellwig 	SETUP_PORT_ATTRIBUTE(negotiated_linkrate);
832c7ebbbceSChristoph Hellwig 	SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw);
833c7ebbbceSChristoph Hellwig 	SETUP_PORT_ATTRIBUTE(minimum_linkrate);
834c7ebbbceSChristoph Hellwig 	SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw);
835c7ebbbceSChristoph Hellwig 	SETUP_PORT_ATTRIBUTE(maximum_linkrate);
836c3ee74c4SChristoph Hellwig 
837c3ee74c4SChristoph Hellwig 	SETUP_PORT_ATTRIBUTE(invalid_dword_count);
838c3ee74c4SChristoph Hellwig 	SETUP_PORT_ATTRIBUTE(running_disparity_error_count);
839c3ee74c4SChristoph Hellwig 	SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count);
840c3ee74c4SChristoph Hellwig 	SETUP_PORT_ATTRIBUTE(phy_reset_problem_count);
84107ba3a95SChristoph Hellwig 	SETUP_PORT_ATTRIBUTE_WRONLY(link_reset);
84207ba3a95SChristoph Hellwig 	SETUP_PORT_ATTRIBUTE_WRONLY(hard_reset);
843c7ebbbceSChristoph Hellwig 	i->phy_attrs[count] = NULL;
844c7ebbbceSChristoph Hellwig 
845c7ebbbceSChristoph Hellwig 	count = 0;
846c7ebbbceSChristoph Hellwig 	SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols);
847c7ebbbceSChristoph Hellwig 	SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols);
848c7ebbbceSChristoph Hellwig 	SETUP_RPORT_ATTRIBUTE(rphy_device_type);
849c7ebbbceSChristoph Hellwig 	SETUP_RPORT_ATTRIBUTE(rphy_sas_address);
850c7ebbbceSChristoph Hellwig 	SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier);
851c7ebbbceSChristoph Hellwig 	i->rphy_attrs[count] = NULL;
852c7ebbbceSChristoph Hellwig 
853c7ebbbceSChristoph Hellwig 	return &i->t;
854c7ebbbceSChristoph Hellwig }
855c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_attach_transport);
856c7ebbbceSChristoph Hellwig 
857c7ebbbceSChristoph Hellwig /**
858c7ebbbceSChristoph Hellwig  * sas_release_transport  --  release SAS transport template instance
859c7ebbbceSChristoph Hellwig  * @t:		transport template instance
860c7ebbbceSChristoph Hellwig  */
861c7ebbbceSChristoph Hellwig void sas_release_transport(struct scsi_transport_template *t)
862c7ebbbceSChristoph Hellwig {
863c7ebbbceSChristoph Hellwig 	struct sas_internal *i = to_sas_internal(t);
864c7ebbbceSChristoph Hellwig 
865c7ebbbceSChristoph Hellwig 	transport_container_unregister(&i->t.host_attrs);
866c7ebbbceSChristoph Hellwig 	transport_container_unregister(&i->phy_attr_cont);
867c7ebbbceSChristoph Hellwig 	transport_container_unregister(&i->rphy_attr_cont);
868c7ebbbceSChristoph Hellwig 
869c7ebbbceSChristoph Hellwig 	kfree(i);
870c7ebbbceSChristoph Hellwig }
871c7ebbbceSChristoph Hellwig EXPORT_SYMBOL(sas_release_transport);
872c7ebbbceSChristoph Hellwig 
873c7ebbbceSChristoph Hellwig static __init int sas_transport_init(void)
874c7ebbbceSChristoph Hellwig {
875c7ebbbceSChristoph Hellwig 	int error;
876c7ebbbceSChristoph Hellwig 
877c7ebbbceSChristoph Hellwig 	error = transport_class_register(&sas_host_class);
878c7ebbbceSChristoph Hellwig 	if (error)
879c7ebbbceSChristoph Hellwig 		goto out;
880c7ebbbceSChristoph Hellwig 	error = transport_class_register(&sas_phy_class);
881c7ebbbceSChristoph Hellwig 	if (error)
882c7ebbbceSChristoph Hellwig 		goto out_unregister_transport;
883c7ebbbceSChristoph Hellwig 	error = transport_class_register(&sas_rphy_class);
884c7ebbbceSChristoph Hellwig 	if (error)
885c7ebbbceSChristoph Hellwig 		goto out_unregister_phy;
886c7ebbbceSChristoph Hellwig 
887c7ebbbceSChristoph Hellwig 	return 0;
888c7ebbbceSChristoph Hellwig 
889c7ebbbceSChristoph Hellwig  out_unregister_phy:
890c7ebbbceSChristoph Hellwig 	transport_class_unregister(&sas_phy_class);
891c7ebbbceSChristoph Hellwig  out_unregister_transport:
892c7ebbbceSChristoph Hellwig 	transport_class_unregister(&sas_host_class);
893c7ebbbceSChristoph Hellwig  out:
894c7ebbbceSChristoph Hellwig 	return error;
895c7ebbbceSChristoph Hellwig 
896c7ebbbceSChristoph Hellwig }
897c7ebbbceSChristoph Hellwig 
898c7ebbbceSChristoph Hellwig static void __exit sas_transport_exit(void)
899c7ebbbceSChristoph Hellwig {
900c7ebbbceSChristoph Hellwig 	transport_class_unregister(&sas_host_class);
901c7ebbbceSChristoph Hellwig 	transport_class_unregister(&sas_phy_class);
902c7ebbbceSChristoph Hellwig 	transport_class_unregister(&sas_rphy_class);
903c7ebbbceSChristoph Hellwig }
904c7ebbbceSChristoph Hellwig 
905c7ebbbceSChristoph Hellwig MODULE_AUTHOR("Christoph Hellwig");
906c7ebbbceSChristoph Hellwig MODULE_DESCRIPTION("SAS Transphy Attributes");
907c7ebbbceSChristoph Hellwig MODULE_LICENSE("GPL");
908c7ebbbceSChristoph Hellwig 
909c7ebbbceSChristoph Hellwig module_init(sas_transport_init);
910c7ebbbceSChristoph Hellwig module_exit(sas_transport_exit);
911