mirror of
https://github.com/torvalds/linux.git
synced 2024-12-29 06:12:08 +00:00
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>
This commit is contained in:
parent
9a8d23d885
commit
5b36ad6000
@ -135,6 +135,7 @@ struct mg_host {
|
|||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
|
||||||
struct request_queue *breq;
|
struct request_queue *breq;
|
||||||
|
struct request *req;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
struct gendisk *gd;
|
struct gendisk *gd;
|
||||||
|
|
||||||
@ -171,17 +172,27 @@ struct mg_host {
|
|||||||
|
|
||||||
static void mg_request(struct request_queue *);
|
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,
|
static void mg_dump_status(const char *msg, unsigned int stat,
|
||||||
struct mg_host *host)
|
struct mg_host *host)
|
||||||
{
|
{
|
||||||
char *name = MG_DISK_NAME;
|
char *name = MG_DISK_NAME;
|
||||||
struct request *req;
|
|
||||||
|
|
||||||
if (host->breq) {
|
if (host->req)
|
||||||
req = elv_next_request(host->breq);
|
name = host->req->rq_disk->disk_name;
|
||||||
if (req)
|
|
||||||
name = req->rq_disk->disk_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
printk(KERN_ERR "%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
|
printk(KERN_ERR "%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
|
||||||
if (stat & ATA_BUSY)
|
if (stat & ATA_BUSY)
|
||||||
@ -217,13 +228,9 @@ static void mg_dump_status(const char *msg, unsigned int stat,
|
|||||||
printk("AddrMarkNotFound ");
|
printk("AddrMarkNotFound ");
|
||||||
printk("}");
|
printk("}");
|
||||||
if (host->error & (ATA_BBK | ATA_UNC | ATA_IDNF | ATA_AMNF)) {
|
if (host->error & (ATA_BBK | ATA_UNC | ATA_IDNF | ATA_AMNF)) {
|
||||||
if (host->breq) {
|
if (host->req)
|
||||||
req = elv_next_request(host->breq);
|
printk(", sector=%u",
|
||||||
if (req)
|
(unsigned int)blk_rq_pos(host->req));
|
||||||
printk(", sector=%u",
|
|
||||||
(unsigned int)blk_rq_pos(req));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
printk("\n");
|
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)
|
static void mg_bad_rw_intr(struct mg_host *host)
|
||||||
{
|
{
|
||||||
struct request *req = elv_next_request(host->breq);
|
if (host->req)
|
||||||
if (req != NULL)
|
if (++host->req->errors >= MG_MAX_ERRORS ||
|
||||||
if (++req->errors >= MG_MAX_ERRORS ||
|
host->error == MG_ERR_TIMEOUT)
|
||||||
host->error == MG_ERR_TIMEOUT)
|
mg_end_request_cur(host, -EIO);
|
||||||
__blk_end_request_cur(req, -EIO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int mg_out(struct mg_host *host,
|
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 +
|
outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base +
|
||||||
MG_REG_COMMAND);
|
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)
|
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 +
|
outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base +
|
||||||
MG_REG_COMMAND);
|
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)
|
static void mg_read_intr(struct mg_host *host)
|
||||||
{
|
{
|
||||||
|
struct request *req = host->req;
|
||||||
u32 i;
|
u32 i;
|
||||||
u16 *buff;
|
u16 *buff;
|
||||||
struct request *req;
|
|
||||||
|
|
||||||
/* check status */
|
/* check status */
|
||||||
do {
|
do {
|
||||||
@ -571,7 +577,6 @@ static void mg_read_intr(struct mg_host *host)
|
|||||||
|
|
||||||
ok_to_read:
|
ok_to_read:
|
||||||
/* get current segment of request */
|
/* get current segment of request */
|
||||||
req = elv_next_request(host->breq);
|
|
||||||
buff = (u16 *)req->buffer;
|
buff = (u16 *)req->buffer;
|
||||||
|
|
||||||
/* read 1 sector */
|
/* read 1 sector */
|
||||||
@ -585,7 +590,7 @@ ok_to_read:
|
|||||||
/* send read confirm */
|
/* send read confirm */
|
||||||
outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND);
|
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 */
|
/* set handler if read remains */
|
||||||
host->mg_do_intr = mg_read_intr;
|
host->mg_do_intr = mg_read_intr;
|
||||||
mod_timer(&host->timer, jiffies + 3 * HZ);
|
mod_timer(&host->timer, jiffies + 3 * HZ);
|
||||||
@ -595,14 +600,11 @@ ok_to_read:
|
|||||||
|
|
||||||
static void mg_write_intr(struct mg_host *host)
|
static void mg_write_intr(struct mg_host *host)
|
||||||
{
|
{
|
||||||
|
struct request *req = host->req;
|
||||||
u32 i, j;
|
u32 i, j;
|
||||||
u16 *buff;
|
u16 *buff;
|
||||||
struct request *req;
|
|
||||||
bool rem;
|
bool rem;
|
||||||
|
|
||||||
/* get current segment of request */
|
|
||||||
req = elv_next_request(host->breq);
|
|
||||||
|
|
||||||
/* check status */
|
/* check status */
|
||||||
do {
|
do {
|
||||||
i = inb((unsigned long)host->dev_base + MG_REG_STATUS);
|
i = inb((unsigned long)host->dev_base + MG_REG_STATUS);
|
||||||
@ -619,7 +621,7 @@ static void mg_write_intr(struct mg_host *host)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ok_to_write:
|
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 */
|
/* write 1 sector and set handler if remains */
|
||||||
buff = (u16 *)req->buffer;
|
buff = (u16 *)req->buffer;
|
||||||
for (j = 0; j < MG_STORAGE_BUFFER_SIZE >> 1; j++) {
|
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;
|
struct mg_host *host = (struct mg_host *)data;
|
||||||
char *name;
|
char *name;
|
||||||
struct request *req;
|
|
||||||
|
|
||||||
spin_lock_irq(&host->lock);
|
spin_lock_irq(&host->lock);
|
||||||
|
|
||||||
req = elv_next_request(host->breq);
|
if (!host->req)
|
||||||
if (!req)
|
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
host->mg_do_intr = NULL;
|
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);
|
printk(KERN_DEBUG "%s: timeout\n", name);
|
||||||
|
|
||||||
host->error = MG_ERR_TIMEOUT;
|
host->error = MG_ERR_TIMEOUT;
|
||||||
mg_bad_rw_intr(host);
|
mg_bad_rw_intr(host);
|
||||||
|
|
||||||
mg_request(host->breq);
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
|
mg_request(host->breq);
|
||||||
spin_unlock_irq(&host->lock);
|
spin_unlock_irq(&host->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mg_request_poll(struct request_queue *q)
|
static void mg_request_poll(struct request_queue *q)
|
||||||
{
|
{
|
||||||
struct request *req;
|
struct mg_host *host = q->queuedata;
|
||||||
struct mg_host *host;
|
|
||||||
|
|
||||||
while ((req = elv_next_request(q)) != NULL) {
|
while (1) {
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
if (unlikely(!blk_fs_request(req))) {
|
if (unlikely(!blk_fs_request(host->req))) {
|
||||||
__blk_end_request_cur(req, -EIO);
|
mg_end_request_cur(host, -EIO);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rq_data_dir(req) == READ)
|
if (rq_data_dir(host->req) == READ)
|
||||||
mg_read(req);
|
mg_read(host->req);
|
||||||
else
|
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 */
|
/* This function also called from IRQ context */
|
||||||
static void mg_request(struct request_queue *q)
|
static void mg_request(struct request_queue *q)
|
||||||
{
|
{
|
||||||
|
struct mg_host *host = q->queuedata;
|
||||||
struct request *req;
|
struct request *req;
|
||||||
struct mg_host *host;
|
|
||||||
u32 sect_num, sect_cnt;
|
u32 sect_num, sect_cnt;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
req = elv_next_request(q);
|
if (!host->req) {
|
||||||
if (!req)
|
host->req = elv_next_request(q);
|
||||||
return;
|
if (host->req)
|
||||||
|
blkdev_dequeue_request(host->req);
|
||||||
host = req->rq_disk->private_data;
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
req = host->req;
|
||||||
|
|
||||||
/* check unwanted request call */
|
/* check unwanted request call */
|
||||||
if (host->mg_do_intr)
|
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",
|
"%s: bad access: sector=%d, count=%d\n",
|
||||||
req->rq_disk->disk_name,
|
req->rq_disk->disk_name,
|
||||||
sect_num, sect_cnt);
|
sect_num, sect_cnt);
|
||||||
__blk_end_request_cur(req, -EIO);
|
mg_end_request_cur(host, -EIO);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(!blk_fs_request(req))) {
|
if (unlikely(!blk_fs_request(req))) {
|
||||||
__blk_end_request_cur(req, -EIO);
|
mg_end_request_cur(host, -EIO);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -981,6 +989,7 @@ static int mg_probe(struct platform_device *plat_dev)
|
|||||||
__func__, __LINE__);
|
__func__, __LINE__);
|
||||||
goto probe_err_5;
|
goto probe_err_5;
|
||||||
}
|
}
|
||||||
|
host->breq->queuedata = host;
|
||||||
|
|
||||||
/* mflash is random device, thanx for the noop */
|
/* mflash is random device, thanx for the noop */
|
||||||
elevator_exit(host->breq->elevator);
|
elevator_exit(host->breq->elevator);
|
||||||
|
Loading…
Reference in New Issue
Block a user