Commit e1eec525 authored by Martin Dalecki's avatar Martin Dalecki Committed by Linus Torvalds

[PATCH] IDE 107

 - Fix "temporal anomaly" in do_ide_request pointed out by Petr
   Vandrovec. Thanks Petr!
parent 2993fd69
...@@ -517,49 +517,21 @@ void ide_stall_queue(struct ata_device *drive, unsigned long timeout) ...@@ -517,49 +517,21 @@ void ide_stall_queue(struct ata_device *drive, unsigned long timeout)
* Issue a new request. * Issue a new request.
* Caller must have already done spin_lock_irqsave(channel->lock, ...) * Caller must have already done spin_lock_irqsave(channel->lock, ...)
*/ */
static void do_request(struct ata_channel *channel) void do_ide_request(request_queue_t *q)
{ {
struct ata_channel *ch; struct ata_channel *channel = q->queuedata;
struct ata_device *drive = NULL;
unsigned int unit;
ide_startstop_t ret;
local_irq_disable(); /* necessary paranoia */
/*
* Select the next device which will be serviced. This selects
* only between devices on the same channel, since everything
* else will be scheduled on the queue level.
*/
for (unit = 0; unit < MAX_DRIVES; ++unit) {
struct ata_device *tmp = &channel->drives[unit];
if (!tmp->present)
continue;
/* There are no requests pending for this device.
*/
if (blk_queue_empty(&tmp->queue))
continue;
/* This device still wants to remain idle. while (!test_and_set_bit(IDE_BUSY, channel->active)) {
*/ struct ata_channel *ch;
if (tmp->sleep && time_after(tmp->sleep, jiffies)) struct ata_device *drive = NULL;
continue; unsigned int unit;
ide_startstop_t ret;
/* Take this device, if there is no device choosen thus /*
* far or which is more urgent. * Select the next device which will be serviced. This selects
* only between devices on the same channel, since everything
* else will be scheduled on the queue level.
*/ */
if (!drive || (tmp->sleep && (!drive->sleep || time_after(drive->sleep, tmp->sleep)))) {
if (!blk_queue_plugged(&tmp->queue))
drive = tmp;
}
}
if (!drive) {
unsigned long sleep = 0;
for (unit = 0; unit < MAX_DRIVES; ++unit) { for (unit = 0; unit < MAX_DRIVES; ++unit) {
struct ata_device *tmp = &channel->drives[unit]; struct ata_device *tmp = &channel->drives[unit];
...@@ -567,208 +539,229 @@ static void do_request(struct ata_channel *channel) ...@@ -567,208 +539,229 @@ static void do_request(struct ata_channel *channel)
if (!tmp->present) if (!tmp->present)
continue; continue;
/* This device is sleeping and waiting to be serviced /* There are no requests pending for this device.
* earlier than any other device we checked thus far.
*/
if (tmp->sleep && (!sleep || time_after(sleep, tmp->sleep)))
sleep = tmp->sleep;
}
if (sleep) {
/*
* Take a short snooze, and then wake up again. Just
* in case there are big differences in relative
* throughputs.. don't want to hog the cpu too much.
*/ */
if (blk_queue_empty(&tmp->queue))
continue;
if (time_after(jiffies, sleep - WAIT_MIN_SLEEP))
sleep = jiffies + WAIT_MIN_SLEEP;
#if 1
if (timer_pending(&channel->timer))
printk(KERN_ERR "%s: timer already active\n", __FUNCTION__);
#endif
set_bit(IDE_SLEEP, channel->active);
mod_timer(&channel->timer, sleep);
/* /* This device still wants to remain idle.
* We purposely leave us busy while sleeping becouse we
* are prepared to handle the IRQ from it.
*
* FIXME: Make sure sleeping can't interferre with
* operations of other devices on the same channel.
*/
} else {
/* FIXME: use queue plugging instead of active to block
* upper layers from stomping on us */
/* Ugly, but how can we sleep for the lock otherwise?
* */
ide_release_lock(&ide_irq_lock);/* for atari only */
clear_bit(IDE_BUSY, channel->active);
/* All requests are done.
*
* Disable IRQs from the last drive on this channel, to
* make sure that it wan't throw stones at us when we
* are not prepared to take them.
*/ */
if (tmp->sleep && time_after(tmp->sleep, jiffies))
continue;
if (channel->drive && !channel->drive->using_tcq) /* Take this device, if there is no device choosen thus
ata_irq_enable(channel->drive, 0); * far or which is more urgent.
*/
if (!drive || (tmp->sleep && (!drive->sleep || time_after(drive->sleep, tmp->sleep)))) {
if (!blk_queue_plugged(&tmp->queue))
drive = tmp;
}
} }
return; if (!drive) {
} unsigned long sleep = 0;
/* Remember the last drive we where acting on.
*/
ch = drive->channel;
ch->drive = drive;
/* Feed commands to a drive until it barfs. for (unit = 0; unit < MAX_DRIVES; ++unit) {
*/ struct ata_device *tmp = &channel->drives[unit];
do {
struct request *rq = NULL;
sector_t block;
/* Abort early if we can't queue another command. for non tcq, if (!tmp->present)
* ata_can_queue is always 1 since we never get here unless the continue;
* drive is idle.
*/
if (!ata_can_queue(drive)) { /* This device is sleeping and waiting to be serviced
if (!ata_pending_commands(drive)) { * earlier than any other device we checked thus far.
clear_bit(IDE_BUSY, ch->active); */
if (drive->using_tcq) if (tmp->sleep && (!sleep || time_after(sleep, tmp->sleep)))
ata_irq_enable(drive, 0); sleep = tmp->sleep;
} }
break;
}
drive->sleep = 0; if (sleep) {
/*
* Take a short snooze, and then wake up again. Just
* in case there are big differences in relative
* throughputs.. don't want to hog the cpu too much.
*/
if (time_after(jiffies, sleep - WAIT_MIN_SLEEP))
sleep = jiffies + WAIT_MIN_SLEEP;
#if 1
if (timer_pending(&channel->timer))
printk(KERN_ERR "%s: timer already active\n", __FUNCTION__);
#endif
set_bit(IDE_SLEEP, channel->active);
mod_timer(&channel->timer, sleep);
/*
* We purposely leave us busy while sleeping becouse we
* are prepared to handle the IRQ from it.
*
* FIXME: Make sure sleeping can't interferre with
* operations of other devices on the same channel.
*/
} else {
/* FIXME: use queue plugging instead of active to block
* upper layers from stomping on us */
/* Ugly, but how can we sleep for the lock otherwise?
* */
ide_release_lock(&ide_irq_lock);/* for atari only */
clear_bit(IDE_BUSY, channel->active);
/* All requests are done.
*
* Disable IRQs from the last drive on this channel, to
* make sure that it wan't throw stones at us when we
* are not prepared to take them.
*/
if (channel->drive && !channel->drive->using_tcq)
ata_irq_enable(channel->drive, 0);
}
if (test_bit(IDE_DMA, ch->active)) { return;
printk(KERN_ERR "%s: error: DMA in progress...\n", drive->name);
break;
} }
/* There's a small window between where the queue could be /* Remember the last drive we where acting on.
* replugged while we are in here when using tcq (in which case
* the queue is probably empty anyways...), so check and leave
* if appropriate. When not using tcq, this is still a severe
* BUG!
*/ */
ch = drive->channel;
ch->drive = drive;
if (blk_queue_plugged(&drive->queue)) { /* Feed commands to a drive until it barfs.
BUG_ON(!drive->using_tcq); */
break; do {
} struct request *rq = NULL;
sector_t block;
/* Abort early if we can't queue another command. for non tcq,
* ata_can_queue is always 1 since we never get here unless the
* drive is idle.
*/
if (!ata_can_queue(drive)) {
if (!ata_pending_commands(drive)) {
clear_bit(IDE_BUSY, ch->active);
if (drive->using_tcq)
ata_irq_enable(drive, 0);
}
break;
}
drive->sleep = 0;
if (!(rq = elv_next_request(&drive->queue))) { if (test_bit(IDE_DMA, ch->active)) {
if (!ata_pending_commands(drive)) { printk(KERN_ERR "%s: error: DMA in progress...\n", drive->name);
clear_bit(IDE_BUSY, ch->active); break;
if (drive->using_tcq)
ata_irq_enable(drive, 0);
} }
drive->rq = NULL;
break; /* There's a small window between where the queue could be
} * replugged while we are in here when using tcq (in which case
* the queue is probably empty anyways...), so check and leave
* if appropriate. When not using tcq, this is still a severe
* BUG!
*/
/* If there are queued commands, we can't start a if (blk_queue_plugged(&drive->queue)) {
* non-fs request (really, a non-queuable command) BUG_ON(!drive->using_tcq);
* until the queue is empty. break;
*/ }
if (!(rq->flags & REQ_CMD) && ata_pending_commands(drive))
break;
drive->rq = rq; if (!(rq = elv_next_request(&drive->queue))) {
if (!ata_pending_commands(drive)) {
clear_bit(IDE_BUSY, ch->active);
if (drive->using_tcq)
ata_irq_enable(drive, 0);
}
drive->rq = NULL;
spin_unlock(ch->lock); break;
/* allow other IRQs while we start this request */ }
local_irq_enable();
/* /* If there are queued commands, we can't start a
* This initiates handling of a new I/O request. * non-fs request (really, a non-queuable command)
*/ * until the queue is empty.
*/
if (!(rq->flags & REQ_CMD) && ata_pending_commands(drive))
break;
drive->rq = rq;
spin_unlock(ch->lock);
/* allow other IRQs while we start this request */
local_irq_enable();
/*
* This initiates handling of a new I/O request.
*/
BUG_ON(!(rq->flags & REQ_STARTED)); BUG_ON(!(rq->flags & REQ_STARTED));
#ifdef DEBUG #ifdef DEBUG
printk("%s: %s: current=0x%08lx\n", ch->name, __FUNCTION__, (unsigned long) rq); printk("%s: %s: current=0x%08lx\n", ch->name, __FUNCTION__, (unsigned long) rq);
#endif #endif
/* bail early if we've exceeded max_failures */ /* bail early if we've exceeded max_failures */
if (drive->max_failures && (drive->failures > drive->max_failures)) if (drive->max_failures && (drive->failures > drive->max_failures))
goto kill_rq; goto kill_rq;
block = rq->sector; block = rq->sector;
/* Strange disk manager remap. /* Strange disk manager remap.
*/ */
if (rq->flags & REQ_CMD) if (rq->flags & REQ_CMD)
if (drive->type == ATA_DISK || drive->type == ATA_FLOPPY) if (drive->type == ATA_DISK || drive->type == ATA_FLOPPY)
block += drive->sect0; block += drive->sect0;
/* Yecch - this will shift the entire interval, possibly killing some /* Yecch - this will shift the entire interval, possibly killing some
* innocent following sector. * innocent following sector.
*/ */
if (block == 0 && drive->remap_0_to_1 == 1) if (block == 0 && drive->remap_0_to_1 == 1)
block = 1; /* redirect MBR access to EZ-Drive partn table */ block = 1; /* redirect MBR access to EZ-Drive partn table */
ata_select(drive, 0); ata_select(drive, 0);
ret = ata_status_poll(drive, drive->ready_stat, BUSY_STAT | DRQ_STAT, ret = ata_status_poll(drive, drive->ready_stat, BUSY_STAT | DRQ_STAT,
WAIT_READY, rq); WAIT_READY, rq);
if (ret != ATA_OP_READY) { if (ret != ATA_OP_READY) {
printk(KERN_ERR "%s: drive not ready for command\n", drive->name); printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
goto kill_rq; goto kill_rq;
} }
if (!ata_ops(drive)) { if (!ata_ops(drive)) {
printk(KERN_WARNING "%s: device type %d not supported\n", printk(KERN_WARNING "%s: device type %d not supported\n",
drive->name, drive->type); drive->name, drive->type);
goto kill_rq; goto kill_rq;
} }
/* The normal way of execution is to pass and execute the request /* The normal way of execution is to pass and execute the request
* handler down to the device type driver. * handler down to the device type driver.
*/ */
if (ata_ops(drive)->do_request) { if (ata_ops(drive)->do_request) {
ret = ata_ops(drive)->do_request(drive, rq, block); ret = ata_ops(drive)->do_request(drive, rq, block);
} else { } else {
kill_rq: kill_rq:
if (ata_ops(drive) && ata_ops(drive)->end_request) if (ata_ops(drive) && ata_ops(drive)->end_request)
ata_ops(drive)->end_request(drive, rq, 0); ata_ops(drive)->end_request(drive, rq, 0);
else else
ata_end_request(drive, rq, 0, 0); ata_end_request(drive, rq, 0, 0);
ret = ATA_OP_FINISHED; ret = ATA_OP_FINISHED;
} }
spin_lock_irq(ch->lock); spin_lock_irq(ch->lock);
/* continue if command started, so we are busy */
} while (ret != ATA_OP_CONTINUES);
/* make sure the BUSY bit is set */
/* FIXME: perhaps there is some place where we miss to set it? */
// set_bit(IDE_BUSY, ch->active);
}
void do_ide_request(request_queue_t *q)
{
struct ata_channel *ch = q->queuedata;
while (!test_and_set_bit(IDE_BUSY, ch->active)) { /* continue if command started, so we are busy */
do_request(ch); } while (ret != ATA_OP_CONTINUES);
/* make sure the BUSY bit is set */
/* FIXME: perhaps there is some place where we miss to set it? */
// set_bit(IDE_BUSY, ch->active);
} }
} }
/* /*
* This is our timeout function for all drive operations. But note that it can * This is our timeout function for all drive operations. But note that it can
* also be invoked as a result of a "sleep" operation triggered by the * also be invoked as a result of a "sleep" operation triggered by the
* mod_timer() call in do_request. * mod_timer() call in do_ide_request.
* *
* FIXME: This should take a drive context instead of a channel. * FIXME: This should take a drive context instead of a channel.
* FIXME: This should not explicitly reenter the request handling engine. * FIXME: This should not explicitly reenter the request handling engine.
...@@ -893,7 +886,8 @@ void ide_timer_expiry(unsigned long data) ...@@ -893,7 +886,8 @@ void ide_timer_expiry(unsigned long data)
if (ret == ATA_OP_FINISHED) { if (ret == ATA_OP_FINISHED) {
/* Reenter the request handling engine. */ /* Reenter the request handling engine. */
do_request(ch); clear_bit(IDE_BUSY, ch->active);
do_ide_request(&drive->queue);
} }
} }
spin_unlock_irqrestore(ch->lock, flags); spin_unlock_irqrestore(ch->lock, flags);
...@@ -1050,9 +1044,10 @@ void ata_irq_request(int irq, void *data, struct pt_regs *regs) ...@@ -1050,9 +1044,10 @@ void ata_irq_request(int irq, void *data, struct pt_regs *regs)
* another interrupt. * another interrupt.
*/ */
if (!ch->handler) if (!ch->handler) {
do_request(ch); clear_bit(IDE_BUSY, ch->active);
else do_ide_request(&drive->queue);
} else
printk("%s: %s: huh? expected NULL handler on exit\n", printk("%s: %s: huh? expected NULL handler on exit\n",
drive->name, __FUNCTION__); drive->name, __FUNCTION__);
} }
......
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