]> err.no Git - linux-2.6/commitdiff
[SCSI] aic94xx: Lock DDB read/write accesses
authorDarrick J. Wong <djwong@us.ibm.com>
Thu, 11 Jan 2007 22:15:32 +0000 (14:15 -0800)
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>
Sat, 13 Jan 2007 22:19:42 +0000 (16:19 -0600)
Extend the use of the DDB lock to include all DDB accesses, because
DDB updates now occur from multiple threads.  This fixes the SMP timeout
problems that we were occasionally seeing with a x260, because the
controller got confused when the DDBs got corrupted.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
drivers/scsi/aic94xx/aic94xx_dev.c
drivers/scsi/aic94xx/aic94xx_seq.c

index 6f8901b748f737c676d0c22226f06117e09a545e..c520e5b41fb52288982d73ac2ce46362407938d5 100644 (file)
 
 static inline int asd_get_ddb(struct asd_ha_struct *asd_ha)
 {
-       unsigned long flags;
        int ddb, i;
 
-       spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
        ddb = FIND_FREE_DDB(asd_ha);
        if (ddb >= asd_ha->hw_prof.max_ddbs) {
                ddb = -ENOMEM;
-               spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
                goto out;
        }
        SET_DDB(ddb, asd_ha);
-       spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
 
        for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4)
                asd_ddbsite_write_dword(asd_ha, ddb, i, 0);
@@ -77,14 +73,10 @@ out:
 
 static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb)
 {
-       unsigned long flags;
-
        if (!ddb || ddb >= 0xFFFF)
                return;
        asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED);
-       spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
        CLEAR_DDB(ddb, asd_ha);
-       spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
 }
 
 static inline void asd_set_ddb_type(struct domain_device *dev)
@@ -320,8 +312,11 @@ out:
 
 int asd_dev_found(struct domain_device *dev)
 {
+       unsigned long flags;
        int res = 0;
+       struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
 
+       spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
        switch (dev->dev_type) {
        case SATA_PM:
                res = asd_init_sata_pm_ddb(dev);
@@ -335,14 +330,18 @@ int asd_dev_found(struct domain_device *dev)
                else
                        res = asd_init_initiator_ddb(dev);
        }
+       spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
+
        return res;
 }
 
 void asd_dev_gone(struct domain_device *dev)
 {
        int ddb, sister_ddb;
+       unsigned long flags;
        struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
 
+       spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
        ddb = (int) (unsigned long) dev->lldd_dev;
        sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB);
 
@@ -350,4 +349,5 @@ void asd_dev_gone(struct domain_device *dev)
                asd_free_ddb(asd_ha, sister_ddb);
        asd_free_ddb(asd_ha, ddb);
        dev->lldd_dev = NULL;
+       spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
 }
index 0d343cfd433350ab5f087626188f1a1e91c43ae3..2768fe4d66ba19f6fa26a42b39b207a6e945be2f 100644 (file)
@@ -1395,7 +1395,9 @@ void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
        u8  phy_is_up;
        u8  mask;
        int i, err;
+       unsigned long flags;
 
+       spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
        for_each_phy(phy_mask, mask, i)
                asd_ddbsite_write_byte(asd_ha, 0,
                                       offsetof(struct asd_ddb_seq_shared,
@@ -1415,6 +1417,7 @@ void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
                        break;
                }
        }
+       spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
 
        if (err)
                asd_printk("couldn't update DDB 0:error:%d\n", err);