[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>
This commit is contained in:
parent
f7c95ef02b
commit
50d5c60634
|
@ -853,6 +853,8 @@ int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
|||
*mpi_reply, Mpi2IOUnitPage1_t *config_page);
|
||||
int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz);
|
||||
int mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc,
|
||||
Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz);
|
||||
int mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2IOCPage8_t *config_page);
|
||||
int mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
|
|
|
@ -324,7 +324,9 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
|
|||
if (r != 0)
|
||||
goto out;
|
||||
if (mpi_request->Action ==
|
||||
MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT) {
|
||||
MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT ||
|
||||
mpi_request->Action ==
|
||||
MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
|
||||
ioc->base_add_sg_single(&mpi_request->PageBufferSGE,
|
||||
MPT2_CONFIG_COMMON_WRITE_SGLFLAGS | mem.sz,
|
||||
mem.page_dma);
|
||||
|
@ -882,7 +884,7 @@ mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
|||
}
|
||||
|
||||
/**
|
||||
* mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 0
|
||||
* mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 1
|
||||
* @ioc: per adapter object
|
||||
* @mpi_reply: reply mf payload returned from firmware
|
||||
* @config_page: contents of the config page
|
||||
|
@ -907,7 +909,7 @@ mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
|||
mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
|
||||
mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
|
||||
mpi_request.Header.PageNumber = 1;
|
||||
mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION;
|
||||
mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION;
|
||||
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
|
||||
r = _config_request(ioc, &mpi_request, mpi_reply,
|
||||
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
|
||||
|
@ -921,6 +923,49 @@ mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
|||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpt2sas_config_set_sas_iounit_pg1 - send sas iounit page 1
|
||||
* @ioc: per adapter object
|
||||
* @mpi_reply: reply mf payload returned from firmware
|
||||
* @config_page: contents of the config page
|
||||
* @sz: size of buffer passed in config_page
|
||||
* Context: sleep.
|
||||
*
|
||||
* Calling function should call config_get_number_hba_phys prior to
|
||||
* this function, so enough memory is allocated for config_page.
|
||||
*
|
||||
* Returns 0 for success, non-zero for failure.
|
||||
*/
|
||||
int
|
||||
mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz)
|
||||
{
|
||||
Mpi2ConfigRequest_t mpi_request;
|
||||
int r;
|
||||
|
||||
memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
|
||||
mpi_request.Function = MPI2_FUNCTION_CONFIG;
|
||||
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
|
||||
mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
|
||||
mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
|
||||
mpi_request.Header.PageNumber = 1;
|
||||
mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION;
|
||||
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
|
||||
r = _config_request(ioc, &mpi_request, mpi_reply,
|
||||
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
|
||||
_config_request(ioc, &mpi_request, mpi_reply,
|
||||
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
|
||||
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
|
||||
r = _config_request(ioc, &mpi_request, mpi_reply,
|
||||
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpt2sas_config_get_expander_pg0 - obtain expander page 0
|
||||
* @ioc: per adapter object
|
||||
|
|
|
@ -855,6 +855,17 @@ rphy_to_ioc(struct sas_rphy *rphy)
|
|||
return shost_priv(shost);
|
||||
}
|
||||
|
||||
static struct _sas_phy *
|
||||
_transport_find_local_phy(struct MPT2SAS_ADAPTER *ioc, struct sas_phy *phy)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ioc->sas_hba.num_phys; i++)
|
||||
if (ioc->sas_hba.phy[i].phy == phy)
|
||||
return(&ioc->sas_hba.phy[i]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* _transport_get_linkerrors -
|
||||
* @phy: The sas phy object
|
||||
|
@ -870,14 +881,8 @@ _transport_get_linkerrors(struct sas_phy *phy)
|
|||
struct _sas_phy *mpt2sas_phy;
|
||||
Mpi2ConfigReply_t mpi_reply;
|
||||
Mpi2SasPhyPage1_t phy_pg1;
|
||||
int i;
|
||||
|
||||
for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys &&
|
||||
!mpt2sas_phy; i++) {
|
||||
if (ioc->sas_hba.phy[i].phy != phy)
|
||||
continue;
|
||||
mpt2sas_phy = &ioc->sas_hba.phy[i];
|
||||
}
|
||||
mpt2sas_phy = _transport_find_local_phy(ioc, phy);
|
||||
|
||||
if (!mpt2sas_phy) /* this phy not on sas_host */
|
||||
return -EINVAL;
|
||||
|
@ -971,14 +976,8 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset)
|
|||
struct _sas_phy *mpt2sas_phy;
|
||||
Mpi2SasIoUnitControlReply_t mpi_reply;
|
||||
Mpi2SasIoUnitControlRequest_t mpi_request;
|
||||
int i;
|
||||
|
||||
for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys &&
|
||||
!mpt2sas_phy; i++) {
|
||||
if (ioc->sas_hba.phy[i].phy != phy)
|
||||
continue;
|
||||
mpt2sas_phy = &ioc->sas_hba.phy[i];
|
||||
}
|
||||
mpt2sas_phy = _transport_find_local_phy(ioc, phy);
|
||||
|
||||
if (!mpt2sas_phy) /* this phy not on sas_host */
|
||||
return -EINVAL;
|
||||
|
@ -1005,6 +1004,173 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* _transport_phy_enable - enable/disable phys
|
||||
* @phy: The sas phy object
|
||||
* @enable: enable phy when true
|
||||
*
|
||||
* Only support sas_host direct attached phys.
|
||||
* Returns 0 for success, non-zero for failure.
|
||||
*/
|
||||
static int
|
||||
_transport_phy_enable(struct sas_phy *phy, int enable)
|
||||
{
|
||||
struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
|
||||
struct _sas_phy *mpt2sas_phy;
|
||||
Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
|
||||
Mpi2ConfigReply_t mpi_reply;
|
||||
u16 ioc_status;
|
||||
u16 sz;
|
||||
int rc = 0;
|
||||
|
||||
mpt2sas_phy = _transport_find_local_phy(ioc, phy);
|
||||
|
||||
if (!mpt2sas_phy) /* this phy not on sas_host */
|
||||
return -EINVAL;
|
||||
|
||||
/* sas_iounit page 1 */
|
||||
sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
|
||||
sizeof(Mpi2SasIOUnit1PhyData_t));
|
||||
sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
|
||||
if (!sas_iounit_pg1) {
|
||||
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
|
||||
ioc->name, __FILE__, __LINE__, __func__);
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
|
||||
sas_iounit_pg1, sz))) {
|
||||
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
|
||||
ioc->name, __FILE__, __LINE__, __func__);
|
||||
rc = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
|
||||
MPI2_IOCSTATUS_MASK;
|
||||
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
|
||||
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
|
||||
ioc->name, __FILE__, __LINE__, __func__);
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
|
||||
&= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
|
||||
else
|
||||
sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
|
||||
|= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
|
||||
|
||||
mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz);
|
||||
|
||||
out:
|
||||
kfree(sas_iounit_pg1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* _transport_phy_speed - set phy min/max link rates
|
||||
* @phy: The sas phy object
|
||||
* @rates: rates defined in sas_phy_linkrates
|
||||
*
|
||||
* Only support sas_host direct attached phys.
|
||||
* Returns 0 for success, non-zero for failure.
|
||||
*/
|
||||
static int
|
||||
_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
|
||||
{
|
||||
struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
|
||||
struct _sas_phy *mpt2sas_phy;
|
||||
Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
|
||||
Mpi2SasPhyPage0_t phy_pg0;
|
||||
Mpi2ConfigReply_t mpi_reply;
|
||||
u16 ioc_status;
|
||||
u16 sz;
|
||||
int i;
|
||||
int rc = 0;
|
||||
|
||||
mpt2sas_phy = _transport_find_local_phy(ioc, phy);
|
||||
|
||||
if (!mpt2sas_phy) /* this phy not on sas_host */
|
||||
return -EINVAL;
|
||||
|
||||
if (!rates->minimum_linkrate)
|
||||
rates->minimum_linkrate = phy->minimum_linkrate;
|
||||
else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
|
||||
rates->minimum_linkrate = phy->minimum_linkrate_hw;
|
||||
|
||||
if (!rates->maximum_linkrate)
|
||||
rates->maximum_linkrate = phy->maximum_linkrate;
|
||||
else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
|
||||
rates->maximum_linkrate = phy->maximum_linkrate_hw;
|
||||
|
||||
/* sas_iounit page 1 */
|
||||
sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
|
||||
sizeof(Mpi2SasIOUnit1PhyData_t));
|
||||
sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
|
||||
if (!sas_iounit_pg1) {
|
||||
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
|
||||
ioc->name, __FILE__, __LINE__, __func__);
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
|
||||
sas_iounit_pg1, sz))) {
|
||||
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
|
||||
ioc->name, __FILE__, __LINE__, __func__);
|
||||
rc = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
|
||||
MPI2_IOCSTATUS_MASK;
|
||||
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
|
||||
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
|
||||
ioc->name, __FILE__, __LINE__, __func__);
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < ioc->sas_hba.num_phys; i++) {
|
||||
if (mpt2sas_phy->phy_id != i) {
|
||||
sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
|
||||
(ioc->sas_hba.phy[i].phy->minimum_linkrate +
|
||||
(ioc->sas_hba.phy[i].phy->maximum_linkrate << 4));
|
||||
} else {
|
||||
sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
|
||||
(rates->minimum_linkrate +
|
||||
(rates->maximum_linkrate << 4));
|
||||
}
|
||||
}
|
||||
|
||||
if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,
|
||||
sz)) {
|
||||
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
|
||||
ioc->name, __FILE__, __LINE__, __func__);
|
||||
rc = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* link reset */
|
||||
_transport_phy_reset(phy, 0);
|
||||
|
||||
/* read phy page 0, then update the rates in the sas transport phy */
|
||||
if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
|
||||
mpt2sas_phy->phy_id)) {
|
||||
phy->minimum_linkrate = _transport_convert_phy_link_rate(
|
||||
phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
|
||||
phy->maximum_linkrate = _transport_convert_phy_link_rate(
|
||||
phy_pg0.ProgrammedLinkRate >> 4);
|
||||
phy->negotiated_linkrate = _transport_convert_phy_link_rate(
|
||||
phy_pg0.NegotiatedLinkRate &
|
||||
MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(sas_iounit_pg1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* _transport_smp_handler - transport portal for smp passthru
|
||||
* @shost: shost object
|
||||
|
@ -1207,6 +1373,8 @@ struct sas_function_template mpt2sas_transport_functions = {
|
|||
.get_enclosure_identifier = _transport_get_enclosure_identifier,
|
||||
.get_bay_identifier = _transport_get_bay_identifier,
|
||||
.phy_reset = _transport_phy_reset,
|
||||
.phy_enable = _transport_phy_enable,
|
||||
.set_phy_speed = _transport_phy_speed,
|
||||
.smp_handler = _transport_smp_handler,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue