aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/scsi_transport_sas.c199
1 files changed, 165 insertions, 34 deletions
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 434f3954aa87..5de29b941c6b 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -39,6 +39,7 @@
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 7 41#define SAS_RPORT_ATTRS 7
42#define SAS_END_DEV_ATTRS 3
42 43
43struct sas_internal { 44struct sas_internal {
44 struct scsi_transport_template t; 45 struct scsi_transport_template t;
@@ -47,9 +48,11 @@ struct sas_internal {
47 struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS]; 48 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_phy_attrs[SAS_PORT_ATTRS];
49 struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS]; 50 struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS];
51 struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS];
50 52
51 struct transport_container phy_attr_cont; 53 struct transport_container phy_attr_cont;
52 struct transport_container rphy_attr_cont; 54 struct transport_container rphy_attr_cont;
55 struct transport_container end_dev_attr_cont;
53 56
54 /* 57 /*
55 * The array of null terminated pointers to attributes 58 * The array of null terminated pointers to attributes
@@ -58,6 +61,7 @@ struct sas_internal {
58 struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1]; 61 struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1];
59 struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1]; 62 struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1];
60 struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1]; 63 struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1];
64 struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1];
61}; 65};
62#define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t) 66#define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t)
63 67
@@ -588,6 +592,73 @@ sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
588 unsigned long long); 592 unsigned long long);
589sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 593sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
590 594
595/* only need 8 bytes of data plus header (4 or 8) */
596#define BUF_SIZE 64
597
598int sas_read_port_mode_page(struct scsi_device *sdev)
599{
600 char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata;
601 struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target);
602 struct sas_end_device *rdev;
603 struct scsi_mode_data mode_data;
604 int res, error;
605
606 BUG_ON(rphy->identify.device_type != SAS_END_DEVICE);
607
608 rdev = rphy_to_end_device(rphy);
609
610 if (!buffer)
611 return -ENOMEM;
612
613 res = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3,
614 &mode_data, NULL);
615
616 error = -EINVAL;
617 if (!scsi_status_is_good(res))
618 goto out;
619
620 msdata = buffer + mode_data.header_length +
621 mode_data.block_descriptor_length;
622
623 if (msdata - buffer > BUF_SIZE - 8)
624 goto out;
625
626 error = 0;
627
628 rdev->ready_led_meaning = msdata[2] & 0x10 ? 1 : 0;
629 rdev->I_T_nexus_loss_timeout = (msdata[4] << 8) + msdata[5];
630 rdev->initiator_response_timeout = (msdata[6] << 8) + msdata[7];
631
632 out:
633 kfree(buffer);
634 return error;
635}
636EXPORT_SYMBOL(sas_read_port_mode_page);
637
638#define sas_end_dev_show_simple(field, name, format_string, cast) \
639static ssize_t \
640show_sas_end_dev_##name(struct class_device *cdev, char *buf) \
641{ \
642 struct sas_rphy *rphy = transport_class_to_rphy(cdev); \
643 struct sas_end_device *rdev = rphy_to_end_device(rphy); \
644 \
645 return snprintf(buf, 20, format_string, cast rdev->field); \
646}
647
648#define sas_end_dev_simple_attr(field, name, format_string, type) \
649 sas_end_dev_show_simple(field, name, format_string, (type)) \
650static SAS_CLASS_DEVICE_ATTR(end_dev, name, S_IRUGO, \
651 show_sas_end_dev_##name, NULL)
652
653sas_end_dev_simple_attr(ready_led_meaning, ready_led_meaning, "%d\n", int);
654sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout,
655 "%d\n", int);
656sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout,
657 "%d\n", int);
658
659static DECLARE_TRANSPORT_CLASS(sas_end_dev_class,
660 "sas_end_device", NULL, NULL, NULL);
661
591static DECLARE_TRANSPORT_CLASS(sas_rphy_class, 662static DECLARE_TRANSPORT_CLASS(sas_rphy_class,
592 "sas_rphy", NULL, NULL, NULL); 663 "sas_rphy", NULL, NULL, NULL);
593 664
@@ -610,6 +681,31 @@ static int sas_rphy_match(struct attribute_container *cont, struct device *dev)
610 return &i->rphy_attr_cont.ac == cont; 681 return &i->rphy_attr_cont.ac == cont;
611} 682}
612 683
684static int sas_end_dev_match(struct attribute_container *cont,
685 struct device *dev)
686{
687 struct Scsi_Host *shost;
688 struct sas_internal *i;
689 struct sas_rphy *rphy;
690
691 if (!scsi_is_sas_rphy(dev))
692 return 0;
693 shost = dev_to_shost(dev->parent->parent);
694 rphy = dev_to_rphy(dev);
695
696 if (!shost->transportt)
697 return 0;
698 if (shost->transportt->host_attrs.ac.class !=
699 &sas_host_class.class)
700 return 0;
701
702 i = to_sas_internal(shost->transportt);
703 return &i->end_dev_attr_cont.ac == cont &&
704 rphy->identify.device_type == SAS_END_DEVICE &&
705 /* FIXME: remove contained eventually */
706 rphy->contained;
707}
708
613static void sas_rphy_release(struct device *dev) 709static void sas_rphy_release(struct device *dev)
614{ 710{
615 struct sas_rphy *rphy = dev_to_rphy(dev); 711 struct sas_rphy *rphy = dev_to_rphy(dev);
@@ -650,6 +746,40 @@ struct sas_rphy *sas_rphy_alloc(struct sas_phy *parent)
650EXPORT_SYMBOL(sas_rphy_alloc); 746EXPORT_SYMBOL(sas_rphy_alloc);
651 747
652/** 748/**
749 * sas_end_device_alloc - allocate an rphy for an end device
750 *
751 * Allocates an SAS remote PHY structure, connected to @parent.
752 *
753 * Returns:
754 * SAS PHY allocated or %NULL if the allocation failed.
755 */
756struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent)
757{
758 struct Scsi_Host *shost = dev_to_shost(&parent->dev);
759 struct sas_end_device *rdev;
760
761 rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
762 if (!rdev) {
763 put_device(&parent->dev);
764 return NULL;
765 }
766
767 device_initialize(&rdev->rphy.dev);
768 rdev->rphy.dev.parent = get_device(&parent->dev);
769 rdev->rphy.dev.release = sas_rphy_release;
770 sprintf(rdev->rphy.dev.bus_id, "rphy-%d:%d-%d",
771 shost->host_no, parent->port_identifier, parent->number);
772 rdev->rphy.identify.device_type = SAS_END_DEVICE;
773 /* FIXME: mark the rphy as being contained in a larger structure */
774 rdev->rphy.contained = 1;
775 transport_setup_device(&rdev->rphy.dev);
776
777 return &rdev->rphy;
778}
779EXPORT_SYMBOL(sas_end_device_alloc);
780
781
782/**
653 * sas_rphy_add -- add a SAS remote PHY to the device hierachy 783 * sas_rphy_add -- add a SAS remote PHY to the device hierachy
654 * @rphy: The remote PHY to be added 784 * @rphy: The remote PHY to be added
655 * 785 *
@@ -807,51 +937,35 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
807 * Setup / Teardown code 937 * Setup / Teardown code
808 */ 938 */
809 939
810#define SETUP_RPORT_ATTRIBUTE(field) \ 940#define SETUP_TEMPLATE(attrb, field, perm, test) \
811 i->private_rphy_attrs[count] = class_device_attr_##field; \ 941 i->private_##attrb[count] = class_device_attr_##field; \
812 i->private_rphy_attrs[count].attr.mode = S_IRUGO; \ 942 i->private_##attrb[count].attr.mode = perm; \
813 i->private_rphy_attrs[count].store = NULL; \ 943 i->private_##attrb[count].store = NULL; \
814 i->rphy_attrs[count] = &i->private_rphy_attrs[count]; \ 944 i->attrb[count] = &i->private_##attrb[count]; \
815 count++ 945 if (test) \
946 count++
947
948
949#define SETUP_RPORT_ATTRIBUTE(field) \
950 SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1)
816 951
817#define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \ 952#define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \
818 i->private_rphy_attrs[count] = class_device_attr_##field; \ 953 SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func)
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 954
825#define SETUP_PORT_ATTRIBUTE(field) \ 955#define SETUP_PORT_ATTRIBUTE(field) \
826 i->private_phy_attrs[count] = class_device_attr_##field; \ 956 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1)
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 957
832#define SETUP_OPTIONAL_PORT_ATTRIBUTE(field, func) \ 958#define SETUP_OPTIONAL_PORT_ATTRIBUTE(field, func) \
833 i->private_phy_attrs[count] = class_device_attr_##field; \ 959 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func)
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 960
840#define SETUP_PORT_ATTRIBUTE_WRONLY(field) \ 961#define SETUP_PORT_ATTRIBUTE_WRONLY(field) \
841 i->private_phy_attrs[count] = class_device_attr_##field; \ 962 SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, 1)
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 963
847#define SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(field, func) \ 964#define SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(field, func) \
848 i->private_phy_attrs[count] = class_device_attr_##field; \ 965 SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, i->f->func)
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 966
967#define SETUP_END_DEV_ATTRIBUTE(field) \
968 SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1)
855 969
856/** 970/**
857 * sas_attach_transport -- instantiate SAS transport template 971 * sas_attach_transport -- instantiate SAS transport template
@@ -885,6 +999,11 @@ sas_attach_transport(struct sas_function_template *ft)
885 i->rphy_attr_cont.ac.match = sas_rphy_match; 999 i->rphy_attr_cont.ac.match = sas_rphy_match;
886 transport_container_register(&i->rphy_attr_cont); 1000 transport_container_register(&i->rphy_attr_cont);
887 1001
1002 i->end_dev_attr_cont.ac.class = &sas_end_dev_class.class;
1003 i->end_dev_attr_cont.ac.attrs = &i->end_dev_attrs[0];
1004 i->end_dev_attr_cont.ac.match = sas_end_dev_match;
1005 transport_container_register(&i->end_dev_attr_cont);
1006
888 i->f = ft; 1007 i->f = ft;
889 1008
890 count = 0; 1009 count = 0;
@@ -923,6 +1042,12 @@ sas_attach_transport(struct sas_function_template *ft)
923 get_bay_identifier); 1042 get_bay_identifier);
924 i->rphy_attrs[count] = NULL; 1043 i->rphy_attrs[count] = NULL;
925 1044
1045 count = 0;
1046 SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning);
1047 SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout);
1048 SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout);
1049 i->end_dev_attrs[count] = NULL;
1050
926 return &i->t; 1051 return &i->t;
927} 1052}
928EXPORT_SYMBOL(sas_attach_transport); 1053EXPORT_SYMBOL(sas_attach_transport);
@@ -956,9 +1081,14 @@ static __init int sas_transport_init(void)
956 error = transport_class_register(&sas_rphy_class); 1081 error = transport_class_register(&sas_rphy_class);
957 if (error) 1082 if (error)
958 goto out_unregister_phy; 1083 goto out_unregister_phy;
1084 error = transport_class_register(&sas_end_dev_class);
1085 if (error)
1086 goto out_unregister_rphy;
959 1087
960 return 0; 1088 return 0;
961 1089
1090 out_unregister_rphy:
1091 transport_class_unregister(&sas_rphy_class);
962 out_unregister_phy: 1092 out_unregister_phy:
963 transport_class_unregister(&sas_phy_class); 1093 transport_class_unregister(&sas_phy_class);
964 out_unregister_transport: 1094 out_unregister_transport:
@@ -973,6 +1103,7 @@ static void __exit sas_transport_exit(void)
973 transport_class_unregister(&sas_host_class); 1103 transport_class_unregister(&sas_host_class);
974 transport_class_unregister(&sas_phy_class); 1104 transport_class_unregister(&sas_phy_class);
975 transport_class_unregister(&sas_rphy_class); 1105 transport_class_unregister(&sas_rphy_class);
1106 transport_class_unregister(&sas_end_dev_class);
976} 1107}
977 1108
978MODULE_AUTHOR("Christoph Hellwig"); 1109MODULE_AUTHOR("Christoph Hellwig");