Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1317089 > unrolled thread

[PATCH v2 00/23] HiSilicon SAS v2 hw support

Started byj00310691 <john.garry@huawei.com>
First post2016-01-25 18:20 +0100
Last post2016-01-25 18:30 +0100
Articles 9 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v2 00/23] HiSilicon SAS v2 hw support  j00310691 <john.garry@huawei.com> - 2016-01-25 18:20 +0100
    [PATCH v2 15/23] hisi_sas: add v2 SATA interrupt handler j00310691 <john.garry@huawei.com> - 2016-01-25 18:20 +0100
    [PATCH v2 13/23] hisi_sas: add v2 phy down handler j00310691 <john.garry@huawei.com> - 2016-01-25 18:20 +0100
    [PATCH v2 01/23] devicetree: bindings: hisi_sas: add v2 HW bindings j00310691 <john.garry@huawei.com> - 2016-01-25 18:20 +0100
      Re: [PATCH v2 01/23] devicetree: bindings: hisi_sas: add v2 HW  bindings Rob Herring <robh@kernel.org> - 2016-01-25 20:40 +0100
    [PATCH v2 17/23] hisi_sas: add v2 path to send ssp frame j00310691 <john.garry@huawei.com> - 2016-01-25 18:20 +0100
    [PATCH v2 21/23] hisi_sas: add v2 slot error handler j00310691 <john.garry@huawei.com> - 2016-01-25 18:20 +0100
    [PATCH v2 14/23] hisi_sas: add v2 channel interrupt handler j00310691 <john.garry@huawei.com> - 2016-01-25 18:20 +0100
    Re: [PATCH v2 00/23] HiSilicon SAS v2 hw support John Garry <john.garry@huawei.com> - 2016-01-25 18:30 +0100

#1317089 — [PATCH v2 00/23] HiSilicon SAS v2 hw support

Fromj00310691 <john.garry@huawei.com>
Date2016-01-25 18:20 +0100
Subject[PATCH v2 00/23] HiSilicon SAS v2 hw support
Message-ID<qUSOl-7cE-3@gated-at.bofh.it>
From: John Garry <john.garry@huawei.com>

This patchset introduces support for the HiSi SAS v2 hw.
The major difference between v1 and v2 hw is support
for SATA/STP.

Known limitation:
- We cannot connect a SATA disk through an expander
  which enables DMA setup auto-activate, as our controller
  does not support this feature. Directly connecting
  a SATA disk to the HBA is ok.

Differences to v1:
- Update dt bindings, specificially for am-max-transmissions
- some small SATA fixes
- minor formatting changes

John Garry (23):
  devicetree: bindings: hisi_sas: add v2 HW bindings
  hisi_sas: relocate DEV_IS_EXPANDER
  hisi_sas: set max commands as configurable
  hisi_sas: reduce max itct entries
  hisi_sas: add hisi_sas_err_record_v1
  hisi_sas: rename some fields in hisi_sas_itct
  hisi_sas: add bare v2 hw driver
  hisi_sas: add v2 register definitions
  hisi_sas: add v2 hw init
  hisi_sas: add init_id_frame_v2_hw()
  hisi_sas: add v2 phy init code
  hisi_sas: add v2 int init and phy up handler
  hisi_sas: add v2 phy down handler
  hisi_sas: add v2 channel interrupt handler
  hisi_sas: add v2 SATA interrupt handler
  hisi_sas: add v2 cq interrupt handler
  hisi_sas: add v2 path to send ssp frame
  hisi_sas: add v2 code to send smp command
  hisi_sas: add v2 code for itct setup and free
  hisi_sas: add v2 path to send ATA command
  hisi_sas: add v2 slot error handler
  hisi_sas: add v2 tmf functions
  hisi_sas: update driver version to 1.1

 .../devicetree/bindings/scsi/hisilicon-sas.txt     |   21 +-
 drivers/scsi/hisi_sas/Kconfig                      |    1 +
 drivers/scsi/hisi_sas/Makefile                     |    2 +-
 drivers/scsi/hisi_sas/hisi_sas.h                   |   39 +-
 drivers/scsi/hisi_sas/hisi_sas_main.c              |   36 +-
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c             |   20 +-
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c             | 2205 ++++++++++++++++++++
 7 files changed, 2278 insertions(+), 46 deletions(-)
 create mode 100644 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c

Reviewed-by: Hannes Reinecke <hare@suse.com>
-- 
1.9.1

[toc] | [next] | [standalone]


#1317090 — [PATCH v2 15/23] hisi_sas: add v2 SATA interrupt handler

