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