/*
* drivers/block/mg_disk.c
*
* Support for the mGine m[g]flash IO mode.
* Based on legacy hd.c
*
* (c) 2008 mGine Co.,LTD
* (c) 2008 unsik Kim <donari75@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/libata.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/mg_disk.h>
#define MG_RES_SEC (CONFIG_MG_DISK_RES << 1)
static void mg_request(struct request_queue *);
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;
}
printk(KERN_ERR "%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
if (stat & MG_REG_STATUS_BIT_BUSY)
printk("Busy ");
if (stat & MG_REG_STATUS_BIT_READY)
printk("DriveReady ");
if (stat & MG_REG_STATUS_BIT_WRITE_FAULT)
printk("WriteFault ");
if (stat & MG_REG_STATUS_BIT_SEEK_DONE)
printk("SeekComplete ");
if (stat & MG_REG_STATUS_BIT_DATA_REQ)
printk("DataRequest ");
if (stat & MG_REG_STATUS_BIT_CORRECTED_ERROR)
printk("CorrectedError ");
if (stat & MG_REG_STATUS_BIT_ERROR)
printk("Error ");
printk("}\n");
if ((stat & MG_REG_STATUS_BIT_ERROR) == 0) {
host->error = 0;
} else {
host->error = inb((unsigned long)host->dev_base + MG_REG_ERROR);
printk(KERN_ERR "%s: %s: error=0x%02x { ", name, msg,
host->error & 0xff);
if (host->error & MG_REG_ERR_BBK)
printk("BadSector ");
if (host->error & MG_REG_ERR_UNC)
printk("UncorrectableError ");
if (host->error & MG_REG_ERR_IDNF)
printk("SectorIdNotFound ");
if (host->error & MG_REG_ERR_ABRT)
printk("DriveStatusError ");
if (host->error & MG_REG_ERR_AMNF)
printk("AddrMarkNotFound ");
printk("}");
if (host->error &
(MG_REG_ERR_BBK | MG_REG_ERR_UNC |
MG_REG_ERR_IDNF | MG_REG_ERR_AMNF)) {
if (host->breq) {
req = elv_next_request(host->breq);
if (req)
printk(", sector=%ld", req->sector);
}
}
printk("\n");
}
}
static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec)
{
u8 status;
unsigned long expire, cur_jiffies;
struct mg_drv_data *prv_data = host->dev->platform_data;
host->error = MG_ERR_NONE;
expire = jiffies + msecs_to_jiffies(msec);
status = inb((unsigned long)host->dev_base + MG_REG_STATUS);
do {
cur_jiffies = jiffies;
if (status & MG_REG_STATUS_BIT_BUSY) {
if (expect == MG_REG_STATUS_BIT_BUSY)
break;
} else {
/* Check the error condition! */
if (status & MG_REG_STATUS_BIT_ERROR) {
mg_dump_status("mg_wait", status, host);
break;
}
if (expect == MG_STAT_READY)
if (MG_READY_OK(status))
break;
if (expect == MG_REG_STATUS_BIT_DATA_REQ)
if (status & MG_REG_STATUS_BIT_DATA_REQ)
break;
}
if (!msec) {
mg_dump_status("not ready", status, host);
return MG_ERR_INV_STAT;
}
if (prv_data->use_polling)
msleep(1);
status = inb((unsigned long)host->dev_base + MG_REG_STATUS);
} while (time_before(cur_jiffies, expire));
if (time_after_eq(cur_jiffies, expire) && msec)
host->error