lkml.org 
[lkml]   [1996]   [Jul]   [31]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
SubjectCMD640 Code: need beta testers before submission!
Date
Michael Meskes wrote:
>
> On my office machine (with cmd640 chip) 2.0.10 doesn't boot.

This is a common problem with all 2.0.xx kernels, it seems.

When we fix the driver for some folks, it breaks for others.
The "F-ing SUN blows me" has nothing on this screwed-up design!

There is hope. I have now taken over development of cmd640.c,
and the latest version (below) is working successfully for many
of the folks who have had problems in the past.

If you have a CMD640 IDE interface, then *PLEASE* give this patch a try.
We need to get this thing working for *everyone* before submitting
to Linus for 2.0.whatever.

If you do NOT include CMD640 support in your kernels, then you are
running a very real risk of severe filesystem/memory corruption
(this could explain some of the mysterious kernel panics reported here).
This device is buggy as hell, and will experience data corruption
under a variety of common circumstances, including using multiplemode,
using more than one drive, using the floppy disk at the same time, etc.

The CMD640 kernel support is designed to eliminate all possibility
of data corruption due to this chip. In the past, the authors tried
to make it too fancy, and introduced even more troubles. With this
update, I am trying to simplify it again.

Please try out this new code two ways:

1. as-is.
2. with kernel boot parameters: ide0=autotune ide1=autotune

And report to me (email) exactly what you observe, including the
kernel boot up messages.

Thanks a million!

-ml
the Linux IDE guy
diff -u --recursive --new-file --exclude=.* linux-2.0.10/drivers/block/cmd640.c linux/drivers/block/cmd640.c
--- linux-2.0.10/drivers/block/cmd640.c Sat Jul 27 11:36:40 1996
+++ linux/drivers/block/cmd640.c Wed Jul 31 07:50:24 1996
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/cmd640.c Version 0.13 Jul 23, 1996
+ * linux/drivers/block/cmd640.c Version 0.91 Jul 31, 1996
*
* Copyright (C) 1995-1996 Linus Torvalds & authors (see below)
*/
@@ -7,8 +7,8 @@
/*
* Original author: abramov@cecmow.enet.dec.com (Igor Abramov)
*
- * Maintained by: s0033las@sun10.vsz.bme.hu (Laszlo Peter)
- * mlord@pobox.com (Mark Lord)
+ * Maintained by: mlord@pobox.com (Mark Lord)
+ * with fanatic support from a legion of hackers!
*
* This file provides support for the advanced features and bugs
* of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
@@ -17,7 +17,7 @@
* to work on every motherboard design that uses this screwed chip seems
* bloody well impossible. However, we're still trying.
*
- * We think version 0.12 should work for most folks.
+ * We think version 0.90 should work for most folks.
* User feedback is essential.
*
*
@@ -62,6 +62,12 @@
* try to be even smarter about the second port. -lp
* tidy up source code formatting. -ml
* Version 0.13 permit irq unmasking again. -ml
+ * Version 0.90 massive code cleanup, some bugs fixed. -ml
+ * defaults all drives to PIO mode0, readahead off. -ml
+ * autotune is OFF by default, with compile time flag. -ml
+ * readahead can be turned OFF/ON using "hdparm -p8/-p9"
+ * (requires hdparm-3.1 or newer)
+ * Version 0.91 first release to linux-kernel list. -ml
*/

#undef REALLY_SLOW_IO /* most systems can safely undef this */
@@ -79,6 +85,8 @@
#include "ide_modes.h"

#define PARANOID_ABOUT_CMD640 1 /* used to tag superstitious code */
+#define AUTOCONF_READAHEAD 0 /* default used to be 1 */
+#define AUTOCONF_PIOMODE 0 /* default used to be 1 */

int cmd640_vlb = 0;

@@ -120,8 +128,8 @@
#define ARTTIM1 0x55
#define DRWTIM1 0x56
#define ARTTIM23 0x57
-#define DIS_RA2 0x04
-#define DIS_RA3 0x08
+#define ARTTIM23_DIS_RA2 0x04
+#define ARTTIM23_DIS_RA3 0x08
#define DRWTIM23 0x58
#define BRST 0x59

@@ -135,7 +143,6 @@
static int bus_type = none;
static int cmd640_chip_version;
static int cmd640_key;
-static int bus_speed; /* MHz */

/*
* The CMD640x chip does not support DWORD config write cycles, but some
@@ -231,6 +238,10 @@
{
long id;
int k;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();

for (k = 0x80000000; k <= 0x8000f800; k += 0x800) {
outl(k, 0xcf8);
@@ -240,8 +251,10 @@
put_cmd640_reg = put_cmd640_reg_pci1;
get_cmd640_reg = get_cmd640_reg_pci1;
cmd640_key = k;
+ restore_flags(flags);
return 1;
}
+ restore_flags(flags);
return 0;
}

@@ -254,6 +267,10 @@
int i;
int v_id;
int d_id;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();

for (i = 0xc000; i <= 0xcf00; i += 0x100) {
outb(0x10, 0xcf8);
@@ -265,8 +282,10 @@
put_cmd640_reg = put_cmd640_reg_pci2;
get_cmd640_reg = get_cmd640_reg_pci2;
cmd640_key = i;
+ restore_flags(flags);
return 1;
}
+ restore_flags(flags);
return 0;
}

@@ -276,84 +295,74 @@

static int probe_for_cmd640_vlb(void) {
byte b;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();

outb(CFR, 0x178);
b = inb(0x17c);
if (b == 0xff || b == 0 || (b & CFR_AT_VESA_078h)) {
outb(CFR, 0x78);
b = inb(0x7c);
- if (b == 0xff || b == 0 || !(b & CFR_AT_VESA_078h))
+ if (b == 0xff || b == 0 || !(b & CFR_AT_VESA_078h)) {
+ restore_flags(flags);
return 0;
+ }
cmd640_key = 0x70;
} else {
cmd640_key = 0x170;
}
put_cmd640_reg = put_cmd640_reg_vlb;
get_cmd640_reg = get_cmd640_reg_vlb;
+ restore_flags(flags);
return 1;
}

-#if 0
-/*
- * Low level reset for controller, actually it has nothing specific for
- * CMD640, but I don't know how to use standard reset routine before
- * we recognized any drives.
- */
-static void cmd640_reset_controller(int iface_no)
-{
- int retry_count = 600;
- int base_port = iface_no ? 0x170 : 0x1f0;
-
- outb_p(4, base_port + 7);
- udelay(5);
- outb_p(0, base_port + 7);
-
- do {
- udelay(5);
- retry_count -= 1;
- } while ((inb_p(base_port + 7) & 0x80) && retry_count);
-
- if (retry_count == 0)
- printk("cmd640: failed to reset controller %d\n", iface_no);
-}
-#endif /* 0 */
-
/*
* Returns 1 if an IDE interface/drive exists at 0x170,
* Returns 0 otherwise.
*/
static int secondary_port_responding (void)
{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
/*
* Test for hardware at 0x170 (secondary IDE port).
*/
- outb_p(0xa0, 0x170 + IDE_SELECT_OFFSET); /* select drive0 */
+ outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET); /* select drive0 */
udelay(100);
- if (inb_p(0x170 + IDE_SELECT_OFFSET) != 0xa0) {
- outb_p(0xb0, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
+ if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) {
+ outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
udelay(100);
- if (inb_p(0x170 + IDE_SELECT_OFFSET) != 0xb0)
+ if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
+ restore_flags(flags);
return 0; /* nothing is there */
+ }
}
+ restore_flags(flags);
return 1; /* something is there */
}

