Blob Blame History Raw
From: Xiaofei Tan <tanxiaofei@huawei.com>
Date: Thu, 18 Jan 2018 00:46:53 +0800
Subject: scsi: hisi_sas: directly attached disk LED feature for v2 hw
Git-commit: 6379c56070b9ee32ae2b3efa51e121242042e72d
Patch-mainline: v4.16-rc1
References: bsc#1083411

This patch implements LED feature of directly attached disk for v2 hw.
As libsas has provided an interface lldd_write_gpio() for this feature,
we just need realise the interface following SPGIO API.

We use an CPLD to finish the hardware part of this feature, and the base
address of CPLD should be configured through ACPI or DT tables.

Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Matthias Brugger <mbrugger@suse.com>
---
 drivers/scsi/hisi_sas/hisi_sas.h       |    3 ++
 drivers/scsi/hisi_sas/hisi_sas_main.c  |   20 ++++++++++++++++
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c |   39 +++++++++++++++++++++++++++++++++
 3 files changed, 62 insertions(+)

--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -245,6 +245,8 @@ struct hisi_sas_hw {
 				struct domain_device *device);
 	int (*soft_reset)(struct hisi_hba *hisi_hba);
 	u32 (*get_phys_state)(struct hisi_hba *hisi_hba);
+	int (*write_gpio)(struct hisi_hba *hisi_hba, u8 reg_type,
+				u8 reg_index, u8 reg_count, u8 *write_data);
 	int max_command_entries;
 	int complete_hdr_size;
 };
@@ -258,6 +260,7 @@ struct hisi_hba {
 	struct device *dev;
 
 	void __iomem *regs;
+	void __iomem *sgpio_regs;
 	struct regmap *ctrl;
 	u32 ctrl_reset_reg;
 	u32 ctrl_reset_sts_reg;
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1636,6 +1636,18 @@ static void hisi_sas_port_deformed(struc
 {
 }
 
+static int hisi_sas_write_gpio(struct sas_ha_struct *sha, u8 reg_type,
+			u8 reg_index, u8 reg_count, u8 *write_data)
+{
+	struct hisi_hba *hisi_hba = sha->lldd_ha;
+
+	if (!hisi_hba->hw->write_gpio)
+		return -EOPNOTSUPP;
+
+	return hisi_hba->hw->write_gpio(hisi_hba, reg_type,
+				reg_index, reg_count, write_data);
+}
+
 static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy)
 {
 	phy->phy_attached = 0;
@@ -1726,6 +1738,7 @@ static struct sas_domain_function_templa
 	.lldd_control_phy	= hisi_sas_control_phy,
 	.lldd_abort_task	= hisi_sas_abort_task,
 	.lldd_abort_task_set	= hisi_sas_abort_task_set,
+	.lldd_write_gpio = hisi_sas_write_gpio,
 	.lldd_clear_aca		= hisi_sas_clear_aca,
 	.lldd_I_T_nexus_reset	= hisi_sas_I_T_nexus_reset,
 	.lldd_lu_reset		= hisi_sas_lu_reset,
@@ -2057,6 +2070,13 @@ static struct Scsi_Host *hisi_sas_shost_
 	if (IS_ERR(hisi_hba->regs))
 		goto err_out;
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (res) {
+		hisi_hba->sgpio_regs = devm_ioremap_resource(dev, res);
+		if (IS_ERR(hisi_hba->sgpio_regs))
+			goto err_out;
+	}
+
 	if (hisi_sas_alloc(hisi_hba, shost)) {
 		hisi_sas_free(hisi_hba);
 		goto err_out;
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -3476,6 +3476,44 @@ static int soft_reset_v2_hw(struct hisi_
 	return 0;
 }
 
+static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type,
+			u8 reg_index, u8 reg_count, u8 *write_data)
+{
+	struct device *dev = hisi_hba->dev;
+	int phy_no, count;
+
+	if (!hisi_hba->sgpio_regs)
+		return -EOPNOTSUPP;
+
+	switch (reg_type) {
+	case SAS_GPIO_REG_TX:
+		count = reg_count * 4;
+		count = min(count, hisi_hba->n_phy);
+
+		for (phy_no = 0; phy_no < count; phy_no++) {
+			/*
+			 * GPIO_TX[n] register has the highest numbered drive
+			 * of the four in the first byte and the lowest
+			 * numbered drive in the fourth byte.
+			 * See SFF-8485 Rev. 0.7 Table 24.
+			 */
+			void __iomem  *reg_addr = hisi_hba->sgpio_regs +
+					reg_index * 4 + phy_no;
+			int data_idx = phy_no + 3 - (phy_no % 4) * 2;
+
+			writeb(write_data[data_idx], reg_addr);
+		}
+
+		break;
+	default:
+		dev_err(dev, "write gpio: unsupported or bad reg type %d\n",
+				reg_type);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static const struct hisi_sas_hw hisi_sas_v2_hw = {
 	.hw_init = hisi_sas_v2_init,
 	.setup_itct = setup_itct_v2_hw,
@@ -3503,6 +3541,7 @@ static const struct hisi_sas_hw hisi_sas
 	.complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr),
 	.soft_reset = soft_reset_v2_hw,
 	.get_phys_state = get_phys_state_v2_hw,
+	.write_gpio = write_gpio_v2_hw,
 };
 
 static int hisi_sas_v2_probe(struct platform_device *pdev)