scsi_transport_sas.c revision 9f434d4f84a235f6b61aec6e691d6b07bc46fc24
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#include "scsi_sas_internal.h"
39struct sas_host_attrs {
40	struct list_head rphy_list;
41	struct mutex lock;
42	u32 next_target_id;
43	u32 next_expander_id;
44};
45#define to_sas_host_attrs(host)	((struct sas_host_attrs *)(host)->shost_data)
46
47
48/*
49 * Hack to allow attributes of the same name in different objects.
50 */
51#define SAS_CLASS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \
52	struct class_device_attribute class_device_attr_##_prefix##_##_name = \
53	__ATTR(_name,_mode,_show,_store)
54
55
56/*
57 * Pretty printing helpers
58 */
59
60#define sas_bitfield_name_match(title, table)			\
61static ssize_t							\
62get_sas_##title##_names(u32 table_key, char *buf)		\
63{								\
64	char *prefix = "";					\
65	ssize_t len = 0;					\
66	int i;							\
67								\
68	for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) {	\
69		if (table[i].value & table_key) {		\
70			len += sprintf(buf + len, "%s%s",	\
71				prefix, table[i].name);		\
72			prefix = ", ";				\
73		}						\
74	}							\
75	len += sprintf(buf + len, "\n");			\
76	return len;						\
77}
78
79#define sas_bitfield_name_search(title, table)			\
80static ssize_t							\
81get_sas_##title##_names(u32 table_key, char *buf)		\
82{								\
83	ssize_t len = 0;					\
84	int i;							\
85								\
86	for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) {	\
87		if (table[i].value == table_key) {		\
88			len += sprintf(buf + len, "%s",		\
89				table[i].name);			\
90			break;					\
91		}						\
92	}							\
93	len += sprintf(buf + len, "\n");			\
94	return len;						\
95}
96
97static struct {
98	u32		value;
99	char		*name;
100} sas_device_type_names[] = {
101	{ SAS_PHY_UNUSED,		"unused" },
102	{ SAS_END_DEVICE,		"end device" },
103	{ SAS_EDGE_EXPANDER_DEVICE,	"edge expander" },
104	{ SAS_FANOUT_EXPANDER_DEVICE,	"fanout expander" },
105};
106sas_bitfield_name_search(device_type, sas_device_type_names)
107
108
109static struct {
110	u32		value;
111	char		*name;
112} sas_protocol_names[] = {
113	{ SAS_PROTOCOL_SATA,		"sata" },
114	{ SAS_PROTOCOL_SMP,		"smp" },
115	{ SAS_PROTOCOL_STP,		"stp" },
116	{ SAS_PROTOCOL_SSP,		"ssp" },
117};
118sas_bitfield_name_match(protocol, sas_protocol_names)
119
120static struct {
121	u32		value;
122	char		*name;
123} sas_linkspeed_names[] = {
124	{ SAS_LINK_RATE_UNKNOWN,	"Unknown" },
125	{ SAS_PHY_DISABLED,		"Phy disabled" },
126	{ SAS_LINK_RATE_FAILED,		"Link Rate failed" },
127	{ SAS_SATA_SPINUP_HOLD,		"Spin-up hold" },
128	{ SAS_LINK_RATE_1_5_GBPS,	"1.5 Gbit" },
129	{ SAS_LINK_RATE_3_0_GBPS,	"3.0 Gbit" },
130	{ SAS_LINK_RATE_6_0_GBPS,	"6.0 Gbit" },
131};
132sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
133
134
135/*
136 * SAS host attributes
137 */
138
139static int sas_host_setup(struct transport_container *tc, struct device *dev,
140			  struct class_device *cdev)
141{
142	struct Scsi_Host *shost = dev_to_shost(dev);
143	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
144
145	INIT_LIST_HEAD(&sas_host->rphy_list);
146	mutex_init(&sas_host->lock);
147	sas_host->next_target_id = 0;
148	sas_host->next_expander_id = 0;
149	return 0;
150}
151
152static DECLARE_TRANSPORT_CLASS(sas_host_class,
153		"sas_host", sas_host_setup, NULL, NULL);
154
155static int sas_host_match(struct attribute_container *cont,
156			    struct device *dev)
157{
158	struct Scsi_Host *shost;
159	struct sas_internal *i;
160
161	if (!scsi_is_host_device(dev))
162		return 0;
163	shost = dev_to_shost(dev);
164
165	if (!shost->transportt)
166		return 0;
167	if (shost->transportt->host_attrs.ac.class !=
168			&sas_host_class.class)
169		return 0;
170
171	i = to_sas_internal(shost->transportt);
172	return &i->t.host_attrs.ac == cont;
173}
174
175static int do_sas_phy_delete(struct device *dev, void *data)
176{
177	if (scsi_is_sas_phy(dev))
178		sas_phy_delete(dev_to_phy(dev));
179	return 0;
180}
181
182/**
183 * sas_remove_host  --  tear down a Scsi_Host's SAS data structures
184 * @shost:	Scsi Host that is torn down
185 *
186 * Removes all SAS PHYs and remote PHYs for a given Scsi_Host.
187 * Must be called just before scsi_remove_host for SAS HBAs.
188 */
189void sas_remove_host(struct Scsi_Host *shost)
190{
191	device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete);
192}
193EXPORT_SYMBOL(sas_remove_host);
194
195
196/*
197 * SAS Port attributes
198 */
199
200#define sas_phy_show_simple(field, name, format_string, cast)		\
201static ssize_t								\
202show_sas_phy_##name(struct class_device *cdev, char *buf)		\
203{									\
204	struct sas_phy *phy = transport_class_to_phy(cdev);		\
205									\
206	return snprintf(buf, 20, format_string, cast phy->field);	\
207}
208
209#define sas_phy_simple_attr(field, name, format_string, type)		\
210	sas_phy_show_simple(field, name, format_string, (type))	\
211static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
212
213#define sas_phy_show_protocol(field, name)				\
214static ssize_t								\
215show_sas_phy_##name(struct class_device *cdev, char *buf)		\
216{									\
217	struct sas_phy *phy = transport_class_to_phy(cdev);		\
218									\
219	if (!phy->field)						\
220		return snprintf(buf, 20, "none\n");			\
221	return get_sas_protocol_names(phy->field, buf);		\
222}
223
224#define sas_phy_protocol_attr(field, name)				\
225	sas_phy_show_protocol(field, name)				\
226static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
227
228#define sas_phy_show_linkspeed(field)					\
229static ssize_t								\
230show_sas_phy_##field(struct class_device *cdev, char *buf)		\
231{									\
232	struct sas_phy *phy = transport_class_to_phy(cdev);		\
233									\
234	return get_sas_linkspeed_names(phy->field, buf);		\
235}
236
237#define sas_phy_linkspeed_attr(field)					\
238	sas_phy_show_linkspeed(field)					\
239static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
240
241#define sas_phy_show_linkerror(field)					\
242static ssize_t								\
243show_sas_phy_##field(struct class_device *cdev, char *buf)		\
244{									\
245	struct sas_phy *phy = transport_class_to_phy(cdev);		\
246	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);	\
247	struct sas_internal *i = to_sas_internal(shost->transportt);	\
248	int error;							\
249									\
250	if (!phy->local_attached)					\
251		return -EINVAL;						\
252									\
253	error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0;	\
254	if (error)							\
255		return error;						\
256	return snprintf(buf, 20, "%u\n", phy->field);			\
257}
258
259#define sas_phy_linkerror_attr(field)					\
260	sas_phy_show_linkerror(field)					\
261static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
262
263
264static ssize_t
265show_sas_device_type(struct class_device *cdev, char *buf)
266{
267	struct sas_phy *phy = transport_class_to_phy(cdev);
268
269	if (!phy->identify.device_type)
270		return snprintf(buf, 20, "none\n");
271	return get_sas_device_type_names(phy->identify.device_type, buf);
272}
273static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL);
274
275static ssize_t do_sas_phy_reset(struct class_device *cdev,
276		size_t count, int hard_reset)
277{
278	struct sas_phy *phy = transport_class_to_phy(cdev);
279	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
280	struct sas_internal *i = to_sas_internal(shost->transportt);
281	int error;
282
283	if (!phy->local_attached)
284		return -EINVAL;
285
286	error = i->f->phy_reset(phy, hard_reset);
287	if (error)
288		return error;
289	return count;
290};
291
292static ssize_t store_sas_link_reset(struct class_device *cdev,
293		const char *buf, size_t count)
294{
295	return do_sas_phy_reset(cdev, count, 0);
296}
297static CLASS_DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset);
298
299static ssize_t store_sas_hard_reset(struct class_device *cdev,
300		const char *buf, size_t count)
301{
302	return do_sas_phy_reset(cdev, count, 1);
303}
304static CLASS_DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset);
305
306sas_phy_protocol_attr(identify.initiator_port_protocols,
307		initiator_port_protocols);
308sas_phy_protocol_attr(identify.target_port_protocols,
309		target_port_protocols);
310sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
311		unsigned long long);
312sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
313sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8);
314sas_phy_linkspeed_attr(negotiated_linkrate);
315sas_phy_linkspeed_attr(minimum_linkrate_hw);
316sas_phy_linkspeed_attr(minimum_linkrate);
317sas_phy_linkspeed_attr(maximum_linkrate_hw);
318sas_phy_linkspeed_attr(maximum_linkrate);
319sas_phy_linkerror_attr(invalid_dword_count);
320sas_phy_linkerror_attr(running_disparity_error_count);
321sas_phy_linkerror_attr(loss_of_dword_sync_count);
322sas_phy_linkerror_attr(phy_reset_problem_count);
323
324
325static DECLARE_TRANSPORT_CLASS(sas_phy_class,
326		"sas_phy", NULL, NULL, NULL);
327
328static int sas_phy_match(struct attribute_container *cont, struct device *dev)
329{
330	struct Scsi_Host *shost;
331	struct sas_internal *i;
332
333	if (!scsi_is_sas_phy(dev))
334		return 0;
335	shost = dev_to_shost(dev->parent);
336
337	if (!shost->transportt)
338		return 0;
339	if (shost->transportt->host_attrs.ac.class !=
340			&sas_host_class.class)
341		return 0;
342
343	i = to_sas_internal(shost->transportt);
344	return &i->phy_attr_cont.ac == cont;
345}
346
347static void sas_phy_release(struct device *dev)
348{
349	struct sas_phy *phy = dev_to_phy(dev);
350
351	put_device(dev->parent);
352	kfree(phy);
353}
354
355/**
356 * sas_phy_alloc  --  allocates and initialize a SAS PHY structure
357 * @parent:	Parent device
358 * @number:	Phy index
359 *
360 * Allocates an SAS PHY structure.  It will be added in the device tree
361 * below the device specified by @parent, which has to be either a Scsi_Host
362 * or sas_rphy.
363 *
364 * Returns:
365 *	SAS PHY allocated or %NULL if the allocation failed.
366 */
367struct sas_phy *sas_phy_alloc(struct device *parent, int number)
368{
369	struct Scsi_Host *shost = dev_to_shost(parent);
370	struct sas_phy *phy;
371
372	phy = kzalloc(sizeof(*phy), GFP_KERNEL);
373	if (!phy)
374		return NULL;
375
376	phy->number = number;
377
378	device_initialize(&phy->dev);
379	phy->dev.parent = get_device(parent);
380	phy->dev.release = sas_phy_release;
381	if (scsi_is_sas_expander_device(parent)) {
382		struct sas_rphy *rphy = dev_to_rphy(parent);
383		sprintf(phy->dev.bus_id, "phy-%d-%d:%d", shost->host_no,
384			rphy->scsi_target_id, number);
385	} else
386		sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number);
387
388	transport_setup_device(&phy->dev);
389
390	return phy;
391}
392EXPORT_SYMBOL(sas_phy_alloc);
393
394/**
395 * sas_phy_add  --  add a SAS PHY to the device hierachy
396 * @phy:	The PHY to be added
397 *
398 * Publishes a SAS PHY to the rest of the system.
399 */
400int sas_phy_add(struct sas_phy *phy)
401{
402	int error;
403
404	error = device_add(&phy->dev);
405	if (!error) {
406		transport_add_device(&phy->dev);
407		transport_configure_device(&phy->dev);
408	}
409
410	return error;
411}
412EXPORT_SYMBOL(sas_phy_add);
413
414/**
415 * sas_phy_free  --  free a SAS PHY
416 * @phy:	SAS PHY to free
417 *
418 * Frees the specified SAS PHY.
419 *
420 * Note:
421 *   This function must only be called on a PHY that has not
422 *   sucessfully been added using sas_phy_add().
423 */
424void sas_phy_free(struct sas_phy *phy)
425{
426	transport_destroy_device(&phy->dev);
427	put_device(&phy->dev);
428}
429EXPORT_SYMBOL(sas_phy_free);
430
431/**
432 * sas_phy_delete  --  remove SAS PHY
433 * @phy:	SAS PHY to remove
434 *
435 * Removes the specified SAS PHY.  If the SAS PHY has an
436 * associated remote PHY it is removed before.
437 */
438void
439sas_phy_delete(struct sas_phy *phy)
440{
441	struct device *dev = &phy->dev;
442
443	if (phy->rphy)
444		sas_rphy_delete(phy->rphy);
445
446	transport_remove_device(dev);
447	device_del(dev);
448	transport_destroy_device(dev);
449	put_device(dev);
450}
451EXPORT_SYMBOL(sas_phy_delete);
452
453/**
454 * scsi_is_sas_phy  --  check if a struct device represents a SAS PHY
455 * @dev:	device to check
456 *
457 * Returns:
458 *	%1 if the device represents a SAS PHY, %0 else
459 */
460int scsi_is_sas_phy(const struct device *dev)
461{
462	return dev->release == sas_phy_release;
463}
464EXPORT_SYMBOL(scsi_is_sas_phy);
465
466/*
467 * SAS remote PHY attributes.
468 */
469
470#define sas_rphy_show_simple(field, name, format_string, cast)		\
471static ssize_t								\
472show_sas_rphy_##name(struct class_device *cdev, char *buf)		\
473{									\
474	struct sas_rphy *rphy = transport_class_to_rphy(cdev);	\
475									\
476	return snprintf(buf, 20, format_string, cast rphy->field);	\
477}
478
479#define sas_rphy_simple_attr(field, name, format_string, type)		\
480	sas_rphy_show_simple(field, name, format_string, (type))	\
481static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, 			\
482		show_sas_rphy_##name, NULL)
483
484#define sas_rphy_show_protocol(field, name)				\
485static ssize_t								\
486show_sas_rphy_##name(struct class_device *cdev, char *buf)		\
487{									\
488	struct sas_rphy *rphy = transport_class_to_rphy(cdev);	\
489									\
490	if (!rphy->field)					\
491		return snprintf(buf, 20, "none\n");			\
492	return get_sas_protocol_names(rphy->field, buf);	\
493}
494
495#define sas_rphy_protocol_attr(field, name)				\
496	sas_rphy_show_protocol(field, name)				\
497static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO,			\
498		show_sas_rphy_##name, NULL)
499
500static ssize_t
501show_sas_rphy_device_type(struct class_device *cdev, char *buf)
502{
503	struct sas_rphy *rphy = transport_class_to_rphy(cdev);
504
505	if (!rphy->identify.device_type)
506		return snprintf(buf, 20, "none\n");
507	return get_sas_device_type_names(
508			rphy->identify.device_type, buf);
509}
510
511static SAS_CLASS_DEVICE_ATTR(rphy, device_type, S_IRUGO,
512		show_sas_rphy_device_type, NULL);
513
514static ssize_t
515show_sas_rphy_enclosure_identifier(struct class_device *cdev, char *buf)
516{
517	struct sas_rphy *rphy = transport_class_to_rphy(cdev);
518	struct sas_phy *phy = dev_to_phy(rphy->dev.parent);
519	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
520	struct sas_internal *i = to_sas_internal(shost->transportt);
521	u64 identifier;
522	int error;
523
524	/*
525	 * Only devices behind an expander are supported, because the
526	 * enclosure identifier is a SMP feature.
527	 */
528	if (phy->local_attached)
529		return -EINVAL;
530
531	error = i->f->get_enclosure_identifier(rphy, &identifier);
532	if (error)
533		return error;
534	return sprintf(buf, "0x%llx\n", (unsigned long long)identifier);
535}
536
537static SAS_CLASS_DEVICE_ATTR(rphy, enclosure_identifier, S_IRUGO,
538		show_sas_rphy_enclosure_identifier, NULL);
539
540static ssize_t
541show_sas_rphy_bay_identifier(struct class_device *cdev, char *buf)
542{
543	struct sas_rphy *rphy = transport_class_to_rphy(cdev);
544	struct sas_phy *phy = dev_to_phy(rphy->dev.parent);
545	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
546	struct sas_internal *i = to_sas_internal(shost->transportt);
547	int val;
548
549	if (phy->local_attached)
550		return -EINVAL;
551
552	val = i->f->get_bay_identifier(rphy);
553	if (val < 0)
554		return val;
555	return sprintf(buf, "%d\n", val);
556}
557
558static SAS_CLASS_DEVICE_ATTR(rphy, bay_identifier, S_IRUGO,
559		show_sas_rphy_bay_identifier, NULL);
560
561sas_rphy_protocol_attr(identify.initiator_port_protocols,
562		initiator_port_protocols);
563sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols);
564sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
565		unsigned long long);
566sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
567
568/* only need 8 bytes of data plus header (4 or 8) */
569#define BUF_SIZE 64
570
571int sas_read_port_mode_page(struct scsi_device *sdev)
572{
573	char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata;
574	struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target);
575	struct sas_end_device *rdev;
576	struct scsi_mode_data mode_data;
577	int res, error;
578
579	BUG_ON(rphy->identify.device_type != SAS_END_DEVICE);
580
581	rdev = rphy_to_end_device(rphy);
582
583	if (!buffer)
584		return -ENOMEM;
585
586	res = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3,
587			      &mode_data, NULL);
588
589	error = -EINVAL;
590	if (!scsi_status_is_good(res))
591		goto out;
592
593	msdata = buffer +  mode_data.header_length +
594		mode_data.block_descriptor_length;
595
596	if (msdata - buffer > BUF_SIZE - 8)
597		goto out;
598
599	error = 0;
600
601	rdev->ready_led_meaning = msdata[2] & 0x10 ? 1 : 0;
602	rdev->I_T_nexus_loss_timeout = (msdata[4] << 8) + msdata[5];
603	rdev->initiator_response_timeout = (msdata[6] << 8) + msdata[7];
604
605 out:
606	kfree(buffer);
607	return error;
608}
609EXPORT_SYMBOL(sas_read_port_mode_page);
610
611static DECLARE_TRANSPORT_CLASS(sas_end_dev_class,
612			       "sas_end_device", NULL, NULL, NULL);
613
614#define sas_end_dev_show_simple(field, name, format_string, cast)	\
615static ssize_t								\
616show_sas_end_dev_##name(struct class_device *cdev, char *buf)		\
617{									\
618	struct sas_rphy *rphy = transport_class_to_rphy(cdev);		\
619	struct sas_end_device *rdev = rphy_to_end_device(rphy);		\
620									\
621	return snprintf(buf, 20, format_string, cast rdev->field);	\
622}
623
624#define sas_end_dev_simple_attr(field, name, format_string, type)	\
625	sas_end_dev_show_simple(field, name, format_string, (type))	\
626static SAS_CLASS_DEVICE_ATTR(end_dev, name, S_IRUGO, 			\
627		show_sas_end_dev_##name, NULL)
628
629sas_end_dev_simple_attr(ready_led_meaning, ready_led_meaning, "%d\n", int);
630sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout,
631			"%d\n", int);
632sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout,
633			"%d\n", int);
634
635static DECLARE_TRANSPORT_CLASS(sas_expander_class,
636			       "sas_expander", NULL, NULL, NULL);
637
638#define sas_expander_show_simple(field, name, format_string, cast)	\
639static ssize_t								\
640show_sas_expander_##name(struct class_device *cdev, char *buf)		\
641{									\
642	struct sas_rphy *rphy = transport_class_to_rphy(cdev);		\
643	struct sas_expander_device *edev = rphy_to_expander_device(rphy); \
644									\
645	return snprintf(buf, 20, format_string, cast edev->field);	\
646}
647
648#define sas_expander_simple_attr(field, name, format_string, type)	\
649	sas_expander_show_simple(field, name, format_string, (type))	\
650static SAS_CLASS_DEVICE_ATTR(expander, name, S_IRUGO, 			\
651		show_sas_expander_##name, NULL)
652
653sas_expander_simple_attr(vendor_id, vendor_id, "%s\n", char *);
654sas_expander_simple_attr(product_id, product_id, "%s\n", char *);
655sas_expander_simple_attr(product_rev, product_rev, "%s\n", char *);
656sas_expander_simple_attr(component_vendor_id, component_vendor_id,
657			 "%s\n", char *);
658sas_expander_simple_attr(component_id, component_id, "%u\n", unsigned int);
659sas_expander_simple_attr(component_revision_id, component_revision_id, "%u\n",
660			 unsigned int);
661sas_expander_simple_attr(level, level, "%d\n", int);
662
663static DECLARE_TRANSPORT_CLASS(sas_rphy_class,
664		"sas_device", NULL, NULL, NULL);
665
666static int sas_rphy_match(struct attribute_container *cont, struct device *dev)
667{
668	struct Scsi_Host *shost;
669	struct sas_internal *i;
670
671	if (!scsi_is_sas_rphy(dev))
672		return 0;
673	shost = dev_to_shost(dev->parent->parent);
674
675	if (!shost->transportt)
676		return 0;
677	if (shost->transportt->host_attrs.ac.class !=
678			&sas_host_class.class)
679		return 0;
680
681	i = to_sas_internal(shost->transportt);
682	return &i->rphy_attr_cont.ac == cont;
683}
684
685static int sas_end_dev_match(struct attribute_container *cont,
686			     struct device *dev)
687{
688	struct Scsi_Host *shost;
689	struct sas_internal *i;
690	struct sas_rphy *rphy;
691
692	if (!scsi_is_sas_rphy(dev))
693		return 0;
694	shost = dev_to_shost(dev->parent->parent);
695	rphy = dev_to_rphy(dev);
696
697	if (!shost->transportt)
698		return 0;
699	if (shost->transportt->host_attrs.ac.class !=
700			&sas_host_class.class)
701		return 0;
702
703	i = to_sas_internal(shost->transportt);
704	return &i->end_dev_attr_cont.ac == cont &&
705		rphy->identify.device_type == SAS_END_DEVICE;
706}
707
708static int sas_expander_match(struct attribute_container *cont,
709			      struct device *dev)
710{
711	struct Scsi_Host *shost;
712	struct sas_internal *i;
713	struct sas_rphy *rphy;
714
715	if (!scsi_is_sas_rphy(dev))
716		return 0;
717	shost = dev_to_shost(dev->parent->parent);
718	rphy = dev_to_rphy(dev);
719
720	if (!shost->transportt)
721		return 0;
722	if (shost->transportt->host_attrs.ac.class !=
723			&sas_host_class.class)
724		return 0;
725
726	i = to_sas_internal(shost->transportt);
727	return &i->expander_attr_cont.ac == cont &&
728		(rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
729		 rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE);
730}
731
732static void sas_expander_release(struct device *dev)
733{
734	struct sas_rphy *rphy = dev_to_rphy(dev);
735	struct sas_expander_device *edev = rphy_to_expander_device(rphy);
736
737	put_device(dev->parent);
738	kfree(edev);
739}
740
741static void sas_end_device_release(struct device *dev)
742{
743	struct sas_rphy *rphy = dev_to_rphy(dev);
744	struct sas_end_device *edev = rphy_to_end_device(rphy);
745
746	put_device(dev->parent);
747	kfree(edev);
748}
749
750/**
751 * sas_end_device_alloc - allocate an rphy for an end device
752 *
753 * Allocates an SAS remote PHY structure, connected to @parent.
754 *
755 * Returns:
756 *	SAS PHY allocated or %NULL if the allocation failed.
757 */
758struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent)
759{
760	struct Scsi_Host *shost = dev_to_shost(&parent->dev);
761	struct sas_end_device *rdev;
762
763	rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
764	if (!rdev) {
765		return NULL;
766	}
767
768	device_initialize(&rdev->rphy.dev);
769	rdev->rphy.dev.parent = get_device(&parent->dev);
770	rdev->rphy.dev.release = sas_end_device_release;
771	sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d-%d",
772		shost->host_no, parent->port_identifier, parent->number);
773	rdev->rphy.identify.device_type = SAS_END_DEVICE;
774	transport_setup_device(&rdev->rphy.dev);
775
776	return &rdev->rphy;
777}
778EXPORT_SYMBOL(sas_end_device_alloc);
779
780/**
781 * sas_expander_alloc - allocate an rphy for an end device
782 *
783 * Allocates an SAS remote PHY structure, connected to @parent.
784 *
785 * Returns:
786 *	SAS PHY allocated or %NULL if the allocation failed.
787 */
788struct sas_rphy *sas_expander_alloc(struct sas_phy *parent,
789				    enum sas_device_type type)
790{
791	struct Scsi_Host *shost = dev_to_shost(&parent->dev);
792	struct sas_expander_device *rdev;
793	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
794
795	BUG_ON(type != SAS_EDGE_EXPANDER_DEVICE &&
796	       type != SAS_FANOUT_EXPANDER_DEVICE);
797
798	rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
799	if (!rdev) {
800		return NULL;
801	}
802
803	device_initialize(&rdev->rphy.dev);
804	rdev->rphy.dev.parent = get_device(&parent->dev);
805	rdev->rphy.dev.release = sas_expander_release;
806	mutex_lock(&sas_host->lock);
807	rdev->rphy.scsi_target_id = sas_host->next_expander_id++;
808	mutex_unlock(&sas_host->lock);
809	sprintf(rdev->rphy.dev.bus_id, "expander-%d:%d",
810		shost->host_no, rdev->rphy.scsi_target_id);
811	rdev->rphy.identify.device_type = type;
812	transport_setup_device(&rdev->rphy.dev);
813
814	return &rdev->rphy;
815}
816EXPORT_SYMBOL(sas_expander_alloc);
817
818/**
819 * sas_rphy_add  --  add a SAS remote PHY to the device hierachy
820 * @rphy:	The remote PHY to be added
821 *
822 * Publishes a SAS remote PHY to the rest of the system.
823 */
824int sas_rphy_add(struct sas_rphy *rphy)
825{
826	struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
827	struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
828	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
829	struct sas_identify *identify = &rphy->identify;
830	int error;
831
832	if (parent->rphy)
833		return -ENXIO;
834	parent->rphy = rphy;
835
836	error = device_add(&rphy->dev);
837	if (error)
838		return error;
839	transport_add_device(&rphy->dev);
840	transport_configure_device(&rphy->dev);
841
842	mutex_lock(&sas_host->lock);
843	list_add_tail(&rphy->list, &sas_host->rphy_list);
844	if (identify->device_type == SAS_END_DEVICE &&
845	    (identify->target_port_protocols &
846	     (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA)))
847		rphy->scsi_target_id = sas_host->next_target_id++;
848	else if (identify->device_type == SAS_END_DEVICE)
849		rphy->scsi_target_id = -1;
850	mutex_unlock(&sas_host->lock);
851
852	if (identify->device_type == SAS_END_DEVICE &&
853	    rphy->scsi_target_id != -1) {
854		scsi_scan_target(&rphy->dev, parent->port_identifier,
855				rphy->scsi_target_id, ~0, 0);
856	}
857
858	return 0;
859}
860EXPORT_SYMBOL(sas_rphy_add);
861
862/**
863 * sas_rphy_free  --  free a SAS remote PHY
864 * @rphy	SAS remote PHY to free
865 *
866 * Frees the specified SAS remote PHY.
867 *
868 * Note:
869 *   This function must only be called on a remote
870 *   PHY that has not sucessfully been added using
871 *   sas_rphy_add().
872 */
873void sas_rphy_free(struct sas_rphy *rphy)
874{
875	struct device *dev = &rphy->dev;
876	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
877	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
878
879	mutex_lock(&sas_host->lock);
880	list_del(&rphy->list);
881	mutex_unlock(&sas_host->lock);
882
883	transport_destroy_device(dev);
884
885	put_device(dev);
886}
887EXPORT_SYMBOL(sas_rphy_free);
888
889/**
890 * sas_rphy_delete  --  remove SAS remote PHY
891 * @rphy:	SAS remote PHY to remove
892 *
893 * Removes the specified SAS remote PHY.
894 */
895void
896sas_rphy_delete(struct sas_rphy *rphy)
897{
898	struct device *dev = &rphy->dev;
899	struct sas_phy *parent = dev_to_phy(dev->parent);
900	struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
901	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
902
903	switch (rphy->identify.device_type) {
904	case SAS_END_DEVICE:
905		scsi_remove_target(dev);
906		break;
907	case SAS_EDGE_EXPANDER_DEVICE:
908	case SAS_FANOUT_EXPANDER_DEVICE:
909		device_for_each_child(dev, NULL, do_sas_phy_delete);
910		break;
911	default:
912		break;
913	}
914
915	transport_remove_device(dev);
916	device_del(dev);
917	transport_destroy_device(dev);
918
919	mutex_lock(&sas_host->lock);
920	list_del(&rphy->list);
921	mutex_unlock(&sas_host->lock);
922
923	parent->rphy = NULL;
924
925	put_device(dev);
926}
927EXPORT_SYMBOL(sas_rphy_delete);
928
929/**
930 * scsi_is_sas_rphy  --  check if a struct device represents a SAS remote PHY
931 * @dev:	device to check
932 *
933 * Returns:
934 *	%1 if the device represents a SAS remote PHY, %0 else
935 */
936int scsi_is_sas_rphy(const struct device *dev)
937{
938	return dev->release == sas_end_device_release ||
939		dev->release == sas_expander_release;
940}
941EXPORT_SYMBOL(scsi_is_sas_rphy);
942
943
944/*
945 * SCSI scan helper
946 */
947
948static int sas_user_scan(struct Scsi_Host *shost, uint channel,
949		uint id, uint lun)
950{
951	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
952	struct sas_rphy *rphy;
953
954	mutex_lock(&sas_host->lock);
955	list_for_each_entry(rphy, &sas_host->rphy_list, list) {
956		struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
957
958		if (rphy->identify.device_type != SAS_END_DEVICE ||
959		    rphy->scsi_target_id == -1)
960			continue;
961
962		if ((channel == SCAN_WILD_CARD || channel == parent->port_identifier) &&
963		    (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) {
964			scsi_scan_target(&rphy->dev, parent->port_identifier,
965					 rphy->scsi_target_id, lun, 1);
966		}
967	}
968	mutex_unlock(&sas_host->lock);
969
970	return 0;
971}
972
973
974/*
975 * Setup / Teardown code
976 */
977
978#define SETUP_TEMPLATE(attrb, field, perm, test)				\
979	i->private_##attrb[count] = class_device_attr_##field;		\
980	i->private_##attrb[count].attr.mode = perm;			\
981	i->attrb[count] = &i->private_##attrb[count];			\
982	if (test)							\
983		count++
984
985
986#define SETUP_RPORT_ATTRIBUTE(field) 					\
987	SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1)
988
989#define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func)			\
990	SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func)
991
992#define SETUP_PORT_ATTRIBUTE(field)					\
993	SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1)
994
995#define SETUP_OPTIONAL_PORT_ATTRIBUTE(field, func)			\
996	SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func)
997
998#define SETUP_PORT_ATTRIBUTE_WRONLY(field)				\
999	SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, 1)
1000
1001#define SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(field, func)		\
1002	SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, i->f->func)
1003
1004#define SETUP_END_DEV_ATTRIBUTE(field)					\
1005	SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1)
1006
1007#define SETUP_EXPANDER_ATTRIBUTE(field)					\
1008	SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1)
1009
1010/**
1011 * sas_attach_transport  --  instantiate SAS transport template
1012 * @ft:		SAS transport class function template
1013 */
1014struct scsi_transport_template *
1015sas_attach_transport(struct sas_function_template *ft)
1016{
1017	struct sas_internal *i;
1018	int count;
1019
1020	i = kzalloc(sizeof(struct sas_internal), GFP_KERNEL);
1021	if (!i)
1022		return NULL;
1023
1024	i->t.user_scan = sas_user_scan;
1025
1026	i->t.host_attrs.ac.attrs = &i->host_attrs[0];
1027	i->t.host_attrs.ac.class = &sas_host_class.class;
1028	i->t.host_attrs.ac.match = sas_host_match;
1029	transport_container_register(&i->t.host_attrs);
1030	i->t.host_size = sizeof(struct sas_host_attrs);
1031
1032	i->phy_attr_cont.ac.class = &sas_phy_class.class;
1033	i->phy_attr_cont.ac.attrs = &i->phy_attrs[0];
1034	i->phy_attr_cont.ac.match = sas_phy_match;
1035	transport_container_register(&i->phy_attr_cont);
1036
1037	i->rphy_attr_cont.ac.class = &sas_rphy_class.class;
1038	i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0];
1039	i->rphy_attr_cont.ac.match = sas_rphy_match;
1040	transport_container_register(&i->rphy_attr_cont);
1041
1042	i->end_dev_attr_cont.ac.class = &sas_end_dev_class.class;
1043	i->end_dev_attr_cont.ac.attrs = &i->end_dev_attrs[0];
1044	i->end_dev_attr_cont.ac.match = sas_end_dev_match;
1045	transport_container_register(&i->end_dev_attr_cont);
1046
1047	i->expander_attr_cont.ac.class = &sas_expander_class.class;
1048	i->expander_attr_cont.ac.attrs = &i->expander_attrs[0];
1049	i->expander_attr_cont.ac.match = sas_expander_match;
1050	transport_container_register(&i->expander_attr_cont);
1051
1052	i->f = ft;
1053
1054	count = 0;
1055	i->host_attrs[count] = NULL;
1056
1057	count = 0;
1058	SETUP_PORT_ATTRIBUTE(initiator_port_protocols);
1059	SETUP_PORT_ATTRIBUTE(target_port_protocols);
1060	SETUP_PORT_ATTRIBUTE(device_type);
1061	SETUP_PORT_ATTRIBUTE(sas_address);
1062	SETUP_PORT_ATTRIBUTE(phy_identifier);
1063	SETUP_PORT_ATTRIBUTE(port_identifier);
1064	SETUP_PORT_ATTRIBUTE(negotiated_linkrate);
1065	SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw);
1066	SETUP_PORT_ATTRIBUTE(minimum_linkrate);
1067	SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw);
1068	SETUP_PORT_ATTRIBUTE(maximum_linkrate);
1069
1070	SETUP_PORT_ATTRIBUTE(invalid_dword_count);
1071	SETUP_PORT_ATTRIBUTE(running_disparity_error_count);
1072	SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count);
1073	SETUP_PORT_ATTRIBUTE(phy_reset_problem_count);
1074	SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(link_reset, phy_reset);
1075	SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(hard_reset, phy_reset);
1076	i->phy_attrs[count] = NULL;
1077
1078	count = 0;
1079	SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols);
1080	SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols);
1081	SETUP_RPORT_ATTRIBUTE(rphy_device_type);
1082	SETUP_RPORT_ATTRIBUTE(rphy_sas_address);
1083	SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier);
1084	SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_enclosure_identifier,
1085				       get_enclosure_identifier);
1086	SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_bay_identifier,
1087				       get_bay_identifier);
1088	i->rphy_attrs[count] = NULL;
1089
1090	count = 0;
1091	SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning);
1092	SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout);
1093	SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout);
1094	i->end_dev_attrs[count] = NULL;
1095
1096	count = 0;
1097	SETUP_EXPANDER_ATTRIBUTE(vendor_id);
1098	SETUP_EXPANDER_ATTRIBUTE(product_id);
1099	SETUP_EXPANDER_ATTRIBUTE(product_rev);
1100	SETUP_EXPANDER_ATTRIBUTE(component_vendor_id);
1101	SETUP_EXPANDER_ATTRIBUTE(component_id);
1102	SETUP_EXPANDER_ATTRIBUTE(component_revision_id);
1103	SETUP_EXPANDER_ATTRIBUTE(level);
1104	i->expander_attrs[count] = NULL;
1105
1106	return &i->t;
1107}
1108EXPORT_SYMBOL(sas_attach_transport);
1109
1110/**
1111 * sas_release_transport  --  release SAS transport template instance
1112 * @t:		transport template instance
1113 */
1114void sas_release_transport(struct scsi_transport_template *t)
1115{
1116	struct sas_internal *i = to_sas_internal(t);
1117
1118	transport_container_unregister(&i->t.host_attrs);
1119	transport_container_unregister(&i->phy_attr_cont);
1120	transport_container_unregister(&i->rphy_attr_cont);
1121	transport_container_unregister(&i->end_dev_attr_cont);
1122	transport_container_unregister(&i->expander_attr_cont);
1123
1124	kfree(i);
1125}
1126EXPORT_SYMBOL(sas_release_transport);
1127
1128static __init int sas_transport_init(void)
1129{
1130	int error;
1131
1132	error = transport_class_register(&sas_host_class);
1133	if (error)
1134		goto out;
1135	error = transport_class_register(&sas_phy_class);
1136	if (error)
1137		goto out_unregister_transport;
1138	error = transport_class_register(&sas_rphy_class);
1139	if (error)
1140		goto out_unregister_phy;
1141	error = transport_class_register(&sas_end_dev_class);
1142	if (error)
1143		goto out_unregister_rphy;
1144	error = transport_class_register(&sas_expander_class);
1145	if (error)
1146		goto out_unregister_end_dev;
1147
1148	return 0;
1149
1150 out_unregister_end_dev:
1151	transport_class_unregister(&sas_end_dev_class);
1152 out_unregister_rphy:
1153	transport_class_unregister(&sas_rphy_class);
1154 out_unregister_phy:
1155	transport_class_unregister(&sas_phy_class);
1156 out_unregister_transport:
1157	transport_class_unregister(&sas_host_class);
1158 out:
1159	return error;
1160
1161}
1162
1163static void __exit sas_transport_exit(void)
1164{
1165	transport_class_unregister(&sas_host_class);
1166	transport_class_unregister(&sas_phy_class);
1167	transport_class_unregister(&sas_rphy_class);
1168	transport_class_unregister(&sas_end_dev_class);
1169	transport_class_unregister(&sas_expander_class);
1170}
1171
1172MODULE_AUTHOR("Christoph Hellwig");
1173MODULE_DESCRIPTION("SAS Transphy Attributes");
1174MODULE_LICENSE("GPL");
1175
1176module_init(sas_transport_init);
1177module_exit(sas_transport_exit);
1178