Fromj00310691 <john.garry@huawei.com>
Date2016-01-25 18:20 +0100
Subject[PATCH v2 15/23] hisi_sas: add v2 SATA interrupt handler
Message-ID<qUSY5-7hD-69@gated-at.bofh.it>
In reply to#1317089
From: John Garry <john.garry@huawei.com>

Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 100 +++++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 5af2069..c4a887c 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -861,6 +861,86 @@ static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
+{
+	struct hisi_sas_phy *phy = p;
+	struct hisi_hba *hisi_hba = phy->hisi_hba;
+	struct asd_sas_phy *sas_phy = &phy->sas_phy;
+	struct device *dev = &hisi_hba->pdev->dev;
+	struct	hisi_sas_initial_fis *initial_fis;
+	struct dev_to_host_fis *fis;
+	u32 ent_tmp, ent_msk, ent_int, port_id, link_rate, hard_phy_linkrate;
+	irqreturn_t res = IRQ_HANDLED;
+	u8 attached_sas_addr[SAS_ADDR_SIZE] = {0};
+	int phy_no;
+
+	phy_no = sas_phy->id;
+	initial_fis = &hisi_hba->initial_fis[phy_no];
+	fis = &initial_fis->fis;
+
+	ent_msk = hisi_sas_read32(hisi_hba, ENT_INT_SRC_MSK1);
+	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, ent_msk | 1 << phy_no);
+
+	ent_int = hisi_sas_read32(hisi_hba, ENT_INT_SRC1);
+	ent_tmp = ent_int;
+	ent_int >>= ENT_INT_SRC1_D2H_FIS_CH1_OFF * (phy_no % 4);
+	if ((ent_int & ENT_INT_SRC1_D2H_FIS_CH0_MSK) == 0) {
+		dev_warn(dev, "sata int: phy%d did not receive FIS\n", phy_no);
+		hisi_sas_write32(hisi_hba, ENT_INT_SRC1, ent_tmp);
+		hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, ent_msk);
+		res = IRQ_NONE;
+		goto end;
+	}
+
+	if (unlikely(phy_no == 8)) {
+		u32 port_state = hisi_sas_read32(hisi_hba, PORT_STATE);
+
+		port_id = (port_state & PORT_STATE_PHY8_PORT_NUM_MSK) >>
+			  PORT_STATE_PHY8_PORT_NUM_OFF;
+		link_rate = (port_state & PORT_STATE_PHY8_CONN_RATE_MSK) >>
+			    PORT_STATE_PHY8_CONN_RATE_OFF;
+	} else {
+		port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
+		port_id = (port_id >> (4 * phy_no)) & 0xf;
+		link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
+		link_rate = (link_rate >> (phy_no * 4)) & 0xf;
+	}
+
+	if (port_id == 0xf) {
+		dev_err(dev, "sata int: phy%d invalid portid\n", phy_no);
+		res = IRQ_NONE;
+		goto end;
+	}
+
+	sas_phy->linkrate = link_rate;
+	hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no,
+						HARD_PHY_LINKRATE);
+	phy->maximum_linkrate = hard_phy_linkrate & 0xf;
+	phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf;
+
+	sas_phy->oob_mode = SATA_OOB_MODE;
+	/* Make up some unique SAS address */
+	attached_sas_addr[0] = 0x50;
+	attached_sas_addr[7] = phy_no;
+	memcpy(sas_phy->attached_sas_addr, attached_sas_addr, SAS_ADDR_SIZE);
+	memcpy(sas_phy->frame_rcvd, fis, sizeof(struct dev_to_host_fis));
+	dev_info(dev, "sata int phyup: phy%d link_rate=%d\n", phy_no, link_rate);
+	phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+	phy->port_id = port_id;
+	phy->phy_type |= PORT_TYPE_SATA;
+	phy->phy_attached = 1;
+	phy->identify.device_type = SAS_SATA_DEV;
+	phy->frame_rcvd_size = sizeof(struct dev_to_host_fis);
+	phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
+	queue_work(hisi_hba->wq, &phy->phyup_ws);
+
+end:
+	hisi_sas_write32(hisi_hba, ENT_INT_SRC1, ent_tmp);
+	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, ent_msk);
+
+	return res;
+}
+
 static irq_handler_t phy_interrupts[HISI_SAS_PHY_INT_NR] = {
 	int_phy_updown_v2_hw,
 	int_chnl_int_v2_hw,
@@ -900,6 +980,26 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
 		}
 	}
 
+	for (i = 0; i < hisi_hba->n_phy; i++) {
+		struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+		int idx = i + 72; /* First SATA interrupt is irq72 */
+
+		irq = irq_map[idx];
+		if (!irq) {
+			dev_err(dev, "irq init: fail map phy interrupt %d\n",
+				idx);
+			return -ENOENT;
+		}
+
+		rc = devm_request_irq(dev, irq, sata_int_v2_hw, 0,
+				      DRV_NAME " sata", phy);
+		if (rc) {
+			dev_err(dev, "irq init: could not request "
+				"sata interrupt %d, rc=%d\n",
+				irq, rc);
+			return -ENOENT;
+		}
+	}
 	return 0;
 }
 
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1317091 — [PATCH v2 13/23] hisi_sas: add v2 phy down handler

Fromj00310691 <john.garry@huawei.com>
Date2016-01-25 18:20 +0100
Subject[PATCH v2 13/23] hisi_sas: add v2 phy down handler
Message-ID<qUSY5-7hD-73@gated-at.bofh.it>
In reply to#1317089
From: John Garry <john.garry@huawei.com>

Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 49 ++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index a7b83bd..35ce7b6 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -628,6 +628,29 @@ static void sl_notify_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
 	hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
 }
 
+static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id)
+{
+	int i, bitmap = 0;
+	u32 phy_port_num_ma = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
+	u32 phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+
+	for (i = 0; i < (hisi_hba->n_phy < 9 ? hisi_hba->n_phy : 8); i++)
+		if (phy_state & 1 << i)
+			if (((phy_port_num_ma >> (i * 4)) & 0xf) == port_id)
+				bitmap |= 1 << i;
+
+	if (hisi_hba->n_phy == 9) {
+		u32 port_state = hisi_sas_read32(hisi_hba, PORT_STATE);
+
+		if (phy_state & 1 << 8)
+			if (((port_state & PORT_STATE_PHY8_PORT_NUM_MSK) >>
+			     PORT_STATE_PHY8_PORT_NUM_OFF) == port_id)
+				bitmap |= 1 << 9;
+	}
+
+	return bitmap;
+}
+
 static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 {
 	int i, res = 0;
@@ -705,6 +728,25 @@ end:
 	return res;
 }
 
+static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
+{
+	int res = 0;
+	u32 phy_cfg, phy_state;
+
+	hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1);
+
+	phy_cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+	phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+
+	hisi_sas_phy_down(hisi_hba, phy_no, (phy_state & 1 << phy_no) ? 1 : 0);
+
+	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_NOT_RDY_MSK);
+	hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 0);
+
+	return res;
+}
+
 static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
 {
 	struct hisi_hba *hisi_hba = p;
@@ -726,6 +768,12 @@ static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
 					goto end;
 				}
 
+			if (irq_value & CHL_INT0_NOT_RDY_MSK)
+				/* phy down */
+				if (phy_down_v2_hw(phy_no, hisi_hba)) {
+					res = IRQ_NONE;
+					goto end;
+				}
 		}
 		irq_msk >>= 1;
 		phy_no++;
@@ -796,6 +844,7 @@ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba)
 static const struct hisi_sas_hw hisi_sas_v2_hw = {
 	.hw_init = hisi_sas_v2_init,
 	.sl_notify = sl_notify_v2_hw,
+	.get_wideport_bitmap = get_wideport_bitmap_v2_hw,
 	.max_command_entries = HISI_SAS_COMMAND_ENTRIES_V2_HW,
 	.complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr),
 };
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1317092 — [PATCH v2 01/23] devicetree: bindings: hisi_sas: add v2 HW bindings

Fromj00310691 <john.garry@huawei.com>
Date2016-01-25 18:20 +0100
Subject[PATCH v2 01/23] devicetree: bindings: hisi_sas: add v2 HW bindings
Message-ID<qUSY5-7hD-71@gated-at.bofh.it>
In reply to#1317089
From: John Garry <john.garry@huawei.com>

Add the dt bindings for HiSi SAS controller v2 HW.

The main difference in the controller from dt perspective
is interrupts. The v2 controller does not have dedicated
fatal and broadcast interrupts - they are multiplexed on
the channel interrupt.

