[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>
This commit is contained in:
parent
3b709df5f7
commit
57ba07dc54
|
@ -37,18 +37,14 @@
|
||||||
|
|
||||||
static inline int asd_get_ddb(struct asd_ha_struct *asd_ha)
|
static inline int asd_get_ddb(struct asd_ha_struct *asd_ha)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
int ddb, i;
|
int ddb, i;
|
||||||
|
|
||||||
spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
|
|
||||||
ddb = FIND_FREE_DDB(asd_ha);
|
ddb = FIND_FREE_DDB(asd_ha);
|
||||||
if (ddb >= asd_ha->hw_prof.max_ddbs) {
|
if (ddb >= asd_ha->hw_prof.max_ddbs) {
|
||||||
ddb = -ENOMEM;
|
ddb = -ENOMEM;
|
||||||
spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
SET_DDB(ddb, asd_ha);
|
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)
|
for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4)
|
||||||
asd_ddbsite_write_dword(asd_ha, ddb, i, 0);
|
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)
|
static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (!ddb || ddb >= 0xFFFF)
|
if (!ddb || ddb >= 0xFFFF)
|
||||||
return;
|
return;
|
||||||
asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED);
|
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);
|
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)
|
static inline void asd_set_ddb_type(struct domain_device *dev)
|
||||||
|
@ -320,8 +312,11 @@ out:
|
||||||
|
|
||||||
int asd_dev_found(struct domain_device *dev)
|
int asd_dev_found(struct domain_device *dev)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
int res = 0;
|
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) {
|
switch (dev->dev_type) {
|
||||||
case SATA_PM:
|
case SATA_PM:
|
||||||
res = asd_init_sata_pm_ddb(dev);
|
res = asd_init_sata_pm_ddb(dev);
|
||||||
|
@ -335,14 +330,18 @@ int asd_dev_found(struct domain_device *dev)
|
||||||
else
|
else
|
||||||
res = asd_init_initiator_ddb(dev);
|
res = asd_init_initiator_ddb(dev);
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void asd_dev_gone(struct domain_device *dev)
|
void asd_dev_gone(struct domain_device *dev)
|
||||||
{
|
{
|
||||||
int ddb, sister_ddb;
|
int ddb, sister_ddb;
|
||||||
|
unsigned long flags;
|
||||||
struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
|
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;
|
ddb = (int) (unsigned long) dev->lldd_dev;
|
||||||
sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB);
|
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, sister_ddb);
|
||||||
asd_free_ddb(asd_ha, ddb);
|
asd_free_ddb(asd_ha, ddb);
|
||||||
dev->lldd_dev = NULL;
|
dev->lldd_dev = NULL;
|
||||||
|
spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1395,7 +1395,9 @@ void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
|
||||||
u8 phy_is_up;
|
u8 phy_is_up;
|
||||||
u8 mask;
|
u8 mask;
|
||||||
int i, err;
|
int i, err;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
|
||||||
for_each_phy(phy_mask, mask, i)
|
for_each_phy(phy_mask, mask, i)
|
||||||
asd_ddbsite_write_byte(asd_ha, 0,
|
asd_ddbsite_write_byte(asd_ha, 0,
|
||||||
offsetof(struct asd_ddb_seq_shared,
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
asd_printk("couldn't update DDB 0:error:%d\n", err);
|
asd_printk("couldn't update DDB 0:error:%d\n", err);
|
||||||
|
|
Loading…
Reference in New Issue