scsi: hisi_sas: fix a bug when free device for v3 hw

Use completion to wait on ITCT CLR interrupt finishing before
processing other things when freeing a device.

This is safer than the pre-existing process of polling the register.

Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Xiang Chen 2017-10-24 23:51:46 +08:00 committed by Martin K. Petersen
parent b4241f0fa3
commit 13cd5ed612

View File

@ -393,7 +393,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 0xffffffff); hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 0xffffffff);
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xfefefefe); hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xfefefefe);
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xfefefefe); hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xfefefefe);
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffffffff); hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xfffe20ff);
hisi_sas_write32(hisi_hba, CHNL_PHYUPDOWN_INT_MSK, 0x0); hisi_sas_write32(hisi_hba, CHNL_PHYUPDOWN_INT_MSK, 0x0);
hisi_sas_write32(hisi_hba, CHNL_ENT_INT_MSK, 0x0); hisi_sas_write32(hisi_hba, CHNL_ENT_INT_MSK, 0x0);
hisi_sas_write32(hisi_hba, HGC_COM_INT_MSK, 0x0); hisi_sas_write32(hisi_hba, HGC_COM_INT_MSK, 0x0);
@ -582,35 +582,24 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba,
static void free_device_v3_hw(struct hisi_hba *hisi_hba, static void free_device_v3_hw(struct hisi_hba *hisi_hba,
struct hisi_sas_device *sas_dev) struct hisi_sas_device *sas_dev)
{ {
DECLARE_COMPLETION_ONSTACK(completion);
u64 dev_id = sas_dev->device_id; u64 dev_id = sas_dev->device_id;
struct device *dev = hisi_hba->dev;
struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id]; struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3); u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
sas_dev->completion = &completion;
/* clear the itct interrupt state */ /* clear the itct interrupt state */
if (ENT_INT_SRC3_ITC_INT_MSK & reg_val) if (ENT_INT_SRC3_ITC_INT_MSK & reg_val)
hisi_sas_write32(hisi_hba, ENT_INT_SRC3, hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
ENT_INT_SRC3_ITC_INT_MSK); ENT_INT_SRC3_ITC_INT_MSK);
/* clear the itct table*/ /* clear the itct table*/
reg_val = hisi_sas_read32(hisi_hba, ITCT_CLR); reg_val = ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
reg_val |= ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK);
hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val); hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val);
udelay(10); wait_for_completion(sas_dev->completion);
reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3); memset(itct, 0, sizeof(struct hisi_sas_itct));
if (ENT_INT_SRC3_ITC_INT_MSK & reg_val) {
dev_dbg(dev, "got clear ITCT done interrupt\n");
/* invalid the itct state*/
memset(itct, 0, sizeof(struct hisi_sas_itct));
hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
ENT_INT_SRC3_ITC_INT_MSK);
/* clear the itct */
hisi_sas_write32(hisi_hba, ITCT_CLR, 0);
dev_dbg(dev, "clear ITCT ok\n");
}
} }
static void dereg_device_v3_hw(struct hisi_hba *hisi_hba, static void dereg_device_v3_hw(struct hisi_hba *hisi_hba,