Each SAS v2 controller can issue upto 64 commands
(or connection requests) on the system bus without waiting
for a response - this is know as am-max-transmissions.
In hip06, sas controller #1 has a limitation that it has to
limit am-max-transmissions to 32 - this limitation is due
to chip system bus design. It is not anticipated that any
future chip incorporating v2 controller will have such a
limitation.

Signed-off-by: John Garry <john.garry@huawei.com>
---
 .../devicetree/bindings/scsi/hisilicon-sas.txt      | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt b/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt
index f67e761..f3da463 100644
--- a/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt
+++ b/Documentation/devicetree/bindings/scsi/hisilicon-sas.txt
@@ -5,6 +5,7 @@ The HiSilicon SAS controller supports SAS/SATA.
 Main node required properties:
   - compatible : value should be as follows:
 	(a) "hisilicon,hip05-sas-v1" for v1 hw in hip05 chipset
+	(b) "hisilicon,hip06-sas-v2" for v2 hw in hip06 chipset
   - sas-addr : array of 8 bytes for host SAS address
   - reg : Address and length of the SAS register
   - hisilicon,sas-syscon: phandle of syscon used for sas control
@@ -13,7 +14,7 @@ Main node required properties:
   - ctrl-clock-ena-reg : offset to controller clock enable register in ctrl reg
   - queue-count : number of delivery and completion queues in the controller
   - phy-count : number of phys accessible by the controller
-  - interrupts : Interrupts for phys, completion queues, and fatal
+  - interrupts : For v1 hw: Interrupts for phys, completion queues, and fatal
 		sources; the interrupts are ordered in 3 groups, as follows:
 			- Phy interrupts
 			- Completion queue interrupts
@@ -30,6 +31,24 @@ Main node required properties:
 		Fatal interrupts : the fatal interrupts are ordered as follows:
 			- ECC
 			- AXI bus
+		For v2 hw: Interrupts for phys, Sata, and completion queues;
+		the interrupts are ordered in 3 groups, as follows:
+			- Phy interrupts
+			- Sata interrupts
+			- Completion queue interrupts
+		Phy interrupts : Each controller has 2 phy interrupts:
+			- phy up/down
+			- channel interrupt
+		Sata interrupts : Each phy on the controller has 1 Sata
+			interrupt. The interrupts are ordered in increasing
+			order.
+		Completion queue interrupts : each completion queue has 1
+			interrupt source. The interrupts are ordered in
+			increasing order.
+
+Optional main node properties:
+ - hip06-sas-v2-quirk-amt : when set, indicates that the v2 controller has the
+			    "am-max-transmissions" limitation.
 
 Example:
 	sas0: sas@c1000000 {
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1317239 — Re: [PATCH v2 01/23] devicetree: bindings: hisi_sas: add v2 HW bindings

FromRob Herring <robh@kernel.org>
Date2016-01-25 20:40 +0100
SubjectRe: [PATCH v2 01/23] devicetree: bindings: hisi_sas: add v2 HW bindings
Message-ID<qUV9w-lx-21@gated-at.bofh.it>
In reply to#1317092
On Tue, Jan 26, 2016 at 01:21:50AM +0800, j00310691 wrote:
> From: John Garry <john.garry@huawei.com>
> 
> Add the dt bindings for HiSi SAS controller v2 HW.
> 
> The main difference in the controller from dt perspective
> is interrupts. The v2 controller does not have dedicated
> fatal and broadcast interrupts - they are multiplexed on
> the channel interrupt.
> 
> Each SAS v2 controller can issue upto 64 commands
> (or connection requests) on the system bus without waiting
> for a response - this is know as am-max-transmissions.
> In hip06, sas controller #1 has a limitation that it has to
> limit am-max-transmissions to 32 - this limitation is due
> to chip system bus design. It is not anticipated that any
> future chip incorporating v2 controller will have such a
> limitation.
> 
> Signed-off-by: John Garry <john.garry@huawei.com>
> ---
>  .../devicetree/bindings/scsi/hisilicon-sas.txt      | 21 ++++++++++++++++++++-
>  1 file changed, 20 insertions(+), 1 deletion(-)

Acked-by: Rob Herring <robh@kernel.org>

[toc] | [prev] | [next] | [standalone]


#1317093 — [PATCH v2 17/23] hisi_sas: add v2 path to send ssp frame

Fromj00310691 <john.garry@huawei.com>
Date2016-01-25 18:20 +0100
Subject[PATCH v2 17/23] hisi_sas: add v2 path to send ssp frame
Message-ID<qUSY5-7hD-77@gated-at.bofh.it>
In reply to#1317089
From: John Garry <john.garry@huawei.com>

Include code to prep ssp frame and deliver
to hardware.

Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 185 +++++++++++++++++++++++++++++++++
 1 file changed, 185 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 099bc13..ab6ea25 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -264,6 +264,11 @@ enum {
 
 #define HISI_SAS_COMMAND_ENTRIES_V2_HW 4096
 
+#define DIR_NO_DATA 0
+#define DIR_TO_INI 1
+#define DIR_TO_DEVICE 2
+#define DIR_RESERVED 3
+
 static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
 {
 	void __iomem *regs = hisi_hba->regs + off;
@@ -271,6 +276,13 @@ static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
 	return readl(regs);
 }
 
+static u32 hisi_sas_read32_relaxed(struct hisi_hba *hisi_hba, u32 off)
+{
+	void __iomem *regs = hisi_hba->regs + off;
+
+	return readl_relaxed(regs);
+}
+
 static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val)
 {
 	void __iomem *regs = hisi_hba->regs + off;
@@ -652,6 +664,176 @@ static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id)
 	return bitmap;
 }
 
