diff options
author | Tejun Heo <tj@kernel.org> | 2009-05-08 11:54:01 +0900 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2009-05-11 09:52:15 +0200 |
commit | 5b36ad6000ddea390aca3c3b67ead7616ace2ffc (patch) | |
tree | dedca03fffd6729487fbd9bc3959428038e0cdfb | |
parent | 9a8d23d8855e554fc5887f14cb008b55c4300ccc (diff) |
mg_disk: dequeue and track in-flight request
mg_disk has at most single request in flight per device. Till now,
whenever it needs to access the in-flight request it called
elv_next_request(). This patch makes mg_disk track the in-flight
request directly using mg_host->req and dequeue it when processing
starts.
q->queuedata is set to mg_host so that mg_host can be determined
without fetching request from the queue.
[ Impact: dequeue in-flight request, one elv_next_request() per request ]
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: unsik Kim <donari75@gmail.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r-- | drivers/block/mg_disk.c | 109 |
1 files changed, 59 insertions, 50 deletions
diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index be323880f24..1ca5d1423fa 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -135,6 +135,7 @@ struct mg_host { struct device *dev; struct request_queue *breq; + struct request *req; spinlock_t lock; struct gendisk *gd; @@ -171,17 +172,27 @@ struct mg_host { static void mg_request(struct request_queue *); +static bool mg_end_request(struct mg_host *host, int err, unsigned int nr_bytes) +{ + if (__blk_end_request(host->req, err, nr_bytes)) + return true; + + host->req = NULL; + return false; +} + +static bool mg_end_request_cur(struct mg_host *host, int err) +{ + return mg_end_request(host, err, blk_rq_cur_bytes(host->req)); +} + static void mg_dump_status(const char *msg, unsigned int stat, struct mg_host *host) { char *name = MG_DISK_NAME; - struct request *req; - if (host->breq) { - req = elv_next_request(host->breq); - if (req) - name = req->rq_disk->disk_name; - } + if (host->req) + name = host->req->rq_disk->disk_name; printk(KERN_ERR "%s: %s: status=0x%02x { ", name, msg, stat & 0xff); if (stat & ATA_BUSY) @@ -217,13 +228,9 @@ static void mg_dump_status(const char *msg, unsigned int stat, printk("AddrMarkNotFound "); printk("}"); if (host->error & (ATA_BBK | ATA_UNC | ATA_IDNF | ATA_AMNF)) { - if (host->breq) { - req = elv_next_request(host->breq); - if (req) - printk(", sector=%u", - (unsigned int)blk_rq_pos(req)); - } - + if (host->req) + printk(", sector=%u", + (unsigned int)blk_rq_pos(host->req)); } printk("\n"); } @@ -453,11 +460,10 @@ static int mg_disk_init(struct mg_host *host) static void mg_bad_rw_intr(struct mg_host *host) { - struct request *req = elv_next_request(host->breq); - if (req != NULL) - if (++req->errors >= MG_MAX_ERRORS || - host->error == MG_ERR_TIMEOUT) - __blk_end_request_cur(req, -EIO); + if (host->req) + if (++host->req->errors >= MG_MAX_ERRORS || + host->error == MG_ERR_TIMEOUT) + mg_end_request_cur(host, -EIO); } static unsigned int mg_out(struct mg_host *host, @@ -515,7 +521,7 @@ static void mg_read(struct request *req) outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); - } while (__blk_end_request(req, 0, MG_SECTOR_SIZE)); + } while (mg_end_request(host, 0, MG_SECTOR_SIZE)); } static void mg_write(struct request *req) @@ -545,14 +551,14 @@ static void mg_write(struct request *req) outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); - } while (__blk_end_request(req, 0, MG_SECTOR_SIZE)); + } while (mg_end_request(host, 0, MG_SECTOR_SIZE)); } static void mg_read_intr(struct mg_host *host) { + struct request *req = host->req; u32 i; u16 *buff; - struct request *req; /* check status */ do { @@ -571,7 +577,6 @@ static void mg_read_intr(struct mg_host *host) ok_to_read: /* get current segment of request */ - req = elv_next_request(host->breq); buff = (u16 *)req->buffer; /* read 1 sector */ @@ -585,7 +590,7 @@ ok_to_read: /* send read confirm */ outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); - if (__blk_end_request(req, 0, MG_SECTOR_SIZE)) { + if (mg_end_request(host, 0, MG_SECTOR_SIZE)) { /* set handler if read remains */ host->mg_do_intr = mg_read_intr; mod_timer(&host->timer, jiffies + 3 * HZ); @@ -595,14 +600,11 @@ ok_to_read: static void mg_write_intr(struct mg_host *host) { + struct request *req = host->req; u32 i, j; u16 *buff; - struct request *req; bool rem; - /* get current segment of request */ - req = elv_next_request(host->breq); - /* check status */ do { i = inb((unsigned long)host->dev_base + MG_REG_STATUS); @@ -619,7 +621,7 @@ static void mg_write_intr(struct mg_host *host) return; ok_to_write: - if ((rem = __blk_end_request(req, 0, MG_SECTOR_SIZE))) { + if ((rem = mg_end_request(host, 0, MG_SECTOR_SIZE))) { /* write 1 sector and set handler if remains */ buff = (u16 *)req->buffer; for (j = 0; j < MG_STORAGE_BUFFER_SIZE >> 1; j++) { @@ -644,44 +646,47 @@ void mg_times_out(unsigned long data) { struct mg_host *host = (struct mg_host *)data; char *name; - struct request *req; spin_lock_irq(&host->lock); - req = elv_next_request(host->breq); - if (!req) + if (!host->req) goto out_unlock; host->mg_do_intr = NULL; - name = req->rq_disk->disk_name; + name = host->req->rq_disk->disk_name; printk(KERN_DEBUG "%s: timeout\n", name); host->error = MG_ERR_TIMEOUT; mg_bad_rw_intr(host); - mg_request(host->breq); out_unlock: + mg_request(host->breq); spin_unlock_irq(&host->lock); } static void mg_request_poll(struct request_queue *q) { - struct request *req; - struct mg_host *host; + struct mg_host *host = q->queuedata; - while ((req = elv_next_request(q)) != NULL) { - host = req->rq_disk->private_data; + while (1) { + if (!host->req) { + host->req = elv_next_request(q); + if (host->req) + blkdev_dequeue_request(host->req); + else + break; + } - if (unlikely(!blk_fs_request(req))) { - __blk_end_request_cur(req, -EIO); + if (unlikely(!blk_fs_request(host->req))) { + mg_end_request_cur(host, -EIO); continue; } - if (rq_data_dir(req) == READ) - mg_read(req); + if (rq_data_dir(host->req) == READ) + mg_read(host->req); else - mg_write(req); + mg_write(host->req); } } @@ -733,16 +738,19 @@ static unsigned int mg_issue_req(struct request *req, /* This function also called from IRQ context */ static void mg_request(struct request_queue *q) { + struct mg_host *host = q->queuedata; struct request *req; - struct mg_host *host; u32 sect_num, sect_cnt; while (1) { - req = elv_next_request(q); - if (!req) - return; - - host = req->rq_disk->private_data; + if (!host->req) { + host->req = elv_next_request(q); + if (host->req) + blkdev_dequeue_request(host->req); + else + break; + } + req = host->req; /* check unwanted request call */ if (host->mg_do_intr) @@ -762,12 +770,12 @@ static void mg_request(struct request_queue *q) "%s: bad access: sector=%d, count=%d\n", req->rq_disk->disk_name, sect_num, sect_cnt); - __blk_end_request_cur(req, -EIO); + mg_end_request_cur(host, -EIO); continue; } if (unlikely(!blk_fs_request(req))) { - __blk_end_request_cur(req, -EIO); + mg_end_request_cur(host, -EIO); continue; } @@ -981,6 +989,7 @@ static int mg_probe(struct platform_device *plat_dev) __func__, __LINE__); goto probe_err_5; } + host->breq->queuedata = host; /* mflash is random device, thanx for the noop */ elevator_exit(host->breq->elevator); |