--- linux/kernel/blk_drv/hd.c 2018/04/24 18:06:41 1.1.1.6 +++ linux/kernel/blk_drv/hd.c 2018/04/24 18:09:57 1.1.1.8 @@ -24,6 +24,8 @@ #include #include #include + +#define REALLY_SLOW_IO #include #include #include @@ -37,6 +39,8 @@ static inline unsigned char CMOS_READ(un return inb_p(0x71); } +#define HD_DELAY 0 + /* Max read/write errors/sector */ #define MAX_ERRORS 7 #define MAX_HD 2 @@ -47,6 +51,10 @@ static void bad_rw_intr(void); static int recalibrate = 0; static int reset = 0; +#if (HD_DELAY > 0) +unsigned long last_req, read_timer(); +#endif + /* * This struct defines the HD's and their types. */ @@ -125,7 +133,7 @@ static void extended_partition(unsigned current_minor, hd[current_minor].start_sect, hd[current_minor].nr_sects, hd[current_minor].start_sect + - hd[current_minor].nr_sects); + hd[current_minor].nr_sects - 1); current_minor++; p++; /* @@ -171,7 +179,7 @@ static void check_partition(unsigned int hd[minor].start_sect = first_sector + p->start_sect; printk(" part %d start %d size %d end %d \n\r", i, hd[minor].start_sect, hd[minor].nr_sects, - hd[minor].start_sect + hd[minor].nr_sects); + hd[minor].start_sect + hd[minor].nr_sects - 1); if ((current_minor & 0x3f) >= 60) continue; if (p->sys_ind == EXTENDED_PARTITION) { @@ -196,7 +204,7 @@ static void check_partition(unsigned int hd[current_minor].start_sect, hd[current_minor].nr_sects, hd[current_minor].start_sect + - hd[current_minor].nr_sects); + hd[current_minor].nr_sects - 1); } } } else @@ -276,6 +284,22 @@ int sys_setup(void * BIOS) return (0); } +#if (HD_DELAY > 0) +unsigned long read_timer(void) +{ + unsigned long t; + int i; + + cli(); + outb_p(0xc2, 0x43); + t = jiffies * 11931 + (inb_p(0x40) & 0x80 ? 5966 : 11932); + i = inb_p(0x40); + i |= inb(0x40) << 8; + sti(); + return(t - i / 2); +} +#endif + static int controller_ready(void) { int retries = 100000; @@ -308,6 +332,10 @@ static void hd_out(unsigned int drive,un if (drive>1 || head>15) panic("Trying to write bad sector"); +#if (HD_DELAY > 0) + while (read_timer() - last_req < HD_DELAY) + /* nothing */; +#endif if (reset || !controller_ready()) { reset = 1; return; @@ -321,7 +349,7 @@ static void hd_out(unsigned int drive,un outb_p(cyl,++port); outb_p(cyl>>8,++port); outb_p(0xA0|(drive<<4)|head,++port); - outb(cmd,++port); + outb_p(cmd,++port); } static int drive_busy(void) @@ -343,6 +371,7 @@ static void reset_controller(void) { int i; + printk("HD-controller reset\r\n"); outb(4,HD_CMD); for(i = 0; i < 1000; i++) nop(); outb(hd_info[0].ctl & 0x0f ,HD_CMD); @@ -397,48 +426,82 @@ static void bad_rw_intr(void) return; if (++CURRENT->errors >= MAX_ERRORS) end_request(0); - if (CURRENT->errors > MAX_ERRORS/2) + else if (CURRENT->errors > MAX_ERRORS/2) reset = 1; else recalibrate = 1; } +#define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT) +#define STAT_OK (READY_STAT | SEEK_STAT) + static void read_intr(void) { - SET_INTR(&read_intr); - if (win_result()) { - SET_INTR(NULL); - bad_rw_intr(); - do_hd_request(); - return; - } + int i; + + i = (unsigned) inb_p(HD_STATUS); + if (!(i & DRQ_STAT)) + goto bad_read; + if ((i & STAT_MASK) != STAT_OK) + goto bad_read; port_read(HD_DATA,CURRENT->buffer,256); + i = (unsigned) inb_p(HD_STATUS); + if (!(i & BUSY_STAT)) + if ((i & STAT_MASK) != STAT_OK) + goto bad_read; CURRENT->errors = 0; CURRENT->buffer += 512; CURRENT->sector++; - if (--CURRENT->nr_sectors) + i = --CURRENT->nr_sectors; + if (!i || (CURRENT->bh && !(i&1))) + end_request(1); + if (i > 0) { + SET_INTR(&read_intr); return; - SET_INTR(NULL); - end_request(1); + } +#if (HD_DELAY > 0) + last_req = read_timer(); +#endif + do_hd_request(); + return; +bad_read: + if (i & ERR_STAT) + i = (unsigned) inb(HD_ERROR); + bad_rw_intr(); do_hd_request(); + return; } static void write_intr(void) { - if (win_result()) { - bad_rw_intr(); - do_hd_request(); - return; - } - if (--CURRENT->nr_sectors) { - CURRENT->sector++; - CURRENT->buffer += 512; + int i; + + i = (unsigned) inb_p(HD_STATUS); + if ((i & STAT_MASK) != STAT_OK) + goto bad_write; + if (CURRENT->nr_sectors > 1 && !(i & DRQ_STAT)) + goto bad_write; + CURRENT->sector++; + i = --CURRENT->nr_sectors; + CURRENT->buffer += 512; + if (!i || (CURRENT->bh && !(i & 1))) + end_request(1); + if (i > 0) { SET_INTR(&write_intr); port_write(HD_DATA,CURRENT->buffer,256); - return; + } else { +#if (HD_DELAY > 0) + last_req = read_timer(); +#endif + do_hd_request(); } - end_request(1); + return; +bad_write: + if (i & ERR_STAT) + i = (unsigned) inb(HD_ERROR); + bad_rw_intr(); do_hd_request(); + return; } static void recal_intr(void) @@ -476,7 +539,7 @@ static void do_hd_request(void) dev = MINOR(CURRENT->dev); block = CURRENT->sector; nsect = CURRENT->nr_sectors; - if (dev >= (NR_HD<<6) || block+nsect > hd[dev].nr_sects) { + if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) { end_request(0); goto repeat; } @@ -494,8 +557,7 @@ static void do_hd_request(void) } if (recalibrate) { recalibrate = 0; - hd_out(dev,hd_info[dev].sect,0,0,0, - WIN_RESTORE,&recal_intr); + hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr); if (reset) goto repeat; return; @@ -519,27 +581,20 @@ static void do_hd_request(void) panic("unknown hd-command"); } -void hd_init(void) -{ - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; - set_intr_gate(0x2E,&hd_interrupt); - outb_p(inb_p(0x21)&0xfb,0x21); - outb(inb_p(0xA1)&0xbf,0xA1); - timer_table[HD_TIMER].fn = hd_times_out; -} - -int hd_ioctl(int dev, int cmd, int arg) +static int hd_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned int arg) { struct hd_geometry *loc = (void *) arg; + int dev; - if (!loc) + if (!loc || !inode) return -EINVAL; - dev = MINOR(dev) >> 6; + dev = MINOR(inode->i_rdev) >> 6; if (dev >= NR_HD) return -EINVAL; - switch (cmd) { case HDIO_REQ: + verify_area(loc, sizeof(*loc)); put_fs_byte(hd_info[dev].head, (char *) &loc->heads); put_fs_byte(hd_info[dev].sect, @@ -551,3 +606,33 @@ int hd_ioctl(int dev, int cmd, int arg) return -EINVAL; } } + +/* + * Releasing a block device means we sync() it, so that it can safely + * be forgotten about... + */ +static void hd_release(struct inode * inode, struct file * file) +{ + sync_dev(inode->i_rdev); +} + +static struct file_operations hd_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + hd_ioctl, /* ioctl */ + NULL, /* no special open code */ + hd_release /* release */ +}; + +void hd_init(void) +{ + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blkdev_fops[MAJOR_NR] = &hd_fops; + set_intr_gate(0x2E,&hd_interrupt); + outb_p(inb_p(0x21)&0xfb,0x21); + outb(inb_p(0xA1)&0xbf,0xA1); + timer_table[HD_TIMER].fn = hd_times_out; +}