summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjack wang <jack_wang@usish.com>2009-12-07 10:22:36 +0100
committerJames Bottomley <James.Bottomley@suse.de>2009-12-10 16:58:54 +0100
commit9e79e12554d651f586ff2364e69a8e9cd5e9dbcb (patch)
tree034b6b41675573b5458501a04a8c635229c33fcd
parent[SCSI] hpsa: add driver for HP Smart Array controllers. (diff)
downloadlinux-9e79e12554d651f586ff2364e69a8e9cd5e9dbcb.tar.xz
linux-9e79e12554d651f586ff2364e69a8e9cd5e9dbcb.zip
[SCSI] pm8001: Fix for sata io circular lock dependency.
This patch fix for sata IO circular lock dependency. When we call task_done for SATA IO, we have got pm8001_ha->lock ,and in sas_ata_task_done, it will get (dev->sata_dev.ap->lock. then cause circular lock dependency .So we should drop pm8001_ha->lock when we call task_done for SATA task. Signed-off-by: Jack Wang <jack_wang@usish.com> Signed-off-by: Lindar Liu <lindar_liu@usish.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c40
1 files changed, 35 insertions, 5 deletions
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index a3de306b9045..68695b72e1ef 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -1901,7 +1901,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
struct sas_task *t;
struct pm8001_ccb_info *ccb;
- unsigned long flags;
+ unsigned long flags = 0;
u32 param;
u32 status;
u32 tag;
@@ -2040,7 +2040,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
ts->stat = SAS_QUEUE_FULL;
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
mb();/*in order to force CPU ordering*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
return;
}
break;
@@ -2058,7 +2060,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
ts->stat = SAS_QUEUE_FULL;
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
mb();/*ditto*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
return;
}
break;
@@ -2084,7 +2088,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
ts->stat = SAS_QUEUE_FULL;
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
mb();/* ditto*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
return;
}
break;
@@ -2149,7 +2155,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
ts->stat = SAS_QUEUE_FULL;
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
mb();/*ditto*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
return;
}
break;
@@ -2171,7 +2179,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
ts->stat = SAS_QUEUE_FULL;
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
mb();/*ditto*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
return;
}
break;
@@ -2200,11 +2210,20 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
" resp 0x%x stat 0x%x but aborted by upper layer!\n",
t, status, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- } else {
+ } else if (t->uldd_task) {
spin_unlock_irqrestore(&t->task_state_lock, flags);
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
mb();/* ditto */
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+ t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
+ } else if (!t->uldd_task) {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ mb();/*ditto*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
}
}
@@ -2212,7 +2231,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
{
struct sas_task *t;
- unsigned long flags;
+ unsigned long flags = 0;
struct task_status_struct *ts;
struct pm8001_ccb_info *ccb;
struct pm8001_device *pm8001_dev;
@@ -2292,7 +2311,9 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
ts->stat = SAS_QUEUE_FULL;
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
mb();/*ditto*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
return;
}
break;
@@ -2401,11 +2422,20 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
" resp 0x%x stat 0x%x but aborted by upper layer!\n",
t, event, ts->resp, ts->stat));
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- } else {
+ } else if (t->uldd_task) {
spin_unlock_irqrestore(&t->task_state_lock, flags);
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
- mb();/* in order to force CPU ordering */
+ mb();/* ditto */
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+ t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
+ } else if (!t->uldd_task) {
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
+ pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
+ mb();/*ditto*/
+ spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
+ spin_lock_irqsave(&pm8001_ha->lock, flags);
}
}