+/**
+ * This function allocates across all queues to load balance.
+ * Slots are allocated from queues in a round-robin fashion.
+ *
+ * The callpath to this function and upto writing the write
+ * queue pointer should be safe from interruption.
+ */
+static int get_free_slot_v2_hw(struct hisi_hba *hisi_hba, int *q, int *s)
+{
+	struct device *dev = &hisi_hba->pdev->dev;
+	u32 r, w;
+	int queue = hisi_hba->queue;
+
+	while (1) {
+		w = hisi_sas_read32_relaxed(hisi_hba,
+					    DLVRY_Q_0_WR_PTR + (queue * 0x14));
+		r = hisi_sas_read32_relaxed(hisi_hba,
+					    DLVRY_Q_0_RD_PTR + (queue * 0x14));
+		if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
+			queue = (queue + 1) % hisi_hba->queue_count;
+			if (queue == hisi_hba->queue) {
+				dev_warn(dev, "could not find free slot\n");
+				return -EAGAIN;
+			}
+			continue;
+		}
+		break;
+	}
+	hisi_hba->queue = (queue + 1) % hisi_hba->queue_count;
+	*q = queue;
+	*s = w;
+	return 0;
+}
+
+static void start_delivery_v2_hw(struct hisi_hba *hisi_hba)
+{
+	int dlvry_queue = hisi_hba->slot_prep->dlvry_queue;
+	int dlvry_queue_slot = hisi_hba->slot_prep->dlvry_queue_slot;
+
+	hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
+			 ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS);
+}
+
+static int prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba,
+			      struct hisi_sas_slot *slot,
+			      struct hisi_sas_cmd_hdr *hdr,
+			      struct scatterlist *scatter,
+			      int n_elem)
+{
+	struct device *dev = &hisi_hba->pdev->dev;
+	struct scatterlist *sg;
+	int i;
+
+	if (n_elem > HISI_SAS_SGE_PAGE_CNT) {
+		dev_err(dev, "prd err: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT",
+			n_elem);
+		return -EINVAL;
+	}
+
+	slot->sge_page = dma_pool_alloc(hisi_hba->sge_page_pool, GFP_ATOMIC,
+					&slot->sge_page_dma);
+	if (!slot->sge_page)
+		return -ENOMEM;
+
+	for_each_sg(scatter, sg, n_elem, i) {
+		struct hisi_sas_sge *entry = &slot->sge_page->sge[i];
+
+		entry->addr = cpu_to_le64(sg_dma_address(sg));
+		entry->page_ctrl_0 = entry->page_ctrl_1 = 0;
+		entry->data_len = cpu_to_le32(sg_dma_len(sg));
+		entry->data_off = 0;
+	}
+
+	hdr->prd_table_addr = cpu_to_le64(slot->sge_page_dma);
+
+	hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
+
+	return 0;
+}
+
+static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
+			  struct hisi_sas_slot *slot, int is_tmf,
+			  struct hisi_sas_tmf_task *tmf)
+{
+	struct sas_task *task = slot->task;
+	struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+	struct domain_device *device = task->dev;
+	struct hisi_sas_device *sas_dev = device->lldd_dev;
+	struct hisi_sas_port *port = slot->port;
+	struct sas_ssp_task *ssp_task = &task->ssp_task;
+	struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
+	int has_data = 0, rc, priority = is_tmf;
+	u8 *buf_cmd;
+	u32 dw1 = 0, dw2 = 0;
+
+	hdr->dw0 = cpu_to_le32((1 << CMD_HDR_RESP_REPORT_OFF) |
+			       (2 << CMD_HDR_TLR_CTRL_OFF) |
+			       (port->id << CMD_HDR_PORT_OFF) |
+			       (priority << CMD_HDR_PRIORITY_OFF) |
+			       (1 << CMD_HDR_CMD_OFF)); /* ssp */
+
+	dw1 = 1 << CMD_HDR_VDTL_OFF;
+	if (is_tmf) {
+		dw1 |= 2 << CMD_HDR_FRAME_TYPE_OFF;
+		dw1 |= DIR_NO_DATA << CMD_HDR_DIR_OFF;
+	} else {
+		dw1 |= 1 << CMD_HDR_FRAME_TYPE_OFF;
+		switch (scsi_cmnd->sc_data_direction) {
+		case DMA_TO_DEVICE:
+			has_data = 1;
+			dw1 |= DIR_TO_DEVICE << CMD_HDR_DIR_OFF;
+			break;
+		case DMA_FROM_DEVICE:
+			has_data = 1;
+			dw1 |= DIR_TO_INI << CMD_HDR_DIR_OFF;
+			break;
+		default:
+			dw1 &= ~CMD_HDR_DIR_MSK;
+		}
+	}
+
+	/* map itct entry */
+	dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF;
+	hdr->dw1 = cpu_to_le32(dw1);
+
+	dw2 = (((sizeof(struct ssp_command_iu) + sizeof(struct ssp_frame_hdr)
+	      + 3) / 4) << CMD_HDR_CFL_OFF) |
+	      ((HISI_SAS_MAX_SSP_RESP_SZ / 4) << CMD_HDR_MRFL_OFF) |
+	      (2 << CMD_HDR_SG_MOD_OFF);
+	hdr->dw2 = cpu_to_le32(dw2);
+
+	hdr->transfer_tags = cpu_to_le32(slot->idx);
+
+	if (has_data) {
+		rc = prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter,
+					slot->n_elem);
+		if (rc)
+			return rc;
+	}
+
+	hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
+	hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
+	hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+	buf_cmd = slot->command_table + sizeof(struct ssp_frame_hdr);
+
+	memcpy(buf_cmd, &task->ssp_task.LUN, 8);
+	if (!is_tmf) {
+		buf_cmd[9] = task->ssp_task.task_attr |
+				(task->ssp_task.task_prio << 3);
+		memcpy(buf_cmd + 12, task->ssp_task.cmd->cmnd,
+				task->ssp_task.cmd->cmd_len);
+	} else {
+		buf_cmd[10] = tmf->tmf;
+		switch (tmf->tmf) {
+		case TMF_ABORT_TASK:
+		case TMF_QUERY_TASK:
+			buf_cmd[12] =
+				(tmf->tag_of_task_to_be_managed >> 8) & 0xff;
+			buf_cmd[13] =
+				tmf->tag_of_task_to_be_managed & 0xff;
+			break;
+		default:
+			break;
+		}
+	}
+
+	return 0;
+}
+
 static int
 slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot,
 		    int abort)
@@ -1213,6 +1395,9 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = {
 	.hw_init = hisi_sas_v2_init,
 	.sl_notify = sl_notify_v2_hw,
 	.get_wideport_bitmap = get_wideport_bitmap_v2_hw,
+	.prep_ssp = prep_ssp_v2_hw,
+	.get_free_slot = get_free_slot_v2_hw,
+	.start_delivery = start_delivery_v2_hw,
 	.slot_complete = slot_complete_v2_hw,
 	.max_command_entries = HISI_SAS_COMMAND_ENTRIES_V2_HW,
 	.complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr),
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1317094 — [PATCH v2 21/23] hisi_sas: add v2 slot error handler

