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