summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/hisi_sas/hisi_sas_v2_hw.c')
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v2_hw.c1201
1 files changed, 942 insertions, 259 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 1b214450dcb5..e241921bee10 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -194,9 +194,9 @@
#define SL_CONTROL_NOTIFY_EN_MSK (0x1 << SL_CONTROL_NOTIFY_EN_OFF)
#define SL_CONTROL_CTA_OFF 17
#define SL_CONTROL_CTA_MSK (0x1 << SL_CONTROL_CTA_OFF)
-#define RX_PRIMS_STATUS (PORT_BASE + 0x98)
-#define RX_BCAST_CHG_OFF 1
-#define RX_BCAST_CHG_MSK (0x1 << RX_BCAST_CHG_OFF)
+#define RX_PRIMS_STATUS (PORT_BASE + 0x98)
+#define RX_BCAST_CHG_OFF 1
+#define RX_BCAST_CHG_MSK (0x1 << RX_BCAST_CHG_OFF)
#define TX_ID_DWORD0 (PORT_BASE + 0x9c)
#define TX_ID_DWORD1 (PORT_BASE + 0xa0)
#define TX_ID_DWORD2 (PORT_BASE + 0xa4)
@@ -207,8 +207,10 @@
#define TXID_AUTO (PORT_BASE + 0xb8)
#define TXID_AUTO_CT3_OFF 1
#define TXID_AUTO_CT3_MSK (0x1 << TXID_AUTO_CT3_OFF)
-#define TX_HARDRST_OFF 2
-#define TX_HARDRST_MSK (0x1 << TX_HARDRST_OFF)
+#define TXID_AUTO_CTB_OFF 11
+#define TXID_AUTO_CTB_MSK (0x1 << TXID_AUTO_CTB_OFF)
+#define TX_HARDRST_OFF 2
+#define TX_HARDRST_MSK (0x1 << TX_HARDRST_OFF)
#define RX_IDAF_DWORD0 (PORT_BASE + 0xc4)
#define RX_IDAF_DWORD1 (PORT_BASE + 0xc8)
#define RX_IDAF_DWORD2 (PORT_BASE + 0xcc)
@@ -218,6 +220,9 @@
#define RX_IDAF_DWORD6 (PORT_BASE + 0xdc)
#define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc)
#define CON_CONTROL (PORT_BASE + 0x118)
+#define CON_CONTROL_CFG_OPEN_ACC_STP_OFF 0
+#define CON_CONTROL_CFG_OPEN_ACC_STP_MSK \
+ (0x01 << CON_CONTROL_CFG_OPEN_ACC_STP_OFF)
#define DONE_RECEIVED_TIME (PORT_BASE + 0x11c)
#define CHL_INT0 (PORT_BASE + 0x1b4)
#define CHL_INT0_HOTPLUG_TOUT_OFF 0
@@ -240,6 +245,17 @@
#define CHL_INT1_MSK (PORT_BASE + 0x1c4)
#define CHL_INT2_MSK (PORT_BASE + 0x1c8)
#define CHL_INT_COAL_EN (PORT_BASE + 0x1d0)
+#define DMA_TX_DFX0 (PORT_BASE + 0x200)
+#define DMA_TX_DFX1 (PORT_BASE + 0x204)
+#define DMA_TX_DFX1_IPTT_OFF 0
+#define DMA_TX_DFX1_IPTT_MSK (0xffff << DMA_TX_DFX1_IPTT_OFF)
+#define DMA_TX_FIFO_DFX0 (PORT_BASE + 0x240)
+#define PORT_DFX0 (PORT_BASE + 0x258)
+#define LINK_DFX2 (PORT_BASE + 0X264)
+#define LINK_DFX2_RCVR_HOLD_STS_OFF 9
+#define LINK_DFX2_RCVR_HOLD_STS_MSK (0x1 << LINK_DFX2_RCVR_HOLD_STS_OFF)
+#define LINK_DFX2_SEND_HOLD_STS_OFF 10
+#define LINK_DFX2_SEND_HOLD_STS_MSK (0x1 << LINK_DFX2_SEND_HOLD_STS_OFF)
#define PHY_CTRL_RDY_MSK (PORT_BASE + 0x2b0)
#define PHYCTRL_NOT_RDY_MSK (PORT_BASE + 0x2b4)
#define PHYCTRL_DWS_RESET_MSK (PORT_BASE + 0x2b8)
@@ -257,6 +273,10 @@
#define AM_CFG_MAX_TRANS (0x5010)
#define AM_CFG_SINGLE_PORT_MAX_TRANS (0x5014)
+#define AXI_MASTER_CFG_BASE (0x5000)
+#define AM_CTRL_GLOBAL (0x0)
+#define AM_CURR_TRANS_RETURN (0x150)
+
/* HW dma structures */
/* Delivery queue header */
/* dw0 */
@@ -309,6 +329,8 @@
/* Completion header */
/* dw0 */
+#define CMPLT_HDR_ERR_PHASE_OFF 2
+#define CMPLT_HDR_ERR_PHASE_MSK (0xff << CMPLT_HDR_ERR_PHASE_OFF)
#define CMPLT_HDR_RSPNS_XFRD_OFF 10
#define CMPLT_HDR_RSPNS_XFRD_MSK (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF)
#define CMPLT_HDR_ERX_OFF 12
@@ -385,10 +407,10 @@ enum {
enum {
TRANS_TX_FAIL_BASE = 0x0, /* dw0 */
- TRANS_RX_FAIL_BASE = 0x100, /* dw1 */
- DMA_TX_ERR_BASE = 0x200, /* dw2 bit 15-0 */
- SIPC_RX_ERR_BASE = 0x300, /* dw2 bit 31-16*/
- DMA_RX_ERR_BASE = 0x400, /* dw3 */
+ TRANS_RX_FAIL_BASE = 0x20, /* dw1 */
+ DMA_TX_ERR_BASE = 0x40, /* dw2 bit 15-0 */
+ SIPC_RX_ERR_BASE = 0x50, /* dw2 bit 31-16*/
+ DMA_RX_ERR_BASE = 0x60, /* dw3 */
/* trans tx*/
TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS = TRANS_TX_FAIL_BASE, /* 0x0 */
@@ -428,100 +450,104 @@ enum {
TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT, /* 0x1f for sata/stp */
/* trans rx */
- TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x100 */
- TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR, /* 0x101 for sata/stp */
- TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM, /* 0x102 for ssp/smp */
- /*IO_ERR_WITH_RXFIS_8B10B_CODE_ERR, [> 0x102 <] for sata/stp */
- TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR, /* 0x103 for sata/stp */
- TRANS_RX_ERR_WITH_RXFIS_CRC_ERR, /* 0x104 for sata/stp */
- TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN, /* 0x105 for smp */
- /*IO_ERR_WITH_RXFIS_TX SYNCP, [> 0x105 <] for sata/stp */
- TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP, /* 0x106 for sata/stp*/
- TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN, /* 0x107 */
- TRANS_RX_ERR_WITH_BREAK_TIMEOUT, /* 0x108 */
- TRANS_RX_ERR_WITH_BREAK_REQUEST, /* 0x109 */
- TRANS_RX_ERR_WITH_BREAK_RECEVIED, /* 0x10a */
- RESERVED1, /* 0x10b */
- TRANS_RX_ERR_WITH_CLOSE_NORMAL, /* 0x10c */
- TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE, /* 0x10d */
- TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x10e */
- TRANS_RX_ERR_WITH_CLOSE_COMINIT, /* 0x10f */
- TRANS_RX_ERR_WITH_DATA_LEN0, /* 0x110 for ssp/smp */
- TRANS_RX_ERR_WITH_BAD_HASH, /* 0x111 for ssp */
- /*IO_RX_ERR_WITH_FIS_TOO_SHORT, [> 0x111 <] for sata/stp */
- TRANS_RX_XRDY_WLEN_ZERO_ERR, /* 0x112 for ssp*/
- /*IO_RX_ERR_WITH_FIS_TOO_LONG, [> 0x112 <] for sata/stp */
- TRANS_RX_SSP_FRM_LEN_ERR, /* 0x113 for ssp */
- /*IO_RX_ERR_WITH_SATA_DEVICE_LOST, [> 0x113 <] for sata */
- RESERVED2, /* 0x114 */
- RESERVED3, /* 0x115 */
- RESERVED4, /* 0x116 */
- RESERVED5, /* 0x117 */
- TRANS_RX_ERR_WITH_BAD_FRM_TYPE, /* 0x118 */
- TRANS_RX_SMP_FRM_LEN_ERR, /* 0x119 */
- TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x11a */
- RESERVED6, /* 0x11b */
- RESERVED7, /* 0x11c */
- RESERVED8, /* 0x11d */
- RESERVED9, /* 0x11e */
- TRANS_RX_R_ERR, /* 0x11f */
+ TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x20 */
+ TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR, /* 0x21 for sata/stp */
+ TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM, /* 0x22 for ssp/smp */
+ /*IO_ERR_WITH_RXFIS_8B10B_CODE_ERR, [> 0x22 <] for sata/stp */
+ TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR, /* 0x23 for sata/stp */
+ TRANS_RX_ERR_WITH_RXFIS_CRC_ERR, /* 0x24 for sata/stp */
+ TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN, /* 0x25 for smp */
+ /*IO_ERR_WITH_RXFIS_TX SYNCP, [> 0x25 <] for sata/stp */
+ TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP, /* 0x26 for sata/stp*/
+ TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN, /* 0x27 */
+ TRANS_RX_ERR_WITH_BREAK_TIMEOUT, /* 0x28 */
+ TRANS_RX_ERR_WITH_BREAK_REQUEST, /* 0x29 */
+ TRANS_RX_ERR_WITH_BREAK_RECEVIED, /* 0x2a */
+ RESERVED1, /* 0x2b */
+ TRANS_RX_ERR_WITH_CLOSE_NORMAL, /* 0x2c */
+ TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE, /* 0x2d */
+ TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT, /* 0x2e */
+ TRANS_RX_ERR_WITH_CLOSE_COMINIT, /* 0x2f */
+ TRANS_RX_ERR_WITH_DATA_LEN0, /* 0x30 for ssp/smp */
+ TRANS_RX_ERR_WITH_BAD_HASH, /* 0x31 for ssp */
+ /*IO_RX_ERR_WITH_FIS_TOO_SHORT, [> 0x31 <] for sata/stp */
+ TRANS_RX_XRDY_WLEN_ZERO_ERR, /* 0x32 for ssp*/
+ /*IO_RX_ERR_WITH_FIS_TOO_LONG, [> 0x32 <] for sata/stp */
+ TRANS_RX_SSP_FRM_LEN_ERR, /* 0x33 for ssp */
+ /*IO_RX_ERR_WITH_SATA_DEVICE_LOST, [> 0x33 <] for sata */
+ RESERVED2, /* 0x34 */
+ RESERVED3, /* 0x35 */
+ RESERVED4, /* 0x36 */
+ RESERVED5, /* 0x37 */
+ TRANS_RX_ERR_WITH_BAD_FRM_TYPE, /* 0x38 */
+ TRANS_RX_SMP_FRM_LEN_ERR, /* 0x39 */
+ TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x3a */
+ RESERVED6, /* 0x3b */
+ RESERVED7, /* 0x3c */
+ RESERVED8, /* 0x3d */
+ RESERVED9, /* 0x3e */
+ TRANS_RX_R_ERR, /* 0x3f */
/* dma tx */
- DMA_TX_DIF_CRC_ERR = DMA_TX_ERR_BASE, /* 0x200 */
- DMA_TX_DIF_APP_ERR, /* 0x201 */
- DMA_TX_DIF_RPP_ERR, /* 0x202 */
- DMA_TX_DATA_SGL_OVERFLOW, /* 0x203 */
- DMA_TX_DIF_SGL_OVERFLOW, /* 0x204 */
- DMA_TX_UNEXP_XFER_ERR, /* 0x205 */
- DMA_TX_UNEXP_RETRANS_ERR, /* 0x206 */
- DMA_TX_XFER_LEN_OVERFLOW, /* 0x207 */
- DMA_TX_XFER_OFFSET_ERR, /* 0x208 */
- DMA_TX_RAM_ECC_ERR, /* 0x209 */
- DMA_TX_DIF_LEN_ALIGN_ERR, /* 0x20a */
+ DMA_TX_DIF_CRC_ERR = DMA_TX_ERR_BASE, /* 0x40 */
+ DMA_TX_DIF_APP_ERR, /* 0x41 */
+ DMA_TX_DIF_RPP_ERR, /* 0x42 */
+ DMA_TX_DATA_SGL_OVERFLOW, /* 0x43 */
+ DMA_TX_DIF_SGL_OVERFLOW, /* 0x44 */
+ DMA_TX_UNEXP_XFER_ERR, /* 0x45 */
+ DMA_TX_UNEXP_RETRANS_ERR, /* 0x46 */
+ DMA_TX_XFER_LEN_OVERFLOW, /* 0x47 */
+ DMA_TX_XFER_OFFSET_ERR, /* 0x48 */
+ DMA_TX_RAM_ECC_ERR, /* 0x49 */
+ DMA_TX_DIF_LEN_ALIGN_ERR, /* 0x4a */
+ DMA_TX_MAX_ERR_CODE,
/* sipc rx */
- SIPC_RX_FIS_STATUS_ERR_BIT_VLD = SIPC_RX_ERR_BASE, /* 0x300 */
- SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR, /* 0x301 */
- SIPC_RX_FIS_STATUS_BSY_BIT_ERR, /* 0x302 */
- SIPC_RX_WRSETUP_LEN_ODD_ERR, /* 0x303 */
- SIPC_RX_WRSETUP_LEN_ZERO_ERR, /* 0x304 */
- SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR, /* 0x305 */
- SIPC_RX_NCQ_WRSETUP_OFFSET_ERR, /* 0x306 */
- SIPC_RX_NCQ_WRSETUP_AUTO_ACTIVE_ERR, /* 0x307 */
- SIPC_RX_SATA_UNEXP_FIS_ERR, /* 0x308 */
- SIPC_RX_WRSETUP_ESTATUS_ERR, /* 0x309 */
- SIPC_RX_DATA_UNDERFLOW_ERR, /* 0x30a */
+ SIPC_RX_FIS_STATUS_ERR_BIT_VLD = SIPC_RX_ERR_BASE, /* 0x50 */
+ SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR, /* 0x51 */
+ SIPC_RX_FIS_STATUS_BSY_BIT_ERR, /* 0x52 */
+ SIPC_RX_WRSETUP_LEN_ODD_ERR, /* 0x53 */
+ SIPC_RX_WRSETUP_LEN_ZERO_ERR, /* 0x54 */
+ SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR, /* 0x55 */
+ SIPC_RX_NCQ_WRSETUP_OFFSET_ERR, /* 0x56 */
+ SIPC_RX_NCQ_WRSETUP_AUTO_ACTIVE_ERR, /* 0x57 */
+ SIPC_RX_SATA_UNEXP_FIS_ERR, /* 0x58 */
+ SIPC_RX_WRSETUP_ESTATUS_ERR, /* 0x59 */
+ SIPC_RX_DATA_UNDERFLOW_ERR, /* 0x5a */
+ SIPC_RX_MAX_ERR_CODE,
/* dma rx */
- DMA_RX_DIF_CRC_ERR = DMA_RX_ERR_BASE, /* 0x400 */
- DMA_RX_DIF_APP_ERR, /* 0x401 */
- DMA_RX_DIF_RPP_ERR, /* 0x402 */
- DMA_RX_DATA_SGL_OVERFLOW, /* 0x403 */
- DMA_RX_DIF_SGL_OVERFLOW, /* 0x404 */
- DMA_RX_DATA_LEN_OVERFLOW, /* 0x405 */
- DMA_RX_DATA_LEN_UNDERFLOW, /* 0x406 */
- DMA_RX_DATA_OFFSET_ERR, /* 0x407 */
- RESERVED10, /* 0x408 */
- DMA_RX_SATA_FRAME_TYPE_ERR, /* 0x409 */
- DMA_RX_RESP_BUF_OVERFLOW, /* 0x40a */
- DMA_RX_UNEXP_RETRANS_RESP_ERR, /* 0x40b */
- DMA_RX_UNEXP_NORM_RESP_ERR, /* 0x40c */
- DMA_RX_UNEXP_RDFRAME_ERR, /* 0x40d */
- DMA_RX_PIO_DATA_LEN_ERR, /* 0x40e */
- DMA_RX_RDSETUP_STATUS_ERR, /* 0x40f */
- DMA_RX_RDSETUP_STATUS_DRQ_ERR, /* 0x410 */
- DMA_RX_RDSETUP_STATUS_BSY_ERR, /* 0x411 */
- DMA_RX_RDSETUP_LEN_ODD_ERR, /* 0x412 */
- DMA_RX_RDSETUP_LEN_ZERO_ERR, /* 0x413 */
- DMA_RX_RDSETUP_LEN_OVER_ERR, /* 0x414 */
- DMA_RX_RDSETUP_OFFSET_ERR, /* 0x415 */
- DMA_RX_RDSETUP_ACTIVE_ERR, /* 0x416 */
- DMA_RX_RDSETUP_ESTATUS_ERR, /* 0x417 */
- DMA_RX_RAM_ECC_ERR, /* 0x418 */
- DMA_RX_UNKNOWN_FRM_ERR, /* 0x419 */
+ DMA_RX_DIF_CRC_ERR = DMA_RX_ERR_BASE, /* 0x60 */
+ DMA_RX_DIF_APP_ERR, /* 0x61 */
+ DMA_RX_DIF_RPP_ERR, /* 0x62 */
+ DMA_RX_DATA_SGL_OVERFLOW, /* 0x63 */
+ DMA_RX_DIF_SGL_OVERFLOW, /* 0x64 */
+ DMA_RX_DATA_LEN_OVERFLOW, /* 0x65 */
+ DMA_RX_DATA_LEN_UNDERFLOW, /* 0x66 */
+ DMA_RX_DATA_OFFSET_ERR, /* 0x67 */
+ RESERVED10, /* 0x68 */
+ DMA_RX_SATA_FRAME_TYPE_ERR, /* 0x69 */
+ DMA_RX_RESP_BUF_OVERFLOW, /* 0x6a */
+ DMA_RX_UNEXP_RETRANS_RESP_ERR, /* 0x6b */
+ DMA_RX_UNEXP_NORM_RESP_ERR, /* 0x6c */
+ DMA_RX_UNEXP_RDFRAME_ERR, /* 0x6d */
+ DMA_RX_PIO_DATA_LEN_ERR, /* 0x6e */
+ DMA_RX_RDSETUP_STATUS_ERR, /* 0x6f */
+ DMA_RX_RDSETUP_STATUS_DRQ_ERR, /* 0x70 */
+ DMA_RX_RDSETUP_STATUS_BSY_ERR, /* 0x71 */
+ DMA_RX_RDSETUP_LEN_ODD_ERR, /* 0x72 */
+ DMA_RX_RDSETUP_LEN_ZERO_ERR, /* 0x73 */
+ DMA_RX_RDSETUP_LEN_OVER_ERR, /* 0x74 */
+ DMA_RX_RDSETUP_OFFSET_ERR, /* 0x75 */
+ DMA_RX_RDSETUP_ACTIVE_ERR, /* 0x76 */
+ DMA_RX_RDSETUP_ESTATUS_ERR, /* 0x77 */
+ DMA_RX_RAM_ECC_ERR, /* 0x78 */
+ DMA_RX_UNKNOWN_FRM_ERR, /* 0x79 */
+ DMA_RX_MAX_ERR_CODE,
};
#define HISI_SAS_COMMAND_ENTRIES_V2_HW 4096
+#define HISI_MAX_SATA_SUPPORT_V2_HW (HISI_SAS_COMMAND_ENTRIES_V2_HW/64 - 1)
#define DIR_NO_DATA 0
#define DIR_TO_INI 1
@@ -534,7 +560,13 @@ enum {
#define SATA_PROTOCOL_FPDMA 0x8
#define SATA_PROTOCOL_ATAPI 0x10
-static void hisi_sas_link_timeout_disable_link(unsigned long data);
+#define ERR_ON_TX_PHASE(err_phase) (err_phase == 0x2 || \
+ err_phase == 0x4 || err_phase == 0x8 ||\
+ err_phase == 0x6 || err_phase == 0xa)
+#define ERR_ON_RX_PHASE(err_phase) (err_phase == 0x10 || \
+ err_phase == 0x20 || err_phase == 0x40)
+
+static void link_timeout_disable_link(unsigned long data);
static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
{
@@ -576,38 +608,86 @@ static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
/* This function needs to be protected from pre-emption. */
static int
slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx,
- struct domain_device *device)
+ struct domain_device *device)
{
- unsigned int index = 0;
- void *bitmap = hisi_hba->slot_index_tags;
int sata_dev = dev_is_sata(device);
+ void *bitmap = hisi_hba->slot_index_tags;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ int sata_idx = sas_dev->sata_idx;
+ int start, end;
+
+ if (!sata_dev) {
+ /*
+ * STP link SoC bug workaround: index starts from 1.
+ * additionally, we can only allocate odd IPTT(1~4095)
+ * for SAS/SMP device.
+ */
+ start = 1;
+ end = hisi_hba->slot_index_count;
+ } else {
+ if (sata_idx >= HISI_MAX_SATA_SUPPORT_V2_HW)
+ return -EINVAL;
+
+ /*
+ * For SATA device: allocate even IPTT in this interval
+ * [64*(sata_idx+1), 64*(sata_idx+2)], then each SATA device
+ * own 32 IPTTs. IPTT 0 shall not be used duing to STP link
+ * SoC bug workaround. So we ignore the first 32 even IPTTs.
+ */
+ start = 64 * (sata_idx + 1);
+ end = 64 * (sata_idx + 2);
+ }
while (1) {
- index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count,
- index);
- if (index >= hisi_hba->slot_index_count)
+ start = find_next_zero_bit(bitmap,
+ hisi_hba->slot_index_count, start);
+ if (start >= end)
return -SAS_QUEUE_FULL;
/*
- * SAS IPTT bit0 should be 1
- */
- if (sata_dev || (index & 1))
+ * SAS IPTT bit0 should be 1, and SATA IPTT bit0 should be 0.
+ */
+ if (sata_dev ^ (start & 1))
break;
- index++;
+ start++;
}
- set_bit(index, bitmap);
- *slot_idx = index;
+ set_bit(start, bitmap);
+ *slot_idx = start;
return 0;
}
+static bool sata_index_alloc_v2_hw(struct hisi_hba *hisi_hba, int *idx)
+{
+ unsigned int index;
+ struct device *dev = &hisi_hba->pdev->dev;
+ void *bitmap = hisi_hba->sata_dev_bitmap;
+
+ index = find_first_zero_bit(bitmap, HISI_MAX_SATA_SUPPORT_V2_HW);
+ if (index >= HISI_MAX_SATA_SUPPORT_V2_HW) {
+ dev_warn(dev, "alloc sata index failed, index=%d\n", index);
+ return false;
+ }
+
+ set_bit(index, bitmap);
+ *idx = index;
+ return true;
+}
+
+
static struct
hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device)
{
struct hisi_hba *hisi_hba = device->port->ha->lldd_ha;
struct hisi_sas_device *sas_dev = NULL;
int i, sata_dev = dev_is_sata(device);
+ int sata_idx = -1;
spin_lock(&hisi_hba->lock);
+
+ if (sata_dev)
+ if (!sata_index_alloc_v2_hw(hisi_hba, &sata_idx))
+ goto out;
+
for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
/*
* SATA device id bit0 should be 0
@@ -621,9 +701,13 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device)
sas_dev->dev_type = device->dev_type;
sas_dev->hisi_hba = hisi_hba;
sas_dev->sas_device = device;
+ sas_dev->sata_idx = sata_idx;
+ INIT_LIST_HEAD(&hisi_hba->devices[i].list);
break;
}
}
+
+out:
spin_unlock(&hisi_hba->lock);
return sas_dev;
@@ -676,7 +760,8 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
u64 qw0, device_id = sas_dev->device_id;
struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
struct domain_device *parent_dev = device->parent;
- struct hisi_sas_port *port = device->port->lldd_port;
+ struct asd_sas_port *sas_port = device->port;
+ struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
memset(itct, 0, sizeof(*itct));
@@ -729,6 +814,10 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba,
u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
int i;
+ /* SoC bug workaround */
+ if (dev_is_sata(sas_dev->sas_device))
+ clear_bit(sas_dev->sata_idx, hisi_hba->sata_dev_bitmap);
+
/* clear the itct interrupt state */
if (ENT_INT_SRC3_ITC_INT_MSK & reg_val)
hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
@@ -858,6 +947,46 @@ static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
return 0;
}
+/* This function needs to be called after resetting SAS controller. */
+static void phys_reject_stp_links_v2_hw(struct hisi_hba *hisi_hba)
+{
+ u32 cfg;
+ int phy_no;
+
+ hisi_hba->reject_stp_links_msk = (1 << hisi_hba->n_phy) - 1;
+ for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
+ cfg = hisi_sas_phy_read32(hisi_hba, phy_no, CON_CONTROL);
+ if (!(cfg & CON_CONTROL_CFG_OPEN_ACC_STP_MSK))
+ continue;
+
+ cfg &= ~CON_CONTROL_CFG_OPEN_ACC_STP_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, CON_CONTROL, cfg);
+ }
+}
+
+static void phys_try_accept_stp_links_v2_hw(struct hisi_hba *hisi_hba)
+{
+ int phy_no;
+ u32 dma_tx_dfx1;
+
+ for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
+ if (!(hisi_hba->reject_stp_links_msk & BIT(phy_no)))
+ continue;
+
+ dma_tx_dfx1 = hisi_sas_phy_read32(hisi_hba, phy_no,
+ DMA_TX_DFX1);
+ if (dma_tx_dfx1 & DMA_TX_DFX1_IPTT_MSK) {
+ u32 cfg = hisi_sas_phy_read32(hisi_hba,
+ phy_no, CON_CONTROL);
+
+ cfg |= CON_CONTROL_CFG_OPEN_ACC_STP_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no,
+ CON_CONTROL, cfg);
+ clear_bit(phy_no, &hisi_hba->reject_stp_links_msk);
+ }
+ }
+}
+
static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
{
struct device *dev = &hisi_hba->pdev->dev;
@@ -876,7 +1005,7 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
(u32)((1ULL << hisi_hba->queue_count) - 1));
hisi_sas_write32(hisi_hba, AXI_USER1, 0xc0000000);
hisi_sas_write32(hisi_hba, AXI_USER2, 0x10000);
- hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108);
+ hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x0);
hisi_sas_write32(hisi_hba, HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL, 0x7FF);
hisi_sas_write32(hisi_hba, OPENA_WT_CONTI_TIME, 0x1);
hisi_sas_write32(hisi_hba, I_T_NEXUS_LOSS_TIME, 0x1F4);
@@ -885,9 +1014,9 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1);
hisi_sas_write32(hisi_hba, HGC_ERR_STAT_EN, 0x1);
hisi_sas_write32(hisi_hba, HGC_GET_ITV_TIME, 0x1);
- hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1);
- hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x1);
- hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x1);
+ hisi_sas_write32(hisi_hba, INT_COAL_EN, 0xc);
+ hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x60);
+ hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x3);
hisi_sas_write32(hisi_hba, ENT_INT_COAL_TIME, 0x1);
hisi_sas_write32(hisi_hba, ENT_INT_COAL_CNT, 0x1);
hisi_sas_write32(hisi_hba, OQ_INT_SRC, 0x0);
@@ -910,14 +1039,14 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d);
hisi_sas_phy_write32(hisi_hba, i, SL_CONTROL, 0x0);
hisi_sas_phy_write32(hisi_hba, i, TXID_AUTO, 0x2);
- hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0x10);
+ hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0x8);
hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff);
hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xfff87fff);
hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xffffffff);
hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8ffffbff);
- hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x23f801fc);
+ hisi_sas_phy_write32(hisi_hba, i, SL_CFG, 0x13f801fc);
hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0);
hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0);
hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_DWS_RESET_MSK, 0x0);
@@ -989,12 +1118,15 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
upper_32_bits(hisi_hba->initial_fis_dma));
}
-static void hisi_sas_link_timeout_enable_link(unsigned long data)
+static void link_timeout_enable_link(unsigned long data)
{
struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
int i, reg_val;
for (i = 0; i < hisi_hba->n_phy; i++) {
+ if (hisi_hba->reject_stp_links_msk & BIT(i))
+ continue;
+
reg_val = hisi_sas_phy_read32(hisi_hba, i, CON_CONTROL);
if (!(reg_val & BIT(0))) {
hisi_sas_phy_write32(hisi_hba, i,
@@ -1003,17 +1135,20 @@ static void hisi_sas_link_timeout_enable_link(unsigned long data)
}
}
- hisi_hba->timer.function = hisi_sas_link_timeout_disable_link;
+ hisi_hba->timer.function = link_timeout_disable_link;
mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(900));
}
-static void hisi_sas_link_timeout_disable_link(unsigned long data)
+static void link_timeout_disable_link(unsigned long data)
{
struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
int i, reg_val;
reg_val = hisi_sas_read32(hisi_hba, PHY_STATE);
for (i = 0; i < hisi_hba->n_phy && reg_val; i++) {
+ if (hisi_hba->reject_stp_links_msk & BIT(i))
+ continue;
+
if (reg_val & BIT(i)) {
hisi_sas_phy_write32(hisi_hba, i,
CON_CONTROL, 0x6);
@@ -1021,14 +1156,14 @@ static void hisi_sas_link_timeout_disable_link(unsigned long data)
}
}
- hisi_hba->timer.function = hisi_sas_link_timeout_enable_link;
+ hisi_hba->timer.function = link_timeout_enable_link;
mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(100));
}
static void set_link_timer_quirk(struct hisi_hba *hisi_hba)
{
hisi_hba->timer.data = (unsigned long)hisi_hba;
- hisi_hba->timer.function = hisi_sas_link_timeout_disable_link;
+ hisi_hba->timer.function = link_timeout_disable_link;
hisi_hba->timer.expires = jiffies + msecs_to_jiffies(1000);
add_timer(&hisi_hba->timer);
}
@@ -1058,12 +1193,138 @@ static void enable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
}
+static bool is_sata_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 context;
+
+ context = hisi_sas_read32(hisi_hba, PHY_CONTEXT);
+ if (context & (1 << phy_no))
+ return true;
+
+ return false;
+}
+
+static bool tx_fifo_is_empty_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 dfx_val;
+
+ dfx_val = hisi_sas_phy_read32(hisi_hba, phy_no, DMA_TX_DFX1);
+
+ if (dfx_val & BIT(16))
+ return false;
+
+ return true;
+}
+
+static bool axi_bus_is_idle_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ int i, max_loop = 1000;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 status, axi_status, dfx_val, dfx_tx_val;
+
+ for (i = 0; i < max_loop; i++) {
+ status = hisi_sas_read32_relaxed(hisi_hba,
+ AXI_MASTER_CFG_BASE + AM_CURR_TRANS_RETURN);
+
+ axi_status = hisi_sas_read32(hisi_hba, AXI_CFG);
+ dfx_val = hisi_sas_phy_read32(hisi_hba, phy_no, DMA_TX_DFX1);
+ dfx_tx_val = hisi_sas_phy_read32(hisi_hba,
+ phy_no, DMA_TX_FIFO_DFX0);
+
+ if ((status == 0x3) && (axi_status == 0x0) &&
+ (dfx_val & BIT(20)) && (dfx_tx_val & BIT(10)))
+ return true;
+ udelay(10);
+ }
+ dev_err(dev, "bus is not idle phy%d, axi150:0x%x axi100:0x%x port204:0x%x port240:0x%x\n",
+ phy_no, status, axi_status,
+ dfx_val, dfx_tx_val);
+ return false;
+}
+
+static bool wait_io_done_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ int i, max_loop = 1000;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 status, tx_dfx0;
+
+ for (i = 0; i < max_loop; i++) {
+ status = hisi_sas_phy_read32(hisi_hba, phy_no, LINK_DFX2);
+ status = (status & 0x3fc0) >> 6;
+
+ if (status != 0x1)
+ return true;
+
+ tx_dfx0 = hisi_sas_phy_read32(hisi_hba, phy_no, DMA_TX_DFX0);
+ if ((tx_dfx0 & 0x1ff) == 0x2)
+ return true;
+ udelay(10);
+ }
+ dev_err(dev, "IO not done phy%d, port264:0x%x port200:0x%x\n",
+ phy_no, status, tx_dfx0);
+ return false;
+}
+
+static bool allowed_disable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ if (tx_fifo_is_empty_v2_hw(hisi_hba, phy_no))
+ return true;
+
+ if (!axi_bus_is_idle_v2_hw(hisi_hba, phy_no))
+ return false;
+
+ if (!wait_io_done_v2_hw(hisi_hba, phy_no))
+ return false;
+
+ return true;
+}
+
+
static void disable_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
{
- u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+ u32 cfg, axi_val, dfx0_val, txid_auto;
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ /* Close axi bus. */
+ axi_val = hisi_sas_read32(hisi_hba, AXI_MASTER_CFG_BASE +
+ AM_CTRL_GLOBAL);
+ axi_val |= 0x1;
+ hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE +
+ AM_CTRL_GLOBAL, axi_val);
+
+ if (is_sata_phy_v2_hw(hisi_hba, phy_no)) {
+ if (allowed_disable_phy_v2_hw(hisi_hba, phy_no))
+ goto do_disable;
+
+ /* Reset host controller. */
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+ return;
+ }
+
+ dfx0_val = hisi_sas_phy_read32(hisi_hba, phy_no, PORT_DFX0);
+ dfx0_val = (dfx0_val & 0x1fc0) >> 6;
+ if (dfx0_val != 0x4)
+ goto do_disable;
+ if (!tx_fifo_is_empty_v2_hw(hisi_hba, phy_no)) {
+ dev_warn(dev, "phy%d, wait tx fifo need send break\n",
+ phy_no);
+ txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no,
+ TXID_AUTO);
+ txid_auto |= TXID_AUTO_CTB_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
+ txid_auto);
+ }
+
+do_disable:
+ cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
cfg &= ~PHY_CFG_ENA_MSK;
hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+
+ /* Open axi bus. */
+ axi_val &= ~0x1;
+ hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE +
+ AM_CTRL_GLOBAL, axi_val);
}
static void start_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
@@ -1078,6 +1339,14 @@ static void stop_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
disable_phy_v2_hw(hisi_hba, phy_no);
}
+static void stop_phys_v2_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++)
+ stop_phy_v2_hw(hisi_hba, i);
+}
+
static void phy_hard_reset_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
{
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
@@ -1437,10 +1706,205 @@ static void sata_done_v2_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
ts->buf_valid_size = sizeof(*resp);
}
+#define TRANS_TX_ERR 0
+#define TRANS_RX_ERR 1
+#define DMA_TX_ERR 2
+#define SIPC_RX_ERR 3
+#define DMA_RX_ERR 4
+
+#define DMA_TX_ERR_OFF 0
+#define DMA_TX_ERR_MSK (0xffff << DMA_TX_ERR_OFF)
+#define SIPC_RX_ERR_OFF 16
+#define SIPC_RX_ERR_MSK (0xffff << SIPC_RX_ERR_OFF)
+
+static int parse_trans_tx_err_code_v2_hw(u32 err_msk)
+{
+ const u8 trans_tx_err_code_prio[] = {
+ TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS,
+ TRANS_TX_ERR_PHY_NOT_ENABLE,
+ TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION,
+ TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION,
+ TRANS_TX_OPEN_CNX_ERR_BY_OTHER,
+ RESERVED0,
+ TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT,
+ TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY,
+ TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED,
+ TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED,
+ TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION,
+ TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD,
+ TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER,
+ TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED,
+ TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT,
+ TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION,
+ TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED,
+ TRANS_TX_ERR_WITH_CLOSE_PHYDISALE,
+ TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT,
+ TRANS_TX_ERR_WITH_CLOSE_COMINIT,
+ TRANS_TX_ERR_WITH_BREAK_TIMEOUT,
+ TRANS_TX_ERR_WITH_BREAK_REQUEST,
+ TRANS_TX_ERR_WITH_BREAK_RECEVIED,
+ TRANS_TX_ERR_WITH_CLOSE_TIMEOUT,
+ TRANS_TX_ERR_WITH_CLOSE_NORMAL,
+ TRANS_TX_ERR_WITH_NAK_RECEVIED,
+ TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT,
+ TRANS_TX_ERR_WITH_CREDIT_TIMEOUT,
+ TRANS_TX_ERR_WITH_IPTT_CONFLICT,
+ TRANS_TX_ERR_WITH_OPEN_BY_DES_OR_OTHERS,
+ TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT,
+ };
+ int index, i;
+
+ for (i = 0; i < ARRAY_SIZE(trans_tx_err_code_prio); i++) {
+ index = trans_tx_err_code_prio[i] - TRANS_TX_FAIL_BASE;
+ if (err_msk & (1 << index))
+ return trans_tx_err_code_prio[i];
+ }
+ return -1;
+}
+
+static int parse_trans_rx_err_code_v2_hw(u32 err_msk)
+{
+ const u8 trans_rx_err_code_prio[] = {
+ TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR,
+ TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR,
+ TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM,
+ TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR,
+ TRANS_RX_ERR_WITH_RXFIS_CRC_ERR,
+ TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN,
+ TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP,
+ TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN,
+ TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE,
+ TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT,
+ TRANS_RX_ERR_WITH_CLOSE_COMINIT,
+ TRANS_RX_ERR_WITH_BREAK_TIMEOUT,
+ TRANS_RX_ERR_WITH_BREAK_REQUEST,
+ TRANS_RX_ERR_WITH_BREAK_RECEVIED,
+ RESERVED1,
+ TRANS_RX_ERR_WITH_CLOSE_NORMAL,
+ TRANS_RX_ERR_WITH_DATA_LEN0,
+ TRANS_RX_ERR_WITH_BAD_HASH,
+ TRANS_RX_XRDY_WLEN_ZERO_ERR,
+ TRANS_RX_SSP_FRM_LEN_ERR,
+ RESERVED2,
+ RESERVED3,
+ RESERVED4,
+ RESERVED5,
+ TRANS_RX_ERR_WITH_BAD_FRM_TYPE,
+ TRANS_RX_SMP_FRM_LEN_ERR,
+ TRANS_RX_SMP_RESP_TIMEOUT_ERR,
+ RESERVED6,
+ RESERVED7,
+ RESERVED8,
+ RESERVED9,
+ TRANS_RX_R_ERR,
+ };
+ int index, i;
+
+ for (i = 0; i < ARRAY_SIZE(trans_rx_err_code_prio); i++) {
+ index = trans_rx_err_code_prio[i] - TRANS_RX_FAIL_BASE;
+ if (err_msk & (1 << index))
+ return trans_rx_err_code_prio[i];
+ }
+ return -1;
+}
+
+static int parse_dma_tx_err_code_v2_hw(u32 err_msk)
+{
+ const u8 dma_tx_err_code_prio[] = {
+ DMA_TX_UNEXP_XFER_ERR,
+ DMA_TX_UNEXP_RETRANS_ERR,
+ DMA_TX_XFER_LEN_OVERFLOW,
+ DMA_TX_XFER_OFFSET_ERR,
+ DMA_TX_RAM_ECC_ERR,
+ DMA_TX_DIF_LEN_ALIGN_ERR,
+ DMA_TX_DIF_CRC_ERR,
+ DMA_TX_DIF_APP_ERR,
+ DMA_TX_DIF_RPP_ERR,
+ DMA_TX_DATA_SGL_OVERFLOW,
+ DMA_TX_DIF_SGL_OVERFLOW,
+ };
+ int index, i;
+
+ for (i = 0; i < ARRAY_SIZE(dma_tx_err_code_prio); i++) {
+ index = dma_tx_err_code_prio[i] - DMA_TX_ERR_BASE;
+ err_msk = err_msk & DMA_TX_ERR_MSK;
+ if (err_msk & (1 << index))
+ return dma_tx_err_code_prio[i];
+ }
+ return -1;
+}
+
+static int parse_sipc_rx_err_code_v2_hw(u32 err_msk)
+{
+ const u8 sipc_rx_err_code_prio[] = {
+ SIPC_RX_FIS_STATUS_ERR_BIT_VLD,
+ SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR,
+ SIPC_RX_FIS_STATUS_BSY_BIT_ERR,
+ SIPC_RX_WRSETUP_LEN_ODD_ERR,
+ SIPC_RX_WRSETUP_LEN_ZERO_ERR,
+ SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR,
+ SIPC_RX_NCQ_WRSETUP_OFFSET_ERR,
+ SIPC_RX_NCQ_WRSETUP_AUTO_ACTIVE_ERR,
+ SIPC_RX_SATA_UNEXP_FIS_ERR,
+ SIPC_RX_WRSETUP_ESTATUS_ERR,
+ SIPC_RX_DATA_UNDERFLOW_ERR,
+ };
+ int index, i;
+
+ for (i = 0; i < ARRAY_SIZE(sipc_rx_err_code_prio); i++) {
+ index = sipc_rx_err_code_prio[i] - SIPC_RX_ERR_BASE;
+ err_msk = err_msk & SIPC_RX_ERR_MSK;
+ if (err_msk & (1 << (index + 0x10)))
+ return sipc_rx_err_code_prio[i];
+ }
+ return -1;
+}
+
+static int parse_dma_rx_err_code_v2_hw(u32 err_msk)
+{
+ const u8 dma_rx_err_code_prio[] = {
+ DMA_RX_UNKNOWN_FRM_ERR,
+ DMA_RX_DATA_LEN_OVERFLOW,
+ DMA_RX_DATA_LEN_UNDERFLOW,
+ DMA_RX_DATA_OFFSET_ERR,
+ RESERVED10,
+ DMA_RX_SATA_FRAME_TYPE_ERR,
+ DMA_RX_RESP_BUF_OVERFLOW,
+ DMA_RX_UNEXP_RETRANS_RESP_ERR,
+ DMA_RX_UNEXP_NORM_RESP_ERR,
+ DMA_RX_UNEXP_RDFRAME_ERR,
+ DMA_RX_PIO_DATA_LEN_ERR,
+ DMA_RX_RDSETUP_STATUS_ERR,
+ DMA_RX_RDSETUP_STATUS_DRQ_ERR,
+ DMA_RX_RDSETUP_STATUS_BSY_ERR,
+ DMA_RX_RDSETUP_LEN_ODD_ERR,
+ DMA_RX_RDSETUP_LEN_ZERO_ERR,
+ DMA_RX_RDSETUP_LEN_OVER_ERR,
+ DMA_RX_RDSETUP_OFFSET_ERR,
+ DMA_RX_RDSETUP_ACTIVE_ERR,
+ DMA_RX_RDSETUP_ESTATUS_ERR,
+ DMA_RX_RAM_ECC_ERR,
+ DMA_RX_DIF_CRC_ERR,
+ DMA_RX_DIF_APP_ERR,
+ DMA_RX_DIF_RPP_ERR,
+ DMA_RX_DATA_SGL_OVERFLOW,
+ DMA_RX_DIF_SGL_OVERFLOW,
+ };
+ int index, i;
+
+ for (i = 0; i < ARRAY_SIZE(dma_rx_err_code_prio); i++) {
+ index = dma_rx_err_code_prio[i] - DMA_RX_ERR_BASE;
+ if (err_msk & (1 << index))
+ return dma_rx_err_code_prio[i];
+ }
+ return -1;
+}
+
/* by default, task resp is complete */
static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
struct sas_task *task,
- struct hisi_sas_slot *slot)
+ struct hisi_sas_slot *slot,
+ int err_phase)
{
struct task_status_struct *ts = &task->task_status;
struct hisi_sas_err_record_v2 *err_record = slot->status_buffer;
@@ -1451,21 +1915,23 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
u32 dma_rx_err_type = cpu_to_le32(err_record->dma_rx_err_type);
int error = -1;
- if (dma_rx_err_type) {
- error = ffs(dma_rx_err_type)
- - 1 + DMA_RX_ERR_BASE;
- } else if (sipc_rx_err_type) {
- error = ffs(sipc_rx_err_type)
- - 1 + SIPC_RX_ERR_BASE;
- } else if (dma_tx_err_type) {
- error = ffs(dma_tx_err_type)
- - 1 + DMA_TX_ERR_BASE;
- } else if (trans_rx_fail_type) {
- error = ffs(trans_rx_fail_type)
- - 1 + TRANS_RX_FAIL_BASE;
- } else if (trans_tx_fail_type) {
- error = ffs(trans_tx_fail_type)
- - 1 + TRANS_TX_FAIL_BASE;
+ if (err_phase == 1) {
+ /* error in TX phase, the priority of error is: DW2 > DW0 */
+ error = parse_dma_tx_err_code_v2_hw(dma_tx_err_type);
+ if (error == -1)
+ error = parse_trans_tx_err_code_v2_hw(
+ trans_tx_fail_type);
+ } else if (err_phase == 2) {
+ /* error in RX phase, the priority is: DW1 > DW3 > DW2 */
+ error = parse_trans_rx_err_code_v2_hw(
+ trans_rx_fail_type);
+ if (error == -1) {
+ error = parse_dma_rx_err_code_v2_hw(
+ dma_rx_err_type);
+ if (error == -1)
+ error = parse_sipc_rx_err_code_v2_hw(
+ sipc_rx_err_type);
+ }
}
switch (task->task_proto) {
@@ -1478,12 +1944,6 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
ts->open_rej_reason = SAS_OREJ_NO_DEST;
break;
}
- case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
- {
- ts->stat = SAS_OPEN_REJECT;
- ts->open_rej_reason = SAS_OREJ_PATH_BLOCKED;
- break;
- }
case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED:
{
ts->stat = SAS_OPEN_REJECT;
@@ -1502,19 +1962,15 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
ts->open_rej_reason = SAS_OREJ_BAD_DEST;
break;
}
- case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
- {
- ts->stat = SAS_OPEN_REJECT;
- ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
- break;
- }
case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION:
{
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
break;
}
+ case DMA_RX_UNEXP_NORM_RESP_ERR:
case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION:
+ case DMA_RX_RESP_BUF_OVERFLOW:
{
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_UNKNOWN;
@@ -1526,16 +1982,6 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
ts->stat = SAS_DEV_NO_RESPONSE;
break;
}
- case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE:
- {
- ts->stat = SAS_PHY_DOWN;
- break;
- }
- case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
- {
- ts->stat = SAS_OPEN_TO;
- break;
- }
case DMA_RX_DATA_LEN_OVERFLOW:
{
ts->stat = SAS_DATA_OVERRUN;
@@ -1543,60 +1989,65 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
break;
}
case DMA_RX_DATA_LEN_UNDERFLOW:
- case SIPC_RX_DATA_UNDERFLOW_ERR:
{
- ts->residual = trans_tx_fail_type;
+ ts->residual = dma_rx_err_type;
ts->stat = SAS_DATA_UNDERRUN;
break;
}
- case TRANS_TX_ERR_FRAME_TXED:
- {
- /* This will request a retry */
- ts->stat = SAS_QUEUE_FULL;
- slot->abort = 1;
- break;
- }
case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS:
case TRANS_TX_ERR_PHY_NOT_ENABLE:
case TRANS_TX_OPEN_CNX_ERR_BY_OTHER:
case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT:
+ case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
+ case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
+ case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED:
case TRANS_TX_ERR_WITH_BREAK_TIMEOUT:
case TRANS_TX_ERR_WITH_BREAK_REQUEST:
case TRANS_TX_ERR_WITH_BREAK_RECEVIED:
case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT:
case TRANS_TX_ERR_WITH_CLOSE_NORMAL:
+ case TRANS_TX_ERR_WITH_CLOSE_PHYDISALE:
case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT:
case TRANS_TX_ERR_WITH_CLOSE_COMINIT:
case TRANS_TX_ERR_WITH_NAK_RECEVIED:
case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT:
- case TRANS_TX_ERR_WITH_IPTT_CONFLICT:
case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT:
+ case TRANS_TX_ERR_WITH_IPTT_CONFLICT:
case TRANS_RX_ERR_WITH_RXFRAME_CRC_ERR:
case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR:
case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM:
+ case TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN:
case TRANS_RX_ERR_WITH_BREAK_TIMEOUT:
case TRANS_RX_ERR_WITH_BREAK_REQUEST:
case TRANS_RX_ERR_WITH_BREAK_RECEVIED:
case TRANS_RX_ERR_WITH_CLOSE_NORMAL:
case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT:
case TRANS_RX_ERR_WITH_CLOSE_COMINIT:
+ case TRANS_TX_ERR_FRAME_TXED:
+ case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE:
case TRANS_RX_ERR_WITH_DATA_LEN0:
case TRANS_RX_ERR_WITH_BAD_HASH:
case TRANS_RX_XRDY_WLEN_ZERO_ERR:
case TRANS_RX_SSP_FRM_LEN_ERR:
case TRANS_RX_ERR_WITH_BAD_FRM_TYPE:
+ case DMA_TX_DATA_SGL_OVERFLOW:
case DMA_TX_UNEXP_XFER_ERR:
case DMA_TX_UNEXP_RETRANS_ERR:
case DMA_TX_XFER_LEN_OVERFLOW:
case DMA_TX_XFER_OFFSET_ERR:
+ case SIPC_RX_DATA_UNDERFLOW_ERR:
+ case DMA_RX_DATA_SGL_OVERFLOW:
case DMA_RX_DATA_OFFSET_ERR:
- case DMA_RX_UNEXP_NORM_RESP_ERR:
- case DMA_RX_UNEXP_RDFRAME_ERR:
+ case DMA_RX_RDSETUP_LEN_ODD_ERR:
+ case DMA_RX_RDSETUP_LEN_ZERO_ERR:
+ case DMA_RX_RDSETUP_LEN_OVER_ERR:
+ case DMA_RX_SATA_FRAME_TYPE_ERR:
case DMA_RX_UNKNOWN_FRM_ERR:
{
- ts->stat = SAS_OPEN_REJECT;
- ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ /* This will request a retry */
+ ts->stat = SAS_QUEUE_FULL;
+ slot->abort = 1;
break;
}
default:
@@ -1613,57 +2064,92 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
{
switch (error) {
- case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER:
- case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
case TRANS_TX_OPEN_CNX_ERR_NO_DESTINATION:
{
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_NO_DEST;
+ break;
+ }
+ case TRANS_TX_OPEN_CNX_ERR_LOW_PHY_POWER:
+ {
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_DEV_NO_RESPONSE;
break;
}
case TRANS_TX_OPEN_CNX_ERR_PROTOCOL_NOT_SUPPORTED:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_EPROTO;
+ break;
+ }
case TRANS_TX_OPEN_CNX_ERR_CONNECTION_RATE_NOT_SUPPORTED:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_CONN_RATE;
+ break;
+ }
case TRANS_TX_OPEN_CNX_ERR_BAD_DESTINATION:
- case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_CONN_RATE;
+ break;
+ }
case TRANS_TX_OPEN_CNX_ERR_WRONG_DESTINATION:
- case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION:
- case TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY:
{
ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
break;
}
- case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
+ case DMA_RX_RESP_BUF_OVERFLOW:
+ case DMA_RX_UNEXP_NORM_RESP_ERR:
+ case TRANS_TX_OPEN_CNX_ERR_ZONE_VIOLATION:
{
- ts->stat = SAS_OPEN_TO;
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
break;
}
case DMA_RX_DATA_LEN_OVERFLOW:
{
ts->stat = SAS_DATA_OVERRUN;
+ ts->residual = 0;
+ break;
+ }
+ case DMA_RX_DATA_LEN_UNDERFLOW:
+ {
+ ts->residual = dma_rx_err_type;
+ ts->stat = SAS_DATA_UNDERRUN;
break;
}
case TRANS_TX_OPEN_FAIL_WITH_IT_NEXUS_LOSS:
case TRANS_TX_ERR_PHY_NOT_ENABLE:
case TRANS_TX_OPEN_CNX_ERR_BY_OTHER:
case TRANS_TX_OPEN_CNX_ERR_AIP_TIMEOUT:
+ case TRANS_TX_OPEN_CNX_ERR_BREAK_RCVD:
+ case TRANS_TX_OPEN_CNX_ERR_PATHWAY_BLOCKED:
+ case TRANS_TX_OPEN_CNX_ERR_OPEN_TIMEOUT:
case TRANS_TX_OPEN_RETRY_ERR_THRESHOLD_REACHED:
case TRANS_TX_ERR_WITH_BREAK_TIMEOUT:
case TRANS_TX_ERR_WITH_BREAK_REQUEST:
case TRANS_TX_ERR_WITH_BREAK_RECEVIED:
case TRANS_TX_ERR_WITH_CLOSE_TIMEOUT:
case TRANS_TX_ERR_WITH_CLOSE_NORMAL:
+ case TRANS_TX_ERR_WITH_CLOSE_PHYDISALE:
case TRANS_TX_ERR_WITH_CLOSE_DWS_TIMEOUT:
case TRANS_TX_ERR_WITH_CLOSE_COMINIT:
- case TRANS_TX_ERR_WITH_NAK_RECEVIED:
case TRANS_TX_ERR_WITH_ACK_NAK_TIMEOUT:
case TRANS_TX_ERR_WITH_CREDIT_TIMEOUT:
+ case TRANS_TX_ERR_WITH_OPEN_BY_DES_OR_OTHERS:
case TRANS_TX_ERR_WITH_WAIT_RECV_TIMEOUT:
- case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR:
case TRANS_RX_ERR_WITH_RXFRAME_HAVE_ERRPRM:
+ case TRANS_RX_ERR_WITH_RXFIS_8B10B_DISP_ERR:
case TRANS_RX_ERR_WITH_RXFIS_DECODE_ERROR:
case TRANS_RX_ERR_WITH_RXFIS_CRC_ERR:
case TRANS_RX_ERR_WITH_RXFRAME_LENGTH_OVERRUN:
case TRANS_RX_ERR_WITH_RXFIS_RX_SYNCP:
+ case TRANS_RX_ERR_WITH_LINK_BUF_OVERRUN:
+ case TRANS_RX_ERR_WITH_BREAK_TIMEOUT:
+ case TRANS_RX_ERR_WITH_BREAK_REQUEST:
+ case TRANS_RX_ERR_WITH_BREAK_RECEVIED:
case TRANS_RX_ERR_WITH_CLOSE_NORMAL:
case TRANS_RX_ERR_WITH_CLOSE_PHY_DISABLE:
case TRANS_RX_ERR_WITH_CLOSE_DWS_TIMEOUT:
@@ -1671,7 +2157,12 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
case TRANS_RX_ERR_WITH_DATA_LEN0:
case TRANS_RX_ERR_WITH_BAD_HASH:
case TRANS_RX_XRDY_WLEN_ZERO_ERR:
- case TRANS_RX_SSP_FRM_LEN_ERR:
+ case TRANS_RX_ERR_WITH_BAD_FRM_TYPE:
+ case DMA_TX_DATA_SGL_OVERFLOW:
+ case DMA_TX_UNEXP_XFER_ERR:
+ case DMA_TX_UNEXP_RETRANS_ERR:
+ case DMA_TX_XFER_LEN_OVERFLOW:
+ case DMA_TX_XFER_OFFSET_ERR:
case SIPC_RX_FIS_STATUS_ERR_BIT_VLD:
case SIPC_RX_PIO_WRSETUP_STATUS_DRQ_ERR:
case SIPC_RX_FIS_STATUS_BSY_BIT_ERR:
@@ -1679,6 +2170,8 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
case SIPC_RX_WRSETUP_LEN_ZERO_ERR:
case SIPC_RX_WRDATA_LEN_NOT_MATCH_ERR:
case SIPC_RX_SATA_UNEXP_FIS_ERR:
+ case DMA_RX_DATA_SGL_OVERFLOW:
+ case DMA_RX_DATA_OFFSET_ERR:
case DMA_RX_SATA_FRAME_TYPE_ERR:
case DMA_RX_UNEXP_RDFRAME_ERR:
case DMA_RX_PIO_DATA_LEN_ERR:
@@ -1692,8 +2185,11 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
case DMA_RX_RDSETUP_ACTIVE_ERR:
case DMA_RX_RDSETUP_ESTATUS_ERR:
case DMA_RX_UNKNOWN_FRM_ERR:
+ case TRANS_RX_SSP_FRM_LEN_ERR:
+ case TRANS_TX_OPEN_CNX_ERR_STP_RESOURCES_BUSY:
{
- ts->stat = SAS_OPEN_REJECT;
+ slot->abort = 1;
+ ts->stat = SAS_PHY_DOWN;
break;
}
default:
@@ -1711,8 +2207,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
}
static int
-slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot,
- int abort)
+slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
{
struct sas_task *task = slot->task;
struct hisi_sas_device *sas_dev;
@@ -1724,6 +2219,8 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot,
hisi_hba->complete_hdr[slot->cmplt_queue];
struct hisi_sas_complete_v2_hdr *complete_hdr =
&complete_queue[slot->cmplt_queue_slot];
+ unsigned long flags;
+ int aborted;
if (unlikely(!task || !task->lldd_task || !task->dev))
return -EINVAL;
@@ -1732,16 +2229,23 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot,
device = task->dev;
sas_dev = device->lldd_dev;
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
task->task_state_flags &=
~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
- task->task_state_flags |= SAS_TASK_STATE_DONE;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
memset(ts, 0, sizeof(*ts));
ts->resp = SAS_TASK_COMPLETE;
- if (unlikely(!sas_dev || abort)) {
- if (!sas_dev)
- dev_dbg(dev, "slot complete: port has not device\n");
+ if (unlikely(aborted)) {
+ ts->stat = SAS_ABORTED_TASK;
+ hisi_sas_slot_task_free(hisi_hba, task, slot);
+ return -1;
+ }
+
+ if (unlikely(!sas_dev)) {
+ dev_dbg(dev, "slot complete: port has no device\n");
ts->stat = SAS_PHY_DOWN;
goto out;
}
@@ -1755,16 +2259,19 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot,
goto out;
case STAT_IO_COMPLETE:
/* internal abort command complete */
- ts->stat = TMF_RESP_FUNC_COMPLETE;
+ ts->stat = TMF_RESP_FUNC_SUCC;
+ del_timer(&slot->internal_abort_timer);
goto out;
case STAT_IO_NO_DEVICE:
ts->stat = TMF_RESP_FUNC_COMPLETE;
+ del_timer(&slot->internal_abort_timer);
goto out;
case STAT_IO_NOT_VALID:
/* abort single io, controller don't find
* the io need to abort
*/
ts->stat = TMF_RESP_FUNC_FAILED;
+ del_timer(&slot->internal_abort_timer);
goto out;
default:
break;
@@ -1772,13 +2279,17 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot,
if ((complete_hdr->dw0 & CMPLT_HDR_ERX_MSK) &&
(!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))) {
+ u32 err_phase = (complete_hdr->dw0 & CMPLT_HDR_ERR_PHASE_MSK)
+ >> CMPLT_HDR_ERR_PHASE_OFF;
+
+ /* Analyse error happens on which phase TX or RX */
+ if (ERR_ON_TX_PHASE(err_phase))
+ slot_err_v2_hw(hisi_hba, task, slot, 1);
+ else if (ERR_ON_RX_PHASE(err_phase))
+ slot_err_v2_hw(hisi_hba, task, slot, 2);
- slot_err_v2_hw(hisi_hba, task, slot);
- if (unlikely(slot->abort)) {
- queue_work(hisi_hba->wq, &slot->abort_slot);
- /* immediately return and do not complete */
+ if (unlikely(slot->abort))
return ts->stat;
- }
goto out;
}
@@ -1830,7 +2341,9 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot,
}
out:
-
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ task->task_state_flags |= SAS_TASK_STATE_DONE;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
hisi_sas_slot_task_free(hisi_hba, task, slot);
sts = ts->stat;
@@ -1920,7 +2433,8 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
struct domain_device *parent_dev = device->parent;
struct hisi_sas_device *sas_dev = device->lldd_dev;
struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
- struct hisi_sas_port *port = device->port->lldd_port;
+ struct asd_sas_port *sas_port = device->port;
+ struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
u8 *buf_cmd;
int has_data = 0, rc = 0, hdr_tag = 0;
u32 dw1 = 0, dw2 = 0;
@@ -1947,7 +2461,8 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
dw1 &= ~CMD_HDR_DIR_MSK;
}
- if (0 == task->ata_task.fis.command)
+ if ((task->ata_task.fis.command == ATA_CMD_DEV_RESET) &&
+ (task->ata_task.fis.control & ATA_SRST))
dw1 |= 1 << CMD_HDR_RESET_OFF;
dw1 |= (get_ata_protocol(task->ata_task.fis.command, task->data_dir))
@@ -1990,6 +2505,40 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
return 0;
}
+static void hisi_sas_internal_abort_quirk_timeout(unsigned long data)
+{
+ struct hisi_sas_slot *slot = (struct hisi_sas_slot *)data;
+ struct hisi_sas_port *port = slot->port;
+ struct asd_sas_port *asd_sas_port;
+ struct asd_sas_phy *sas_phy;
+
+ if (!port)
+ return;
+
+ asd_sas_port = &port->sas_port;
+
+ /* Kick the hardware - send break command */
+ list_for_each_entry(sas_phy, &asd_sas_port->phy_list, port_phy_el) {
+ struct hisi_sas_phy *phy = sas_phy->lldd_phy;
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ int phy_no = sas_phy->id;
+ u32 link_dfx2;
+
+ link_dfx2 = hisi_sas_phy_read32(hisi_hba, phy_no, LINK_DFX2);
+ if ((link_dfx2 == LINK_DFX2_RCVR_HOLD_STS_MSK) ||
+ (link_dfx2 & LINK_DFX2_SEND_HOLD_STS_MSK)) {
+ u32 txid_auto;
+
+ txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no,
+ TXID_AUTO);
+ txid_auto |= TXID_AUTO_CTB_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
+ txid_auto);
+ return;
+ }
+ }
+}
+
static int prep_abort_v2_hw(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot,
int device_id, int abort_flag, int tag_to_abort)
@@ -1998,6 +2547,13 @@ static int prep_abort_v2_hw(struct hisi_hba *hisi_hba,
struct domain_device *dev = task->dev;
struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
struct hisi_sas_port *port = slot->port;
+ struct timer_list *timer = &slot->internal_abort_timer;
+
+ /* setup the quirk timer */
+ setup_timer(timer, hisi_sas_internal_abort_quirk_timeout,
+ (unsigned long)slot);
+ /* Set the timeout to 10ms less than internal abort timeout */
+ mod_timer(timer, jiffies + msecs_to_jiffies(100));
/* dw0 */
hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/
@@ -2018,8 +2574,8 @@ static int prep_abort_v2_hw(struct hisi_hba *hisi_hba,
static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
{
- int i, res = 0;
- u32 context, port_id, link_rate, hard_phy_linkrate;
+ int i, res = IRQ_HANDLED;
+ u32 port_id, link_rate, hard_phy_linkrate;
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
struct asd_sas_phy *sas_phy = &phy->sas_phy;
struct device *dev = &hisi_hba->pdev->dev;
@@ -2028,9 +2584,7 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
- /* Check for SATA dev */
- context = hisi_sas_read32(hisi_hba, PHY_CONTEXT);
- if (context & (1 << phy_no))
+ if (is_sata_phy_v2_hw(hisi_hba, phy_no))
goto end;
if (phy_no == 8) {
@@ -2106,7 +2660,6 @@ static bool check_any_wideports_v2_hw(struct hisi_hba *hisi_hba)
static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
{
- int res = 0;
u32 phy_state, sl_ctrl, txid_auto;
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
struct hisi_sas_port *port = phy->port;
@@ -2131,7 +2684,7 @@ static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_NOT_RDY_MSK);
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 0);
- return res;
+ return IRQ_HANDLED;
}
static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
@@ -2139,35 +2692,58 @@ static irqreturn_t int_phy_updown_v2_hw(int irq_no, void *p)
struct hisi_hba *hisi_hba = p;
u32 irq_msk;
int phy_no = 0;
- irqreturn_t res = IRQ_HANDLED;
irq_msk = (hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO)
>> HGC_INVLD_DQE_INFO_FB_CH0_OFF) & 0x1ff;
while (irq_msk) {
if (irq_msk & 1) {
- u32 irq_value = hisi_sas_phy_read32(hisi_hba, phy_no,
- CHL_INT0);
+ u32 reg_value = hisi_sas_phy_read32(hisi_hba, phy_no,
+ CHL_INT0);
- if (irq_value & CHL_INT0_SL_PHY_ENABLE_MSK)
+ switch (reg_value & (CHL_INT0_NOT_RDY_MSK |
+ CHL_INT0_SL_PHY_ENABLE_MSK)) {
+
+ case CHL_INT0_SL_PHY_ENABLE_MSK:
/* phy up */
- if (phy_up_v2_hw(phy_no, hisi_hba)) {
- res = IRQ_NONE;
- goto end;
- }
+ if (phy_up_v2_hw(phy_no, hisi_hba) ==
+ IRQ_NONE)
+ return IRQ_NONE;
+ break;
- if (irq_value & CHL_INT0_NOT_RDY_MSK)
+ case CHL_INT0_NOT_RDY_MSK:
/* phy down */
- if (phy_down_v2_hw(phy_no, hisi_hba)) {
- res = IRQ_NONE;
- goto end;
+ if (phy_down_v2_hw(phy_no, hisi_hba) ==
+ IRQ_NONE)
+ return IRQ_NONE;
+ break;
+
+ case (CHL_INT0_NOT_RDY_MSK |
+ CHL_INT0_SL_PHY_ENABLE_MSK):
+ reg_value = hisi_sas_read32(hisi_hba,
+ PHY_STATE);
+ if (reg_value & BIT(phy_no)) {
+ /* phy up */
+ if (phy_up_v2_hw(phy_no, hisi_hba) ==
+ IRQ_NONE)
+ return IRQ_NONE;
+ } else {
+ /* phy down */
+ if (phy_down_v2_hw(phy_no, hisi_hba) ==
+ IRQ_NONE)
+ return IRQ_NONE;
}
+ break;
+
+ default:
+ break;
+ }
+
}
irq_msk >>= 1;
phy_no++;
}
-end:
- return res;
+ return IRQ_HANDLED;
}
static void phy_bcast_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
@@ -2342,94 +2918,105 @@ static void multi_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba,
if (irq_value & BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF)) {
reg_val = hisi_sas_read32(hisi_hba, HGC_DQE_ECC_ADDR);
- panic("%s: hgc_dqe_accbad_intr (0x%x) found: \
+ dev_warn(dev, "hgc_dqe_accbad_intr (0x%x) found: \
Ram address is 0x%08X\n",
- dev_name(dev), irq_value,
+ irq_value,
(reg_val & HGC_DQE_ECC_MB_ADDR_MSK) >>
HGC_DQE_ECC_MB_ADDR_OFF);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
if (irq_value & BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF)) {
reg_val = hisi_sas_read32(hisi_hba, HGC_IOST_ECC_ADDR);
- panic("%s: hgc_iost_accbad_intr (0x%x) found: \
+ dev_warn(dev, "hgc_iost_accbad_intr (0x%x) found: \
Ram address is 0x%08X\n",
- dev_name(dev), irq_value,
+ irq_value,
(reg_val & HGC_IOST_ECC_MB_ADDR_MSK) >>
HGC_IOST_ECC_MB_ADDR_OFF);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
if (irq_value & BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF)) {
reg_val = hisi_sas_read32(hisi_hba, HGC_ITCT_ECC_ADDR);
- panic("%s: hgc_itct_accbad_intr (0x%x) found: \
+ dev_warn(dev,"hgc_itct_accbad_intr (0x%x) found: \
Ram address is 0x%08X\n",
- dev_name(dev), irq_value,
+ irq_value,
(reg_val & HGC_ITCT_ECC_MB_ADDR_MSK) >>
HGC_ITCT_ECC_MB_ADDR_OFF);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
if (irq_value & BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF)) {
reg_val = hisi_sas_read32(hisi_hba, HGC_LM_DFX_STATUS2);
- panic("%s: hgc_iostl_accbad_intr (0x%x) found: \
+ dev_warn(dev, "hgc_iostl_accbad_intr (0x%x) found: \
memory address is 0x%08X\n",
- dev_name(dev), irq_value,
+ irq_value,
(reg_val & HGC_LM_DFX_STATUS2_IOSTLIST_MSK) >>
HGC_LM_DFX_STATUS2_IOSTLIST_OFF);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
if (irq_value & BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF)) {
reg_val = hisi_sas_read32(hisi_hba, HGC_LM_DFX_STATUS2);
- panic("%s: hgc_itctl_accbad_intr (0x%x) found: \
+ dev_warn(dev, "hgc_itctl_accbad_intr (0x%x) found: \
memory address is 0x%08X\n",
- dev_name(dev), irq_value,
+ irq_value,
(reg_val & HGC_LM_DFX_STATUS2_ITCTLIST_MSK) >>
HGC_LM_DFX_STATUS2_ITCTLIST_OFF);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
if (irq_value & BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF)) {
reg_val = hisi_sas_read32(hisi_hba, HGC_CQE_ECC_ADDR);
- panic("%s: hgc_cqe_accbad_intr (0x%x) found: \
+ dev_warn(dev, "hgc_cqe_accbad_intr (0x%x) found: \
Ram address is 0x%08X\n",
- dev_name(dev), irq_value,
+ irq_value,
(reg_val & HGC_CQE_ECC_MB_ADDR_MSK) >>
HGC_CQE_ECC_MB_ADDR_OFF);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF)) {
reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14);
- panic("%s: rxm_mem0_accbad_intr (0x%x) found: \
+ dev_warn(dev, "rxm_mem0_accbad_intr (0x%x) found: \
memory address is 0x%08X\n",
- dev_name(dev), irq_value,
+ irq_value,
(reg_val & HGC_RXM_DFX_STATUS14_MEM0_MSK) >>
HGC_RXM_DFX_STATUS14_MEM0_OFF);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF)) {
reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14);
- panic("%s: rxm_mem1_accbad_intr (0x%x) found: \
+ dev_warn(dev, "rxm_mem1_accbad_intr (0x%x) found: \
memory address is 0x%08X\n",
- dev_name(dev), irq_value,
+ irq_value,
(reg_val & HGC_RXM_DFX_STATUS14_MEM1_MSK) >>
HGC_RXM_DFX_STATUS14_MEM1_OFF);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF)) {
reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS14);
- panic("%s: rxm_mem2_accbad_intr (0x%x) found: \
+ dev_warn(dev, "rxm_mem2_accbad_intr (0x%x) found: \
memory address is 0x%08X\n",
- dev_name(dev), irq_value,
+ irq_value,
(reg_val & HGC_RXM_DFX_STATUS14_MEM2_MSK) >>
HGC_RXM_DFX_STATUS14_MEM2_OFF);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
if (irq_value & BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF)) {
reg_val = hisi_sas_read32(hisi_hba, HGC_RXM_DFX_STATUS15);
- panic("%s: rxm_mem3_accbad_intr (0x%x) found: \
+ dev_warn(dev, "rxm_mem3_accbad_intr (0x%x) found: \
memory address is 0x%08X\n",
- dev_name(dev), irq_value,
+ irq_value,
(reg_val & HGC_RXM_DFX_STATUS15_MEM3_MSK) >>
HGC_RXM_DFX_STATUS15_MEM3_OFF);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
+ return;
}
static irqreturn_t fatal_ecc_int_v2_hw(int irq_no, void *p)
@@ -2487,23 +3074,27 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
if (irq_value & BIT(ENT_INT_SRC3_WP_DEPTH_OFF)) {
hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
1 << ENT_INT_SRC3_WP_DEPTH_OFF);
- panic("%s: write pointer and depth error (0x%x) \
+ dev_warn(dev, "write pointer and depth error (0x%x) \
found!\n",
- dev_name(dev), irq_value);
+ irq_value);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
if (irq_value & BIT(ENT_INT_SRC3_IPTT_SLOT_NOMATCH_OFF)) {
hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
1 <<
ENT_INT_SRC3_IPTT_SLOT_NOMATCH_OFF);
- panic("%s: iptt no match slot error (0x%x) found!\n",
- dev_name(dev), irq_value);
+ dev_warn(dev, "iptt no match slot error (0x%x) found!\n",
+ irq_value);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
- if (irq_value & BIT(ENT_INT_SRC3_RP_DEPTH_OFF))
- panic("%s: read pointer and depth error (0x%x) \
+ if (irq_value & BIT(ENT_INT_SRC3_RP_DEPTH_OFF)) {
+ dev_warn(dev, "read pointer and depth error (0x%x) \
found!\n",
- dev_name(dev), irq_value);
+ irq_value);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+ }
if (irq_value & BIT(ENT_INT_SRC3_AXI_OFF)) {
int i;
@@ -2514,10 +3105,11 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
HGC_AXI_FIFO_ERR_INFO);
for (i = 0; i < AXI_ERR_NR; i++) {
- if (err_value & BIT(i))
- panic("%s: %s (0x%x) found!\n",
- dev_name(dev),
+ if (err_value & BIT(i)) {
+ dev_warn(dev, "%s (0x%x) found!\n",
axi_err_info[i], irq_value);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+ }
}
}
@@ -2530,10 +3122,11 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
HGC_AXI_FIFO_ERR_INFO);
for (i = 0; i < FIFO_ERR_NR; i++) {
- if (err_value & BIT(AXI_ERR_NR + i))
- panic("%s: %s (0x%x) found!\n",
- dev_name(dev),
+ if (err_value & BIT(AXI_ERR_NR + i)) {
+ dev_warn(dev, "%s (0x%x) found!\n",
fifo_err_info[i], irq_value);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+ }
}
}
@@ -2541,15 +3134,17 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
if (irq_value & BIT(ENT_INT_SRC3_LM_OFF)) {
hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
1 << ENT_INT_SRC3_LM_OFF);
- panic("%s: LM add/fetch list error (0x%x) found!\n",
- dev_name(dev), irq_value);
+ dev_warn(dev, "LM add/fetch list error (0x%x) found!\n",
+ irq_value);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
if (irq_value & BIT(ENT_INT_SRC3_ABT_OFF)) {
hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
1 << ENT_INT_SRC3_ABT_OFF);
- panic("%s: SAS_HGC_ABT fetch LM list error (0x%x) found!\n",
- dev_name(dev), irq_value);
+ dev_warn(dev, "SAS_HGC_ABT fetch LM list error (0x%x) found!\n",
+ irq_value);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
}
@@ -2568,6 +3163,9 @@ static void cq_tasklet_v2_hw(unsigned long val)
u32 rd_point = cq->rd_point, wr_point, dev_id;
int queue = cq->id;
+ if (unlikely(hisi_hba->reject_stp_links_msk))
+ phys_try_accept_stp_links_v2_hw(hisi_hba);
+
complete_queue = hisi_hba->complete_hdr[queue];
spin_lock(&hisi_hba->lock);
@@ -2600,7 +3198,7 @@ static void cq_tasklet_v2_hw(unsigned long val)
slot = &hisi_hba->slot_info[iptt];
slot->cmplt_queue_slot = rd_point;
slot->cmplt_queue = queue;
- slot_complete_v2_hw(hisi_hba, slot, 0);
+ slot_complete_v2_hw(hisi_hba, slot);
act_tmp &= ~(1 << ncq_tag_count);
ncq_tag_count = ffs(act_tmp);
@@ -2610,7 +3208,7 @@ static void cq_tasklet_v2_hw(unsigned long val)
slot = &hisi_hba->slot_info[iptt];
slot->cmplt_queue_slot = rd_point;
slot->cmplt_queue = queue;
- slot_complete_v2_hw(hisi_hba, slot, 0);
+ slot_complete_v2_hw(hisi_hba, slot);
}
if (++rd_point >= HISI_SAS_QUEUE_SLOTS)
@@ -2842,6 +3440,8 @@ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba)
{
int rc;
+ memset(hisi_hba->sata_dev_bitmap, 0, sizeof(hisi_hba->sata_dev_bitmap));
+
rc = hw_init_v2_hw(hisi_hba);
if (rc)
return rc;
@@ -2850,7 +3450,88 @@ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba)
if (rc)
return rc;
- phys_init_v2_hw(hisi_hba);
+ return 0;
+}
+
+static void interrupt_disable_v2_hw(struct hisi_hba *hisi_hba)
+{
+ struct platform_device *pdev = hisi_hba->pdev;
+ int i;
+
+ for (i = 0; i < hisi_hba->queue_count; i++)
+ hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK + 0x4 * i, 0x1);
+
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xffffffff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xffffffff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffffffff);
+ hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0xffffffff);
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xffffffff);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0xffffffff);
+ }
+
+ for (i = 0; i < 128; i++)
+ synchronize_irq(platform_get_irq(pdev, i));
+}
+
+static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 old_state, state;
+ int rc, cnt;
+ int phy_no;
+
+ old_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+
+ interrupt_disable_v2_hw(hisi_hba);
+ hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
+
+ stop_phys_v2_hw(hisi_hba);
+
+ mdelay(10);
+
+ hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE + AM_CTRL_GLOBAL, 0x1);
+
+ /* wait until bus idle */
+ cnt = 0;
+ while (1) {
+ u32 status = hisi_sas_read32_relaxed(hisi_hba,
+ AXI_MASTER_CFG_BASE + AM_CURR_TRANS_RETURN);
+
+ if (status == 0x3)
+ break;
+
+ udelay(10);
+ if (cnt++ > 10) {
+ dev_info(dev, "wait axi bus state to idle timeout!\n");
+ return -1;
+ }
+ }
+
+ hisi_sas_init_mem(hisi_hba);
+
+ rc = hw_init_v2_hw(hisi_hba);
+ if (rc)
+ return rc;
+
+ phys_reject_stp_links_v2_hw(hisi_hba);
+
+ /* Re-enable the PHYs */
+ for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+ if (sas_phy->enabled)
+ start_phy_v2_hw(hisi_hba, phy_no);
+ }
+
+ /* Wait for the PHYs to come up and read the PHY state */
+ msleep(1000);
+
+ state = hisi_sas_read32(hisi_hba, PHY_STATE);
+
+ hisi_sas_rescan_topology(hisi_hba, old_state, state);
return 0;
}
@@ -2870,6 +3551,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = {
.get_free_slot = get_free_slot_v2_hw,
.start_delivery = start_delivery_v2_hw,
.slot_complete = slot_complete_v2_hw,
+ .phys_init = phys_init_v2_hw,
.phy_enable = enable_phy_v2_hw,
.phy_disable = disable_phy_v2_hw,
.phy_hard_reset = phy_hard_reset_v2_hw,
@@ -2877,6 +3559,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = {
.phy_get_max_linkrate = phy_get_max_linkrate_v2_hw,
.max_command_entries = HISI_SAS_COMMAND_ENTRIES_V2_HW,
.complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr),
+ .soft_reset = soft_reset_v2_hw,
};
static int hisi_sas_v2_probe(struct platform_device *pdev)