patch-1.3.23 linux/drivers/block/ide.c
Next file: linux/drivers/block/ide.h
Previous file: linux/drivers/block/ide-cd.c
Back to the patch index
Back to the overall index
- Lines: 480
- Date:
Sun Sep 3 12:03:00 1995
- Orig file:
v1.3.22/linux/drivers/block/ide.c
- Orig date:
Sun Sep 3 12:26:51 1995
diff -u --recursive --new-file v1.3.22/linux/drivers/block/ide.c linux/drivers/block/ide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide.c Version 5.11 Aug 29, 1995
+ * linux/drivers/block/ide.c Version 5.12 Sep 1, 1995
*
* Copyright (C) 1994, 1995 Linus Torvalds & authors (see below)
*/
@@ -130,15 +130,24 @@
* added automatic PCI CMD640 detection/support
* added option for VLB CMD640 support
* tweaked probe to find cdrom on hdb with disks on hda,hdc
+ * Version 5.12 some performance tuning
+ * added message to alert user to bad /dev/hd[cd] entries
+ * OOOPS! fixed bug in atapi reset
+ * driver now forces "serialize" again for all cmd640 chips
+ * noticed REALLY_SLOW_IO had no effect, moved it to ide.c
+ * made do_drive_cmd() into public ide_do_drive_cmd()
*
* Driver compile-time options are in ide.h
*
* To do, in likely order of completion:
- * - improved CMD support: probably handing this off to someone else
+ * - add ioctls to get/set interface timings on cmd640, ht6560b, triton
* - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
+ * - improved CMD support: probably handing this off to someone else
* - find someone to work on IDE *tape drive* support
*/
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+
#include <linux/config.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -156,6 +165,7 @@
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/segment.h>
+#include <asm/io.h>
#ifdef CONFIG_PCI
#include <linux/bios32.h>
@@ -239,7 +249,7 @@
/* fill in any non-zero initial values */
hwif->noprobe = (h > 1);
hwif->io_base = default_io_base[h];
- hwif->ctl_port = hwif->io_base ? hwif->io_base + 0x206 : 0x000;
+ hwif->ctl_port = hwif->io_base ? hwif->io_base+0x206 : 0x000;
#ifdef CONFIG_BLK_DEV_HD
if (hwif->io_base == HD_DATA)
hwif->noprobe = 1; /* may be overriden by ide_setup() */
@@ -268,7 +278,6 @@
}
}
-#ifdef __i386__
#define VLB_SYNC 1
/*
* Some localbus EIDE interfaces require a special access sequence
@@ -278,34 +287,32 @@
* to ensure that the reads all happen together.
*/
static inline void do_vlb_sync (unsigned short port) {
- unsigned int _v;
- __asm__ __volatile__ (
- "inb %w1,%b0\n\t"
- "inb %w1,%b0\n\t"
- "inb %w1,%b0"
- : "=&a" (_v) /* outputs */
- : "d" (port) ); /* inputs */
+ (void) inb (port);
+ (void) inb (port);
+ (void) inb (port);
}
-#endif /* __i386__ */
/*
* This is used for most PIO data transfers *from* the IDE interface
*/
void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
+ unsigned short io_base = HWIF(drive)->io_base;
+ unsigned short data_reg = io_base+IDE_DATA_OFFSET;
+
if (drive->vlb_32bit) {
#ifdef VLB_SYNC
if (drive->vlb_sync) {
cli();
- do_vlb_sync(IDE_NSECTOR_REG);
- insl(IDE_DATA_REG, buffer, wcount);
+ do_vlb_sync(io_base+IDE_NSECTOR_OFFSET);
+ insl(data_reg, buffer, wcount);
if (drive->unmask)
sti();
} else
#endif /* VLB_SYNC */
- insl(IDE_DATA_REG, buffer, wcount);
+ insl(data_reg, buffer, wcount);
} else
- insw(IDE_DATA_REG, buffer, wcount<<1);
+ insw(data_reg, buffer, wcount<<1);
}
/*
@@ -313,19 +320,22 @@
*/
void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
+ unsigned short io_base = HWIF(drive)->io_base;
+ unsigned short data_reg = io_base+IDE_DATA_OFFSET;
+
if (drive->vlb_32bit) {
#ifdef VLB_SYNC
if (drive->vlb_sync) {
cli();
- do_vlb_sync(IDE_NSECTOR_REG);
- outsl(IDE_DATA_REG, buffer, wcount);
+ do_vlb_sync(io_base+IDE_NSECTOR_OFFSET);
+ outsl(data_reg, buffer, wcount);
if (drive->unmask)
sti();
} else
#endif /* VLB_SYNC */
- outsl(IDE_DATA_REG, buffer, wcount);
+ outsl(data_reg, buffer, wcount);
} else
- outsw(IDE_DATA_REG, buffer, wcount<<1);
+ outsw(data_reg, buffer, wcount<<1);
}
#if SUPPORT_HT6560B
@@ -677,8 +687,8 @@
if (!drive->keep_settings)
drive->unmask = 0;
OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+ udelay (20);
OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
- udelay (10);
hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE;
start_reset_timer (hwif); /* begin periodic polling */
restore_flags (flags);
@@ -851,12 +861,10 @@
err = ide_dump_status(drive, msg, stat);
if ((rq = HWGROUP(drive)->rq) == NULL || drive == NULL)
return 0;
-#ifdef IDE_DRIVE_CMD
if (rq->cmd == IDE_DRIVE_CMD) { /* never retry an explicit DRIVE_CMD */
end_drive_cmd(drive, stat, err);
return 0;
}
-#endif /* IDE_DRIVE_CMD */
if (stat & BUSY_STAT) { /* other bits are useless when BUSY */
rq->errors |= ERROR_RESET;
} else {
@@ -1105,7 +1113,6 @@
IDE_DO_REQUEST;
}
-#ifdef IDE_DRIVE_CMD
/*
* drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
*/
@@ -1120,7 +1127,6 @@
return;
IDE_DO_REQUEST;
}
-#endif /* IDE_DRIVE_CMD */
/*
* do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
@@ -1175,26 +1181,28 @@
int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
{
byte stat;
+ unsigned long flags;
+test:
+ udelay(1); /* spec allows drive 400ns to change "BUSY" */
+ if (OK_STAT((stat = GET_STAT()), good, bad))
+ return 0; /* fast exit for most frequent case */
+ if (!(stat & BUSY_STAT)) {
+ (void) ide_error(drive, "status error", stat);
+ return 1;
+ }
- udelay(1); /* spec allows drive 400ns to assert "BUSY" */
- if (GET_STAT() & BUSY_STAT) {
- unsigned long flags;
- save_flags(flags);
- sti();
- timeout += jiffies;
- while (GET_STAT() & BUSY_STAT) {
- if (jiffies > timeout) {
- restore_flags(flags);
- (void) ide_error(drive, "status timeout", GET_STAT());
- return 1;
- }
+ save_flags(flags);
+ sti();
+ timeout += jiffies;
+ do {
+ if (!((stat = GET_STAT()) & BUSY_STAT)) {
+ restore_flags(flags);
+ goto test;
}
- restore_flags(flags);
- udelay(1); /* spec allows 400ns for status to stabilize */
- }
- if (OK_STAT(stat=GET_STAT(), good, bad))
- return 0;
- (void) ide_error(drive, "status error", stat);
+ } while (jiffies <= timeout);
+
+ restore_flags(flags);
+ (void) ide_error(drive, "status timeout", GET_STAT());
return 1;
}
@@ -1205,28 +1213,30 @@
*/
static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
{
+ unsigned short io_base = HWIF(drive)->io_base;
+
OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
- OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG);
+ OUT_BYTE(rq->nr_sectors,io_base+IDE_NSECTOR_OFFSET);
if (drive->select.b.lba) {
#ifdef DEBUG
printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
drive->name, (rq->cmd==READ)?"read":"writ",
block, rq->nr_sectors, (unsigned long) rq->buffer);
#endif
- OUT_BYTE(block,IDE_SECTOR_REG);
- OUT_BYTE(block>>=8,IDE_LCYL_REG);
- OUT_BYTE(block>>=8,IDE_HCYL_REG);
- OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
+ OUT_BYTE(block,io_base+IDE_SECTOR_OFFSET);
+ OUT_BYTE(block>>=8,io_base+IDE_LCYL_OFFSET);
+ OUT_BYTE(block>>=8,io_base+IDE_HCYL_OFFSET);
+ OUT_BYTE(((block>>8)&0x0f)|drive->select.all,io_base+IDE_SELECT_OFFSET);
} else {
unsigned int sect,head,cyl,track;
track = block / drive->sect;
sect = block % drive->sect + 1;
- OUT_BYTE(sect,IDE_SECTOR_REG);
+ OUT_BYTE(sect,io_base+IDE_SECTOR_OFFSET);
head = track % drive->head;
cyl = track / drive->head;
- OUT_BYTE(cyl,IDE_LCYL_REG);
- OUT_BYTE(cyl>>8,IDE_HCYL_REG);
- OUT_BYTE(head|drive->select.all,IDE_SELECT_REG);
+ OUT_BYTE(cyl,io_base+IDE_LCYL_OFFSET);
+ OUT_BYTE(cyl>>8,io_base+IDE_HCYL_OFFSET);
+ OUT_BYTE(head|drive->select.all,io_base+IDE_SELECT_OFFSET);
#ifdef DEBUG
printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n",
drive->name, (rq->cmd==READ)?"read":"writ", cyl,
@@ -1239,7 +1249,7 @@
return;
#endif /* CONFIG_BLK_DEV_TRITON */
ide_set_handler(drive, &read_intr);
- OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
+ OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, io_base+IDE_COMMAND_OFFSET);
return;
}
if (rq->cmd == WRITE) {
@@ -1247,7 +1257,7 @@
if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
return;
#endif /* CONFIG_BLK_DEV_TRITON */
- OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
+ OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, io_base+IDE_COMMAND_OFFSET);
if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
printk("%s: no DRQ after issuing %s\n", drive->name,
drive->mult_count ? "MULTWRITE" : "WRITE");
@@ -1265,13 +1275,12 @@
}
return;
}
-#ifdef IDE_DRIVE_CMD
if (rq->cmd == IDE_DRIVE_CMD) {
byte *args = rq->buffer;
if (args) {
printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x\n",
drive->name, args[0], args[1], args[2]);
- OUT_BYTE(args[2],IDE_FEATURE_REG);
+ OUT_BYTE(args[2],io_base+IDE_FEATURE_OFFSET);
ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
return;
} else {
@@ -1286,7 +1295,6 @@
return;
}
}
-#endif /* IDE_DRIVE_CMD */
printk("%s: bad command: %d\n", drive->name, rq->cmd);
ide_end_request(0, HWGROUP(drive));
}
@@ -1574,6 +1582,10 @@
ide_drive_t *drive = &hwif->drives[unit];
if (drive->present)
return drive;
+ } else if (major == IDE0_MAJOR && unit < 4) {
+ printk("ide: probable bad entry for /dev/hd%c%d\n",
+ 'a' + unit, MINOR(i_rdev) & PARTN_MASK);
+ printk("ide: to fix it, run: /usr/src/linux/drivers/block/MAKEDEV.ide\n");
}
break;
}
@@ -1581,14 +1593,13 @@
return NULL;
}
-#ifdef IDE_DRIVE_CMD
/*
* This function issues a specific IDE drive command onto the
* tail of the request queue, and waits for it to be completed.
* If arg is NULL, it goes through all the motions,
* but without actually sending a command to the drive.
*/
-static int do_drive_cmd(int rdev, char *args)
+int ide_do_drive_cmd(int rdev, char *args)
{
unsigned long flags;
unsigned int major = MAJOR(rdev);
@@ -1626,7 +1637,6 @@
restore_flags(flags);
return rq.errors ? -EIO : 0; /* return -EIO if errors */
}
-#endif /* IDE_DRIVE_CMD */
static int ide_open(struct inode * inode, struct file * filp)
{
@@ -1646,13 +1656,9 @@
return ide_cdrom_open (inode, filp, drive);
#endif /* CONFIG_BLK_DEV_IDECD */
if (drive->removeable) {
- check_disk_change(inode->i_rdev);
-#ifdef IDE_DRIVE_CMD
- {
byte door_lock[] = {WIN_DOORLOCK,0,0,0};
- do_drive_cmd(inode->i_rdev, door_lock);
- }
-#endif /* IDE_DRIVE_CMD */
+ check_disk_change(inode->i_rdev);
+ ide_do_drive_cmd(inode->i_rdev, door_lock);
}
return 0;
}
@@ -1674,13 +1680,9 @@
else
#endif /* CONFIG_BLK_DEV_IDECD */
if (drive->removeable) {
- invalidate_buffers(inode->i_rdev);
-#ifdef IDE_DRIVE_CMD
- {
byte door_unlock[] = {WIN_DOORUNLOCK,0,0,0};
- do_drive_cmd(inode->i_rdev, door_unlock);
- }
-#endif /* IDE_DRIVE_CMD */
+ invalidate_buffers(inode->i_rdev);
+ ide_do_drive_cmd(inode->i_rdev, door_unlock);
}
}
}
@@ -1876,10 +1878,7 @@
drive->mult_req = arg;
drive->special.b.set_multmode = 1;
restore_flags(flags);
-#ifndef IDE_DRIVE_CMD
- return 0;
-#else
- do_drive_cmd (inode->i_rdev, NULL);
+ ide_do_drive_cmd (inode->i_rdev, NULL);
return (drive->mult_count == arg) ? 0 : -EIO;
case HDIO_DRIVE_CMD:
@@ -1887,20 +1886,19 @@
unsigned long args;
if (NULL == (long *) arg)
- err = do_drive_cmd(inode->i_rdev,NULL);
+ err = ide_do_drive_cmd(inode->i_rdev,NULL);
else {
if (!(err = verify_area(VERIFY_READ,(long *)arg,sizeof(long))))
{
args = get_user((long *)arg);
if (!(err = verify_area(VERIFY_WRITE,(long *)arg,sizeof(long)))) {
- err = do_drive_cmd(inode->i_rdev,(char *)&args);
+ err = ide_do_drive_cmd(inode->i_rdev,(char *)&args);
put_user(args,(long *)arg);
}
}
}
return err;
}
-#endif /* IDE_DRIVE_CMD */
RO_IOCTLS(inode->i_rdev, arg);
@@ -2398,7 +2396,8 @@
byte reg;
unsigned short port = 0x178;
- printk("ide: buggy CMD640 interface: ");
+ single_threaded = 1;
+ printk("ide: buggy CMD640 interface: serialized, ");
reg = read_cmd640_vlb(port, 0x50);
if (reg == 0xff || (reg & 0x90) != 0x90) {
#if TRY_CMD640_VLB_AT_0x78
@@ -2406,9 +2405,8 @@
if (reg == 0xff || (reg & 0x90) != 0x90)
#endif
{
- single_threaded = 1;
disallow_unmask = 1;
- printk("(probe failed) serialized, disabled unmasking\n");
+ printk("(probe failed) disabled unmasking\n");
return;
}
}
@@ -2578,8 +2576,14 @@
#if SUPPORT_HT6560B
case -4: /* "ht6560b" */
if (hw > 1) goto bad_hwif;
- ide_hwifs[0].select = 0x1c;
- ide_hwifs[1].select = 0x1d;
+ /*
+ * Using 0x1c and 0x1d apparently selects a
+ * faster interface speed than 0x3c and 0x3d.
+ *
+ * Need to add an ioctl to select between them.
+ */
+ ide_hwifs[0].select = 0x3c;
+ ide_hwifs[1].select = 0x3d;
goto do_serialize;
#endif /* SUPPORT_HT6560B */
#if SUPPORT_DTC2278
@@ -2752,7 +2756,7 @@
restore_flags(flags); /* safe now that hwif->hwgroup is set up */
printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name,
- hwif->io_base, hwif->io_base + 7, hwif->ctl_port, hwif->irq);
+ hwif->io_base, hwif->io_base+7, hwif->ctl_port, hwif->irq);
if (hwgroup->hwif != hwif) {
char *name = hwgroup->hwif->name;
if (hwgroup->hwif->irq == hwif->irq)
@@ -2818,12 +2822,13 @@
int rc;
unsigned char reg;
+ single_threaded = 1;
printk("ide: buggy CMD640 interface: ");
if ((rc = pcibios_read_config_byte(bus, fn, 0x51, ®))
|| (rc = pcibios_write_config_byte(bus, fn, 0x51, reg | 0xc8)))
buggy_interface_fallback (rc);
else
- printk("disabled read-ahead, enabled secondary\n");
+ printk("serialized, disabled read-ahead, enabled secondary\n");
}
#endif /* SUPPORT_CMD640 */
@@ -2840,8 +2845,6 @@
byte fn, bus;
int rc;
- if (!pcibios_present())
- return;
save_flags(flags);
cli();
for (index = 0; !pcibios_find_device (vendor, device, index, &bus, &fn); ++index) {
@@ -2892,7 +2895,8 @@
/*
* Find/initialize PCI IDE interfaces
*/
- ide_init_pci ();
+ if (pcibios_present())
+ ide_init_pci ();
#endif /* CONFIG_PCI */
/*
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this