Fromj00310691 <john.garry@huawei.com>
Date2016-01-25 18:20 +0100
Subject[PATCH v2 21/23] hisi_sas: add v2 slot error handler
Message-ID<qUSY5-7hD-79@gated-at.bofh.it>
In reply to#1317089
From: John Garry <john.garry@huawei.com>

Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 421 +++++++++++++++++++++++++++++++++
 1 file changed, 421 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index cea0b36..481aff9 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -256,12 +256,165 @@ struct hisi_sas_complete_v2_hdr {
 	__le32 dw3;
 };
 
+struct hisi_sas_err_record_v2 {
+	/* dw0 */
+	__le32 trans_tx_fail_type;
+
+	/* dw1 */
+	__le32 trans_rx_fail_type;
+
+	/* dw2 */
+	__le16 dma_tx_err_type;
+	__le16 sipc_rx_err_type;
+
+	/* dw3 */
+	__le32 dma_rx_err_type;
+};
+
 enum {
 	HISI_SAS_PHY_PHY_UPDOWN,
 	HISI_SAS_PHY_CHNL_INT,
 	HISI_SAS_PHY_INT_NR
 };
 
+enum {
+	TRANS_TX_FAIL_BASE = 0x0, /* dw0 */
+	TRANS_RX_FAIL_BASE = 0x100, /* dw1 */
+	DMA_TX_ERR_BASE = 0x200, /* dw2 bit 15-0 */
+	SIPC_RX_ERR_BASE = 0x300, /* dw2 bit 31-16*/
+	DMA_RX_ERR_BASE = 0x400, /* dw3 */
+
+	/* trans tx*/
+	TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS = TRANS_TX_FAIL_BASE, /* 0x0 */
+	TRANS_TX_ERR_PHY_NOT_ENABLE, /* 0x1 */
+	TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION, /* 0x2 */
+	TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION, /* 0x3 */
+	TRANS_TX_OPEN_CNX_ERR_BY_OTHER, /* 0x4 */
+	RESERVED0, /* 0x5 */
+	TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT, /* 0x6 */
+	TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY, /* 0x7 */
+	TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED, /* 0x8 */
+	TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED, /* 0x9 */
+	TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION, /* 0xa */
+	TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD, /* 0xb */
+	TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER, /* 0xc */
+	TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED, /* 0xd */
+	TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT, /* 0xe */
+	TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION, /* 0xf */
+	TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED, /* 0x10 */
+	TRANS_TX_ERR_FRAME_TXED, /* 0x11 */
+	TRANS_TX_ERR_WITH_BREAK_TIMEOUT, /* 0x12 */
+	TRANS_TX_ERR_WITH_BREAK_REQUEST, /* 0x13 */
+	TRANS_TX_ERR_WITH_BREAK_RECEVIED, /* 0x14 */
+	TRANS_TX_ERR_WITH_CLOSE_TIMEOUT, /* 0x15 */
+	TRANS_TX_ERR_WITH_CLOSE_NORMAL, /* 0x16 for ssp*/
+	TRANS_TX_ERR_WITH_CLOSE_PHYDISALE, /* 0x17 */
+	TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x18 */
+	TRANS_TX_ERR_WITH_CLOSE_COMINIT, /* 0x19 */
+	TRANS_TX_ERR_WITH_NAK_RECEVIED, /* 0x1a for ssp*/
+	TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT, /* 0x1b for ssp*/
+	/*IO_TX_ERR_WITH_R_ERR_RECEVIED, [> 0x1b for sata/stp<] */
+	TRANS_TX_ERR_WITH_CREDIT_TIMEOUT, /* 0x1c for ssp */
+	/*IO_RX_ERR_WITH_SATA_DEVICE_LOST 0x1c for sata/stp */
+	TRANS_TX_ERR_WITH_IPTT_CONFLICT, /* 0x1d for ssp/smp */
+	TRANS_TX_ERR_WITH_OPEN_BY_DES_OR_OTHERS, /* 0x1e */
+	/*IO_TX_ERR_WITH_SYNC_RXD, [> 0x1e <] for sata/stp */
+	TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT, /* 0x1f for sata/stp */
+
+	/* trans rx */
+	TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x100 */
+	TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR, /* 0x101 for sata/stp */
+	TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM, /* 0x102 for ssp/smp */
+	/*IO_ERR_WITH_RXFIS_8B10B_CODE_ERR, [> 0x102 <] for sata/stp */
+	TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR, /* 0x103 for sata/stp */
+	TRANS_RX_ERR_WITH_RXFIS_CRC_ERR, /* 0x104 for sata/stp */
+	TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN, /* 0x105 for smp */
+	/*IO_ERR_WITH_RXFIS_TX SYNCP, [> 0x105 <] for sata/stp */
+	TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP, /* 0x106 for sata/stp*/
+	TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN, /* 0x107 */
+	TRANS_RX_ERR_WITH_BREAK_TIMEOUT, /* 0x108 */
+	TRANS_RX_ERR_WITH_BREAK_REQUEST, /* 0x109 */
+	TRANS_RX_ERR_WITH_BREAK_RECEVIED, /* 0x10a */
+	RESERVED1, /* 0x10b */
+	TRANS_RX_ERR_WITH_CLOSE_NORMAL, /* 0x10c */
+	TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE, /* 0x10d */
+	TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x10e */
+	TRANS_RX_ERR_WITH_CLOSE_COMINIT, /* 0x10f */
+	TRANS_RX_ERR_WITH_DATA_LEN0, /* 0x110 for ssp/smp */
+	TRANS_RX_ERR_WITH_BAD_HASH, /* 0x111 for ssp */
+	/*IO_RX_ERR_WITH_FIS_TOO_SHORT, [> 0x111 <] for sata/stp */
+	TRANS_RX_XRDY_WLEN_ZERO_ERR, /* 0x112 for ssp*/
+	/*IO_RX_ERR_WITH_FIS_TOO_LONG, [> 0x112 <] for sata/stp */
+	TRANS_RX_SSP_FRM_LEN_ERR, /* 0x113 for ssp */
+	/*IO_RX_ERR_WITH_SATA_DEVICE_LOST, [> 0x113 <] for sata */
+	RESERVED2, /* 0x114 */
+	RESERVED3, /* 0x115 */
+	RESERVED4, /* 0x116 */
+	RESERVED5, /* 0x117 */
+	TRANS_RX_ERR_WITH_BAD_FRM_TYPE, /* 0x118 */
+	TRANS_RX_SMP_FRM_LEN_ERR, /* 0x119 */
+	TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x11a */
+	RESERVED6, /* 0x11b */
+	RESERVED7, /* 0x11c */
+	RESERVED8, /* 0x11d */
+	RESERVED9, /* 0x11e */
+	TRANS_RX_R_ERR, /* 0x11f */
+
+	/* dma tx */
+	DMA_TX_DIF_CRC_ERR = DMA_TX_ERR_BASE, /* 0x200 */
+	DMA_TX_DIF_APP_ERR, /* 0x201 */
+	DMA_TX_DIF_RPP_ERR, /* 0x202 */
+	DMA_TX_DATA_SGL_OVERFLOW, /* 0x203 */
+	DMA_TX_DIF_SGL_OVERFLOW, /* 0x204 */
+	DMA_TX_UNEXP_XFER_ERR, /* 0x205 */
+	DMA_TX_UNEXP_RETRANS_ERR, /* 0x206 */
+	DMA_TX_XFER_LEN_OVERFLOW, /* 0x207 */
+	DMA_TX_XFER_OFFSET_ERR, /* 0x208 */
+	DMA_TX_RAM_ECC_ERR, /* 0x209 */
+	DMA_TX_DIF_LEN_ALIGN_ERR, /* 0x20a */
+
+	/* sipc rx */
+	SIPC_RX_FIS_STATUS_ERR_BIT_VLD = SIPC_RX_ERR_BASE, /* 0x300 */
+	SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR, /* 0x301 */
+	SIPC_RX_FIS_STATUS_BSY_BIT_ERR, /* 0x302 */
+	SIPC_RX_WRSETUP_LEN_ODD_ERR, /* 0x303 */
+	SIPC_RX_WRSETUP_LEN_ZERO_ERR, /* 0x304 */
+	SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR, /* 0x305 */
+	SIPC_RX_NCQ_WRSETUP_OFFSET_ERR, /* 0x306 */
+	SIPC_RX_NCQ_WRSETUP_AUTO_ACTIVE_ERR, /* 0x307 */
+	SIPC_RX_SATA_UNEXP_FIS_ERR, /* 0x308 */
+	SIPC_RX_WRSETUP_ESTATUS_ERR, /* 0x309 */
+	SIPC_RX_DATA_UNDERFLOW_ERR, /* 0x30a */
+
+	/* dma rx */
+	DMA_RX_DIF_CRC_ERR = DMA_RX_ERR_BASE, /* 0x400 */
+	DMA_RX_DIF_APP_ERR, /* 0x401 */
+	DMA_RX_DIF_RPP_ERR, /* 0x402 */
+	DMA_RX_DATA_SGL_OVERFLOW, /* 0x403 */
+	DMA_RX_DIF_SGL_OVERFLOW, /* 0x404 */
+	DMA_RX_DATA_LEN_OVERFLOW, /* 0x405 */
+	DMA_RX_DATA_LEN_UNDERFLOW, /* 0x406 */
+	DMA_RX_DATA_OFFSET_ERR, /* 0x407 */
+	RESERVED10, /* 0x408 */
+	DMA_RX_SATA_FRAME_TYPE_ERR, /* 0x409 */
+	DMA_RX_RESP_BUF_OVERFLOW, /* 0x40a */
+	DMA_RX_UNEXP_RETRANS_RESP_ERR, /* 0x40b */
+	DMA_RX_UNEXP_NORM_RESP_ERR, /* 0x40c */
+	DMA_RX_UNEXP_RDFRAME_ERR, /* 0x40d */
+	DMA_RX_PIO_DATA_LEN_ERR, /* 0x40e */
+	DMA_RX_RDSETUP_STATUS_ERR, /* 0x40f */
+	DMA_RX_RDSETUP_STATUS_DRQ_ERR, /* 0x410 */
+	DMA_RX_RDSETUP_STATUS_BSY_ERR, /* 0x411 */
+	DMA_RX_RDSETUP_LEN_ODD_ERR, /* 0x412 */
+	DMA_RX_RDSETUP_LEN_ZERO_ERR, /* 0x413 */
+	DMA_RX_RDSETUP_LEN_OVER_ERR, /* 0x414 */
+	DMA_RX_RDSETUP_OFFSET_ERR, /* 0x415 */
+	DMA_RX_RDSETUP_ACTIVE_ERR, /* 0x416 */
+	DMA_RX_RDSETUP_ESTATUS_ERR, /* 0x417 */
+	DMA_RX_RAM_ECC_ERR, /* 0x418 */
+	DMA_RX_UNKNOWN_FRM_ERR, /* 0x419 */
+};
+
 #define HISI_SAS_COMMAND_ENTRIES_V2_HW 4096
 
 #define DIR_NO_DATA 0
