Commit 12db5ca7 authored by Jens Axboe's avatar Jens Axboe

[PATCH] ide locking botch

I took a quick look at why 2.5.21 hung at boot detecting partitions,
because a 2.5.22 did the exact same thing on my test box today... The
tcq locking is completely screwed now, and as I said before the weekend
I think the entire locking is just getting worse now.

Anyways, this patch at least attempts to make tcq follow the channel
lock usage to make it work for me.
parent d9083ea2
...@@ -175,13 +175,8 @@ static void ata_tcq_irq_timeout(unsigned long data) ...@@ -175,13 +175,8 @@ static void ata_tcq_irq_timeout(unsigned long data)
tcq_invalidate_queue(drive); tcq_invalidate_queue(drive);
} }
static void set_irq(struct ata_device *drive, ata_handler_t *handler) static void __set_irq(struct ata_channel *ch, ata_handler_t *handler)
{ {
struct ata_channel *ch = drive->channel;
unsigned long flags;
spin_lock_irqsave(ch->lock, flags);
/* /*
* always just bump the timer for now, the timeout handling will * always just bump the timer for now, the timeout handling will
* have to be changed to be per-command * have to be changed to be per-command
...@@ -194,7 +189,15 @@ static void set_irq(struct ata_device *drive, ata_handler_t *handler) ...@@ -194,7 +189,15 @@ static void set_irq(struct ata_device *drive, ata_handler_t *handler)
ch->timer.data = (unsigned long) ch->drive; ch->timer.data = (unsigned long) ch->drive;
mod_timer(&ch->timer, jiffies + 5 * HZ); mod_timer(&ch->timer, jiffies + 5 * HZ);
ch->handler = handler; ch->handler = handler;
}
static void set_irq(struct ata_device *drive, ata_handler_t *handler)
{
struct ata_channel *ch = drive->channel;
unsigned long flags;
spin_lock_irqsave(ch->lock, flags);
__set_irq(ch, handler);
spin_unlock_irqrestore(ch->lock, flags); spin_unlock_irqrestore(ch->lock, flags);
} }
...@@ -230,8 +233,10 @@ static ide_startstop_t udma_tcq_start(struct ata_device *drive, struct request * ...@@ -230,8 +233,10 @@ static ide_startstop_t udma_tcq_start(struct ata_device *drive, struct request *
*/ */
static ide_startstop_t service(struct ata_device *drive, struct request *rq) static ide_startstop_t service(struct ata_device *drive, struct request *rq)
{ {
u8 feat; struct ata_channel *ch = drive->channel;
u8 stat; ide_startstop_t ret;
unsigned long flags;
u8 feat, stat;
int tag; int tag;
TCQ_PRINTK("%s: started service\n", drive->name); TCQ_PRINTK("%s: started service\n", drive->name);
...@@ -291,9 +296,12 @@ static ide_startstop_t service(struct ata_device *drive, struct request *rq) ...@@ -291,9 +296,12 @@ static ide_startstop_t service(struct ata_device *drive, struct request *rq)
TCQ_PRINTK("%s: stat %x, feat %x\n", __FUNCTION__, stat, feat); TCQ_PRINTK("%s: stat %x, feat %x\n", __FUNCTION__, stat, feat);
spin_lock_irqsave(ch->lock, flags);
rq = blk_queue_find_tag(&drive->queue, tag); rq = blk_queue_find_tag(&drive->queue, tag);
if (!rq) { if (!rq) {
printk(KERN_ERR"%s: missing request for tag %d\n", __FUNCTION__, tag); printk(KERN_ERR"%s: missing request for tag %d\n", __FUNCTION__, tag);
spin_unlock_irqrestore(ch->lock, flags);
return ide_stopped; return ide_stopped;
} }
...@@ -304,7 +312,10 @@ static ide_startstop_t service(struct ata_device *drive, struct request *rq) ...@@ -304,7 +312,10 @@ static ide_startstop_t service(struct ata_device *drive, struct request *rq)
* interrupt to indicate end of transfer, release is not allowed * interrupt to indicate end of transfer, release is not allowed
*/ */
TCQ_PRINTK("%s: starting command %x\n", __FUNCTION__, stat); TCQ_PRINTK("%s: starting command %x\n", __FUNCTION__, stat);
return udma_tcq_start(drive, rq);
ret = udma_tcq_start(drive, rq);
spin_unlock_irqrestore(ch->lock, flags);
return ret;
} }
static ide_startstop_t check_service(struct ata_device *drive, struct request *rq) static ide_startstop_t check_service(struct ata_device *drive, struct request *rq)
...@@ -538,7 +549,7 @@ static ide_startstop_t udma_tcq_start(struct ata_device *drive, struct request * ...@@ -538,7 +549,7 @@ static ide_startstop_t udma_tcq_start(struct ata_device *drive, struct request *
if (ata_start_dma(drive, rq)) if (ata_start_dma(drive, rq))
return ide_stopped; return ide_stopped;
set_irq(drive, ide_dmaq_intr); __set_irq(ch, ide_dmaq_intr);
udma_start(drive, rq); udma_start(drive, rq);
return ide_started; return ide_started;
...@@ -590,7 +601,7 @@ ide_startstop_t udma_tcq_init(struct ata_device *drive, struct request *rq) ...@@ -590,7 +601,7 @@ ide_startstop_t udma_tcq_init(struct ata_device *drive, struct request *rq)
if ((feat = GET_FEAT()) & NSEC_REL) { if ((feat = GET_FEAT()) & NSEC_REL) {
drive->immed_rel++; drive->immed_rel++;
drive->rq = NULL; drive->rq = NULL;
set_irq(drive, ide_dmaq_intr); __set_irq(drive->channel, ide_dmaq_intr);
TCQ_PRINTK("REL in queued_start\n"); TCQ_PRINTK("REL in queued_start\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment