aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2007-01-11 17:15:32 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-01-13 17:19:42 -0500
commit57ba07dc54b7657e69fe8ac42d83df21e415c85b (patch)
tree493da7233a4d7116c6302099a81c6c087b106165
parent3b709df5f7c83b6b0907217a248a1414a37ffcb6 (diff)
[SCSI] aic94xx: Lock DDB read/write accesses
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>
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dev.c16
-rw-r--r--drivers/scsi/aic94xx/aic94xx_seq.c3
2 files changed, 11 insertions, 8 deletions
diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c
index 6f8901b748f7..c520e5b41fb5 100644
--- a/drivers/scsi/aic94xx/aic94xx_dev.c
+++ b/drivers/scsi/aic94xx/aic94xx_dev.c
@@ -37,18 +37,14 @@
37 37
38static inline int asd_get_ddb(struct asd_ha_struct *asd_ha) 38static inline int asd_get_ddb(struct asd_ha_struct *asd_ha)
39{ 39{
40 unsigned long flags;
41 int ddb, i; 40 int ddb, i;
42 41
43 spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
44 ddb = FIND_FREE_DDB(asd_ha); 42 ddb = FIND_FREE_DDB(asd_ha);
45 if (ddb >= asd_ha->hw_prof.max_ddbs) { 43 if (ddb >= asd_ha->hw_prof.max_ddbs) {
46 ddb = -ENOMEM; 44 ddb = -ENOMEM;
47 spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
48 goto out; 45 goto out;
49 } 46 }
50 SET_DDB(ddb, asd_ha); 47 SET_DDB(ddb, asd_ha);
51 spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
52 48
53 for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4) 49 for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4)
54 asd_ddbsite_write_dword(asd_ha, ddb, i, 0); 50 asd_ddbsite_write_dword(asd_ha, ddb, i, 0);
@@ -77,14 +73,10 @@ out:
77 73
78static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb) 74static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb)
79{ 75{
80 unsigned long flags;
81
82 if (!ddb || ddb >= 0xFFFF) 76 if (!ddb || ddb >= 0xFFFF)
83 return; 77 return;
84 asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED); 78 asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED);
85 spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
86 CLEAR_DDB(ddb, asd_ha); 79 CLEAR_DDB(ddb, asd_ha);
87 spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
88} 80}
89 81
90static inline void asd_set_ddb_type(struct domain_device *dev) 82static inline void asd_set_ddb_type(struct domain_device *dev)
@@ -320,8 +312,11 @@ out:
320 312
321int asd_dev_found(struct domain_device *dev) 313int asd_dev_found(struct domain_device *dev)
322{ 314{
315 unsigned long flags;
323 int res = 0; 316 int res = 0;
317 struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
324 318
319 spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
325 switch (dev->dev_type) { 320 switch (dev->dev_type) {
326 case SATA_PM: 321 case SATA_PM:
327 res = asd_init_sata_pm_ddb(dev); 322 res = asd_init_sata_pm_ddb(dev);
@@ -335,14 +330,18 @@ int asd_dev_found(struct domain_device *dev)
335 else 330 else
336 res = asd_init_initiator_ddb(dev); 331 res = asd_init_initiator_ddb(dev);
337 } 332 }
333 spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
334
338 return res; 335 return res;
339} 336}
340 337
341void asd_dev_gone(struct domain_device *dev) 338void asd_dev_gone(struct domain_device *dev)
342{ 339{
343 int ddb, sister_ddb; 340 int ddb, sister_ddb;
341 unsigned long flags;
344 struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; 342 struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
345 343
344 spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
346 ddb = (int) (unsigned long) dev->lldd_dev; 345 ddb = (int) (unsigned long) dev->lldd_dev;
347 sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB); 346 sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB);
348 347
@@ -350,4 +349,5 @@ void asd_dev_gone(struct domain_device *dev)
350 asd_free_ddb(asd_ha, sister_ddb); 349 asd_free_ddb(asd_ha, sister_ddb);
351 asd_free_ddb(asd_ha, ddb); 350 asd_free_ddb(asd_ha, ddb);
352 dev->lldd_dev = NULL; 351 dev->lldd_dev = NULL;
352 spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
353} 353}
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c
index 0d343cfd4333..2768fe4d66ba 100644
--- a/drivers/scsi/aic94xx/aic94xx_seq.c
+++ b/drivers/scsi/aic94xx/aic94xx_seq.c
@@ -1395,7 +1395,9 @@ void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
1395 u8 phy_is_up; 1395 u8 phy_is_up;
1396 u8 mask; 1396 u8 mask;
1397 int i, err; 1397 int i, err;
1398 unsigned long flags;
1398 1399
1400 spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
1399 for_each_phy(phy_mask, mask, i) 1401 for_each_phy(phy_mask, mask, i)
1400 asd_ddbsite_write_byte(asd_ha, 0, 1402 asd_ddbsite_write_byte(asd_ha, 0,
1401 offsetof(struct asd_ddb_seq_shared, 1403 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)
1415 break; 1417 break;
1416 } 1418 }
1417 } 1419 }
1420 spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
1418 1421
1419 if (err) 1422 if (err)
1420 asd_printk("couldn't update DDB 0:error:%d\n", err); 1423 asd_printk("couldn't update DDB 0:error:%d\n", err);