xref: /openbmc/linux/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
23417ba8aSJohn Garry /*
33417ba8aSJohn Garry  * Copyright (c) 2016 Linaro Ltd.
43417ba8aSJohn Garry  * Copyright (c) 2016 Hisilicon Limited.
53417ba8aSJohn Garry  */
63417ba8aSJohn Garry 
73417ba8aSJohn Garry #include "hisi_sas.h"
83417ba8aSJohn Garry #define DRV_NAME "hisi_sas_v2_hw"
93417ba8aSJohn Garry 
1045c901b8SJohn Garry /* global registers need init*/
1145c901b8SJohn Garry #define DLVRY_QUEUE_ENABLE		0x0
1245c901b8SJohn Garry #define IOST_BASE_ADDR_LO		0x8
1345c901b8SJohn Garry #define IOST_BASE_ADDR_HI		0xc
1445c901b8SJohn Garry #define ITCT_BASE_ADDR_LO		0x10
1545c901b8SJohn Garry #define ITCT_BASE_ADDR_HI		0x14
1645c901b8SJohn Garry #define IO_BROKEN_MSG_ADDR_LO		0x18
1745c901b8SJohn Garry #define IO_BROKEN_MSG_ADDR_HI		0x1c
1845c901b8SJohn Garry #define PHY_CONTEXT			0x20
1945c901b8SJohn Garry #define PHY_STATE			0x24
2045c901b8SJohn Garry #define PHY_PORT_NUM_MA			0x28
2145c901b8SJohn Garry #define PORT_STATE			0x2c
2245c901b8SJohn Garry #define PORT_STATE_PHY8_PORT_NUM_OFF	16
2345c901b8SJohn Garry #define PORT_STATE_PHY8_PORT_NUM_MSK	(0xf << PORT_STATE_PHY8_PORT_NUM_OFF)
2445c901b8SJohn Garry #define PORT_STATE_PHY8_CONN_RATE_OFF	20
2545c901b8SJohn Garry #define PORT_STATE_PHY8_CONN_RATE_MSK	(0xf << PORT_STATE_PHY8_CONN_RATE_OFF)
2645c901b8SJohn Garry #define PHY_CONN_RATE			0x30
2745c901b8SJohn Garry #define HGC_TRANS_TASK_CNT_LIMIT	0x38
2845c901b8SJohn Garry #define AXI_AHB_CLK_CFG			0x3c
2945c901b8SJohn Garry #define ITCT_CLR			0x44
3045c901b8SJohn Garry #define ITCT_CLR_EN_OFF			16
3145c901b8SJohn Garry #define ITCT_CLR_EN_MSK			(0x1 << ITCT_CLR_EN_OFF)
3245c901b8SJohn Garry #define ITCT_DEV_OFF			0
3345c901b8SJohn Garry #define ITCT_DEV_MSK			(0x7ff << ITCT_DEV_OFF)
3445c901b8SJohn Garry #define AXI_USER1			0x48
3545c901b8SJohn Garry #define AXI_USER2			0x4c
3645c901b8SJohn Garry #define IO_SATA_BROKEN_MSG_ADDR_LO	0x58
3745c901b8SJohn Garry #define IO_SATA_BROKEN_MSG_ADDR_HI	0x5c
3845c901b8SJohn Garry #define SATA_INITI_D2H_STORE_ADDR_LO	0x60
3945c901b8SJohn Garry #define SATA_INITI_D2H_STORE_ADDR_HI	0x64
4045c901b8SJohn Garry #define HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL	0x84
4145c901b8SJohn Garry #define HGC_SAS_TXFAIL_RETRY_CTRL	0x88
4245c901b8SJohn Garry #define HGC_GET_ITV_TIME		0x90
4345c901b8SJohn Garry #define DEVICE_MSG_WORK_MODE		0x94
4445c901b8SJohn Garry #define OPENA_WT_CONTI_TIME		0x9c
4545c901b8SJohn Garry #define I_T_NEXUS_LOSS_TIME		0xa0
4645c901b8SJohn Garry #define MAX_CON_TIME_LIMIT_TIME		0xa4
4745c901b8SJohn Garry #define BUS_INACTIVE_LIMIT_TIME		0xa8
4845c901b8SJohn Garry #define REJECT_TO_OPEN_LIMIT_TIME	0xac
4945c901b8SJohn Garry #define CFG_AGING_TIME			0xbc
5045c901b8SJohn Garry #define HGC_DFX_CFG2			0xc0
5145c901b8SJohn Garry #define HGC_IOMB_PROC1_STATUS	0x104
5245c901b8SJohn Garry #define CFG_1US_TIMER_TRSH		0xcc
53d3b688d3SXiang Chen #define HGC_LM_DFX_STATUS2		0x128
54d3b688d3SXiang Chen #define HGC_LM_DFX_STATUS2_IOSTLIST_OFF		0
55d3b688d3SXiang Chen #define HGC_LM_DFX_STATUS2_IOSTLIST_MSK	(0xfff << \
56d3b688d3SXiang Chen 					 HGC_LM_DFX_STATUS2_IOSTLIST_OFF)
57d3b688d3SXiang Chen #define HGC_LM_DFX_STATUS2_ITCTLIST_OFF		12
58d3b688d3SXiang Chen #define HGC_LM_DFX_STATUS2_ITCTLIST_MSK	(0x7ff << \
59d3b688d3SXiang Chen 					 HGC_LM_DFX_STATUS2_ITCTLIST_OFF)
60d3b688d3SXiang Chen #define HGC_CQE_ECC_ADDR		0x13c
61d3b688d3SXiang Chen #define HGC_CQE_ECC_1B_ADDR_OFF	0
62ce41b41eSDan Carpenter #define HGC_CQE_ECC_1B_ADDR_MSK	(0x3f << HGC_CQE_ECC_1B_ADDR_OFF)
63d3b688d3SXiang Chen #define HGC_CQE_ECC_MB_ADDR_OFF	8
64ce41b41eSDan Carpenter #define HGC_CQE_ECC_MB_ADDR_MSK (0x3f << HGC_CQE_ECC_MB_ADDR_OFF)
65d3b688d3SXiang Chen #define HGC_IOST_ECC_ADDR		0x140
66d3b688d3SXiang Chen #define HGC_IOST_ECC_1B_ADDR_OFF	0
67ce41b41eSDan Carpenter #define HGC_IOST_ECC_1B_ADDR_MSK	(0x3ff << HGC_IOST_ECC_1B_ADDR_OFF)
68d3b688d3SXiang Chen #define HGC_IOST_ECC_MB_ADDR_OFF	16
69ce41b41eSDan Carpenter #define HGC_IOST_ECC_MB_ADDR_MSK	(0x3ff << HGC_IOST_ECC_MB_ADDR_OFF)
70d3b688d3SXiang Chen #define HGC_DQE_ECC_ADDR		0x144
71d3b688d3SXiang Chen #define HGC_DQE_ECC_1B_ADDR_OFF	0
72ce41b41eSDan Carpenter #define HGC_DQE_ECC_1B_ADDR_MSK	(0xfff << HGC_DQE_ECC_1B_ADDR_OFF)
73d3b688d3SXiang Chen #define HGC_DQE_ECC_MB_ADDR_OFF	16
74ce41b41eSDan Carpenter #define HGC_DQE_ECC_MB_ADDR_MSK (0xfff << HGC_DQE_ECC_MB_ADDR_OFF)
7545c901b8SJohn Garry #define HGC_INVLD_DQE_INFO		0x148
7645c901b8SJohn Garry #define HGC_INVLD_DQE_INFO_FB_CH0_OFF	9
7745c901b8SJohn Garry #define HGC_INVLD_DQE_INFO_FB_CH0_MSK	(0x1 << HGC_INVLD_DQE_INFO_FB_CH0_OFF)
7845c901b8SJohn Garry #define HGC_INVLD_DQE_INFO_FB_CH3_OFF	18
79d3b688d3SXiang Chen #define HGC_ITCT_ECC_ADDR		0x150
80d3b688d3SXiang Chen #define HGC_ITCT_ECC_1B_ADDR_OFF		0
81d3b688d3SXiang Chen #define HGC_ITCT_ECC_1B_ADDR_MSK		(0x3ff << \
82d3b688d3SXiang Chen 						 HGC_ITCT_ECC_1B_ADDR_OFF)
83d3b688d3SXiang Chen #define HGC_ITCT_ECC_MB_ADDR_OFF		16
84d3b688d3SXiang Chen #define HGC_ITCT_ECC_MB_ADDR_MSK		(0x3ff << \
85d3b688d3SXiang Chen 						 HGC_ITCT_ECC_MB_ADDR_OFF)
86d3b688d3SXiang Chen #define HGC_AXI_FIFO_ERR_INFO	0x154
87d3b688d3SXiang Chen #define AXI_ERR_INFO_OFF		0
88d3b688d3SXiang Chen #define AXI_ERR_INFO_MSK		(0xff << AXI_ERR_INFO_OFF)
89d3b688d3SXiang Chen #define FIFO_ERR_INFO_OFF		8
90d3b688d3SXiang Chen #define FIFO_ERR_INFO_MSK		(0xff << FIFO_ERR_INFO_OFF)
9145c901b8SJohn Garry #define INT_COAL_EN			0x19c
9245c901b8SJohn Garry #define OQ_INT_COAL_TIME		0x1a0
9345c901b8SJohn Garry #define OQ_INT_COAL_CNT			0x1a4
9445c901b8SJohn Garry #define ENT_INT_COAL_TIME		0x1a8
9545c901b8SJohn Garry #define ENT_INT_COAL_CNT		0x1ac
9645c901b8SJohn Garry #define OQ_INT_SRC			0x1b0
9745c901b8SJohn Garry #define OQ_INT_SRC_MSK			0x1b4
9845c901b8SJohn Garry #define ENT_INT_SRC1			0x1b8
9945c901b8SJohn Garry #define ENT_INT_SRC1_D2H_FIS_CH0_OFF	0
10045c901b8SJohn Garry #define ENT_INT_SRC1_D2H_FIS_CH0_MSK	(0x1 << ENT_INT_SRC1_D2H_FIS_CH0_OFF)
10145c901b8SJohn Garry #define ENT_INT_SRC1_D2H_FIS_CH1_OFF	8
10245c901b8SJohn Garry #define ENT_INT_SRC1_D2H_FIS_CH1_MSK	(0x1 << ENT_INT_SRC1_D2H_FIS_CH1_OFF)
10345c901b8SJohn Garry #define ENT_INT_SRC2			0x1bc
10445c901b8SJohn Garry #define ENT_INT_SRC3			0x1c0
105d3b688d3SXiang Chen #define ENT_INT_SRC3_WP_DEPTH_OFF		8
106d3b688d3SXiang Chen #define ENT_INT_SRC3_IPTT_SLOT_NOMATCH_OFF	9
107d3b688d3SXiang Chen #define ENT_INT_SRC3_RP_DEPTH_OFF		10
108d3b688d3SXiang Chen #define ENT_INT_SRC3_AXI_OFF			11
109d3b688d3SXiang Chen #define ENT_INT_SRC3_FIFO_OFF			12
110d3b688d3SXiang Chen #define ENT_INT_SRC3_LM_OFF				14
11145c901b8SJohn Garry #define ENT_INT_SRC3_ITC_INT_OFF	15
11245c901b8SJohn Garry #define ENT_INT_SRC3_ITC_INT_MSK	(0x1 << ENT_INT_SRC3_ITC_INT_OFF)
113d3b688d3SXiang Chen #define ENT_INT_SRC3_ABT_OFF		16
11445c901b8SJohn Garry #define ENT_INT_SRC_MSK1		0x1c4
11545c901b8SJohn Garry #define ENT_INT_SRC_MSK2		0x1c8
11645c901b8SJohn Garry #define ENT_INT_SRC_MSK3		0x1cc
11745c901b8SJohn Garry #define ENT_INT_SRC_MSK3_ENT95_MSK_OFF	31
11845c901b8SJohn Garry #define ENT_INT_SRC_MSK3_ENT95_MSK_MSK	(0x1 << ENT_INT_SRC_MSK3_ENT95_MSK_OFF)
119d3b688d3SXiang Chen #define SAS_ECC_INTR			0x1e8
120d3b688d3SXiang Chen #define SAS_ECC_INTR_DQE_ECC_1B_OFF		0
121d3b688d3SXiang Chen #define SAS_ECC_INTR_DQE_ECC_MB_OFF		1
122d3b688d3SXiang Chen #define SAS_ECC_INTR_IOST_ECC_1B_OFF	2
123d3b688d3SXiang Chen #define SAS_ECC_INTR_IOST_ECC_MB_OFF	3
124d3b688d3SXiang Chen #define SAS_ECC_INTR_ITCT_ECC_MB_OFF	4
125d3b688d3SXiang Chen #define SAS_ECC_INTR_ITCT_ECC_1B_OFF	5
126d3b688d3SXiang Chen #define SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF	6
127d3b688d3SXiang Chen #define SAS_ECC_INTR_IOSTLIST_ECC_1B_OFF	7
128d3b688d3SXiang Chen #define SAS_ECC_INTR_ITCTLIST_ECC_1B_OFF	8
129d3b688d3SXiang Chen #define SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF	9
130d3b688d3SXiang Chen #define SAS_ECC_INTR_CQE_ECC_1B_OFF		10
131d3b688d3SXiang Chen #define SAS_ECC_INTR_CQE_ECC_MB_OFF		11
132d3b688d3SXiang Chen #define SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF	12
133d3b688d3SXiang Chen #define SAS_ECC_INTR_NCQ_MEM0_ECC_1B_OFF	13
134d3b688d3SXiang Chen #define SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF	14
135d3b688d3SXiang Chen #define SAS_ECC_INTR_NCQ_MEM1_ECC_1B_OFF	15
136d3b688d3SXiang Chen #define SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF	16
137d3b688d3SXiang Chen #define SAS_ECC_INTR_NCQ_MEM2_ECC_1B_OFF	17
138d3b688d3SXiang Chen #define SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF	18
139d3b688d3SXiang Chen #define SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF	19
14045c901b8SJohn Garry #define SAS_ECC_INTR_MSK		0x1ec
14145c901b8SJohn Garry #define HGC_ERR_STAT_EN			0x238
142a865ae14SXiaofei Tan #define CQE_SEND_CNT			0x248
14345c901b8SJohn Garry #define DLVRY_Q_0_BASE_ADDR_LO		0x260
14445c901b8SJohn Garry #define DLVRY_Q_0_BASE_ADDR_HI		0x264
14545c901b8SJohn Garry #define DLVRY_Q_0_DEPTH			0x268
14645c901b8SJohn Garry #define DLVRY_Q_0_WR_PTR		0x26c
14745c901b8SJohn Garry #define DLVRY_Q_0_RD_PTR		0x270
14845c901b8SJohn Garry #define HYPER_STREAM_ID_EN_CFG		0xc80
14945c901b8SJohn Garry #define OQ0_INT_SRC_MSK			0xc90
15045c901b8SJohn Garry #define COMPL_Q_0_BASE_ADDR_LO		0x4e0
15145c901b8SJohn Garry #define COMPL_Q_0_BASE_ADDR_HI		0x4e4
15245c901b8SJohn Garry #define COMPL_Q_0_DEPTH			0x4e8
15345c901b8SJohn Garry #define COMPL_Q_0_WR_PTR		0x4ec
15445c901b8SJohn Garry #define COMPL_Q_0_RD_PTR		0x4f0
155d3b688d3SXiang Chen #define HGC_RXM_DFX_STATUS14	0xae8
156d3b688d3SXiang Chen #define HGC_RXM_DFX_STATUS14_MEM0_OFF		0
157d3b688d3SXiang Chen #define HGC_RXM_DFX_STATUS14_MEM0_MSK		(0x1ff << \
158d3b688d3SXiang Chen 						 HGC_RXM_DFX_STATUS14_MEM0_OFF)
159d3b688d3SXiang Chen #define HGC_RXM_DFX_STATUS14_MEM1_OFF		9
160d3b688d3SXiang Chen #define HGC_RXM_DFX_STATUS14_MEM1_MSK		(0x1ff << \
161d3b688d3SXiang Chen 						 HGC_RXM_DFX_STATUS14_MEM1_OFF)
162d3b688d3SXiang Chen #define HGC_RXM_DFX_STATUS14_MEM2_OFF		18
163d3b688d3SXiang Chen #define HGC_RXM_DFX_STATUS14_MEM2_MSK		(0x1ff << \
164d3b688d3SXiang Chen 						 HGC_RXM_DFX_STATUS14_MEM2_OFF)
165d3b688d3SXiang Chen #define HGC_RXM_DFX_STATUS15	0xaec
166d3b688d3SXiang Chen #define HGC_RXM_DFX_STATUS15_MEM3_OFF		0
167d3b688d3SXiang Chen #define HGC_RXM_DFX_STATUS15_MEM3_MSK		(0x1ff << \
168d3b688d3SXiang Chen 						 HGC_RXM_DFX_STATUS15_MEM3_OFF)
16945c901b8SJohn Garry /* phy registers need init */
17045c901b8SJohn Garry #define PORT_BASE			(0x2000)
17145c901b8SJohn Garry 
17245c901b8SJohn Garry #define PHY_CFG				(PORT_BASE + 0x0)
17345c901b8SJohn Garry #define HARD_PHY_LINKRATE		(PORT_BASE + 0x4)
17445c901b8SJohn Garry #define PHY_CFG_ENA_OFF			0
17545c901b8SJohn Garry #define PHY_CFG_ENA_MSK			(0x1 << PHY_CFG_ENA_OFF)
17645c901b8SJohn Garry #define PHY_CFG_DC_OPT_OFF		2
17745c901b8SJohn Garry #define PHY_CFG_DC_OPT_MSK		(0x1 << PHY_CFG_DC_OPT_OFF)
17845c901b8SJohn Garry #define PROG_PHY_LINK_RATE		(PORT_BASE + 0x8)
17945c901b8SJohn Garry #define PROG_PHY_LINK_RATE_MAX_OFF	0
18045c901b8SJohn Garry #define PROG_PHY_LINK_RATE_MAX_MSK	(0xff << PROG_PHY_LINK_RATE_MAX_OFF)
18145c901b8SJohn Garry #define PHY_CTRL			(PORT_BASE + 0x14)
18245c901b8SJohn Garry #define PHY_CTRL_RESET_OFF		0
18345c901b8SJohn Garry #define PHY_CTRL_RESET_MSK		(0x1 << PHY_CTRL_RESET_OFF)
18445c901b8SJohn Garry #define SAS_PHY_CTRL			(PORT_BASE + 0x20)
18545c901b8SJohn Garry #define SL_CFG				(PORT_BASE + 0x84)
18645c901b8SJohn Garry #define PHY_PCN				(PORT_BASE + 0x44)
18745c901b8SJohn Garry #define SL_TOUT_CFG			(PORT_BASE + 0x8c)
18845c901b8SJohn Garry #define SL_CONTROL			(PORT_BASE + 0x94)
18945c901b8SJohn Garry #define SL_CONTROL_NOTIFY_EN_OFF	0
19045c901b8SJohn Garry #define SL_CONTROL_NOTIFY_EN_MSK	(0x1 << SL_CONTROL_NOTIFY_EN_OFF)
1919c81e2cfSJohn Garry #define SL_CONTROL_CTA_OFF		17
1929c81e2cfSJohn Garry #define SL_CONTROL_CTA_MSK		(0x1 << SL_CONTROL_CTA_OFF)
19385080a25SXiang Chen #define RX_PRIMS_STATUS			(PORT_BASE + 0x98)
19485080a25SXiang Chen #define RX_BCAST_CHG_OFF		1
19585080a25SXiang Chen #define RX_BCAST_CHG_MSK		(0x1 << RX_BCAST_CHG_OFF)
19645c901b8SJohn Garry #define TX_ID_DWORD0			(PORT_BASE + 0x9c)
19745c901b8SJohn Garry #define TX_ID_DWORD1			(PORT_BASE + 0xa0)
19845c901b8SJohn Garry #define TX_ID_DWORD2			(PORT_BASE + 0xa4)
19945c901b8SJohn Garry #define TX_ID_DWORD3			(PORT_BASE + 0xa8)
20045c901b8SJohn Garry #define TX_ID_DWORD4			(PORT_BASE + 0xaC)
20145c901b8SJohn Garry #define TX_ID_DWORD5			(PORT_BASE + 0xb0)
20245c901b8SJohn Garry #define TX_ID_DWORD6			(PORT_BASE + 0xb4)
2039c81e2cfSJohn Garry #define TXID_AUTO			(PORT_BASE + 0xb8)
2049c81e2cfSJohn Garry #define TXID_AUTO_CT3_OFF		1
2059c81e2cfSJohn Garry #define TXID_AUTO_CT3_MSK		(0x1 << TXID_AUTO_CT3_OFF)
206819cbf18SXiaofei Tan #define TXID_AUTO_CTB_OFF		11
207819cbf18SXiaofei Tan #define TXID_AUTO_CTB_MSK		(0x1 << TXID_AUTO_CTB_OFF)
2080edef7e4SXiang Chen #define TX_HARDRST_OFF			2
2090edef7e4SXiang Chen #define TX_HARDRST_MSK			(0x1 << TX_HARDRST_OFF)
21045c901b8SJohn Garry #define RX_IDAF_DWORD0			(PORT_BASE + 0xc4)
21145c901b8SJohn Garry #define RX_IDAF_DWORD1			(PORT_BASE + 0xc8)
21245c901b8SJohn Garry #define RX_IDAF_DWORD2			(PORT_BASE + 0xcc)
21345c901b8SJohn Garry #define RX_IDAF_DWORD3			(PORT_BASE + 0xd0)
21445c901b8SJohn Garry #define RX_IDAF_DWORD4			(PORT_BASE + 0xd4)
21545c901b8SJohn Garry #define RX_IDAF_DWORD5			(PORT_BASE + 0xd8)
21645c901b8SJohn Garry #define RX_IDAF_DWORD6			(PORT_BASE + 0xdc)
21745c901b8SJohn Garry #define RXOP_CHECK_CFG_H		(PORT_BASE + 0xfc)
218f2f89c32SXiang Chen #define CON_CONTROL			(PORT_BASE + 0x118)
219c7b9d369SXiaofei Tan #define CON_CONTROL_CFG_OPEN_ACC_STP_OFF	0
220c7b9d369SXiaofei Tan #define CON_CONTROL_CFG_OPEN_ACC_STP_MSK	\
221c7b9d369SXiaofei Tan 		(0x01 << CON_CONTROL_CFG_OPEN_ACC_STP_OFF)
22245c901b8SJohn Garry #define DONE_RECEIVED_TIME		(PORT_BASE + 0x11c)
22345c901b8SJohn Garry #define CHL_INT0			(PORT_BASE + 0x1b4)
22445c901b8SJohn Garry #define CHL_INT0_HOTPLUG_TOUT_OFF	0
22545c901b8SJohn Garry #define CHL_INT0_HOTPLUG_TOUT_MSK	(0x1 << CHL_INT0_HOTPLUG_TOUT_OFF)
22645c901b8SJohn Garry #define CHL_INT0_SL_RX_BCST_ACK_OFF	1
22745c901b8SJohn Garry #define CHL_INT0_SL_RX_BCST_ACK_MSK	(0x1 << CHL_INT0_SL_RX_BCST_ACK_OFF)
22845c901b8SJohn Garry #define CHL_INT0_SL_PHY_ENABLE_OFF	2
22945c901b8SJohn Garry #define CHL_INT0_SL_PHY_ENABLE_MSK	(0x1 << CHL_INT0_SL_PHY_ENABLE_OFF)
23045c901b8SJohn Garry #define CHL_INT0_NOT_RDY_OFF		4
23145c901b8SJohn Garry #define CHL_INT0_NOT_RDY_MSK		(0x1 << CHL_INT0_NOT_RDY_OFF)
23245c901b8SJohn Garry #define CHL_INT0_PHY_RDY_OFF		5
23345c901b8SJohn Garry #define CHL_INT0_PHY_RDY_MSK		(0x1 << CHL_INT0_PHY_RDY_OFF)
23445c901b8SJohn Garry #define CHL_INT1			(PORT_BASE + 0x1b8)
23545c901b8SJohn Garry #define CHL_INT1_DMAC_TX_ECC_ERR_OFF	15
23645c901b8SJohn Garry #define CHL_INT1_DMAC_TX_ECC_ERR_MSK	(0x1 << CHL_INT1_DMAC_TX_ECC_ERR_OFF)
23745c901b8SJohn Garry #define CHL_INT1_DMAC_RX_ECC_ERR_OFF	17
23845c901b8SJohn Garry #define CHL_INT1_DMAC_RX_ECC_ERR_MSK	(0x1 << CHL_INT1_DMAC_RX_ECC_ERR_OFF)
23972f7fc30SXiaofei Tan #define CHL_INT1_DMAC_TX_AXI_WR_ERR_OFF	19
24072f7fc30SXiaofei Tan #define CHL_INT1_DMAC_TX_AXI_RD_ERR_OFF	20
24172f7fc30SXiaofei Tan #define CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF	21
24272f7fc30SXiaofei Tan #define CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF	22
24345c901b8SJohn Garry #define CHL_INT2			(PORT_BASE + 0x1bc)
244057c3d1fSXiaofei Tan #define CHL_INT2_SL_IDAF_TOUT_CONF_OFF	0
24545c901b8SJohn Garry #define CHL_INT0_MSK			(PORT_BASE + 0x1c0)
24645c901b8SJohn Garry #define CHL_INT1_MSK			(PORT_BASE + 0x1c4)
24745c901b8SJohn Garry #define CHL_INT2_MSK			(PORT_BASE + 0x1c8)
24845c901b8SJohn Garry #define CHL_INT_COAL_EN			(PORT_BASE + 0x1d0)
249819cbf18SXiaofei Tan #define DMA_TX_DFX0				(PORT_BASE + 0x200)
250c7b9d369SXiaofei Tan #define DMA_TX_DFX1				(PORT_BASE + 0x204)
251c7b9d369SXiaofei Tan #define DMA_TX_DFX1_IPTT_OFF		0
252c7b9d369SXiaofei Tan #define DMA_TX_DFX1_IPTT_MSK		(0xffff << DMA_TX_DFX1_IPTT_OFF)
253819cbf18SXiaofei Tan #define DMA_TX_FIFO_DFX0		(PORT_BASE + 0x240)
254819cbf18SXiaofei Tan #define PORT_DFX0				(PORT_BASE + 0x258)
255819cbf18SXiaofei Tan #define LINK_DFX2					(PORT_BASE + 0X264)
256819cbf18SXiaofei Tan #define LINK_DFX2_RCVR_HOLD_STS_OFF	9
257819cbf18SXiaofei Tan #define LINK_DFX2_RCVR_HOLD_STS_MSK	(0x1 << LINK_DFX2_RCVR_HOLD_STS_OFF)
258819cbf18SXiaofei Tan #define LINK_DFX2_SEND_HOLD_STS_OFF	10
259819cbf18SXiaofei Tan #define LINK_DFX2_SEND_HOLD_STS_MSK	(0x1 << LINK_DFX2_SEND_HOLD_STS_OFF)
260c52108c6SXiaofei Tan #define SAS_ERR_CNT4_REG		(PORT_BASE + 0x290)
261c52108c6SXiaofei Tan #define SAS_ERR_CNT6_REG		(PORT_BASE + 0x298)
26245c901b8SJohn Garry #define PHY_CTRL_RDY_MSK		(PORT_BASE + 0x2b0)
26345c901b8SJohn Garry #define PHYCTRL_NOT_RDY_MSK		(PORT_BASE + 0x2b4)
26445c901b8SJohn Garry #define PHYCTRL_DWS_RESET_MSK		(PORT_BASE + 0x2b8)
26545c901b8SJohn Garry #define PHYCTRL_PHY_ENA_MSK		(PORT_BASE + 0x2bc)
26645c901b8SJohn Garry #define SL_RX_BCAST_CHK_MSK		(PORT_BASE + 0x2c0)
26745c901b8SJohn Garry #define PHYCTRL_OOB_RESTART_MSK		(PORT_BASE + 0x2c4)
26845c901b8SJohn Garry #define DMA_TX_STATUS			(PORT_BASE + 0x2d0)
26945c901b8SJohn Garry #define DMA_TX_STATUS_BUSY_OFF		0
27045c901b8SJohn Garry #define DMA_TX_STATUS_BUSY_MSK		(0x1 << DMA_TX_STATUS_BUSY_OFF)
27145c901b8SJohn Garry #define DMA_RX_STATUS			(PORT_BASE + 0x2e8)
27245c901b8SJohn Garry #define DMA_RX_STATUS_BUSY_OFF		0
27345c901b8SJohn Garry #define DMA_RX_STATUS_BUSY_MSK		(0x1 << DMA_RX_STATUS_BUSY_OFF)
27445c901b8SJohn Garry 
27545c901b8SJohn Garry #define AXI_CFG				(0x5100)
27645c901b8SJohn Garry #define AM_CFG_MAX_TRANS		(0x5010)
27745c901b8SJohn Garry #define AM_CFG_SINGLE_PORT_MAX_TRANS	(0x5014)
27845c901b8SJohn Garry 
27906ec0fb9SXiang Chen #define AXI_MASTER_CFG_BASE		(0x5000)
28006ec0fb9SXiang Chen #define AM_CTRL_GLOBAL			(0x0)
28106ec0fb9SXiang Chen #define AM_CURR_TRANS_RETURN	(0x150)
28206ec0fb9SXiang Chen 
28345c901b8SJohn Garry /* HW dma structures */
28445c901b8SJohn Garry /* Delivery queue header */
28545c901b8SJohn Garry /* dw0 */
286a3e665d9SJohn Garry #define CMD_HDR_ABORT_FLAG_OFF		0
287a3e665d9SJohn Garry #define CMD_HDR_ABORT_FLAG_MSK		(0x3 << CMD_HDR_ABORT_FLAG_OFF)
288a3e665d9SJohn Garry #define CMD_HDR_ABORT_DEVICE_TYPE_OFF	2
289a3e665d9SJohn Garry #define CMD_HDR_ABORT_DEVICE_TYPE_MSK	(0x1 << CMD_HDR_ABORT_DEVICE_TYPE_OFF)
29045c901b8SJohn Garry #define CMD_HDR_RESP_REPORT_OFF		5
29145c901b8SJohn Garry #define CMD_HDR_RESP_REPORT_MSK		(0x1 << CMD_HDR_RESP_REPORT_OFF)
29245c901b8SJohn Garry #define CMD_HDR_TLR_CTRL_OFF		6
29345c901b8SJohn Garry #define CMD_HDR_TLR_CTRL_MSK		(0x3 << CMD_HDR_TLR_CTRL_OFF)
294b09fcd09SXiaofei Tan #define CMD_HDR_PHY_ID_OFF		8
295b09fcd09SXiaofei Tan #define CMD_HDR_PHY_ID_MSK		(0x1ff << CMD_HDR_PHY_ID_OFF)
296b09fcd09SXiaofei Tan #define CMD_HDR_FORCE_PHY_OFF		17
297b09fcd09SXiaofei Tan #define CMD_HDR_FORCE_PHY_MSK		(0x1 << CMD_HDR_FORCE_PHY_OFF)
29845c901b8SJohn Garry #define CMD_HDR_PORT_OFF		18
29945c901b8SJohn Garry #define CMD_HDR_PORT_MSK		(0xf << CMD_HDR_PORT_OFF)
30045c901b8SJohn Garry #define CMD_HDR_PRIORITY_OFF		27
30145c901b8SJohn Garry #define CMD_HDR_PRIORITY_MSK		(0x1 << CMD_HDR_PRIORITY_OFF)
30245c901b8SJohn Garry #define CMD_HDR_CMD_OFF			29
30345c901b8SJohn Garry #define CMD_HDR_CMD_MSK			(0x7 << CMD_HDR_CMD_OFF)
30445c901b8SJohn Garry /* dw1 */
30545c901b8SJohn Garry #define CMD_HDR_DIR_OFF			5
30645c901b8SJohn Garry #define CMD_HDR_DIR_MSK			(0x3 << CMD_HDR_DIR_OFF)
30745c901b8SJohn Garry #define CMD_HDR_RESET_OFF		7
30845c901b8SJohn Garry #define CMD_HDR_RESET_MSK		(0x1 << CMD_HDR_RESET_OFF)
30945c901b8SJohn Garry #define CMD_HDR_VDTL_OFF		10
31045c901b8SJohn Garry #define CMD_HDR_VDTL_MSK		(0x1 << CMD_HDR_VDTL_OFF)
31145c901b8SJohn Garry #define CMD_HDR_FRAME_TYPE_OFF		11
31245c901b8SJohn Garry #define CMD_HDR_FRAME_TYPE_MSK		(0x1f << CMD_HDR_FRAME_TYPE_OFF)
31345c901b8SJohn Garry #define CMD_HDR_DEV_ID_OFF		16
31445c901b8SJohn Garry #define CMD_HDR_DEV_ID_MSK		(0xffff << CMD_HDR_DEV_ID_OFF)
31545c901b8SJohn Garry /* dw2 */
31645c901b8SJohn Garry #define CMD_HDR_CFL_OFF			0
31745c901b8SJohn Garry #define CMD_HDR_CFL_MSK			(0x1ff << CMD_HDR_CFL_OFF)
31845c901b8SJohn Garry #define CMD_HDR_NCQ_TAG_OFF		10
31945c901b8SJohn Garry #define CMD_HDR_NCQ_TAG_MSK		(0x1f << CMD_HDR_NCQ_TAG_OFF)
32045c901b8SJohn Garry #define CMD_HDR_MRFL_OFF		15
32145c901b8SJohn Garry #define CMD_HDR_MRFL_MSK		(0x1ff << CMD_HDR_MRFL_OFF)
32245c901b8SJohn Garry #define CMD_HDR_SG_MOD_OFF		24
32345c901b8SJohn Garry #define CMD_HDR_SG_MOD_MSK		(0x3 << CMD_HDR_SG_MOD_OFF)
32445c901b8SJohn Garry #define CMD_HDR_FIRST_BURST_OFF		26
32545c901b8SJohn Garry #define CMD_HDR_FIRST_BURST_MSK		(0x1 << CMD_HDR_SG_MOD_OFF)
32645c901b8SJohn Garry /* dw3 */
32745c901b8SJohn Garry #define CMD_HDR_IPTT_OFF		0
32845c901b8SJohn Garry #define CMD_HDR_IPTT_MSK		(0xffff << CMD_HDR_IPTT_OFF)
32945c901b8SJohn Garry /* dw6 */
33045c901b8SJohn Garry #define CMD_HDR_DIF_SGL_LEN_OFF		0
33145c901b8SJohn Garry #define CMD_HDR_DIF_SGL_LEN_MSK		(0xffff << CMD_HDR_DIF_SGL_LEN_OFF)
33245c901b8SJohn Garry #define CMD_HDR_DATA_SGL_LEN_OFF	16
33345c901b8SJohn Garry #define CMD_HDR_DATA_SGL_LEN_MSK	(0xffff << CMD_HDR_DATA_SGL_LEN_OFF)
334a3e665d9SJohn Garry #define CMD_HDR_ABORT_IPTT_OFF		16
335a3e665d9SJohn Garry #define CMD_HDR_ABORT_IPTT_MSK		(0xffff << CMD_HDR_ABORT_IPTT_OFF)
33645c901b8SJohn Garry 
33745c901b8SJohn Garry /* Completion header */
33845c901b8SJohn Garry /* dw0 */
339634a9585SXiang Chen #define CMPLT_HDR_ERR_PHASE_OFF	2
340634a9585SXiang Chen #define CMPLT_HDR_ERR_PHASE_MSK	(0xff << CMPLT_HDR_ERR_PHASE_OFF)
34145c901b8SJohn Garry #define CMPLT_HDR_RSPNS_XFRD_OFF	10
34245c901b8SJohn Garry #define CMPLT_HDR_RSPNS_XFRD_MSK	(0x1 << CMPLT_HDR_RSPNS_XFRD_OFF)
34345c901b8SJohn Garry #define CMPLT_HDR_ERX_OFF		12
34445c901b8SJohn Garry #define CMPLT_HDR_ERX_MSK		(0x1 << CMPLT_HDR_ERX_OFF)
345df032d0eSJohn Garry #define CMPLT_HDR_ABORT_STAT_OFF	13
346df032d0eSJohn Garry #define CMPLT_HDR_ABORT_STAT_MSK	(0x7 << CMPLT_HDR_ABORT_STAT_OFF)
347df032d0eSJohn Garry /* abort_stat */
348df032d0eSJohn Garry #define STAT_IO_NOT_VALID		0x1
349df032d0eSJohn Garry #define STAT_IO_NO_DEVICE		0x2
350df032d0eSJohn Garry #define STAT_IO_COMPLETE		0x3
351df032d0eSJohn Garry #define STAT_IO_ABORTED			0x4
35245c901b8SJohn Garry /* dw1 */
35345c901b8SJohn Garry #define CMPLT_HDR_IPTT_OFF		0
35445c901b8SJohn Garry #define CMPLT_HDR_IPTT_MSK		(0xffff << CMPLT_HDR_IPTT_OFF)
35545c901b8SJohn Garry #define CMPLT_HDR_DEV_ID_OFF		16
35645c901b8SJohn Garry #define CMPLT_HDR_DEV_ID_MSK		(0xffff << CMPLT_HDR_DEV_ID_OFF)
35745c901b8SJohn Garry 
35845c901b8SJohn Garry /* ITCT header */
35945c901b8SJohn Garry /* qw0 */
36045c901b8SJohn Garry #define ITCT_HDR_DEV_TYPE_OFF		0
36145c901b8SJohn Garry #define ITCT_HDR_DEV_TYPE_MSK		(0x3 << ITCT_HDR_DEV_TYPE_OFF)
36245c901b8SJohn Garry #define ITCT_HDR_VALID_OFF		2
36345c901b8SJohn Garry #define ITCT_HDR_VALID_MSK		(0x1 << ITCT_HDR_VALID_OFF)
36445c901b8SJohn Garry #define ITCT_HDR_MCR_OFF		5
36545c901b8SJohn Garry #define ITCT_HDR_MCR_MSK		(0xf << ITCT_HDR_MCR_OFF)
36645c901b8SJohn Garry #define ITCT_HDR_VLN_OFF		9
36745c901b8SJohn Garry #define ITCT_HDR_VLN_MSK		(0xf << ITCT_HDR_VLN_OFF)
368c399acfbSXiang Chen #define ITCT_HDR_SMP_TIMEOUT_OFF	16
369c399acfbSXiang Chen #define ITCT_HDR_SMP_TIMEOUT_8US	1
370c399acfbSXiang Chen #define ITCT_HDR_SMP_TIMEOUT		(ITCT_HDR_SMP_TIMEOUT_8US * \
371c399acfbSXiang Chen 					 250) /* 2ms */
372c399acfbSXiang Chen #define ITCT_HDR_AWT_CONTINUE_OFF	25
37345c901b8SJohn Garry #define ITCT_HDR_PORT_ID_OFF		28
37445c901b8SJohn Garry #define ITCT_HDR_PORT_ID_MSK		(0xf << ITCT_HDR_PORT_ID_OFF)
37545c901b8SJohn Garry /* qw2 */
37645c901b8SJohn Garry #define ITCT_HDR_INLT_OFF		0
37745c901b8SJohn Garry #define ITCT_HDR_INLT_MSK		(0xffffULL << ITCT_HDR_INLT_OFF)
37845c901b8SJohn Garry #define ITCT_HDR_BITLT_OFF		16
37945c901b8SJohn Garry #define ITCT_HDR_BITLT_MSK		(0xffffULL << ITCT_HDR_BITLT_OFF)
38045c901b8SJohn Garry #define ITCT_HDR_MCTLT_OFF		32
38145c901b8SJohn Garry #define ITCT_HDR_MCTLT_MSK		(0xffffULL << ITCT_HDR_MCTLT_OFF)
38245c901b8SJohn Garry #define ITCT_HDR_RTOLT_OFF		48
38345c901b8SJohn Garry #define ITCT_HDR_RTOLT_MSK		(0xffffULL << ITCT_HDR_RTOLT_OFF)
38445c901b8SJohn Garry 
385d3b688d3SXiang Chen #define HISI_SAS_FATAL_INT_NR	2
386d3b688d3SXiang Chen 
38794eac9e1SJohn Garry struct hisi_sas_complete_v2_hdr {
38894eac9e1SJohn Garry 	__le32 dw0;
38994eac9e1SJohn Garry 	__le32 dw1;
39094eac9e1SJohn Garry 	__le32 act;
39194eac9e1SJohn Garry 	__le32 dw3;
39294eac9e1SJohn Garry };
39394eac9e1SJohn Garry 
394e8fed0e9SJohn Garry struct hisi_sas_err_record_v2 {
395e8fed0e9SJohn Garry 	/* dw0 */
396e8fed0e9SJohn Garry 	__le32 trans_tx_fail_type;
397e8fed0e9SJohn Garry 
398e8fed0e9SJohn Garry 	/* dw1 */
399e8fed0e9SJohn Garry 	__le32 trans_rx_fail_type;
400e8fed0e9SJohn Garry 
401e8fed0e9SJohn Garry 	/* dw2 */
402e8fed0e9SJohn Garry 	__le16 dma_tx_err_type;
403e8fed0e9SJohn Garry 	__le16 sipc_rx_err_type;
404e8fed0e9SJohn Garry 
405e8fed0e9SJohn Garry 	/* dw3 */
406e8fed0e9SJohn Garry 	__le32 dma_rx_err_type;
407e8fed0e9SJohn Garry };
408e8fed0e9SJohn Garry 
40967c2bf23SXiaofei Tan struct signal_attenuation_s {
41067c2bf23SXiaofei Tan 	u32 de_emphasis;
41167c2bf23SXiaofei Tan 	u32 preshoot;
41267c2bf23SXiaofei Tan 	u32 boost;
41367c2bf23SXiaofei Tan };
41467c2bf23SXiaofei Tan 
41567c2bf23SXiaofei Tan struct sig_atten_lu_s {
41667c2bf23SXiaofei Tan 	const struct signal_attenuation_s *att;
41767c2bf23SXiaofei Tan 	u32 sas_phy_ctrl;
41867c2bf23SXiaofei Tan };
41967c2bf23SXiaofei Tan 
4202b383351SJohn Garry static const struct hisi_sas_hw_error one_bit_ecc_errors[] = {
4212b383351SJohn Garry 	{
4222b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF),
4232b383351SJohn Garry 		.msk = HGC_DQE_ECC_1B_ADDR_MSK,
4242b383351SJohn Garry 		.shift = HGC_DQE_ECC_1B_ADDR_OFF,
425794327abSXiaofei Tan 		.msg = "hgc_dqe_ecc1b_intr",
4262b383351SJohn Garry 		.reg = HGC_DQE_ECC_ADDR,
4272b383351SJohn Garry 	},
4282b383351SJohn Garry 	{
4292b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_1B_OFF),
4302b383351SJohn Garry 		.msk = HGC_IOST_ECC_1B_ADDR_MSK,
4312b383351SJohn Garry 		.shift = HGC_IOST_ECC_1B_ADDR_OFF,
432794327abSXiaofei Tan 		.msg = "hgc_iost_ecc1b_intr",
4332b383351SJohn Garry 		.reg = HGC_IOST_ECC_ADDR,
4342b383351SJohn Garry 	},
4352b383351SJohn Garry 	{
4362b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_1B_OFF),
4372b383351SJohn Garry 		.msk = HGC_ITCT_ECC_1B_ADDR_MSK,
4382b383351SJohn Garry 		.shift = HGC_ITCT_ECC_1B_ADDR_OFF,
439794327abSXiaofei Tan 		.msg = "hgc_itct_ecc1b_intr",
4402b383351SJohn Garry 		.reg = HGC_ITCT_ECC_ADDR,
4412b383351SJohn Garry 	},
4422b383351SJohn Garry 	{
4432b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_1B_OFF),
4442b383351SJohn Garry 		.msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK,
4452b383351SJohn Garry 		.shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF,
446794327abSXiaofei Tan 		.msg = "hgc_iostl_ecc1b_intr",
4472b383351SJohn Garry 		.reg = HGC_LM_DFX_STATUS2,
4482b383351SJohn Garry 	},
4492b383351SJohn Garry 	{
4502b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_1B_OFF),
4512b383351SJohn Garry 		.msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK,
4522b383351SJohn Garry 		.shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF,
453794327abSXiaofei Tan 		.msg = "hgc_itctl_ecc1b_intr",
4542b383351SJohn Garry 		.reg = HGC_LM_DFX_STATUS2,
4552b383351SJohn Garry 	},
4562b383351SJohn Garry 	{
4572b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_1B_OFF),
4582b383351SJohn Garry 		.msk = HGC_CQE_ECC_1B_ADDR_MSK,
4592b383351SJohn Garry 		.shift = HGC_CQE_ECC_1B_ADDR_OFF,
460794327abSXiaofei Tan 		.msg = "hgc_cqe_ecc1b_intr",
4612b383351SJohn Garry 		.reg = HGC_CQE_ECC_ADDR,
4622b383351SJohn Garry 	},
4632b383351SJohn Garry 	{
4642b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_1B_OFF),
4652b383351SJohn Garry 		.msk = HGC_RXM_DFX_STATUS14_MEM0_MSK,
4662b383351SJohn Garry 		.shift = HGC_RXM_DFX_STATUS14_MEM0_OFF,
467794327abSXiaofei Tan 		.msg = "rxm_mem0_ecc1b_intr",
4682b383351SJohn Garry 		.reg = HGC_RXM_DFX_STATUS14,
4692b383351SJohn Garry 	},
4702b383351SJohn Garry 	{
4712b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_1B_OFF),
4722b383351SJohn Garry 		.msk = HGC_RXM_DFX_STATUS14_MEM1_MSK,
4732b383351SJohn Garry 		.shift = HGC_RXM_DFX_STATUS14_MEM1_OFF,
474794327abSXiaofei Tan 		.msg = "rxm_mem1_ecc1b_intr",
4752b383351SJohn Garry 		.reg = HGC_RXM_DFX_STATUS14,
4762b383351SJohn Garry 	},
4772b383351SJohn Garry 	{
4782b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_1B_OFF),
4792b383351SJohn Garry 		.msk = HGC_RXM_DFX_STATUS14_MEM2_MSK,
4802b383351SJohn Garry 		.shift = HGC_RXM_DFX_STATUS14_MEM2_OFF,
481794327abSXiaofei Tan 		.msg = "rxm_mem2_ecc1b_intr",
4822b383351SJohn Garry 		.reg = HGC_RXM_DFX_STATUS14,
4832b383351SJohn Garry 	},
4842b383351SJohn Garry 	{
4852b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF),
4862b383351SJohn Garry 		.msk = HGC_RXM_DFX_STATUS15_MEM3_MSK,
4872b383351SJohn Garry 		.shift = HGC_RXM_DFX_STATUS15_MEM3_OFF,
488794327abSXiaofei Tan 		.msg = "rxm_mem3_ecc1b_intr",
4892b383351SJohn Garry 		.reg = HGC_RXM_DFX_STATUS15,
4902b383351SJohn Garry 	},
4912b383351SJohn Garry };
4922b383351SJohn Garry 
4932b383351SJohn Garry static const struct hisi_sas_hw_error multi_bit_ecc_errors[] = {
4942b383351SJohn Garry 	{
4952b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF),
4962b383351SJohn Garry 		.msk = HGC_DQE_ECC_MB_ADDR_MSK,
4972b383351SJohn Garry 		.shift = HGC_DQE_ECC_MB_ADDR_OFF,
498794327abSXiaofei Tan 		.msg = "hgc_dqe_eccbad_intr",
4992b383351SJohn Garry 		.reg = HGC_DQE_ECC_ADDR,
5002b383351SJohn Garry 	},
5012b383351SJohn Garry 	{
5022b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF),
5032b383351SJohn Garry 		.msk = HGC_IOST_ECC_MB_ADDR_MSK,
5042b383351SJohn Garry 		.shift = HGC_IOST_ECC_MB_ADDR_OFF,
505794327abSXiaofei Tan 		.msg = "hgc_iost_eccbad_intr",
5062b383351SJohn Garry 		.reg = HGC_IOST_ECC_ADDR,
5072b383351SJohn Garry 	},
5082b383351SJohn Garry 	{
5092b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF),
5102b383351SJohn Garry 		.msk = HGC_ITCT_ECC_MB_ADDR_MSK,
5112b383351SJohn Garry 		.shift = HGC_ITCT_ECC_MB_ADDR_OFF,
512794327abSXiaofei Tan 		.msg = "hgc_itct_eccbad_intr",
5132b383351SJohn Garry 		.reg = HGC_ITCT_ECC_ADDR,
5142b383351SJohn Garry 	},
5152b383351SJohn Garry 	{
5162b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF),
5172b383351SJohn Garry 		.msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK,
5182b383351SJohn Garry 		.shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF,
519794327abSXiaofei Tan 		.msg = "hgc_iostl_eccbad_intr",
5202b383351SJohn Garry 		.reg = HGC_LM_DFX_STATUS2,
5212b383351SJohn Garry 	},
5222b383351SJohn Garry 	{
5232b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF),
5242b383351SJohn Garry 		.msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK,
5252b383351SJohn Garry 		.shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF,
526794327abSXiaofei Tan 		.msg = "hgc_itctl_eccbad_intr",
5272b383351SJohn Garry 		.reg = HGC_LM_DFX_STATUS2,
5282b383351SJohn Garry 	},
5292b383351SJohn Garry 	{
5302b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF),
5312b383351SJohn Garry 		.msk = HGC_CQE_ECC_MB_ADDR_MSK,
5322b383351SJohn Garry 		.shift = HGC_CQE_ECC_MB_ADDR_OFF,
533794327abSXiaofei Tan 		.msg = "hgc_cqe_eccbad_intr",
5342b383351SJohn Garry 		.reg = HGC_CQE_ECC_ADDR,
5352b383351SJohn Garry 	},
5362b383351SJohn Garry 	{
5372b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF),
5382b383351SJohn Garry 		.msk = HGC_RXM_DFX_STATUS14_MEM0_MSK,
5392b383351SJohn Garry 		.shift = HGC_RXM_DFX_STATUS14_MEM0_OFF,
540794327abSXiaofei Tan 		.msg = "rxm_mem0_eccbad_intr",
5412b383351SJohn Garry 		.reg = HGC_RXM_DFX_STATUS14,
5422b383351SJohn Garry 	},
5432b383351SJohn Garry 	{
5442b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF),
5452b383351SJohn Garry 		.msk = HGC_RXM_DFX_STATUS14_MEM1_MSK,
5462b383351SJohn Garry 		.shift = HGC_RXM_DFX_STATUS14_MEM1_OFF,
547794327abSXiaofei Tan 		.msg = "rxm_mem1_eccbad_intr",
5482b383351SJohn Garry 		.reg = HGC_RXM_DFX_STATUS14,
5492b383351SJohn Garry 	},
5502b383351SJohn Garry 	{
5512b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF),
5522b383351SJohn Garry 		.msk = HGC_RXM_DFX_STATUS14_MEM2_MSK,
5532b383351SJohn Garry 		.shift = HGC_RXM_DFX_STATUS14_MEM2_OFF,
554794327abSXiaofei Tan 		.msg = "rxm_mem2_eccbad_intr",
5552b383351SJohn Garry 		.reg = HGC_RXM_DFX_STATUS14,
5562b383351SJohn Garry 	},
5572b383351SJohn Garry 	{
5582b383351SJohn Garry 		.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF),
5592b383351SJohn Garry 		.msk = HGC_RXM_DFX_STATUS15_MEM3_MSK,
5602b383351SJohn Garry 		.shift = HGC_RXM_DFX_STATUS15_MEM3_OFF,
561794327abSXiaofei Tan 		.msg = "rxm_mem3_eccbad_intr",
5622b383351SJohn Garry 		.reg = HGC_RXM_DFX_STATUS15,
5632b383351SJohn Garry 	},
5642b383351SJohn Garry };
5652b383351SJohn Garry 
5667911e66fSJohn Garry enum {
5677911e66fSJohn Garry 	HISI_SAS_PHY_PHY_UPDOWN,
568d3bf3d84SJohn Garry 	HISI_SAS_PHY_CHNL_INT,
5697911e66fSJohn Garry 	HISI_SAS_PHY_INT_NR
5707911e66fSJohn Garry };
5717911e66fSJohn Garry 
572e8fed0e9SJohn Garry enum {
573e8fed0e9SJohn Garry 	TRANS_TX_FAIL_BASE = 0x0, /* dw0 */
574634a9585SXiang Chen 	TRANS_RX_FAIL_BASE = 0x20, /* dw1 */
575634a9585SXiang Chen 	DMA_TX_ERR_BASE = 0x40, /* dw2 bit 15-0 */
576634a9585SXiang Chen 	SIPC_RX_ERR_BASE = 0x50, /* dw2 bit 31-16*/
577634a9585SXiang Chen 	DMA_RX_ERR_BASE = 0x60, /* dw3 */
578e8fed0e9SJohn Garry 
579e8fed0e9SJohn Garry 	/* trans tx*/
580e8fed0e9SJohn Garry 	TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS = TRANS_TX_FAIL_BASE, /* 0x0 */
581e8fed0e9SJohn Garry 	TRANS_TX_ERR_PHY_NOT_ENABLE, /* 0x1 */
582e8fed0e9SJohn Garry 	TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION, /* 0x2 */
583e8fed0e9SJohn Garry 	TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION, /* 0x3 */
584e8fed0e9SJohn Garry 	TRANS_TX_OPEN_CNX_ERR_BY_OTHER, /* 0x4 */
585e8fed0e9SJohn Garry 	RESERVED0, /* 0x5 */
586e8fed0e9SJohn Garry 	TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT, /* 0x6 */
587e8fed0e9SJohn Garry 	TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY, /* 0x7 */
588e8fed0e9SJohn Garry 	TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED, /* 0x8 */
589e8fed0e9SJohn Garry 	TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED, /* 0x9 */
590e8fed0e9SJohn Garry 	TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION, /* 0xa */
591e8fed0e9SJohn Garry 	TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD, /* 0xb */
592e8fed0e9SJohn Garry 	TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER, /* 0xc */
593e8fed0e9SJohn Garry 	TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED, /* 0xd */
594e8fed0e9SJohn Garry 	TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT, /* 0xe */
595e8fed0e9SJohn Garry 	TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION, /* 0xf */
596e8fed0e9SJohn Garry 	TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED, /* 0x10 */
597e8fed0e9SJohn Garry 	TRANS_TX_ERR_FRAME_TXED, /* 0x11 */
598e8fed0e9SJohn Garry 	TRANS_TX_ERR_WITH_BREAK_TIMEOUT, /* 0x12 */
599e8fed0e9SJohn Garry 	TRANS_TX_ERR_WITH_BREAK_REQUEST, /* 0x13 */
600e8fed0e9SJohn Garry 	TRANS_TX_ERR_WITH_BREAK_RECEVIED, /* 0x14 */
601e8fed0e9SJohn Garry 	TRANS_TX_ERR_WITH_CLOSE_TIMEOUT, /* 0x15 */
602e8fed0e9SJohn Garry 	TRANS_TX_ERR_WITH_CLOSE_NORMAL, /* 0x16 for ssp*/
603e8fed0e9SJohn Garry 	TRANS_TX_ERR_WITH_CLOSE_PHYDISALE, /* 0x17 */
604e8fed0e9SJohn Garry 	TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x18 */
605e8fed0e9SJohn Garry 	TRANS_TX_ERR_WITH_CLOSE_COMINIT, /* 0x19 */
606e8fed0e9SJohn Garry 	TRANS_TX_ERR_WITH_NAK_RECEVIED, /* 0x1a for ssp*/
607e8fed0e9SJohn Garry 	TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT, /* 0x1b for ssp*/
608e8fed0e9SJohn Garry 	/*IO_TX_ERR_WITH_R_ERR_RECEVIED, [> 0x1b for sata/stp<] */
609e8fed0e9SJohn Garry 	TRANS_TX_ERR_WITH_CREDIT_TIMEOUT, /* 0x1c for ssp */
610e8fed0e9SJohn Garry 	/*IO_RX_ERR_WITH_SATA_DEVICE_LOST 0x1c for sata/stp */
611e8fed0e9SJohn Garry 	TRANS_TX_ERR_WITH_IPTT_CONFLICT, /* 0x1d for ssp/smp */
612e8fed0e9SJohn Garry 	TRANS_TX_ERR_WITH_OPEN_BY_DES_OR_OTHERS, /* 0x1e */
613e8fed0e9SJohn Garry 	/*IO_TX_ERR_WITH_SYNC_RXD, [> 0x1e <] for sata/stp */
614e8fed0e9SJohn Garry 	TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT, /* 0x1f for sata/stp */
615e8fed0e9SJohn Garry 
616e8fed0e9SJohn Garry 	/* trans rx */
617634a9585SXiang Chen 	TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x20 */
618634a9585SXiang Chen 	TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR, /* 0x21 for sata/stp */
619634a9585SXiang Chen 	TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM, /* 0x22 for ssp/smp */
620634a9585SXiang Chen 	/*IO_ERR_WITH_RXFIS_8B10B_CODE_ERR, [> 0x22 <] for sata/stp */
621634a9585SXiang Chen 	TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR, /* 0x23 for sata/stp */
622634a9585SXiang Chen 	TRANS_RX_ERR_WITH_RXFIS_CRC_ERR, /* 0x24 for sata/stp */
623634a9585SXiang Chen 	TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN, /* 0x25 for smp */
624634a9585SXiang Chen 	/*IO_ERR_WITH_RXFIS_TX SYNCP, [> 0x25 <] for sata/stp */
625634a9585SXiang Chen 	TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP, /* 0x26 for sata/stp*/
626634a9585SXiang Chen 	TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN, /* 0x27 */
627634a9585SXiang Chen 	TRANS_RX_ERR_WITH_BREAK_TIMEOUT, /* 0x28 */
628634a9585SXiang Chen 	TRANS_RX_ERR_WITH_BREAK_REQUEST, /* 0x29 */
629634a9585SXiang Chen 	TRANS_RX_ERR_WITH_BREAK_RECEVIED, /* 0x2a */
630634a9585SXiang Chen 	RESERVED1, /* 0x2b */
631634a9585SXiang Chen 	TRANS_RX_ERR_WITH_CLOSE_NORMAL, /* 0x2c */
632634a9585SXiang Chen 	TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE, /* 0x2d */
633634a9585SXiang Chen 	TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x2e */
634634a9585SXiang Chen 	TRANS_RX_ERR_WITH_CLOSE_COMINIT, /* 0x2f */
635634a9585SXiang Chen 	TRANS_RX_ERR_WITH_DATA_LEN0, /* 0x30 for ssp/smp */
636634a9585SXiang Chen 	TRANS_RX_ERR_WITH_BAD_HASH, /* 0x31 for ssp */
637634a9585SXiang Chen 	/*IO_RX_ERR_WITH_FIS_TOO_SHORT, [> 0x31 <] for sata/stp */
638634a9585SXiang Chen 	TRANS_RX_XRDY_WLEN_ZERO_ERR, /* 0x32 for ssp*/
639634a9585SXiang Chen 	/*IO_RX_ERR_WITH_FIS_TOO_LONG, [> 0x32 <] for sata/stp */
640634a9585SXiang Chen 	TRANS_RX_SSP_FRM_LEN_ERR, /* 0x33 for ssp */
641634a9585SXiang Chen 	/*IO_RX_ERR_WITH_SATA_DEVICE_LOST, [> 0x33 <] for sata */
642634a9585SXiang Chen 	RESERVED2, /* 0x34 */
643634a9585SXiang Chen 	RESERVED3, /* 0x35 */
644634a9585SXiang Chen 	RESERVED4, /* 0x36 */
645634a9585SXiang Chen 	RESERVED5, /* 0x37 */
646634a9585SXiang Chen 	TRANS_RX_ERR_WITH_BAD_FRM_TYPE, /* 0x38 */
647634a9585SXiang Chen 	TRANS_RX_SMP_FRM_LEN_ERR, /* 0x39 */
648634a9585SXiang Chen 	TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x3a */
649634a9585SXiang Chen 	RESERVED6, /* 0x3b */
650634a9585SXiang Chen 	RESERVED7, /* 0x3c */
651634a9585SXiang Chen 	RESERVED8, /* 0x3d */
652634a9585SXiang Chen 	RESERVED9, /* 0x3e */
653634a9585SXiang Chen 	TRANS_RX_R_ERR, /* 0x3f */
654e8fed0e9SJohn Garry 
655e8fed0e9SJohn Garry 	/* dma tx */
656634a9585SXiang Chen 	DMA_TX_DIF_CRC_ERR = DMA_TX_ERR_BASE, /* 0x40 */
657634a9585SXiang Chen 	DMA_TX_DIF_APP_ERR, /* 0x41 */
658634a9585SXiang Chen 	DMA_TX_DIF_RPP_ERR, /* 0x42 */
659634a9585SXiang Chen 	DMA_TX_DATA_SGL_OVERFLOW, /* 0x43 */
660634a9585SXiang Chen 	DMA_TX_DIF_SGL_OVERFLOW, /* 0x44 */
661634a9585SXiang Chen 	DMA_TX_UNEXP_XFER_ERR, /* 0x45 */
662634a9585SXiang Chen 	DMA_TX_UNEXP_RETRANS_ERR, /* 0x46 */
663634a9585SXiang Chen 	DMA_TX_XFER_LEN_OVERFLOW, /* 0x47 */
664634a9585SXiang Chen 	DMA_TX_XFER_OFFSET_ERR, /* 0x48 */
665634a9585SXiang Chen 	DMA_TX_RAM_ECC_ERR, /* 0x49 */
666634a9585SXiang Chen 	DMA_TX_DIF_LEN_ALIGN_ERR, /* 0x4a */
667634a9585SXiang Chen 	DMA_TX_MAX_ERR_CODE,
668e8fed0e9SJohn Garry 
669e8fed0e9SJohn Garry 	/* sipc rx */
670634a9585SXiang Chen 	SIPC_RX_FIS_STATUS_ERR_BIT_VLD = SIPC_RX_ERR_BASE, /* 0x50 */
671634a9585SXiang Chen 	SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR, /* 0x51 */
672634a9585SXiang Chen 	SIPC_RX_FIS_STATUS_BSY_BIT_ERR, /* 0x52 */
673634a9585SXiang Chen 	SIPC_RX_WRSETUP_LEN_ODD_ERR, /* 0x53 */
674634a9585SXiang Chen 	SIPC_RX_WRSETUP_LEN_ZERO_ERR, /* 0x54 */
675634a9585SXiang Chen 	SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR, /* 0x55 */
676634a9585SXiang Chen 	SIPC_RX_NCQ_WRSETUP_OFFSET_ERR, /* 0x56 */
677634a9585SXiang Chen 	SIPC_RX_NCQ_WRSETUP_AUTO_ACTIVE_ERR, /* 0x57 */
678634a9585SXiang Chen 	SIPC_RX_SATA_UNEXP_FIS_ERR, /* 0x58 */
679634a9585SXiang Chen 	SIPC_RX_WRSETUP_ESTATUS_ERR, /* 0x59 */
680634a9585SXiang Chen 	SIPC_RX_DATA_UNDERFLOW_ERR, /* 0x5a */
681634a9585SXiang Chen 	SIPC_RX_MAX_ERR_CODE,
682e8fed0e9SJohn Garry 
683e8fed0e9SJohn Garry 	/* dma rx */
684634a9585SXiang Chen 	DMA_RX_DIF_CRC_ERR = DMA_RX_ERR_BASE, /* 0x60 */
685634a9585SXiang Chen 	DMA_RX_DIF_APP_ERR, /* 0x61 */
686634a9585SXiang Chen 	DMA_RX_DIF_RPP_ERR, /* 0x62 */
687634a9585SXiang Chen 	DMA_RX_DATA_SGL_OVERFLOW, /* 0x63 */
688634a9585SXiang Chen 	DMA_RX_DIF_SGL_OVERFLOW, /* 0x64 */
689634a9585SXiang Chen 	DMA_RX_DATA_LEN_OVERFLOW, /* 0x65 */
690634a9585SXiang Chen 	DMA_RX_DATA_LEN_UNDERFLOW, /* 0x66 */
691634a9585SXiang Chen 	DMA_RX_DATA_OFFSET_ERR, /* 0x67 */
692634a9585SXiang Chen 	RESERVED10, /* 0x68 */
693634a9585SXiang Chen 	DMA_RX_SATA_FRAME_TYPE_ERR, /* 0x69 */
694634a9585SXiang Chen 	DMA_RX_RESP_BUF_OVERFLOW, /* 0x6a */
695634a9585SXiang Chen 	DMA_RX_UNEXP_RETRANS_RESP_ERR, /* 0x6b */
696634a9585SXiang Chen 	DMA_RX_UNEXP_NORM_RESP_ERR, /* 0x6c */
697634a9585SXiang Chen 	DMA_RX_UNEXP_RDFRAME_ERR, /* 0x6d */
698634a9585SXiang Chen 	DMA_RX_PIO_DATA_LEN_ERR, /* 0x6e */
699634a9585SXiang Chen 	DMA_RX_RDSETUP_STATUS_ERR, /* 0x6f */
700634a9585SXiang Chen 	DMA_RX_RDSETUP_STATUS_DRQ_ERR, /* 0x70 */
701634a9585SXiang Chen 	DMA_RX_RDSETUP_STATUS_BSY_ERR, /* 0x71 */
702634a9585SXiang Chen 	DMA_RX_RDSETUP_LEN_ODD_ERR, /* 0x72 */
703634a9585SXiang Chen 	DMA_RX_RDSETUP_LEN_ZERO_ERR, /* 0x73 */
704634a9585SXiang Chen 	DMA_RX_RDSETUP_LEN_OVER_ERR, /* 0x74 */
705634a9585SXiang Chen 	DMA_RX_RDSETUP_OFFSET_ERR, /* 0x75 */
706634a9585SXiang Chen 	DMA_RX_RDSETUP_ACTIVE_ERR, /* 0x76 */
707634a9585SXiang Chen 	DMA_RX_RDSETUP_ESTATUS_ERR, /* 0x77 */
708634a9585SXiang Chen 	DMA_RX_RAM_ECC_ERR, /* 0x78 */
709634a9585SXiang Chen 	DMA_RX_UNKNOWN_FRM_ERR, /* 0x79 */
710634a9585SXiang Chen 	DMA_RX_MAX_ERR_CODE,
711e8fed0e9SJohn Garry };
712e8fed0e9SJohn Garry 
71394eac9e1SJohn Garry #define HISI_SAS_COMMAND_ENTRIES_V2_HW 4096
71432ccba52SXiaofei Tan #define HISI_MAX_SATA_SUPPORT_V2_HW	(HISI_SAS_COMMAND_ENTRIES_V2_HW/64 - 1)
71594eac9e1SJohn Garry 
7168c36e31dSJohn Garry #define DIR_NO_DATA 0
7178c36e31dSJohn Garry #define DIR_TO_INI 1
7188c36e31dSJohn Garry #define DIR_TO_DEVICE 2
7198c36e31dSJohn Garry #define DIR_RESERVED 3
7208c36e31dSJohn Garry 
721634a9585SXiang Chen #define ERR_ON_TX_PHASE(err_phase) (err_phase == 0x2 || \
722634a9585SXiang Chen 		err_phase == 0x4 || err_phase == 0x8 ||\
723634a9585SXiang Chen 		err_phase == 0x6 || err_phase == 0xa)
724634a9585SXiang Chen #define ERR_ON_RX_PHASE(err_phase) (err_phase == 0x10 || \
725634a9585SXiang Chen 		err_phase == 0x20 || err_phase == 0x40)
726634a9585SXiang Chen 
72777570eedSKees Cook static void link_timeout_disable_link(struct timer_list *t);
728f2f89c32SXiang Chen 
hisi_sas_read32(struct hisi_hba * hisi_hba,u32 off)72994eac9e1SJohn Garry static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
73094eac9e1SJohn Garry {
73194eac9e1SJohn Garry 	void __iomem *regs = hisi_hba->regs + off;
73294eac9e1SJohn Garry 
73394eac9e1SJohn Garry 	return readl(regs);
73494eac9e1SJohn Garry }
73594eac9e1SJohn Garry 
hisi_sas_read32_relaxed(struct hisi_hba * hisi_hba,u32 off)7368c36e31dSJohn Garry static u32 hisi_sas_read32_relaxed(struct hisi_hba *hisi_hba, u32 off)
7378c36e31dSJohn Garry {
7388c36e31dSJohn Garry 	void __iomem *regs = hisi_hba->regs + off;
7398c36e31dSJohn Garry 
7408c36e31dSJohn Garry 	return readl_relaxed(regs);
7418c36e31dSJohn Garry }
7428c36e31dSJohn Garry 
hisi_sas_write32(struct hisi_hba * hisi_hba,u32 off,u32 val)74394eac9e1SJohn Garry static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val)
74494eac9e1SJohn Garry {
74594eac9e1SJohn Garry 	void __iomem *regs = hisi_hba->regs + off;
74694eac9e1SJohn Garry 
74794eac9e1SJohn Garry 	writel(val, regs);
74894eac9e1SJohn Garry }
74994eac9e1SJohn Garry 
hisi_sas_phy_write32(struct hisi_hba * hisi_hba,int phy_no,u32 off,u32 val)75094eac9e1SJohn Garry static void hisi_sas_phy_write32(struct hisi_hba *hisi_hba, int phy_no,
75194eac9e1SJohn Garry 				 u32 off, u32 val)
75294eac9e1SJohn Garry {
75394eac9e1SJohn Garry 	void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
75494eac9e1SJohn Garry 
75594eac9e1SJohn Garry 	writel(val, regs);
75694eac9e1SJohn Garry }
75794eac9e1SJohn Garry 
hisi_sas_phy_read32(struct hisi_hba * hisi_hba,int phy_no,u32 off)75894eac9e1SJohn Garry static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
75994eac9e1SJohn Garry 				      int phy_no, u32 off)
76094eac9e1SJohn Garry {
76194eac9e1SJohn Garry 	void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
76294eac9e1SJohn Garry 
76394eac9e1SJohn Garry 	return readl(regs);
76494eac9e1SJohn Garry }
76594eac9e1SJohn Garry 
766330fa7f3SJohn Garry /* This function needs to be protected from pre-emption. */
767330fa7f3SJohn Garry static int
slot_index_alloc_quirk_v2_hw(struct hisi_hba * hisi_hba,struct domain_device * device)768784b46b7SXiang Chen slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba,
769330fa7f3SJohn Garry 			     struct domain_device *device)
770330fa7f3SJohn Garry {
771330fa7f3SJohn Garry 	int sata_dev = dev_is_sata(device);
77232ccba52SXiaofei Tan 	void *bitmap = hisi_hba->slot_index_tags;
77332ccba52SXiaofei Tan 	struct hisi_sas_device *sas_dev = device->lldd_dev;
77432ccba52SXiaofei Tan 	int sata_idx = sas_dev->sata_idx;
77532ccba52SXiaofei Tan 	int start, end;
77632ccba52SXiaofei Tan 
77732ccba52SXiaofei Tan 	if (!sata_dev) {
77832ccba52SXiaofei Tan 		/*
77932ccba52SXiaofei Tan 		 * STP link SoC bug workaround: index starts from 1.
78032ccba52SXiaofei Tan 		 * additionally, we can only allocate odd IPTT(1~4095)
78132ccba52SXiaofei Tan 		 * for SAS/SMP device.
78232ccba52SXiaofei Tan 		 */
78332ccba52SXiaofei Tan 		start = 1;
78432ccba52SXiaofei Tan 		end = hisi_hba->slot_index_count;
78532ccba52SXiaofei Tan 	} else {
78632ccba52SXiaofei Tan 		if (sata_idx >= HISI_MAX_SATA_SUPPORT_V2_HW)
78732ccba52SXiaofei Tan 			return -EINVAL;
78832ccba52SXiaofei Tan 
78932ccba52SXiaofei Tan 		/*
79032ccba52SXiaofei Tan 		 * For SATA device: allocate even IPTT in this interval
79132ccba52SXiaofei Tan 		 * [64*(sata_idx+1), 64*(sata_idx+2)], then each SATA device
79232ccba52SXiaofei Tan 		 * own 32 IPTTs. IPTT 0 shall not be used duing to STP link
79332ccba52SXiaofei Tan 		 * SoC bug workaround. So we ignore the first 32 even IPTTs.
79432ccba52SXiaofei Tan 		 */
79532ccba52SXiaofei Tan 		start = 64 * (sata_idx + 1);
79632ccba52SXiaofei Tan 		end = 64 * (sata_idx + 2);
79732ccba52SXiaofei Tan 	}
798330fa7f3SJohn Garry 
799e9dc5e11SXiang Chen 	spin_lock(&hisi_hba->lock);
800330fa7f3SJohn Garry 	while (1) {
80132ccba52SXiaofei Tan 		start = find_next_zero_bit(bitmap,
80232ccba52SXiaofei Tan 					hisi_hba->slot_index_count, start);
803fe5fb42dSJohn Garry 		if (start >= end) {
804e9dc5e11SXiang Chen 			spin_unlock(&hisi_hba->lock);
805330fa7f3SJohn Garry 			return -SAS_QUEUE_FULL;
806fe5fb42dSJohn Garry 		}
807330fa7f3SJohn Garry 		/*
80832ccba52SXiaofei Tan 		 * SAS IPTT bit0 should be 1, and SATA IPTT bit0 should be 0.
809330fa7f3SJohn Garry 		 */
81032ccba52SXiaofei Tan 		if (sata_dev ^ (start & 1))
811330fa7f3SJohn Garry 			break;
81232ccba52SXiaofei Tan 		start++;
81332ccba52SXiaofei Tan 	}
81432ccba52SXiaofei Tan 
81532ccba52SXiaofei Tan 	set_bit(start, bitmap);
816e9dc5e11SXiang Chen 	spin_unlock(&hisi_hba->lock);
817784b46b7SXiang Chen 	return start;
81832ccba52SXiaofei Tan }
81932ccba52SXiaofei Tan 
sata_index_alloc_v2_hw(struct hisi_hba * hisi_hba,int * idx)82032ccba52SXiaofei Tan static bool sata_index_alloc_v2_hw(struct hisi_hba *hisi_hba, int *idx)
82132ccba52SXiaofei Tan {
82232ccba52SXiaofei Tan 	unsigned int index;
82311b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
82432ccba52SXiaofei Tan 	void *bitmap = hisi_hba->sata_dev_bitmap;
82532ccba52SXiaofei Tan 
82632ccba52SXiaofei Tan 	index = find_first_zero_bit(bitmap, HISI_MAX_SATA_SUPPORT_V2_HW);
82732ccba52SXiaofei Tan 	if (index >= HISI_MAX_SATA_SUPPORT_V2_HW) {
82832ccba52SXiaofei Tan 		dev_warn(dev, "alloc sata index failed, index=%d\n", index);
82932ccba52SXiaofei Tan 		return false;
830330fa7f3SJohn Garry 	}
831330fa7f3SJohn Garry 
832330fa7f3SJohn Garry 	set_bit(index, bitmap);
83332ccba52SXiaofei Tan 	*idx = index;
83432ccba52SXiaofei Tan 	return true;
835330fa7f3SJohn Garry }
836330fa7f3SJohn Garry 
83732ccba52SXiaofei Tan 
838b2bdaf2bSJohn Garry static struct
alloc_dev_quirk_v2_hw(struct domain_device * device)839b2bdaf2bSJohn Garry hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device)
840b2bdaf2bSJohn Garry {
841b2bdaf2bSJohn Garry 	struct hisi_hba *hisi_hba = device->port->ha->lldd_ha;
842b2bdaf2bSJohn Garry 	struct hisi_sas_device *sas_dev = NULL;
843b2bdaf2bSJohn Garry 	int i, sata_dev = dev_is_sata(device);
84432ccba52SXiaofei Tan 	int sata_idx = -1;
845b2bdaf2bSJohn Garry 
846e9dc5e11SXiang Chen 	spin_lock(&hisi_hba->lock);
84732ccba52SXiaofei Tan 
84832ccba52SXiaofei Tan 	if (sata_dev)
84932ccba52SXiaofei Tan 		if (!sata_index_alloc_v2_hw(hisi_hba, &sata_idx))
85032ccba52SXiaofei Tan 			goto out;
85132ccba52SXiaofei Tan 
852b2bdaf2bSJohn Garry 	for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
853b2bdaf2bSJohn Garry 		/*
854b2bdaf2bSJohn Garry 		 * SATA device id bit0 should be 0
855b2bdaf2bSJohn Garry 		 */
856b2bdaf2bSJohn Garry 		if (sata_dev && (i & 1))
857b2bdaf2bSJohn Garry 			continue;
858b2bdaf2bSJohn Garry 		if (hisi_hba->devices[i].dev_type == SAS_PHY_UNUSED) {
859b1a49412SXiang Chen 			int queue = i % hisi_hba->queue_count;
860b1a49412SXiang Chen 			struct hisi_sas_dq *dq = &hisi_hba->dq[queue];
861b1a49412SXiang Chen 
862b2bdaf2bSJohn Garry 			hisi_hba->devices[i].device_id = i;
863b2bdaf2bSJohn Garry 			sas_dev = &hisi_hba->devices[i];
86457dbb2b2SXiang Chen 			sas_dev->dev_status = HISI_SAS_DEV_INIT;
865b2bdaf2bSJohn Garry 			sas_dev->dev_type = device->dev_type;
866b2bdaf2bSJohn Garry 			sas_dev->hisi_hba = hisi_hba;
867b2bdaf2bSJohn Garry 			sas_dev->sas_device = device;
86832ccba52SXiaofei Tan 			sas_dev->sata_idx = sata_idx;
869b1a49412SXiang Chen 			sas_dev->dq = dq;
8704fefe5bbSXiang Chen 			spin_lock_init(&sas_dev->lock);
871405314dfSJohn Garry 			INIT_LIST_HEAD(&hisi_hba->devices[i].list);
872b2bdaf2bSJohn Garry 			break;
873b2bdaf2bSJohn Garry 		}
874b2bdaf2bSJohn Garry 	}
87532ccba52SXiaofei Tan 
87632ccba52SXiaofei Tan out:
877e9dc5e11SXiang Chen 	spin_unlock(&hisi_hba->lock);
878b2bdaf2bSJohn Garry 
879b2bdaf2bSJohn Garry 	return sas_dev;
880b2bdaf2bSJohn Garry }
881b2bdaf2bSJohn Garry 
config_phy_opt_mode_v2_hw(struct hisi_hba * hisi_hba,int phy_no)88229a20428SJohn Garry static void config_phy_opt_mode_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
88329a20428SJohn Garry {
88429a20428SJohn Garry 	u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
88529a20428SJohn Garry 
88629a20428SJohn Garry 	cfg &= ~PHY_CFG_DC_OPT_MSK;
88729a20428SJohn Garry 	cfg |= 1 << PHY_CFG_DC_OPT_OFF;
88829a20428SJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
88929a20428SJohn Garry }
89029a20428SJohn Garry 
config_id_frame_v2_hw(struct hisi_hba * hisi_hba,int phy_no)891806bb768SJohn Garry static void config_id_frame_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
892806bb768SJohn Garry {
893806bb768SJohn Garry 	struct sas_identify_frame identify_frame;
894806bb768SJohn Garry 	u32 *identify_buffer;
895806bb768SJohn Garry 
896806bb768SJohn Garry 	memset(&identify_frame, 0, sizeof(identify_frame));
897806bb768SJohn Garry 	identify_frame.dev_type = SAS_END_DEVICE;
898806bb768SJohn Garry 	identify_frame.frame_type = 0;
899806bb768SJohn Garry 	identify_frame._un1 = 1;
900806bb768SJohn Garry 	identify_frame.initiator_bits = SAS_PROTOCOL_ALL;
901806bb768SJohn Garry 	identify_frame.target_bits = SAS_PROTOCOL_NONE;
902806bb768SJohn Garry 	memcpy(&identify_frame._un4_11[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
903806bb768SJohn Garry 	memcpy(&identify_frame.sas_addr[0], hisi_hba->sas_addr,	SAS_ADDR_SIZE);
904806bb768SJohn Garry 	identify_frame.phy_id = phy_no;
905806bb768SJohn Garry 	identify_buffer = (u32 *)(&identify_frame);
906806bb768SJohn Garry 
907806bb768SJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0,
908806bb768SJohn Garry 			__swab32(identify_buffer[0]));
909806bb768SJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1,
910d82debecSJohn Garry 			__swab32(identify_buffer[1]));
911806bb768SJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2,
912d82debecSJohn Garry 			__swab32(identify_buffer[2]));
913806bb768SJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3,
914d82debecSJohn Garry 			__swab32(identify_buffer[3]));
915806bb768SJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4,
916d82debecSJohn Garry 			__swab32(identify_buffer[4]));
917806bb768SJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5,
918806bb768SJohn Garry 			__swab32(identify_buffer[5]));
919806bb768SJohn Garry }
920806bb768SJohn Garry 
setup_itct_v2_hw(struct hisi_hba * hisi_hba,struct hisi_sas_device * sas_dev)92185b2c3c0SJohn Garry static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
92285b2c3c0SJohn Garry 			     struct hisi_sas_device *sas_dev)
92385b2c3c0SJohn Garry {
92485b2c3c0SJohn Garry 	struct domain_device *device = sas_dev->sas_device;
92511b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
92685b2c3c0SJohn Garry 	u64 qw0, device_id = sas_dev->device_id;
92785b2c3c0SJohn Garry 	struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
92885b2c3c0SJohn Garry 	struct domain_device *parent_dev = device->parent;
9292e244f0fSJohn Garry 	struct asd_sas_port *sas_port = device->port;
9302e244f0fSJohn Garry 	struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
931735bcc77SJohn Garry 	u64 sas_addr;
93285b2c3c0SJohn Garry 
93385b2c3c0SJohn Garry 	memset(itct, 0, sizeof(*itct));
93485b2c3c0SJohn Garry 
93585b2c3c0SJohn Garry 	/* qw0 */
93685b2c3c0SJohn Garry 	qw0 = 0;
93785b2c3c0SJohn Garry 	switch (sas_dev->dev_type) {
93885b2c3c0SJohn Garry 	case SAS_END_DEVICE:
93985b2c3c0SJohn Garry 	case SAS_EDGE_EXPANDER_DEVICE:
94085b2c3c0SJohn Garry 	case SAS_FANOUT_EXPANDER_DEVICE:
94185b2c3c0SJohn Garry 		qw0 = HISI_SAS_DEV_TYPE_SSP << ITCT_HDR_DEV_TYPE_OFF;
94285b2c3c0SJohn Garry 		break;
94385b2c3c0SJohn Garry 	case SAS_SATA_DEV:
94456cc74b9SJohn Garry 	case SAS_SATA_PENDING:
945924a3541SJohn Garry 		if (parent_dev && dev_is_expander(parent_dev->dev_type))
94685b2c3c0SJohn Garry 			qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF;
94785b2c3c0SJohn Garry 		else
94885b2c3c0SJohn Garry 			qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF;
94985b2c3c0SJohn Garry 		break;
95085b2c3c0SJohn Garry 	default:
95185b2c3c0SJohn Garry 		dev_warn(dev, "setup itct: unsupported dev type (%d)\n",
95285b2c3c0SJohn Garry 			 sas_dev->dev_type);
95385b2c3c0SJohn Garry 	}
95485b2c3c0SJohn Garry 
95585b2c3c0SJohn Garry 	qw0 |= ((1 << ITCT_HDR_VALID_OFF) |
95675249268SJohn Garry 		(device->linkrate << ITCT_HDR_MCR_OFF) |
95785b2c3c0SJohn Garry 		(1 << ITCT_HDR_VLN_OFF) |
958c399acfbSXiang Chen 		(ITCT_HDR_SMP_TIMEOUT << ITCT_HDR_SMP_TIMEOUT_OFF) |
959c399acfbSXiang Chen 		(1 << ITCT_HDR_AWT_CONTINUE_OFF) |
96085b2c3c0SJohn Garry 		(port->id << ITCT_HDR_PORT_ID_OFF));
96185b2c3c0SJohn Garry 	itct->qw0 = cpu_to_le64(qw0);
96285b2c3c0SJohn Garry 
96385b2c3c0SJohn Garry 	/* qw1 */
964735bcc77SJohn Garry 	memcpy(&sas_addr, device->sas_addr, SAS_ADDR_SIZE);
965735bcc77SJohn Garry 	itct->sas_addr = cpu_to_le64(__swab64(sas_addr));
96685b2c3c0SJohn Garry 
96785b2c3c0SJohn Garry 	/* qw2 */
968f76a0b49SJohn Garry 	if (!dev_is_sata(device))
969c399acfbSXiang Chen 		itct->qw2 = cpu_to_le64((5000ULL << ITCT_HDR_INLT_OFF) |
970f76a0b49SJohn Garry 					(0x1ULL << ITCT_HDR_BITLT_OFF) |
971f76a0b49SJohn Garry 					(0x32ULL << ITCT_HDR_MCTLT_OFF) |
972f76a0b49SJohn Garry 					(0x1ULL << ITCT_HDR_RTOLT_OFF));
97385b2c3c0SJohn Garry }
97485b2c3c0SJohn Garry 
clear_itct_v2_hw(struct hisi_hba * hisi_hba,struct hisi_sas_device * sas_dev)9758fa9a7bdSXiang Chen static int clear_itct_v2_hw(struct hisi_hba *hisi_hba,
97685b2c3c0SJohn Garry 			    struct hisi_sas_device *sas_dev)
97785b2c3c0SJohn Garry {
978640acc9aSXiang Chen 	DECLARE_COMPLETION_ONSTACK(completion);
979c399acfbSXiang Chen 	u64 dev_id = sas_dev->device_id;
98085b2c3c0SJohn Garry 	struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
98185b2c3c0SJohn Garry 	u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
9828fa9a7bdSXiang Chen 	struct device *dev = hisi_hba->dev;
98385b2c3c0SJohn Garry 	int i;
98485b2c3c0SJohn Garry 
985640acc9aSXiang Chen 	sas_dev->completion = &completion;
986640acc9aSXiang Chen 
98785b2c3c0SJohn Garry 	/* clear the itct interrupt state */
98885b2c3c0SJohn Garry 	if (ENT_INT_SRC3_ITC_INT_MSK & reg_val)
98985b2c3c0SJohn Garry 		hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
99085b2c3c0SJohn Garry 				 ENT_INT_SRC3_ITC_INT_MSK);
99185b2c3c0SJohn Garry 
9928fa9a7bdSXiang Chen 	/* need to set register twice to clear ITCT for v2 hw */
99385b2c3c0SJohn Garry 	for (i = 0; i < 2; i++) {
994640acc9aSXiang Chen 		reg_val = ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
99585b2c3c0SJohn Garry 		hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val);
9968fa9a7bdSXiang Chen 		if (!wait_for_completion_timeout(sas_dev->completion,
9972f12a499SLuo Jiaxing 						 HISI_SAS_CLEAR_ITCT_TIMEOUT)) {
9988fa9a7bdSXiang Chen 			dev_warn(dev, "failed to clear ITCT\n");
9998fa9a7bdSXiang Chen 			return -ETIMEDOUT;
10008fa9a7bdSXiang Chen 		}
100185b2c3c0SJohn Garry 
1002c399acfbSXiang Chen 		memset(itct, 0, sizeof(struct hisi_sas_itct));
100385b2c3c0SJohn Garry 	}
10048fa9a7bdSXiang Chen 	return 0;
100585b2c3c0SJohn Garry }
100685b2c3c0SJohn Garry 
free_device_v2_hw(struct hisi_sas_device * sas_dev)10070258141aSXiaofei Tan static void free_device_v2_hw(struct hisi_sas_device *sas_dev)
10080258141aSXiaofei Tan {
10090258141aSXiaofei Tan 	struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
10100258141aSXiaofei Tan 
10110258141aSXiaofei Tan 	/* SoC bug workaround */
10120258141aSXiaofei Tan 	if (dev_is_sata(sas_dev->sas_device))
10130258141aSXiaofei Tan 		clear_bit(sas_dev->sata_idx, hisi_hba->sata_dev_bitmap);
10140258141aSXiaofei Tan }
10150258141aSXiaofei Tan 
reset_hw_v2_hw(struct hisi_hba * hisi_hba)101694eac9e1SJohn Garry static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
101794eac9e1SJohn Garry {
101894eac9e1SJohn Garry 	int i, reset_val;
101994eac9e1SJohn Garry 	u32 val;
102094eac9e1SJohn Garry 	unsigned long end_time;
102111b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
102294eac9e1SJohn Garry 
102394eac9e1SJohn Garry 	/* The mask needs to be set depending on the number of phys */
102494eac9e1SJohn Garry 	if (hisi_hba->n_phy == 9)
102594eac9e1SJohn Garry 		reset_val = 0x1fffff;
102694eac9e1SJohn Garry 	else
102794eac9e1SJohn Garry 		reset_val = 0x7ffff;
102894eac9e1SJohn Garry 
102994eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0);
103094eac9e1SJohn Garry 
103194eac9e1SJohn Garry 	/* Disable all of the PHYs */
103294eac9e1SJohn Garry 	for (i = 0; i < hisi_hba->n_phy; i++) {
103394eac9e1SJohn Garry 		u32 phy_cfg = hisi_sas_phy_read32(hisi_hba, i, PHY_CFG);
103494eac9e1SJohn Garry 
103594eac9e1SJohn Garry 		phy_cfg &= ~PHY_CTRL_RESET_MSK;
103694eac9e1SJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, PHY_CFG, phy_cfg);
103794eac9e1SJohn Garry 	}
103894eac9e1SJohn Garry 	udelay(50);
103994eac9e1SJohn Garry 
104094eac9e1SJohn Garry 	/* Ensure DMA tx & rx idle */
104194eac9e1SJohn Garry 	for (i = 0; i < hisi_hba->n_phy; i++) {
104294eac9e1SJohn Garry 		u32 dma_tx_status, dma_rx_status;
104394eac9e1SJohn Garry 
104494eac9e1SJohn Garry 		end_time = jiffies + msecs_to_jiffies(1000);
104594eac9e1SJohn Garry 
104694eac9e1SJohn Garry 		while (1) {
104794eac9e1SJohn Garry 			dma_tx_status = hisi_sas_phy_read32(hisi_hba, i,
104894eac9e1SJohn Garry 							    DMA_TX_STATUS);
104994eac9e1SJohn Garry 			dma_rx_status = hisi_sas_phy_read32(hisi_hba, i,
105094eac9e1SJohn Garry 							    DMA_RX_STATUS);
105194eac9e1SJohn Garry 
105294eac9e1SJohn Garry 			if (!(dma_tx_status & DMA_TX_STATUS_BUSY_MSK) &&
105394eac9e1SJohn Garry 				!(dma_rx_status & DMA_RX_STATUS_BUSY_MSK))
105494eac9e1SJohn Garry 				break;
105594eac9e1SJohn Garry 
105694eac9e1SJohn Garry 			msleep(20);
105794eac9e1SJohn Garry 			if (time_after(jiffies, end_time))
105894eac9e1SJohn Garry 				return -EIO;
105994eac9e1SJohn Garry 		}
106094eac9e1SJohn Garry 	}
106194eac9e1SJohn Garry 
106294eac9e1SJohn Garry 	/* Ensure axi bus idle */
106394eac9e1SJohn Garry 	end_time = jiffies + msecs_to_jiffies(1000);
106494eac9e1SJohn Garry 	while (1) {
106594eac9e1SJohn Garry 		u32 axi_status =
106694eac9e1SJohn Garry 			hisi_sas_read32(hisi_hba, AXI_CFG);
106794eac9e1SJohn Garry 
106894eac9e1SJohn Garry 		if (axi_status == 0)
106994eac9e1SJohn Garry 			break;
107094eac9e1SJohn Garry 
107194eac9e1SJohn Garry 		msleep(20);
107294eac9e1SJohn Garry 		if (time_after(jiffies, end_time))
107394eac9e1SJohn Garry 			return -EIO;
107494eac9e1SJohn Garry 	}
107594eac9e1SJohn Garry 
107650408712SJohn Garry 	if (ACPI_HANDLE(dev)) {
107750408712SJohn Garry 		acpi_status s;
107850408712SJohn Garry 
107950408712SJohn Garry 		s = acpi_evaluate_object(ACPI_HANDLE(dev), "_RST", NULL, NULL);
108050408712SJohn Garry 		if (ACPI_FAILURE(s)) {
108150408712SJohn Garry 			dev_err(dev, "Reset failed\n");
108250408712SJohn Garry 			return -EIO;
108350408712SJohn Garry 		}
108450408712SJohn Garry 	} else if (hisi_hba->ctrl) {
108594eac9e1SJohn Garry 		/* reset and disable clock*/
108694eac9e1SJohn Garry 		regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg,
108794eac9e1SJohn Garry 				reset_val);
108894eac9e1SJohn Garry 		regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg + 4,
108994eac9e1SJohn Garry 				reset_val);
109094eac9e1SJohn Garry 		msleep(1);
109194eac9e1SJohn Garry 		regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
109294eac9e1SJohn Garry 		if (reset_val != (val & reset_val)) {
109394eac9e1SJohn Garry 			dev_err(dev, "SAS reset fail.\n");
109494eac9e1SJohn Garry 			return -EIO;
109594eac9e1SJohn Garry 		}
109694eac9e1SJohn Garry 
109794eac9e1SJohn Garry 		/* De-reset and enable clock*/
109894eac9e1SJohn Garry 		regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg + 4,
109994eac9e1SJohn Garry 				reset_val);
110094eac9e1SJohn Garry 		regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg,
110194eac9e1SJohn Garry 				reset_val);
110294eac9e1SJohn Garry 		msleep(1);
110394eac9e1SJohn Garry 		regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg,
110494eac9e1SJohn Garry 				&val);
110594eac9e1SJohn Garry 		if (val & reset_val) {
110694eac9e1SJohn Garry 			dev_err(dev, "SAS de-reset fail.\n");
110794eac9e1SJohn Garry 			return -EIO;
110894eac9e1SJohn Garry 		}
1109edafeef4SXiang Chen 	} else {
1110edafeef4SXiang Chen 		dev_err(dev, "no reset method\n");
1111edafeef4SXiang Chen 		return -EINVAL;
1112edafeef4SXiang Chen 	}
111394eac9e1SJohn Garry 
111494eac9e1SJohn Garry 	return 0;
111594eac9e1SJohn Garry }
111694eac9e1SJohn Garry 
1117c7b9d369SXiaofei Tan /* This function needs to be called after resetting SAS controller. */
phys_reject_stp_links_v2_hw(struct hisi_hba * hisi_hba)1118c7b9d369SXiaofei Tan static void phys_reject_stp_links_v2_hw(struct hisi_hba *hisi_hba)
1119c7b9d369SXiaofei Tan {
1120c7b9d369SXiaofei Tan 	u32 cfg;
1121c7b9d369SXiaofei Tan 	int phy_no;
1122c7b9d369SXiaofei Tan 
1123c7b9d369SXiaofei Tan 	hisi_hba->reject_stp_links_msk = (1 << hisi_hba->n_phy) - 1;
1124c7b9d369SXiaofei Tan 	for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
1125c7b9d369SXiaofei Tan 		cfg = hisi_sas_phy_read32(hisi_hba, phy_no, CON_CONTROL);
1126c7b9d369SXiaofei Tan 		if (!(cfg & CON_CONTROL_CFG_OPEN_ACC_STP_MSK))
1127c7b9d369SXiaofei Tan 			continue;
1128c7b9d369SXiaofei Tan 
1129c7b9d369SXiaofei Tan 		cfg &= ~CON_CONTROL_CFG_OPEN_ACC_STP_MSK;
1130c7b9d369SXiaofei Tan 		hisi_sas_phy_write32(hisi_hba, phy_no, CON_CONTROL, cfg);
1131c7b9d369SXiaofei Tan 	}
1132c7b9d369SXiaofei Tan }
1133c7b9d369SXiaofei Tan 
phys_try_accept_stp_links_v2_hw(struct hisi_hba * hisi_hba)1134c7b9d369SXiaofei Tan static void phys_try_accept_stp_links_v2_hw(struct hisi_hba *hisi_hba)
1135c7b9d369SXiaofei Tan {
1136c7b9d369SXiaofei Tan 	int phy_no;
1137c7b9d369SXiaofei Tan 	u32 dma_tx_dfx1;
1138c7b9d369SXiaofei Tan 
1139c7b9d369SXiaofei Tan 	for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
1140c7b9d369SXiaofei Tan 		if (!(hisi_hba->reject_stp_links_msk & BIT(phy_no)))
1141c7b9d369SXiaofei Tan 			continue;
1142c7b9d369SXiaofei Tan 
1143c7b9d369SXiaofei Tan 		dma_tx_dfx1 = hisi_sas_phy_read32(hisi_hba, phy_no,
1144c7b9d369SXiaofei Tan 						DMA_TX_DFX1);
1145c7b9d369SXiaofei Tan 		if (dma_tx_dfx1 & DMA_TX_DFX1_IPTT_MSK) {
1146c7b9d369SXiaofei Tan 			u32 cfg = hisi_sas_phy_read32(hisi_hba,
1147c7b9d369SXiaofei Tan 				phy_no, CON_CONTROL);
1148c7b9d369SXiaofei Tan 
1149c7b9d369SXiaofei Tan 			cfg |= CON_CONTROL_CFG_OPEN_ACC_STP_MSK;
1150c7b9d369SXiaofei Tan 			hisi_sas_phy_write32(hisi_hba, phy_no,
1151c7b9d369SXiaofei Tan 				CON_CONTROL, cfg);
1152c7b9d369SXiaofei Tan 			clear_bit(phy_no, &hisi_hba->reject_stp_links_msk);
1153c7b9d369SXiaofei Tan 		}
1154c7b9d369SXiaofei Tan 	}
1155c7b9d369SXiaofei Tan }
1156c7b9d369SXiaofei Tan 
115767c2bf23SXiaofei Tan static const struct signal_attenuation_s x6000 = {9200, 0, 10476};
115867c2bf23SXiaofei Tan static const struct sig_atten_lu_s sig_atten_lu[] = {
115967c2bf23SXiaofei Tan 	{ &x6000, 0x3016a68 },
116067c2bf23SXiaofei Tan };
116167c2bf23SXiaofei Tan 
init_reg_v2_hw(struct hisi_hba * hisi_hba)116294eac9e1SJohn Garry static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
116394eac9e1SJohn Garry {
116411b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
116567c2bf23SXiaofei Tan 	u32 sas_phy_ctrl = 0x30b9908;
116667c2bf23SXiaofei Tan 	u32 signal[3];
116794eac9e1SJohn Garry 	int i;
116894eac9e1SJohn Garry 
116994eac9e1SJohn Garry 	/* Global registers init */
117094eac9e1SJohn Garry 
117194eac9e1SJohn Garry 	/* Deal with am-max-transmissions quirk */
117250408712SJohn Garry 	if (device_property_present(dev, "hip06-sas-v2-quirk-amt")) {
117394eac9e1SJohn Garry 		hisi_sas_write32(hisi_hba, AM_CFG_MAX_TRANS, 0x2020);
117494eac9e1SJohn Garry 		hisi_sas_write32(hisi_hba, AM_CFG_SINGLE_PORT_MAX_TRANS,
117594eac9e1SJohn Garry 				 0x2020);
117694eac9e1SJohn Garry 	} /* Else, use defaults -> do nothing */
117794eac9e1SJohn Garry 
117894eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
117994eac9e1SJohn Garry 			 (u32)((1ULL << hisi_hba->queue_count) - 1));
118094eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, AXI_USER1, 0xc0000000);
118194eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, AXI_USER2, 0x10000);
1182f1dc7518SJohn Garry 	hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x0);
118394eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL, 0x7FF);
118494eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, OPENA_WT_CONTI_TIME, 0x1);
118594eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, I_T_NEXUS_LOSS_TIME, 0x1F4);
1186f76a0b49SJohn Garry 	hisi_sas_write32(hisi_hba, MAX_CON_TIME_LIMIT_TIME, 0x32);
118794eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, BUS_INACTIVE_LIMIT_TIME, 0x1);
118894eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1);
118994eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, HGC_ERR_STAT_EN, 0x1);
119094eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, HGC_GET_ITV_TIME, 0x1);
1191f1dc7518SJohn Garry 	hisi_sas_write32(hisi_hba, INT_COAL_EN, 0xc);
1192f1dc7518SJohn Garry 	hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x60);
1193f1dc7518SJohn Garry 	hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x3);
119494eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, ENT_INT_COAL_TIME, 0x1);
119594eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, ENT_INT_COAL_CNT, 0x1);
119694eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, OQ_INT_SRC, 0x0);
119794eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, ENT_INT_SRC1, 0xffffffff);
119894eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, ENT_INT_SRC2, 0xffffffff);
119994eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 0xffffffff);
120094eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0x7efefefe);
120194eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0x7efefefe);
1202640acc9aSXiang Chen 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0x7ffe20fe);
1203d3b688d3SXiang Chen 	hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0xfff00c30);
120494eac9e1SJohn Garry 	for (i = 0; i < hisi_hba->queue_count; i++)
120594eac9e1SJohn Garry 		hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK + 0x4 * i, 0);
120694eac9e1SJohn Garry 
120794eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, AXI_AHB_CLK_CFG, 1);
120894eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
120994eac9e1SJohn Garry 
121067c2bf23SXiaofei Tan 	/* Get sas_phy_ctrl value to deal with TX FFE issue. */
121167c2bf23SXiaofei Tan 	if (!device_property_read_u32_array(dev, "hisilicon,signal-attenuation",
121267c2bf23SXiaofei Tan 					    signal, ARRAY_SIZE(signal))) {
121367c2bf23SXiaofei Tan 		for (i = 0; i < ARRAY_SIZE(sig_atten_lu); i++) {
121467c2bf23SXiaofei Tan 			const struct sig_atten_lu_s *lookup = &sig_atten_lu[i];
121567c2bf23SXiaofei Tan 			const struct signal_attenuation_s *att = lookup->att;
121667c2bf23SXiaofei Tan 
121767c2bf23SXiaofei Tan 			if ((signal[0] == att->de_emphasis) &&
121867c2bf23SXiaofei Tan 			    (signal[1] == att->preshoot) &&
121967c2bf23SXiaofei Tan 			    (signal[2] == att->boost)) {
122067c2bf23SXiaofei Tan 				sas_phy_ctrl = lookup->sas_phy_ctrl;
122167c2bf23SXiaofei Tan 				break;
122267c2bf23SXiaofei Tan 			}
122367c2bf23SXiaofei Tan 		}
122467c2bf23SXiaofei Tan 
122567c2bf23SXiaofei Tan 		if (i == ARRAY_SIZE(sig_atten_lu))
122667c2bf23SXiaofei Tan 			dev_warn(dev, "unknown signal attenuation values, using default PHY ctrl config\n");
122767c2bf23SXiaofei Tan 	}
122867c2bf23SXiaofei Tan 
122994eac9e1SJohn Garry 	for (i = 0; i < hisi_hba->n_phy; i++) {
1230c2c1d9deSXiang Chen 		struct hisi_sas_phy *phy = &hisi_hba->phy[i];
1231c2c1d9deSXiang Chen 		struct asd_sas_phy *sas_phy = &phy->sas_phy;
1232c2c1d9deSXiang Chen 		u32 prog_phy_link_rate = 0x800;
1233c2c1d9deSXiang Chen 
1234c2c1d9deSXiang Chen 		if (!sas_phy->phy || (sas_phy->phy->maximum_linkrate <
1235c2c1d9deSXiang Chen 				SAS_LINK_RATE_1_5_GBPS)) {
1236c2c1d9deSXiang Chen 			prog_phy_link_rate = 0x855;
1237c2c1d9deSXiang Chen 		} else {
1238c2c1d9deSXiang Chen 			enum sas_linkrate max = sas_phy->phy->maximum_linkrate;
1239c2c1d9deSXiang Chen 
1240c2c1d9deSXiang Chen 			prog_phy_link_rate =
1241c2c1d9deSXiang Chen 				hisi_sas_get_prog_phy_linkrate_mask(max) |
1242c2c1d9deSXiang Chen 				0x800;
1243c2c1d9deSXiang Chen 		}
1244c2c1d9deSXiang Chen 		hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE,
1245c2c1d9deSXiang Chen 			prog_phy_link_rate);
124667c2bf23SXiaofei Tan 		hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, sas_phy_ctrl);
124794eac9e1SJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d);
12489c81e2cfSJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, SL_CONTROL, 0x0);
12499c81e2cfSJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, TXID_AUTO, 0x2);
1250f1dc7518SJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0x8);
125194eac9e1SJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff);
125294eac9e1SJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
1253d3b688d3SXiang Chen 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xfff87fff);
125494eac9e1SJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
125572f7fc30SXiaofei Tan 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xff857fff);
1256057c3d1fSXiaofei Tan 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbfe);
1257f1dc7518SJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x13f801fc);
125894eac9e1SJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0);
125994eac9e1SJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0);
126094eac9e1SJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_DWS_RESET_MSK, 0x0);
126194eac9e1SJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_PHY_ENA_MSK, 0x0);
126294eac9e1SJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, SL_RX_BCAST_CHK_MSK, 0x0);
126394eac9e1SJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT_COAL_EN, 0x0);
126494eac9e1SJohn Garry 		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x0);
12653bc45af8SJohn Garry 		if (hisi_hba->refclk_frequency_mhz == 66)
126694eac9e1SJohn Garry 			hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL, 0x199B694);
12673bc45af8SJohn Garry 		/* else, do nothing -> leave it how you found it */
126894eac9e1SJohn Garry 	}
126994eac9e1SJohn Garry 
127094eac9e1SJohn Garry 	for (i = 0; i < hisi_hba->queue_count; i++) {
127194eac9e1SJohn Garry 		/* Delivery queue */
127294eac9e1SJohn Garry 		hisi_sas_write32(hisi_hba,
127394eac9e1SJohn Garry 				 DLVRY_Q_0_BASE_ADDR_HI + (i * 0x14),
127494eac9e1SJohn Garry 				 upper_32_bits(hisi_hba->cmd_hdr_dma[i]));
127594eac9e1SJohn Garry 
127694eac9e1SJohn Garry 		hisi_sas_write32(hisi_hba, DLVRY_Q_0_BASE_ADDR_LO + (i * 0x14),
127794eac9e1SJohn Garry 				 lower_32_bits(hisi_hba->cmd_hdr_dma[i]));
127894eac9e1SJohn Garry 
127994eac9e1SJohn Garry 		hisi_sas_write32(hisi_hba, DLVRY_Q_0_DEPTH + (i * 0x14),
128094eac9e1SJohn Garry 				 HISI_SAS_QUEUE_SLOTS);
128194eac9e1SJohn Garry 
128294eac9e1SJohn Garry 		/* Completion queue */
128394eac9e1SJohn Garry 		hisi_sas_write32(hisi_hba, COMPL_Q_0_BASE_ADDR_HI + (i * 0x14),
128494eac9e1SJohn Garry 				 upper_32_bits(hisi_hba->complete_hdr_dma[i]));
128594eac9e1SJohn Garry 
128694eac9e1SJohn Garry 		hisi_sas_write32(hisi_hba, COMPL_Q_0_BASE_ADDR_LO + (i * 0x14),
128794eac9e1SJohn Garry 				 lower_32_bits(hisi_hba->complete_hdr_dma[i]));
128894eac9e1SJohn Garry 
128994eac9e1SJohn Garry 		hisi_sas_write32(hisi_hba, COMPL_Q_0_DEPTH + (i * 0x14),
129094eac9e1SJohn Garry 				 HISI_SAS_QUEUE_SLOTS);
129194eac9e1SJohn Garry 	}
129294eac9e1SJohn Garry 
129394eac9e1SJohn Garry 	/* itct */
129494eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_LO,
129594eac9e1SJohn Garry 			 lower_32_bits(hisi_hba->itct_dma));
129694eac9e1SJohn Garry 
129794eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_HI,
129894eac9e1SJohn Garry 			 upper_32_bits(hisi_hba->itct_dma));
129994eac9e1SJohn Garry 
130094eac9e1SJohn Garry 	/* iost */
130194eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_LO,
130294eac9e1SJohn Garry 			 lower_32_bits(hisi_hba->iost_dma));
130394eac9e1SJohn Garry 
130494eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_HI,
130594eac9e1SJohn Garry 			 upper_32_bits(hisi_hba->iost_dma));
130694eac9e1SJohn Garry 
130794eac9e1SJohn Garry 	/* breakpoint */
130894eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, IO_BROKEN_MSG_ADDR_LO,
130994eac9e1SJohn Garry 			 lower_32_bits(hisi_hba->breakpoint_dma));
131094eac9e1SJohn Garry 
131194eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, IO_BROKEN_MSG_ADDR_HI,
131294eac9e1SJohn Garry 			 upper_32_bits(hisi_hba->breakpoint_dma));
131394eac9e1SJohn Garry 
131494eac9e1SJohn Garry 	/* SATA broken msg */
131594eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, IO_SATA_BROKEN_MSG_ADDR_LO,
131694eac9e1SJohn Garry 			 lower_32_bits(hisi_hba->sata_breakpoint_dma));
131794eac9e1SJohn Garry 
131894eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, IO_SATA_BROKEN_MSG_ADDR_HI,
131994eac9e1SJohn Garry 			 upper_32_bits(hisi_hba->sata_breakpoint_dma));
132094eac9e1SJohn Garry 
132194eac9e1SJohn Garry 	/* SATA initial fis */
132294eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, SATA_INITI_D2H_STORE_ADDR_LO,
132394eac9e1SJohn Garry 			 lower_32_bits(hisi_hba->initial_fis_dma));
132494eac9e1SJohn Garry 
132594eac9e1SJohn Garry 	hisi_sas_write32(hisi_hba, SATA_INITI_D2H_STORE_ADDR_HI,
132694eac9e1SJohn Garry 			 upper_32_bits(hisi_hba->initial_fis_dma));
132794eac9e1SJohn Garry }
132894eac9e1SJohn Garry 
link_timeout_enable_link(struct timer_list * t)132977570eedSKees Cook static void link_timeout_enable_link(struct timer_list *t)
1330f2f89c32SXiang Chen {
133177570eedSKees Cook 	struct hisi_hba *hisi_hba = from_timer(hisi_hba, t, timer);
1332f2f89c32SXiang Chen 	int i, reg_val;
1333f2f89c32SXiang Chen 
1334f2f89c32SXiang Chen 	for (i = 0; i < hisi_hba->n_phy; i++) {
1335c7b9d369SXiaofei Tan 		if (hisi_hba->reject_stp_links_msk & BIT(i))
1336c7b9d369SXiaofei Tan 			continue;
1337c7b9d369SXiaofei Tan 
1338f2f89c32SXiang Chen 		reg_val = hisi_sas_phy_read32(hisi_hba, i, CON_CONTROL);
1339f2f89c32SXiang Chen 		if (!(reg_val & BIT(0))) {
1340f2f89c32SXiang Chen 			hisi_sas_phy_write32(hisi_hba, i,
1341f2f89c32SXiang Chen 					CON_CONTROL, 0x7);
1342f2f89c32SXiang Chen 			break;
1343f2f89c32SXiang Chen 		}
1344f2f89c32SXiang Chen 	}
1345f2f89c32SXiang Chen 
1346841b86f3SKees Cook 	hisi_hba->timer.function = link_timeout_disable_link;
1347f2f89c32SXiang Chen 	mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(900));
1348f2f89c32SXiang Chen }
1349f2f89c32SXiang Chen 
link_timeout_disable_link(struct timer_list * t)135077570eedSKees Cook static void link_timeout_disable_link(struct timer_list *t)
1351f2f89c32SXiang Chen {
135277570eedSKees Cook 	struct hisi_hba *hisi_hba = from_timer(hisi_hba, t, timer);
1353f2f89c32SXiang Chen 	int i, reg_val;
1354f2f89c32SXiang Chen 
1355f2f89c32SXiang Chen 	reg_val = hisi_sas_read32(hisi_hba, PHY_STATE);
1356f2f89c32SXiang Chen 	for (i = 0; i < hisi_hba->n_phy && reg_val; i++) {
1357c7b9d369SXiaofei Tan 		if (hisi_hba->reject_stp_links_msk & BIT(i))
1358c7b9d369SXiaofei Tan 			continue;
1359c7b9d369SXiaofei Tan 
1360f2f89c32SXiang Chen 		if (reg_val & BIT(i)) {
1361f2f89c32SXiang Chen 			hisi_sas_phy_write32(hisi_hba, i,
1362f2f89c32SXiang Chen 					CON_CONTROL, 0x6);
1363f2f89c32SXiang Chen 			break;
1364f2f89c32SXiang Chen 		}
1365f2f89c32SXiang Chen 	}
1366f2f89c32SXiang Chen 
1367841b86f3SKees Cook 	hisi_hba->timer.function = link_timeout_enable_link;
1368f2f89c32SXiang Chen 	mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(100));
1369f2f89c32SXiang Chen }
1370f2f89c32SXiang Chen 
set_link_timer_quirk(struct hisi_hba * hisi_hba)1371f2f89c32SXiang Chen static void set_link_timer_quirk(struct hisi_hba *hisi_hba)
1372f2f89c32SXiang Chen {
1373841b86f3SKees Cook 	hisi_hba->timer.function = link_timeout_disable_link;
1374f2f89c32SXiang Chen 	hisi_hba->timer.expires = jiffies + msecs_to_jiffies(1000);
1375f2f89c32SXiang Chen 	add_timer(&hisi_hba->timer);
1376f2f89c32SXiang Chen }
1377f2f89c32SXiang Chen 
hw_init_v2_hw(struct hisi_hba * hisi_hba)137894eac9e1SJohn Garry static int hw_init_v2_hw(struct hisi_hba *hisi_hba)
137994eac9e1SJohn Garry {
138011b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
138194eac9e1SJohn Garry 	int rc;
138294eac9e1SJohn Garry 
138394eac9e1SJohn Garry 	rc = reset_hw_v2_hw(hisi_hba);
138494eac9e1SJohn Garry 	if (rc) {
1385b601577dSXiang Chen 		dev_err(dev, "hisi_sas_reset_hw failed, rc=%d\n", rc);
138694eac9e1SJohn Garry 		return rc;
138794eac9e1SJohn Garry 	}
138894eac9e1SJohn Garry 
138994eac9e1SJohn Garry 	msleep(100);
139094eac9e1SJohn Garry 	init_reg_v2_hw(hisi_hba);
139194eac9e1SJohn Garry 
139294eac9e1SJohn Garry 	return 0;
139394eac9e1SJohn Garry }
139494eac9e1SJohn Garry 
enable_phy_v2_hw(struct hisi_hba * hisi_hba,int phy_no)139529a20428SJohn Garry static void enable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
139629a20428SJohn Garry {
139729a20428SJohn Garry 	u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
139829a20428SJohn Garry 
139929a20428SJohn Garry 	cfg |= PHY_CFG_ENA_MSK;
140029a20428SJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
140129a20428SJohn Garry }
140229a20428SJohn Garry 
is_sata_phy_v2_hw(struct hisi_hba * hisi_hba,int phy_no)14034935933eSXiaofei Tan static bool is_sata_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
14044935933eSXiaofei Tan {
14054935933eSXiaofei Tan 	u32 context;
14064935933eSXiaofei Tan 
14074935933eSXiaofei Tan 	context = hisi_sas_read32(hisi_hba, PHY_CONTEXT);
14084935933eSXiaofei Tan 	if (context & (1 << phy_no))
14094935933eSXiaofei Tan 		return true;
14104935933eSXiaofei Tan 
14114935933eSXiaofei Tan 	return false;
14124935933eSXiaofei Tan }
14134935933eSXiaofei Tan 
tx_fifo_is_empty_v2_hw(struct hisi_hba * hisi_hba,int phy_no)1414819cbf18SXiaofei Tan static bool tx_fifo_is_empty_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
1415819cbf18SXiaofei Tan {
1416819cbf18SXiaofei Tan 	u32 dfx_val;
1417819cbf18SXiaofei Tan 
1418819cbf18SXiaofei Tan 	dfx_val = hisi_sas_phy_read32(hisi_hba, phy_no, DMA_TX_DFX1);
1419819cbf18SXiaofei Tan 
1420819cbf18SXiaofei Tan 	if (dfx_val & BIT(16))
1421819cbf18SXiaofei Tan 		return false;
1422819cbf18SXiaofei Tan 
1423819cbf18SXiaofei Tan 	return true;
1424819cbf18SXiaofei Tan }
1425819cbf18SXiaofei Tan 
axi_bus_is_idle_v2_hw(struct hisi_hba * hisi_hba,int phy_no)1426819cbf18SXiaofei Tan static bool axi_bus_is_idle_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
1427819cbf18SXiaofei Tan {
1428819cbf18SXiaofei Tan 	int i, max_loop = 1000;
142911b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
1430819cbf18SXiaofei Tan 	u32 status, axi_status, dfx_val, dfx_tx_val;
1431819cbf18SXiaofei Tan 
1432819cbf18SXiaofei Tan 	for (i = 0; i < max_loop; i++) {
1433819cbf18SXiaofei Tan 		status = hisi_sas_read32_relaxed(hisi_hba,
1434819cbf18SXiaofei Tan 			AXI_MASTER_CFG_BASE + AM_CURR_TRANS_RETURN);
1435819cbf18SXiaofei Tan 
1436819cbf18SXiaofei Tan 		axi_status = hisi_sas_read32(hisi_hba, AXI_CFG);
1437819cbf18SXiaofei Tan 		dfx_val = hisi_sas_phy_read32(hisi_hba, phy_no, DMA_TX_DFX1);
1438819cbf18SXiaofei Tan 		dfx_tx_val = hisi_sas_phy_read32(hisi_hba,
1439819cbf18SXiaofei Tan 			phy_no, DMA_TX_FIFO_DFX0);
1440819cbf18SXiaofei Tan 
1441819cbf18SXiaofei Tan 		if ((status == 0x3) && (axi_status == 0x0) &&
1442819cbf18SXiaofei Tan 		    (dfx_val & BIT(20)) && (dfx_tx_val & BIT(10)))
1443819cbf18SXiaofei Tan 			return true;
1444819cbf18SXiaofei Tan 		udelay(10);
1445819cbf18SXiaofei Tan 	}
1446819cbf18SXiaofei Tan 	dev_err(dev, "bus is not idle phy%d, axi150:0x%x axi100:0x%x port204:0x%x port240:0x%x\n",
1447819cbf18SXiaofei Tan 			phy_no, status, axi_status,
1448819cbf18SXiaofei Tan 			dfx_val, dfx_tx_val);
1449819cbf18SXiaofei Tan 	return false;
1450819cbf18SXiaofei Tan }
1451819cbf18SXiaofei Tan 
wait_io_done_v2_hw(struct hisi_hba * hisi_hba,int phy_no)1452819cbf18SXiaofei Tan static bool wait_io_done_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
1453819cbf18SXiaofei Tan {
1454819cbf18SXiaofei Tan 	int i, max_loop = 1000;
145511b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
1456819cbf18SXiaofei Tan 	u32 status, tx_dfx0;
1457819cbf18SXiaofei Tan 
1458819cbf18SXiaofei Tan 	for (i = 0; i < max_loop; i++) {
1459819cbf18SXiaofei Tan 		status = hisi_sas_phy_read32(hisi_hba, phy_no, LINK_DFX2);
1460819cbf18SXiaofei Tan 		status = (status & 0x3fc0) >> 6;
1461819cbf18SXiaofei Tan 
1462819cbf18SXiaofei Tan 		if (status != 0x1)
1463819cbf18SXiaofei Tan 			return true;
1464819cbf18SXiaofei Tan 
1465819cbf18SXiaofei Tan 		tx_dfx0 = hisi_sas_phy_read32(hisi_hba, phy_no, DMA_TX_DFX0);
1466819cbf18SXiaofei Tan 		if ((tx_dfx0 & 0x1ff) == 0x2)
1467819cbf18SXiaofei Tan 			return true;
1468819cbf18SXiaofei Tan 		udelay(10);
1469819cbf18SXiaofei Tan 	}
1470819cbf18SXiaofei Tan 	dev_err(dev, "IO not done phy%d, port264:0x%x port200:0x%x\n",
1471819cbf18SXiaofei Tan 			phy_no, status, tx_dfx0);
1472819cbf18SXiaofei Tan 	return false;
1473819cbf18SXiaofei Tan }
1474819cbf18SXiaofei Tan 
allowed_disable_phy_v2_hw(struct hisi_hba * hisi_hba,int phy_no)1475819cbf18SXiaofei Tan static bool allowed_disable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
1476819cbf18SXiaofei Tan {
1477819cbf18SXiaofei Tan 	if (tx_fifo_is_empty_v2_hw(hisi_hba, phy_no))
1478819cbf18SXiaofei Tan 		return true;
1479819cbf18SXiaofei Tan 
1480819cbf18SXiaofei Tan 	if (!axi_bus_is_idle_v2_hw(hisi_hba, phy_no))
1481819cbf18SXiaofei Tan 		return false;
1482819cbf18SXiaofei Tan 
1483819cbf18SXiaofei Tan 	if (!wait_io_done_v2_hw(hisi_hba, phy_no))
1484819cbf18SXiaofei Tan 		return false;
1485819cbf18SXiaofei Tan 
1486819cbf18SXiaofei Tan 	return true;
1487819cbf18SXiaofei Tan }
1488819cbf18SXiaofei Tan 
1489819cbf18SXiaofei Tan 
disable_phy_v2_hw(struct hisi_hba * hisi_hba,int phy_no)149063fb11b8SJohn Garry static void disable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
149163fb11b8SJohn Garry {
1492819cbf18SXiaofei Tan 	u32 cfg, axi_val, dfx0_val, txid_auto;
149311b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
149463fb11b8SJohn Garry 
1495819cbf18SXiaofei Tan 	/* Close axi bus. */
1496819cbf18SXiaofei Tan 	axi_val = hisi_sas_read32(hisi_hba, AXI_MASTER_CFG_BASE +
1497819cbf18SXiaofei Tan 				AM_CTRL_GLOBAL);
1498819cbf18SXiaofei Tan 	axi_val |= 0x1;
1499819cbf18SXiaofei Tan 	hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE +
1500819cbf18SXiaofei Tan 		AM_CTRL_GLOBAL, axi_val);
1501819cbf18SXiaofei Tan 
1502819cbf18SXiaofei Tan 	if (is_sata_phy_v2_hw(hisi_hba, phy_no)) {
1503819cbf18SXiaofei Tan 		if (allowed_disable_phy_v2_hw(hisi_hba, phy_no))
1504819cbf18SXiaofei Tan 			goto do_disable;
1505819cbf18SXiaofei Tan 
1506819cbf18SXiaofei Tan 		/* Reset host controller. */
1507819cbf18SXiaofei Tan 		queue_work(hisi_hba->wq, &hisi_hba->rst_work);
1508819cbf18SXiaofei Tan 		return;
1509819cbf18SXiaofei Tan 	}
1510819cbf18SXiaofei Tan 
1511819cbf18SXiaofei Tan 	dfx0_val = hisi_sas_phy_read32(hisi_hba, phy_no, PORT_DFX0);
1512819cbf18SXiaofei Tan 	dfx0_val = (dfx0_val & 0x1fc0) >> 6;
1513819cbf18SXiaofei Tan 	if (dfx0_val != 0x4)
1514819cbf18SXiaofei Tan 		goto do_disable;
1515819cbf18SXiaofei Tan 
1516819cbf18SXiaofei Tan 	if (!tx_fifo_is_empty_v2_hw(hisi_hba, phy_no)) {
1517819cbf18SXiaofei Tan 		dev_warn(dev, "phy%d, wait tx fifo need send break\n",
1518819cbf18SXiaofei Tan 			phy_no);
1519819cbf18SXiaofei Tan 		txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no,
1520819cbf18SXiaofei Tan 					TXID_AUTO);
1521819cbf18SXiaofei Tan 		txid_auto |= TXID_AUTO_CTB_MSK;
1522819cbf18SXiaofei Tan 		hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
1523819cbf18SXiaofei Tan 					txid_auto);
1524819cbf18SXiaofei Tan 	}
1525819cbf18SXiaofei Tan 
1526819cbf18SXiaofei Tan do_disable:
1527819cbf18SXiaofei Tan 	cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
152863fb11b8SJohn Garry 	cfg &= ~PHY_CFG_ENA_MSK;
152963fb11b8SJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
1530819cbf18SXiaofei Tan 
1531819cbf18SXiaofei Tan 	/* Open axi bus. */
1532819cbf18SXiaofei Tan 	axi_val &= ~0x1;
1533819cbf18SXiaofei Tan 	hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE +
1534819cbf18SXiaofei Tan 		AM_CTRL_GLOBAL, axi_val);
153563fb11b8SJohn Garry }
153663fb11b8SJohn Garry 
start_phy_v2_hw(struct hisi_hba * hisi_hba,int phy_no)153729a20428SJohn Garry static void start_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
153829a20428SJohn Garry {
153929a20428SJohn Garry 	config_id_frame_v2_hw(hisi_hba, phy_no);
154029a20428SJohn Garry 	config_phy_opt_mode_v2_hw(hisi_hba, phy_no);
154129a20428SJohn Garry 	enable_phy_v2_hw(hisi_hba, phy_no);
154229a20428SJohn Garry }
154329a20428SJohn Garry 
phy_hard_reset_v2_hw(struct hisi_hba * hisi_hba,int phy_no)154463fb11b8SJohn Garry static void phy_hard_reset_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
154563fb11b8SJohn Garry {
15460edef7e4SXiang Chen 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
15470edef7e4SXiang Chen 	u32 txid_auto;
15480edef7e4SXiang Chen 
1549c63b88ccSJohn Garry 	hisi_sas_phy_enable(hisi_hba, phy_no, 0);
15500edef7e4SXiang Chen 	if (phy->identify.device_type == SAS_END_DEVICE) {
15510edef7e4SXiang Chen 		txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO);
15520edef7e4SXiang Chen 		hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
15530edef7e4SXiang Chen 					txid_auto | TX_HARDRST_MSK);
15540edef7e4SXiang Chen 	}
155563fb11b8SJohn Garry 	msleep(100);
1556c63b88ccSJohn Garry 	hisi_sas_phy_enable(hisi_hba, phy_no, 1);
155763fb11b8SJohn Garry }
155863fb11b8SJohn Garry 
phy_get_events_v2_hw(struct hisi_hba * hisi_hba,int phy_no)1559c52108c6SXiaofei Tan static void phy_get_events_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
1560c52108c6SXiaofei Tan {
1561c52108c6SXiaofei Tan 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
1562c52108c6SXiaofei Tan 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
1563c52108c6SXiaofei Tan 	struct sas_phy *sphy = sas_phy->phy;
1564c52108c6SXiaofei Tan 	u32 err4_reg_val, err6_reg_val;
1565c52108c6SXiaofei Tan 
1566c52108c6SXiaofei Tan 	/* loss dword syn, phy reset problem */
1567c52108c6SXiaofei Tan 	err4_reg_val = hisi_sas_phy_read32(hisi_hba, phy_no, SAS_ERR_CNT4_REG);
1568c52108c6SXiaofei Tan 
1569c52108c6SXiaofei Tan 	/* disparity err, invalid dword */
1570c52108c6SXiaofei Tan 	err6_reg_val = hisi_sas_phy_read32(hisi_hba, phy_no, SAS_ERR_CNT6_REG);
1571c52108c6SXiaofei Tan 
1572c52108c6SXiaofei Tan 	sphy->loss_of_dword_sync_count += (err4_reg_val >> 16) & 0xFFFF;
1573c52108c6SXiaofei Tan 	sphy->phy_reset_problem_count += err4_reg_val & 0xFFFF;
1574c52108c6SXiaofei Tan 	sphy->invalid_dword_count += (err6_reg_val & 0xFF0000) >> 16;
1575c52108c6SXiaofei Tan 	sphy->running_disparity_error_count += err6_reg_val & 0xFF;
1576c52108c6SXiaofei Tan }
1577c52108c6SXiaofei Tan 
phys_init_v2_hw(struct hisi_hba * hisi_hba)1578a25d0d3dSXiang Chen static void phys_init_v2_hw(struct hisi_hba *hisi_hba)
157929a20428SJohn Garry {
158029a20428SJohn Garry 	int i;
158129a20428SJohn Garry 
1582917d3bdaSXiaofei Tan 	for (i = 0; i < hisi_hba->n_phy; i++) {
1583917d3bdaSXiaofei Tan 		struct hisi_sas_phy *phy = &hisi_hba->phy[i];
1584917d3bdaSXiaofei Tan 		struct asd_sas_phy *sas_phy = &phy->sas_phy;
1585917d3bdaSXiaofei Tan 
1586917d3bdaSXiaofei Tan 		if (!sas_phy->phy->enabled)
1587917d3bdaSXiaofei Tan 			continue;
1588917d3bdaSXiaofei Tan 
1589c63b88ccSJohn Garry 		hisi_sas_phy_enable(hisi_hba, i, 1);
159029a20428SJohn Garry 	}
1591917d3bdaSXiaofei Tan }
159229a20428SJohn Garry 
sl_notify_ssp_v2_hw(struct hisi_hba * hisi_hba,int phy_no)1593569eddcfSXiang Chen static void sl_notify_ssp_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
15947911e66fSJohn Garry {
15957911e66fSJohn Garry 	u32 sl_control;
15967911e66fSJohn Garry 
15977911e66fSJohn Garry 	sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
15987911e66fSJohn Garry 	sl_control |= SL_CONTROL_NOTIFY_EN_MSK;
15997911e66fSJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
16007911e66fSJohn Garry 	msleep(1);
16017911e66fSJohn Garry 	sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
16027911e66fSJohn Garry 	sl_control &= ~SL_CONTROL_NOTIFY_EN_MSK;
16037911e66fSJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
16047911e66fSJohn Garry }
16057911e66fSJohn Garry 
phy_get_max_linkrate_v2_hw(void)16062ae75787SXiang Chen static enum sas_linkrate phy_get_max_linkrate_v2_hw(void)
16072ae75787SXiang Chen {
16082ae75787SXiang Chen 	return SAS_LINK_RATE_12_0_GBPS;
16092ae75787SXiang Chen }
16102ae75787SXiang Chen 
phy_set_linkrate_v2_hw(struct hisi_hba * hisi_hba,int phy_no,struct sas_phy_linkrates * r)16112ae75787SXiang Chen static void phy_set_linkrate_v2_hw(struct hisi_hba *hisi_hba, int phy_no,
16122ae75787SXiang Chen 		struct sas_phy_linkrates *r)
16132ae75787SXiang Chen {
1614757db2daSJohn Garry 	enum sas_linkrate max = r->maximum_linkrate;
1615c2c1d9deSXiang Chen 	u32 prog_phy_link_rate = 0x800;
16162ae75787SXiang Chen 
1617c2c1d9deSXiang Chen 	prog_phy_link_rate |= hisi_sas_get_prog_phy_linkrate_mask(max);
16182ae75787SXiang Chen 	hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE,
16192ae75787SXiang Chen 			     prog_phy_link_rate);
16202ae75787SXiang Chen }
16212ae75787SXiang Chen 
get_wideport_bitmap_v2_hw(struct hisi_hba * hisi_hba,int port_id)16225473c060SJohn Garry static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id)
16235473c060SJohn Garry {
16245473c060SJohn Garry 	int i, bitmap = 0;
16255473c060SJohn Garry 	u32 phy_port_num_ma = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
16265473c060SJohn Garry 	u32 phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
16275473c060SJohn Garry 
16285473c060SJohn Garry 	for (i = 0; i < (hisi_hba->n_phy < 9 ? hisi_hba->n_phy : 8); i++)
16295473c060SJohn Garry 		if (phy_state & 1 << i)
16305473c060SJohn Garry 			if (((phy_port_num_ma >> (i * 4)) & 0xf) == port_id)
16315473c060SJohn Garry 				bitmap |= 1 << i;
16325473c060SJohn Garry 
16335473c060SJohn Garry 	if (hisi_hba->n_phy == 9) {
16345473c060SJohn Garry 		u32 port_state = hisi_sas_read32(hisi_hba, PORT_STATE);
16355473c060SJohn Garry 
16365473c060SJohn Garry 		if (phy_state & 1 << 8)
16375473c060SJohn Garry 			if (((port_state & PORT_STATE_PHY8_PORT_NUM_MSK) >>
16385473c060SJohn Garry 			     PORT_STATE_PHY8_PORT_NUM_OFF) == port_id)
16395473c060SJohn Garry 				bitmap |= 1 << 9;
16405473c060SJohn Garry 	}
16415473c060SJohn Garry 
16425473c060SJohn Garry 	return bitmap;
16435473c060SJohn Garry }
16445473c060SJohn Garry 
1645fa222db0SXiang Chen /* DQ lock must be taken here */
start_delivery_v2_hw(struct hisi_sas_dq * dq)1646b1a49412SXiang Chen static void start_delivery_v2_hw(struct hisi_sas_dq *dq)
16478c36e31dSJohn Garry {
1648b1a49412SXiang Chen 	struct hisi_hba *hisi_hba = dq->hisi_hba;
16491c09b663SXiaofei Tan 	struct hisi_sas_slot *s, *s1, *s2 = NULL;
1650fa222db0SXiang Chen 	int dlvry_queue = dq->id;
16511c09b663SXiaofei Tan 	int wp;
16528c36e31dSJohn Garry 
1653fa222db0SXiang Chen 	list_for_each_entry_safe(s, s1, &dq->list, delivery) {
1654fa222db0SXiang Chen 		if (!s->ready)
1655fa222db0SXiang Chen 			break;
16561c09b663SXiaofei Tan 		s2 = s;
1657fa222db0SXiang Chen 		list_del(&s->delivery);
1658fa222db0SXiang Chen 	}
1659fa222db0SXiang Chen 
16601c09b663SXiaofei Tan 	if (!s2)
1661fa222db0SXiang Chen 		return;
1662fa222db0SXiang Chen 
16631c09b663SXiaofei Tan 	/*
16641c09b663SXiaofei Tan 	 * Ensure that memories for slots built on other CPUs is observed.
16651c09b663SXiaofei Tan 	 */
16661c09b663SXiaofei Tan 	smp_rmb();
16671c09b663SXiaofei Tan 	wp = (s2->dlvry_queue_slot + 1) % HISI_SAS_QUEUE_SLOTS;
16681c09b663SXiaofei Tan 
1669fa222db0SXiang Chen 	hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14), wp);
16708c36e31dSJohn Garry }
16718c36e31dSJohn Garry 
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)1672a2b3820bSXiang Chen static void prep_prd_sge_v2_hw(struct hisi_hba *hisi_hba,
16738c36e31dSJohn Garry 			      struct hisi_sas_slot *slot,
16748c36e31dSJohn Garry 			      struct hisi_sas_cmd_hdr *hdr,
16758c36e31dSJohn Garry 			      struct scatterlist *scatter,
16768c36e31dSJohn Garry 			      int n_elem)
16778c36e31dSJohn Garry {
1678f557e32cSXiaofei Tan 	struct hisi_sas_sge_page *sge_page = hisi_sas_sge_addr_mem(slot);
16798c36e31dSJohn Garry 	struct scatterlist *sg;
16808c36e31dSJohn Garry 	int i;
16818c36e31dSJohn Garry 
16828c36e31dSJohn Garry 	for_each_sg(scatter, sg, n_elem, i) {
1683f557e32cSXiaofei Tan 		struct hisi_sas_sge *entry = &sge_page->sge[i];
16848c36e31dSJohn Garry 
16858c36e31dSJohn Garry 		entry->addr = cpu_to_le64(sg_dma_address(sg));
16868c36e31dSJohn Garry 		entry->page_ctrl_0 = entry->page_ctrl_1 = 0;
16878c36e31dSJohn Garry 		entry->data_len = cpu_to_le32(sg_dma_len(sg));
16888c36e31dSJohn Garry 		entry->data_off = 0;
16898c36e31dSJohn Garry 	}
16908c36e31dSJohn Garry 
1691f557e32cSXiaofei Tan 	hdr->prd_table_addr = cpu_to_le64(hisi_sas_sge_addr_dma(slot));
16928c36e31dSJohn Garry 
16938c36e31dSJohn Garry 	hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
16948c36e31dSJohn Garry }
16958c36e31dSJohn Garry 
prep_smp_v2_hw(struct hisi_hba * hisi_hba,struct hisi_sas_slot * slot)1696a2b3820bSXiang Chen static void prep_smp_v2_hw(struct hisi_hba *hisi_hba,
1697c2d89392SJohn Garry 			  struct hisi_sas_slot *slot)
1698c2d89392SJohn Garry {
1699c2d89392SJohn Garry 	struct sas_task *task = slot->task;
1700c2d89392SJohn Garry 	struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
1701c2d89392SJohn Garry 	struct domain_device *device = task->dev;
1702c2d89392SJohn Garry 	struct hisi_sas_port *port = slot->port;
17037eee4b92SXiang Chen 	struct scatterlist *sg_req;
1704c2d89392SJohn Garry 	struct hisi_sas_device *sas_dev = device->lldd_dev;
1705c2d89392SJohn Garry 	dma_addr_t req_dma_addr;
17067eee4b92SXiang Chen 	unsigned int req_len;
1707c2d89392SJohn Garry 
1708c2d89392SJohn Garry 	/* req */
1709c2d89392SJohn Garry 	sg_req = &task->smp_task.smp_req;
1710c2d89392SJohn Garry 	req_dma_addr = sg_dma_address(sg_req);
17117eee4b92SXiang Chen 	req_len = sg_dma_len(&task->smp_task.smp_req);
1712c2d89392SJohn Garry 
1713c2d89392SJohn Garry 	/* create header */
1714c2d89392SJohn Garry 	/* dw0 */
1715c2d89392SJohn Garry 	hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) |
1716c2d89392SJohn Garry 			       (1 << CMD_HDR_PRIORITY_OFF) | /* high pri */
1717c2d89392SJohn Garry 			       (2 << CMD_HDR_CMD_OFF)); /* smp */
1718c2d89392SJohn Garry 
1719c2d89392SJohn Garry 	/* map itct entry */
1720c2d89392SJohn Garry 	hdr->dw1 = cpu_to_le32((sas_dev->device_id << CMD_HDR_DEV_ID_OFF) |
1721c2d89392SJohn Garry 			       (1 << CMD_HDR_FRAME_TYPE_OFF) |
1722c2d89392SJohn Garry 			       (DIR_NO_DATA << CMD_HDR_DIR_OFF));
1723c2d89392SJohn Garry 
1724c2d89392SJohn Garry 	/* dw2 */
1725c2d89392SJohn Garry 	hdr->dw2 = cpu_to_le32((((req_len - 4) / 4) << CMD_HDR_CFL_OFF) |
1726c2d89392SJohn Garry 			       (HISI_SAS_MAX_SMP_RESP_SZ / 4 <<
1727c2d89392SJohn Garry 			       CMD_HDR_MRFL_OFF));
1728c2d89392SJohn Garry 
1729c2d89392SJohn Garry 	hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
1730c2d89392SJohn Garry 
1731c2d89392SJohn Garry 	hdr->cmd_table_addr = cpu_to_le64(req_dma_addr);
1732f557e32cSXiaofei Tan 	hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
1733c2d89392SJohn Garry }
1734c2d89392SJohn Garry 
prep_ssp_v2_hw(struct hisi_hba * hisi_hba,struct hisi_sas_slot * slot)1735a2b3820bSXiang Chen static void prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
173678bd2b4fSXiaofei Tan 			  struct hisi_sas_slot *slot)
17378c36e31dSJohn Garry {
17388c36e31dSJohn Garry 	struct sas_task *task = slot->task;
17398c36e31dSJohn Garry 	struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
17408c36e31dSJohn Garry 	struct domain_device *device = task->dev;
17418c36e31dSJohn Garry 	struct hisi_sas_device *sas_dev = device->lldd_dev;
17428c36e31dSJohn Garry 	struct hisi_sas_port *port = slot->port;
17438c36e31dSJohn Garry 	struct sas_ssp_task *ssp_task = &task->ssp_task;
17448c36e31dSJohn Garry 	struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
1745bbfe82cdSJohn Garry 	struct sas_tmf_task *tmf = slot->tmf;
174678bd2b4fSXiaofei Tan 	int has_data = 0, priority = !!tmf;
17478c36e31dSJohn Garry 	u8 *buf_cmd;
17488c36e31dSJohn Garry 	u32 dw1 = 0, dw2 = 0;
17498c36e31dSJohn Garry 
17508c36e31dSJohn Garry 	hdr->dw0 = cpu_to_le32((1 << CMD_HDR_RESP_REPORT_OFF) |
17518c36e31dSJohn Garry 			       (2 << CMD_HDR_TLR_CTRL_OFF) |
17528c36e31dSJohn Garry 			       (port->id << CMD_HDR_PORT_OFF) |
17538c36e31dSJohn Garry 			       (priority << CMD_HDR_PRIORITY_OFF) |
17548c36e31dSJohn Garry 			       (1 << CMD_HDR_CMD_OFF)); /* ssp */
17558c36e31dSJohn Garry 
17568c36e31dSJohn Garry 	dw1 = 1 << CMD_HDR_VDTL_OFF;
175778bd2b4fSXiaofei Tan 	if (tmf) {
17588c36e31dSJohn Garry 		dw1 |= 2 << CMD_HDR_FRAME_TYPE_OFF;
17598c36e31dSJohn Garry 		dw1 |= DIR_NO_DATA << CMD_HDR_DIR_OFF;
17608c36e31dSJohn Garry 	} else {
17618c36e31dSJohn Garry 		dw1 |= 1 << CMD_HDR_FRAME_TYPE_OFF;
17628c36e31dSJohn Garry 		switch (scsi_cmnd->sc_data_direction) {
17638c36e31dSJohn Garry 		case DMA_TO_DEVICE:
17648c36e31dSJohn Garry 			has_data = 1;
17658c36e31dSJohn Garry 			dw1 |= DIR_TO_DEVICE << CMD_HDR_DIR_OFF;
17668c36e31dSJohn Garry 			break;
17678c36e31dSJohn Garry 		case DMA_FROM_DEVICE:
17688c36e31dSJohn Garry 			has_data = 1;
17698c36e31dSJohn Garry 			dw1 |= DIR_TO_INI << CMD_HDR_DIR_OFF;
17708c36e31dSJohn Garry 			break;
17718c36e31dSJohn Garry 		default:
17728c36e31dSJohn Garry 			dw1 &= ~CMD_HDR_DIR_MSK;
17738c36e31dSJohn Garry 		}
17748c36e31dSJohn Garry 	}
17758c36e31dSJohn Garry 
17768c36e31dSJohn Garry 	/* map itct entry */
17778c36e31dSJohn Garry 	dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF;
17788c36e31dSJohn Garry 	hdr->dw1 = cpu_to_le32(dw1);
17798c36e31dSJohn Garry 
17808c36e31dSJohn Garry 	dw2 = (((sizeof(struct ssp_command_iu) + sizeof(struct ssp_frame_hdr)
17818c36e31dSJohn Garry 	      + 3) / 4) << CMD_HDR_CFL_OFF) |
17828c36e31dSJohn Garry 	      ((HISI_SAS_MAX_SSP_RESP_SZ / 4) << CMD_HDR_MRFL_OFF) |
17838c36e31dSJohn Garry 	      (2 << CMD_HDR_SG_MOD_OFF);
17848c36e31dSJohn Garry 	hdr->dw2 = cpu_to_le32(dw2);
17858c36e31dSJohn Garry 
17868c36e31dSJohn Garry 	hdr->transfer_tags = cpu_to_le32(slot->idx);
17878c36e31dSJohn Garry 
1788a2b3820bSXiang Chen 	if (has_data)
1789a2b3820bSXiang Chen 		prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter,
17908c36e31dSJohn Garry 					slot->n_elem);
17918c36e31dSJohn Garry 
17928c36e31dSJohn Garry 	hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
1793f557e32cSXiaofei Tan 	hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot));
1794f557e32cSXiaofei Tan 	hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
17958c36e31dSJohn Garry 
1796f557e32cSXiaofei Tan 	buf_cmd = hisi_sas_cmd_hdr_addr_mem(slot) +
1797f557e32cSXiaofei Tan 		sizeof(struct ssp_frame_hdr);
17988c36e31dSJohn Garry 
17998c36e31dSJohn Garry 	memcpy(buf_cmd, &task->ssp_task.LUN, 8);
180078bd2b4fSXiaofei Tan 	if (!tmf) {
1801*4dc051ebSJohn Garry 		buf_cmd[9] = task->ssp_task.task_attr;
18028c36e31dSJohn Garry 		memcpy(buf_cmd + 12, task->ssp_task.cmd->cmnd,
18038c36e31dSJohn Garry 				task->ssp_task.cmd->cmd_len);
18048c36e31dSJohn Garry 	} else {
18058c36e31dSJohn Garry 		buf_cmd[10] = tmf->tmf;
18068c36e31dSJohn Garry 		switch (tmf->tmf) {
18078c36e31dSJohn Garry 		case TMF_ABORT_TASK:
18088c36e31dSJohn Garry 		case TMF_QUERY_TASK:
18098c36e31dSJohn Garry 			buf_cmd[12] =
18108c36e31dSJohn Garry 				(tmf->tag_of_task_to_be_managed >> 8) & 0xff;
18118c36e31dSJohn Garry 			buf_cmd[13] =
18128c36e31dSJohn Garry 				tmf->tag_of_task_to_be_managed & 0xff;
18138c36e31dSJohn Garry 			break;
18148c36e31dSJohn Garry 		default:
18158c36e31dSJohn Garry 			break;
18168c36e31dSJohn Garry 		}
18178c36e31dSJohn Garry 	}
18188c36e31dSJohn Garry }
18198c36e31dSJohn Garry 
1820634a9585SXiang Chen #define TRANS_TX_ERR	0
1821634a9585SXiang Chen #define TRANS_RX_ERR	1
1822634a9585SXiang Chen #define DMA_TX_ERR		2
1823634a9585SXiang Chen #define SIPC_RX_ERR		3
1824634a9585SXiang Chen #define DMA_RX_ERR		4
1825634a9585SXiang Chen 
1826634a9585SXiang Chen #define DMA_TX_ERR_OFF	0
1827634a9585SXiang Chen #define DMA_TX_ERR_MSK	(0xffff << DMA_TX_ERR_OFF)
1828634a9585SXiang Chen #define SIPC_RX_ERR_OFF	16
1829634a9585SXiang Chen #define SIPC_RX_ERR_MSK (0xffff << SIPC_RX_ERR_OFF)
1830634a9585SXiang Chen 
parse_trans_tx_err_code_v2_hw(u32 err_msk)1831634a9585SXiang Chen static int parse_trans_tx_err_code_v2_hw(u32 err_msk)
1832634a9585SXiang Chen {
183389b203e9SColin Ian King 	static const u8 trans_tx_err_code_prio[] = {
1834634a9585SXiang Chen 		TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS,
1835634a9585SXiang Chen 		TRANS_TX_ERR_PHY_NOT_ENABLE,
1836634a9585SXiang Chen 		TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION,
1837634a9585SXiang Chen 		TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION,
1838634a9585SXiang Chen 		TRANS_TX_OPEN_CNX_ERR_BY_OTHER,
1839634a9585SXiang Chen 		RESERVED0,
1840634a9585SXiang Chen 		TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT,
1841634a9585SXiang Chen 		TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY,
1842634a9585SXiang Chen 		TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED,
1843634a9585SXiang Chen 		TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED,
1844634a9585SXiang Chen 		TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION,
1845634a9585SXiang Chen 		TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD,
1846634a9585SXiang Chen 		TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER,
1847634a9585SXiang Chen 		TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED,
1848634a9585SXiang Chen 		TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT,
1849634a9585SXiang Chen 		TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION,
1850634a9585SXiang Chen 		TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED,
1851634a9585SXiang Chen 		TRANS_TX_ERR_WITH_CLOSE_PHYDISALE,
1852634a9585SXiang Chen 		TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT,
1853634a9585SXiang Chen 		TRANS_TX_ERR_WITH_CLOSE_COMINIT,
1854634a9585SXiang Chen 		TRANS_TX_ERR_WITH_BREAK_TIMEOUT,
1855634a9585SXiang Chen 		TRANS_TX_ERR_WITH_BREAK_REQUEST,
1856634a9585SXiang Chen 		TRANS_TX_ERR_WITH_BREAK_RECEVIED,
1857634a9585SXiang Chen 		TRANS_TX_ERR_WITH_CLOSE_TIMEOUT,
1858634a9585SXiang Chen 		TRANS_TX_ERR_WITH_CLOSE_NORMAL,
1859634a9585SXiang Chen 		TRANS_TX_ERR_WITH_NAK_RECEVIED,
1860634a9585SXiang Chen 		TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT,
1861634a9585SXiang Chen 		TRANS_TX_ERR_WITH_CREDIT_TIMEOUT,
1862634a9585SXiang Chen 		TRANS_TX_ERR_WITH_IPTT_CONFLICT,
1863634a9585SXiang Chen 		TRANS_TX_ERR_WITH_OPEN_BY_DES_OR_OTHERS,
1864634a9585SXiang Chen 		TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT,
1865634a9585SXiang Chen 	};
1866634a9585SXiang Chen 	int index, i;
1867634a9585SXiang Chen 
1868634a9585SXiang Chen 	for (i = 0; i < ARRAY_SIZE(trans_tx_err_code_prio); i++) {
1869634a9585SXiang Chen 		index = trans_tx_err_code_prio[i] - TRANS_TX_FAIL_BASE;
1870634a9585SXiang Chen 		if (err_msk & (1 << index))
1871634a9585SXiang Chen 			return trans_tx_err_code_prio[i];
1872634a9585SXiang Chen 	}
1873634a9585SXiang Chen 	return -1;
1874634a9585SXiang Chen }
1875634a9585SXiang Chen 
parse_trans_rx_err_code_v2_hw(u32 err_msk)1876634a9585SXiang Chen static int parse_trans_rx_err_code_v2_hw(u32 err_msk)
1877634a9585SXiang Chen {
187889b203e9SColin Ian King 	static const u8 trans_rx_err_code_prio[] = {
1879634a9585SXiang Chen 		TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR,
1880634a9585SXiang Chen 		TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR,
1881634a9585SXiang Chen 		TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM,
1882634a9585SXiang Chen 		TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR,
1883634a9585SXiang Chen 		TRANS_RX_ERR_WITH_RXFIS_CRC_ERR,
1884634a9585SXiang Chen 		TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN,
1885634a9585SXiang Chen 		TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP,
1886634a9585SXiang Chen 		TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN,
1887634a9585SXiang Chen 		TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE,
1888634a9585SXiang Chen 		TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT,
1889634a9585SXiang Chen 		TRANS_RX_ERR_WITH_CLOSE_COMINIT,
1890634a9585SXiang Chen 		TRANS_RX_ERR_WITH_BREAK_TIMEOUT,
1891634a9585SXiang Chen 		TRANS_RX_ERR_WITH_BREAK_REQUEST,
1892634a9585SXiang Chen 		TRANS_RX_ERR_WITH_BREAK_RECEVIED,
1893634a9585SXiang Chen 		RESERVED1,
1894634a9585SXiang Chen 		TRANS_RX_ERR_WITH_CLOSE_NORMAL,
1895634a9585SXiang Chen 		TRANS_RX_ERR_WITH_DATA_LEN0,
1896634a9585SXiang Chen 		TRANS_RX_ERR_WITH_BAD_HASH,
1897634a9585SXiang Chen 		TRANS_RX_XRDY_WLEN_ZERO_ERR,
1898634a9585SXiang Chen 		TRANS_RX_SSP_FRM_LEN_ERR,
1899634a9585SXiang Chen 		RESERVED2,
1900634a9585SXiang Chen 		RESERVED3,
1901634a9585SXiang Chen 		RESERVED4,
1902634a9585SXiang Chen 		RESERVED5,
1903634a9585SXiang Chen 		TRANS_RX_ERR_WITH_BAD_FRM_TYPE,
1904634a9585SXiang Chen 		TRANS_RX_SMP_FRM_LEN_ERR,
1905634a9585SXiang Chen 		TRANS_RX_SMP_RESP_TIMEOUT_ERR,
1906634a9585SXiang Chen 		RESERVED6,
1907634a9585SXiang Chen 		RESERVED7,
1908634a9585SXiang Chen 		RESERVED8,
1909634a9585SXiang Chen 		RESERVED9,
1910634a9585SXiang Chen 		TRANS_RX_R_ERR,
1911634a9585SXiang Chen 	};
1912634a9585SXiang Chen 	int index, i;
1913634a9585SXiang Chen 
1914634a9585SXiang Chen 	for (i = 0; i < ARRAY_SIZE(trans_rx_err_code_prio); i++) {
1915634a9585SXiang Chen 		index = trans_rx_err_code_prio[i] - TRANS_RX_FAIL_BASE;
1916634a9585SXiang Chen 		if (err_msk & (1 << index))
1917634a9585SXiang Chen 			return trans_rx_err_code_prio[i];
1918634a9585SXiang Chen 	}
1919634a9585SXiang Chen 	return -1;
1920634a9585SXiang Chen }
1921634a9585SXiang Chen 
parse_dma_tx_err_code_v2_hw(u32 err_msk)1922634a9585SXiang Chen static int parse_dma_tx_err_code_v2_hw(u32 err_msk)
1923634a9585SXiang Chen {
192489b203e9SColin Ian King 	static const u8 dma_tx_err_code_prio[] = {
1925634a9585SXiang Chen 		DMA_TX_UNEXP_XFER_ERR,
1926634a9585SXiang Chen 		DMA_TX_UNEXP_RETRANS_ERR,
1927634a9585SXiang Chen 		DMA_TX_XFER_LEN_OVERFLOW,
1928634a9585SXiang Chen 		DMA_TX_XFER_OFFSET_ERR,
1929634a9585SXiang Chen 		DMA_TX_RAM_ECC_ERR,
1930634a9585SXiang Chen 		DMA_TX_DIF_LEN_ALIGN_ERR,
1931634a9585SXiang Chen 		DMA_TX_DIF_CRC_ERR,
1932634a9585SXiang Chen 		DMA_TX_DIF_APP_ERR,
1933634a9585SXiang Chen 		DMA_TX_DIF_RPP_ERR,
1934634a9585SXiang Chen 		DMA_TX_DATA_SGL_OVERFLOW,
1935634a9585SXiang Chen 		DMA_TX_DIF_SGL_OVERFLOW,
1936634a9585SXiang Chen 	};
1937634a9585SXiang Chen 	int index, i;
1938634a9585SXiang Chen 
1939634a9585SXiang Chen 	for (i = 0; i < ARRAY_SIZE(dma_tx_err_code_prio); i++) {
1940634a9585SXiang Chen 		index = dma_tx_err_code_prio[i] - DMA_TX_ERR_BASE;
1941634a9585SXiang Chen 		err_msk = err_msk & DMA_TX_ERR_MSK;
1942634a9585SXiang Chen 		if (err_msk & (1 << index))
1943634a9585SXiang Chen 			return dma_tx_err_code_prio[i];
1944634a9585SXiang Chen 	}
1945634a9585SXiang Chen 	return -1;
1946634a9585SXiang Chen }
1947634a9585SXiang Chen 
parse_sipc_rx_err_code_v2_hw(u32 err_msk)1948634a9585SXiang Chen static int parse_sipc_rx_err_code_v2_hw(u32 err_msk)
1949634a9585SXiang Chen {
195089b203e9SColin Ian King 	static const u8 sipc_rx_err_code_prio[] = {
1951634a9585SXiang Chen 		SIPC_RX_FIS_STATUS_ERR_BIT_VLD,
1952634a9585SXiang Chen 		SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR,
1953634a9585SXiang Chen 		SIPC_RX_FIS_STATUS_BSY_BIT_ERR,
1954634a9585SXiang Chen 		SIPC_RX_WRSETUP_LEN_ODD_ERR,
1955634a9585SXiang Chen 		SIPC_RX_WRSETUP_LEN_ZERO_ERR,
1956634a9585SXiang Chen 		SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR,
1957634a9585SXiang Chen 		SIPC_RX_NCQ_WRSETUP_OFFSET_ERR,
1958634a9585SXiang Chen 		SIPC_RX_NCQ_WRSETUP_AUTO_ACTIVE_ERR,
1959634a9585SXiang Chen 		SIPC_RX_SATA_UNEXP_FIS_ERR,
1960634a9585SXiang Chen 		SIPC_RX_WRSETUP_ESTATUS_ERR,
1961634a9585SXiang Chen 		SIPC_RX_DATA_UNDERFLOW_ERR,
1962634a9585SXiang Chen 	};
1963634a9585SXiang Chen 	int index, i;
1964634a9585SXiang Chen 
1965634a9585SXiang Chen 	for (i = 0; i < ARRAY_SIZE(sipc_rx_err_code_prio); i++) {
1966634a9585SXiang Chen 		index = sipc_rx_err_code_prio[i] - SIPC_RX_ERR_BASE;
1967634a9585SXiang Chen 		err_msk = err_msk & SIPC_RX_ERR_MSK;
1968634a9585SXiang Chen 		if (err_msk & (1 << (index + 0x10)))
1969634a9585SXiang Chen 			return sipc_rx_err_code_prio[i];
1970634a9585SXiang Chen 	}
1971634a9585SXiang Chen 	return -1;
1972634a9585SXiang Chen }
1973634a9585SXiang Chen 
parse_dma_rx_err_code_v2_hw(u32 err_msk)1974634a9585SXiang Chen static int parse_dma_rx_err_code_v2_hw(u32 err_msk)
1975634a9585SXiang Chen {
197689b203e9SColin Ian King 	static const u8 dma_rx_err_code_prio[] = {
1977634a9585SXiang Chen 		DMA_RX_UNKNOWN_FRM_ERR,
1978634a9585SXiang Chen 		DMA_RX_DATA_LEN_OVERFLOW,
1979634a9585SXiang Chen 		DMA_RX_DATA_LEN_UNDERFLOW,
1980634a9585SXiang Chen 		DMA_RX_DATA_OFFSET_ERR,
1981634a9585SXiang Chen 		RESERVED10,
1982634a9585SXiang Chen 		DMA_RX_SATA_FRAME_TYPE_ERR,
1983634a9585SXiang Chen 		DMA_RX_RESP_BUF_OVERFLOW,
1984634a9585SXiang Chen 		DMA_RX_UNEXP_RETRANS_RESP_ERR,
1985634a9585SXiang Chen 		DMA_RX_UNEXP_NORM_RESP_ERR,
1986634a9585SXiang Chen 		DMA_RX_UNEXP_RDFRAME_ERR,
1987634a9585SXiang Chen 		DMA_RX_PIO_DATA_LEN_ERR,
1988634a9585SXiang Chen 		DMA_RX_RDSETUP_STATUS_ERR,
1989634a9585SXiang Chen 		DMA_RX_RDSETUP_STATUS_DRQ_ERR,
1990634a9585SXiang Chen 		DMA_RX_RDSETUP_STATUS_BSY_ERR,
1991634a9585SXiang Chen 		DMA_RX_RDSETUP_LEN_ODD_ERR,
1992634a9585SXiang Chen 		DMA_RX_RDSETUP_LEN_ZERO_ERR,
1993634a9585SXiang Chen 		DMA_RX_RDSETUP_LEN_OVER_ERR,
1994634a9585SXiang Chen 		DMA_RX_RDSETUP_OFFSET_ERR,
1995634a9585SXiang Chen 		DMA_RX_RDSETUP_ACTIVE_ERR,
1996634a9585SXiang Chen 		DMA_RX_RDSETUP_ESTATUS_ERR,
1997634a9585SXiang Chen 		DMA_RX_RAM_ECC_ERR,
1998634a9585SXiang Chen 		DMA_RX_DIF_CRC_ERR,
1999634a9585SXiang Chen 		DMA_RX_DIF_APP_ERR,
2000634a9585SXiang Chen 		DMA_RX_DIF_RPP_ERR,
2001634a9585SXiang Chen 		DMA_RX_DATA_SGL_OVERFLOW,
2002634a9585SXiang Chen 		DMA_RX_DIF_SGL_OVERFLOW,
2003634a9585SXiang Chen 	};
2004634a9585SXiang Chen 	int index, i;
2005634a9585SXiang Chen 
2006634a9585SXiang Chen 	for (i = 0; i < ARRAY_SIZE(dma_rx_err_code_prio); i++) {
2007634a9585SXiang Chen 		index = dma_rx_err_code_prio[i] - DMA_RX_ERR_BASE;
2008634a9585SXiang Chen 		if (err_msk & (1 << index))
2009634a9585SXiang Chen 			return dma_rx_err_code_prio[i];
2010634a9585SXiang Chen 	}
2011634a9585SXiang Chen 	return -1;
2012634a9585SXiang Chen }
2013634a9585SXiang Chen 
2014e8fed0e9SJohn Garry /* by default, task resp is complete */
slot_err_v2_hw(struct hisi_hba * hisi_hba,struct sas_task * task,struct hisi_sas_slot * slot,int err_phase)2015e8fed0e9SJohn Garry static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
2016e8fed0e9SJohn Garry 			   struct sas_task *task,
2017634a9585SXiang Chen 			   struct hisi_sas_slot *slot,
2018634a9585SXiang Chen 			   int err_phase)
2019e8fed0e9SJohn Garry {
2020e8fed0e9SJohn Garry 	struct task_status_struct *ts = &task->task_status;
2021f557e32cSXiaofei Tan 	struct hisi_sas_err_record_v2 *err_record =
2022f557e32cSXiaofei Tan 			hisi_sas_status_buf_addr_mem(slot);
2023735bcc77SJohn Garry 	u32 trans_tx_fail_type = le32_to_cpu(err_record->trans_tx_fail_type);
2024735bcc77SJohn Garry 	u32 trans_rx_fail_type = le32_to_cpu(err_record->trans_rx_fail_type);
2025735bcc77SJohn Garry 	u16 dma_tx_err_type = le16_to_cpu(err_record->dma_tx_err_type);
2026735bcc77SJohn Garry 	u16 sipc_rx_err_type = le16_to_cpu(err_record->sipc_rx_err_type);
2027735bcc77SJohn Garry 	u32 dma_rx_err_type = le32_to_cpu(err_record->dma_rx_err_type);
2028f5393a56SXingui Yang 	struct hisi_sas_complete_v2_hdr *complete_queue =
2029f5393a56SXingui Yang 			hisi_hba->complete_hdr[slot->cmplt_queue];
2030f5393a56SXingui Yang 	struct hisi_sas_complete_v2_hdr *complete_hdr =
2031f5393a56SXingui Yang 			&complete_queue[slot->cmplt_queue_slot];
2032f5393a56SXingui Yang 	u32 dw0 = le32_to_cpu(complete_hdr->dw0);
2033e8fed0e9SJohn Garry 	int error = -1;
2034e8fed0e9SJohn Garry 
2035634a9585SXiang Chen 	if (err_phase == 1) {
2036634a9585SXiang Chen 		/* error in TX phase, the priority of error is: DW2 > DW0 */
2037634a9585SXiang Chen 		error = parse_dma_tx_err_code_v2_hw(dma_tx_err_type);
2038634a9585SXiang Chen 		if (error == -1)
2039634a9585SXiang Chen 			error = parse_trans_tx_err_code_v2_hw(
2040634a9585SXiang Chen 					trans_tx_fail_type);
2041634a9585SXiang Chen 	} else if (err_phase == 2) {
2042634a9585SXiang Chen 		/* error in RX phase, the priority is: DW1 > DW3 > DW2 */
2043735bcc77SJohn Garry 		error = parse_trans_rx_err_code_v2_hw(trans_rx_fail_type);
2044634a9585SXiang Chen 		if (error == -1) {
2045634a9585SXiang Chen 			error = parse_dma_rx_err_code_v2_hw(
2046634a9585SXiang Chen 					dma_rx_err_type);
2047634a9585SXiang Chen 			if (error == -1)
2048634a9585SXiang Chen 				error = parse_sipc_rx_err_code_v2_hw(
2049634a9585SXiang Chen 						sipc_rx_err_type);
2050634a9585SXiang Chen 		}
2051e8fed0e9SJohn Garry 	}
2052e8fed0e9SJohn Garry 
2053e8fed0e9SJohn Garry 	switch (task->task_proto) {
2054e8fed0e9SJohn Garry 	case SAS_PROTOCOL_SSP:
2055e8fed0e9SJohn Garry 	{
2056e8fed0e9SJohn Garry 		switch (error) {
2057e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION:
2058e8fed0e9SJohn Garry 		{
2059e8fed0e9SJohn Garry 			ts->stat = SAS_OPEN_REJECT;
2060e8fed0e9SJohn Garry 			ts->open_rej_reason = SAS_OREJ_NO_DEST;
2061a28b259bSColin Ian King 			break;
2062e8fed0e9SJohn Garry 		}
2063e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED:
2064e8fed0e9SJohn Garry 		{
2065e8fed0e9SJohn Garry 			ts->stat = SAS_OPEN_REJECT;
2066e8fed0e9SJohn Garry 			ts->open_rej_reason = SAS_OREJ_EPROTO;
2067e8fed0e9SJohn Garry 			break;
2068e8fed0e9SJohn Garry 		}
2069e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED:
2070e8fed0e9SJohn Garry 		{
2071e8fed0e9SJohn Garry 			ts->stat = SAS_OPEN_REJECT;
2072e8fed0e9SJohn Garry 			ts->open_rej_reason = SAS_OREJ_CONN_RATE;
2073e8fed0e9SJohn Garry 			break;
2074e8fed0e9SJohn Garry 		}
2075e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION:
2076e8fed0e9SJohn Garry 		{
2077e8fed0e9SJohn Garry 			ts->stat = SAS_OPEN_REJECT;
2078e8fed0e9SJohn Garry 			ts->open_rej_reason = SAS_OREJ_BAD_DEST;
2079e8fed0e9SJohn Garry 			break;
2080e8fed0e9SJohn Garry 		}
2081e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION:
2082e8fed0e9SJohn Garry 		{
2083e8fed0e9SJohn Garry 			ts->stat = SAS_OPEN_REJECT;
2084e8fed0e9SJohn Garry 			ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
2085e8fed0e9SJohn Garry 			break;
2086e8fed0e9SJohn Garry 		}
2087634a9585SXiang Chen 		case DMA_RX_UNEXP_NORM_RESP_ERR:
2088e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION:
2089634a9585SXiang Chen 		case DMA_RX_RESP_BUF_OVERFLOW:
2090e8fed0e9SJohn Garry 		{
2091e8fed0e9SJohn Garry 			ts->stat = SAS_OPEN_REJECT;
2092e8fed0e9SJohn Garry 			ts->open_rej_reason = SAS_OREJ_UNKNOWN;
2093e8fed0e9SJohn Garry 			break;
2094e8fed0e9SJohn Garry 		}
2095e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER:
2096e8fed0e9SJohn Garry 		{
2097e8fed0e9SJohn Garry 			/* not sure */
2098e8fed0e9SJohn Garry 			ts->stat = SAS_DEV_NO_RESPONSE;
2099e8fed0e9SJohn Garry 			break;
2100e8fed0e9SJohn Garry 		}
2101e8fed0e9SJohn Garry 		case DMA_RX_DATA_LEN_OVERFLOW:
2102e8fed0e9SJohn Garry 		{
2103e8fed0e9SJohn Garry 			ts->stat = SAS_DATA_OVERRUN;
2104e8fed0e9SJohn Garry 			ts->residual = 0;
2105e8fed0e9SJohn Garry 			break;
2106e8fed0e9SJohn Garry 		}
2107e8fed0e9SJohn Garry 		case DMA_RX_DATA_LEN_UNDERFLOW:
2108e8fed0e9SJohn Garry 		{
210901b361fcSXiang Chen 			ts->residual = trans_tx_fail_type;
2110e8fed0e9SJohn Garry 			ts->stat = SAS_DATA_UNDERRUN;
2111e8fed0e9SJohn Garry 			break;
2112e8fed0e9SJohn Garry 		}
2113e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS:
2114e8fed0e9SJohn Garry 		case TRANS_TX_ERR_PHY_NOT_ENABLE:
2115e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_CNX_ERR_BY_OTHER:
2116e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT:
2117634a9585SXiang Chen 		case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
2118634a9585SXiang Chen 		case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
2119634a9585SXiang Chen 		case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
2120e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED:
2121e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_BREAK_TIMEOUT:
2122e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_BREAK_REQUEST:
2123e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_BREAK_RECEVIED:
2124e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT:
2125e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_CLOSE_NORMAL:
2126634a9585SXiang Chen 		case TRANS_TX_ERR_WITH_CLOSE_PHYDISALE:
2127e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT:
2128e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_CLOSE_COMINIT:
2129e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_NAK_RECEVIED:
2130e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT:
2131e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT:
2132634a9585SXiang Chen 		case TRANS_TX_ERR_WITH_IPTT_CONFLICT:
2133e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR:
2134e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR:
2135e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM:
2136634a9585SXiang Chen 		case TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN:
2137e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_BREAK_TIMEOUT:
2138e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_BREAK_REQUEST:
2139e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_BREAK_RECEVIED:
2140e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_CLOSE_NORMAL:
2141e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT:
2142e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_CLOSE_COMINIT:
2143634a9585SXiang Chen 		case TRANS_TX_ERR_FRAME_TXED:
2144634a9585SXiang Chen 		case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE:
2145e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_DATA_LEN0:
2146e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_BAD_HASH:
2147e8fed0e9SJohn Garry 		case TRANS_RX_XRDY_WLEN_ZERO_ERR:
2148e8fed0e9SJohn Garry 		case TRANS_RX_SSP_FRM_LEN_ERR:
2149e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_BAD_FRM_TYPE:
2150634a9585SXiang Chen 		case DMA_TX_DATA_SGL_OVERFLOW:
2151e8fed0e9SJohn Garry 		case DMA_TX_UNEXP_XFER_ERR:
2152e8fed0e9SJohn Garry 		case DMA_TX_UNEXP_RETRANS_ERR:
2153e8fed0e9SJohn Garry 		case DMA_TX_XFER_LEN_OVERFLOW:
2154e8fed0e9SJohn Garry 		case DMA_TX_XFER_OFFSET_ERR:
2155634a9585SXiang Chen 		case SIPC_RX_DATA_UNDERFLOW_ERR:
2156634a9585SXiang Chen 		case DMA_RX_DATA_SGL_OVERFLOW:
2157e8fed0e9SJohn Garry 		case DMA_RX_DATA_OFFSET_ERR:
2158634a9585SXiang Chen 		case DMA_RX_RDSETUP_LEN_ODD_ERR:
2159634a9585SXiang Chen 		case DMA_RX_RDSETUP_LEN_ZERO_ERR:
2160634a9585SXiang Chen 		case DMA_RX_RDSETUP_LEN_OVER_ERR:
2161634a9585SXiang Chen 		case DMA_RX_SATA_FRAME_TYPE_ERR:
2162e8fed0e9SJohn Garry 		case DMA_RX_UNKNOWN_FRM_ERR:
2163e8fed0e9SJohn Garry 		{
2164634a9585SXiang Chen 			/* This will request a retry */
2165634a9585SXiang Chen 			ts->stat = SAS_QUEUE_FULL;
2166634a9585SXiang Chen 			slot->abort = 1;
2167e8fed0e9SJohn Garry 			break;
2168e8fed0e9SJohn Garry 		}
2169e8fed0e9SJohn Garry 		default:
2170e8fed0e9SJohn Garry 			break;
2171e8fed0e9SJohn Garry 		}
2172e8fed0e9SJohn Garry 	}
2173e8fed0e9SJohn Garry 		break;
2174e8fed0e9SJohn Garry 	case SAS_PROTOCOL_SMP:
2175d377f415SBart Van Assche 		ts->stat = SAS_SAM_STAT_CHECK_CONDITION;
2176e8fed0e9SJohn Garry 		break;
2177e8fed0e9SJohn Garry 
2178e8fed0e9SJohn Garry 	case SAS_PROTOCOL_SATA:
2179e8fed0e9SJohn Garry 	case SAS_PROTOCOL_STP:
2180e8fed0e9SJohn Garry 	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
2181e8fed0e9SJohn Garry 	{
2182e8fed0e9SJohn Garry 		switch (error) {
2183e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION:
2184e8fed0e9SJohn Garry 		{
2185634a9585SXiang Chen 			ts->stat = SAS_OPEN_REJECT;
2186634a9585SXiang Chen 			ts->open_rej_reason = SAS_OREJ_NO_DEST;
2187634a9585SXiang Chen 			break;
2188634a9585SXiang Chen 		}
2189634a9585SXiang Chen 		case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER:
2190634a9585SXiang Chen 		{
2191e8fed0e9SJohn Garry 			ts->resp = SAS_TASK_UNDELIVERED;
2192e8fed0e9SJohn Garry 			ts->stat = SAS_DEV_NO_RESPONSE;
2193e8fed0e9SJohn Garry 			break;
2194e8fed0e9SJohn Garry 		}
2195e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED:
2196e8fed0e9SJohn Garry 		{
2197e8fed0e9SJohn Garry 			ts->stat = SAS_OPEN_REJECT;
2198634a9585SXiang Chen 			ts->open_rej_reason = SAS_OREJ_EPROTO;
2199e8fed0e9SJohn Garry 			break;
2200e8fed0e9SJohn Garry 		}
2201634a9585SXiang Chen 		case TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED:
2202e8fed0e9SJohn Garry 		{
2203634a9585SXiang Chen 			ts->stat = SAS_OPEN_REJECT;
2204634a9585SXiang Chen 			ts->open_rej_reason = SAS_OREJ_CONN_RATE;
2205634a9585SXiang Chen 			break;
2206634a9585SXiang Chen 		}
2207634a9585SXiang Chen 		case TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION:
2208634a9585SXiang Chen 		{
2209634a9585SXiang Chen 			ts->stat = SAS_OPEN_REJECT;
2210634a9585SXiang Chen 			ts->open_rej_reason = SAS_OREJ_CONN_RATE;
2211634a9585SXiang Chen 			break;
2212634a9585SXiang Chen 		}
2213634a9585SXiang Chen 		case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION:
2214634a9585SXiang Chen 		{
2215634a9585SXiang Chen 			ts->stat = SAS_OPEN_REJECT;
2216634a9585SXiang Chen 			ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
2217634a9585SXiang Chen 			break;
2218634a9585SXiang Chen 		}
2219634a9585SXiang Chen 		case DMA_RX_RESP_BUF_OVERFLOW:
2220634a9585SXiang Chen 		case DMA_RX_UNEXP_NORM_RESP_ERR:
2221634a9585SXiang Chen 		case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION:
2222634a9585SXiang Chen 		{
2223634a9585SXiang Chen 			ts->stat = SAS_OPEN_REJECT;
2224634a9585SXiang Chen 			ts->open_rej_reason = SAS_OREJ_UNKNOWN;
2225e8fed0e9SJohn Garry 			break;
2226e8fed0e9SJohn Garry 		}
2227e8fed0e9SJohn Garry 		case DMA_RX_DATA_LEN_OVERFLOW:
2228e8fed0e9SJohn Garry 		{
2229e8fed0e9SJohn Garry 			ts->stat = SAS_DATA_OVERRUN;
2230634a9585SXiang Chen 			ts->residual = 0;
2231634a9585SXiang Chen 			break;
2232634a9585SXiang Chen 		}
2233634a9585SXiang Chen 		case DMA_RX_DATA_LEN_UNDERFLOW:
2234634a9585SXiang Chen 		{
223501b361fcSXiang Chen 			ts->residual = trans_tx_fail_type;
2236634a9585SXiang Chen 			ts->stat = SAS_DATA_UNDERRUN;
2237e8fed0e9SJohn Garry 			break;
2238e8fed0e9SJohn Garry 		}
2239e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS:
2240e8fed0e9SJohn Garry 		case TRANS_TX_ERR_PHY_NOT_ENABLE:
2241e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_CNX_ERR_BY_OTHER:
2242e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT:
2243634a9585SXiang Chen 		case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
2244634a9585SXiang Chen 		case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
2245634a9585SXiang Chen 		case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
2246e8fed0e9SJohn Garry 		case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED:
2247e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_BREAK_TIMEOUT:
2248e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_BREAK_REQUEST:
2249e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_BREAK_RECEVIED:
2250e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT:
2251e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_CLOSE_NORMAL:
2252634a9585SXiang Chen 		case TRANS_TX_ERR_WITH_CLOSE_PHYDISALE:
2253e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT:
2254e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_CLOSE_COMINIT:
2255e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT:
2256e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT:
2257634a9585SXiang Chen 		case TRANS_TX_ERR_WITH_OPEN_BY_DES_OR_OTHERS:
2258e8fed0e9SJohn Garry 		case TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT:
2259e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM:
2260634a9585SXiang Chen 		case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR:
2261e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR:
2262e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_RXFIS_CRC_ERR:
2263e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN:
2264e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP:
2265634a9585SXiang Chen 		case TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN:
2266634a9585SXiang Chen 		case TRANS_RX_ERR_WITH_BREAK_TIMEOUT:
2267634a9585SXiang Chen 		case TRANS_RX_ERR_WITH_BREAK_REQUEST:
2268634a9585SXiang Chen 		case TRANS_RX_ERR_WITH_BREAK_RECEVIED:
2269e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_CLOSE_NORMAL:
2270e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE:
2271e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT:
2272e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_CLOSE_COMINIT:
2273e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_DATA_LEN0:
2274e8fed0e9SJohn Garry 		case TRANS_RX_ERR_WITH_BAD_HASH:
2275e8fed0e9SJohn Garry 		case TRANS_RX_XRDY_WLEN_ZERO_ERR:
2276634a9585SXiang Chen 		case TRANS_RX_ERR_WITH_BAD_FRM_TYPE:
2277634a9585SXiang Chen 		case DMA_TX_DATA_SGL_OVERFLOW:
2278634a9585SXiang Chen 		case DMA_TX_UNEXP_XFER_ERR:
2279634a9585SXiang Chen 		case DMA_TX_UNEXP_RETRANS_ERR:
2280634a9585SXiang Chen 		case DMA_TX_XFER_LEN_OVERFLOW:
2281634a9585SXiang Chen 		case DMA_TX_XFER_OFFSET_ERR:
2282e8fed0e9SJohn Garry 		case SIPC_RX_FIS_STATUS_ERR_BIT_VLD:
2283e8fed0e9SJohn Garry 		case SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR:
2284e8fed0e9SJohn Garry 		case SIPC_RX_FIS_STATUS_BSY_BIT_ERR:
2285e8fed0e9SJohn Garry 		case SIPC_RX_WRSETUP_LEN_ODD_ERR:
2286e8fed0e9SJohn Garry 		case SIPC_RX_WRSETUP_LEN_ZERO_ERR:
2287e8fed0e9SJohn Garry 		case SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR:
2288e8fed0e9SJohn Garry 		case SIPC_RX_SATA_UNEXP_FIS_ERR:
2289634a9585SXiang Chen 		case DMA_RX_DATA_SGL_OVERFLOW:
2290634a9585SXiang Chen 		case DMA_RX_DATA_OFFSET_ERR:
2291e8fed0e9SJohn Garry 		case DMA_RX_SATA_FRAME_TYPE_ERR:
2292e8fed0e9SJohn Garry 		case DMA_RX_UNEXP_RDFRAME_ERR:
2293e8fed0e9SJohn Garry 		case DMA_RX_PIO_DATA_LEN_ERR:
2294e8fed0e9SJohn Garry 		case DMA_RX_RDSETUP_STATUS_ERR:
2295e8fed0e9SJohn Garry 		case DMA_RX_RDSETUP_STATUS_DRQ_ERR:
2296e8fed0e9SJohn Garry 		case DMA_RX_RDSETUP_STATUS_BSY_ERR:
2297e8fed0e9SJohn Garry 		case DMA_RX_RDSETUP_LEN_ODD_ERR:
2298e8fed0e9SJohn Garry 		case DMA_RX_RDSETUP_LEN_ZERO_ERR:
2299e8fed0e9SJohn Garry 		case DMA_RX_RDSETUP_LEN_OVER_ERR:
2300e8fed0e9SJohn Garry 		case DMA_RX_RDSETUP_OFFSET_ERR:
2301e8fed0e9SJohn Garry 		case DMA_RX_RDSETUP_ACTIVE_ERR:
2302e8fed0e9SJohn Garry 		case DMA_RX_RDSETUP_ESTATUS_ERR:
2303e8fed0e9SJohn Garry 		case DMA_RX_UNKNOWN_FRM_ERR:
2304634a9585SXiang Chen 		case TRANS_RX_SSP_FRM_LEN_ERR:
2305634a9585SXiang Chen 		case TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY:
2306e8fed0e9SJohn Garry 		{
2307634a9585SXiang Chen 			slot->abort = 1;
2308634a9585SXiang Chen 			ts->stat = SAS_PHY_DOWN;
2309e8fed0e9SJohn Garry 			break;
2310e8fed0e9SJohn Garry 		}
2311e8fed0e9SJohn Garry 		default:
2312e8fed0e9SJohn Garry 		{
2313e8fed0e9SJohn Garry 			ts->stat = SAS_PROTO_RESPONSE;
2314e8fed0e9SJohn Garry 			break;
2315e8fed0e9SJohn Garry 		}
2316e8fed0e9SJohn Garry 		}
2317f5393a56SXingui Yang 		if (dw0 & CMPLT_HDR_RSPNS_XFRD_MSK)
231875904077SXiang Chen 			hisi_sas_sata_done(task, slot);
2319e8fed0e9SJohn Garry 	}
2320e8fed0e9SJohn Garry 		break;
2321e8fed0e9SJohn Garry 	default:
2322e8fed0e9SJohn Garry 		break;
2323e8fed0e9SJohn Garry 	}
2324e8fed0e9SJohn Garry }
2325e8fed0e9SJohn Garry 
slot_complete_v2_hw(struct hisi_hba * hisi_hba,struct hisi_sas_slot * slot)23261cdee004SJohn Garry static void slot_complete_v2_hw(struct hisi_hba *hisi_hba,
23271cdee004SJohn Garry 				struct hisi_sas_slot *slot)
232831a9cfa6SJohn Garry {
232931a9cfa6SJohn Garry 	struct sas_task *task = slot->task;
233031a9cfa6SJohn Garry 	struct hisi_sas_device *sas_dev;
233111b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
233231a9cfa6SJohn Garry 	struct task_status_struct *ts;
233331a9cfa6SJohn Garry 	struct domain_device *device;
2334cd938e53SXiang Chen 	struct sas_ha_struct *ha;
233531a9cfa6SJohn Garry 	struct hisi_sas_complete_v2_hdr *complete_queue =
233631a9cfa6SJohn Garry 			hisi_hba->complete_hdr[slot->cmplt_queue];
233731a9cfa6SJohn Garry 	struct hisi_sas_complete_v2_hdr *complete_hdr =
233831a9cfa6SJohn Garry 			&complete_queue[slot->cmplt_queue_slot];
233954c9dd2dSJohn Garry 	unsigned long flags;
2340cd938e53SXiang Chen 	bool is_internal = slot->is_internal;
2341735bcc77SJohn Garry 	u32 dw0;
234231a9cfa6SJohn Garry 
234331a9cfa6SJohn Garry 	if (unlikely(!task || !task->lldd_task || !task->dev))
23441cdee004SJohn Garry 		return;
234531a9cfa6SJohn Garry 
234631a9cfa6SJohn Garry 	ts = &task->task_status;
234731a9cfa6SJohn Garry 	device = task->dev;
2348cd938e53SXiang Chen 	ha = device->port->ha;
234931a9cfa6SJohn Garry 	sas_dev = device->lldd_dev;
235031a9cfa6SJohn Garry 
235154c9dd2dSJohn Garry 	spin_lock_irqsave(&task->task_state_lock, flags);
235226fc0ea7SJohn Garry 	task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
235354c9dd2dSJohn Garry 	spin_unlock_irqrestore(&task->task_state_lock, flags);
235431a9cfa6SJohn Garry 
235531a9cfa6SJohn Garry 	memset(ts, 0, sizeof(*ts));
235631a9cfa6SJohn Garry 	ts->resp = SAS_TASK_COMPLETE;
235731a9cfa6SJohn Garry 
2358405314dfSJohn Garry 	if (unlikely(!sas_dev)) {
2359405314dfSJohn Garry 		dev_dbg(dev, "slot complete: port has no device\n");
236031a9cfa6SJohn Garry 		ts->stat = SAS_PHY_DOWN;
236131a9cfa6SJohn Garry 		goto out;
236231a9cfa6SJohn Garry 	}
236331a9cfa6SJohn Garry 
2364df032d0eSJohn Garry 	/* Use SAS+TMF status codes */
2365735bcc77SJohn Garry 	dw0 = le32_to_cpu(complete_hdr->dw0);
2366735bcc77SJohn Garry 	switch ((dw0 & CMPLT_HDR_ABORT_STAT_MSK) >>
2367735bcc77SJohn Garry 		CMPLT_HDR_ABORT_STAT_OFF) {
2368df032d0eSJohn Garry 	case STAT_IO_ABORTED:
2369df032d0eSJohn Garry 		/* this io has been aborted by abort command */
2370df032d0eSJohn Garry 		ts->stat = SAS_ABORTED_TASK;
2371df032d0eSJohn Garry 		goto out;
2372df032d0eSJohn Garry 	case STAT_IO_COMPLETE:
2373df032d0eSJohn Garry 		/* internal abort command complete */
2374c35279f2SJohn Garry 		ts->stat = TMF_RESP_FUNC_SUCC;
2375080b4f97SXiang Chen 		del_timer_sync(&slot->internal_abort_timer);
2376df032d0eSJohn Garry 		goto out;
2377df032d0eSJohn Garry 	case STAT_IO_NO_DEVICE:
2378df032d0eSJohn Garry 		ts->stat = TMF_RESP_FUNC_COMPLETE;
2379080b4f97SXiang Chen 		del_timer_sync(&slot->internal_abort_timer);
2380df032d0eSJohn Garry 		goto out;
2381df032d0eSJohn Garry 	case STAT_IO_NOT_VALID:
2382df032d0eSJohn Garry 		/* abort single io, controller don't find
2383df032d0eSJohn Garry 		 * the io need to abort
2384df032d0eSJohn Garry 		 */
2385df032d0eSJohn Garry 		ts->stat = TMF_RESP_FUNC_FAILED;
2386080b4f97SXiang Chen 		del_timer_sync(&slot->internal_abort_timer);
2387df032d0eSJohn Garry 		goto out;
2388df032d0eSJohn Garry 	default:
2389df032d0eSJohn Garry 		break;
2390df032d0eSJohn Garry 	}
2391df032d0eSJohn Garry 
2392735bcc77SJohn Garry 	if ((dw0 & CMPLT_HDR_ERX_MSK) && (!(dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) {
2393735bcc77SJohn Garry 		u32 err_phase = (dw0 & CMPLT_HDR_ERR_PHASE_MSK)
2394634a9585SXiang Chen 				>> CMPLT_HDR_ERR_PHASE_OFF;
2395f1c88211SXiang Chen 		u32 *error_info = hisi_sas_status_buf_addr_mem(slot);
239631a9cfa6SJohn Garry 
2397634a9585SXiang Chen 		/* Analyse error happens on which phase TX or RX */
2398634a9585SXiang Chen 		if (ERR_ON_TX_PHASE(err_phase))
2399634a9585SXiang Chen 			slot_err_v2_hw(hisi_hba, task, slot, 1);
2400634a9585SXiang Chen 		else if (ERR_ON_RX_PHASE(err_phase))
2401634a9585SXiang Chen 			slot_err_v2_hw(hisi_hba, task, slot, 2);
2402fc866951SXiang Chen 
2403f1c88211SXiang Chen 		if (ts->stat != SAS_DATA_UNDERRUN)
2404e7513f66SXiang Chen 			dev_info(dev, "erroneous completion iptt=%d task=%pK dev id=%d CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n",
2405381ed6c0SJohn Garry 				 slot->idx, task, sas_dev->device_id,
2406f1c88211SXiang Chen 				 complete_hdr->dw0, complete_hdr->dw1,
2407f1c88211SXiang Chen 				 complete_hdr->act, complete_hdr->dw3,
2408f1c88211SXiang Chen 				 error_info[0], error_info[1],
2409f1c88211SXiang Chen 				 error_info[2], error_info[3]);
2410f1c88211SXiang Chen 
241105d91b55SLuo Jiaxing 		if (unlikely(slot->abort)) {
2412bb544224SXingui Yang 			if (dev_is_sata(device) && task->ata_task.use_ncq)
2413bb544224SXingui Yang 				sas_ata_device_link_abort(device, true);
2414bb544224SXingui Yang 			else
241505d91b55SLuo Jiaxing 				sas_task_abort(task);
2416bb544224SXingui Yang 
24171cdee004SJohn Garry 			return;
241805d91b55SLuo Jiaxing 		}
241931a9cfa6SJohn Garry 		goto out;
242031a9cfa6SJohn Garry 	}
242131a9cfa6SJohn Garry 
242231a9cfa6SJohn Garry 	switch (task->task_proto) {
242331a9cfa6SJohn Garry 	case SAS_PROTOCOL_SSP:
242431a9cfa6SJohn Garry 	{
2425f557e32cSXiaofei Tan 		struct hisi_sas_status_buffer *status_buffer =
2426f557e32cSXiaofei Tan 				hisi_sas_status_buf_addr_mem(slot);
2427f557e32cSXiaofei Tan 		struct ssp_response_iu *iu = (struct ssp_response_iu *)
2428f557e32cSXiaofei Tan 				&status_buffer->iu[0];
242931a9cfa6SJohn Garry 
243031a9cfa6SJohn Garry 		sas_ssp_task_response(dev, task, iu);
243131a9cfa6SJohn Garry 		break;
243231a9cfa6SJohn Garry 	}
243331a9cfa6SJohn Garry 	case SAS_PROTOCOL_SMP:
243431a9cfa6SJohn Garry 	{
243531a9cfa6SJohn Garry 		struct scatterlist *sg_resp = &task->smp_task.smp_resp;
24361c003146SJohn Garry 		void *to = page_address(sg_page(sg_resp));
243731a9cfa6SJohn Garry 
2438d377f415SBart Van Assche 		ts->stat = SAS_SAM_STAT_GOOD;
243931a9cfa6SJohn Garry 
244031a9cfa6SJohn Garry 		memcpy(to + sg_resp->offset,
2441f557e32cSXiaofei Tan 		       hisi_sas_status_buf_addr_mem(slot) +
244231a9cfa6SJohn Garry 		       sizeof(struct hisi_sas_err_record),
24435f6c32d7SJohn Garry 		       sg_resp->length);
244431a9cfa6SJohn Garry 		break;
244531a9cfa6SJohn Garry 	}
244631a9cfa6SJohn Garry 	case SAS_PROTOCOL_SATA:
244731a9cfa6SJohn Garry 	case SAS_PROTOCOL_STP:
244831a9cfa6SJohn Garry 	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
24496f2ff1a1SJohn Garry 	{
2450d377f415SBart Van Assche 		ts->stat = SAS_SAM_STAT_GOOD;
2451f5393a56SXingui Yang 		if (dw0 & CMPLT_HDR_RSPNS_XFRD_MSK)
245275904077SXiang Chen 			hisi_sas_sata_done(task, slot);
24536f2ff1a1SJohn Garry 		break;
24546f2ff1a1SJohn Garry 	}
245531a9cfa6SJohn Garry 	default:
2456d377f415SBart Van Assche 		ts->stat = SAS_SAM_STAT_CHECK_CONDITION;
245731a9cfa6SJohn Garry 		break;
245831a9cfa6SJohn Garry 	}
245931a9cfa6SJohn Garry 
246031a9cfa6SJohn Garry 	if (!slot->port->port_attached) {
2461f1c88211SXiang Chen 		dev_warn(dev, "slot complete: port %d has removed\n",
246231a9cfa6SJohn Garry 			slot->port->sas_port.id);
246331a9cfa6SJohn Garry 		ts->stat = SAS_PHY_DOWN;
246431a9cfa6SJohn Garry 	}
246531a9cfa6SJohn Garry 
246631a9cfa6SJohn Garry out:
246754c9dd2dSJohn Garry 	spin_lock_irqsave(&task->task_state_lock, flags);
2468b81b6cceSXiang Chen 	if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
2469b81b6cceSXiang Chen 		spin_unlock_irqrestore(&task->task_state_lock, flags);
2470e7513f66SXiang Chen 		dev_info(dev, "slot complete: task(%pK) aborted\n", task);
24711cdee004SJohn Garry 		return;
2472b81b6cceSXiang Chen 	}
2473fc866951SXiang Chen 	task->task_state_flags |= SAS_TASK_STATE_DONE;
247454c9dd2dSJohn Garry 	spin_unlock_irqrestore(&task->task_state_lock, flags);
247571fb36b5SXingui Yang 	hisi_sas_slot_task_free(hisi_hba, task, slot, true);
247631a9cfa6SJohn Garry 
2477cd938e53SXiang Chen 	if (!is_internal && (task->task_proto != SAS_PROTOCOL_SMP)) {
2478cd938e53SXiang Chen 		spin_lock_irqsave(&device->done_lock, flags);
2479cd938e53SXiang Chen 		if (test_bit(SAS_HA_FROZEN, &ha->state)) {
2480cd938e53SXiang Chen 			spin_unlock_irqrestore(&device->done_lock, flags);
2481e7513f66SXiang Chen 			dev_info(dev, "slot complete: task(%pK) ignored\n",
2482cd938e53SXiang Chen 				 task);
24831cdee004SJohn Garry 			return;
2484cd938e53SXiang Chen 		}
2485cd938e53SXiang Chen 		spin_unlock_irqrestore(&device->done_lock, flags);
2486cd938e53SXiang Chen 	}
2487cd938e53SXiang Chen 
248831a9cfa6SJohn Garry 	if (task->task_done)
248931a9cfa6SJohn Garry 		task->task_done(task);
249031a9cfa6SJohn Garry }
249131a9cfa6SJohn Garry 
prep_ata_v2_hw(struct hisi_hba * hisi_hba,struct hisi_sas_slot * slot)2492a2b3820bSXiang Chen static void prep_ata_v2_hw(struct hisi_hba *hisi_hba,
24936f2ff1a1SJohn Garry 			  struct hisi_sas_slot *slot)
24946f2ff1a1SJohn Garry {
24956f2ff1a1SJohn Garry 	struct sas_task *task = slot->task;
24966f2ff1a1SJohn Garry 	struct domain_device *device = task->dev;
24976f2ff1a1SJohn Garry 	struct domain_device *parent_dev = device->parent;
24986f2ff1a1SJohn Garry 	struct hisi_sas_device *sas_dev = device->lldd_dev;
24996f2ff1a1SJohn Garry 	struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
25002e244f0fSJohn Garry 	struct asd_sas_port *sas_port = device->port;
25012e244f0fSJohn Garry 	struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
25023f2e252eSJohn Garry 	struct sas_ata_task *ata_task = &task->ata_task;
2503bbfe82cdSJohn Garry 	struct sas_tmf_task *tmf = slot->tmf;
25046f2ff1a1SJohn Garry 	u8 *buf_cmd;
2505a2b3820bSXiang Chen 	int has_data = 0, hdr_tag = 0;
2506735bcc77SJohn Garry 	u32 dw0, dw1 = 0, dw2 = 0;
25076f2ff1a1SJohn Garry 
25086f2ff1a1SJohn Garry 	/* create header */
25096f2ff1a1SJohn Garry 	/* dw0 */
2510735bcc77SJohn Garry 	dw0 = port->id << CMD_HDR_PORT_OFF;
2511924a3541SJohn Garry 	if (parent_dev && dev_is_expander(parent_dev->dev_type))
2512735bcc77SJohn Garry 		dw0 |= 3 << CMD_HDR_CMD_OFF;
25136f2ff1a1SJohn Garry 	else
2514735bcc77SJohn Garry 		dw0 |= 4 << CMD_HDR_CMD_OFF;
25156f2ff1a1SJohn Garry 
25163f2e252eSJohn Garry 	if (tmf && ata_task->force_phy) {
2517735bcc77SJohn Garry 		dw0 |= CMD_HDR_FORCE_PHY_MSK;
25183f2e252eSJohn Garry 		dw0 |= (1 << ata_task->force_phy_id) << CMD_HDR_PHY_ID_OFF;
2519b09fcd09SXiaofei Tan 	}
2520b09fcd09SXiaofei Tan 
2521735bcc77SJohn Garry 	hdr->dw0 = cpu_to_le32(dw0);
2522735bcc77SJohn Garry 
25236f2ff1a1SJohn Garry 	/* dw1 */
25246f2ff1a1SJohn Garry 	switch (task->data_dir) {
25256f2ff1a1SJohn Garry 	case DMA_TO_DEVICE:
25266f2ff1a1SJohn Garry 		has_data = 1;
25276f2ff1a1SJohn Garry 		dw1 |= DIR_TO_DEVICE << CMD_HDR_DIR_OFF;
25286f2ff1a1SJohn Garry 		break;
25296f2ff1a1SJohn Garry 	case DMA_FROM_DEVICE:
25306f2ff1a1SJohn Garry 		has_data = 1;
25316f2ff1a1SJohn Garry 		dw1 |= DIR_TO_INI << CMD_HDR_DIR_OFF;
25326f2ff1a1SJohn Garry 		break;
25336f2ff1a1SJohn Garry 	default:
25346f2ff1a1SJohn Garry 		dw1 &= ~CMD_HDR_DIR_MSK;
25356f2ff1a1SJohn Garry 	}
25366f2ff1a1SJohn Garry 
25377c594f04SXiang Chen 	if ((task->ata_task.fis.command == ATA_CMD_DEV_RESET) &&
25387c594f04SXiang Chen 			(task->ata_task.fis.control & ATA_SRST))
25396f2ff1a1SJohn Garry 		dw1 |= 1 << CMD_HDR_RESET_OFF;
25406f2ff1a1SJohn Garry 
25416c7bb8a1SXiang Chen 	dw1 |= (hisi_sas_get_ata_protocol(
2542468f4b8dSchenxiang 		&task->ata_task.fis, task->data_dir))
25436f2ff1a1SJohn Garry 		<< CMD_HDR_FRAME_TYPE_OFF;
25446f2ff1a1SJohn Garry 	dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF;
25456f2ff1a1SJohn Garry 	hdr->dw1 = cpu_to_le32(dw1);
25466f2ff1a1SJohn Garry 
25476f2ff1a1SJohn Garry 	/* dw2 */
2548435a05cfSXiang Chen 	if (task->ata_task.use_ncq) {
2549435a05cfSXiang Chen 		struct ata_queued_cmd *qc = task->uldd_task;
2550435a05cfSXiang Chen 
2551435a05cfSXiang Chen 		hdr_tag = qc->tag;
25526f2ff1a1SJohn Garry 		task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
25536f2ff1a1SJohn Garry 		dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF;
25546f2ff1a1SJohn Garry 	}
25556f2ff1a1SJohn Garry 
25566f2ff1a1SJohn Garry 	dw2 |= (HISI_SAS_MAX_STP_RESP_SZ / 4) << CMD_HDR_CFL_OFF |
25576f2ff1a1SJohn Garry 			2 << CMD_HDR_SG_MOD_OFF;
25586f2ff1a1SJohn Garry 	hdr->dw2 = cpu_to_le32(dw2);
25596f2ff1a1SJohn Garry 
25606f2ff1a1SJohn Garry 	/* dw3 */
25616f2ff1a1SJohn Garry 	hdr->transfer_tags = cpu_to_le32(slot->idx);
25626f2ff1a1SJohn Garry 
2563a2b3820bSXiang Chen 	if (has_data)
2564a2b3820bSXiang Chen 		prep_prd_sge_v2_hw(hisi_hba, slot, hdr, task->scatter,
25656f2ff1a1SJohn Garry 					slot->n_elem);
25666f2ff1a1SJohn Garry 
25676f2ff1a1SJohn Garry 	hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
2568f557e32cSXiaofei Tan 	hdr->cmd_table_addr = cpu_to_le64(hisi_sas_cmd_hdr_addr_dma(slot));
2569f557e32cSXiaofei Tan 	hdr->sts_buffer_addr = cpu_to_le64(hisi_sas_status_buf_addr_dma(slot));
25706f2ff1a1SJohn Garry 
2571f557e32cSXiaofei Tan 	buf_cmd = hisi_sas_cmd_hdr_addr_mem(slot);
25726f2ff1a1SJohn Garry 
25736f2ff1a1SJohn Garry 	if (likely(!task->ata_task.device_control_reg_update))
25746f2ff1a1SJohn Garry 		task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
25756f2ff1a1SJohn Garry 	/* fill in command FIS */
25766f2ff1a1SJohn Garry 	memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
25776f2ff1a1SJohn Garry }
25786f2ff1a1SJohn Garry 
hisi_sas_internal_abort_quirk_timeout(struct timer_list * t)257977570eedSKees Cook static void hisi_sas_internal_abort_quirk_timeout(struct timer_list *t)
25800844a3ffSJohn Garry {
258177570eedSKees Cook 	struct hisi_sas_slot *slot = from_timer(slot, t, internal_abort_timer);
25820844a3ffSJohn Garry 	struct hisi_sas_port *port = slot->port;
25830844a3ffSJohn Garry 	struct asd_sas_port *asd_sas_port;
25840844a3ffSJohn Garry 	struct asd_sas_phy *sas_phy;
25850844a3ffSJohn Garry 
25860844a3ffSJohn Garry 	if (!port)
25870844a3ffSJohn Garry 		return;
25880844a3ffSJohn Garry 
25890844a3ffSJohn Garry 	asd_sas_port = &port->sas_port;
25900844a3ffSJohn Garry 
25910844a3ffSJohn Garry 	/* Kick the hardware - send break command */
25920844a3ffSJohn Garry 	list_for_each_entry(sas_phy, &asd_sas_port->phy_list, port_phy_el) {
25930844a3ffSJohn Garry 		struct hisi_sas_phy *phy = sas_phy->lldd_phy;
25940844a3ffSJohn Garry 		struct hisi_hba *hisi_hba = phy->hisi_hba;
25950844a3ffSJohn Garry 		int phy_no = sas_phy->id;
25960844a3ffSJohn Garry 		u32 link_dfx2;
25970844a3ffSJohn Garry 
25980844a3ffSJohn Garry 		link_dfx2 = hisi_sas_phy_read32(hisi_hba, phy_no, LINK_DFX2);
25990844a3ffSJohn Garry 		if ((link_dfx2 == LINK_DFX2_RCVR_HOLD_STS_MSK) ||
26000844a3ffSJohn Garry 		    (link_dfx2 & LINK_DFX2_SEND_HOLD_STS_MSK)) {
26010844a3ffSJohn Garry 			u32 txid_auto;
26020844a3ffSJohn Garry 
26030844a3ffSJohn Garry 			txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no,
26040844a3ffSJohn Garry 							TXID_AUTO);
26050844a3ffSJohn Garry 			txid_auto |= TXID_AUTO_CTB_MSK;
26060844a3ffSJohn Garry 			hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
26070844a3ffSJohn Garry 					     txid_auto);
26080844a3ffSJohn Garry 			return;
26090844a3ffSJohn Garry 		}
26100844a3ffSJohn Garry 	}
26110844a3ffSJohn Garry }
26120844a3ffSJohn Garry 
prep_abort_v2_hw(struct hisi_hba * hisi_hba,struct hisi_sas_slot * slot)2613a2b3820bSXiang Chen static void prep_abort_v2_hw(struct hisi_hba *hisi_hba,
2614095478a6SJohn Garry 			     struct hisi_sas_slot *slot)
2615a3e665d9SJohn Garry {
2616a3e665d9SJohn Garry 	struct sas_task *task = slot->task;
2617095478a6SJohn Garry 	struct sas_internal_abort_task *abort = &task->abort_task;
2618a3e665d9SJohn Garry 	struct domain_device *dev = task->dev;
2619a3e665d9SJohn Garry 	struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
2620a3e665d9SJohn Garry 	struct hisi_sas_port *port = slot->port;
26210844a3ffSJohn Garry 	struct timer_list *timer = &slot->internal_abort_timer;
2622095478a6SJohn Garry 	struct hisi_sas_device *sas_dev = dev->lldd_dev;
26230844a3ffSJohn Garry 
26240844a3ffSJohn Garry 	/* setup the quirk timer */
262577570eedSKees Cook 	timer_setup(timer, hisi_sas_internal_abort_quirk_timeout, 0);
26260844a3ffSJohn Garry 	/* Set the timeout to 10ms less than internal abort timeout */
26270844a3ffSJohn Garry 	mod_timer(timer, jiffies + msecs_to_jiffies(100));
2628a3e665d9SJohn Garry 
2629a3e665d9SJohn Garry 	/* dw0 */
2630a3e665d9SJohn Garry 	hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/
2631a3e665d9SJohn Garry 			       (port->id << CMD_HDR_PORT_OFF) |
2632edafeef4SXiang Chen 			       (dev_is_sata(dev) <<
2633a3e665d9SJohn Garry 				CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
2634095478a6SJohn Garry 			       (abort->type << CMD_HDR_ABORT_FLAG_OFF));
2635a3e665d9SJohn Garry 
2636a3e665d9SJohn Garry 	/* dw1 */
2637095478a6SJohn Garry 	hdr->dw1 = cpu_to_le32(sas_dev->device_id << CMD_HDR_DEV_ID_OFF);
2638a3e665d9SJohn Garry 
2639a3e665d9SJohn Garry 	/* dw7 */
2640095478a6SJohn Garry 	hdr->dw7 = cpu_to_le32(abort->tag << CMD_HDR_ABORT_IPTT_OFF);
2641a3e665d9SJohn Garry 	hdr->transfer_tags = cpu_to_le32(slot->idx);
2642a3e665d9SJohn Garry }
2643a3e665d9SJohn Garry 
phy_up_v2_hw(int phy_no,struct hisi_hba * hisi_hba)26447911e66fSJohn Garry static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
26457911e66fSJohn Garry {
2646981843c6SXiaofei Tan 	int i, res = IRQ_HANDLED;
2647eba8c20cSXiaofei Tan 	u32 port_id, link_rate;
26487911e66fSJohn Garry 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
26497911e66fSJohn Garry 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
265011b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
26517911e66fSJohn Garry 	u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
26527911e66fSJohn Garry 	struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd;
26537911e66fSJohn Garry 
26547911e66fSJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
26557911e66fSJohn Garry 
26564935933eSXiaofei Tan 	if (is_sata_phy_v2_hw(hisi_hba, phy_no))
26577911e66fSJohn Garry 		goto end;
26587911e66fSJohn Garry 
2659b6c9b15eSXiaofei Tan 	del_timer(&phy->timer);
2660b6c9b15eSXiaofei Tan 
26617911e66fSJohn Garry 	if (phy_no == 8) {
26627911e66fSJohn Garry 		u32 port_state = hisi_sas_read32(hisi_hba, PORT_STATE);
26637911e66fSJohn Garry 
26647911e66fSJohn Garry 		port_id = (port_state & PORT_STATE_PHY8_PORT_NUM_MSK) >>
26657911e66fSJohn Garry 			  PORT_STATE_PHY8_PORT_NUM_OFF;
26667911e66fSJohn Garry 		link_rate = (port_state & PORT_STATE_PHY8_CONN_RATE_MSK) >>
26677911e66fSJohn Garry 			    PORT_STATE_PHY8_CONN_RATE_OFF;
26687911e66fSJohn Garry 	} else {
26697911e66fSJohn Garry 		port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
26707911e66fSJohn Garry 		port_id = (port_id >> (4 * phy_no)) & 0xf;
26717911e66fSJohn Garry 		link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
26727911e66fSJohn Garry 		link_rate = (link_rate >> (phy_no * 4)) & 0xf;
26737911e66fSJohn Garry 	}
26747911e66fSJohn Garry 
26757911e66fSJohn Garry 	if (port_id == 0xf) {
26767911e66fSJohn Garry 		dev_err(dev, "phyup: phy%d invalid portid\n", phy_no);
26777911e66fSJohn Garry 		res = IRQ_NONE;
26787911e66fSJohn Garry 		goto end;
26797911e66fSJohn Garry 	}
26807911e66fSJohn Garry 
26817911e66fSJohn Garry 	for (i = 0; i < 6; i++) {
26827911e66fSJohn Garry 		u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no,
26837911e66fSJohn Garry 					       RX_IDAF_DWORD0 + (i * 4));
26847911e66fSJohn Garry 		frame_rcvd[i] = __swab32(idaf);
26857911e66fSJohn Garry 	}
26867911e66fSJohn Garry 
26877911e66fSJohn Garry 	sas_phy->linkrate = link_rate;
26887911e66fSJohn Garry 	sas_phy->oob_mode = SAS_OOB_MODE;
26897911e66fSJohn Garry 	memcpy(sas_phy->attached_sas_addr, &id->sas_addr, SAS_ADDR_SIZE);
26907911e66fSJohn Garry 	dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate);
26917911e66fSJohn Garry 	phy->port_id = port_id;
26927911e66fSJohn Garry 	phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
26937911e66fSJohn Garry 	phy->phy_type |= PORT_TYPE_SAS;
26947911e66fSJohn Garry 	phy->phy_attached = 1;
26957911e66fSJohn Garry 	phy->identify.device_type = id->dev_type;
26967911e66fSJohn Garry 	phy->frame_rcvd_size =	sizeof(struct sas_identify_frame);
26977911e66fSJohn Garry 	if (phy->identify.device_type == SAS_END_DEVICE)
26987911e66fSJohn Garry 		phy->identify.target_port_protocols =
26997911e66fSJohn Garry 			SAS_PROTOCOL_SSP;
2700f2f89c32SXiang Chen 	else if (phy->identify.device_type != SAS_PHY_UNUSED) {
27017911e66fSJohn Garry 		phy->identify.target_port_protocols =
27027911e66fSJohn Garry 			SAS_PROTOCOL_SMP;
2703f2f89c32SXiang Chen 		if (!timer_pending(&hisi_hba->timer))
2704f2f89c32SXiang Chen 			set_link_timer_quirk(hisi_hba);
2705f2f89c32SXiang Chen 	}
2706e537b62bSXiaofei Tan 	hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
27077911e66fSJohn Garry end:
2708046ab7d0SXiang Chen 	if (phy->reset_completion)
2709046ab7d0SXiang Chen 		complete(phy->reset_completion);
27107911e66fSJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
27117911e66fSJohn Garry 			     CHL_INT0_SL_PHY_ENABLE_MSK);
27127911e66fSJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 0);
27137911e66fSJohn Garry 
27147911e66fSJohn Garry 	return res;
27157911e66fSJohn Garry }
27167911e66fSJohn Garry 
check_any_wideports_v2_hw(struct hisi_hba * hisi_hba)2717f2f89c32SXiang Chen static bool check_any_wideports_v2_hw(struct hisi_hba *hisi_hba)
2718f2f89c32SXiang Chen {
2719f2f89c32SXiang Chen 	u32 port_state;
2720f2f89c32SXiang Chen 
2721f2f89c32SXiang Chen 	port_state = hisi_sas_read32(hisi_hba, PORT_STATE);
2722f2f89c32SXiang Chen 	if (port_state & 0x1ff)
2723f2f89c32SXiang Chen 		return true;
2724f2f89c32SXiang Chen 
2725f2f89c32SXiang Chen 	return false;
2726f2f89c32SXiang Chen }
2727f2f89c32SXiang Chen 
phy_down_v2_hw(int phy_no,struct hisi_hba * hisi_hba)27285473c060SJohn Garry static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
27295473c060SJohn Garry {
27309c81e2cfSJohn Garry 	u32 phy_state, sl_ctrl, txid_auto;
2731f2f89c32SXiang Chen 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
2732f2f89c32SXiang Chen 	struct hisi_sas_port *port = phy->port;
2733f1c88211SXiang Chen 	struct device *dev = hisi_hba->dev;
27345473c060SJohn Garry 
2735b6c9b15eSXiaofei Tan 	del_timer(&phy->timer);
27365473c060SJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1);
27375473c060SJohn Garry 
27385473c060SJohn Garry 	phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
2739f1c88211SXiang Chen 	dev_info(dev, "phydown: phy%d phy_state=0x%x\n", phy_no, phy_state);
274026c7efc3SAhmed S. Darwish 	hisi_sas_phy_down(hisi_hba, phy_no, (phy_state & 1 << phy_no) ? 1 : 0,
274126c7efc3SAhmed S. Darwish 			  GFP_ATOMIC);
27425473c060SJohn Garry 
27439c81e2cfSJohn Garry 	sl_ctrl = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
27449c81e2cfSJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL,
27459c81e2cfSJohn Garry 			     sl_ctrl & ~SL_CONTROL_CTA_MSK);
2746f2f89c32SXiang Chen 	if (port && !get_wideport_bitmap_v2_hw(hisi_hba, port->id))
2747f2f89c32SXiang Chen 		if (!check_any_wideports_v2_hw(hisi_hba) &&
2748f2f89c32SXiang Chen 				timer_pending(&hisi_hba->timer))
2749f2f89c32SXiang Chen 			del_timer(&hisi_hba->timer);
27509c81e2cfSJohn Garry 
27519c81e2cfSJohn Garry 	txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO);
27529c81e2cfSJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
27539c81e2cfSJohn Garry 			     txid_auto | TXID_AUTO_CT3_MSK);
27549c81e2cfSJohn Garry 
27555473c060SJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_NOT_RDY_MSK);
27565473c060SJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 0);
27575473c060SJohn Garry 
2758981843c6SXiaofei Tan 	return IRQ_HANDLED;
27595473c060SJohn Garry }
27605473c060SJohn Garry 
int_phy_updown_v2_hw(int irq_no,void * p)27617911e66fSJohn Garry static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
27627911e66fSJohn Garry {
27637911e66fSJohn Garry 	struct hisi_hba *hisi_hba = p;
27647911e66fSJohn Garry 	u32 irq_msk;
27657911e66fSJohn Garry 	int phy_no = 0;
2766c16db736SXiang Chen 	irqreturn_t res = IRQ_NONE;
27677911e66fSJohn Garry 
27687911e66fSJohn Garry 	irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO)
27697911e66fSJohn Garry 		   >> HGC_INVLD_DQE_INFO_FB_CH0_OFF) & 0x1ff;
27707911e66fSJohn Garry 	while (irq_msk) {
27717911e66fSJohn Garry 		if (irq_msk  & 1) {
2772981843c6SXiaofei Tan 			u32 reg_value = hisi_sas_phy_read32(hisi_hba, phy_no,
27737911e66fSJohn Garry 					    CHL_INT0);
27747911e66fSJohn Garry 
2775981843c6SXiaofei Tan 			switch (reg_value & (CHL_INT0_NOT_RDY_MSK |
2776981843c6SXiaofei Tan 					CHL_INT0_SL_PHY_ENABLE_MSK)) {
2777981843c6SXiaofei Tan 
2778981843c6SXiaofei Tan 			case CHL_INT0_SL_PHY_ENABLE_MSK:
27797911e66fSJohn Garry 				/* phy up */
2780981843c6SXiaofei Tan 				if (phy_up_v2_hw(phy_no, hisi_hba) ==
2781c16db736SXiang Chen 				    IRQ_HANDLED)
2782c16db736SXiang Chen 					res = IRQ_HANDLED;
2783981843c6SXiaofei Tan 				break;
2784981843c6SXiaofei Tan 
2785981843c6SXiaofei Tan 			case CHL_INT0_NOT_RDY_MSK:
2786981843c6SXiaofei Tan 				/* phy down */
2787981843c6SXiaofei Tan 				if (phy_down_v2_hw(phy_no, hisi_hba) ==
2788c16db736SXiang Chen 				    IRQ_HANDLED)
2789c16db736SXiang Chen 					res = IRQ_HANDLED;
2790981843c6SXiaofei Tan 				break;
2791981843c6SXiaofei Tan 
2792981843c6SXiaofei Tan 			case (CHL_INT0_NOT_RDY_MSK |
2793981843c6SXiaofei Tan 					CHL_INT0_SL_PHY_ENABLE_MSK):
2794981843c6SXiaofei Tan 				reg_value = hisi_sas_read32(hisi_hba,
2795981843c6SXiaofei Tan 						PHY_STATE);
2796981843c6SXiaofei Tan 				if (reg_value & BIT(phy_no)) {
2797981843c6SXiaofei Tan 					/* phy up */
2798981843c6SXiaofei Tan 					if (phy_up_v2_hw(phy_no, hisi_hba) ==
2799c16db736SXiang Chen 					    IRQ_HANDLED)
2800c16db736SXiang Chen 						res = IRQ_HANDLED;
2801981843c6SXiaofei Tan 				} else {
2802981843c6SXiaofei Tan 					/* phy down */
2803981843c6SXiaofei Tan 					if (phy_down_v2_hw(phy_no, hisi_hba) ==
2804c16db736SXiang Chen 					    IRQ_HANDLED)
2805c16db736SXiang Chen 						res = IRQ_HANDLED;
2806981843c6SXiaofei Tan 				}
2807981843c6SXiaofei Tan 				break;
2808981843c6SXiaofei Tan 
2809981843c6SXiaofei Tan 			default:
2810981843c6SXiaofei Tan 				break;
28117911e66fSJohn Garry 			}
28127911e66fSJohn Garry 
28137911e66fSJohn Garry 		}
28147911e66fSJohn Garry 		irq_msk >>= 1;
28157911e66fSJohn Garry 		phy_no++;
28167911e66fSJohn Garry 	}
28177911e66fSJohn Garry 
2818c16db736SXiang Chen 	return res;
28197911e66fSJohn Garry }
28207911e66fSJohn Garry 
phy_bcast_v2_hw(int phy_no,struct hisi_hba * hisi_hba)2821d3bf3d84SJohn Garry static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
2822d3bf3d84SJohn Garry {
2823d3bf3d84SJohn Garry 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
282485080a25SXiang Chen 	u32 bcast_status;
2825d3bf3d84SJohn Garry 
2826d3bf3d84SJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 1);
282785080a25SXiang Chen 	bcast_status = hisi_sas_phy_read32(hisi_hba, phy_no, RX_PRIMS_STATUS);
2828e9b6badaSJohn Garry 	if (bcast_status & RX_BCAST_CHG_MSK)
2829e9b6badaSJohn Garry 		hisi_sas_phy_bcast(phy);
2830d3bf3d84SJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
2831d3bf3d84SJohn Garry 			     CHL_INT0_SL_RX_BCST_ACK_MSK);
2832d3bf3d84SJohn Garry 	hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 0);
2833d3bf3d84SJohn Garry }
2834d3bf3d84SJohn Garry 
283572f7fc30SXiaofei Tan static const struct hisi_sas_hw_error port_ecc_axi_error[] = {
283672f7fc30SXiaofei Tan 	{
283772f7fc30SXiaofei Tan 		.irq_msk = BIT(CHL_INT1_DMAC_TX_ECC_ERR_OFF),
283872f7fc30SXiaofei Tan 		.msg = "dmac_tx_ecc_bad_err",
283972f7fc30SXiaofei Tan 	},
284072f7fc30SXiaofei Tan 	{
284172f7fc30SXiaofei Tan 		.irq_msk = BIT(CHL_INT1_DMAC_RX_ECC_ERR_OFF),
284272f7fc30SXiaofei Tan 		.msg = "dmac_rx_ecc_bad_err",
284372f7fc30SXiaofei Tan 	},
284472f7fc30SXiaofei Tan 	{
284572f7fc30SXiaofei Tan 		.irq_msk = BIT(CHL_INT1_DMAC_TX_AXI_WR_ERR_OFF),
284672f7fc30SXiaofei Tan 		.msg = "dma_tx_axi_wr_err",
284772f7fc30SXiaofei Tan 	},
284872f7fc30SXiaofei Tan 	{
284972f7fc30SXiaofei Tan 		.irq_msk = BIT(CHL_INT1_DMAC_TX_AXI_RD_ERR_OFF),
285072f7fc30SXiaofei Tan 		.msg = "dma_tx_axi_rd_err",
285172f7fc30SXiaofei Tan 	},
285272f7fc30SXiaofei Tan 	{
285372f7fc30SXiaofei Tan 		.irq_msk = BIT(CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF),
285472f7fc30SXiaofei Tan 		.msg = "dma_rx_axi_wr_err",
285572f7fc30SXiaofei Tan 	},
285672f7fc30SXiaofei Tan 	{
285772f7fc30SXiaofei Tan 		.irq_msk = BIT(CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF),
285872f7fc30SXiaofei Tan 		.msg = "dma_rx_axi_rd_err",
285972f7fc30SXiaofei Tan 	},
286072f7fc30SXiaofei Tan };
286172f7fc30SXiaofei Tan 
int_chnl_int_v2_hw(int irq_no,void * p)2862d3bf3d84SJohn Garry static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
2863d3bf3d84SJohn Garry {
2864d3bf3d84SJohn Garry 	struct hisi_hba *hisi_hba = p;
286511b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
2866d3bf3d84SJohn Garry 	u32 ent_msk, ent_tmp, irq_msk;
2867d3bf3d84SJohn Garry 	int phy_no = 0;
2868d3bf3d84SJohn Garry 
2869d3bf3d84SJohn Garry 	ent_msk = hisi_sas_read32(hisi_hba, ENT_INT_SRC_MSK3);
2870d3bf3d84SJohn Garry 	ent_tmp = ent_msk;
2871d3bf3d84SJohn Garry 	ent_msk |= ENT_INT_SRC_MSK3_ENT95_MSK_MSK;
2872d3bf3d84SJohn Garry 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, ent_msk);
2873d3bf3d84SJohn Garry 
2874d3bf3d84SJohn Garry 	irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO) >>
2875d3bf3d84SJohn Garry 			HGC_INVLD_DQE_INFO_FB_CH3_OFF) & 0x1ff;
2876d3bf3d84SJohn Garry 
2877d3bf3d84SJohn Garry 	while (irq_msk) {
2878d3bf3d84SJohn Garry 		u32 irq_value0 = hisi_sas_phy_read32(hisi_hba, phy_no,
2879d3bf3d84SJohn Garry 						     CHL_INT0);
2880d3bf3d84SJohn Garry 		u32 irq_value1 = hisi_sas_phy_read32(hisi_hba, phy_no,
2881d3bf3d84SJohn Garry 						     CHL_INT1);
2882d3bf3d84SJohn Garry 		u32 irq_value2 = hisi_sas_phy_read32(hisi_hba, phy_no,
2883d3bf3d84SJohn Garry 						     CHL_INT2);
2884d3bf3d84SJohn Garry 
2885f64715d2SXiaofei Tan 		if ((irq_msk & (1 << phy_no)) && irq_value1) {
288672f7fc30SXiaofei Tan 			int i;
288772f7fc30SXiaofei Tan 
288872f7fc30SXiaofei Tan 			for (i = 0; i < ARRAY_SIZE(port_ecc_axi_error); i++) {
288972f7fc30SXiaofei Tan 				const struct hisi_sas_hw_error *error =
289072f7fc30SXiaofei Tan 						&port_ecc_axi_error[i];
289172f7fc30SXiaofei Tan 
289272f7fc30SXiaofei Tan 				if (!(irq_value1 & error->irq_msk))
289372f7fc30SXiaofei Tan 					continue;
289472f7fc30SXiaofei Tan 
289572f7fc30SXiaofei Tan 				dev_warn(dev, "%s error (phy%d 0x%x) found!\n",
289672f7fc30SXiaofei Tan 					error->msg, phy_no, irq_value1);
289772f7fc30SXiaofei Tan 				queue_work(hisi_hba->wq, &hisi_hba->rst_work);
289872f7fc30SXiaofei Tan 			}
2899d3bf3d84SJohn Garry 
2900d3bf3d84SJohn Garry 			hisi_sas_phy_write32(hisi_hba, phy_no,
2901d3bf3d84SJohn Garry 					     CHL_INT1, irq_value1);
2902d3bf3d84SJohn Garry 		}
2903d3bf3d84SJohn Garry 
2904057c3d1fSXiaofei Tan 		if ((irq_msk & (1 << phy_no)) && irq_value2) {
2905057c3d1fSXiaofei Tan 			struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
2906057c3d1fSXiaofei Tan 
2907057c3d1fSXiaofei Tan 			if (irq_value2 & BIT(CHL_INT2_SL_IDAF_TOUT_CONF_OFF)) {
2908057c3d1fSXiaofei Tan 				dev_warn(dev, "phy%d identify timeout\n",
2909057c3d1fSXiaofei Tan 					 phy_no);
2910057c3d1fSXiaofei Tan 				hisi_sas_notify_phy_event(phy,
2911057c3d1fSXiaofei Tan 						HISI_PHYE_LINK_RESET);
2912057c3d1fSXiaofei Tan 			}
2913057c3d1fSXiaofei Tan 
2914d3bf3d84SJohn Garry 			hisi_sas_phy_write32(hisi_hba, phy_no,
2915d3bf3d84SJohn Garry 						 CHL_INT2, irq_value2);
2916057c3d1fSXiaofei Tan 		}
2917d3bf3d84SJohn Garry 
2918f64715d2SXiaofei Tan 		if ((irq_msk & (1 << phy_no)) && irq_value0) {
2919d3bf3d84SJohn Garry 			if (irq_value0 & CHL_INT0_SL_RX_BCST_ACK_MSK)
2920d3bf3d84SJohn Garry 				phy_bcast_v2_hw(phy_no, hisi_hba);
2921d3bf3d84SJohn Garry 
2922b6c9b15eSXiaofei Tan 			if (irq_value0 & CHL_INT0_PHY_RDY_MSK)
2923b6c9b15eSXiaofei Tan 				hisi_sas_phy_oob_ready(hisi_hba, phy_no);
2924b6c9b15eSXiaofei Tan 
2925d3bf3d84SJohn Garry 			hisi_sas_phy_write32(hisi_hba, phy_no,
2926d3bf3d84SJohn Garry 					CHL_INT0, irq_value0
2927d3bf3d84SJohn Garry 					& (~CHL_INT0_HOTPLUG_TOUT_MSK)
2928d3bf3d84SJohn Garry 					& (~CHL_INT0_SL_PHY_ENABLE_MSK)
2929d3bf3d84SJohn Garry 					& (~CHL_INT0_NOT_RDY_MSK));
2930d3bf3d84SJohn Garry 		}
2931d3bf3d84SJohn Garry 		irq_msk &= ~(1 << phy_no);
2932d3bf3d84SJohn Garry 		phy_no++;
2933d3bf3d84SJohn Garry 	}
2934d3bf3d84SJohn Garry 
2935d3bf3d84SJohn Garry 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, ent_tmp);
2936d3bf3d84SJohn Garry 
2937d3bf3d84SJohn Garry 	return IRQ_HANDLED;
2938d3bf3d84SJohn Garry }
2939d3bf3d84SJohn Garry 
2940d3b688d3SXiang Chen static void
one_bit_ecc_error_process_v2_hw(struct hisi_hba * hisi_hba,u32 irq_value)2941d3b688d3SXiang Chen one_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba, u32 irq_value)
2942d3b688d3SXiang Chen {
294311b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
29442b383351SJohn Garry 	const struct hisi_sas_hw_error *ecc_error;
29452b383351SJohn Garry 	u32 val;
29462b383351SJohn Garry 	int i;
2947d3b688d3SXiang Chen 
29482b383351SJohn Garry 	for (i = 0; i < ARRAY_SIZE(one_bit_ecc_errors); i++) {
29492b383351SJohn Garry 		ecc_error = &one_bit_ecc_errors[i];
29502b383351SJohn Garry 		if (irq_value & ecc_error->irq_msk) {
29512b383351SJohn Garry 			val = hisi_sas_read32(hisi_hba, ecc_error->reg);
29522b383351SJohn Garry 			val &= ecc_error->msk;
29532b383351SJohn Garry 			val >>= ecc_error->shift;
2954794327abSXiaofei Tan 			dev_warn(dev, "%s found: mem addr is 0x%08X\n",
2955794327abSXiaofei Tan 				 ecc_error->msg, val);
2956d3b688d3SXiang Chen 		}
2957d3b688d3SXiang Chen 	}
2958d3b688d3SXiang Chen }
2959d3b688d3SXiang Chen 
multi_bit_ecc_error_process_v2_hw(struct hisi_hba * hisi_hba,u32 irq_value)2960d3b688d3SXiang Chen static void multi_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba,
2961d3b688d3SXiang Chen 		u32 irq_value)
2962d3b688d3SXiang Chen {
296311b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
29642b383351SJohn Garry 	const struct hisi_sas_hw_error *ecc_error;
29652b383351SJohn Garry 	u32 val;
29662b383351SJohn Garry 	int i;
2967d3b688d3SXiang Chen 
29682b383351SJohn Garry 	for (i = 0; i < ARRAY_SIZE(multi_bit_ecc_errors); i++) {
29692b383351SJohn Garry 		ecc_error = &multi_bit_ecc_errors[i];
29702b383351SJohn Garry 		if (irq_value & ecc_error->irq_msk) {
29712b383351SJohn Garry 			val = hisi_sas_read32(hisi_hba, ecc_error->reg);
29722b383351SJohn Garry 			val &= ecc_error->msk;
29732b383351SJohn Garry 			val >>= ecc_error->shift;
2974794327abSXiaofei Tan 			dev_err(dev, "%s (0x%x) found: mem addr is 0x%08X\n",
2975794327abSXiaofei Tan 				ecc_error->msg, irq_value, val);
2976e281f42fSXiang Chen 			queue_work(hisi_hba->wq, &hisi_hba->rst_work);
2977d3b688d3SXiang Chen 		}
2978d3b688d3SXiang Chen 	}
2979d3b688d3SXiang Chen 
2980e281f42fSXiang Chen 	return;
2981d3b688d3SXiang Chen }
2982d3b688d3SXiang Chen 
fatal_ecc_int_v2_hw(int irq_no,void * p)2983d3b688d3SXiang Chen static irqreturn_t fatal_ecc_int_v2_hw(int irq_no, void *p)
2984d3b688d3SXiang Chen {
2985d3b688d3SXiang Chen 	struct hisi_hba *hisi_hba = p;
2986d3b688d3SXiang Chen 	u32 irq_value, irq_msk;
2987d3b688d3SXiang Chen 
2988d3b688d3SXiang Chen 	irq_msk = hisi_sas_read32(hisi_hba, SAS_ECC_INTR_MSK);
2989d3b688d3SXiang Chen 	hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, irq_msk | 0xffffffff);
2990d3b688d3SXiang Chen 
2991d3b688d3SXiang Chen 	irq_value = hisi_sas_read32(hisi_hba, SAS_ECC_INTR);
2992d3b688d3SXiang Chen 	if (irq_value) {
2993d3b688d3SXiang Chen 		one_bit_ecc_error_process_v2_hw(hisi_hba, irq_value);
2994d3b688d3SXiang Chen 		multi_bit_ecc_error_process_v2_hw(hisi_hba, irq_value);
2995d3b688d3SXiang Chen 	}
2996d3b688d3SXiang Chen 
2997d3b688d3SXiang Chen 	hisi_sas_write32(hisi_hba, SAS_ECC_INTR, irq_value);
2998d3b688d3SXiang Chen 	hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, irq_msk);
2999d3b688d3SXiang Chen 
3000d3b688d3SXiang Chen 	return IRQ_HANDLED;
3001d3b688d3SXiang Chen }
3002d3b688d3SXiang Chen 
3003729428caSShiju Jose static const struct hisi_sas_hw_error axi_error[] = {
3004729428caSShiju Jose 	{ .msk = BIT(0), .msg = "IOST_AXI_W_ERR" },
3005729428caSShiju Jose 	{ .msk = BIT(1), .msg = "IOST_AXI_R_ERR" },
3006729428caSShiju Jose 	{ .msk = BIT(2), .msg = "ITCT_AXI_W_ERR" },
3007729428caSShiju Jose 	{ .msk = BIT(3), .msg = "ITCT_AXI_R_ERR" },
3008729428caSShiju Jose 	{ .msk = BIT(4), .msg = "SATA_AXI_W_ERR" },
3009729428caSShiju Jose 	{ .msk = BIT(5), .msg = "SATA_AXI_R_ERR" },
3010729428caSShiju Jose 	{ .msk = BIT(6), .msg = "DQE_AXI_R_ERR" },
3011729428caSShiju Jose 	{ .msk = BIT(7), .msg = "CQE_AXI_W_ERR" },
301201d4e3a2SXiang Chen 	{}
3013d3b688d3SXiang Chen };
3014d3b688d3SXiang Chen 
3015729428caSShiju Jose static const struct hisi_sas_hw_error fifo_error[] = {
3016729428caSShiju Jose 	{ .msk = BIT(8),  .msg = "CQE_WINFO_FIFO" },
3017729428caSShiju Jose 	{ .msk = BIT(9),  .msg = "CQE_MSG_FIFIO" },
3018729428caSShiju Jose 	{ .msk = BIT(10), .msg = "GETDQE_FIFO" },
3019729428caSShiju Jose 	{ .msk = BIT(11), .msg = "CMDP_FIFO" },
3020729428caSShiju Jose 	{ .msk = BIT(12), .msg = "AWTCTRL_FIFO" },
302101d4e3a2SXiang Chen 	{}
3022729428caSShiju Jose };
3023729428caSShiju Jose 
3024729428caSShiju Jose static const struct hisi_sas_hw_error fatal_axi_errors[] = {
3025729428caSShiju Jose 	{
3026729428caSShiju Jose 		.irq_msk = BIT(ENT_INT_SRC3_WP_DEPTH_OFF),
3027729428caSShiju Jose 		.msg = "write pointer and depth",
3028729428caSShiju Jose 	},
3029729428caSShiju Jose 	{
3030729428caSShiju Jose 		.irq_msk = BIT(ENT_INT_SRC3_IPTT_SLOT_NOMATCH_OFF),
3031729428caSShiju Jose 		.msg = "iptt no match slot",
3032729428caSShiju Jose 	},
3033729428caSShiju Jose 	{
3034729428caSShiju Jose 		.irq_msk = BIT(ENT_INT_SRC3_RP_DEPTH_OFF),
3035729428caSShiju Jose 		.msg = "read pointer and depth",
3036729428caSShiju Jose 	},
3037729428caSShiju Jose 	{
3038729428caSShiju Jose 		.irq_msk = BIT(ENT_INT_SRC3_AXI_OFF),
3039729428caSShiju Jose 		.reg = HGC_AXI_FIFO_ERR_INFO,
3040729428caSShiju Jose 		.sub = axi_error,
3041729428caSShiju Jose 	},
3042729428caSShiju Jose 	{
3043729428caSShiju Jose 		.irq_msk = BIT(ENT_INT_SRC3_FIFO_OFF),
3044729428caSShiju Jose 		.reg = HGC_AXI_FIFO_ERR_INFO,
3045729428caSShiju Jose 		.sub = fifo_error,
3046729428caSShiju Jose 	},
3047729428caSShiju Jose 	{
3048729428caSShiju Jose 		.irq_msk = BIT(ENT_INT_SRC3_LM_OFF),
3049729428caSShiju Jose 		.msg = "LM add/fetch list",
3050729428caSShiju Jose 	},
3051729428caSShiju Jose 	{
3052729428caSShiju Jose 		.irq_msk = BIT(ENT_INT_SRC3_ABT_OFF),
3053729428caSShiju Jose 		.msg = "SAS_HGC_ABT fetch LM list",
3054729428caSShiju Jose 	},
3055d3b688d3SXiang Chen };
3056d3b688d3SXiang Chen 
fatal_axi_int_v2_hw(int irq_no,void * p)3057d3b688d3SXiang Chen static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
3058d3b688d3SXiang Chen {
3059d3b688d3SXiang Chen 	struct hisi_hba *hisi_hba = p;
3060d3b688d3SXiang Chen 	u32 irq_value, irq_msk, err_value;
306111b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
3062729428caSShiju Jose 	const struct hisi_sas_hw_error *axi_error;
3063729428caSShiju Jose 	int i;
3064d3b688d3SXiang Chen 
3065d3b688d3SXiang Chen 	irq_msk = hisi_sas_read32(hisi_hba, ENT_INT_SRC_MSK3);
3066d3b688d3SXiang Chen 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, irq_msk | 0xfffffffe);
3067d3b688d3SXiang Chen 
3068d3b688d3SXiang Chen 	irq_value = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
3069d3b688d3SXiang Chen 
3070729428caSShiju Jose 	for (i = 0; i < ARRAY_SIZE(fatal_axi_errors); i++) {
3071729428caSShiju Jose 		axi_error = &fatal_axi_errors[i];
3072729428caSShiju Jose 		if (!(irq_value & axi_error->irq_msk))
3073729428caSShiju Jose 			continue;
3074d3b688d3SXiang Chen 
3075d3b688d3SXiang Chen 		hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
3076729428caSShiju Jose 				 1 << axi_error->shift);
3077729428caSShiju Jose 		if (axi_error->sub) {
3078729428caSShiju Jose 			const struct hisi_sas_hw_error *sub = axi_error->sub;
3079d3b688d3SXiang Chen 
3080729428caSShiju Jose 			err_value = hisi_sas_read32(hisi_hba, axi_error->reg);
3081729428caSShiju Jose 			for (; sub->msk || sub->msg; sub++) {
3082729428caSShiju Jose 				if (!(err_value & sub->msk))
3083729428caSShiju Jose 					continue;
3084f1c88211SXiang Chen 				dev_err(dev, "%s (0x%x) found!\n",
3085729428caSShiju Jose 					sub->msg, irq_value);
3086e281f42fSXiang Chen 				queue_work(hisi_hba->wq, &hisi_hba->rst_work);
3087e281f42fSXiang Chen 			}
3088729428caSShiju Jose 		} else {
3089f1c88211SXiang Chen 			dev_err(dev, "%s (0x%x) found!\n",
3090729428caSShiju Jose 				axi_error->msg, irq_value);
3091e281f42fSXiang Chen 			queue_work(hisi_hba->wq, &hisi_hba->rst_work);
3092e281f42fSXiang Chen 		}
3093d3b688d3SXiang Chen 	}
3094d3b688d3SXiang Chen 
3095640acc9aSXiang Chen 	if (irq_value & BIT(ENT_INT_SRC3_ITC_INT_OFF)) {
3096640acc9aSXiang Chen 		u32 reg_val = hisi_sas_read32(hisi_hba, ITCT_CLR);
3097640acc9aSXiang Chen 		u32 dev_id = reg_val & ITCT_DEV_MSK;
3098729428caSShiju Jose 		struct hisi_sas_device *sas_dev = &hisi_hba->devices[dev_id];
3099640acc9aSXiang Chen 
3100640acc9aSXiang Chen 		hisi_sas_write32(hisi_hba, ITCT_CLR, 0);
3101640acc9aSXiang Chen 		dev_dbg(dev, "clear ITCT ok\n");
3102640acc9aSXiang Chen 		complete(sas_dev->completion);
3103640acc9aSXiang Chen 	}
3104d3b688d3SXiang Chen 
3105640acc9aSXiang Chen 	hisi_sas_write32(hisi_hba, ENT_INT_SRC3, irq_value);
3106d3b688d3SXiang Chen 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, irq_msk);
3107d3b688d3SXiang Chen 
3108d3b688d3SXiang Chen 	return IRQ_HANDLED;
3109d3b688d3SXiang Chen }
3110d3b688d3SXiang Chen 
cq_thread_v2_hw(int irq_no,void * p)311181f338e9SXiang Chen static irqreturn_t  cq_thread_v2_hw(int irq_no, void *p)
311231a9cfa6SJohn Garry {
311381f338e9SXiang Chen 	struct hisi_sas_cq *cq = p;
311431a9cfa6SJohn Garry 	struct hisi_hba *hisi_hba = cq->hisi_hba;
311531a9cfa6SJohn Garry 	struct hisi_sas_slot *slot;
311631a9cfa6SJohn Garry 	struct hisi_sas_itct *itct;
311731a9cfa6SJohn Garry 	struct hisi_sas_complete_v2_hdr *complete_queue;
3118d177c408SJohn Garry 	u32 rd_point = cq->rd_point, wr_point, dev_id;
311931a9cfa6SJohn Garry 	int queue = cq->id;
312031a9cfa6SJohn Garry 
3121c7b9d369SXiaofei Tan 	if (unlikely(hisi_hba->reject_stp_links_msk))
3122c7b9d369SXiaofei Tan 		phys_try_accept_stp_links_v2_hw(hisi_hba);
3123c7b9d369SXiaofei Tan 
312431a9cfa6SJohn Garry 	complete_queue = hisi_hba->complete_hdr[queue];
312531a9cfa6SJohn Garry 
312631a9cfa6SJohn Garry 	wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR +
312731a9cfa6SJohn Garry 				   (0x14 * queue));
312831a9cfa6SJohn Garry 
312931a9cfa6SJohn Garry 	while (rd_point != wr_point) {
313031a9cfa6SJohn Garry 		struct hisi_sas_complete_v2_hdr *complete_hdr;
313131a9cfa6SJohn Garry 		int iptt;
313231a9cfa6SJohn Garry 
313331a9cfa6SJohn Garry 		complete_hdr = &complete_queue[rd_point];
313431a9cfa6SJohn Garry 
313531a9cfa6SJohn Garry 		/* Check for NCQ completion */
313631a9cfa6SJohn Garry 		if (complete_hdr->act) {
3137735bcc77SJohn Garry 			u32 act_tmp = le32_to_cpu(complete_hdr->act);
313831a9cfa6SJohn Garry 			int ncq_tag_count = ffs(act_tmp);
3139735bcc77SJohn Garry 			u32 dw1 = le32_to_cpu(complete_hdr->dw1);
314031a9cfa6SJohn Garry 
3141735bcc77SJohn Garry 			dev_id = (dw1 & CMPLT_HDR_DEV_ID_MSK) >>
314231a9cfa6SJohn Garry 				 CMPLT_HDR_DEV_ID_OFF;
314331a9cfa6SJohn Garry 			itct = &hisi_hba->itct[dev_id];
314431a9cfa6SJohn Garry 
314531a9cfa6SJohn Garry 			/* The NCQ tags are held in the itct header */
314631a9cfa6SJohn Garry 			while (ncq_tag_count) {
3147735bcc77SJohn Garry 				__le64 *_ncq_tag = &itct->qw4_15[0], __ncq_tag;
3148735bcc77SJohn Garry 				u64 ncq_tag;
314931a9cfa6SJohn Garry 
3150735bcc77SJohn Garry 				ncq_tag_count--;
3151735bcc77SJohn Garry 				__ncq_tag = _ncq_tag[ncq_tag_count / 5];
3152735bcc77SJohn Garry 				ncq_tag = le64_to_cpu(__ncq_tag);
3153735bcc77SJohn Garry 				iptt = (ncq_tag >> (ncq_tag_count % 5) * 12) &
3154735bcc77SJohn Garry 				       0xfff;
315531a9cfa6SJohn Garry 
315631a9cfa6SJohn Garry 				slot = &hisi_hba->slot_info[iptt];
315731a9cfa6SJohn Garry 				slot->cmplt_queue_slot = rd_point;
315831a9cfa6SJohn Garry 				slot->cmplt_queue = queue;
3159405314dfSJohn Garry 				slot_complete_v2_hw(hisi_hba, slot);
316031a9cfa6SJohn Garry 
316131a9cfa6SJohn Garry 				act_tmp &= ~(1 << ncq_tag_count);
316231a9cfa6SJohn Garry 				ncq_tag_count = ffs(act_tmp);
316331a9cfa6SJohn Garry 			}
316431a9cfa6SJohn Garry 		} else {
3165735bcc77SJohn Garry 			u32 dw1 = le32_to_cpu(complete_hdr->dw1);
3166735bcc77SJohn Garry 
3167735bcc77SJohn Garry 			iptt = dw1 & CMPLT_HDR_IPTT_MSK;
316831a9cfa6SJohn Garry 			slot = &hisi_hba->slot_info[iptt];
316931a9cfa6SJohn Garry 			slot->cmplt_queue_slot = rd_point;
317031a9cfa6SJohn Garry 			slot->cmplt_queue = queue;
3171405314dfSJohn Garry 			slot_complete_v2_hw(hisi_hba, slot);
317231a9cfa6SJohn Garry 		}
317331a9cfa6SJohn Garry 
317431a9cfa6SJohn Garry 		if (++rd_point >= HISI_SAS_QUEUE_SLOTS)
317531a9cfa6SJohn Garry 			rd_point = 0;
317631a9cfa6SJohn Garry 	}
317731a9cfa6SJohn Garry 
317831a9cfa6SJohn Garry 	/* update rd_point */
3179e6c346f3SJohn Garry 	cq->rd_point = rd_point;
318031a9cfa6SJohn Garry 	hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
318181f338e9SXiang Chen 
318281f338e9SXiang Chen 	return IRQ_HANDLED;
3183d177c408SJohn Garry }
3184d177c408SJohn Garry 
cq_interrupt_v2_hw(int irq_no,void * p)3185d177c408SJohn Garry static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
3186d177c408SJohn Garry {
3187d177c408SJohn Garry 	struct hisi_sas_cq *cq = p;
3188d177c408SJohn Garry 	struct hisi_hba *hisi_hba = cq->hisi_hba;
3189d177c408SJohn Garry 	int queue = cq->id;
3190d177c408SJohn Garry 
3191d177c408SJohn Garry 	hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
3192d177c408SJohn Garry 
319381f338e9SXiang Chen 	return IRQ_WAKE_THREAD;
319431a9cfa6SJohn Garry }
319531a9cfa6SJohn Garry 
sata_int_v2_hw(int irq_no,void * p)3196d43f9cdbSJohn Garry static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
3197d43f9cdbSJohn Garry {
3198d43f9cdbSJohn Garry 	struct hisi_sas_phy *phy = p;
3199d43f9cdbSJohn Garry 	struct hisi_hba *hisi_hba = phy->hisi_hba;
3200d43f9cdbSJohn Garry 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
320111b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
3202d43f9cdbSJohn Garry 	struct	hisi_sas_initial_fis *initial_fis;
3203d43f9cdbSJohn Garry 	struct dev_to_host_fis *fis;
3204d43f9cdbSJohn Garry 	u32 ent_tmp, ent_msk, ent_int, port_id, link_rate, hard_phy_linkrate;
3205d43f9cdbSJohn Garry 	irqreturn_t res = IRQ_HANDLED;
3206d43f9cdbSJohn Garry 	u8 attached_sas_addr[SAS_ADDR_SIZE] = {0};
320711826e5dSJohn Garry 	int phy_no, offset;
3208d43f9cdbSJohn Garry 
3209b6c9b15eSXiaofei Tan 	del_timer(&phy->timer);
3210b6c9b15eSXiaofei Tan 
3211d43f9cdbSJohn Garry 	phy_no = sas_phy->id;
3212d43f9cdbSJohn Garry 	initial_fis = &hisi_hba->initial_fis[phy_no];
3213d43f9cdbSJohn Garry 	fis = &initial_fis->fis;
3214d43f9cdbSJohn Garry 
321511826e5dSJohn Garry 	offset = 4 * (phy_no / 4);
321611826e5dSJohn Garry 	ent_msk = hisi_sas_read32(hisi_hba, ENT_INT_SRC_MSK1 + offset);
321711826e5dSJohn Garry 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1 + offset,
321811826e5dSJohn Garry 			 ent_msk | 1 << ((phy_no % 4) * 8));
3219d43f9cdbSJohn Garry 
322011826e5dSJohn Garry 	ent_int = hisi_sas_read32(hisi_hba, ENT_INT_SRC1 + offset);
322111826e5dSJohn Garry 	ent_tmp = ent_int & (1 << (ENT_INT_SRC1_D2H_FIS_CH1_OFF *
322211826e5dSJohn Garry 			     (phy_no % 4)));
3223d43f9cdbSJohn Garry 	ent_int >>= ENT_INT_SRC1_D2H_FIS_CH1_OFF * (phy_no % 4);
3224d43f9cdbSJohn Garry 	if ((ent_int & ENT_INT_SRC1_D2H_FIS_CH0_MSK) == 0) {
3225d43f9cdbSJohn Garry 		dev_warn(dev, "sata int: phy%d did not receive FIS\n", phy_no);
3226d43f9cdbSJohn Garry 		res = IRQ_NONE;
3227d43f9cdbSJohn Garry 		goto end;
3228d43f9cdbSJohn Garry 	}
3229d43f9cdbSJohn Garry 
323004708ff4SXiang Chen 	/* check ERR bit of Status Register */
323104708ff4SXiang Chen 	if (fis->status & ATA_ERR) {
323204708ff4SXiang Chen 		dev_warn(dev, "sata int: phy%d FIS status: 0x%x\n", phy_no,
323304708ff4SXiang Chen 			 fis->status);
3234f4e34f2aSXiang Chen 		hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET);
323504708ff4SXiang Chen 		res = IRQ_NONE;
323604708ff4SXiang Chen 		goto end;
323704708ff4SXiang Chen 	}
323804708ff4SXiang Chen 
3239d43f9cdbSJohn Garry 	if (unlikely(phy_no == 8)) {
3240d43f9cdbSJohn Garry 		u32 port_state = hisi_sas_read32(hisi_hba, PORT_STATE);
3241d43f9cdbSJohn Garry 
3242d43f9cdbSJohn Garry 		port_id = (port_state & PORT_STATE_PHY8_PORT_NUM_MSK) >>
3243d43f9cdbSJohn Garry 			  PORT_STATE_PHY8_PORT_NUM_OFF;
3244d43f9cdbSJohn Garry 		link_rate = (port_state & PORT_STATE_PHY8_CONN_RATE_MSK) >>
3245d43f9cdbSJohn Garry 			    PORT_STATE_PHY8_CONN_RATE_OFF;
3246d43f9cdbSJohn Garry 	} else {
3247d43f9cdbSJohn Garry 		port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
3248d43f9cdbSJohn Garry 		port_id = (port_id >> (4 * phy_no)) & 0xf;
3249d43f9cdbSJohn Garry 		link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
3250d43f9cdbSJohn Garry 		link_rate = (link_rate >> (phy_no * 4)) & 0xf;
3251d43f9cdbSJohn Garry 	}
3252d43f9cdbSJohn Garry 
3253d43f9cdbSJohn Garry 	if (port_id == 0xf) {
3254d43f9cdbSJohn Garry 		dev_err(dev, "sata int: phy%d invalid portid\n", phy_no);
3255d43f9cdbSJohn Garry 		res = IRQ_NONE;
3256d43f9cdbSJohn Garry 		goto end;
3257d43f9cdbSJohn Garry 	}
3258d43f9cdbSJohn Garry 
3259d43f9cdbSJohn Garry 	sas_phy->linkrate = link_rate;
3260d43f9cdbSJohn Garry 	hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no,
3261d43f9cdbSJohn Garry 						HARD_PHY_LINKRATE);
3262d43f9cdbSJohn Garry 	phy->maximum_linkrate = hard_phy_linkrate & 0xf;
3263d43f9cdbSJohn Garry 	phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf;
3264d43f9cdbSJohn Garry 
3265d43f9cdbSJohn Garry 	sas_phy->oob_mode = SATA_OOB_MODE;
3266d43f9cdbSJohn Garry 	/* Make up some unique SAS address */
3267d43f9cdbSJohn Garry 	attached_sas_addr[0] = 0x50;
32688b8d6653SXiang Chen 	attached_sas_addr[6] = hisi_hba->shost->host_no;
3269d43f9cdbSJohn Garry 	attached_sas_addr[7] = phy_no;
3270d43f9cdbSJohn Garry 	memcpy(sas_phy->attached_sas_addr, attached_sas_addr, SAS_ADDR_SIZE);
3271d43f9cdbSJohn Garry 	memcpy(sas_phy->frame_rcvd, fis, sizeof(struct dev_to_host_fis));
3272d43f9cdbSJohn Garry 	dev_info(dev, "sata int phyup: phy%d link_rate=%d\n", phy_no, link_rate);
3273d43f9cdbSJohn Garry 	phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
3274d43f9cdbSJohn Garry 	phy->port_id = port_id;
3275d43f9cdbSJohn Garry 	phy->phy_type |= PORT_TYPE_SATA;
3276d43f9cdbSJohn Garry 	phy->phy_attached = 1;
3277d43f9cdbSJohn Garry 	phy->identify.device_type = SAS_SATA_DEV;
3278d43f9cdbSJohn Garry 	phy->frame_rcvd_size = sizeof(struct dev_to_host_fis);
3279d43f9cdbSJohn Garry 	phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
3280e537b62bSXiaofei Tan 	hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
3281d43f9cdbSJohn Garry 
3282046ab7d0SXiang Chen 	if (phy->reset_completion)
32833e1fb1b8SXiang Chen 		complete(phy->reset_completion);
3284d43f9cdbSJohn Garry end:
328511826e5dSJohn Garry 	hisi_sas_write32(hisi_hba, ENT_INT_SRC1 + offset, ent_tmp);
328611826e5dSJohn Garry 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1 + offset, ent_msk);
3287d43f9cdbSJohn Garry 
3288d43f9cdbSJohn Garry 	return res;
3289d43f9cdbSJohn Garry }
3290d43f9cdbSJohn Garry 
32917911e66fSJohn Garry static irq_handler_t phy_interrupts[HISI_SAS_PHY_INT_NR] = {
32927911e66fSJohn Garry 	int_phy_updown_v2_hw,
3293d3bf3d84SJohn Garry 	int_chnl_int_v2_hw,
32947911e66fSJohn Garry };
32957911e66fSJohn Garry 
3296d3b688d3SXiang Chen static irq_handler_t fatal_interrupts[HISI_SAS_FATAL_INT_NR] = {
3297d3b688d3SXiang Chen 	fatal_ecc_int_v2_hw,
3298d3b688d3SXiang Chen 	fatal_axi_int_v2_hw
3299d3b688d3SXiang Chen };
3300d3b688d3SXiang Chen 
330174a29219SJohn Garry #define CQ0_IRQ_INDEX (96)
330274a29219SJohn Garry 
hisi_sas_v2_interrupt_preinit(struct hisi_hba * hisi_hba)330374a29219SJohn Garry static int hisi_sas_v2_interrupt_preinit(struct hisi_hba *hisi_hba)
330474a29219SJohn Garry {
330574a29219SJohn Garry 	struct platform_device *pdev = hisi_hba->platform_dev;
330674a29219SJohn Garry 	struct Scsi_Host *shost = hisi_hba->shost;
330774a29219SJohn Garry 	struct irq_affinity desc = {
330874a29219SJohn Garry 		.pre_vectors = CQ0_IRQ_INDEX,
330974a29219SJohn Garry 		.post_vectors = 16,
331074a29219SJohn Garry 	};
331174a29219SJohn Garry 	int resv = desc.pre_vectors + desc.post_vectors, minvec = resv + 1, nvec;
331274a29219SJohn Garry 
331374a29219SJohn Garry 	nvec = devm_platform_get_irqs_affinity(pdev, &desc, minvec, 128,
331474a29219SJohn Garry 					       &hisi_hba->irq_map);
331574a29219SJohn Garry 	if (nvec < 0)
331674a29219SJohn Garry 		return nvec;
331774a29219SJohn Garry 
331874a29219SJohn Garry 	shost->nr_hw_queues = hisi_hba->cq_nvecs = nvec - resv;
331974a29219SJohn Garry 
332074a29219SJohn Garry 	return 0;
332174a29219SJohn Garry }
332274a29219SJohn Garry 
33233d570a28SJohn Garry /*
33247911e66fSJohn Garry  * There is a limitation in the hip06 chipset that we need
33257911e66fSJohn Garry  * to map in all mbigen interrupts, even if they are not used.
33267911e66fSJohn Garry  */
interrupt_init_v2_hw(struct hisi_hba * hisi_hba)33277911e66fSJohn Garry static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
33287911e66fSJohn Garry {
332911b75249SJohn Garry 	struct platform_device *pdev = hisi_hba->platform_dev;
33307911e66fSJohn Garry 	struct device *dev = &pdev->dev;
333174a29219SJohn Garry 	int irq, rc = 0;
3332e16963f3SXiang Chen 	int i, phy_no, fatal_no, queue_no;
33337911e66fSJohn Garry 
33347911e66fSJohn Garry 	for (i = 0; i < HISI_SAS_PHY_INT_NR; i++) {
333574a29219SJohn Garry 		irq = hisi_hba->irq_map[i + 1]; /* Phy up/down is irq1 */
33367911e66fSJohn Garry 		rc = devm_request_irq(dev, irq, phy_interrupts[i], 0,
33377911e66fSJohn Garry 				      DRV_NAME " phy", hisi_hba);
33387911e66fSJohn Garry 		if (rc) {
333901d4e3a2SXiang Chen 			dev_err(dev, "irq init: could not request phy interrupt %d, rc=%d\n",
33407911e66fSJohn Garry 				irq, rc);
33418a253888SXiang Chen 			rc = -ENOENT;
3342e16963f3SXiang Chen 			goto err_out;
33437911e66fSJohn Garry 		}
33447911e66fSJohn Garry 	}
33457911e66fSJohn Garry 
33468a253888SXiang Chen 	for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
33478a253888SXiang Chen 		struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
3348d43f9cdbSJohn Garry 
334974a29219SJohn Garry 		irq = hisi_hba->irq_map[phy_no + 72];
3350d43f9cdbSJohn Garry 		rc = devm_request_irq(dev, irq, sata_int_v2_hw, 0,
3351d43f9cdbSJohn Garry 				      DRV_NAME " sata", phy);
3352d43f9cdbSJohn Garry 		if (rc) {
335301d4e3a2SXiang Chen 			dev_err(dev, "irq init: could not request sata interrupt %d, rc=%d\n",
3354d43f9cdbSJohn Garry 				irq, rc);
33558a253888SXiang Chen 			rc = -ENOENT;
3356e16963f3SXiang Chen 			goto err_out;
3357d43f9cdbSJohn Garry 		}
3358d43f9cdbSJohn Garry 	}
335931a9cfa6SJohn Garry 
33608a253888SXiang Chen 	for (fatal_no = 0; fatal_no < HISI_SAS_FATAL_INT_NR; fatal_no++) {
336174a29219SJohn Garry 		irq = hisi_hba->irq_map[fatal_no + 81];
33628a253888SXiang Chen 		rc = devm_request_irq(dev, irq, fatal_interrupts[fatal_no], 0,
3363d3b688d3SXiang Chen 				      DRV_NAME " fatal", hisi_hba);
3364d3b688d3SXiang Chen 		if (rc) {
336501d4e3a2SXiang Chen 			dev_err(dev, "irq init: could not request fatal interrupt %d, rc=%d\n",
3366d3b688d3SXiang Chen 				irq, rc);
33678a253888SXiang Chen 			rc = -ENOENT;
3368e16963f3SXiang Chen 			goto err_out;
3369d3b688d3SXiang Chen 		}
3370d3b688d3SXiang Chen 	}
3371d3b688d3SXiang Chen 
337274a29219SJohn Garry 	for (queue_no = 0; queue_no < hisi_hba->cq_nvecs; queue_no++) {
33738a253888SXiang Chen 		struct hisi_sas_cq *cq = &hisi_hba->cq[queue_no];
337431a9cfa6SJohn Garry 
337574a29219SJohn Garry 		cq->irq_no = hisi_hba->irq_map[queue_no + 96];
337681f338e9SXiang Chen 		rc = devm_request_threaded_irq(dev, cq->irq_no,
337781f338e9SXiang Chen 					       cq_interrupt_v2_hw,
337881f338e9SXiang Chen 					       cq_thread_v2_hw, IRQF_ONESHOT,
33798a253888SXiang Chen 					       DRV_NAME " cq", cq);
338031a9cfa6SJohn Garry 		if (rc) {
338101d4e3a2SXiang Chen 			dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n",
338274a29219SJohn Garry 					cq->irq_no, rc);
33838a253888SXiang Chen 			rc = -ENOENT;
3384e16963f3SXiang Chen 			goto err_out;
338531a9cfa6SJohn Garry 		}
338674a29219SJohn Garry 		cq->irq_mask = irq_get_affinity_mask(cq->irq_no);
338731a9cfa6SJohn Garry 	}
3388e16963f3SXiang Chen err_out:
33898a253888SXiang Chen 	return rc;
33907911e66fSJohn Garry }
33917911e66fSJohn Garry 
hisi_sas_v2_init(struct hisi_hba * hisi_hba)339294eac9e1SJohn Garry static int hisi_sas_v2_init(struct hisi_hba *hisi_hba)
339394eac9e1SJohn Garry {
339494eac9e1SJohn Garry 	int rc;
339594eac9e1SJohn Garry 
339632ccba52SXiaofei Tan 	memset(hisi_hba->sata_dev_bitmap, 0, sizeof(hisi_hba->sata_dev_bitmap));
339732ccba52SXiaofei Tan 
339894eac9e1SJohn Garry 	rc = hw_init_v2_hw(hisi_hba);
339994eac9e1SJohn Garry 	if (rc)
340094eac9e1SJohn Garry 		return rc;
340194eac9e1SJohn Garry 
34027911e66fSJohn Garry 	rc = interrupt_init_v2_hw(hisi_hba);
34037911e66fSJohn Garry 	if (rc)
34047911e66fSJohn Garry 		return rc;
34057911e66fSJohn Garry 
340694eac9e1SJohn Garry 	return 0;
340794eac9e1SJohn Garry }
340894eac9e1SJohn Garry 
interrupt_disable_v2_hw(struct hisi_hba * hisi_hba)340906ec0fb9SXiang Chen static void interrupt_disable_v2_hw(struct hisi_hba *hisi_hba)
341006ec0fb9SXiang Chen {
341111b75249SJohn Garry 	struct platform_device *pdev = hisi_hba->platform_dev;
341206ec0fb9SXiang Chen 	int i;
341306ec0fb9SXiang Chen 
341406ec0fb9SXiang Chen 	for (i = 0; i < hisi_hba->queue_count; i++)
341506ec0fb9SXiang Chen 		hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK + 0x4 * i, 0x1);
341606ec0fb9SXiang Chen 
341706ec0fb9SXiang Chen 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xffffffff);
341806ec0fb9SXiang Chen 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xffffffff);
341906ec0fb9SXiang Chen 	hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffffffff);
342006ec0fb9SXiang Chen 	hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0xffffffff);
342106ec0fb9SXiang Chen 
342206ec0fb9SXiang Chen 	for (i = 0; i < hisi_hba->n_phy; i++) {
342306ec0fb9SXiang Chen 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xffffffff);
342406ec0fb9SXiang Chen 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0xffffffff);
342506ec0fb9SXiang Chen 	}
342606ec0fb9SXiang Chen 
342706ec0fb9SXiang Chen 	for (i = 0; i < 128; i++)
342806ec0fb9SXiang Chen 		synchronize_irq(platform_get_irq(pdev, i));
342906ec0fb9SXiang Chen }
343006ec0fb9SXiang Chen 
3431917d3bdaSXiaofei Tan 
get_phys_state_v2_hw(struct hisi_hba * hisi_hba)3432917d3bdaSXiaofei Tan static u32 get_phys_state_v2_hw(struct hisi_hba *hisi_hba)
3433917d3bdaSXiaofei Tan {
3434917d3bdaSXiaofei Tan 	return hisi_sas_read32(hisi_hba, PHY_STATE);
3435917d3bdaSXiaofei Tan }
3436917d3bdaSXiaofei Tan 
soft_reset_v2_hw(struct hisi_hba * hisi_hba)343706ec0fb9SXiang Chen static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
343806ec0fb9SXiang Chen {
343911b75249SJohn Garry 	struct device *dev = hisi_hba->dev;
344006ec0fb9SXiang Chen 	int rc, cnt;
344106ec0fb9SXiang Chen 
344206ec0fb9SXiang Chen 	interrupt_disable_v2_hw(hisi_hba);
344306ec0fb9SXiang Chen 	hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
344406ec0fb9SXiang Chen 
3445a25d0d3dSXiang Chen 	hisi_sas_stop_phys(hisi_hba);
344606ec0fb9SXiang Chen 
344706ec0fb9SXiang Chen 	mdelay(10);
344806ec0fb9SXiang Chen 
344906ec0fb9SXiang Chen 	hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE + AM_CTRL_GLOBAL, 0x1);
345006ec0fb9SXiang Chen 
345106ec0fb9SXiang Chen 	/* wait until bus idle */
345206ec0fb9SXiang Chen 	cnt = 0;
345306ec0fb9SXiang Chen 	while (1) {
345406ec0fb9SXiang Chen 		u32 status = hisi_sas_read32_relaxed(hisi_hba,
345506ec0fb9SXiang Chen 				AXI_MASTER_CFG_BASE + AM_CURR_TRANS_RETURN);
345606ec0fb9SXiang Chen 
345706ec0fb9SXiang Chen 		if (status == 0x3)
345806ec0fb9SXiang Chen 			break;
345906ec0fb9SXiang Chen 
346006ec0fb9SXiang Chen 		udelay(10);
346106ec0fb9SXiang Chen 		if (cnt++ > 10) {
3462f1c88211SXiang Chen 			dev_err(dev, "wait axi bus state to idle timeout!\n");
346306ec0fb9SXiang Chen 			return -1;
346406ec0fb9SXiang Chen 		}
346506ec0fb9SXiang Chen 	}
346606ec0fb9SXiang Chen 
346706ec0fb9SXiang Chen 	hisi_sas_init_mem(hisi_hba);
346806ec0fb9SXiang Chen 
346906ec0fb9SXiang Chen 	rc = hw_init_v2_hw(hisi_hba);
347006ec0fb9SXiang Chen 	if (rc)
347106ec0fb9SXiang Chen 		return rc;
347206ec0fb9SXiang Chen 
3473c7b9d369SXiaofei Tan 	phys_reject_stp_links_v2_hw(hisi_hba);
3474c7b9d369SXiaofei Tan 
347506ec0fb9SXiang Chen 	return 0;
347606ec0fb9SXiang Chen }
347706ec0fb9SXiang Chen 
write_gpio_v2_hw(struct hisi_hba * hisi_hba,u8 reg_type,u8 reg_index,u8 reg_count,u8 * write_data)34786379c560SXiaofei Tan static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type,
34796379c560SXiaofei Tan 			u8 reg_index, u8 reg_count, u8 *write_data)
34806379c560SXiaofei Tan {
34816379c560SXiaofei Tan 	struct device *dev = hisi_hba->dev;
34826379c560SXiaofei Tan 	int phy_no, count;
34836379c560SXiaofei Tan 
34846379c560SXiaofei Tan 	if (!hisi_hba->sgpio_regs)
34856379c560SXiaofei Tan 		return -EOPNOTSUPP;
34866379c560SXiaofei Tan 
34876379c560SXiaofei Tan 	switch (reg_type) {
34886379c560SXiaofei Tan 	case SAS_GPIO_REG_TX:
34896379c560SXiaofei Tan 		count = reg_count * 4;
34906379c560SXiaofei Tan 		count = min(count, hisi_hba->n_phy);
34916379c560SXiaofei Tan 
34926379c560SXiaofei Tan 		for (phy_no = 0; phy_no < count; phy_no++) {
34936379c560SXiaofei Tan 			/*
34946379c560SXiaofei Tan 			 * GPIO_TX[n] register has the highest numbered drive
34956379c560SXiaofei Tan 			 * of the four in the first byte and the lowest
34966379c560SXiaofei Tan 			 * numbered drive in the fourth byte.
34976379c560SXiaofei Tan 			 * See SFF-8485 Rev. 0.7 Table 24.
34986379c560SXiaofei Tan 			 */
34996379c560SXiaofei Tan 			void __iomem  *reg_addr = hisi_hba->sgpio_regs +
35006379c560SXiaofei Tan 					reg_index * 4 + phy_no;
35016379c560SXiaofei Tan 			int data_idx = phy_no + 3 - (phy_no % 4) * 2;
35026379c560SXiaofei Tan 
35036379c560SXiaofei Tan 			writeb(write_data[data_idx], reg_addr);
35046379c560SXiaofei Tan 		}
35056379c560SXiaofei Tan 
35066379c560SXiaofei Tan 		break;
35076379c560SXiaofei Tan 	default:
35086379c560SXiaofei Tan 		dev_err(dev, "write gpio: unsupported or bad reg type %d\n",
35096379c560SXiaofei Tan 			reg_type);
35106379c560SXiaofei Tan 		return -EINVAL;
35116379c560SXiaofei Tan 	}
35126379c560SXiaofei Tan 
35136379c560SXiaofei Tan 	return 0;
35146379c560SXiaofei Tan }
35156379c560SXiaofei Tan 
wait_cmds_complete_timeout_v2_hw(struct hisi_hba * hisi_hba,int delay_ms,int timeout_ms)35164bc05809SLuo Jiaxing static void wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba,
3517a865ae14SXiaofei Tan 					     int delay_ms, int timeout_ms)
3518a865ae14SXiaofei Tan {
3519a865ae14SXiaofei Tan 	struct device *dev = hisi_hba->dev;
3520a865ae14SXiaofei Tan 	int entries, entries_old = 0, time;
3521a865ae14SXiaofei Tan 
3522a865ae14SXiaofei Tan 	for (time = 0; time < timeout_ms; time += delay_ms) {
3523a865ae14SXiaofei Tan 		entries = hisi_sas_read32(hisi_hba, CQE_SEND_CNT);
3524a865ae14SXiaofei Tan 		if (entries == entries_old)
3525a865ae14SXiaofei Tan 			break;
3526a865ae14SXiaofei Tan 
3527a865ae14SXiaofei Tan 		entries_old = entries;
3528a865ae14SXiaofei Tan 		msleep(delay_ms);
3529a865ae14SXiaofei Tan 	}
3530a865ae14SXiaofei Tan 
35314bc05809SLuo Jiaxing 	if (time >= timeout_ms) {
35324bc05809SLuo Jiaxing 		dev_dbg(dev, "Wait commands complete timeout!\n");
35334bc05809SLuo Jiaxing 		return;
35344bc05809SLuo Jiaxing 	}
353549159a5eSLuo Jiaxing 
3536a865ae14SXiaofei Tan 	dev_dbg(dev, "wait commands complete %dms\n", time);
353749159a5eSLuo Jiaxing 
3538a865ae14SXiaofei Tan }
3539235bfc7fSXiang Chen 
354062ac8ccbSBart Van Assche static struct attribute *host_v2_hw_attrs[] = {
354162ac8ccbSBart Van Assche 	&dev_attr_phy_event_threshold.attr,
3542c3566f9aSXiang Chen 	NULL
3543c3566f9aSXiang Chen };
3544c3566f9aSXiang Chen 
354562ac8ccbSBart Van Assche ATTRIBUTE_GROUPS(host_v2_hw);
354662ac8ccbSBart Van Assche 
map_queues_v2_hw(struct Scsi_Host * shost)3547a4e1d0b7SBart Van Assche static void map_queues_v2_hw(struct Scsi_Host *shost)
354874a29219SJohn Garry {
354974a29219SJohn Garry 	struct hisi_hba *hisi_hba = shost_priv(shost);
355074a29219SJohn Garry 	struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
355174a29219SJohn Garry 	const struct cpumask *mask;
355274a29219SJohn Garry 	unsigned int queue, cpu;
355374a29219SJohn Garry 
355474a29219SJohn Garry 	for (queue = 0; queue < qmap->nr_queues; queue++) {
355574a29219SJohn Garry 		mask = irq_get_affinity_mask(hisi_hba->irq_map[96 + queue]);
355674a29219SJohn Garry 		if (!mask)
355774a29219SJohn Garry 			continue;
355874a29219SJohn Garry 
355974a29219SJohn Garry 		for_each_cpu(cpu, mask)
356074a29219SJohn Garry 			qmap->mq_map[cpu] = qmap->queue_offset + queue;
356174a29219SJohn Garry 	}
356274a29219SJohn Garry }
356374a29219SJohn Garry 
3564e8c0ced9SBart Van Assche static const struct scsi_host_template sht_v2_hw = {
3565235bfc7fSXiang Chen 	.name			= DRV_NAME,
356655ce24b3SJason Yan 	.proc_name		= DRV_NAME,
3567235bfc7fSXiang Chen 	.module			= THIS_MODULE,
3568235bfc7fSXiang Chen 	.queuecommand		= sas_queuecommand,
3569b8f1d1e0SChristoph Hellwig 	.dma_need_drain		= ata_scsi_dma_need_drain,
3570235bfc7fSXiang Chen 	.target_alloc		= sas_target_alloc,
3571235bfc7fSXiang Chen 	.slave_configure	= hisi_sas_slave_configure,
3572235bfc7fSXiang Chen 	.scan_finished		= hisi_sas_scan_finished,
3573235bfc7fSXiang Chen 	.scan_start		= hisi_sas_scan_start,
3574235bfc7fSXiang Chen 	.change_queue_depth	= sas_change_queue_depth,
3575235bfc7fSXiang Chen 	.bios_param		= sas_bios_param,
3576235bfc7fSXiang Chen 	.this_id		= -1,
35776db831f4SXiang Chen 	.sg_tablesize		= HISI_SAS_SGE_PAGE_CNT,
3578235bfc7fSXiang Chen 	.max_sectors		= SCSI_DEFAULT_MAX_SECTORS,
3579235bfc7fSXiang Chen 	.eh_device_reset_handler = sas_eh_device_reset_handler,
3580235bfc7fSXiang Chen 	.eh_target_reset_handler = sas_eh_target_reset_handler,
358136c6b761SXiang Chen 	.slave_alloc		= hisi_sas_slave_alloc,
3582235bfc7fSXiang Chen 	.target_destroy		= sas_target_destroy,
3583235bfc7fSXiang Chen 	.ioctl			= sas_ioctl,
358475c0b0e1SArnd Bergmann #ifdef CONFIG_COMPAT
358575c0b0e1SArnd Bergmann 	.compat_ioctl		= sas_ioctl,
358675c0b0e1SArnd Bergmann #endif
358762ac8ccbSBart Van Assche 	.shost_groups		= host_v2_hw_groups,
3588a97fa586SXiang Chen 	.host_reset		= hisi_sas_host_reset,
358974a29219SJohn Garry 	.map_queues		= map_queues_v2_hw,
359074a29219SJohn Garry 	.host_tagset		= 1,
3591235bfc7fSXiang Chen };
3592235bfc7fSXiang Chen 
35933417ba8aSJohn Garry static const struct hisi_sas_hw hisi_sas_v2_hw = {
359494eac9e1SJohn Garry 	.hw_init = hisi_sas_v2_init,
359574a29219SJohn Garry 	.interrupt_preinit = hisi_sas_v2_interrupt_preinit,
359685b2c3c0SJohn Garry 	.setup_itct = setup_itct_v2_hw,
3597330fa7f3SJohn Garry 	.slot_index_alloc = slot_index_alloc_quirk_v2_hw,
3598b2bdaf2bSJohn Garry 	.alloc_dev = alloc_dev_quirk_v2_hw,
3599569eddcfSXiang Chen 	.sl_notify_ssp = sl_notify_ssp_v2_hw,
36005473c060SJohn Garry 	.get_wideport_bitmap = get_wideport_bitmap_v2_hw,
36010258141aSXiaofei Tan 	.clear_itct = clear_itct_v2_hw,
360285b2c3c0SJohn Garry 	.free_device = free_device_v2_hw,
3603c2d89392SJohn Garry 	.prep_smp = prep_smp_v2_hw,
36048c36e31dSJohn Garry 	.prep_ssp = prep_ssp_v2_hw,
36056f2ff1a1SJohn Garry 	.prep_stp = prep_ata_v2_hw,
3606a3e665d9SJohn Garry 	.prep_abort = prep_abort_v2_hw,
36078c36e31dSJohn Garry 	.start_delivery = start_delivery_v2_hw,
3608396b8044SJohn Garry 	.phys_init = phys_init_v2_hw,
36091eb8eeacSXiang Chen 	.phy_start = start_phy_v2_hw,
361063fb11b8SJohn Garry 	.phy_disable = disable_phy_v2_hw,
361163fb11b8SJohn Garry 	.phy_hard_reset = phy_hard_reset_v2_hw,
3612c52108c6SXiaofei Tan 	.get_events = phy_get_events_v2_hw,
36132ae75787SXiang Chen 	.phy_set_linkrate = phy_set_linkrate_v2_hw,
36142ae75787SXiang Chen 	.phy_get_max_linkrate = phy_get_max_linkrate_v2_hw,
361594eac9e1SJohn Garry 	.complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr),
361606ec0fb9SXiang Chen 	.soft_reset = soft_reset_v2_hw,
3617917d3bdaSXiaofei Tan 	.get_phys_state = get_phys_state_v2_hw,
36186379c560SXiaofei Tan 	.write_gpio = write_gpio_v2_hw,
3619a865ae14SXiaofei Tan 	.wait_cmds_complete_timeout = wait_cmds_complete_timeout_v2_hw,
3620235bfc7fSXiang Chen 	.sht = &sht_v2_hw,
36213417ba8aSJohn Garry };
36223417ba8aSJohn Garry 
hisi_sas_v2_probe(struct platform_device * pdev)36233417ba8aSJohn Garry static int hisi_sas_v2_probe(struct platform_device *pdev)
36243417ba8aSJohn Garry {
36253417ba8aSJohn Garry 	return hisi_sas_probe(pdev, &hisi_sas_v2_hw);
36263417ba8aSJohn Garry }
36273417ba8aSJohn Garry 
36283417ba8aSJohn Garry static const struct of_device_id sas_v2_of_match[] = {
36293417ba8aSJohn Garry 	{ .compatible = "hisilicon,hip06-sas-v2",},
3630039ae102SJohn Garry 	{ .compatible = "hisilicon,hip07-sas-v2",},
36313417ba8aSJohn Garry 	{},
36323417ba8aSJohn Garry };
36333417ba8aSJohn Garry MODULE_DEVICE_TABLE(of, sas_v2_of_match);
36343417ba8aSJohn Garry 
363550408712SJohn Garry static const struct acpi_device_id sas_v2_acpi_match[] = {
363650408712SJohn Garry 	{ "HISI0162", 0 },
363750408712SJohn Garry 	{ }
363850408712SJohn Garry };
363950408712SJohn Garry 
364050408712SJohn Garry MODULE_DEVICE_TABLE(acpi, sas_v2_acpi_match);
364150408712SJohn Garry 
36423417ba8aSJohn Garry static struct platform_driver hisi_sas_v2_driver = {
36433417ba8aSJohn Garry 	.probe = hisi_sas_v2_probe,
36448cd6d0a3SUwe Kleine-König 	.remove_new = hisi_sas_remove,
36453417ba8aSJohn Garry 	.driver = {
36463417ba8aSJohn Garry 		.name = DRV_NAME,
36473417ba8aSJohn Garry 		.of_match_table = sas_v2_of_match,
364850408712SJohn Garry 		.acpi_match_table = ACPI_PTR(sas_v2_acpi_match),
36493417ba8aSJohn Garry 	},
36503417ba8aSJohn Garry };
36513417ba8aSJohn Garry 
36523417ba8aSJohn Garry module_platform_driver(hisi_sas_v2_driver);
36533417ba8aSJohn Garry 
36543417ba8aSJohn Garry MODULE_LICENSE("GPL");
36553417ba8aSJohn Garry MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
36563417ba8aSJohn Garry MODULE_DESCRIPTION("HISILICON SAS controller v2 hw driver");
36573417ba8aSJohn Garry MODULE_ALIAS("platform:" DRV_NAME);
3658