/*
* Probe for Cmd640x and initialize it if found
*/
-
-int ide_probe_for_cmd640x(void)
+int ide_probe_for_cmd640x (void)
{
int second_port_toggled = 0;
int second_port_cmd640 = 0;
byte b;
+ const char *msg;
+ unsigned long flags;

if (probe_for_cmd640_pci1()) {
bus_type = pci1;
} else if (probe_for_cmd640_pci2()) {
bus_type = pci2;
} else if (cmd640_vlb && probe_for_cmd640_vlb()) {
- /* May be remove cmd640_vlb at all, and probe in any case */
+ /* Maybe get rid of cmd640_vlb, and always probe? */
bus_type = vlb;
} else {
return 0;
@@ -363,22 +372,23 @@
ide_hwifs[0].serialized = 1; /* ensure this *always* gets set */
ide_hwifs[1].serialized = 1; /* ensure this *always* gets set */
#endif
-
#if 0
/* Dump initial state of chip registers */
+ printk("ide: cmd640 initial register dump:\n");
for (b = 0; b != 0xff; b++) {
printk(" %2x%c", get_cmd640_reg(b),
((b&0xf) == 0xf) ? '\n' : ',');
}
#endif
-
+ save_flags(flags);
+ cli();
/*
- * Undocumented magic. (There is no 0x5b port in specs)
+ * Undocumented magic. (There is no 0x5b reg in specs)
*/
-
put_cmd640_reg(0x5b, 0xbd);
if (get_cmd640_reg(0x5b) != 0xbd) {
- printk("ide: can't initialize cmd640 -- wrong value in 0x5b\n");
+ restore_flags(flags);
+ printk("ide: cmd640 init failed: wrong value in reg 0x5b\n");
return 0;
}
put_cmd640_reg(0x5b, 0);
@@ -386,33 +396,25 @@
/*
* Documented magic.
*/
-
cmd640_chip_version = get_cmd640_reg(CFR) & CFR_DEVREV;
if (cmd640_chip_version == 0) {
- printk ("ide: wrong CMD640 version -- 0\n");
+ restore_flags(flags);
+ printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
return 0;
}

/*
- * Setup the most conservative timings for all drives,
+ * Set up the most conservative timings for all drives,
+ * and disable readahead for drives at the secondary interface.
*/
-
put_cmd640_reg(CMDTIM, 0);
-
- put_cmd640_reg(ARTTIM0, 0xc0);
- put_cmd640_reg(ARTTIM1, 0xc0);
- put_cmd640_reg(ARTTIM23, 0xcc); /* disable read-ahead for drives 2&3 */
-
+ put_cmd640_reg(ARTTIM0, get_cmd640_reg(ARTTIM0) | 0xc0);
put_cmd640_reg(DRWTIM0, 0);
+ put_cmd640_reg(ARTTIM1, get_cmd640_reg(ARTTIM1) | 0xc0);
put_cmd640_reg(DRWTIM1, 0);
+ put_cmd640_reg(ARTTIM23, get_cmd640_reg(ARTTIM23) | 0xcc);
put_cmd640_reg(DRWTIM23, 0);
-
- /*
- * Set the maximum allowed bus speed (it is safest until we
- * find how to detect bus speed)
- * Normally PCI bus runs at 33MHz, but often works overclocked to 40
- */
- bus_speed = (bus_type == vlb) ? 50 : 40;
+ put_cmd640_reg(BRST, 0x40);

/*
* Setup Control Register
@@ -420,49 +422,41 @@
b = get_cmd640_reg(CNTRL);

/*
- * Disable readahead for drives at primary interface
+ * Disable readahead for drives at the primary interface
*/
b |= (CNTRL_DIS_RA0 | CNTRL_DIS_RA1);
put_cmd640_reg(CNTRL, b);

if (!ide_hwifs[1].noprobe) {
-
if (secondary_port_responding()) {
-
if ((b & CNTRL_ENA_2ND) || (bus_type == vlb))
second_port_cmd640 = 1;
-
- } else if (!(b & CNTRL_ENA_2ND) && (bus_type != vlb)) {
-
- second_port_toggled = 1;
- put_cmd640_reg(CNTRL, b | CNTRL_ENA_2ND); /* Enable second interface */
-
- if (secondary_port_responding())
+ } else {
+ put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
+ if (secondary_port_responding()) {
+ second_port_toggled = 1;
second_port_cmd640 = 1;
- else {
- second_port_toggled = 0;
- put_cmd640_reg(CNTRL, b); /* Disable second interface */
+ } else {
+ put_cmd640_reg(CNTRL, b); /* restore original setting */
}
}
}

/*
- * Note that we assume that the first interface is at 0x1f0,
- * and that the second interface, if enabled, is at 0x170.
+ * Note that we assume that the first interface is ide0,
+ * and that the second interface, if enabled, is ide1.
*/
ide_hwifs[0].chipset = ide_cmd640;
ide_hwifs[0].tuneproc = &cmd640_tune_drive;
-#if 0
- ide_hwifs[0].no_unmask = 1;
-#endif
-
+#if AUTOCONF_PIOMODE
if (ide_hwifs[0].drives[0].autotune == 0)
ide_hwifs[0].drives[0].autotune = 1;
if (ide_hwifs[0].drives[1].autotune == 0)
ide_hwifs[0].drives[1].autotune = 1;
+#endif /* AUTOCONF_PIOMODE */

/*
- * Initialize 2nd IDE port, if required
+ * Configure data structs for second port, if enabled
*/
if (second_port_cmd640) {

@@ -470,99 +464,64 @@
ide_hwifs[0].serialized = 1;
ide_hwifs[1].serialized = 1;
#endif
-
- ide_hwifs[1].chipset = ide_cmd640;
+ ide_hwifs[1].chipset = ide_cmd640;
ide_hwifs[1].tuneproc = &cmd640_tune_drive;
-#if 0
- ide_hwifs[1].no_unmask = 1;
-#endif
+#if AUTOCONF_PIOMODE
if (ide_hwifs[1].drives[0].autotune == 0)
ide_hwifs[1].drives[0].autotune = 1;
if (ide_hwifs[1].drives[1].autotune == 0)
ide_hwifs[1].drives[1].autotune = 1;
-
-#if 0
- /* reset the secondary interface */
- cmd640_reset_controller(1);
-#endif
- }
-
- printk("ide: buggy CMD640%c interface on ",
- 'A' - 1 + cmd640_chip_version);
- switch (bus_type) {
- case vlb :
- printk("vlb (0x%x)", cmd640_key);
- break;
- case pci1:
- printk("pci (0x%x)", cmd640_key);
- break;
- case pci2:
- printk("pci (access method 2) (0x%x)", cmd640_key);
- break;
+#endif /* AUTOCONF_PIOMODE */
}
+ restore_flags(flags);

/*
- * Tell everyone what we did to their system
- */
- printk(":%s serialized, second port %s\n",
- second_port_cmd640 ? "" : " not",
- second_port_toggled ? "toggled" : "untouched");
- return 1;
-}
-
-#if 0 /* not used anywhere */
-int cmd640_off(void) {
- static int a = 0;
- byte b;
-
- if (bus_type == none || a == 1)
- return 0;
- a = 1;
- b = get_cmd640_reg(CNTRL);
- b &= ~CNTRL_ENA_2ND;
- put_cmd640_reg(CNTRL, b);
+ * Tell everyone what we found & did with it:
+ */
+ switch (bus_type) {
+ case pci1: msg = "pci1"; break;
+ case pci2: msg = "pci2"; break;
+ default: msg = "vlb" ; break;
+ }
+ printk("ide: buggy cmd640%c interface on %s, %sserialized, secondary interface %s\n",
+ 'A' + cmd640_chip_version - 1, msg, ide_hwifs[0].serialized ? "" : "not ",
+ second_port_toggled ? "toggled" : "already enabled");
return 1;
}
-#endif /* 0 */

/*
- * Sets readahead mode for specific drive
- * in the future it could be called from ioctl
+ * Sets readahead mode for a drive.
*/
-
-static void set_readahead_mode(ide_drive_t* drive, int mode)
+static void set_readahead_mode (ide_drive_t *drive, int mode)
{
- static int masks[2][2] =
- {
- {CNTRL_DIS_RA0, CNTRL_DIS_RA1},
- {DIS_RA2, DIS_RA3}
- };
byte b;
+ static byte masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
+ ide_hwif_t *hwif = HWIF(drive);
+ int interface = (hwif->io_base == 0x170);
+ int index = (interface << 1) + drive->select.b.unit;
+ int reg = interface ? ARTTIM23 : CNTRL;
+ unsigned long flags;

- int interface_number = HWIF(drive)->index;
- int drive_number = drive->select.b.unit;
-
- int port = (interface_number == 0) ? CNTRL : ARTTIM23;
- int mask = masks[interface_number][drive_number];
-
- b = get_cmd640_reg(port);
-
- /*
- * I don't know why it is necessary, but without this my machine
- * locks up, if bus_speed is not correct. And it even allows me
- * to use 32 bit transfers on the primary port (hdparm -c1).
- */
- if ((interface_number == 0) && mode)
- b|=0x27;
-
+ save_flags(flags);
+ cli();
+ b = get_cmd640_reg(reg);
if (mode)
- b &= ~mask; /* Enable readahead for specific drive */
+ b &= ~masks[index]; /* Enable readahead for specific drive */
else
- b |= mask; /* Disable readahead for specific drive */
-
- put_cmd640_reg(port, b);
+ b |= masks[index]; /* Disable readahead for specific drive */
+ put_cmd640_reg(reg, b);
+ if (mode) {
+ hwif->no_unmask = 1;
+ hwif->drives[0].unmask = 0;
+ hwif->drives[1].unmask = 0;
+ } else {
+ hwif->no_unmask = 0;
+ }
+ restore_flags(flags);
+ printk("%s: %sabled cmd640 read-ahead\n", drive->name, mode ? "en" : "dis");
}

+#if AUTOCONF_READAHEAD
static const struct readahead_black_list {
const char* name;
int mode;
@@ -597,243 +556,192 @@
}
return -1;
}
+#endif /* AUTOCONF_READAHEAD */

-static int arttim[4] = {2, 2, 2, 2}; /* Address setup count (in clocks) */
-static int a_count[4] = {1, 1, 1, 1}; /* Active count (encoded) */
-static int r_count[4] = {1, 1, 1, 1}; /* Recovery count (encoded) */
+static byte setup_counts[4] = {4, 4, 4, 4}; /* Address setup count (in clocks) */
+static byte active_counts[4] = {16, 16, 16, 16}; /* Active count (encoded) */
+static byte recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */

/*
* Convert address setup count from number of clocks
* to representation used by controller
*/

-inline static int pack_arttim(int clocks)
+inline static int encode_setup_count (int clocks)
{
- if (clocks <= 2) return 0x40;
- else if (clocks == 3) return 0x80;
- else if (clocks == 4) return 0x00;
- else return 0xc0;
+ switch (clocks) {
+ case 4: return 0x00;
+ case 3: return 0x80;
+ case 2: return 0x40;
+ case 5:
+ default: return 0xc0;
+ }
}

/*
* Pack active and recovery counts into single byte representation
* used by controller
*/
-
-inline static int pack_counts(int act_count, int rec_count)
+inline static byte pack_nibbles (byte upper, byte lower)
{
- return ((act_count & 0x0f)<<4) | (rec_count & 0x0f);
+ return ((upper & 0x0f) << 4) | (lower & 0x0f);
}

-inline int max(int a, int b) { return a > b ? a : b; }
-inline int max4(int *p) { return max(p[0], max(p[1], max(p[2], p[3]))); }
-
/*
- * Set timing parameters
+ * Set a specific pio_mode for a drive
*/
-
-static void cmd640_set_timing(int if_num, int dr_num)
+static void cmd640_set_mode (ide_drive_t *drive, byte pio_mode, unsigned int cycle_time)
{
- int b_reg;
- int ac, rc, at;
- byte b;
+ int unit = drive->select.b.unit;
+ int interface = (HWIF(drive)->io_base == 0x170);
+ int index = (interface << 1) + unit;
+ int setup_time, active_time, recovery_time, clock_time;
+ byte setup_count, active_count, recovery_count, recovery_count2, cycle_count;
+ byte arttim_reg, drwtim_reg;
+ unsigned long flags;
+
+ if (pio_mode > 5)
+ pio_mode = 5;
+ setup_time = ide_pio_timings[pio_mode].setup_time;
+ active_time = ide_pio_timings[pio_mode].active_time;
+ recovery_time = cycle_time - (setup_time + active_time);
+ clock_time = 1000 / ide_system_bus_speed();
+ cycle_count = (cycle_time + clock_time - 1) / clock_time;
+
+ setup_count = (setup_time + clock_time - 1) / clock_time;
+
+ active_count = (active_time + clock_time - 1) / clock_time;
+ if (active_count < 2)
+ active_count = 2; /* minimum allowed by cmd640 */
+
+ recovery_count = (recovery_time + clock_time - 1) / clock_time;
+ recovery_count2 = cycle_count - (setup_count + active_count);
+ if (recovery_count2 > recovery_count)
+ recovery_count = recovery_count2;
+ if (recovery_count < 2)
+ recovery_count = 2; /* minimum allowed by cmd640 */
+ if (recovery_count > 17) {
+ active_count += recovery_count - 17;
+ recovery_count = 17;
+ }
+ if (active_count > 16)
+ active_count = 16; /* maximum allowed by cmd640 */
+ if (cmd640_chip_version > 1)
+ recovery_count -= 1; /* cmd640b uses (count + 1)*/
+ if (recovery_count > 16)
+ recovery_count = 16; /* maximum allowed by cmd640 */
+
+ setup_counts[index] = setup_count;
+ active_counts[index] = active_count;
+ recovery_counts[index] = recovery_count;
+
+ /*
+ * In a perfect world, we might set the drive pio mode here
+ * (using WIN_SETFEATURE) before continuing.
+ *
+ * But we do not, because:
+ * 1) this is the wrong place to do it (proper is do_special() in ide.c)
+ * 2) in practice it is not (seldom?) necessary to do so.
+ */

/*
- * Set address setup count and drive read/write timing registers.
+ * Set up address setup count and drive read/write timing registers.
* Primary interface has individual count/timing registers for
- * each drive. Secondary interface has common set of registers, and
- * we should set timings for the slowest drive.
+ * each drive. Secondary interface has one common set of registers,
+ * so we merge the timings, using the slowest of the two for each timing.
*/

- if (if_num == 0) {
- b_reg = dr_num ? ARTTIM1 : ARTTIM0;
- at = arttim[dr_num];
- ac = a_count[dr_num];
- rc = r_count[dr_num];
- b = pack_arttim(at);
+ if (index <= 1) {
+ arttim_reg = unit ? ARTTIM1 : ARTTIM0;
+ drwtim_reg = unit ? DRWTIM1 : DRWTIM0;
} else {
- b_reg = ARTTIM23;
- at = max(arttim[2], arttim[3]);
- ac = max(a_count[2], a_count[3]);
- rc = max(r_count[2], r_count[3]);
-
- /*
- * Protect the readahead bits
- */
- b = pack_arttim(at) | (get_cmd640_reg(ARTTIM23) & (DIS_RA2 | DIS_RA3));
+ arttim_reg = ARTTIM23;
+ drwtim_reg = DRWTIM23;
+ if (HWIF(drive)->drives[unit ^ 1].present) {
+ int mate = index ^ 1;
+ if (setup_count < setup_counts[mate])
+ setup_count = setup_counts[mate];
+ if (active_count < active_counts[mate])
+ active_count = active_counts[mate];
+ if (recovery_count < recovery_counts[mate])
+ recovery_count = recovery_counts[mate];
+ }
}

- put_cmd640_reg(b_reg, b);
- put_cmd640_reg(b_reg + 1, pack_counts(ac, rc));
-
+ save_flags (flags);
+ cli();
/*
- * Update CMDTIM (IDE Command Block Timing Register)
+ * Program the address_setup clocks into ARTTIM reg,
+ * and then the active/recovery counts into the DRWTIM reg
+ * (this converts counts of 16 into counts of zero -- okay).
*/
-
- ac = max4(a_count);
- rc = max4(r_count);
- put_cmd640_reg(CMDTIM, pack_counts(ac, rc));
+ put_cmd640_reg(arttim_reg, encode_setup_count(setup_count) | (get_cmd640_reg(arttim_reg) & 0x3f));
+ put_cmd640_reg(drwtim_reg, pack_nibbles(active_count, recovery_count));
+#if 0
+ /*
+ * Assume that the command block registers can be accessed
+ * as fast as the slowest drive data port of the four drives.
+ *
+ * This is not a 100% valid assumption. According to ATA2 specifications,
+ * as drives are only required to provide fast access to the data port.
+ * Many other IDE interface chips use slow access to the command block.
+ */
+#define max4(p) { max(p[0], max(p[1], max(p[2], p[3]))); }
+ active_count = max4(active_count);
+ recovery_count = max4(recovery_count);
+ put_cmd640_reg(CMDTIM, pack_nibbles(active_count, recovery_count));
+#else
+ /*
+ * Ensure compatibility by always using the slowest timings
+ * for access to the drive's command register block.
+ */
+ put_cmd640_reg(CMDTIM, 0);
+#endif
+ restore_flags(flags);
}

/*
- * Standard timings for PIO modes
+ * Drive PIO mode selection:
*/
-
-static const struct pio_timing {
- int mc_time; /* Address setup (ns) min */
- int av_time; /* Active pulse (ns) min */
- int ds_time; /* Cycle time (ns) min = Active pulse + Recovery pulse */
-} pio_timings[6] = {
- { 70, 165, 600 }, /* PIO Mode 0 */
- { 50, 125, 383 }, /* PIO Mode 1 */
- { 30, 100, 240 }, /* PIO Mode 2 */
- { 30, 80, 180 }, /* PIO Mode 3 w/IORDY */
- { 25, 70, 125 }, /* PIO Mode 4 w/IORDY -- should be 120, not 125 */
- { 20, 50, 100 } /* PIO Mode 5 w/IORDY (nonstandard) */
-};
-
-static void cmd640_timings_to_clocks(int mc_time, int av_time, int ds_time,
- int clock_time, int drv_idx)
+static void cmd640_tune_drive (ide_drive_t *drive, byte mode_wanted)
{
- int a, b;
-
- arttim[drv_idx] = (mc_time + clock_time - 1)/clock_time;
-
- a = (av_time + clock_time - 1)/clock_time;
- if (a < 2)
- a = 2;
- b = (ds_time + clock_time - 1)/clock_time - a;
- if (b < 2)
- b = 2;
- if (b > 0x11) {
- a += b - 0x11;
- b = 0x11;
- }
- if (a > 0x10)
- a = 0x10;
- if (cmd640_chip_version > 1)
- b -= 1;
- if (b > 0x10)
- b = 0x10;
-
- a_count[drv_idx] = a;
- r_count[drv_idx] = b;
-}
-
-static void set_pio_mode(int if_num, int drv_num, int mode_num) {
- int p_base;
- int i;
-
- p_base = if_num ? 0x170 : 0x1f0;
-
- outb_p(3, p_base + IDE_FEATURE_OFFSET);
- outb_p(mode_num | 0x08, p_base + IDE_NSECTOR_OFFSET);
- outb_p((drv_num | 0x0a) << 4, p_base + IDE_SELECT_OFFSET);
- outb_p(WIN_SETFEATURES, p_base + IDE_COMMAND_OFFSET);
-
- for (i = 0; (i < 100) && (inb(p_base + IDE_STATUS_OFFSET) & BUSY_STAT); i++)
- udelay(10000);
-}
-
-/*
- * Set a specific pio_mode for a drive
- */
-
-static void cmd640_set_mode(ide_drive_t* drive, byte pio_mode, int ds_time) {
- int interface_number;
- int drive_number;
- int clock_time; /* ns */
- int mc_time, av_time;
-
- if (pio_mode > 5) return;
-
- interface_number = HWIF(drive)->index;
- drive_number = drive->select.b.unit;
- clock_time = 1000/bus_speed;
-
- mc_time = pio_timings[pio_mode].mc_time;
- av_time = pio_timings[pio_mode].av_time;
- ds_time = (ds_time != 0) ? ds_time : pio_timings[pio_mode].ds_time;
-
- cmd640_timings_to_clocks(mc_time, av_time, ds_time, clock_time,
- interface_number*2 + drive_number);
- set_pio_mode(interface_number, drive_number, pio_mode);
- cmd640_set_timing(interface_number, drive_number);
-}
+ ide_pio_data_t d;

-/*
- * Drive PIO mode "autoconfiguration".
- */
-
-static void cmd640_tune_drive(ide_drive_t *drive, byte pio_mode) {
- int max_pio;
- int ds_time;
- int readahead; /* there is a global named read_ahead */
- int overridden;
- int iordy;
- struct hd_driveid* id;
-
- if (pio_mode != 255) {
- cmd640_set_mode(drive, pio_mode, 0);
+ /*
+ * If the user asks for pio_mode 9 (no such mode),
+ * we take it to mean "turn ON readahead" for this drive.
+ *
+ * If the user asks for pio_mode 8 (no such mode),
+ * we take it to mean "turn OFF readahead" for this drive.
+ */
+ if ((mode_wanted & 0xfe) == 0x08) { /* program readahead? */
+ set_readahead_mode(drive, mode_wanted & 1);
return;
}

- overridden = 0;
- iordy = 0;
- id = drive->id;
-
- if ((max_pio = ide_scan_pio_blacklist(id->model)) != -1) {
- ds_time = pio_timings[max_pio].ds_time;
- overridden = 1;
- iordy = (max_pio > 2);
- } else {
- max_pio = id->tPIO;
- ds_time = pio_timings[max_pio].ds_time;
- if (id->field_valid & 2) {
- if ((id->capability & 8) && (id->eide_pio_modes & 7)) {
- if (id->eide_pio_modes & 4) max_pio = 5;
- else if (id->eide_pio_modes & 2) max_pio = 4;
- else max_pio = 3;
- ds_time = id->eide_pio_iordy;
- iordy = 1;
- } else {
- ds_time = id->eide_pio;
- }
- if (ds_time == 0) {
- ds_time = pio_timings[max_pio].ds_time;
- iordy = (max_pio > 2);
- }
- }
-
+#if AUTOCONF_READAHEAD
+ if (mode_wanted == 255) {
+ int readahead = 0;
/*
- * Conservative "downgrade"
+ * Autoconfig the cmd640 readahead mode
*/
- if (max_pio < 4 && max_pio != 0) {
- max_pio--;
- overridden = 1;
- iordy = (max_pio > 2);
- ds_time = pio_timings[max_pio].ds_time;
+ if (cmd640_chip_version > 1) {
+ readahead = known_drive_readahead(drive->id->model);
+ if (readahead == -1)
+ readahead = 1;
}
- }
-
- cmd640_set_mode(drive, max_pio, ds_time);
-
- /*
- * Disable (or set) readahead mode
- */
-
- readahead = 0;
- if (cmd640_chip_version > 1) { /* Mmmm.. probably should be > 2 ?? */
- readahead = known_drive_readahead(id->model);
- if (readahead == -1)
- readahead = 1; /* Mmmm.. probably be 0 ?? */
set_readahead_mode(drive, readahead);
}
+#endif /* AUTOCONF_READAHEAD */

- printk ("Drive Timing: PIO Mode %d (%dns) %s/IORDY%s, Read-ahead: %s\n",
- max_pio,
- ds_time,
- iordy ? "w" : "wo",
- overridden ? " (overriding vendor mode)" : "",
- readahead ? "enabled" : "disabled");
+ (void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+ cmd640_set_mode (drive, d.pio_mode, d.cycle_time);
+
+ printk ("%s: selected cmd640 PIO mode%d (%dns) %s/IORDY%s\n",
+ drive->name,
+ d.pio_mode,
+ d.cycle_time,
+ d.use_iordy ? "w" : "wo",
+ d.overridden ? " (overriding vendor mode)" : "");
}
+
diff -u --recursive --new-file --exclude=.* linux-2.0.10/drivers/block/ali14xx.c linux/drivers/block/ali14xx.c
--- linux-2.0.10/drivers/block/ali14xx.c Fri Jul 26 17:48:14 1996
+++ linux/drivers/block/ali14xx.c Tue Jul 30 00:13:33 1996
@@ -51,20 +51,6 @@
#include "ide.h"
#include "ide_modes.h"

-/*
- * This should be set to the system's local bus (PCI or VLB) speed,
- * e.g., 33 for a 486DX33 or 486DX2/66. Legal values are anything
- * from 25 to 50. Setting this too *low* will make the EIDE
- * controller unable to communicate with the disks.
- *
- * The value is 50 by default -- this should work ok with any system.
- * (Low values cause problems because it multiplies by bus speed
- * to get cycles, and thus gets a too-small cycle count and tries to
- * access the disks too fast. I tried this once under DOS and it locked
- * up the system.) -- derekn@vw.ece.cmu.edu
- */
-#define ALI_14xx_BUS_SPEED 50 /* PCI / VLB bus speed */
-
/* port addresses for auto-detection */
#define ALI_NUM_PORTS 4
static int ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4};
@@ -82,15 +68,7 @@
{0x35, 0x03}, {0x00, 0x00}
};

-/* default timing parameters for each PIO mode */
#define ALI_MAX_PIO 4
-static struct { int time1, time2; } timeTab[ALI_MAX_PIO+1] = {
- {600, 165}, /* PIO 0 */
- {383, 125}, /* PIO 1 */
- {240, 100}, /* PIO 2 */
- {180, 80}, /* PIO 3 */
- {120, 70} /* PIO 4 */
-};

/* timing parameter registers for each drive */
static struct { byte reg1, reg2, reg3, reg4; } regTab[4] = {
@@ -134,26 +112,18 @@
static void ali14xx_tune_drive (ide_drive_t *drive, byte pio)
{
int driveNum;
- int time1, time2, time1a;
+ int time1, time2;
byte param1, param2, param3, param4;
- struct hd_driveid *id = drive->id;
unsigned long flags;
+ ide_pio_data_t d;

- if (pio == 255)
- pio = ide_get_best_pio_mode(drive);
- if (pio > ALI_MAX_PIO)
- pio = ALI_MAX_PIO;
+ pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);

/* calculate timing, according to PIO mode */
- time1 = timeTab[pio].time1;
- time2 = timeTab[pio].time2;
- if (pio >= 3) {
- time1a = (id->capability & 0x08) ? id->eide_pio_iordy : id->eide_pio;
- if (time1a != 0 && time1a < time1)
- time1 = time1a;
- }
- param3 = param1 = (time2 * ALI_14xx_BUS_SPEED + 999) / 1000;
- param4 = param2 = (time1 * ALI_14xx_BUS_SPEED + 999) / 1000 - param1;
+ time1 = d.cycle_time;
+ time2 = ide_pio_timings[pio].active_time;
+ param3 = param1 = (time2 * ide_system_bus_speed() + 999) / 1000;
+ param4 = param2 = (time1 * ide_system_bus_speed() + 999) / 1000 - param1;
if (pio < 3) {
param3 += 8;
param4 += 8;
diff -u --recursive --new-file --exclude=.* linux-2.0.10/drivers/block/dtc2278.c linux/drivers/block/dtc2278.c
--- linux-2.0.10/drivers/block/dtc2278.c Fri Jul 26 17:48:14 1996
+++ linux/drivers/block/dtc2278.c Tue Jul 30 00:16:10 1996
@@ -71,8 +71,7 @@
{
unsigned long flags;

- if (pio == 255)
- pio = ide_get_best_pio_mode(drive);
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);

if (pio >= 3) {
save_flags(flags);
diff -u --recursive --new-file --exclude=.* linux-2.0.10/drivers/block/ht6560b.c linux/drivers/block/ht6560b.c
--- linux-2.0.10/drivers/block/ht6560b.c Fri Apr 12 02:49:32 1996
+++ linux/drivers/block/ht6560b.c Tue Jul 30 00:18:17 1996
@@ -201,10 +201,8 @@
if (drive->media != ide_disk)
pio = 0; /* some cdroms don't like fast modes (?) */
else
- pio = ide_get_best_pio_mode (drive);
+ pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
}
- if (pio > 5)
- pio = 5;
unit = drive->select.b.unit;
hwif = HWIF(drive)->index;
ht6560b_timings[hwif][unit] = pio_to_timings[pio];
diff -u --recursive --new-file --exclude=.* linux-2.0.10/drivers/block/ide.c linux/drivers/block/ide.c
--- linux-2.0.10/drivers/block/ide.c Sat Jul 27 11:36:40 1996
+++ linux/drivers/block/ide.c Tue Jul 30 21:13:11 1996
@@ -246,6 +246,7 @@
* include mc68000 patches from Geert Uytterhoeven
* add Gadi's fix for PCMCIA cdroms
* Version 5.46 remove the mc68000 #ifdefs for 2.0.x
+ * Version 4.57 tidy up tuneproc invocations
*
* Some additional driver compile-time options are in ide.h
*
@@ -1183,7 +1184,7 @@
static inline void do_special (ide_drive_t *drive)
{
special_t *s = &drive->special;
-next:
+
#ifdef DEBUG
printk("%s: do_special: 0x%02x\n", drive->name, s->all);
#endif
@@ -1206,7 +1207,7 @@
s->b.set_pio = 0;
if (tuneproc != NULL)
tuneproc(drive, drive->pio_req);
- goto next;
+ /* goto next; */
} else if (s->b.set_multmode) {
s->b.set_multmode = 0;
if (drive->media == ide_disk) {
@@ -2123,7 +2124,11 @@
return -ENOSYS;
save_flags(flags);
cli();
- drive->pio_req = (int) arg;
+ if (drive->special.b.set_pio) {
+ restore_flags(flags);
+ return -EBUSY;
+ }
+ drive->pio_req = (byte) arg;
drive->special.b.set_pio = 1;
restore_flags(flags);
return 0;
@@ -2433,8 +2438,10 @@
do_identify(drive, cmd); /* drive returned ID */
if (drive->present && drive->media != ide_tape) {
ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
- if (tuneproc != NULL && drive->autotune == 1)
- tuneproc(drive, 255); /* auto-tune PIO mode */
+ if (tuneproc != NULL && drive->autotune == 1) {
+ drive->pio_req = 255;
+ drive->special.b.set_pio = 1;
+ }
}
rc = 0; /* drive responded with ID */
(void) GET_STAT(); /* clear drive IRQ */
diff -u --recursive --new-file --exclude=.* linux-2.0.10/drivers/block/ide_modes.h linux/drivers/block/ide_modes.h
--- linux-2.0.10/drivers/block/ide_modes.h Sun May 12 14:21:04 1996
+++ linux/drivers/block/ide_modes.h Tue Jul 30 00:15:03 1996
@@ -15,13 +15,44 @@

#if defined(CONFIG_BLK_DEV_CMD640) || defined(CONFIG_IDE_CHIPSETS)

+/*
+ * Standard (generic) timings for PIO modes, from ATA2 specification.
+ * These timings are for access to the IDE data port register *only*.
+ * Some drives may specify a mode, while also specifying a different
+ * value for cycle_time (from drive identification data).
+ */
+typedef struct ide_pio_timings_s {
+ int setup_time; /* Address setup (ns) minimum */
+ int active_time; /* Active pulse (ns) minimum */
+ int cycle_time; /* Cycle time (ns) minimum = (setup + active + recovery) */
+} ide_pio_timings_t;
+
+typedef struct ide_pio_data_s {
+ byte pio_mode;
+ byte use_iordy;
+ byte overridden;
+ byte blacklisted;
+ unsigned int cycle_time;
+} ide_pio_data_t;
+
#ifndef _IDE_C

int ide_scan_pio_blacklist (char *model);
-unsigned int ide_get_best_pio_mode (ide_drive_t *drive);
+byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d);
+extern const ide_pio_timings_t ide_pio_timings[6];
+int ide_system_bus_speed (void);

#else /* _IDE_C */

+const ide_pio_timings_t ide_pio_timings[6] = {
+ { 70, 165, 600 }, /* PIO Mode 0 */
+ { 50, 125, 383 }, /* PIO Mode 1 */
+ { 30, 100, 240 }, /* PIO Mode 2 */
+ { 30, 80, 180 }, /* PIO Mode 3 with IORDY */
+ { 25, 70, 120 }, /* PIO Mode 4 with IORDY */
+ { 20, 50, 100 } /* PIO Mode 5 with IORDY (nonstandard) */
+};
+
/*
* Black list. Some drives incorrectly report their maximal PIO mode,
* at least in respect to CMD640. Here we keep info on some known drives.
@@ -112,31 +143,91 @@
}

/*
- * This routine returns the recommended PIO mode for a given drive,
+ * Guess at host system bus speed (PCI or VLB):
+ */
+int ide_system_bus_speed (void)
+{
+ if (pcibios_present())
+ return 40;
+ else
+ return 50;
+}
+
+/*
+ * This routine returns the recommended PIO settings for a given drive,
* based on the drive->id information and the ide_pio_blacklist[].
* This is used by most chipset support modules when "auto-tuning".
*/
-unsigned int ide_get_best_pio_mode (ide_drive_t *drive)
-{
- unsigned int pio = 0;
- struct hd_driveid *id = drive->id;

- if (id != NULL) {
- if (HWIF(drive)->chipset != ide_cmd640 && !strcmp("QUANTUM FIREBALL1080A", id->model))
- pio = 4;
- else
- pio = ide_scan_pio_blacklist(id->model);
- if (pio == -1) {
- pio = (id->tPIO < 2) ? id->tPIO : 2;
- if (id->field_valid & 2) {
- byte modes = id->eide_pio_modes;
- if (modes & 4) pio = 5;
- else if (modes & 2) pio = 4;
- else if (modes & 1) pio = 3;
+/*
+ * Drive PIO mode auto selection
+ */
+byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d)
+{
+ int pio_mode;
+ int cycle_time = 0;
+ int use_iordy = 0;
+ struct hd_driveid* id = drive->id;
+ int overridden = 0;
+ int blacklisted = 0;
+
+ if (mode_wanted != 255) {
+ pio_mode = mode_wanted;
+ } else if (!drive->id) {
+ pio_mode = 0;
+ } else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
+ overridden = 1;
+ blacklisted = 1;
+ use_iordy = (pio_mode > 2);
+ } else {
+ pio_mode = id->tPIO;
+ if (pio_mode > 2) { /* 2 is maximum allowed tPIO value */
+ pio_mode = 2;
+ overridden = 1;
+ }
+ if (id->field_valid & 2) { /* drive implements ATA2? */
+ if (id->capability & 8) { /* drive supports use_iordy? */
+ use_iordy = 1;
+ cycle_time = id->eide_pio_iordy;
+ if (id->eide_pio_modes & 7) {
+ overridden = 0;
+ if (id->eide_pio_modes & 4)
+ pio_mode = 5;
+ else if (id->eide_pio_modes & 2)
+ pio_mode = 4;
+ else
+ pio_mode = 3;
+ }
+ } else {
+ cycle_time = id->eide_pio;
}
}
+
+ /*
+ * Conservative "downgrade" for all pre-ATA2 drives
+ */
+ if (pio_mode && pio_mode < 4) {
+ pio_mode--;
+ overridden = 1;
+#if 0
+ use_iordy = (pio_mode > 2);
+#endif
+ if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
+ cycle_time = 0; /* use standard timing */
+ }
+ }
+ if (pio_mode > max_mode) {
+ pio_mode = max_mode;
+ cycle_time = 0;
+ }
+ if (d) {
+ d->pio_mode = pio_mode;
+ d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
+ d->use_iordy = use_iordy;
+ d->overridden = overridden;
+ d->blacklisted = blacklisted;
}
- return pio;
+ return pio_mode;
}

#endif /* _IDE_C */
diff -u --recursive --new-file --exclude=.* linux-2.0.10/drivers/block/qd6580.c linux/drivers/block/qd6580.c
--- linux-2.0.10/drivers/block/qd6580.c Fri May 3 04:07:24 1996
+++ linux/drivers/block/qd6580.c Tue Jul 30 00:19:05 1996
@@ -47,10 +47,7 @@
{
unsigned long flags;

- if (pio == 255)
- pio = ide_get_best_pio_mode (drive);
- if (pio > 3)
- pio = 3;
+ pio = ide_get_best_pio_mode(drive, pio, 3, NULL);

save_flags(flags);
cli();
diff -u --recursive --new-file --exclude=.* linux-2.0.10/drivers/block/umc8672.c linux/drivers/block/umc8672.c
--- linux-2.0.10/drivers/block/umc8672.c Fri May 10 01:03:33 1996
+++ linux/drivers/block/umc8672.c Tue Jul 30 00:19:59 1996
@@ -109,10 +109,7 @@

static void tune_umc (ide_drive_t *drive, byte pio)
{
- if (pio == 255)
- pio = ide_get_best_pio_mode(drive);
- if (pio > 4)
- pio = 4;
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);

current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
umc_set_speeds (current_speeds);
\
 
 \ /
  Last update: 2005-03-22 13:38    [W:0.185 / U:0.100 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site