@@ -1013,6 +1166,273 @@ static void sata_done_v2_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
 
 	ts->buf_valid_size = sizeof(*resp);
 }
+
+/* by default, task resp is complete */
+static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
+			   struct sas_task *task,
+			   struct hisi_sas_slot *slot)
+{
+	struct task_status_struct *ts = &task->task_status;
+	struct hisi_sas_err_record_v2 *err_record = slot->status_buffer;
+	u32 trans_tx_fail_type = cpu_to_le32(err_record->trans_tx_fail_type);
+	u32 trans_rx_fail_type = cpu_to_le32(err_record->trans_rx_fail_type);
+	u16 dma_tx_err_type = cpu_to_le16(err_record->dma_tx_err_type);
+	u16 sipc_rx_err_type = cpu_to_le16(err_record->sipc_rx_err_type);
+	u32 dma_rx_err_type = cpu_to_le32(err_record->dma_rx_err_type);
+	int error = -1;
+
+	if (dma_rx_err_type) {
+		error = ffs(dma_rx_err_type)
+			- 1 + DMA_RX_ERR_BASE;
+	} else if (sipc_rx_err_type) {
+		error = ffs(sipc_rx_err_type)
+			- 1 + SIPC_RX_ERR_BASE;
+	}  else if (dma_tx_err_type) {
+		error = ffs(dma_tx_err_type)
+			- 1 + DMA_TX_ERR_BASE;
+	} else if (trans_rx_fail_type) {
+		error = ffs(trans_rx_fail_type)
+			- 1 + TRANS_RX_FAIL_BASE;
+	} else if (trans_tx_fail_type) {
+		error = ffs(trans_tx_fail_type)
+			- 1 + TRANS_TX_FAIL_BASE;
+	}
+
+	switch (task->task_proto) {
+	case SAS_PROTOCOL_SSP:
+	{
+		switch (error) {
+		case TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION:
+		{
+			ts->stat = SAS_OPEN_REJECT;
+			ts->open_rej_reason = SAS_OREJ_NO_DEST;
+			break;
+		}
+		case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
+		{
+			ts->stat = SAS_OPEN_REJECT;
+			ts->open_rej_reason = SAS_OREJ_PATH_BLOCKED;
+			break;
+		}
+		case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED:
+		{
+			ts->stat = SAS_OPEN_REJECT;
+			ts->open_rej_reason = SAS_OREJ_EPROTO;
+			break;
+		}
+		case TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED:
+		{
+			ts->stat = SAS_OPEN_REJECT;
+			ts->open_rej_reason = SAS_OREJ_CONN_RATE;
+			break;
+		}
+		case TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION:
+		{
+			ts->stat = SAS_OPEN_REJECT;
+			ts->open_rej_reason = SAS_OREJ_BAD_DEST;
+			break;
+		}
+		case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
+		{
+			ts->stat = SAS_OPEN_REJECT;
+			ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+			break;
+		}
+		case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION:
+		{
+			ts->stat = SAS_OPEN_REJECT;
+			ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
+			break;
+		}
+		case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION:
+		{
+			ts->stat = SAS_OPEN_REJECT;
+			ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+			break;
+		}
+		case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER:
+		{
+			/* not sure */
+			ts->stat = SAS_DEV_NO_RESPONSE;
+			break;
+		}
+		case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE:
+		{
+			ts->stat = SAS_PHY_DOWN;
+			break;
+		}
+		case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
+		{
+			ts->stat = SAS_OPEN_TO;
+			break;
+		}
+		case DMA_RX_DATA_LEN_OVERFLOW:
+		{
+			ts->stat = SAS_DATA_OVERRUN;
+			ts->residual = 0;
+			break;
+		}
+		case DMA_RX_DATA_LEN_UNDERFLOW:
+		case SIPC_RX_DATA_UNDERFLOW_ERR:
+		{
+			ts->residual = trans_tx_fail_type;
+			ts->stat = SAS_DATA_UNDERRUN;
+			break;
+		}
+		case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS:
+		case TRANS_TX_ERR_PHY_NOT_ENABLE:
+		case TRANS_TX_OPEN_CNX_ERR_BY_OTHER:
+		case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT:
+		case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED:
+		case TRANS_TX_ERR_WITH_BREAK_TIMEOUT:
+		case TRANS_TX_ERR_WITH_BREAK_REQUEST:
+		case TRANS_TX_ERR_WITH_BREAK_RECEVIED:
+		case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT:
+		case TRANS_TX_ERR_WITH_CLOSE_NORMAL:
+		case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT:
+		case TRANS_TX_ERR_WITH_CLOSE_COMINIT:
+		case TRANS_TX_ERR_WITH_NAK_RECEVIED:
+		case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT:
+		case TRANS_TX_ERR_WITH_IPTT_CONFLICT:
+		case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT:
+		case TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR:
+		case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR:
+		case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM:
+		case TRANS_RX_ERR_WITH_BREAK_TIMEOUT:
+		case TRANS_RX_ERR_WITH_BREAK_REQUEST:
+		case TRANS_RX_ERR_WITH_BREAK_RECEVIED:
+		case TRANS_RX_ERR_WITH_CLOSE_NORMAL:
+		case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT:
+		case TRANS_RX_ERR_WITH_CLOSE_COMINIT:
+		case TRANS_RX_ERR_WITH_DATA_LEN0:
+		case TRANS_RX_ERR_WITH_BAD_HASH:
+		case TRANS_RX_XRDY_WLEN_ZERO_ERR:
+		case TRANS_RX_SSP_FRM_LEN_ERR:
+		case TRANS_RX_ERR_WITH_BAD_FRM_TYPE:
+		case DMA_TX_UNEXP_XFER_ERR:
+		case DMA_TX_UNEXP_RETRANS_ERR:
+		case DMA_TX_XFER_LEN_OVERFLOW:
+		case DMA_TX_XFER_OFFSET_ERR:
+		case DMA_RX_DATA_OFFSET_ERR:
+		case DMA_RX_UNEXP_NORM_RESP_ERR:
+		case DMA_RX_UNEXP_RDFRAME_ERR:
+		case DMA_RX_UNKNOWN_FRM_ERR:
+		{
+			ts->stat = SAS_OPEN_REJECT;
+			ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+			break;
+		}
+		default:
+			break;
+		}
+	}
+		break;
+	case SAS_PROTOCOL_SMP:
+		ts->stat = SAM_STAT_CHECK_CONDITION;
+		break;
+
+	case SAS_PROTOCOL_SATA:
+	case SAS_PROTOCOL_STP:
+	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+	{
+		switch (error) {
+		case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER:
+		case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
+		case TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION:
+		{
+			ts->resp = SAS_TASK_UNDELIVERED;
+			ts->stat = SAS_DEV_NO_RESPONSE;
+			break;
+		}
+		case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED:
+		case TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED:
+		case TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION:
+		case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
+		case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION:
+		case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION:
+		case TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY:
+		{
+			ts->stat = SAS_OPEN_REJECT;
+			break;
+		}
+		case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
+		{
+			ts->stat = SAS_OPEN_TO;
+			break;
+		}
+		case DMA_RX_DATA_LEN_OVERFLOW:
+		{
+			ts->stat = SAS_DATA_OVERRUN;
+			break;
+		}
+		case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS:
+		case TRANS_TX_ERR_PHY_NOT_ENABLE:
+		case TRANS_TX_OPEN_CNX_ERR_BY_OTHER:
+		case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT:
+		case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED:
+		case TRANS_TX_ERR_WITH_BREAK_TIMEOUT:
+		case TRANS_TX_ERR_WITH_BREAK_REQUEST:
+		case TRANS_TX_ERR_WITH_BREAK_RECEVIED:
+		case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT:
+		case TRANS_TX_ERR_WITH_CLOSE_NORMAL:
+		case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT:
+		case TRANS_TX_ERR_WITH_CLOSE_COMINIT:
+		case TRANS_TX_ERR_WITH_NAK_RECEVIED:
+		case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT:
+		case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT:
+		case TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT:
+		case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR:
+		case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM:
+		case TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR:
+		case TRANS_RX_ERR_WITH_RXFIS_CRC_ERR:
+		case TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN:
+		case TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP:
+		case TRANS_RX_ERR_WITH_CLOSE_NORMAL:
+		case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE:
+		case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT:
+		case TRANS_RX_ERR_WITH_CLOSE_COMINIT:
+		case TRANS_RX_ERR_WITH_DATA_LEN0:
+		case TRANS_RX_ERR_WITH_BAD_HASH:
+		case TRANS_RX_XRDY_WLEN_ZERO_ERR:
+		case TRANS_RX_SSP_FRM_LEN_ERR:
+		case SIPC_RX_FIS_STATUS_ERR_BIT_VLD:
+		case SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR:
+		case SIPC_RX_FIS_STATUS_BSY_BIT_ERR:
+		case SIPC_RX_WRSETUP_LEN_ODD_ERR:
+		case SIPC_RX_WRSETUP_LEN_ZERO_ERR:
+		case SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR:
+		case SIPC_RX_SATA_UNEXP_FIS_ERR:
+		case DMA_RX_SATA_FRAME_TYPE_ERR:
+		case DMA_RX_UNEXP_RDFRAME_ERR:
+		case DMA_RX_PIO_DATA_LEN_ERR:
+		case DMA_RX_RDSETUP_STATUS_ERR:
+		case DMA_RX_RDSETUP_STATUS_DRQ_ERR:
+		case DMA_RX_RDSETUP_STATUS_BSY_ERR:
+		case DMA_RX_RDSETUP_LEN_ODD_ERR:
+		case DMA_RX_RDSETUP_LEN_ZERO_ERR:
+		case DMA_RX_RDSETUP_LEN_OVER_ERR:
+		case DMA_RX_RDSETUP_OFFSET_ERR:
+		case DMA_RX_RDSETUP_ACTIVE_ERR:
+		case DMA_RX_RDSETUP_ESTATUS_ERR:
+		case DMA_RX_UNKNOWN_FRM_ERR:
+		{
+			ts->stat = SAS_OPEN_REJECT;
+			break;
+		}
+		default:
+		{
+			ts->stat = SAS_PROTO_RESPONSE;
+			break;
+		}
+		}
+		sata_done_v2_hw(hisi_hba, task, slot);
+	}
+		break;
+	default:
+		break;
+	}
+}
+
 static int
 slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot,
 		    int abort)
@@ -1055,6 +1475,7 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot,
 			__func__, slot->cmplt_queue_slot,
 			complete_hdr->dw0 & CMPLT_HDR_ERX_MSK);
 
+		slot_err_v2_hw(hisi_hba, task, slot);
 		goto out;
 	}
 
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1317095 — [PATCH v2 14/23] hisi_sas: add v2 channel interrupt handler

Fromj00310691 <john.garry@huawei.com>
Date2016-01-25 18:20 +0100
Subject[PATCH v2 14/23] hisi_sas: add v2 channel interrupt handler
Message-ID<qUSY5-7hD-75@gated-at.bofh.it>
In reply to#1317089
From: John Garry <john.garry@huawei.com>

This also includes broadcast handler. Unlike v1 hw,
broadcast does not have its own dedicated interrupt.

Signed-off-by: John Garry <john.garry@huawei.com>
---
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 79 ++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 35ce7b6..5af2069 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -258,6 +258,7 @@ struct hisi_sas_complete_v2_hdr {
 
 enum {
 	HISI_SAS_PHY_PHY_UPDOWN,
+	HISI_SAS_PHY_CHNL_INT,
 	HISI_SAS_PHY_INT_NR
 };
 
@@ -783,8 +784,86 @@ end:
 	return res;
 }
 
