aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_transport_sas.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/scsi_transport_sas.c')
-rw-r--r--drivers/scsi/scsi_transport_sas.c412
1 files changed, 364 insertions, 48 deletions
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 210dab5879fa..134c44c8538a 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2005 Dell Inc. 2 * Copyright (C) 2005-2006 Dell Inc.
3 * Released under GPL v2. 3 * Released under GPL v2.
4 * 4 *
5 * Serial Attached SCSI (SAS) transport class. 5 * Serial Attached SCSI (SAS) transport class.
@@ -38,7 +38,9 @@
38 38
39#define SAS_HOST_ATTRS 0 39#define SAS_HOST_ATTRS 0
40#define SAS_PORT_ATTRS 17 40#define SAS_PORT_ATTRS 17
41#define SAS_RPORT_ATTRS 5 41#define SAS_RPORT_ATTRS 7
42#define SAS_END_DEV_ATTRS 3
43#define SAS_EXPANDER_ATTRS 7
42 44
43struct sas_internal { 45struct sas_internal {
44 struct scsi_transport_template t; 46 struct scsi_transport_template t;
@@ -47,9 +49,13 @@ struct sas_internal {
47 struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS]; 49 struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS];
48 struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS]; 50 struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS];
49 struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS]; 51 struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS];
52 struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS];
53 struct class_device_attribute private_expander_attrs[SAS_EXPANDER_ATTRS];
50 54
51 struct transport_container phy_attr_cont; 55 struct transport_container phy_attr_cont;
52 struct transport_container rphy_attr_cont; 56 struct transport_container rphy_attr_cont;
57 struct transport_container end_dev_attr_cont;
58 struct transport_container expander_attr_cont;
53 59
54 /* 60 /*
55 * The array of null terminated pointers to attributes 61 * The array of null terminated pointers to attributes
@@ -58,6 +64,8 @@ struct sas_internal {
58 struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1]; 64 struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1];
59 struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1]; 65 struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1];
60 struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1]; 66 struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1];
67 struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1];
68 struct class_device_attribute *expander_attrs[SAS_EXPANDER_ATTRS + 1];
61}; 69};
62#define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t) 70#define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t)
63 71
@@ -65,6 +73,7 @@ struct sas_host_attrs {
65 struct list_head rphy_list; 73 struct list_head rphy_list;
66 struct mutex lock; 74 struct mutex lock;
67 u32 next_target_id; 75 u32 next_target_id;
76 u32 next_expander_id;
68}; 77};
69#define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data) 78#define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data)
70 79
@@ -151,6 +160,7 @@ static struct {
151 { SAS_SATA_SPINUP_HOLD, "Spin-up hold" }, 160 { SAS_SATA_SPINUP_HOLD, "Spin-up hold" },
152 { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" }, 161 { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" },
153 { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" }, 162 { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" },
163 { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" },
154}; 164};
155sas_bitfield_name_search(linkspeed, sas_linkspeed_names) 165sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
156 166
@@ -168,6 +178,7 @@ static int sas_host_setup(struct transport_container *tc, struct device *dev,
168 INIT_LIST_HEAD(&sas_host->rphy_list); 178 INIT_LIST_HEAD(&sas_host->rphy_list);
169 mutex_init(&sas_host->lock); 179 mutex_init(&sas_host->lock);
170 sas_host->next_target_id = 0; 180 sas_host->next_target_id = 0;
181 sas_host->next_expander_id = 0;
171 return 0; 182 return 0;
172} 183}
173 184
@@ -272,7 +283,7 @@ show_sas_phy_##field(struct class_device *cdev, char *buf) \
272 if (!phy->local_attached) \ 283 if (!phy->local_attached) \
273 return -EINVAL; \ 284 return -EINVAL; \
274 \ 285 \
275 error = i->f->get_linkerrors(phy); \ 286 error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0; \
276 if (error) \ 287 if (error) \
277 return error; \ 288 return error; \
278 return snprintf(buf, 20, "%u\n", phy->field); \ 289 return snprintf(buf, 20, "%u\n", phy->field); \
@@ -391,10 +402,9 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number)
391 struct Scsi_Host *shost = dev_to_shost(parent); 402 struct Scsi_Host *shost = dev_to_shost(parent);
392 struct sas_phy *phy; 403 struct sas_phy *phy;
393 404
394 phy = kmalloc(sizeof(*phy), GFP_KERNEL); 405 phy = kzalloc(sizeof(*phy), GFP_KERNEL);
395 if (!phy) 406 if (!phy)
396 return NULL; 407 return NULL;
397 memset(phy, 0, sizeof(*phy));
398 408
399 get_device(parent); 409 get_device(parent);
400 410
@@ -403,7 +413,12 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number)
403 device_initialize(&phy->dev); 413 device_initialize(&phy->dev);
404 phy->dev.parent = get_device(parent); 414 phy->dev.parent = get_device(parent);
405 phy->dev.release = sas_phy_release; 415 phy->dev.release = sas_phy_release;
406 sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number); 416 if (scsi_is_sas_expander_device(parent)) {
417 struct sas_rphy *rphy = dev_to_rphy(parent);
418 sprintf(phy->dev.bus_id, "phy-%d-%d:%d", shost->host_no,
419 rphy->scsi_target_id, number);
420 } else
421 sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number);
407 422
408 transport_setup_device(&phy->dev); 423 transport_setup_device(&phy->dev);
409 424
@@ -534,6 +549,53 @@ show_sas_rphy_device_type(struct class_device *cdev, char *buf)
534static SAS_CLASS_DEVICE_ATTR(rphy, device_type, S_IRUGO, 549static SAS_CLASS_DEVICE_ATTR(rphy, device_type, S_IRUGO,
535 show_sas_rphy_device_type, NULL); 550 show_sas_rphy_device_type, NULL);
536 551
552static ssize_t
553show_sas_rphy_enclosure_identifier(struct class_device *cdev, char *buf)
554{
555 struct sas_rphy *rphy = transport_class_to_rphy(cdev);
556 struct sas_phy *phy = dev_to_phy(rphy->dev.parent);
557 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
558 struct sas_internal *i = to_sas_internal(shost->transportt);
559 u64 identifier;
560 int error;
561
562 /*
563 * Only devices behind an expander are supported, because the
564 * enclosure identifier is a SMP feature.
565 */
566 if (phy->local_attached)
567 return -EINVAL;
568
569 error = i->f->get_enclosure_identifier(rphy, &identifier);
570 if (error)
571 return error;
572 return sprintf(buf, "0x%llx\n", (unsigned long long)identifier);
573}
574
575static SAS_CLASS_DEVICE_ATTR(rphy, enclosure_identifier, S_IRUGO,
576 show_sas_rphy_enclosure_identifier, NULL);
577
578static ssize_t
579show_sas_rphy_bay_identifier(struct class_device *cdev, char *buf)
580{
581 struct sas_rphy *rphy = transport_class_to_rphy(cdev);
582 struct sas_phy *phy = dev_to_phy(rphy->dev.parent);
583 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
584 struct sas_internal *i = to_sas_internal(shost->transportt);
585 int val;
586
587 if (phy->local_attached)
588 return -EINVAL;
589
590 val = i->f->get_bay_identifier(rphy);
591 if (val < 0)
592 return val;
593 return sprintf(buf, "%d\n", val);
594}
595
596static SAS_CLASS_DEVICE_ATTR(rphy, bay_identifier, S_IRUGO,
597 show_sas_rphy_bay_identifier, NULL);
598
537sas_rphy_protocol_attr(identify.initiator_port_protocols, 599sas_rphy_protocol_attr(identify.initiator_port_protocols,
538 initiator_port_protocols); 600 initiator_port_protocols);
539sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols); 601sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols);
@@ -541,8 +603,103 @@ sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
541 unsigned long long); 603 unsigned long long);
542sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 604sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
543 605
606/* only need 8 bytes of data plus header (4 or 8) */
607#define BUF_SIZE 64
608
609int sas_read_port_mode_page(struct scsi_device *sdev)
610{
611 char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata;
612 struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target);
613 struct sas_end_device *rdev;
614 struct scsi_mode_data mode_data;
615 int res, error;
616
617 BUG_ON(rphy->identify.device_type != SAS_END_DEVICE);
618
619 rdev = rphy_to_end_device(rphy);
620
621 if (!buffer)
622 return -ENOMEM;
623
624 res = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3,
625 &mode_data, NULL);
626
627 error = -EINVAL;
628 if (!scsi_status_is_good(res))
629 goto out;
630
631 msdata = buffer + mode_data.header_length +
632 mode_data.block_descriptor_length;
633
634 if (msdata - buffer > BUF_SIZE - 8)
635 goto out;
636
637 error = 0;
638
639 rdev->ready_led_meaning = msdata[2] & 0x10 ? 1 : 0;
640 rdev->I_T_nexus_loss_timeout = (msdata[4] << 8) + msdata[5];
641 rdev->initiator_response_timeout = (msdata[6] << 8) + msdata[7];
642
643 out:
644 kfree(buffer);
645 return error;
646}
647EXPORT_SYMBOL(sas_read_port_mode_page);
648
649static DECLARE_TRANSPORT_CLASS(sas_end_dev_class,
650 "sas_end_device", NULL, NULL, NULL);
651
652#define sas_end_dev_show_simple(field, name, format_string, cast) \
653static ssize_t \
654show_sas_end_dev_##name(struct class_device *cdev, char *buf) \
655{ \
656 struct sas_rphy *rphy = transport_class_to_rphy(cdev); \
657 struct sas_end_device *rdev = rphy_to_end_device(rphy); \
658 \
659 return snprintf(buf, 20, format_string, cast rdev->field); \
660}
661
662#define sas_end_dev_simple_attr(field, name, format_string, type) \
663 sas_end_dev_show_simple(field, name, format_string, (type)) \
664static SAS_CLASS_DEVICE_ATTR(end_dev, name, S_IRUGO, \
665 show_sas_end_dev_##name, NULL)
666
667sas_end_dev_simple_attr(ready_led_meaning, ready_led_meaning, "%d\n", int);
668sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout,
669 "%d\n", int);
670sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout,
671 "%d\n", int);
672
673static DECLARE_TRANSPORT_CLASS(sas_expander_class,
674 "sas_expander", NULL, NULL, NULL);
675
676#define sas_expander_show_simple(field, name, format_string, cast) \
677static ssize_t \
678show_sas_expander_##name(struct class_device *cdev, char *buf) \
679{ \
680 struct sas_rphy *rphy = transport_class_to_rphy(cdev); \
681 struct sas_expander_device *edev = rphy_to_expander_device(rphy); \
682 \
683 return snprintf(buf, 20, format_string, cast edev->field); \
684}
685
686#define sas_expander_simple_attr(field, name, format_string, type) \
687 sas_expander_show_simple(field, name, format_string, (type)) \
688static SAS_CLASS_DEVICE_ATTR(expander, name, S_IRUGO, \
689 show_sas_expander_##name, NULL)
690
691sas_expander_simple_attr(vendor_id, vendor_id, "%s\n", char *);
692sas_expander_simple_attr(product_id, product_id, "%s\n", char *);
693sas_expander_simple_attr(product_rev, product_rev, "%s\n", char *);
694sas_expander_simple_attr(component_vendor_id, component_vendor_id,
695 "%s\n", char *);
696sas_expander_simple_attr(component_id, component_id, "%u\n", unsigned int);
697sas_expander_simple_attr(component_revision_id, component_revision_id, "%u\n",
698 unsigned int);
699sas_expander_simple_attr(level, level, "%d\n", int);
700
544static DECLARE_TRANSPORT_CLASS(sas_rphy_class, 701static DECLARE_TRANSPORT_CLASS(sas_rphy_class,
545 "sas_rphy", NULL, NULL, NULL); 702 "sas_device", NULL, NULL, NULL);
546 703
547static int sas_rphy_match(struct attribute_container *cont, struct device *dev) 704static int sas_rphy_match(struct attribute_container *cont, struct device *dev)
548{ 705{
@@ -563,45 +720,140 @@ static int sas_rphy_match(struct attribute_container *cont, struct device *dev)
563 return &i->rphy_attr_cont.ac == cont; 720 return &i->rphy_attr_cont.ac == cont;
564} 721}
565 722
566static void sas_rphy_release(struct device *dev) 723static int sas_end_dev_match(struct attribute_container *cont,
724 struct device *dev)
725{
726 struct Scsi_Host *shost;
727 struct sas_internal *i;
728 struct sas_rphy *rphy;
729
730 if (!scsi_is_sas_rphy(dev))
731 return 0;
732 shost = dev_to_shost(dev->parent->parent);
733 rphy = dev_to_rphy(dev);
734
735 if (!shost->transportt)
736 return 0;
737 if (shost->transportt->host_attrs.ac.class !=
738 &sas_host_class.class)
739 return 0;
740
741 i = to_sas_internal(shost->transportt);
742 return &i->end_dev_attr_cont.ac == cont &&
743 rphy->identify.device_type == SAS_END_DEVICE;
744}
745
746static int sas_expander_match(struct attribute_container *cont,
747 struct device *dev)
748{
749 struct Scsi_Host *shost;
750 struct sas_internal *i;
751 struct sas_rphy *rphy;
752
753 if (!scsi_is_sas_rphy(dev))
754 return 0;
755 shost = dev_to_shost(dev->parent->parent);
756 rphy = dev_to_rphy(dev);
757
758 if (!shost->transportt)
759 return 0;
760 if (shost->transportt->host_attrs.ac.class !=
761 &sas_host_class.class)
762 return 0;
763
764 i = to_sas_internal(shost->transportt);
765 return &i->expander_attr_cont.ac == cont &&
766 (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
767 rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE);
768}
769
770static void sas_expander_release(struct device *dev)
771{
772 struct sas_rphy *rphy = dev_to_rphy(dev);
773 struct sas_expander_device *edev = rphy_to_expander_device(rphy);
774
775 put_device(dev->parent);
776 kfree(edev);
777}
778
779static void sas_end_device_release(struct device *dev)
567{ 780{
568 struct sas_rphy *rphy = dev_to_rphy(dev); 781 struct sas_rphy *rphy = dev_to_rphy(dev);
782 struct sas_end_device *edev = rphy_to_end_device(rphy);
569 783
570 put_device(dev->parent); 784 put_device(dev->parent);
571 kfree(rphy); 785 kfree(edev);
572} 786}
573 787
574/** 788/**
575 * sas_rphy_alloc -- allocates and initialize a SAS remote PHY structure 789 * sas_end_device_alloc - allocate an rphy for an end device
576 * @parent: SAS PHY this remote PHY is conneted to
577 * 790 *
578 * Allocates an SAS remote PHY structure, connected to @parent. 791 * Allocates an SAS remote PHY structure, connected to @parent.
579 * 792 *
580 * Returns: 793 * Returns:
581 * SAS PHY allocated or %NULL if the allocation failed. 794 * SAS PHY allocated or %NULL if the allocation failed.
582 */ 795 */
583struct sas_rphy *sas_rphy_alloc(struct sas_phy *parent) 796struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent)
584{ 797{
585 struct Scsi_Host *shost = dev_to_shost(&parent->dev); 798 struct Scsi_Host *shost = dev_to_shost(&parent->dev);
586 struct sas_rphy *rphy; 799 struct sas_end_device *rdev;
587 800
588 rphy = kmalloc(sizeof(*rphy), GFP_KERNEL); 801 rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
589 if (!rphy) { 802 if (!rdev) {
590 put_device(&parent->dev); 803 put_device(&parent->dev);
591 return NULL; 804 return NULL;
592 } 805 }
593 memset(rphy, 0, sizeof(*rphy));
594 806
595 device_initialize(&rphy->dev); 807 device_initialize(&rdev->rphy.dev);
596 rphy->dev.parent = get_device(&parent->dev); 808 rdev->rphy.dev.parent = get_device(&parent->dev);
597 rphy->dev.release = sas_rphy_release; 809 rdev->rphy.dev.release = sas_end_device_release;
598 sprintf(rphy->dev.bus_id, "rphy-%d:%d-%d", 810 sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d-%d",
599 shost->host_no, parent->port_identifier, parent->number); 811 shost->host_no, parent->port_identifier, parent->number);
600 transport_setup_device(&rphy->dev); 812 rdev->rphy.identify.device_type = SAS_END_DEVICE;
813 transport_setup_device(&rdev->rphy.dev);
601 814
602 return rphy; 815 return &rdev->rphy;
603} 816}
604EXPORT_SYMBOL(sas_rphy_alloc); 817EXPORT_SYMBOL(sas_end_device_alloc);
818
819/**
820 * sas_expander_alloc - allocate an rphy for an end device
821 *
822 * Allocates an SAS remote PHY structure, connected to @parent.
823 *
824 * Returns:
825 * SAS PHY allocated or %NULL if the allocation failed.
826 */
827struct sas_rphy *sas_expander_alloc(struct sas_phy *parent,
828 enum sas_device_type type)
829{
830 struct Scsi_Host *shost = dev_to_shost(&parent->dev);
831 struct sas_expander_device *rdev;
832 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
833
834 BUG_ON(type != SAS_EDGE_EXPANDER_DEVICE &&
835 type != SAS_FANOUT_EXPANDER_DEVICE);
836
837 rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
838 if (!rdev) {
839 put_device(&parent->dev);
840 return NULL;
841 }
842
843 device_initialize(&rdev->rphy.dev);
844 rdev->rphy.dev.parent = get_device(&parent->dev);
845 rdev->rphy.dev.release = sas_expander_release;
846 mutex_lock(&sas_host->lock);
847 rdev->rphy.scsi_target_id = sas_host->next_expander_id++;
848 mutex_unlock(&sas_host->lock);
849 sprintf(rdev->rphy.dev.bus_id, "expander-%d:%d",
850 shost->host_no, rdev->rphy.scsi_target_id);
851 rdev->rphy.identify.device_type = type;
852 transport_setup_device(&rdev->rphy.dev);
853
854 return &rdev->rphy;
855}
856EXPORT_SYMBOL(sas_expander_alloc);
605 857
606/** 858/**
607 * sas_rphy_add -- add a SAS remote PHY to the device hierachy 859 * sas_rphy_add -- add a SAS remote PHY to the device hierachy
@@ -633,11 +885,10 @@ int sas_rphy_add(struct sas_rphy *rphy)
633 (identify->target_port_protocols & 885 (identify->target_port_protocols &
634 (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA))) 886 (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA)))
635 rphy->scsi_target_id = sas_host->next_target_id++; 887 rphy->scsi_target_id = sas_host->next_target_id++;
636 else
637 rphy->scsi_target_id = -1;
638 mutex_unlock(&sas_host->lock); 888 mutex_unlock(&sas_host->lock);
639 889
640 if (rphy->scsi_target_id != -1) { 890 if (identify->device_type == SAS_END_DEVICE &&
891 rphy->scsi_target_id != -1) {
641 scsi_scan_target(&rphy->dev, parent->port_identifier, 892 scsi_scan_target(&rphy->dev, parent->port_identifier,
642 rphy->scsi_target_id, ~0, 0); 893 rphy->scsi_target_id, ~0, 0);
643 } 894 }
@@ -670,7 +921,17 @@ void sas_rphy_free(struct sas_rphy *rphy)
670 put_device(rphy->dev.parent); 921 put_device(rphy->dev.parent);
671 put_device(rphy->dev.parent); 922 put_device(rphy->dev.parent);
672 put_device(rphy->dev.parent); 923 put_device(rphy->dev.parent);
673 kfree(rphy); 924 if (rphy->identify.device_type == SAS_END_DEVICE) {
925 struct sas_end_device *edev = rphy_to_end_device(rphy);
926
927 kfree(edev);
928 } else {
929 /* must be expander */
930 struct sas_expander_device *edev =
931 rphy_to_expander_device(rphy);
932
933 kfree(edev);
934 }
674} 935}
675EXPORT_SYMBOL(sas_rphy_free); 936EXPORT_SYMBOL(sas_rphy_free);
676 937
@@ -723,7 +984,8 @@ EXPORT_SYMBOL(sas_rphy_delete);
723 */ 984 */
724int scsi_is_sas_rphy(const struct device *dev) 985int scsi_is_sas_rphy(const struct device *dev)
725{ 986{
726 return dev->release == sas_rphy_release; 987 return dev->release == sas_end_device_release ||
988 dev->release == sas_expander_release;
727} 989}
728EXPORT_SYMBOL(scsi_is_sas_rphy); 990EXPORT_SYMBOL(scsi_is_sas_rphy);
729 991
@@ -761,27 +1023,38 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
761 * Setup / Teardown code 1023 * Setup / Teardown code
762 */ 1024 */
763 1025
764#define SETUP_RPORT_ATTRIBUTE(field) \ 1026#define SETUP_TEMPLATE(attrb, field, perm, test) \
765 i->private_rphy_attrs[count] = class_device_attr_##field; \ 1027 i->private_##attrb[count] = class_device_attr_##field; \
766 i->private_rphy_attrs[count].attr.mode = S_IRUGO; \ 1028 i->private_##attrb[count].attr.mode = perm; \
767 i->private_rphy_attrs[count].store = NULL; \ 1029 i->private_##attrb[count].store = NULL; \
768 i->rphy_attrs[count] = &i->private_rphy_attrs[count]; \ 1030 i->attrb[count] = &i->private_##attrb[count]; \
769 count++ 1031 if (test) \
1032 count++
1033
1034
1035#define SETUP_RPORT_ATTRIBUTE(field) \
1036 SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1)
1037
1038#define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \
1039 SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func)
770 1040
771#define SETUP_PORT_ATTRIBUTE(field) \ 1041#define SETUP_PORT_ATTRIBUTE(field) \
772 i->private_phy_attrs[count] = class_device_attr_##field; \ 1042 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1)
773 i->private_phy_attrs[count].attr.mode = S_IRUGO; \ 1043
774 i->private_phy_attrs[count].store = NULL; \ 1044#define SETUP_OPTIONAL_PORT_ATTRIBUTE(field, func) \
775 i->phy_attrs[count] = &i->private_phy_attrs[count]; \ 1045 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func)
776 count++
777 1046
778#define SETUP_PORT_ATTRIBUTE_WRONLY(field) \ 1047#define SETUP_PORT_ATTRIBUTE_WRONLY(field) \
779 i->private_phy_attrs[count] = class_device_attr_##field; \ 1048 SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, 1)
780 i->private_phy_attrs[count].attr.mode = S_IWUGO; \ 1049
781 i->private_phy_attrs[count].show = NULL; \ 1050#define SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(field, func) \
782 i->phy_attrs[count] = &i->private_phy_attrs[count]; \ 1051 SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, i->f->func)
783 count++
784 1052
1053#define SETUP_END_DEV_ATTRIBUTE(field) \
1054 SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1)
1055
1056#define SETUP_EXPANDER_ATTRIBUTE(field) \
1057 SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1)
785 1058
786/** 1059/**
787 * sas_attach_transport -- instantiate SAS transport template 1060 * sas_attach_transport -- instantiate SAS transport template
@@ -793,10 +1066,9 @@ sas_attach_transport(struct sas_function_template *ft)
793 struct sas_internal *i; 1066 struct sas_internal *i;
794 int count; 1067 int count;
795 1068
796 i = kmalloc(sizeof(struct sas_internal), GFP_KERNEL); 1069 i = kzalloc(sizeof(struct sas_internal), GFP_KERNEL);
797 if (!i) 1070 if (!i)
798 return NULL; 1071 return NULL;
799 memset(i, 0, sizeof(struct sas_internal));
800 1072
801 i->t.user_scan = sas_user_scan; 1073 i->t.user_scan = sas_user_scan;
802 1074
@@ -816,6 +1088,16 @@ sas_attach_transport(struct sas_function_template *ft)
816 i->rphy_attr_cont.ac.match = sas_rphy_match; 1088 i->rphy_attr_cont.ac.match = sas_rphy_match;
817 transport_container_register(&i->rphy_attr_cont); 1089 transport_container_register(&i->rphy_attr_cont);
818 1090
1091 i->end_dev_attr_cont.ac.class = &sas_end_dev_class.class;
1092 i->end_dev_attr_cont.ac.attrs = &i->end_dev_attrs[0];
1093 i->end_dev_attr_cont.ac.match = sas_end_dev_match;
1094 transport_container_register(&i->end_dev_attr_cont);
1095
1096 i->expander_attr_cont.ac.class = &sas_expander_class.class;
1097 i->expander_attr_cont.ac.attrs = &i->expander_attrs[0];
1098 i->expander_attr_cont.ac.match = sas_expander_match;
1099 transport_container_register(&i->expander_attr_cont);
1100
819 i->f = ft; 1101 i->f = ft;
820 1102
821 count = 0; 1103 count = 0;
@@ -838,8 +1120,8 @@ sas_attach_transport(struct sas_function_template *ft)
838 SETUP_PORT_ATTRIBUTE(running_disparity_error_count); 1120 SETUP_PORT_ATTRIBUTE(running_disparity_error_count);
839 SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count); 1121 SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count);
840 SETUP_PORT_ATTRIBUTE(phy_reset_problem_count); 1122 SETUP_PORT_ATTRIBUTE(phy_reset_problem_count);
841 SETUP_PORT_ATTRIBUTE_WRONLY(link_reset); 1123 SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(link_reset, phy_reset);
842 SETUP_PORT_ATTRIBUTE_WRONLY(hard_reset); 1124 SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(hard_reset, phy_reset);
843 i->phy_attrs[count] = NULL; 1125 i->phy_attrs[count] = NULL;
844 1126
845 count = 0; 1127 count = 0;
@@ -848,8 +1130,28 @@ sas_attach_transport(struct sas_function_template *ft)
848 SETUP_RPORT_ATTRIBUTE(rphy_device_type); 1130 SETUP_RPORT_ATTRIBUTE(rphy_device_type);
849 SETUP_RPORT_ATTRIBUTE(rphy_sas_address); 1131 SETUP_RPORT_ATTRIBUTE(rphy_sas_address);
850 SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier); 1132 SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier);
1133 SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_enclosure_identifier,
1134 get_enclosure_identifier);
1135 SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_bay_identifier,
1136 get_bay_identifier);
851 i->rphy_attrs[count] = NULL; 1137 i->rphy_attrs[count] = NULL;
852 1138
1139 count = 0;
1140 SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning);
1141 SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout);
1142 SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout);
1143 i->end_dev_attrs[count] = NULL;
1144
1145 count = 0;
1146 SETUP_EXPANDER_ATTRIBUTE(vendor_id);
1147 SETUP_EXPANDER_ATTRIBUTE(product_id);
1148 SETUP_EXPANDER_ATTRIBUTE(product_rev);
1149 SETUP_EXPANDER_ATTRIBUTE(component_vendor_id);
1150 SETUP_EXPANDER_ATTRIBUTE(component_id);
1151 SETUP_EXPANDER_ATTRIBUTE(component_revision_id);
1152 SETUP_EXPANDER_ATTRIBUTE(level);
1153 i->expander_attrs[count] = NULL;
1154
853 return &i->t; 1155 return &i->t;
854} 1156}
855EXPORT_SYMBOL(sas_attach_transport); 1157EXPORT_SYMBOL(sas_attach_transport);
@@ -865,6 +1167,8 @@ void sas_release_transport(struct scsi_transport_template *t)
865 transport_container_unregister(&i->t.host_attrs); 1167 transport_container_unregister(&i->t.host_attrs);
866 transport_container_unregister(&i->phy_attr_cont); 1168 transport_container_unregister(&i->phy_attr_cont);
867 transport_container_unregister(&i->rphy_attr_cont); 1169 transport_container_unregister(&i->rphy_attr_cont);
1170 transport_container_unregister(&i->end_dev_attr_cont);
1171 transport_container_unregister(&i->expander_attr_cont);
868 1172
869 kfree(i); 1173 kfree(i);
870} 1174}
@@ -883,9 +1187,19 @@ static __init int sas_transport_init(void)
883 error = transport_class_register(&sas_rphy_class); 1187 error = transport_class_register(&sas_rphy_class);
884 if (error) 1188 if (error)
885 goto out_unregister_phy; 1189 goto out_unregister_phy;
1190 error = transport_class_register(&sas_end_dev_class);
1191 if (error)
1192 goto out_unregister_rphy;
1193 error = transport_class_register(&sas_expander_class);
1194 if (error)
1195 goto out_unregister_end_dev;
886 1196
887 return 0; 1197 return 0;
888 1198
1199 out_unregister_end_dev:
1200 transport_class_unregister(&sas_end_dev_class);
1201 out_unregister_rphy:
1202 transport_class_unregister(&sas_rphy_class);
889 out_unregister_phy: 1203 out_unregister_phy:
890 transport_class_unregister(&sas_phy_class); 1204 transport_class_unregister(&sas_phy_class);
891 out_unregister_transport: 1205 out_unregister_transport:
@@ -900,6 +1214,8 @@ static void __exit sas_transport_exit(void)
900 transport_class_unregister(&sas_host_class); 1214 transport_class_unregister(&sas_host_class);
901 transport_class_unregister(&sas_phy_class); 1215 transport_class_unregister(&sas_phy_class);
902 transport_class_unregister(&sas_rphy_class); 1216 transport_class_unregister(&sas_rphy_class);
1217 transport_class_unregister(&sas_end_dev_class);
1218 transport_class_unregister(&sas_expander_class);
903} 1219}
904 1220
905MODULE_AUTHOR("Christoph Hellwig"); 1221MODULE_AUTHOR("Christoph Hellwig");