summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/hisi_sas/hisi_sas_v3_hw.c')
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v3_hw.c384
1 files changed, 274 insertions, 110 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 5f0f6df11adf..a2debe0c8185 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -71,6 +71,7 @@
#define HGC_DQE_ECC_MB_ADDR_OFF 16
#define HGC_DQE_ECC_MB_ADDR_MSK (0xfff << HGC_DQE_ECC_MB_ADDR_OFF)
#define CHNL_INT_STATUS 0x148
+#define TAB_DFX 0x14c
#define HGC_ITCT_ECC_ADDR 0x150
#define HGC_ITCT_ECC_1B_ADDR_OFF 0
#define HGC_ITCT_ECC_1B_ADDR_MSK (0x3ff << \
@@ -83,6 +84,7 @@
#define AXI_ERR_INFO_MSK (0xff << AXI_ERR_INFO_OFF)
#define FIFO_ERR_INFO_OFF 8
#define FIFO_ERR_INFO_MSK (0xff << FIFO_ERR_INFO_OFF)
+#define TAB_RD_TYPE 0x15c
#define INT_COAL_EN 0x19c
#define OQ_INT_COAL_TIME 0x1a0
#define OQ_INT_COAL_CNT 0x1a4
@@ -189,12 +191,30 @@
#define PHY_CFG_PHY_RST_OFF 3
#define PHY_CFG_PHY_RST_MSK (0x1 << PHY_CFG_PHY_RST_OFF)
#define PROG_PHY_LINK_RATE (PORT_BASE + 0x8)
+#define CFG_PROG_PHY_LINK_RATE_OFF 8
+#define CFG_PROG_PHY_LINK_RATE_MSK (0xf << CFG_PROG_PHY_LINK_RATE_OFF)
#define PHY_CTRL (PORT_BASE + 0x14)
#define PHY_CTRL_RESET_OFF 0
#define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF)
#define CMD_HDR_PIR_OFF 8
#define CMD_HDR_PIR_MSK (0x1 << CMD_HDR_PIR_OFF)
#define SERDES_CFG (PORT_BASE + 0x1c)
+#define CFG_ALOS_CHK_DISABLE_OFF 9
+#define CFG_ALOS_CHK_DISABLE_MSK (0x1 << CFG_ALOS_CHK_DISABLE_OFF)
+#define SAS_PHY_BIST_CTRL (PORT_BASE + 0x2c)
+#define CFG_BIST_MODE_SEL_OFF 0
+#define CFG_BIST_MODE_SEL_MSK (0xf << CFG_BIST_MODE_SEL_OFF)
+#define CFG_LOOP_TEST_MODE_OFF 14
+#define CFG_LOOP_TEST_MODE_MSK (0x3 << CFG_LOOP_TEST_MODE_OFF)
+#define CFG_RX_BIST_EN_OFF 16
+#define CFG_RX_BIST_EN_MSK (0x1 << CFG_RX_BIST_EN_OFF)
+#define CFG_TX_BIST_EN_OFF 17
+#define CFG_TX_BIST_EN_MSK (0x1 << CFG_TX_BIST_EN_OFF)
+#define CFG_BIST_TEST_OFF 18
+#define CFG_BIST_TEST_MSK (0x1 << CFG_BIST_TEST_OFF)
+#define SAS_PHY_BIST_CODE (PORT_BASE + 0x30)
+#define SAS_PHY_BIST_CODE1 (PORT_BASE + 0x34)
+#define SAS_BIST_ERR_CNT (PORT_BASE + 0x38)
#define SL_CFG (PORT_BASE + 0x84)
#define AIP_LIMIT (PORT_BASE + 0x90)
#define SL_CONTROL (PORT_BASE + 0x94)
@@ -475,6 +495,13 @@ struct hisi_sas_err_record_v3 {
#define BASE_VECTORS_V3_HW 16
#define MIN_AFFINE_VECTORS_V3_HW (BASE_VECTORS_V3_HW + 1)
+#define CHNL_INT_STS_MSK 0xeeeeeeee
+#define CHNL_INT_STS_PHY_MSK 0xe
+#define CHNL_INT_STS_INT0_MSK BIT(1)
+#define CHNL_INT_STS_INT1_MSK BIT(2)
+#define CHNL_INT_STS_INT2_MSK BIT(3)
+#define CHNL_WIDTH 4
+
enum {
DSM_FUNC_ERR_HANDLE_MSI = 0,
};
@@ -499,13 +526,6 @@ static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
return readl(regs);
}
-static u32 hisi_sas_read32_relaxed(struct hisi_hba *hisi_hba, u32 off)
-{
- void __iomem *regs = hisi_hba->regs + off;
-
- return readl_relaxed(regs);
-}
-
static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val)
{
void __iomem *regs = hisi_hba->regs + off;
@@ -782,13 +802,14 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba,
(0x1ULL << ITCT_HDR_RTOLT_OFF));
}
-static void clear_itct_v3_hw(struct hisi_hba *hisi_hba,
- struct hisi_sas_device *sas_dev)
+static int clear_itct_v3_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
{
DECLARE_COMPLETION_ONSTACK(completion);
u64 dev_id = sas_dev->device_id;
struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
+ struct device *dev = hisi_hba->dev;
sas_dev->completion = &completion;
@@ -801,8 +822,14 @@ static void clear_itct_v3_hw(struct hisi_hba *hisi_hba,
reg_val = ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val);
- wait_for_completion(sas_dev->completion);
+ if (!wait_for_completion_timeout(sas_dev->completion,
+ CLEAR_ITCT_TIMEOUT * HZ)) {
+ dev_warn(dev, "failed to clear ITCT\n");
+ return -ETIMEDOUT;
+ }
+
memset(itct, 0, sizeof(struct hisi_sas_itct));
+ return 0;
}
static void dereg_device_v3_hw(struct hisi_hba *hisi_hba,
@@ -1006,31 +1033,6 @@ static int get_wideport_bitmap_v3_hw(struct hisi_hba *hisi_hba, int port_id)
return bitmap;
}
-/**
- * The callpath to this function and upto writing the write
- * queue pointer should be safe from interruption.
- */
-static int
-get_free_slot_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq)
-{
- struct device *dev = hisi_hba->dev;
- int queue = dq->id;
- u32 r, w;
-
- w = dq->wr_point;
- r = hisi_sas_read32_relaxed(hisi_hba,
- DLVRY_Q_0_RD_PTR + (queue * 0x14));
- if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
- dev_warn(dev, "full queue=%d r=%d w=%d\n",
- queue, r, w);
- return -EAGAIN;
- }
-
- dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS;
-
- return w;
-}
-
static void start_delivery_v3_hw(struct hisi_sas_dq *dq)
{
struct hisi_hba *hisi_hba = dq->hisi_hba;
@@ -1386,7 +1388,10 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba,
hdr->dw1 = cpu_to_le32(dw1);
/* dw2 */
- if (task->ata_task.use_ncq && hisi_sas_get_ncq_tag(task, &hdr_tag)) {
+ if (task->ata_task.use_ncq) {
+ struct ata_queued_cmd *qc = task->uldd_task;
+
+ hdr_tag = qc->tag;
task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF;
}
@@ -1551,6 +1556,8 @@ static irqreturn_t phy_down_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
u32 phy_state, sl_ctrl, txid_auto;
struct device *dev = hisi_hba->dev;
+ atomic_inc(&phy->down_cnt);
+
del_timer(&phy->timer);
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1);
@@ -1819,19 +1826,19 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
int phy_no = 0;
irq_msk = hisi_sas_read32(hisi_hba, CHNL_INT_STATUS)
- & 0xeeeeeeee;
+ & CHNL_INT_STS_MSK;
while (irq_msk) {
- if (irq_msk & (2 << (phy_no * 4)))
+ if (irq_msk & (CHNL_INT_STS_INT0_MSK << (phy_no * CHNL_WIDTH)))
handle_chl_int0_v3_hw(hisi_hba, phy_no);
- if (irq_msk & (4 << (phy_no * 4)))
+ if (irq_msk & (CHNL_INT_STS_INT1_MSK << (phy_no * CHNL_WIDTH)))
handle_chl_int1_v3_hw(hisi_hba, phy_no);
- if (irq_msk & (8 << (phy_no * 4)))
+ if (irq_msk & (CHNL_INT_STS_INT2_MSK << (phy_no * CHNL_WIDTH)))
handle_chl_int2_v3_hw(hisi_hba, phy_no);
- irq_msk &= ~(0xe << (phy_no * 4));
+ irq_msk &= ~(CHNL_INT_STS_PHY_MSK << (phy_no * CHNL_WIDTH));
phy_no++;
}
@@ -1944,7 +1951,7 @@ static void fatal_ecc_int_v3_hw(struct hisi_hba *hisi_hba)
u32 irq_value, irq_msk;
irq_msk = hisi_sas_read32(hisi_hba, SAS_ECC_INTR_MSK);
- hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, irq_msk | 0xffffffff);
+ hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0xffffffff);
irq_value = hisi_sas_read32(hisi_hba, SAS_ECC_INTR);
if (irq_value)
@@ -2220,7 +2227,7 @@ slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
slot_err_v3_hw(hisi_hba, task, slot);
if (ts->stat != SAS_DATA_UNDERRUN)
- dev_info(dev, "erroneous completion iptt=%d task=%p dev id=%d CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n",
+ 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",
slot->idx, task, sas_dev->device_id,
dw0, dw1, complete_hdr->act, dw3,
error_info[0], error_info[1],
@@ -2241,20 +2248,16 @@ slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
}
case SAS_PROTOCOL_SMP: {
struct scatterlist *sg_resp = &task->smp_task.smp_resp;
- void *to;
+ void *to = page_address(sg_page(sg_resp));
ts->stat = SAM_STAT_GOOD;
- to = kmap_atomic(sg_page(sg_resp));
- dma_unmap_sg(dev, &task->smp_task.smp_resp, 1,
- DMA_FROM_DEVICE);
dma_unmap_sg(dev, &task->smp_task.smp_req, 1,
DMA_TO_DEVICE);
memcpy(to + sg_resp->offset,
hisi_sas_status_buf_addr_mem(slot) +
sizeof(struct hisi_sas_err_record),
- sg_dma_len(sg_resp));
- kunmap_atomic(to);
+ sg_resp->length);
break;
}
case SAS_PROTOCOL_SATA:
@@ -2279,7 +2282,7 @@ out:
spin_lock_irqsave(&task->task_state_lock, flags);
if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
spin_unlock_irqrestore(&task->task_state_lock, flags);
- dev_info(dev, "slot complete: task(%p) aborted\n", task);
+ dev_info(dev, "slot complete: task(%pK) aborted\n", task);
return SAS_ABORTED_TASK;
}
task->task_state_flags |= SAS_TASK_STATE_DONE;
@@ -2290,7 +2293,7 @@ out:
spin_lock_irqsave(&device->done_lock, flags);
if (test_bit(SAS_HA_FROZEN, &ha->state)) {
spin_unlock_irqrestore(&device->done_lock, flags);
- dev_info(dev, "slot complete: task(%p) ignored\n ",
+ dev_info(dev, "slot complete: task(%pK) ignored\n ",
task);
return sts;
}
@@ -2303,9 +2306,9 @@ out:
return sts;
}
-static void cq_tasklet_v3_hw(unsigned long val)
+static irqreturn_t cq_thread_v3_hw(int irq_no, void *p)
{
- struct hisi_sas_cq *cq = (struct hisi_sas_cq *)val;
+ struct hisi_sas_cq *cq = p;
struct hisi_hba *hisi_hba = cq->hisi_hba;
struct hisi_sas_slot *slot;
struct hisi_sas_complete_v3_hdr *complete_queue;
@@ -2342,6 +2345,8 @@ static void cq_tasklet_v3_hw(unsigned long val)
/* update rd_point */
cq->rd_point = rd_point;
hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
+
+ return IRQ_HANDLED;
}
static irqreturn_t cq_interrupt_v3_hw(int irq_no, void *p)
@@ -2352,9 +2357,7 @@ static irqreturn_t cq_interrupt_v3_hw(int irq_no, void *p)
hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
- tasklet_schedule(&cq->tasklet);
-
- return IRQ_HANDLED;
+ return IRQ_WAKE_THREAD;
}
static void setup_reply_map_v3_hw(struct hisi_hba *hisi_hba, int nvecs)
@@ -2369,7 +2372,7 @@ static void setup_reply_map_v3_hw(struct hisi_hba *hisi_hba, int nvecs)
BASE_VECTORS_V3_HW);
if (!mask)
goto fallback;
- cq->pci_irq_mask = mask;
+ cq->irq_mask = mask;
for_each_cpu(cpu, mask)
hisi_hba->reply_map[cpu] = queue;
}
@@ -2385,8 +2388,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
{
struct device *dev = hisi_hba->dev;
struct pci_dev *pdev = hisi_hba->pci_dev;
- int vectors, rc;
- int i, k;
+ int vectors, rc, i;
int max_msi = HISI_SAS_MSI_COUNT_V3_HW, min_msi;
if (auto_affine_msi_experimental) {
@@ -2394,6 +2396,8 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
.pre_vectors = BASE_VECTORS_V3_HW,
};
+ dev_info(dev, "Enable MSI auto-affinity\n");
+
min_msi = MIN_AFFINE_VECTORS_V3_HW;
hisi_hba->reply_map = devm_kcalloc(dev, nr_cpu_ids,
@@ -2434,7 +2438,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
if (rc) {
dev_err(dev, "could not request chnl interrupt, rc=%d\n", rc);
rc = -ENOENT;
- goto free_phy_irq;
+ goto free_irq_vectors;
}
rc = devm_request_irq(dev, pci_irq_vector(pdev, 11),
@@ -2443,43 +2447,34 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
if (rc) {
dev_err(dev, "could not request fatal interrupt, rc=%d\n", rc);
rc = -ENOENT;
- goto free_chnl_interrupt;
+ goto free_irq_vectors;
}
- /* Init tasklets for cq only */
+ if (hisi_sas_intr_conv)
+ dev_info(dev, "Enable interrupt converge\n");
+
for (i = 0; i < hisi_hba->cq_nvecs; i++) {
struct hisi_sas_cq *cq = &hisi_hba->cq[i];
- struct tasklet_struct *t = &cq->tasklet;
int nr = hisi_sas_intr_conv ? 16 : 16 + i;
- unsigned long irqflags = hisi_sas_intr_conv ? IRQF_SHARED : 0;
-
- rc = devm_request_irq(dev, pci_irq_vector(pdev, nr),
- cq_interrupt_v3_hw, irqflags,
+ unsigned long irqflags = hisi_sas_intr_conv ? IRQF_SHARED :
+ IRQF_ONESHOT;
+
+ cq->irq_no = pci_irq_vector(pdev, nr);
+ rc = devm_request_threaded_irq(dev, cq->irq_no,
+ cq_interrupt_v3_hw,
+ cq_thread_v3_hw,
+ irqflags,
DRV_NAME " cq", cq);
if (rc) {
dev_err(dev, "could not request cq%d interrupt, rc=%d\n",
i, rc);
rc = -ENOENT;
- goto free_cq_irqs;
+ goto free_irq_vectors;
}
-
- tasklet_init(t, cq_tasklet_v3_hw, (unsigned long)cq);
}
return 0;
-free_cq_irqs:
- for (k = 0; k < i; k++) {
- struct hisi_sas_cq *cq = &hisi_hba->cq[k];
- int nr = hisi_sas_intr_conv ? 16 : 16 + k;
-
- free_irq(pci_irq_vector(pdev, nr), cq);
- }
- free_irq(pci_irq_vector(pdev, 11), hisi_hba);
-free_chnl_interrupt:
- free_irq(pci_irq_vector(pdev, 2), hisi_hba);
-free_phy_irq:
- free_irq(pci_irq_vector(pdev, 1), hisi_hba);
free_irq_vectors:
pci_free_irq_vectors(pdev);
return rc;
@@ -2551,7 +2546,6 @@ static int disable_host_v3_hw(struct hisi_hba *hisi_hba)
interrupt_disable_v3_hw(hisi_hba);
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
- hisi_sas_kill_tasklets(hisi_hba);
hisi_sas_stop_phys(hisi_hba);
@@ -2620,8 +2614,8 @@ static int write_gpio_v3_hw(struct hisi_hba *hisi_hba, u8 reg_type,
return 0;
}
-static int wait_cmds_complete_timeout_v3_hw(struct hisi_hba *hisi_hba,
- int delay_ms, int timeout_ms)
+static void wait_cmds_complete_timeout_v3_hw(struct hisi_hba *hisi_hba,
+ int delay_ms, int timeout_ms)
{
struct device *dev = hisi_hba->dev;
int entries, entries_old = 0, time;
@@ -2635,12 +2629,12 @@ static int wait_cmds_complete_timeout_v3_hw(struct hisi_hba *hisi_hba,
msleep(delay_ms);
}
- if (time >= timeout_ms)
- return -ETIMEDOUT;
+ if (time >= timeout_ms) {
+ dev_dbg(dev, "Wait commands complete timeout!\n");
+ return;
+ }
dev_dbg(dev, "wait commands complete %dms\n", time);
-
- return 0;
}
static ssize_t intr_conv_v3_hw_show(struct device *dev,
@@ -2887,18 +2881,47 @@ static const struct hisi_sas_debugfs_reg debugfs_global_reg = {
.read_global_reg = hisi_sas_read32,
};
+static const struct hisi_sas_debugfs_reg_lu debugfs_axi_reg_lu[] = {
+ HISI_SAS_DEBUGFS_REG(AM_CFG_MAX_TRANS),
+ HISI_SAS_DEBUGFS_REG(AM_CFG_SINGLE_PORT_MAX_TRANS),
+ HISI_SAS_DEBUGFS_REG(AXI_CFG),
+ HISI_SAS_DEBUGFS_REG(AM_ROB_ECC_ERR_ADDR),
+ {}
+};
+
+static const struct hisi_sas_debugfs_reg debugfs_axi_reg = {
+ .lu = debugfs_axi_reg_lu,
+ .count = 0x61,
+ .base_off = AXI_MASTER_CFG_BASE,
+ .read_global_reg = hisi_sas_read32,
+};
+
+static const struct hisi_sas_debugfs_reg_lu debugfs_ras_reg_lu[] = {
+ HISI_SAS_DEBUGFS_REG(SAS_RAS_INTR1),
+ HISI_SAS_DEBUGFS_REG(SAS_RAS_INTR0_MASK),
+ HISI_SAS_DEBUGFS_REG(SAS_RAS_INTR1_MASK),
+ HISI_SAS_DEBUGFS_REG(CFG_SAS_RAS_INTR_MASK),
+ HISI_SAS_DEBUGFS_REG(SAS_RAS_INTR2),
+ HISI_SAS_DEBUGFS_REG(SAS_RAS_INTR2_MASK),
+ {}
+};
+
+static const struct hisi_sas_debugfs_reg debugfs_ras_reg = {
+ .lu = debugfs_ras_reg_lu,
+ .count = 0x10,
+ .base_off = RAS_BASE,
+ .read_global_reg = hisi_sas_read32,
+};
+
static void debugfs_snapshot_prepare_v3_hw(struct hisi_hba *hisi_hba)
{
- struct device *dev = hisi_hba->dev;
-
set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0);
- if (wait_cmds_complete_timeout_v3_hw(hisi_hba, 100, 5000) == -ETIMEDOUT)
- dev_dbg(dev, "Wait commands complete timeout!\n");
+ wait_cmds_complete_timeout_v3_hw(hisi_hba, 100, 5000);
- hisi_sas_kill_tasklets(hisi_hba);
+ hisi_sas_sync_irqs(hisi_hba);
}
static void debugfs_snapshot_restore_v3_hw(struct hisi_hba *hisi_hba)
@@ -2909,6 +2932,142 @@ static void debugfs_snapshot_restore_v3_hw(struct hisi_hba *hisi_hba)
clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
}
+static void read_iost_itct_cache_v3_hw(struct hisi_hba *hisi_hba,
+ enum hisi_sas_debugfs_cache_type type,
+ u32 *cache)
+{
+ u32 cache_dw_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ *
+ HISI_SAS_IOST_ITCT_CACHE_NUM;
+ u32 *buf = cache;
+ u32 i, val;
+
+ hisi_sas_write32(hisi_hba, TAB_RD_TYPE, type);
+
+ for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_DW_SZ; i++) {
+ val = hisi_sas_read32(hisi_hba, TAB_DFX);
+ if (val == 0xffffffff)
+ break;
+ }
+
+ if (val != 0xffffffff) {
+ pr_err("Issue occur when reading IOST/ITCT cache!\n");
+ return;
+ }
+
+ memset(buf, 0, cache_dw_size * 4);
+ buf[0] = val;
+
+ for (i = 1; i < cache_dw_size; i++)
+ buf[i] = hisi_sas_read32(hisi_hba, TAB_DFX);
+}
+
+static void hisi_sas_bist_test_prep_v3_hw(struct hisi_hba *hisi_hba)
+{
+ u32 reg_val;
+ int phy_id = hisi_hba->debugfs_bist_phy_no;
+
+ /* disable PHY */
+ hisi_sas_phy_enable(hisi_hba, phy_id, 0);
+
+ /* disable ALOS */
+ reg_val = hisi_sas_phy_read32(hisi_hba, phy_id, SERDES_CFG);
+ reg_val |= CFG_ALOS_CHK_DISABLE_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_id, SERDES_CFG, reg_val);
+}
+
+static void hisi_sas_bist_test_restore_v3_hw(struct hisi_hba *hisi_hba)
+{
+ u32 reg_val;
+ int phy_id = hisi_hba->debugfs_bist_phy_no;
+
+ /* disable loopback */
+ reg_val = hisi_sas_phy_read32(hisi_hba, phy_id, SAS_PHY_BIST_CTRL);
+ reg_val &= ~(CFG_RX_BIST_EN_MSK | CFG_TX_BIST_EN_MSK |
+ CFG_BIST_TEST_MSK);
+ hisi_sas_phy_write32(hisi_hba, phy_id, SAS_PHY_BIST_CTRL, reg_val);
+
+ /* enable ALOS */
+ reg_val = hisi_sas_phy_read32(hisi_hba, phy_id, SERDES_CFG);
+ reg_val &= ~CFG_ALOS_CHK_DISABLE_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_id, SERDES_CFG, reg_val);
+
+ /* restore the linkrate */
+ reg_val = hisi_sas_phy_read32(hisi_hba, phy_id, PROG_PHY_LINK_RATE);
+ /* init OOB link rate as 1.5 Gbits */
+ reg_val &= ~CFG_PROG_PHY_LINK_RATE_MSK;
+ reg_val |= (0x8 << CFG_PROG_PHY_LINK_RATE_OFF);
+ hisi_sas_phy_write32(hisi_hba, phy_id, PROG_PHY_LINK_RATE, reg_val);
+
+ /* enable PHY */
+ hisi_sas_phy_enable(hisi_hba, phy_id, 1);
+}
+
+#define SAS_PHY_BIST_CODE_INIT 0x1
+#define SAS_PHY_BIST_CODE1_INIT 0X80
+static int debugfs_set_bist_v3_hw(struct hisi_hba *hisi_hba, bool enable)
+{
+ u32 reg_val, mode_tmp;
+ u32 linkrate = hisi_hba->debugfs_bist_linkrate;
+ u32 phy_id = hisi_hba->debugfs_bist_phy_no;
+ u32 code_mode = hisi_hba->debugfs_bist_code_mode;
+ u32 path_mode = hisi_hba->debugfs_bist_mode;
+ struct device *dev = hisi_hba->dev;
+
+ dev_info(dev, "BIST info:linkrate=%d phy_id=%d code_mode=%d path_mode=%d\n",
+ linkrate, phy_id, code_mode, path_mode);
+ mode_tmp = path_mode ? 2 : 1;
+ if (enable) {
+ /* some preparations before bist test */
+ hisi_sas_bist_test_prep_v3_hw(hisi_hba);
+
+ /* set linkrate of bit test*/
+ reg_val = hisi_sas_phy_read32(hisi_hba, phy_id,
+ PROG_PHY_LINK_RATE);
+ reg_val &= ~CFG_PROG_PHY_LINK_RATE_MSK;
+ reg_val |= (linkrate << CFG_PROG_PHY_LINK_RATE_OFF);
+ hisi_sas_phy_write32(hisi_hba, phy_id,
+ PROG_PHY_LINK_RATE, reg_val);
+
+ /* set code mode of bit test */
+ reg_val = hisi_sas_phy_read32(hisi_hba, phy_id,
+ SAS_PHY_BIST_CTRL);
+ reg_val &= ~(CFG_BIST_MODE_SEL_MSK |
+ CFG_LOOP_TEST_MODE_MSK |
+ CFG_RX_BIST_EN_MSK |
+ CFG_TX_BIST_EN_MSK |
+ CFG_BIST_TEST_MSK);
+ reg_val |= ((code_mode << CFG_BIST_MODE_SEL_OFF) |
+ (mode_tmp << CFG_LOOP_TEST_MODE_OFF) |
+ CFG_BIST_TEST_MSK);
+ hisi_sas_phy_write32(hisi_hba, phy_id,
+ SAS_PHY_BIST_CTRL, reg_val);
+
+ /* set the bist init value */
+ hisi_sas_phy_write32(hisi_hba, phy_id,
+ SAS_PHY_BIST_CODE,
+ SAS_PHY_BIST_CODE_INIT);
+ hisi_sas_phy_write32(hisi_hba, phy_id,
+ SAS_PHY_BIST_CODE1,
+ SAS_PHY_BIST_CODE1_INIT);
+
+ mdelay(100);
+ reg_val |= (CFG_RX_BIST_EN_MSK | CFG_TX_BIST_EN_MSK);
+ hisi_sas_phy_write32(hisi_hba, phy_id,
+ SAS_PHY_BIST_CTRL, reg_val);
+
+ /* clear error bit */
+ mdelay(100);
+ hisi_sas_phy_read32(hisi_hba, phy_id, SAS_BIST_ERR_CNT);
+ } else {
+ /* disable bist test and recover it */
+ hisi_hba->debugfs_bist_cnt += hisi_sas_phy_read32(hisi_hba,
+ phy_id, SAS_BIST_ERR_CNT);
+ hisi_sas_bist_test_restore_v3_hw(hisi_hba);
+ }
+
+ return 0;
+}
+
static struct scsi_host_template sht_v3_hw = {
.name = DRV_NAME,
.module = THIS_MODULE,
@@ -2927,6 +3086,9 @@ static struct scsi_host_template sht_v3_hw = {
.eh_target_reset_handler = sas_eh_target_reset_handler,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = sas_ioctl,
+#endif
.shost_attrs = host_attrs_v3_hw,
.tag_alloc_policy = BLK_TAG_ALLOC_RR,
.host_reset = hisi_sas_host_reset,
@@ -2935,7 +3097,6 @@ static struct scsi_host_template sht_v3_hw = {
static const struct hisi_sas_hw hisi_sas_v3_hw = {
.hw_init = hisi_sas_v3_init,
.setup_itct = setup_itct_v3_hw,
- .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V3_HW,
.get_wideport_bitmap = get_wideport_bitmap_v3_hw,
.complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr),
.clear_itct = clear_itct_v3_hw,
@@ -2944,9 +3105,7 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
.prep_smp = prep_smp_v3_hw,
.prep_stp = prep_ata_v3_hw,
.prep_abort = prep_abort_v3_hw,
- .get_free_slot = get_free_slot_v3_hw,
.start_delivery = start_delivery_v3_hw,
- .slot_complete = slot_complete_v3_hw,
.phys_init = phys_init_v3_hw,
.phy_start = start_phy_v3_hw,
.phy_disable = disable_phy_v3_hw,
@@ -2959,10 +3118,14 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
.get_events = phy_get_events_v3_hw,
.write_gpio = write_gpio_v3_hw,
.wait_cmds_complete_timeout = wait_cmds_complete_timeout_v3_hw,
- .debugfs_reg_global = &debugfs_global_reg,
+ .debugfs_reg_array[DEBUGFS_GLOBAL] = &debugfs_global_reg,
+ .debugfs_reg_array[DEBUGFS_AXI] = &debugfs_axi_reg,
+ .debugfs_reg_array[DEBUGFS_RAS] = &debugfs_ras_reg,
.debugfs_reg_port = &debugfs_port_reg,
.snapshot_prepare = debugfs_snapshot_prepare_v3_hw,
.snapshot_restore = debugfs_snapshot_restore_v3_hw,
+ .read_iost_itct_cache = read_iost_itct_cache_v3_hw,
+ .set_bist = debugfs_set_bist_v3_hw,
};
static struct Scsi_Host *
@@ -2993,8 +3156,6 @@ hisi_sas_shost_alloc_pci(struct pci_dev *pdev)
else
hisi_hba->prot_mask = prot_mask;
- timer_setup(&hisi_hba->timer, NULL, 0);
-
if (hisi_sas_get_fw_info(hisi_hba) < 0)
goto err_out;
@@ -3076,17 +3237,14 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
shost->max_lun = ~0;
shost->max_channel = 1;
shost->max_cmd_len = 16;
- shost->can_queue = hisi_hba->hw->max_command_entries -
- HISI_SAS_RESERVED_IPTT_CNT;
- shost->cmd_per_lun = hisi_hba->hw->max_command_entries -
- HISI_SAS_RESERVED_IPTT_CNT;
+ shost->can_queue = HISI_SAS_UNRESERVED_IPTT;
+ shost->cmd_per_lun = HISI_SAS_UNRESERVED_IPTT;
sha->sas_ha_name = DRV_NAME;
sha->dev = dev;
sha->lldd_module = THIS_MODULE;
sha->sas_addr = &hisi_hba->sas_addr[0];
sha->num_phys = hisi_hba->n_phy;
- sha->core.shost = hisi_hba->shost;
for (i = 0; i < hisi_hba->n_phy; i++) {
sha->sas_phy[i] = &hisi_hba->phy[i].sas_phy;
@@ -3124,6 +3282,7 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err_out_register_ha:
scsi_remove_host(shost);
err_out_ha:
+ hisi_sas_debugfs_exit(hisi_hba);
scsi_host_put(shost);
err_out_regions:
pci_release_regions(pdev);
@@ -3157,8 +3316,6 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev)
struct hisi_hba *hisi_hba = sha->lldd_ha;
struct Scsi_Host *shost = sha->core.shost;
- hisi_sas_debugfs_exit(hisi_hba);
-
if (timer_pending(&hisi_hba->timer))
del_timer(&hisi_hba->timer);
@@ -3166,10 +3323,10 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev)
sas_remove_host(sha->core.shost);
hisi_sas_v3_destroy_irqs(pdev, hisi_hba);
- hisi_sas_kill_tasklets(hisi_hba);
pci_release_regions(pdev);
pci_disable_device(pdev);
hisi_sas_free(hisi_hba);
+ hisi_sas_debugfs_exit(hisi_hba);
scsi_host_put(shost);
}
@@ -3273,15 +3430,22 @@ static int hisi_sas_v3_resume(struct pci_dev *pdev)
pci_enable_wake(pdev, PCI_D0, 0);
pci_restore_state(pdev);
rc = pci_enable_device(pdev);
- if (rc)
+ if (rc) {
dev_err(dev, "enable device failed during resume (%d)\n", rc);
+ return rc;
+ }
pci_set_master(pdev);
scsi_unblock_requests(shost);
clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
sas_prep_resume_ha(sha);
- init_reg_v3_hw(hisi_hba);
+ rc = hw_init_v3_hw(hisi_hba);
+ if (rc) {
+ scsi_remove_host(shost);
+ pci_disable_device(pdev);
+ return rc;
+ }
hisi_hba->hw->phys_init(hisi_hba);
sas_resume_ha(sha);
clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
OpenPOWER on IntegriCloud