Commit a5c66122 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] paride cleanup and fixes (19/25)

Reordered stuff
made pd_ready() inlined
renamed ps_timeout to pd_timeout
renamed ps_tq to fsm_tq
renamed ps_set_intr to fsm_schedule
removed unused pd_wait_open.
parent 4542c37e
...@@ -153,6 +153,8 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV}; ...@@ -153,6 +153,8 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV};
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/blkpg.h> #include <linux/blkpg.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
static spinlock_t pd_lock = SPIN_LOCK_UNLOCKED; static spinlock_t pd_lock = SPIN_LOCK_UNLOCKED;
...@@ -189,84 +191,6 @@ MODULE_PARM(drive3, "1-8i"); ...@@ -189,84 +191,6 @@ MODULE_PARM(drive3, "1-8i");
#include "paride.h" #include "paride.h"
#include <linux/sched.h>
#include <linux/workqueue.h>
static void ps_tq_int( void *data);
enum action {Fail = 0, Ok = 1, Hold, Wait};
static enum action (*phase)(void);
static unsigned long ps_timeout;
static DECLARE_WORK(ps_tq, ps_tq_int, NULL);
static void ps_set_intr(void)
{
if (!nice)
schedule_work(&ps_tq);
else
schedule_delayed_work(&ps_tq, nice-1);
}
static struct pd_unit *pd_current; /* current request's drive */
static PIA *pi_current; /* current request's PIA */
static struct request *pd_req; /* current request */
static enum action do_pd_io_start(void);
static int pd_claimed;
static struct request_queue *pd_queue;
static void run_fsm(void)
{
while (1) {
enum action res;
unsigned long saved_flags;
int stop = 0;
if (!phase) {
pd_current = pd_req->rq_disk->private_data;
pi_current = pd_current->pi;
phase = do_pd_io_start;
}
switch (pd_claimed) {
case 0:
pd_claimed = 1;
if (!pi_schedule_claimed(pi_current, run_fsm))
return;
case 1:
pd_claimed = 2;
pi_current->proto->connect(pi_current);
}
switch(res = phase()) {
case Ok: case Fail:
pi_disconnect(pi_current);
pd_claimed = 0;
phase = NULL;
spin_lock_irqsave(&pd_lock, saved_flags);
end_request(pd_req, res);
pd_req = elv_next_request(pd_queue);
if (!pd_req)
stop = 1;
spin_unlock_irqrestore(&pd_lock, saved_flags);
if (stop)
return;
case Hold:
ps_set_intr();
return;
case Wait:
pi_disconnect(pi_current);
pd_claimed = 0;
}
}
}
static void ps_tq_int(void *data)
{
run_fsm();
}
#define PD_BITS 4 #define PD_BITS 4
/* numbers for "SCSI" geometry */ /* numbers for "SCSI" geometry */
...@@ -312,19 +236,6 @@ static void ps_tq_int(void *data) ...@@ -312,19 +236,6 @@ static void ps_tq_int(void *data)
#define IDE_IDENTIFY 0xec #define IDE_IDENTIFY 0xec
#define IDE_EJECT 0xed #define IDE_EJECT 0xed
void pd_setup(char *str, int *ints);
static int pd_open(struct inode *inode, struct file *file);
static void do_pd_request(request_queue_t * q);
static int pd_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
static int pd_release(struct inode *inode, struct file *file);
static int pd_revalidate(struct gendisk *p);
static int pd_detect(void);
static enum action do_pd_read_start(void);
static enum action do_pd_write_start(void);
static enum action do_pd_read_drq(void);
static enum action do_pd_write_done(void);
#define PD_NAMELEN 8 #define PD_NAMELEN 8
struct pd_unit { struct pd_unit {
...@@ -348,45 +259,13 @@ struct pd_unit { ...@@ -348,45 +259,13 @@ struct pd_unit {
struct pd_unit pd[PD_UNITS]; struct pd_unit pd[PD_UNITS];
static int pd_identify(struct pd_unit *disk);
static void pd_media_check(struct pd_unit *disk);
static void pd_doorlock(struct pd_unit *disk, int func);
static int pd_check_media(struct gendisk *p);
static void pd_eject(struct pd_unit *disk);
static char pd_scratch[512]; /* scratch block buffer */ static char pd_scratch[512]; /* scratch block buffer */
/* the variables below are used mainly in the I/O request engine, which
processes only one request at a time.
*/
static int pd_retries = 0; /* i/o error retry count */
static int pd_block; /* address of next requested block */
static int pd_count; /* number of blocks still to do */
static int pd_run; /* sectors in current cluster */
static int pd_cmd; /* current command READ/WRITE */
static char *pd_buf; /* buffer for request in progress */
static DECLARE_WAIT_QUEUE_HEAD(pd_wait_open);
static char *pd_errs[17] = { "ERR", "INDEX", "ECC", "DRQ", "SEEK", "WRERR", static char *pd_errs[17] = { "ERR", "INDEX", "ECC", "DRQ", "SEEK", "WRERR",
"READY", "BUSY", "AMNF", "TK0NF", "ABRT", "MCR", "READY", "BUSY", "AMNF", "TK0NF", "ABRT", "MCR",
"IDNF", "MC", "UNC", "???", "TMO" "IDNF", "MC", "UNC", "???", "TMO"
}; };
/* kernel glue structures */
extern struct block_device_operations pd_fops;
static struct block_device_operations pd_fops = {
.owner = THIS_MODULE,
.open = pd_open,
.release = pd_release,
.ioctl = pd_ioctl,
.media_changed = pd_check_media,
.revalidate_disk= pd_revalidate
};
static void pd_init_units(void) static void pd_init_units(void)
{ {
int unit; int unit;
...@@ -409,82 +288,6 @@ static void pd_init_units(void) ...@@ -409,82 +288,6 @@ static void pd_init_units(void)
} }
} }
static int pd_open(struct inode *inode, struct file *file)
{
struct pd_unit *disk = inode->i_bdev->bd_disk->private_data;
disk->access++;
if (disk->removable) {
pd_media_check(disk);
pd_doorlock(disk, IDE_DOORLOCK);
}
return 0;
}
static int pd_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct pd_unit *disk = inode->i_bdev->bd_disk->private_data;
struct hd_geometry *geo = (struct hd_geometry *) arg;
struct hd_geometry g;
switch (cmd) {
case CDROMEJECT:
if (disk->access == 1)
pd_eject(disk);
return 0;
case HDIO_GETGEO:
if (disk->alt_geom) {
g.heads = PD_LOG_HEADS;
g.sectors = PD_LOG_SECTS;
g.cylinders = disk->capacity / (g.heads * g.sectors);
} else {
g.heads = disk->heads;
g.sectors = disk->sectors;
g.cylinders = disk->cylinders;
}
g.start = get_start_sect(inode->i_bdev);
if (copy_to_user(geo, &g, sizeof(struct hd_geometry)))
return -EFAULT;
return 0;
default:
return -EINVAL;
}
}
static int pd_release(struct inode *inode, struct file *file)
{
struct pd_unit *disk = inode->i_bdev->bd_disk->private_data;
if (!--disk->access && disk->removable)
pd_doorlock(disk, IDE_DOORUNLOCK);
return 0;
}
static int pd_check_media(struct gendisk *p)
{
struct pd_unit *disk = p->private_data;
int r;
if (!disk->removable)
return 0;
pd_media_check(disk);
r = disk->changed;
disk->changed = 0;
return r;
}
static int pd_revalidate(struct gendisk *p)
{
struct pd_unit *disk = p->private_data;
if (pd_identify(disk))
set_capacity(p, disk->capacity);
else
set_capacity(p, 0);
return 0;
}
static inline int status_reg(struct pd_unit *disk) static inline int status_reg(struct pd_unit *disk)
{ {
return pi_read_regr(disk->pi, 1, 6); return pi_read_regr(disk->pi, 1, 6);
...@@ -586,80 +389,297 @@ static void pd_ide_command(struct pd_unit *disk, int func, int block, int count) ...@@ -586,80 +389,297 @@ static void pd_ide_command(struct pd_unit *disk, int func, int block, int count)
pd_send_command(disk, count, s, h, c0, c1, func); pd_send_command(disk, count, s, h, c0, c1, func);
} }
/* According to the ATA standard, the default CHS geometry should be /* The i/o request engine */
available following a reset. Some Western Digital drives come up
in a mode where only LBA addresses are accepted until the device
parameters are initialised.
*/
static void pd_init_dev_parms(struct pd_unit *disk) enum action {Fail = 0, Ok = 1, Hold, Wait};
{
pi_connect(disk->pi);
pd_wait_for(disk, 0, DBMSG("before init_dev_parms"));
pd_send_command(disk, disk->sectors, 0, disk->heads - 1, 0, 0,
IDE_INIT_DEV_PARMS);
udelay(300);
pd_wait_for(disk, 0, "Initialise device parameters");
pi_disconnect(disk->pi);
}
static void pd_doorlock(struct pd_unit *disk, int func) static struct request *pd_req; /* current request */
{ static enum action (*phase)(void);
pi_connect(disk->pi);
if (!(pd_wait_for(disk, STAT_READY, "Lock") & STAT_ERR)) {
pd_send_command(disk, 1, 0, 0, 0, 0, func);
pd_wait_for(disk, STAT_READY, "Lock done");
}
pi_disconnect(disk->pi);
}
static void pd_eject(struct pd_unit *disk) static void run_fsm(void);
{
pi_connect(disk->pi);
pd_wait_for(disk, 0, DBMSG("before unlock on eject"));
pd_send_command(disk, 1, 0, 0, 0, 0, IDE_DOORUNLOCK);
pd_wait_for(disk, 0, DBMSG("after unlock on eject"));
pd_wait_for(disk, 0, DBMSG("before eject"));
pd_send_command(disk, 0, 0, 0, 0, 0, IDE_EJECT);
pd_wait_for(disk, 0, DBMSG("after eject"));
pi_disconnect(disk->pi);
}
static void pd_media_check(struct pd_unit *disk) static void ps_tq_int( void *data);
{
int r;
pi_connect(disk->pi); static DECLARE_WORK(fsm_tq, ps_tq_int, NULL);
r = pd_wait_for(disk, STAT_READY, DBMSG("before media_check"));
if (!(r & STAT_ERR)) {
pd_send_command(disk, 1, 1, 0, 0, 0, IDE_READ_VRFY);
r = pd_wait_for(disk, STAT_READY, DBMSG("RDY after READ_VRFY"));
} else
disk->changed = 1; /* say changed if other error */
if (r & ERR_MC) {
disk->changed = 1;
pd_send_command(disk, 1, 0, 0, 0, 0, IDE_ACKCHANGE);
pd_wait_for(disk, STAT_READY, DBMSG("RDY after ACKCHANGE"));
pd_send_command(disk, 1, 1, 0, 0, 0, IDE_READ_VRFY);
r = pd_wait_for(disk, STAT_READY, DBMSG("RDY after VRFY"));
}
pi_disconnect(disk->pi);
static void schedule_fsm(void)
{
if (!nice)
schedule_work(&fsm_tq);
else
schedule_delayed_work(&fsm_tq, nice-1);
} }
static void pd_standby_off(struct pd_unit *disk) static void ps_tq_int(void *data)
{ {
pi_connect(disk->pi); run_fsm();
pd_wait_for(disk, 0, DBMSG("before STANDBY"));
pd_send_command(disk, 0, 0, 0, 0, 0, IDE_STANDBY);
pd_wait_for(disk, 0, DBMSG("after STANDBY"));
pi_disconnect(disk->pi);
} }
static int pd_identify(struct pd_unit *disk) static enum action do_pd_io_start(void);
{ static enum action do_pd_read_start(void);
int j; static enum action do_pd_write_start(void);
char id[PD_ID_LEN + 1]; static enum action do_pd_read_drq(void);
static enum action do_pd_write_done(void);
static struct request_queue *pd_queue;
static int pd_claimed;
static struct pd_unit *pd_current; /* current request's drive */
static PIA *pi_current; /* current request's PIA */
static void run_fsm(void)
{
while (1) {
enum action res;
unsigned long saved_flags;
int stop = 0;
if (!phase) {
pd_current = pd_req->rq_disk->private_data;
pi_current = pd_current->pi;
phase = do_pd_io_start;
}
switch (pd_claimed) {
case 0:
pd_claimed = 1;
if (!pi_schedule_claimed(pi_current, run_fsm))
return;
case 1:
pd_claimed = 2;
pi_current->proto->connect(pi_current);
}
switch(res = phase()) {
case Ok: case Fail:
pi_disconnect(pi_current);
pd_claimed = 0;
phase = NULL;
spin_lock_irqsave(&pd_lock, saved_flags);
end_request(pd_req, res);
pd_req = elv_next_request(pd_queue);
if (!pd_req)
stop = 1;
spin_unlock_irqrestore(&pd_lock, saved_flags);
if (stop)
return;
case Hold:
schedule_fsm();
return;
case Wait:
pi_disconnect(pi_current);
pd_claimed = 0;
}
}
}
static int pd_retries = 0; /* i/o error retry count */
static int pd_block; /* address of next requested block */
static int pd_count; /* number of blocks still to do */
static int pd_run; /* sectors in current cluster */
static int pd_cmd; /* current command READ/WRITE */
static char *pd_buf; /* buffer for request in progress */
static enum action do_pd_io_start(void)
{
pd_block = pd_req->sector;
pd_run = pd_req->nr_sectors;
pd_count = pd_req->current_nr_sectors;
if (pd_block + pd_count > get_capacity(pd_req->rq_disk))
return Fail;
pd_cmd = rq_data_dir(pd_req);
pd_buf = pd_req->buffer;
pd_retries = 0;
if (pd_cmd == READ) {
return do_pd_read_start();
} else if (pd_cmd == WRITE) {
return do_pd_write_start();
} else
return Fail;
}
static int pd_next_buf(void)
{
unsigned long saved_flags;
pd_count--;
pd_run--;
pd_buf += 512;
pd_block++;
if (!pd_run)
return 1;
if (pd_count)
return 0;
spin_lock_irqsave(&pd_lock, saved_flags);
end_request(pd_req, 1);
pd_count = pd_req->current_nr_sectors;
pd_buf = pd_req->buffer;
spin_unlock_irqrestore(&pd_lock, saved_flags);
return 0;
}
static unsigned long pd_timeout;
static enum action do_pd_read_start(void)
{
if (pd_wait_for(pd_current, STAT_READY, "do_pd_read") & STAT_ERR) {
if (pd_retries < PD_MAX_RETRIES) {
pd_retries++;
return Wait;
}
return Fail;
}
pd_ide_command(pd_current, IDE_READ, pd_block, pd_run);
phase = do_pd_read_drq;
pd_timeout = jiffies + PD_TMO;
return Hold;
}
static enum action do_pd_write_start(void)
{
if (pd_wait_for(pd_current, STAT_READY, "do_pd_write") & STAT_ERR) {
if (pd_retries < PD_MAX_RETRIES) {
pd_retries++;
return Wait;
}
return Fail;
}
pd_ide_command(pd_current, IDE_WRITE, pd_block, pd_run);
while (1) {
if (pd_wait_for(pd_current, STAT_DRQ, "do_pd_write_drq") & STAT_ERR) {
if (pd_retries < PD_MAX_RETRIES) {
pd_retries++;
return Wait;
}
return Fail;
}
pi_write_block(pd_current->pi, pd_buf, 512);
if (pd_next_buf())
break;
}
phase = do_pd_write_done;
pd_timeout = jiffies + PD_TMO;
return Hold;
}
static inline int pd_ready(void)
{
return !(status_reg(pd_current) & STAT_BUSY);
}
static enum action do_pd_read_drq(void)
{
if (!pd_ready() && !time_after_eq(jiffies, pd_timeout))
return Hold;
while (1) {
if (pd_wait_for(pd_current, STAT_DRQ, "do_pd_read_drq") & STAT_ERR) {
if (pd_retries < PD_MAX_RETRIES) {
pd_retries++;
phase = do_pd_read_start;
return Wait;
}
return Fail;
}
pi_read_block(pd_current->pi, pd_buf, 512);
if (pd_next_buf())
break;
}
return Ok;
}
static enum action do_pd_write_done(void)
{
if (!pd_ready() && !time_after_eq(jiffies, pd_timeout))
return Hold;
if (pd_wait_for(pd_current, STAT_READY, "do_pd_write_done") & STAT_ERR) {
if (pd_retries < PD_MAX_RETRIES) {
pd_retries++;
phase = do_pd_write_start;
return Wait;
}
return Fail;
}
return Ok;
}
/* According to the ATA standard, the default CHS geometry should be
available following a reset. Some Western Digital drives come up
in a mode where only LBA addresses are accepted until the device
parameters are initialised.
*/
static void pd_init_dev_parms(struct pd_unit *disk)
{
pi_connect(disk->pi);
pd_wait_for(disk, 0, DBMSG("before init_dev_parms"));
pd_send_command(disk, disk->sectors, 0, disk->heads - 1, 0, 0,
IDE_INIT_DEV_PARMS);
udelay(300);
pd_wait_for(disk, 0, "Initialise device parameters");
pi_disconnect(disk->pi);
}
static void pd_doorlock(struct pd_unit *disk, int func)
{
pi_connect(disk->pi);
if (!(pd_wait_for(disk, STAT_READY, "Lock") & STAT_ERR)) {
pd_send_command(disk, 1, 0, 0, 0, 0, func);
pd_wait_for(disk, STAT_READY, "Lock done");
}
pi_disconnect(disk->pi);
}
static void pd_eject(struct pd_unit *disk)
{
pi_connect(disk->pi);
pd_wait_for(disk, 0, DBMSG("before unlock on eject"));
pd_send_command(disk, 1, 0, 0, 0, 0, IDE_DOORUNLOCK);
pd_wait_for(disk, 0, DBMSG("after unlock on eject"));
pd_wait_for(disk, 0, DBMSG("before eject"));
pd_send_command(disk, 0, 0, 0, 0, 0, IDE_EJECT);
pd_wait_for(disk, 0, DBMSG("after eject"));
pi_disconnect(disk->pi);
}
static void pd_media_check(struct pd_unit *disk)
{
int r;
pi_connect(disk->pi);
r = pd_wait_for(disk, STAT_READY, DBMSG("before media_check"));
if (!(r & STAT_ERR)) {
pd_send_command(disk, 1, 1, 0, 0, 0, IDE_READ_VRFY);
r = pd_wait_for(disk, STAT_READY, DBMSG("RDY after READ_VRFY"));
} else
disk->changed = 1; /* say changed if other error */
if (r & ERR_MC) {
disk->changed = 1;
pd_send_command(disk, 1, 0, 0, 0, 0, IDE_ACKCHANGE);
pd_wait_for(disk, STAT_READY, DBMSG("RDY after ACKCHANGE"));
pd_send_command(disk, 1, 1, 0, 0, 0, IDE_READ_VRFY);
r = pd_wait_for(disk, STAT_READY, DBMSG("RDY after VRFY"));
}
pi_disconnect(disk->pi);
}
static void pd_standby_off(struct pd_unit *disk)
{
pi_connect(disk->pi);
pd_wait_for(disk, 0, DBMSG("before STANDBY"));
pd_send_command(disk, 0, 0, 0, 0, 0, IDE_STANDBY);
pd_wait_for(disk, 0, DBMSG("after STANDBY"));
pi_disconnect(disk->pi);
}
static int pd_identify(struct pd_unit *disk)
{
int j;
char id[PD_ID_LEN + 1];
/* WARNING: here there may be dragons. reset() applies to both drives, /* WARNING: here there may be dragons. reset() applies to both drives,
but we call it only on probing the MASTER. This should allow most but we call it only on probing the MASTER. This should allow most
...@@ -715,6 +735,104 @@ static int pd_identify(struct pd_unit *disk) ...@@ -715,6 +735,104 @@ static int pd_identify(struct pd_unit *disk)
return 1; return 1;
} }
static void do_pd_request(request_queue_t * q)
{
if (pd_req)
return;
pd_req = elv_next_request(q);
if (!pd_req)
return;
schedule_fsm();
}
/* kernel glue structures */
static int pd_open(struct inode *inode, struct file *file)
{
struct pd_unit *disk = inode->i_bdev->bd_disk->private_data;
disk->access++;
if (disk->removable) {
pd_media_check(disk);
pd_doorlock(disk, IDE_DOORLOCK);
}
return 0;
}
static int pd_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct pd_unit *disk = inode->i_bdev->bd_disk->private_data;
struct hd_geometry *geo = (struct hd_geometry *) arg;
struct hd_geometry g;
switch (cmd) {
case CDROMEJECT:
if (disk->access == 1)
pd_eject(disk);
return 0;
case HDIO_GETGEO:
if (disk->alt_geom) {
g.heads = PD_LOG_HEADS;
g.sectors = PD_LOG_SECTS;
g.cylinders = disk->capacity / (g.heads * g.sectors);
} else {
g.heads = disk->heads;
g.sectors = disk->sectors;
g.cylinders = disk->cylinders;
}
g.start = get_start_sect(inode->i_bdev);
if (copy_to_user(geo, &g, sizeof(struct hd_geometry)))
return -EFAULT;
return 0;
default:
return -EINVAL;
}
}
static int pd_release(struct inode *inode, struct file *file)
{
struct pd_unit *disk = inode->i_bdev->bd_disk->private_data;
if (!--disk->access && disk->removable)
pd_doorlock(disk, IDE_DOORUNLOCK);
return 0;
}
static int pd_check_media(struct gendisk *p)
{
struct pd_unit *disk = p->private_data;
int r;
if (!disk->removable)
return 0;
pd_media_check(disk);
r = disk->changed;
disk->changed = 0;
return r;
}
static int pd_revalidate(struct gendisk *p)
{
struct pd_unit *disk = p->private_data;
if (pd_identify(disk))
set_capacity(p, disk->capacity);
else
set_capacity(p, 0);
return 0;
}
static struct block_device_operations pd_fops = {
.owner = THIS_MODULE,
.open = pd_open,
.release = pd_release,
.ioctl = pd_ioctl,
.media_changed = pd_check_media,
.revalidate_disk= pd_revalidate
};
static int pd_probe_drive(struct pd_unit *disk) static int pd_probe_drive(struct pd_unit *disk)
{ {
if (disk->drive == -1) { if (disk->drive == -1) {
...@@ -784,143 +902,6 @@ static int pd_detect(void) ...@@ -784,143 +902,6 @@ static int pd_detect(void)
return 0; return 0;
} }
/* The i/o request engine */
static int pd_ready(void)
{
return !(status_reg(pd_current) & STAT_BUSY);
}
static void do_pd_request(request_queue_t * q)
{
if (pd_req)
return;
pd_req = elv_next_request(q);
if (!pd_req)
return;
ps_set_intr();
}
static int pd_next_buf(void)
{
unsigned long saved_flags;
pd_count--;
pd_run--;
pd_buf += 512;
pd_block++;
if (!pd_run)
return 1;
if (pd_count)
return 0;
spin_lock_irqsave(&pd_lock, saved_flags);
end_request(pd_req, 1);
pd_count = pd_req->current_nr_sectors;
pd_buf = pd_req->buffer;
spin_unlock_irqrestore(&pd_lock, saved_flags);
return 0;
}
static enum action do_pd_io_start(void)
{
pd_block = pd_req->sector;
pd_run = pd_req->nr_sectors;
pd_count = pd_req->current_nr_sectors;
if (pd_block + pd_count > get_capacity(pd_req->rq_disk))
return Fail;
pd_cmd = rq_data_dir(pd_req);
pd_buf = pd_req->buffer;
pd_retries = 0;
if (pd_cmd == READ) {
return do_pd_read_start();
} else if (pd_cmd == WRITE) {
return do_pd_write_start();
} else
return Fail;
}
static enum action do_pd_read_start(void)
{
if (pd_wait_for(pd_current, STAT_READY, "do_pd_read") & STAT_ERR) {
if (pd_retries < PD_MAX_RETRIES) {
pd_retries++;
return Wait;
}
return Fail;
}
pd_ide_command(pd_current, IDE_READ, pd_block, pd_run);
phase = do_pd_read_drq;
ps_timeout = jiffies + PD_TMO;
return Hold;
}
static enum action do_pd_read_drq(void)
{
if (!pd_ready() && !time_after_eq(jiffies, ps_timeout))
return Hold;
while (1) {
if (pd_wait_for(pd_current, STAT_DRQ, "do_pd_read_drq") & STAT_ERR) {
if (pd_retries < PD_MAX_RETRIES) {
pd_retries++;
phase = do_pd_read_start;
return Wait;
}
return Fail;
}
pi_read_block(pd_current->pi, pd_buf, 512);
if (pd_next_buf())
break;
}
return Ok;
}
static enum action do_pd_write_start(void)
{
if (pd_wait_for(pd_current, STAT_READY, "do_pd_write") & STAT_ERR) {
if (pd_retries < PD_MAX_RETRIES) {
pd_retries++;
return Wait;
}
return Fail;
}
pd_ide_command(pd_current, IDE_WRITE, pd_block, pd_run);
while (1) {
if (pd_wait_for(pd_current, STAT_DRQ, "do_pd_write_drq") & STAT_ERR) {
if (pd_retries < PD_MAX_RETRIES) {
pd_retries++;
return Wait;
}
return Fail;
}
pi_write_block(pd_current->pi, pd_buf, 512);
if (pd_next_buf())
break;
}
phase = do_pd_write_done;
ps_timeout = jiffies + PD_TMO;
return Hold;
}
static enum action do_pd_write_done(void)
{
if (!pd_ready() && !time_after_eq(jiffies, ps_timeout))
return Hold;
if (pd_wait_for(pd_current, STAT_READY, "do_pd_write_done") & STAT_ERR) {
if (pd_retries < PD_MAX_RETRIES) {
pd_retries++;
phase = do_pd_write_start;
return Wait;
}
return Fail;
}
return Ok;
}
static int __init pd_init(void) static int __init pd_init(void)
{ {
if (disable) if (disable)
......
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