OSDN Git Service

scsi: hisi_sas: fix a bug when free device for v3 hw
authorXiang Chen <chenxiang66@hisilicon.com>
Tue, 24 Oct 2017 15:51:46 +0000 (23:51 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 31 Oct 2017 16:28:00 +0000 (12:28 -0400)
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>
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

index 1f8995b..243fa1d 100644 (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_SRC_MSK1, 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_ENT_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,
                              struct hisi_sas_device *sas_dev)
 {
+       DECLARE_COMPLETION_ONSTACK(completion);
        u64 dev_id = sas_dev->device_id;
-       struct device *dev = hisi_hba->dev;
        struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
        u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
 
+       sas_dev->completion = &completion;
+
        /* clear the itct interrupt state */
        if (ENT_INT_SRC3_ITC_INT_MSK & reg_val)
                hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
                                 ENT_INT_SRC3_ITC_INT_MSK);
 
        /* 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);
 
-       udelay(10);
-       reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
-       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");
-       }
+       wait_for_completion(sas_dev->completion);
+       memset(itct, 0, sizeof(struct hisi_sas_itct));
 }
 
 static void dereg_device_v3_hw(struct hisi_hba *hisi_hba,