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)
* Issue a new request.
* 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_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;
struct ata_channel *channel = q->queuedata;
/* This device still wants to remain idle.
*/
if (tmp->sleep && time_after(tmp->sleep, jiffies))
continue;
while (!test_and_set_bit(IDE_BUSY, channel->active)) {
struct ata_channel *ch;
struct ata_device *drive = NULL;
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) {
struct ata_device *tmp = &channel->drives[unit];
......@@ -567,208 +539,229 @@ static void do_request(struct ata_channel *channel)
if (!tmp->present)
continue;
/* This device is sleeping and waiting to be serviced
* 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.
/* There are no requests pending for this device.
*/
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);
/*
* 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.
/* This device still wants to remain idle.
*/
if (tmp->sleep && time_after(tmp->sleep, jiffies))
continue;
if (channel->drive && !channel->drive->using_tcq)
ata_irq_enable(channel->drive, 0);
/* Take this device, if there is no device choosen thus
* 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;
}
/* Remember the last drive we where acting on.
*/
ch = drive->channel;
ch->drive = drive;
if (!drive) {
unsigned long sleep = 0;
/* Feed commands to a drive until it barfs.
*/
do {
struct request *rq = NULL;
sector_t block;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
struct ata_device *tmp = &channel->drives[unit];
/* 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 (!tmp->present)
continue;
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);
/* This device is sleeping and waiting to be serviced
* earlier than any other device we checked thus far.
*/
if (tmp->sleep && (!sleep || time_after(sleep, tmp->sleep)))
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)) {
printk(KERN_ERR "%s: error: DMA in progress...\n", drive->name);
break;
return;
}
/* 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!
/* Remember the last drive we where acting on.
*/
ch = drive->channel;
ch->drive = drive;
if (blk_queue_plugged(&drive->queue)) {
BUG_ON(!drive->using_tcq);
break;
}
/* Feed commands to a drive until it barfs.
*/
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 (!ata_pending_commands(drive)) {
clear_bit(IDE_BUSY, ch->active);
if (drive->using_tcq)
ata_irq_enable(drive, 0);
if (test_bit(IDE_DMA, ch->active)) {
printk(KERN_ERR "%s: error: DMA in progress...\n", drive->name);
break;
}
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
* non-fs request (really, a non-queuable command)
* until the queue is empty.
*/
if (!(rq->flags & REQ_CMD) && ata_pending_commands(drive))
break;
if (blk_queue_plugged(&drive->queue)) {
BUG_ON(!drive->using_tcq);
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);
/* allow other IRQs while we start this request */
local_irq_enable();
break;
}
/*
* This initiates handling of a new I/O request.
*/
/* If there are queued commands, we can't start a
* 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
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
/* bail early if we've exceeded max_failures */
if (drive->max_failures && (drive->failures > drive->max_failures))
goto kill_rq;
/* bail early if we've exceeded max_failures */
if (drive->max_failures && (drive->failures > drive->max_failures))
goto kill_rq;
block = rq->sector;
block = rq->sector;
/* Strange disk manager remap.
*/
if (rq->flags & REQ_CMD)
if (drive->type == ATA_DISK || drive->type == ATA_FLOPPY)
block += drive->sect0;
/* Strange disk manager remap.
*/
if (rq->flags & REQ_CMD)
if (drive->type == ATA_DISK || drive->type == ATA_FLOPPY)
block += drive->sect0;
/* Yecch - this will shift the entire interval, possibly killing some
* innocent following sector.
*/
if (block == 0 && drive->remap_0_to_1 == 1)
block = 1; /* redirect MBR access to EZ-Drive partn table */
/* Yecch - this will shift the entire interval, possibly killing some
* innocent following sector.
*/
if (block == 0 && drive->remap_0_to_1 == 1)
block = 1; /* redirect MBR access to EZ-Drive partn table */
ata_select(drive, 0);
ret = ata_status_poll(drive, drive->ready_stat, BUSY_STAT | DRQ_STAT,
WAIT_READY, rq);
ata_select(drive, 0);
ret = ata_status_poll(drive, drive->ready_stat, BUSY_STAT | DRQ_STAT,
WAIT_READY, rq);
if (ret != ATA_OP_READY) {
printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
if (ret != ATA_OP_READY) {
printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
goto kill_rq;
}
goto kill_rq;
}
if (!ata_ops(drive)) {
printk(KERN_WARNING "%s: device type %d not supported\n",
drive->name, drive->type);
goto kill_rq;
}
if (!ata_ops(drive)) {
printk(KERN_WARNING "%s: device type %d not supported\n",
drive->name, drive->type);
goto kill_rq;
}
/* The normal way of execution is to pass and execute the request
* handler down to the device type driver.
*/
/* The normal way of execution is to pass and execute the request
* handler down to the device type driver.
*/
if (ata_ops(drive)->do_request) {
ret = ata_ops(drive)->do_request(drive, rq, block);
} else {
if (ata_ops(drive)->do_request) {
ret = ata_ops(drive)->do_request(drive, rq, block);
} else {
kill_rq:
if (ata_ops(drive) && ata_ops(drive)->end_request)
ata_ops(drive)->end_request(drive, rq, 0);
else
ata_end_request(drive, rq, 0, 0);
ret = ATA_OP_FINISHED;
if (ata_ops(drive) && ata_ops(drive)->end_request)
ata_ops(drive)->end_request(drive, rq, 0);
else
ata_end_request(drive, rq, 0, 0);
ret = ATA_OP_FINISHED;
}
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;
}
spin_lock_irq(ch->lock);
while (!test_and_set_bit(IDE_BUSY, ch->active)) {
do_request(ch);
/* 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);
}
}
/*
* 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
* 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 not explicitly reenter the request handling engine.
......@@ -893,7 +886,8 @@ void ide_timer_expiry(unsigned long data)
if (ret == ATA_OP_FINISHED) {
/* 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);
......@@ -1050,9 +1044,10 @@ void ata_irq_request(int irq, void *data, struct pt_regs *regs)
* another interrupt.
*/
if (!ch->handler)
do_request(ch);
else
if (!ch->handler) {
clear_bit(IDE_BUSY, ch->active);
do_ide_request(&drive->queue);
} else
printk("%s: %s: huh? expected NULL handler on exit\n",
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