aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/pm8001
diff options
context:
space:
mode:
authorBenjamin Rood <benjaminjrood@gmail.com>2015-10-30 10:53:28 -0400
committerMartin K. Petersen <martin.petersen@oracle.com>2015-11-02 23:39:02 -0500
commitc5614df7ffa74d2fcb591eb4e9008ca38f0bc8c1 (patch)
tree50a3b2c6f0dcdd7920c0fc8e945d267d4363a5a9 /drivers/scsi/pm8001
parent10efa460fe23c4def83fb98be311502b5c5961fa (diff)
pm80xx: set PHY profiles for ATTO 12Gb SAS controllers
PHY profiles are not saved in NVRAM on ATTO 12Gb SAS controllers. Therefore, in order for the controller to function in a wide range of configurations, the PHY profiles must be statically set. This patch provides the necessary functionality to do so. Signed-off-by: Benjamin Rood <brood@attotech.com> Reviewed-by: Jack Wang <jinpu.wang@profitbricks.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/pm8001')
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c130
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h2
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c32
3 files changed, 164 insertions, 0 deletions
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 861416f12655..7ce7ea3d0161 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -732,6 +732,131 @@ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha)
732 return 0; 732 return 0;
733} 733}
734 734
735struct pm8001_mpi3_phy_pg_trx_config {
736 u32 LaneLosCfg;
737 u32 LanePgaCfg1;
738 u32 LanePisoCfg1;
739 u32 LanePisoCfg2;
740 u32 LanePisoCfg3;
741 u32 LanePisoCfg4;
742 u32 LanePisoCfg5;
743 u32 LanePisoCfg6;
744 u32 LaneBctCtrl;
745};
746
747/**
748 * pm8001_get_internal_phy_settings : Retrieves the internal PHY settings
749 * @pm8001_ha : our adapter
750 * @phycfg : PHY config page to populate
751 */
752static
753void pm8001_get_internal_phy_settings(struct pm8001_hba_info *pm8001_ha,
754 struct pm8001_mpi3_phy_pg_trx_config *phycfg)
755{
756 phycfg->LaneLosCfg = 0x00000132;
757 phycfg->LanePgaCfg1 = 0x00203949;
758 phycfg->LanePisoCfg1 = 0x000000FF;
759 phycfg->LanePisoCfg2 = 0xFF000001;
760 phycfg->LanePisoCfg3 = 0xE7011300;
761 phycfg->LanePisoCfg4 = 0x631C40C0;
762 phycfg->LanePisoCfg5 = 0xF8102036;
763 phycfg->LanePisoCfg6 = 0xF74A1000;
764 phycfg->LaneBctCtrl = 0x00FB33F8;
765}
766
767/**
768 * pm8001_get_external_phy_settings : Retrieves the external PHY settings
769 * @pm8001_ha : our adapter
770 * @phycfg : PHY config page to populate
771 */
772static
773void pm8001_get_external_phy_settings(struct pm8001_hba_info *pm8001_ha,
774 struct pm8001_mpi3_phy_pg_trx_config *phycfg)
775{
776 phycfg->LaneLosCfg = 0x00000132;
777 phycfg->LanePgaCfg1 = 0x00203949;
778 phycfg->LanePisoCfg1 = 0x000000FF;
779 phycfg->LanePisoCfg2 = 0xFF000001;
780 phycfg->LanePisoCfg3 = 0xE7011300;
781 phycfg->LanePisoCfg4 = 0x63349140;
782 phycfg->LanePisoCfg5 = 0xF8102036;
783 phycfg->LanePisoCfg6 = 0xF80D9300;
784 phycfg->LaneBctCtrl = 0x00FB33F8;
785}
786
787/**
788 * pm8001_get_phy_mask : Retrieves the mask that denotes if a PHY is int/ext
789 * @pm8001_ha : our adapter
790 * @phymask : The PHY mask
791 */
792static
793void pm8001_get_phy_mask(struct pm8001_hba_info *pm8001_ha, int *phymask)
794{
795 switch (pm8001_ha->pdev->subsystem_device) {
796 case 0x0070: /* H1280 - 8 external 0 internal */
797 case 0x0072: /* H12F0 - 16 external 0 internal */
798 *phymask = 0x0000;
799 break;
800
801 case 0x0071: /* H1208 - 0 external 8 internal */
802 case 0x0073: /* H120F - 0 external 16 internal */
803 *phymask = 0xFFFF;
804 break;
805
806 case 0x0080: /* H1244 - 4 external 4 internal */
807 *phymask = 0x00F0;
808 break;
809
810 case 0x0081: /* H1248 - 4 external 8 internal */
811 *phymask = 0x0FF0;
812 break;
813
814 case 0x0082: /* H1288 - 8 external 8 internal */
815 *phymask = 0xFF00;
816 break;
817
818 default:
819 PM8001_INIT_DBG(pm8001_ha,
820 pm8001_printk("Unknown subsystem device=0x%.04x",
821 pm8001_ha->pdev->subsystem_device));
822 }
823}
824
825/**
826 * pm8001_set_phy_settings_ven_117c_12Gb : Configure ATTO 12Gb PHY settings
827 * @pm8001_ha : our adapter
828 */
829static
830int pm8001_set_phy_settings_ven_117c_12G(struct pm8001_hba_info *pm8001_ha)
831{
832 struct pm8001_mpi3_phy_pg_trx_config phycfg_int;
833 struct pm8001_mpi3_phy_pg_trx_config phycfg_ext;
834 int phymask = 0;
835 int i = 0;
836
837 memset(&phycfg_int, 0, sizeof(phycfg_int));
838 memset(&phycfg_ext, 0, sizeof(phycfg_ext));
839
840 pm8001_get_internal_phy_settings(pm8001_ha, &phycfg_int);
841 pm8001_get_external_phy_settings(pm8001_ha, &phycfg_ext);
842 pm8001_get_phy_mask(pm8001_ha, &phymask);
843
844 for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
845 if (phymask & (1 << i)) {/* Internal PHY */
846 pm8001_set_phy_profile_single(pm8001_ha, i,
847 sizeof(phycfg_int) / sizeof(u32),
848 (u32 *)&phycfg_int);
849
850 } else { /* External PHY */
851 pm8001_set_phy_profile_single(pm8001_ha, i,
852 sizeof(phycfg_ext) / sizeof(u32),
853 (u32 *)&phycfg_ext);
854 }
855 }
856
857 return 0;
858}
859
735/** 860/**
736 * pm8001_configure_phy_settings : Configures PHY settings based on vendor ID. 861 * pm8001_configure_phy_settings : Configures PHY settings based on vendor ID.
737 * @pm8001_ha : our hba. 862 * @pm8001_ha : our hba.
@@ -740,6 +865,11 @@ static int pm8001_configure_phy_settings(struct pm8001_hba_info *pm8001_ha)
740{ 865{
741 switch (pm8001_ha->pdev->subsystem_vendor) { 866 switch (pm8001_ha->pdev->subsystem_vendor) {
742 case PCI_VENDOR_ID_ATTO: 867 case PCI_VENDOR_ID_ATTO:
868 if (pm8001_ha->pdev->device == 0x0042) /* 6Gb */
869 return 0;
870 else
871 return pm8001_set_phy_settings_ven_117c_12G(pm8001_ha);
872
743 case PCI_VENDOR_ID_ADAPTEC2: 873 case PCI_VENDOR_ID_ADAPTEC2:
744 case 0: 874 case 0:
745 return 0; 875 return 0;
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 9fa9705653ae..6628cc38316c 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -710,6 +710,8 @@ int pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha);
710int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); 710int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
711void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha, 711void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
712 u32 length, u8 *buf); 712 u32 length, u8 *buf);
713void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha,
714 u32 phy, u32 length, u32 *buf);
713int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); 715int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
714ssize_t pm80xx_get_fatal_dump(struct device *cdev, 716ssize_t pm80xx_get_fatal_dump(struct device *cdev,
715 struct device_attribute *attr, char *buf); 717 struct device_attribute *attr, char *buf);
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 9a389f1508de..29c548be6438 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -4576,6 +4576,38 @@ void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
4576 } 4576 }
4577 PM8001_INIT_DBG(pm8001_ha, pm8001_printk("phy settings completed\n")); 4577 PM8001_INIT_DBG(pm8001_ha, pm8001_printk("phy settings completed\n"));
4578} 4578}
4579
4580void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha,
4581 u32 phy, u32 length, u32 *buf)
4582{
4583 u32 tag, opc;
4584 int rc, i;
4585 struct set_phy_profile_req payload;
4586 struct inbound_queue_table *circularQ;
4587
4588 memset(&payload, 0, sizeof(payload));
4589
4590 rc = pm8001_tag_alloc(pm8001_ha, &tag);
4591 if (rc)
4592 PM8001_INIT_DBG(pm8001_ha, pm8001_printk("Invalid tag"));
4593
4594 circularQ = &pm8001_ha->inbnd_q_tbl[0];
4595 opc = OPC_INB_SET_PHY_PROFILE;
4596
4597 payload.tag = cpu_to_le32(tag);
4598 payload.ppc_phyid = (((SAS_PHY_ANALOG_SETTINGS_PAGE & 0xF) << 8)
4599 | (phy & 0xFF));
4600
4601 for (i = 0; i < length; i++)
4602 payload.reserved[i] = cpu_to_le32(*(buf + i));
4603
4604 rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
4605 if (rc)
4606 pm8001_tag_free(pm8001_ha, tag);
4607
4608 PM8001_INIT_DBG(pm8001_ha,
4609 pm8001_printk("PHY %d settings applied", phy));
4610}
4579const struct pm8001_dispatch pm8001_80xx_dispatch = { 4611const struct pm8001_dispatch pm8001_80xx_dispatch = {
4580 .name = "pmc80xx", 4612 .name = "pmc80xx",
4581 .chip_init = pm80xx_chip_init, 4613 .chip_init = pm80xx_chip_init,