Commit 8f6205cd authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe

ide: dequeue in-flight request

ide generally has single request in flight and tracks it using
hwif->rq and all state handlers follow the following convention.

* ide_started is returned if the request is in flight.

* ide_stopped is returned if the queue needs to be restarted.  The
  request might or might not have been processed fully or partially.

* hwif->rq is set to NULL, when an issued request completes.

So, dequeueing model can be implemented by dequeueing after fetch,
requeueing if hwif->rq isn't NULL on ide_stopped return and doing
about the same thing on completion / port unlock paths.  These changes
can be made in ide-io proper.

In addition to the above main changes, the following updates are
necessary.

* ide-cd shouldn't dequeue a request when issuing REQUEST SENSE for it
  as the request is already dequeued.

* ide-atapi uses request queue as stack when issuing REQUEST SENSE to
  put the REQUEST SENSE in front of the failed request.  This now
  needs to be done using requeueing.

[ Impact: dequeue in-flight request ]
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Cc: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Cc: Borislav Petkov <petkovbb@googlemail.com>
Cc: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 1011c1b9
...@@ -246,6 +246,7 @@ EXPORT_SYMBOL_GPL(ide_queue_sense_rq); ...@@ -246,6 +246,7 @@ EXPORT_SYMBOL_GPL(ide_queue_sense_rq);
*/ */
void ide_retry_pc(ide_drive_t *drive) void ide_retry_pc(ide_drive_t *drive)
{ {
struct request *failed_rq = drive->hwif->rq;
struct request *sense_rq = &drive->sense_rq; struct request *sense_rq = &drive->sense_rq;
struct ide_atapi_pc *pc = &drive->request_sense_pc; struct ide_atapi_pc *pc = &drive->request_sense_pc;
...@@ -260,8 +261,17 @@ void ide_retry_pc(ide_drive_t *drive) ...@@ -260,8 +261,17 @@ void ide_retry_pc(ide_drive_t *drive)
if (drive->media == ide_tape) if (drive->media == ide_tape)
set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags); set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
if (ide_queue_sense_rq(drive, pc)) /*
ide_complete_rq(drive, -EIO, blk_rq_bytes(drive->hwif->rq)); * Push back the failed request and put request sense on top
* of it. The failed command will be retried after sense data
* is acquired.
*/
blk_requeue_request(failed_rq->q, failed_rq);
drive->hwif->rq = NULL;
if (ide_queue_sense_rq(drive, pc)) {
blkdev_dequeue_request(failed_rq);
ide_complete_rq(drive, -EIO, blk_rq_bytes(failed_rq));
}
} }
EXPORT_SYMBOL_GPL(ide_retry_pc); EXPORT_SYMBOL_GPL(ide_retry_pc);
......
...@@ -405,15 +405,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat) ...@@ -405,15 +405,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
end_request: end_request:
if (stat & ATA_ERR) { if (stat & ATA_ERR) {
struct request_queue *q = drive->queue;
unsigned long flags;
spin_lock_irqsave(q->queue_lock, flags);
blkdev_dequeue_request(rq);
spin_unlock_irqrestore(q->queue_lock, flags);
hwif->rq = NULL; hwif->rq = NULL;
return ide_queue_sense_rq(drive, rq) ? 2 : 1; return ide_queue_sense_rq(drive, rq) ? 2 : 1;
} else } else
return 2; return 2;
......
...@@ -487,10 +487,10 @@ void do_ide_request(struct request_queue *q) ...@@ -487,10 +487,10 @@ void do_ide_request(struct request_queue *q)
if (!ide_lock_port(hwif)) { if (!ide_lock_port(hwif)) {
ide_hwif_t *prev_port; ide_hwif_t *prev_port;
WARN_ON_ONCE(hwif->rq);
repeat: repeat:
prev_port = hwif->host->cur_port; prev_port = hwif->host->cur_port;
hwif->rq = NULL;
if (drive->dev_flags & IDE_DFLAG_SLEEPING && if (drive->dev_flags & IDE_DFLAG_SLEEPING &&
time_after(drive->sleep, jiffies)) { time_after(drive->sleep, jiffies)) {
ide_unlock_port(hwif); ide_unlock_port(hwif);
...@@ -519,7 +519,12 @@ repeat: ...@@ -519,7 +519,12 @@ repeat:
* we know that the queue isn't empty, but this can happen * we know that the queue isn't empty, but this can happen
* if the q->prep_rq_fn() decides to kill a request * if the q->prep_rq_fn() decides to kill a request
*/ */
if (!rq) {
rq = elv_next_request(drive->queue); rq = elv_next_request(drive->queue);
if (rq)
blkdev_dequeue_request(rq);
}
spin_unlock_irq(q->queue_lock); spin_unlock_irq(q->queue_lock);
spin_lock_irq(&hwif->lock); spin_lock_irq(&hwif->lock);
...@@ -555,8 +560,11 @@ repeat: ...@@ -555,8 +560,11 @@ repeat:
startstop = start_request(drive, rq); startstop = start_request(drive, rq);
spin_lock_irq(&hwif->lock); spin_lock_irq(&hwif->lock);
if (startstop == ide_stopped) if (startstop == ide_stopped) {
rq = hwif->rq;
hwif->rq = NULL;
goto repeat; goto repeat;
}
} else } else
goto plug_device; goto plug_device;
out: out:
...@@ -572,18 +580,24 @@ plug_device: ...@@ -572,18 +580,24 @@ plug_device:
plug_device_2: plug_device_2:
spin_lock_irq(q->queue_lock); spin_lock_irq(q->queue_lock);
if (rq)
blk_requeue_request(q, rq);
if (!elv_queue_empty(q)) if (!elv_queue_empty(q))
blk_plug_device(q); blk_plug_device(q);
} }
static void ide_plug_device(ide_drive_t *drive) static void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq)
{ {
struct request_queue *q = drive->queue; struct request_queue *q = drive->queue;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(q->queue_lock, flags); spin_lock_irqsave(q->queue_lock, flags);
if (rq)
blk_requeue_request(q, rq);
if (!elv_queue_empty(q)) if (!elv_queue_empty(q))
blk_plug_device(q); blk_plug_device(q);
spin_unlock_irqrestore(q->queue_lock, flags); spin_unlock_irqrestore(q->queue_lock, flags);
} }
...@@ -632,6 +646,7 @@ void ide_timer_expiry (unsigned long data) ...@@ -632,6 +646,7 @@ void ide_timer_expiry (unsigned long data)
unsigned long flags; unsigned long flags;
int wait = -1; int wait = -1;
int plug_device = 0; int plug_device = 0;
struct request *uninitialized_var(rq_in_flight);
spin_lock_irqsave(&hwif->lock, flags); spin_lock_irqsave(&hwif->lock, flags);
...@@ -693,6 +708,8 @@ void ide_timer_expiry (unsigned long data) ...@@ -693,6 +708,8 @@ void ide_timer_expiry (unsigned long data)
spin_lock_irq(&hwif->lock); spin_lock_irq(&hwif->lock);
enable_irq(hwif->irq); enable_irq(hwif->irq);
if (startstop == ide_stopped) { if (startstop == ide_stopped) {
rq_in_flight = hwif->rq;
hwif->rq = NULL;
ide_unlock_port(hwif); ide_unlock_port(hwif);
plug_device = 1; plug_device = 1;
} }
...@@ -701,7 +718,7 @@ void ide_timer_expiry (unsigned long data) ...@@ -701,7 +718,7 @@ void ide_timer_expiry (unsigned long data)
if (plug_device) { if (plug_device) {
ide_unlock_host(hwif->host); ide_unlock_host(hwif->host);
ide_plug_device(drive); ide_requeue_and_plug(drive, rq_in_flight);
} }
} }
...@@ -787,6 +804,7 @@ irqreturn_t ide_intr (int irq, void *dev_id) ...@@ -787,6 +804,7 @@ irqreturn_t ide_intr (int irq, void *dev_id)
ide_startstop_t startstop; ide_startstop_t startstop;
irqreturn_t irq_ret = IRQ_NONE; irqreturn_t irq_ret = IRQ_NONE;
int plug_device = 0; int plug_device = 0;
struct request *uninitialized_var(rq_in_flight);
if (host->host_flags & IDE_HFLAG_SERIALIZE) { if (host->host_flags & IDE_HFLAG_SERIALIZE) {
if (hwif != host->cur_port) if (hwif != host->cur_port)
...@@ -866,6 +884,8 @@ irqreturn_t ide_intr (int irq, void *dev_id) ...@@ -866,6 +884,8 @@ irqreturn_t ide_intr (int irq, void *dev_id)
*/ */
if (startstop == ide_stopped) { if (startstop == ide_stopped) {
BUG_ON(hwif->handler); BUG_ON(hwif->handler);
rq_in_flight = hwif->rq;
hwif->rq = NULL;
ide_unlock_port(hwif); ide_unlock_port(hwif);
plug_device = 1; plug_device = 1;
} }
...@@ -875,7 +895,7 @@ out: ...@@ -875,7 +895,7 @@ out:
out_early: out_early:
if (plug_device) { if (plug_device) {
ide_unlock_host(hwif->host); ide_unlock_host(hwif->host);
ide_plug_device(drive); ide_requeue_and_plug(drive, rq_in_flight);
} }
return irq_ret; return irq_ret;
......
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