+static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
+{
+	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+	struct asd_sas_phy *sas_phy = &phy->sas_phy;
+	struct sas_ha_struct *sas_ha = &hisi_hba->sha;
+	unsigned long flags;
+
+	hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 1);
+
+	spin_lock_irqsave(&hisi_hba->lock, flags);
+	sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+	spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
+			     CHL_INT0_SL_RX_BCST_ACK_MSK);
+	hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 0);
+}
+
+static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
+{
+	struct hisi_hba *hisi_hba = p;
+	struct device *dev = &hisi_hba->pdev->dev;
+	u32 ent_msk, ent_tmp, irq_msk;
+	int phy_no = 0;
+
+	ent_msk = hisi_sas_read32(hisi_hba, ENT_INT_SRC_MSK3);
+	ent_tmp = ent_msk;
+	ent_msk |= ENT_INT_SRC_MSK3_ENT95_MSK_MSK;
+	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, ent_msk);
+
+	irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO) >>
+			HGC_INVLD_DQE_INFO_FB_CH3_OFF) & 0x1ff;
+
+	while (irq_msk) {
+		if (irq_msk & (1 << phy_no)) {
+			u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no,
+							     CHL_INT0);
+			u32 irq_value1 = hisi_sas_phy_read32(hisi_hba, phy_no,
+							     CHL_INT1);
+			u32 irq_value2 = hisi_sas_phy_read32(hisi_hba, phy_no,
+							     CHL_INT2);
+
+			if (irq_value1) {
+				if (irq_value1 & (CHL_INT1_DMAC_RX_ECC_ERR_MSK |
+						  CHL_INT1_DMAC_TX_ECC_ERR_MSK))
+					panic("%s: DMAC RX/TX ecc bad error! (0x%x)",
+						dev_name(dev), irq_value1);
+
+				hisi_sas_phy_write32(hisi_hba, phy_no,
+						     CHL_INT1, irq_value1);
+			}
+
+			if (irq_value2)
+				hisi_sas_phy_write32(hisi_hba, phy_no,
+						     CHL_INT2, irq_value2);
+
+
+			if (irq_value0) {
+				if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
+					phy_bcast_v2_hw(phy_no, hisi_hba);
+
+				hisi_sas_phy_write32(hisi_hba, phy_no,
+						CHL_INT0, irq_value0
+						& (~CHL_INT0_HOTPLUG_TOUT_MSK)
+						& (~CHL_INT0_SL_PHY_ENABLE_MSK)
+						& (~CHL_INT0_NOT_RDY_MSK));
+			}
+		}
+		irq_msk &= ~(1 << phy_no);
+		phy_no++;
+	}
+
+	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, ent_tmp);
+
+	return IRQ_HANDLED;
+}
+
 static irq_handler_t phy_interrupts[HISI_SAS_PHY_INT_NR] = {
 	int_phy_updown_v2_hw,
+	int_chnl_int_v2_hw,
 };
 
 /**
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1317096

FromJohn Garry <john.garry@huawei.com>
Date2016-01-25 18:30 +0100
Message-ID<qUT7H-7lX-1@gated-at.bofh.it>
In reply to#1317089
I'll re-send this patchset with my real name. I had my user name set to 
my company ID in my terminal.

I did send a trail patchset to myself, but my mail client autochanged 
the ID to my real name so I never detected.

John

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web