aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/mpt2sas/mpt2sas_transport.c
diff options
context:
space:
mode:
authorKashyap, Desai <kashyap.desai@lsi.com>2009-12-16 08:25:26 -0500
committerJames Bottomley <James.Bottomley@suse.de>2010-02-08 19:19:42 -0500
commit50d5c60634673a79f8d88564e10345b50fca7378 (patch)
tree837ce67b8dad98caddfc9469acecaca124ceea1d /drivers/scsi/mpt2sas/mpt2sas_transport.c
parentf7c95ef02b564d9984c0655c9659791b1dd5d7ad (diff)
[SCSI] mpt2sas: Added phy_enable and set_phy_speed sysfs callback support.
Added new callbacks phy_enable and set_phy_speed in the mpt2sas_transport_functions template. This will allow end user to enable/disable phys and change links rates using the SysFS interface. Current implementation only supports direct attached phys, but we could in the future add support for expander based phys. A new subroutine mpt2sas_config_set_sas_iounit_pg1 was added; this wrapper function used to send request to controller firmware to modify the phys and link rates. A new subroutine _transport_find_local_phy was added; a function for easly obtaining the local phy object for direct attached. Example to disable a phy echo 0 > /sys/class/phy3:0/enable Example to enable the same phy echo 1 > /sys/class/phy3:0/enable Example to change the link rate to 1.5 #echo "1.5 Gbit" > /sys/class/phy3:0/maximum_linkrate #cat /sys/class/phy3:0/negotiated_linkrate 1.5 Gbit Example to change the link rate to 3.0 #echo "3.0 Gbit" > /sys/class/phy3:0/maximum_linkrate #cat /sys/class/phy3:0/negotiated_linkrate 3.0 Gbit Example to change the link rate to 6.0 #echo "6.0 Gbit" > /sys/class/phy3:0/maximum_linkrate #cat /sys/class/phy3:0/negotiated_linkrate 6.0 Gbit Signed-off-by: Kashyap Desai <kashyap.desai@lsi.com> Reviewed-by: Eric Moore <eric.moore@lsi.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/mpt2sas/mpt2sas_transport.c')
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c196
1 files changed, 182 insertions, 14 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index 3a82872bad44..789f9ee7f001 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -855,6 +855,17 @@ rphy_to_ioc(struct sas_rphy *rphy)
855 return shost_priv(shost); 855 return shost_priv(shost);
856} 856}
857 857
858static struct _sas_phy *
859_transport_find_local_phy(struct MPT2SAS_ADAPTER *ioc, struct sas_phy *phy)
860{
861 int i;
862
863 for (i = 0; i < ioc->sas_hba.num_phys; i++)
864 if (ioc->sas_hba.phy[i].phy == phy)
865 return(&ioc->sas_hba.phy[i]);
866 return NULL;
867}
868
858/** 869/**
859 * _transport_get_linkerrors - 870 * _transport_get_linkerrors -
860 * @phy: The sas phy object 871 * @phy: The sas phy object
@@ -870,14 +881,8 @@ _transport_get_linkerrors(struct sas_phy *phy)
870 struct _sas_phy *mpt2sas_phy; 881 struct _sas_phy *mpt2sas_phy;
871 Mpi2ConfigReply_t mpi_reply; 882 Mpi2ConfigReply_t mpi_reply;
872 Mpi2SasPhyPage1_t phy_pg1; 883 Mpi2SasPhyPage1_t phy_pg1;
873 int i;
874 884
875 for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys && 885 mpt2sas_phy = _transport_find_local_phy(ioc, phy);
876 !mpt2sas_phy; i++) {
877 if (ioc->sas_hba.phy[i].phy != phy)
878 continue;
879 mpt2sas_phy = &ioc->sas_hba.phy[i];
880 }
881 886
882 if (!mpt2sas_phy) /* this phy not on sas_host */ 887 if (!mpt2sas_phy) /* this phy not on sas_host */
883 return -EINVAL; 888 return -EINVAL;
@@ -971,14 +976,8 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset)
971 struct _sas_phy *mpt2sas_phy; 976 struct _sas_phy *mpt2sas_phy;
972 Mpi2SasIoUnitControlReply_t mpi_reply; 977 Mpi2SasIoUnitControlReply_t mpi_reply;
973 Mpi2SasIoUnitControlRequest_t mpi_request; 978 Mpi2SasIoUnitControlRequest_t mpi_request;
974 int i;
975 979
976 for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys && 980 mpt2sas_phy = _transport_find_local_phy(ioc, phy);
977 !mpt2sas_phy; i++) {
978 if (ioc->sas_hba.phy[i].phy != phy)
979 continue;
980 mpt2sas_phy = &ioc->sas_hba.phy[i];
981 }
982 981
983 if (!mpt2sas_phy) /* this phy not on sas_host */ 982 if (!mpt2sas_phy) /* this phy not on sas_host */
984 return -EINVAL; 983 return -EINVAL;
@@ -1006,6 +1005,173 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset)
1006} 1005}
1007 1006
1008/** 1007/**
1008 * _transport_phy_enable - enable/disable phys
1009 * @phy: The sas phy object
1010 * @enable: enable phy when true
1011 *
1012 * Only support sas_host direct attached phys.
1013 * Returns 0 for success, non-zero for failure.
1014 */
1015static int
1016_transport_phy_enable(struct sas_phy *phy, int enable)
1017{
1018 struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
1019 struct _sas_phy *mpt2sas_phy;
1020 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
1021 Mpi2ConfigReply_t mpi_reply;
1022 u16 ioc_status;
1023 u16 sz;
1024 int rc = 0;
1025
1026 mpt2sas_phy = _transport_find_local_phy(ioc, phy);
1027
1028 if (!mpt2sas_phy) /* this phy not on sas_host */
1029 return -EINVAL;
1030
1031 /* sas_iounit page 1 */
1032 sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
1033 sizeof(Mpi2SasIOUnit1PhyData_t));
1034 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
1035 if (!sas_iounit_pg1) {
1036 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1037 ioc->name, __FILE__, __LINE__, __func__);
1038 rc = -ENOMEM;
1039 goto out;
1040 }
1041 if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
1042 sas_iounit_pg1, sz))) {
1043 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1044 ioc->name, __FILE__, __LINE__, __func__);
1045 rc = -ENXIO;
1046 goto out;
1047 }
1048 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1049 MPI2_IOCSTATUS_MASK;
1050 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1051 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1052 ioc->name, __FILE__, __LINE__, __func__);
1053 rc = -EIO;
1054 goto out;
1055 }
1056
1057 if (enable)
1058 sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
1059 &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
1060 else
1061 sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
1062 |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
1063
1064 mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz);
1065
1066 out:
1067 kfree(sas_iounit_pg1);
1068 return rc;
1069}
1070
1071/**
1072 * _transport_phy_speed - set phy min/max link rates
1073 * @phy: The sas phy object
1074 * @rates: rates defined in sas_phy_linkrates
1075 *
1076 * Only support sas_host direct attached phys.
1077 * Returns 0 for success, non-zero for failure.
1078 */
1079static int
1080_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
1081{
1082 struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
1083 struct _sas_phy *mpt2sas_phy;
1084 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
1085 Mpi2SasPhyPage0_t phy_pg0;
1086 Mpi2ConfigReply_t mpi_reply;
1087 u16 ioc_status;
1088 u16 sz;
1089 int i;
1090 int rc = 0;
1091
1092 mpt2sas_phy = _transport_find_local_phy(ioc, phy);
1093
1094 if (!mpt2sas_phy) /* this phy not on sas_host */
1095 return -EINVAL;
1096
1097 if (!rates->minimum_linkrate)
1098 rates->minimum_linkrate = phy->minimum_linkrate;
1099 else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
1100 rates->minimum_linkrate = phy->minimum_linkrate_hw;
1101
1102 if (!rates->maximum_linkrate)
1103 rates->maximum_linkrate = phy->maximum_linkrate;
1104 else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
1105 rates->maximum_linkrate = phy->maximum_linkrate_hw;
1106
1107 /* sas_iounit page 1 */
1108 sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
1109 sizeof(Mpi2SasIOUnit1PhyData_t));
1110 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
1111 if (!sas_iounit_pg1) {
1112 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1113 ioc->name, __FILE__, __LINE__, __func__);
1114 rc = -ENOMEM;
1115 goto out;
1116 }
1117 if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
1118 sas_iounit_pg1, sz))) {
1119 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1120 ioc->name, __FILE__, __LINE__, __func__);
1121 rc = -ENXIO;
1122 goto out;
1123 }
1124 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1125 MPI2_IOCSTATUS_MASK;
1126 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1127 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1128 ioc->name, __FILE__, __LINE__, __func__);
1129 rc = -EIO;
1130 goto out;
1131 }
1132
1133 for (i = 0; i < ioc->sas_hba.num_phys; i++) {
1134 if (mpt2sas_phy->phy_id != i) {
1135 sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
1136 (ioc->sas_hba.phy[i].phy->minimum_linkrate +
1137 (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4));
1138 } else {
1139 sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
1140 (rates->minimum_linkrate +
1141 (rates->maximum_linkrate << 4));
1142 }
1143 }
1144
1145 if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,
1146 sz)) {
1147 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1148 ioc->name, __FILE__, __LINE__, __func__);
1149 rc = -ENXIO;
1150 goto out;
1151 }
1152
1153 /* link reset */
1154 _transport_phy_reset(phy, 0);
1155
1156 /* read phy page 0, then update the rates in the sas transport phy */
1157 if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
1158 mpt2sas_phy->phy_id)) {
1159 phy->minimum_linkrate = _transport_convert_phy_link_rate(
1160 phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
1161 phy->maximum_linkrate = _transport_convert_phy_link_rate(
1162 phy_pg0.ProgrammedLinkRate >> 4);
1163 phy->negotiated_linkrate = _transport_convert_phy_link_rate(
1164 phy_pg0.NegotiatedLinkRate &
1165 MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
1166 }
1167
1168 out:
1169 kfree(sas_iounit_pg1);
1170 return rc;
1171}
1172
1173
1174/**
1009 * _transport_smp_handler - transport portal for smp passthru 1175 * _transport_smp_handler - transport portal for smp passthru
1010 * @shost: shost object 1176 * @shost: shost object
1011 * @rphy: sas transport rphy object 1177 * @rphy: sas transport rphy object
@@ -1207,6 +1373,8 @@ struct sas_function_template mpt2sas_transport_functions = {
1207 .get_enclosure_identifier = _transport_get_enclosure_identifier, 1373 .get_enclosure_identifier = _transport_get_enclosure_identifier,
1208 .get_bay_identifier = _transport_get_bay_identifier, 1374 .get_bay_identifier = _transport_get_bay_identifier,
1209 .phy_reset = _transport_phy_reset, 1375 .phy_reset = _transport_phy_reset,
1376 .phy_enable = _transport_phy_enable,
1377 .set_phy_speed = _transport_phy_speed,
1210 .smp_handler = _transport_smp_handler, 1378 .smp_handler = _transport_smp_handler,
1211}; 1379};
1212 1380