Commit 9bc1bce3 authored by Alexander Viro's avatar Alexander Viro Committed by James Bottomley

[PATCH] hd.c

	* switched to private queues
	* set ->queue and ->private_data
	* switched to use of ->bd_disk and ->rq_disk
	* folded recalibrate[] and special_op[] into hd_info[]
	* switched to passing pointers instead of indices
	* cleaned up
parent ac8fc838
......@@ -47,7 +47,7 @@
#include <asm/uaccess.h>
#define MAJOR_NR HD_MAJOR
#define DEVICE_NR(device) (minor(device)>>6)
#define QUEUE (&hd_queue)
#include <linux/blk.h>
#ifdef __arm__
......@@ -98,6 +98,7 @@
#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */
static spinlock_t hd_lock = SPIN_LOCK_UNLOCKED;
static struct request_queue hd_queue;
#define TIMEOUT_VALUE (6*HZ)
#define HD_DELAY 0
......@@ -113,9 +114,6 @@ static spinlock_t hd_lock = SPIN_LOCK_UNLOCKED;
static void recal_intr(void);
static void bad_rw_intr(void);
static char recalibrate[MAX_HD];
static char special_op[MAX_HD];
static int reset;
static int hd_error;
......@@ -126,6 +124,9 @@ static int hd_error;
*/
struct hd_i_struct {
unsigned int head,sect,cyl,wpcom,lzone,ctl;
int unit;
int recalibrate;
int special_op;
};
#ifdef HD_TYPE
......@@ -193,11 +194,12 @@ void __init hd_setup(char *str, int *ints)
static void dump_status (const char *msg, unsigned int stat)
{
char devc;
char *name = "hd?";
if (!blk_queue_empty(QUEUE))
name = CURRENT->rq_disk->disk_name;
devc = !blk_queue_empty(QUEUE) ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
#ifdef VERBOSE_ERRORS
printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
printk("%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
if (stat & BUSY_STAT) printk("Busy ");
if (stat & READY_STAT) printk("DriveReady ");
if (stat & WRERR_STAT) printk("WriteFault ");
......@@ -211,7 +213,7 @@ static void dump_status (const char *msg, unsigned int stat)
hd_error = 0;
} else {
hd_error = inb(HD_ERROR);
printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
printk("%s: %s: error=0x%02x { ", name, msg, hd_error & 0xff);
if (hd_error & BBD_ERR) printk("BadSector ");
if (hd_error & ECC_ERR) printk("UncorrectableError ");
if (hd_error & ID_ERR) printk("SectorIdNotFound ");
......@@ -228,12 +230,12 @@ static void dump_status (const char *msg, unsigned int stat)
printk("\n");
}
#else
printk("hd%c: %s: status=0x%02x.\n", devc, msg, stat & 0xff);
printk("%s: %s: status=0x%02x.\n", name, msg, stat & 0xff);
if ((stat & ERR_STAT) == 0) {
hd_error = 0;
} else {
hd_error = inb(HD_ERROR);
printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff);
printk("%s: %s: error=0x%02x.\n", name, msg, hd_error & 0xff);
}
#endif
}
......@@ -288,9 +290,14 @@ static int controller_ready(unsigned int drive, unsigned int head)
return 0;
}
static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
unsigned int head,unsigned int cyl,unsigned int cmd,
void (*intr_addr)(void))
static void hd_out(struct hd_i_struct *disk,
unsigned int nsect,
unsigned int sect,
unsigned int head,
unsigned int cyl,
unsigned int cmd,
void (*intr_addr)(void))
{
unsigned short port;
......@@ -300,19 +307,19 @@ static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
#endif
if (reset)
return;
if (!controller_ready(drive, head)) {
if (!controller_ready(disk->unit, head)) {
reset = 1;
return;
}
SET_HANDLER(intr_addr);
outb_p(hd_info[drive].ctl,HD_CMD);
outb_p(disk->ctl,HD_CMD);
port=HD_DATA;
outb_p(hd_info[drive].wpcom>>2,++port);
outb_p(disk->wpcom>>2,++port);
outb_p(nsect,++port);
outb_p(sect,++port);
outb_p(cyl,++port);
outb_p(cyl>>8,++port);
outb_p(0xA0|(drive<<4)|head,++port);
outb_p(0xA0|(disk->unit<<4)|head,++port);
outb_p(cmd,++port);
}
......@@ -361,9 +368,10 @@ static void reset_hd(void)
goto repeat;
}
if (++i < NR_HD) {
special_op[i] = recalibrate[i] = 1;
hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
struct hd_i_struct *disk = &hd_info[i];
disk->special_op = disk->recalibrate = 1;
hd_out(disk,disk->sect,disk->sect,disk->head-1,
disk->cyl,WIN_SPECIFY,&reset_hd);
if (reset)
goto repeat;
} else
......@@ -396,19 +404,18 @@ void unexpected_hd_interrupt(void)
*/
static void bad_rw_intr(void)
{
int dev;
if (blk_queue_empty(QUEUE))
return;
dev = DEVICE_NR(CURRENT->rq_dev);
if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
end_request(CURRENT, 0);
special_op[dev] = recalibrate[dev] = 1;
} else if (CURRENT->errors % RESET_FREQ == 0)
reset = 1;
else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
special_op[dev] = recalibrate[dev] = 1;
/* Otherwise just retry */
if (!blk_queue_empty(QUEUE)) {
struct request *req = CURRENT;
struct hd_i_struct *disk = req->rq_disk->private_data;
if (++req->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
end_request(req, 0);
disk->special_op = disk->recalibrate = 1;
} else if (req->errors % RESET_FREQ == 0)
reset = 1;
else if ((hd_error & TRK0_ERR) || req->errors % RECAL_FREQ == 0)
disk->special_op = disk->recalibrate = 1;
/* Otherwise just retry */
}
}
static inline int wait_DRQ(void)
......@@ -424,6 +431,7 @@ static inline int wait_DRQ(void)
static void read_intr(void)
{
struct request *req;
int i, retries = 100000;
do {
......@@ -440,19 +448,20 @@ static void read_intr(void)
hd_request();
return;
ok_to_read:
insw(HD_DATA,CURRENT->buffer,256);
CURRENT->sector++;
CURRENT->buffer += 512;
CURRENT->errors = 0;
i = --CURRENT->nr_sectors;
--CURRENT->current_nr_sectors;
req = CURRENT;
insw(HD_DATA,req->buffer,256);
req->sector++;
req->buffer += 512;
req->errors = 0;
i = --req->nr_sectors;
--req->current_nr_sectors;
#ifdef DEBUG
printk("hd%c: read: sector %ld, remaining = %ld, buffer=0x%08lx\n",
dev+'a', CURRENT->sector, CURRENT->nr_sectors,
(unsigned long) CURRENT->buffer+512));
printk("%s: read: sector %ld, remaining = %ld, buffer=%p\n",
req->rq_disk->disk_name, req->sector, req->nr_sectors,
req->buffer+512));
#endif
if (CURRENT->current_nr_sectors <= 0)
end_request(CURRENT, 1);
if (req->current_nr_sectors <= 0)
end_request(req, 1);
if (i > 0) {
SET_HANDLER(&read_intr);
return;
......@@ -468,6 +477,7 @@ static void read_intr(void)
static void write_intr(void)
{
struct request *req = CURRENT;
int i;
int retries = 100000;
......@@ -477,7 +487,7 @@ static void write_intr(void)
continue;
if (!OK_STATUS(i))
break;
if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
if ((req->nr_sectors <= 1) || (i & DRQ_STAT))
goto ok_to_write;
} while (--retries > 0);
dump_status("write_intr", i);
......@@ -485,15 +495,15 @@ static void write_intr(void)
hd_request();
return;
ok_to_write:
CURRENT->sector++;
i = --CURRENT->nr_sectors;
--CURRENT->current_nr_sectors;
CURRENT->buffer += 512;
if (!i || (CURRENT->bio && !SUBSECTOR(i)))
end_request(CURRENT, 1);
req->sector++;
i = --req->nr_sectors;
--req->current_nr_sectors;
req->buffer += 512;
if (!i || (req->bio && req->current_nr_sectors <= 0))
end_request(req, 1);
if (i > 0) {
SET_HANDLER(&write_intr);
outsw(HD_DATA,CURRENT->buffer,256);
outsw(HD_DATA,req->buffer,256);
local_irq_enable();
} else {
#if (HD_DELAY > 0)
......@@ -519,7 +529,7 @@ static void recal_intr(void)
*/
static void hd_times_out(unsigned long dummy)
{
unsigned int dev;
char *name;
do_hd = NULL;
......@@ -529,11 +539,11 @@ static void hd_times_out(unsigned long dummy)
disable_irq(HD_IRQ);
local_irq_enable();
reset = 1;
dev = DEVICE_NR(CURRENT->rq_dev);
printk("hd%c: timeout\n", dev+'a');
name = CURRENT->rq_disk->disk_name;
printk("%s: timeout\n", name);
if (++CURRENT->errors >= MAX_ERRORS) {
#ifdef DEBUG
printk("hd%c: too many errors\n", dev+'a');
printk("%s: too many errors\n", name);
#endif
end_request(CURRENT, 0);
}
......@@ -542,18 +552,18 @@ static void hd_times_out(unsigned long dummy)
enable_irq(HD_IRQ);
}
int do_special_op (unsigned int dev)
int do_special_op(struct hd_i_struct *disk, struct request *req)
{
if (recalibrate[dev]) {
recalibrate[dev] = 0;
hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
if (disk->recalibrate) {
disk->recalibrate = 0;
hd_out(disk,disk->sect,0,0,0,WIN_RESTORE,&recal_intr);
return reset;
}
if (hd_info[dev].head > 16) {
printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
end_request(CURRENT, 0);
if (disk->head > 16) {
printk ("%s: cannot handle device with more than 16 heads - giving up\n", req->rq_disk->disk_name);
end_request(req, 0);
}
special_op[dev] = 0;
disk->special_op = 0;
return 1;
}
......@@ -569,7 +579,9 @@ int do_special_op (unsigned int dev)
*/
static void hd_request(void)
{
unsigned int dev, block, nsect, sec, track, head, cyl;
unsigned int block, nsect, sec, track, head, cyl;
struct hd_i_struct *disk;
struct request *req;
if (do_hd)
return;
......@@ -581,62 +593,58 @@ static void hd_request(void)
do_hd = NULL;
return;
}
req = CURRENT;
if (reset) {
local_irq_disable();
reset_hd();
return;
}
dev = DEVICE_NR(CURRENT->rq_dev);
block = CURRENT->sector;
nsect = CURRENT->nr_sectors;
if (dev >= NR_HD) {
printk("hd: bad disk number: %d\n", dev);
end_request(CURRENT, 0);
goto repeat;
}
if (block >= get_capacity(hd_gendisk[dev]) ||
((block+nsect) > get_capacity(hd_gendisk[dev]))) {
disk = req->rq_disk->private_data;
block = req->sector;
nsect = req->nr_sectors;
if (block >= get_capacity(req->rq_disk) ||
((block+nsect) > get_capacity(req->rq_disk))) {
printk("%s: bad access: block=%d, count=%d\n",
hd_gendisk[dev]->disk_name, block, nsect);
end_request(CURRENT, 0);
req->rq_disk->disk_name, block, nsect);
end_request(req, 0);
goto repeat;
}
if (special_op[dev]) {
if (do_special_op(dev))
if (disk->special_op) {
if (do_special_op(disk, req))
goto repeat;
return;
}
sec = block % hd_info[dev].sect + 1;
track = block / hd_info[dev].sect;
head = track % hd_info[dev].head;
cyl = track / hd_info[dev].head;
sec = block % disk->sect + 1;
track = block / disk->sect;
head = track % disk->head;
cyl = track / disk->head;
#ifdef DEBUG
printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx\n",
dev+'a', (CURRENT->cmd == READ)?"read":"writ",
cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);
printk("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=%p\n",
req->rq_disk->disk_name, (req->cmd == READ)?"read":"writ",
cyl, head, sec, nsect, req->buffer);
#endif
if(CURRENT->flags & REQ_CMD) {
switch (rq_data_dir(CURRENT)) {
if (req->flags & REQ_CMD) {
switch (rq_data_dir(req)) {
case READ:
hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
hd_out(disk,nsect,sec,head,cyl,WIN_READ,&read_intr);
if (reset)
goto repeat;
break;
case WRITE:
hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
hd_out(disk,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
if (reset)
goto repeat;
if (wait_DRQ()) {
bad_rw_intr();
goto repeat;
}
outsw(HD_DATA,CURRENT->buffer,256);
outsw(HD_DATA,req->buffer,256);
break;
default:
printk("unknown hd-command\n");
end_request(CURRENT, 0);
end_request(req, 0);
break;
}
}
......@@ -652,29 +660,19 @@ static void do_hd_request (request_queue_t * q)
static int hd_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
struct hd_i_struct *disk = inode->i_bdev->bd_disk->private_data;
struct hd_geometry *loc = (struct hd_geometry *) arg;
int dev;
struct hd_geometry g;
if ((!inode) || kdev_none(inode->i_rdev))
if (cmd != HDIO_GETGEO)
return -EINVAL;
dev = DEVICE_NR(inode->i_rdev);
if (dev >= NR_HD)
if (!loc)
return -EINVAL;
switch (cmd) {
case HDIO_GETGEO:
{
struct hd_geometry g;
if (!loc) return -EINVAL;
g.heads = hd_info[dev].head;
g.sectors = hd_info[dev].sect;
g.cylinders = hd_info[dev].cyl;
g.start = get_start_sect(inode->i_bdev);
return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0;
}
default:
return -EINVAL;
}
g.heads = disk->head;
g.sectors = disk->sect;
g.cylinders = disk->cyl;
g.start = get_start_sect(inode->i_bdev);
return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0;
}
/*
......@@ -715,11 +713,11 @@ static int __init hd_init(void)
printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
return -1;
}
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_hd_request, &hd_lock);
blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 255);
blk_init_queue(&hd_queue, do_hd_request, &hd_lock);
blk_queue_max_sectors(&hd_queue, 255);
init_timer(&device_timer);
device_timer.function = hd_times_out;
blk_queue_hardsect_size(QUEUE, 512);
blk_queue_hardsect_size(&hd_queue, 512);
#ifdef __i386__
if (!NR_HD) {
......@@ -792,22 +790,21 @@ static int __init hd_init(void)
for (drive=0 ; drive < NR_HD ; drive++) {
struct gendisk *disk = alloc_disk(64);
struct hd_i_struct *p = &hd_info[drive];
if (!disk)
goto Enomem;
disk->major = MAJOR_NR;
disk->first_minor = drive << 6;
disk->fops = &hd_fops;
sprintf(disk->disk_name, "hd%c", 'a'+drive);
disk->private_data = p;
set_capacity(disk, p->head * p->sect * p->cyl);
disk->queue = &hd_queue;
p->unit = drive;
hd_gendisk[drive] = disk;
}
for (drive=0 ; drive < NR_HD ; drive++) {
sector_t size = hd_info[drive].head *
hd_info[drive].sect * hd_info[drive].cyl;
set_capacity(hd_gendisk[drive], size);
printk ("%s: %ldMB, CHS=%d/%d/%d\n",
hd_gendisk[drive]->disk_name,
size / 2048, hd_info[drive].cyl,
hd_info[drive].head, hd_info[drive].sect);
printk ("%s: %luMB, CHS=%d/%d/%d\n",
disk->disk_name, (unsigned long)get_capacity(disk)/2048,
p->cyl, p->head, p->sect);
}
if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
......@@ -824,11 +821,10 @@ static int __init hd_init(void)
goto out3;
}
for(drive=0; drive < NR_HD; drive++) {
struct hd_i_struct *p = hd_info + drive;
set_capacity(hd_gendisk[drive], p->head * p->sect * p->cyl);
/* Let them fly */
for(drive=0; drive < NR_HD; drive++)
add_disk(hd_gendisk[drive]);
}
return 0;
out3:
......@@ -842,7 +838,7 @@ static int __init hd_init(void)
out:
del_timer(&device_timer);
unregister_blkdev(MAJOR_NR,"hd");
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
blk_cleanup_queue(&hd_queue);
return -1;
Enomem:
while (drive--)
......
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