Hi Juan,

I have done some testing on this hpt366 update (attached) and it seems to be 
working just fine on my Abit BP6 MB. I guess it will break the lba48 stuff, 
but that could probably be solved somehow.

Maybe you could implement the patch in the next cooker kernel?

Thanks.

----------  Forwarded Message  ----------

Subject: [PATCH] IDE: hpt366.c and serverworks.c
Date: Wed, 31 Oct 2001 14:03:15 -0800
From: Tim Hockin <[EMAIL PROTECTED]>
To: [EMAIL PROTECTED]
Cc: Linux Kernel Mailing List <[EMAIL PROTECTED]>

Andre,
Attached you'll find the patch to hpt366.c (against your base you sent me)
and serverworks.c.  Both of these have been in use for some time.



Tim




--
Tim Hockin
Systems Software Engineer
Sun Microsystems, Cobalt Server Appliances
[EMAIL PROTECTED]

-------------------------------------------------------



-- 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
| Oden Eriksson, Deserve-IT Networks, Jokkmokk, Sweden.
| Mandrake Linux release 8.2 (Cooker) for i586
| Current uptime with kernel 2.4.13-2mdksmp: 1:33
--- /home/thockin/andre-hpt366.c        Tue Oct 30 16:30:08 2001
+++ drivers/ide/hpt366.c        Wed Oct 31 13:56:44 2001
@@ -1,7 +1,8 @@
 /*
- * linux/drivers/ide/hpt366.c          Version 0.18    June. 9, 2000
+ * linux/drivers/ide/hpt366.c          Version 0.22    20 Sep 2001
  *
  * Copyright (C) 1999-2000             Andre Hedrick <[EMAIL PROTECTED]>
+ * Portions Copyright (C) 2001         Sun Microsystems, Inc.
  * May be copied or modified under the terms of the GNU General Public License
  *
  * Thanks to HighPoint Technologies for their assistance, and hardware.
@@ -11,6 +12,34 @@
  *
  * Note that final HPT370 support was done by force extraction of GPL.
  *
+ * - add function for getting/setting power status of drive
+ * - the HPT370's state machine can get confused. reset it before each dma 
+ *   xfer to prevent that from happening.
+ * - reset state engine whenever we get an error.
+ * - check for busmaster state at end of dma. 
+ * - use new highpoint timings.
+ * - detect bus speed using highpoint register.
+ * - use pll if we don't have a clock table. added a 66MHz table that's
+ *   just 2x the 33MHz table.
+ * - removed turnaround. NOTE: we never want to switch between pll and
+ *   pci clocks as the chip can glitch in those cases. the highpoint
+ *   approved workaround slows everything down too much to be useful. in
+ *   addition, we would have to serialize access to each chip.
+ *     Adrian Sun <[EMAIL PROTECTED]>
+ *
+ * add drive timings for 66MHz PCI bus,
+ * fix ATA Cable signal detection, fix incorrect /proc info
+ * add /proc display for per-drive PIO/DMA/UDMA mode and
+ * per-channel ATA-33/66 Cable detect.
+ *     Duncan Laurie <[EMAIL PROTECTED]>
+ *
+ * fixup /proc output for multiple controllers
+ *     Tim Hockin <[EMAIL PROTECTED]>
+ *
+ * On hpt366: 
+ * Reset the hpt366 on error, reset on dma
+ * Fix disabling Fast Interrupt hpt366.
+ *     Mike Waychison <[EMAIL PROTECTED]>
  */
 
 #include <linux/config.h>
@@ -28,6 +57,7 @@
 #include <linux/init.h>
 #include <linux/ide.h>
 
+#include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
@@ -35,6 +65,11 @@
 
 #define DISPLAY_HPT366_TIMINGS
 
+/* various tuning parameters */
+#define HPT_RESET_STATE_ENGINE
+/*#define HPT_DELAY_INTERRUPT*/
+/*#define HPT_SERIALIZE_IO*/
+
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
@@ -106,146 +141,302 @@
 
 struct chipset_bus_clock_list_entry {
        byte            xfer_speed;
-       unsigned int    chipset_settings_write;
-       unsigned int    chipset_settings_read;
+       unsigned int    chipset_settings;
 };
 
+/* key for bus clock timings
+ * bit
+ * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ *        DMA. cycles = value + 1
+ * 4:8    data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ *        DMA. cycles = value + 1
+ * 9:12   cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ *        register access.
+ * 13:17  cmd_low_time. active time of DIOW_/DIOR_ during task file
+ *        register access.
+ * 18:21  udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ *        during task file register access.
+ * 22:24  pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ *        xfer.
+ * 25:27  cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ *        register access.
+ * 28     UDMA enable
+ * 29     DMA enable
+ * 30     PIO_MST enable. if set, the chip is in bus master mode during
+ *        PIO.
+ * 31     FIFO enable.
+ */
 struct chipset_bus_clock_list_entry forty_base [] = {
 
-       {       XFER_UDMA_4,    0x900fd943,     0x900fd943      },
-       {       XFER_UDMA_3,    0x900ad943,     0x900ad943      },
-       {       XFER_UDMA_2,    0x900bd943,     0x900bd943      },
-       {       XFER_UDMA_1,    0x9008d943,     0x9008d943      },
-       {       XFER_UDMA_0,    0x9008d943,     0x9008d943      },
-
-       {       XFER_MW_DMA_2,  0xa008d943,     0xa008d943      },
-       {       XFER_MW_DMA_1,  0xa010d955,     0xa010d955      },
-       {       XFER_MW_DMA_0,  0xa010d9fc,     0xa010d9fc      },
-
-       {       XFER_PIO_4,     0xc008d963,     0xc008d963      },
-       {       XFER_PIO_3,     0xc010d974,     0xc010d974      },
-       {       XFER_PIO_2,     0xc010d997,     0xc010d997      },
-       {       XFER_PIO_1,     0xc010d9c7,     0xc010d9c7      },
-       {       XFER_PIO_0,     0xc018d9d9,     0xc018d9d9      },
-       {       0,              0x0120d9d9,     0x0120d9d9      }
+       {       XFER_UDMA_4,    0x900fd943      },
+       {       XFER_UDMA_3,    0x900ad943      },
+       {       XFER_UDMA_2,    0x900bd943      },
+       {       XFER_UDMA_1,    0x9008d943      },
+       {       XFER_UDMA_0,    0x9008d943      },
+
+       {       XFER_MW_DMA_2,  0xa008d943      },
+       {       XFER_MW_DMA_1,  0xa010d955      },
+       {       XFER_MW_DMA_0,  0xa010d9fc      },
+
+       {       XFER_PIO_4,     0xc008d963      },
+       {       XFER_PIO_3,     0xc010d974      },
+       {       XFER_PIO_2,     0xc010d997      },
+       {       XFER_PIO_1,     0xc010d9c7      },
+       {       XFER_PIO_0,     0xc018d9d9      },
+       {       0,              0x0120d9d9      }
 };
 
 struct chipset_bus_clock_list_entry thirty_three_base [] = {
 
-       {       XFER_UDMA_4,    0x90c9a731,     0x90c9a731      },
-       {       XFER_UDMA_3,    0x90cfa731,     0x90cfa731      },
-       {       XFER_UDMA_2,    0x90caa731,     0x90caa731      },
-       {       XFER_UDMA_1,    0x90cba731,     0x90cba731      },
-       {       XFER_UDMA_0,    0x90c8a731,     0x90c8a731      },
-
-       {       XFER_MW_DMA_2,  0xa0c8a731,     0xa0c8a731      },
-       {       XFER_MW_DMA_1,  0xa0c8a732,     0xa0c8a732      },      /* 0xa0c8a733 
*/
-       {       XFER_MW_DMA_0,  0xa0c8a797,     0xa0c8a797      },
-
-       {       XFER_PIO_4,     0xc0c8a731,     0xc0c8a731      },
-       {       XFER_PIO_3,     0xc0c8a742,     0xc0c8a742      },
-       {       XFER_PIO_2,     0xc0d0a753,     0xc0d0a753      },
-       {       XFER_PIO_1,     0xc0d0a7a3,     0xc0d0a7a3      },      /* 0xc0d0a793 
*/
-       {       XFER_PIO_0,     0xc0d0a7aa,     0xc0d0a7aa      },      /* 0xc0d0a7a7 
*/
-       {       0,              0x0120a7a7,     0x0120a7a7      }
+       {       XFER_UDMA_4,    0x90c9a731      },
+       {       XFER_UDMA_3,    0x90cfa731      },
+       {       XFER_UDMA_2,    0x90caa731      },
+       {       XFER_UDMA_1,    0x90cba731      },
+       {       XFER_UDMA_0,    0x90c8a731      },
+
+       {       XFER_MW_DMA_2,  0xa0c8a731      },
+       {       XFER_MW_DMA_1,  0xa0c8a732      },      /* 0xa0c8a733 */
+       {       XFER_MW_DMA_0,  0xa0c8a797      },
+
+       {       XFER_PIO_4,     0xc0c8a731      },
+       {       XFER_PIO_3,     0xc0c8a742      },
+       {       XFER_PIO_2,     0xc0d0a753      },
+       {       XFER_PIO_1,     0xc0d0a7a3      },      /* 0xc0d0a793 */
+       {       XFER_PIO_0,     0xc0d0a7aa      },      /* 0xc0d0a7a7 */
+       {       0,              0x0120a7a7      }
 };
 
 struct chipset_bus_clock_list_entry twenty_five_base [] = {
 
-       {       XFER_UDMA_4,    0x90c98521,     0x90c98521      },
-       {       XFER_UDMA_3,    0x90cf8521,     0x90cf8521      },
-       {       XFER_UDMA_2,    0x90cf8521,     0x90cf8521      },
-       {       XFER_UDMA_1,    0x90cb8521,     0x90cb8521      },
-       {       XFER_UDMA_0,    0x90cb8521,     0x90cb8521      },
-
-       {       XFER_MW_DMA_2,  0xa0ca8521,     0xa0ca8521      },
-       {       XFER_MW_DMA_1,  0xa0ca8532,     0xa0ca8532      },
-       {       XFER_MW_DMA_0,  0xa0ca8575,     0xa0ca8575      },
-
-       {       XFER_PIO_4,     0xc0ca8521,     0xc0ca8521      },
-       {       XFER_PIO_3,     0xc0ca8532,     0xc0ca8532      },
-       {       XFER_PIO_2,     0xc0ca8542,     0xc0ca8542      },
-       {       XFER_PIO_1,     0xc0d08572,     0xc0d08572      },
-       {       XFER_PIO_0,     0xc0d08585,     0xc0d08585      },
-       {       0,              0x01208585,     0x01208585      }
+       {       XFER_UDMA_4,    0x90c98521      },
+       {       XFER_UDMA_3,    0x90cf8521      },
+       {       XFER_UDMA_2,    0x90cf8521      },
+       {       XFER_UDMA_1,    0x90cb8521      },
+       {       XFER_UDMA_0,    0x90cb8521      },
+
+       {       XFER_MW_DMA_2,  0xa0ca8521      },
+       {       XFER_MW_DMA_1,  0xa0ca8532      },
+       {       XFER_MW_DMA_0,  0xa0ca8575      },
+
+       {       XFER_PIO_4,     0xc0ca8521      },
+       {       XFER_PIO_3,     0xc0ca8532      },
+       {       XFER_PIO_2,     0xc0ca8542      },
+       {       XFER_PIO_1,     0xc0d08572      },
+       {       XFER_PIO_0,     0xc0d08585      },
+       {       0,              0x01208585      }
+};
+
+#if 1
+/* these are the current (4 sep 2001) timings from highpoint */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+        {       XFER_UDMA_5,    0x12446231      },
+        {       XFER_UDMA_4,    0x12446231      },
+        {       XFER_UDMA_3,    0x126c6231      },
+        {       XFER_UDMA_2,    0x12486231      },
+        {       XFER_UDMA_1,    0x124c6233      },
+        {       XFER_UDMA_0,    0x12506297      },
+
+        {       XFER_MW_DMA_2,  0x22406c31      },
+        {       XFER_MW_DMA_1,  0x22406c33      },
+        {       XFER_MW_DMA_0,  0x22406c97      },
+
+        {       XFER_PIO_4,     0x06414e31      },
+        {       XFER_PIO_3,     0x06414e42      },
+        {       XFER_PIO_2,     0x06414e53      },
+        {       XFER_PIO_1,     0x06814e93      },
+        {       XFER_PIO_0,     0x06814ea7      },
+        {       0,              0x06814ea7      }
 };
 
+/* 2x 33MHz timings */
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+       {       XFER_UDMA_5,    0x1488e673       },
+       {       XFER_UDMA_4,    0x1488e673       },
+       {       XFER_UDMA_3,    0x1498e673       },
+       {       XFER_UDMA_2,    0x1490e673       },
+       {       XFER_UDMA_1,    0x1498e677       },
+       {       XFER_UDMA_0,    0x14a0e73f       },
+
+       {       XFER_MW_DMA_2,  0x2480fa73       },
+       {       XFER_MW_DMA_1,  0x2480fa77       }, 
+       {       XFER_MW_DMA_0,  0x2480fb3f       },
+
+       {       XFER_PIO_4,     0x0c82be73       },
+       {       XFER_PIO_3,     0x0c82be95       },
+       {       XFER_PIO_2,     0x0c82beb7       },
+       {       XFER_PIO_1,     0x0d02bf37       },
+       {       XFER_PIO_0,     0x0d02bf5f       },
+       {       0,              0x0d02bf5f       }
+};
+#else
+/* from highpoint documentation. these are old values */
 struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
-       {       XFER_UDMA_5,    0x1A85F442,     0x16454e31      },
-       {       XFER_UDMA_4,    0x16454e31,     0x16454e31      },
-       {       XFER_UDMA_3,    0x166d4e31,     0x166d4e31      },
-       {       XFER_UDMA_2,    0x16494e31,     0x16494e31      },
-       {       XFER_UDMA_1,    0x164d4e31,     0x164d4e31      },
-       {       XFER_UDMA_0,    0x16514e31,     0x16514e31      },
-
-       {       XFER_MW_DMA_2,  0x26514e21,     0x26514e21      },
-       {       XFER_MW_DMA_1,  0x26514e33,     0x26514e33      },
-       {       XFER_MW_DMA_0,  0x26514e97,     0x26514e97      },
-
-       {       XFER_PIO_4,     0x06514e21,     0x06514e21      },
-       {       XFER_PIO_3,     0x06514e22,     0x06514e22      },
-       {       XFER_PIO_2,     0x06514e33,     0x06514e33      },
-       {       XFER_PIO_1,     0x06914e43,     0x06914e43      },
-       {       XFER_PIO_0,     0x06914e57,     0x06914e57      },
-       {       0,              0x06514e57,     0x06514e57      }
+       {       XFER_UDMA_5,    0x16454e31      },
+       {       XFER_UDMA_4,    0x16454e31      },
+       {       XFER_UDMA_3,    0x166d4e31      },
+       {       XFER_UDMA_2,    0x16494e31      },
+       {       XFER_UDMA_1,    0x164d4e31      },
+       {       XFER_UDMA_0,    0x16514e31      },
+
+       {       XFER_MW_DMA_2,  0x26514e21      },
+       {       XFER_MW_DMA_1,  0x26514e33      },
+       {       XFER_MW_DMA_0,  0x26514e97      },
+
+       {       XFER_PIO_4,     0x06514e21      },
+       {       XFER_PIO_3,     0x06514e22      },
+       {       XFER_PIO_2,     0x06514e33      },
+       {       XFER_PIO_1,     0x06914e43      },
+       {       XFER_PIO_0,     0x06914e57      },
+       {       0,              0x06514e57      }
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+       {       XFER_UDMA_5,    0x14846231      },
+       {       XFER_UDMA_4,    0x14886231      },
+       {       XFER_UDMA_3,    0x148c6231      },
+       {       XFER_UDMA_2,    0x148c6231      },
+       {       XFER_UDMA_1,    0x14906231      },
+       {       XFER_UDMA_0,    0x14986231      },
+       
+       {       XFER_MW_DMA_2,  0x26514e21      },
+       {       XFER_MW_DMA_1,  0x26514e33      },
+       {       XFER_MW_DMA_0,  0x26514e97      },
+       
+       {       XFER_PIO_4,     0x06514e21      },
+       {       XFER_PIO_3,     0x06514e22      },
+       {       XFER_PIO_2,     0x06514e33      },
+       {       XFER_PIO_1,     0x06914e43      },
+       {       XFER_PIO_0,     0x06914e57      },
+       {       0,              0x06514e57      }
+};
+#endif
+
+struct chipset_bus_clock_list_entry fifty_base_hpt370[] = {
+       {       XFER_UDMA_5,    0x12848242      },
+       {       XFER_UDMA_4,    0x12ac8242      },
+       {       XFER_UDMA_3,    0x128c8242      },
+       {       XFER_UDMA_2,    0x120c8242      },
+       {       XFER_UDMA_1,    0x12148254      },
+       {       XFER_UDMA_0,    0x121882ea      },
+
+       {       XFER_MW_DMA_2,  0x22808242      },
+       {       XFER_MW_DMA_1,  0x22808254      },
+       {       XFER_MW_DMA_0,  0x228082ea      },
+
+       {       XFER_PIO_4,     0x0a81f442      },
+       {       XFER_PIO_3,     0x0a81f443      },
+       {       XFER_PIO_2,     0x0a81f454      },
+       {       XFER_PIO_1,     0x0ac1f465      },
+       {       XFER_PIO_0,     0x0ac1f48a      },
+       {       0,              0x0ac1f48a      }
 };
 
 #define HPT366_DEBUG_DRIVE_INFO                0
 #define HPT370_ALLOW_ATA100_5          1
 #define HPT366_ALLOW_ATA66_4           1
 #define HPT366_ALLOW_ATA66_3           1
+#define HPT366_MAX_DEVS                        8
+
+#define F_LOW_PCI_33      0x23
+#define F_LOW_PCI_40      0x29
+#define F_LOW_PCI_50      0x2d
+#define F_LOW_PCI_66      0x42
+
+static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
+static int n_hpt_devs;
+
+static unsigned int pci_rev_check_hpt3xx(struct pci_dev *dev);
+static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev);
+byte hpt366_proc = 0;
+byte hpt363_shared_irq;
+byte hpt363_shared_pin;
+extern char *ide_xfer_verbose (byte xfer_rate);
 
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 static int hpt366_get_info(char *, char **, off_t, int);
 extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
 extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-static struct pci_dev *bmide2_dev;
 
 static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
 {
-       char *p         = buffer;
-       u32 bibma       = bmide_dev->resource[4].start;
-       u32 bibma2      = bmide2_dev->resource[4].start;
-       char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"};
-       u8  c0 = 0, c1 = 0;
-       u32 class_rev;
-
-       pci_read_config_dword(bmide_dev, PCI_CLASS_REVISION, &class_rev);
-       class_rev &= 0xff;
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-       c0 = inb_p((unsigned short)bibma + 0x02);
-       if (bmide2_dev)
-               c1 = inb_p((unsigned short)bibma2 + 0x02);
-
-       p += sprintf(p, "\n                                %s Chipset.\n", 
chipset_names[class_rev]);
-       p += sprintf(p, "--------------- Primary Channel ---------------- Secondary 
Channel -------------\n");
-       p += sprintf(p, "                %sabled                         %sabled\n",
-                       (c0&0x80) ? "dis" : " en",
-                       (c1&0x80) ? "dis" : " en");
-       p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 
---------- drive1 ------\n");
-       p += sprintf(p, "DMA enabled:    %s              %s             %s             
  %s\n",
-                       (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
-                       (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-
-       p += sprintf(p, "UDMA\n");
-       p += sprintf(p, "DMA\n");
-       p += sprintf(p, "PIO\n");
+       char *p = buffer;
+       char *chipset_nums[] = {"366", "366", "368", "370", "370A"};
+       int i;
+
+       p += sprintf(p, "\n                             "
+               "HighPoint HPT366/368/370\n");
+       for (i = 0; i < n_hpt_devs; i++) {
+               struct pci_dev *dev = hpt_devs[i];
+               unsigned short iobase = dev->resource[4].start;
+               u32 class_rev;
+               u8 c0, c1;
+
+               pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+               class_rev &= 0xff;
+
+               p += sprintf(p, "\nController: %d\n", i);
+               p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
+               p += sprintf(p, "--------------- Primary Channel "
+                               "--------------- Secondary Channel "
+                               "--------------\n");
+
+               /* get the bus master status registers */
+               c0 = inb_p(iobase + 0x2);
+               c1 = inb_p(iobase + 0xa);
+               p += sprintf(p, "Enabled:        %s"
+                               "                             %s\n",
+                       (c0 & 0x80) ? "no" : "yes",
+                       (c1 & 0x80) ? "no" : "yes");
+
+               if (pci_rev_check_hpt3xx(dev)) {
+                       u8 cbl;
+                       cbl = inb_p(iobase + 0x7b);
+                       outb_p(cbl | 1, iobase + 0x7b);
+                       outb_p(cbl & ~1, iobase + 0x7b);
+                       cbl = inb_p(iobase + 0x7a);
+                       p += sprintf(p, "Cable:          ATA-%d"
+                                       "                          ATA-%d\n",
+                               (cbl & 0x02) ? 33 : 66,
+                               (cbl & 0x01) ? 33 : 66);
+                       p += sprintf(p, "\n");
+               }
 
+               p += sprintf(p, "--------------- drive0 --------- drive1 "
+                               "------- drive0 ---------- drive1 -------\n");
+               p += sprintf(p, "DMA capable:    %s              %s" 
+                               "            %s               %s\n",
+                       (c0 & 0x20) ? "yes" : "no ", 
+                       (c0 & 0x40) ? "yes" : "no ",
+                       (c1 & 0x20) ? "yes" : "no ", 
+                       (c1 & 0x40) ? "yes" : "no ");
+
+               {
+                       u8 c2, c3;
+                       /* older revs don't have these registers mapped 
+                        * into io space */
+                       pci_read_config_byte(dev, 0x43, &c0);
+                       pci_read_config_byte(dev, 0x47, &c1);
+                       pci_read_config_byte(dev, 0x4b, &c2);
+                       pci_read_config_byte(dev, 0x4f, &c3);
+
+                       p += sprintf(p, "Mode:           %s             %s"
+                                       "           %s              %s\n",
+                               (c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : 
+                                       (c0 & 0x80) ? "PIO " : "off ",
+                               (c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
+                                       (c1 & 0x80) ? "PIO " : "off ",
+                               (c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
+                                       (c2 & 0x80) ? "PIO " : "off ",
+                               (c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
+                                       (c3 & 0x80) ? "PIO " : "off ");
+               }
+       }
+       p += sprintf(p, "\n");
+       
        return p-buffer;/* => must be less than 4k! */
 }
 #endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-byte hpt366_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-byte hpt363_shared_irq;
-byte hpt363_shared_pin;
-
 static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev)
 {
        unsigned int class_rev;
@@ -282,16 +473,16 @@
        return 0;
 }
 
-static unsigned int pci_bus_clock_list (byte speed, int direction, struct 
chipset_bus_clock_list_entry * chipset_table)
+static unsigned int pci_bus_clock_list (byte speed, struct 
+chipset_bus_clock_list_entry * chipset_table)
 {
        for ( ; chipset_table->xfer_speed ; chipset_table++)
                if (chipset_table->xfer_speed == speed) {
-                       return (direction) ? chipset_table->chipset_settings_write : 
chipset_table->chipset_settings_read;
+                       return chipset_table->chipset_settings;
                }
-       return (direction) ? chipset_table->chipset_settings_write : 
chipset_table->chipset_settings_read;
+       return chipset_table->chipset_settings;
 }
 
-static void hpt366_tune_chipset (ide_drive_t *drive, byte speed, int direction)
+static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
 {
        byte regtime            = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
        byte regfast            = (HWIF(drive)->channel) ? 0x55 : 0x51;
@@ -304,36 +495,24 @@
        byte drive_fast         = 0;
 
        /*
-        * Disable the "fast interrupt" prediction.
+        * Disable the "fast interrupt" prediction. 
         */
        pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
-
-       /*
-        * FIXME kludge to correct a detection problem or driver design flaw.
-        */
-       if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
-               if (drive_fast & 0x80)
-                       pci_write_config_byte(HWIF(drive)->pci_dev, regfast, 
drive_fast & ~0x80);
-       } else {
-               if (drive_fast & 0x02)
-                       pci_write_config_byte(HWIF(drive)->pci_dev, regfast, 
drive_fast& ~0x20);
-       }
-       /*
-        * FIXME kludge end of fsckup
-        */
+       if (drive_fast & 0x80)
+               pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & 
+~0x80);
 
        pci_read_config_dword(HWIF(drive)->pci_dev, regtime, &reg1);
        /* detect bus speed by looking at control reg timing: */
        switch((reg1 >> 8) & 15) {
                case 5:
-                       reg2 = pci_bus_clock_list(speed, direction, forty_base);
+                       reg2 = pci_bus_clock_list(speed, forty_base);
                        break;
                case 9:
-                       reg2 = pci_bus_clock_list(speed, direction, twenty_five_base);
+                       reg2 = pci_bus_clock_list(speed, twenty_five_base);
                        break;
                default:
                case 7:
-                       reg2 = pci_bus_clock_list(speed, direction, thirty_three_base);
+                       reg2 = pci_bus_clock_list(speed, thirty_three_base);
                        break;
        }
        /*
@@ -349,40 +528,47 @@
        pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
 }
 
-static void hpt370_tune_chipset (ide_drive_t *drive, byte speed, int direction)
+static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
 {
        byte regfast            = (HWIF(drive)->channel) ? 0x55 : 0x51;
-       byte reg5bh             = (speed != XFER_UDMA_5) ? 0x22 : (direction) ? 0x20 : 
0x22;
-       unsigned int list_conf  = pci_bus_clock_list(speed, direction, 
thirty_three_base_hpt370);
+       unsigned int list_conf  = 0;
        unsigned int drive_conf = 0;
        unsigned int conf_mask  = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-       byte drive_pci          = 0;
-       byte drive_fast         = 0;
+       byte drive_pci          = 0x40 + (drive->dn * 4);
+       byte new_fast, drive_fast               = 0;
+       struct pci_dev *dev     = HWIF(drive)->pci_dev;
 
-       switch (drive->dn) {
-               case 0: drive_pci = 0x40; break;
-               case 1: drive_pci = 0x44; break;
-               case 2: drive_pci = 0x48; break;
-               case 3: drive_pci = 0x4c; break;
-               default: return;
-       }
        /*
         * Disable the "fast interrupt" prediction.
+        * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
         */
-       pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
-       if (drive_fast & 0x80)
-               pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & 
~0x80);
+       pci_read_config_byte(dev, regfast, &drive_fast);
+       new_fast = drive_fast;
+       if (new_fast & 0x02)
+               new_fast &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+       if (new_fast & 0x01)
+               new_fast &= ~0x01;
+#else
+       if ((new_fast & 0x01) == 0)
+               new_fast |= 0x01;
+#endif
+       if (new_fast != drive_fast)
+               pci_write_config_byte(HWIF(drive)->pci_dev, regfast, new_fast);
 
-       pci_read_config_dword(HWIF(drive)->pci_dev, drive_pci, &drive_conf);
-       pci_write_config_byte(HWIF(drive)->pci_dev, 0x5b, reg5bh);
+       list_conf = pci_bus_clock_list(speed, 
+                                      (struct chipset_bus_clock_list_entry *)
+                                      dev->sysdata);
 
+       pci_read_config_dword(dev, drive_pci, &drive_conf);
        list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
-       /*
-        * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors 
later)
-        */
-       list_conf &= ~0x80000000;
+       
+       if (speed < XFER_MW_DMA_0) {
+               list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+       }
 
-       pci_write_config_dword(HWIF(drive)->pci_dev, drive_pci, list_conf);
+       pci_write_config_dword(dev, drive_pci, list_conf);
 }
 
 static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
@@ -394,9 +580,9 @@
                drive->init_speed = speed;
 
        if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
-               hpt370_tune_chipset(drive, speed, 0);
+               hpt370_tune_chipset(drive, speed);
         } else {
-                hpt366_tune_chipset(drive, speed, 0);
+                hpt366_tune_chipset(drive, speed);
         }
        drive->current_speed = speed;
        return ((int) ide_config_drive_speed(drive, speed));
@@ -525,9 +711,8 @@
 
 void hpt3xx_intrproc (ide_drive_t *drive)
 {
-       if (drive->quirk_list) {
+       if (!drive->quirk_list) {
                /* drives in the quirk_list may not like intr setups/cleanups */
-       } else {
                OUT_BYTE((drive)->ctl|2, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
        }
 }
@@ -553,13 +738,6 @@
        }
 }
 
-void hpt370_rw_proc (ide_drive_t *drive, ide_dma_action_t func)
-{
-       if ((func != ide_dma_write) || (func != ide_dma_read))
-               return;
-       hpt370_tune_chipset(drive, drive->current_speed, (func == ide_dma_write));
-}
-
 static int config_drive_xfer_rate (ide_drive_t *drive)
 {
        struct hd_driveid *id = drive->id;
@@ -573,7 +751,7 @@
                }
                dma_func = ide_dma_off_quietly;
                if (id->field_valid & 4) {
-                       if (id->dma_ultra & 0x003F) {
+                       if (id->dma_ultra & 0x002F) {
                                /* Force if Capable UltraDMA */
                                dma_func = config_chipset_for_dma(drive);
                                if ((id->field_valid & 2) &&
@@ -636,17 +814,13 @@
                                reg50h, reg52h, reg5ah);
                        if (reg5ah & 0x10)
                                pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, 
reg5ah & ~0x10);
-                       /* how about we flush and reset, mmmkay? */
-                       pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x1F);
+                       /* fall through to a reset */
 
-                       break;
-#if 0
                case ide_dma_begin:
                case ide_dma_end:
                        /* reset the chips state over and over.. */
                        pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13);
                        break;
-#endif
                case ide_dma_timeout:
                default:
                        break;
@@ -656,8 +830,11 @@
 
 int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-       byte dma_stat = 0;
-       unsigned long dma_base = HWIF(drive)->dma_base;
+       ide_hwif_t *hwif = HWIF(drive);
+       unsigned long dma_base = hwif->dma_base;
+       byte regstate = hwif->channel ? 0x54 : 0x50;
+       byte reginfo = hwif->channel ? 0x56 : 0x52;
+       byte dma_stat;
 
        switch (func) {
                case ide_dma_check:
@@ -665,15 +842,40 @@
                case ide_dma_test_irq:  /* returns 1 if dma irq issued, 0 otherwise */
                        dma_stat = inb(dma_base+2);
                        return (dma_stat & 4) == 4;     /* return 1 if INTR asserted */
-               case ide_dma_lostirq:
-                       /* how about we flush and reset, mmmkay? */
-                       pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x1F);
-                       break;
-               case ide_dma_begin:
+
                case ide_dma_end:
-                       /* reset the chips state over and over.. */
-                       pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13);
+                       dma_stat = inb(dma_base + 2);
+                       if (dma_stat & 0x01) {
+                               udelay(20); /* wait a little */
+                               dma_stat = inb(dma_base + 2);
+                       }
+                       if ((dma_stat & 0x01) == 0) 
+                               break;
+
+                       func = ide_dma_timeout;
+                       /* fallthrough */
+
+               case ide_dma_timeout:
+               case ide_dma_lostirq:
+                       pci_read_config_byte(hwif->pci_dev, reginfo, 
+                                            &dma_stat); 
+                       printk("%s: %d bytes in FIFO\n", drive->name, 
+                              dma_stat);
+                       pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
+                       udelay(10);
+                       dma_stat = inb(dma_base);
+                       outb(dma_stat & ~0x1, dma_base); /* stop dma */
+                       dma_stat = inb(dma_base + 2); 
+                       outb(dma_stat | 0x6, dma_base+2); /* clear errors */
+                       /* fallthrough */
+
+#ifdef HPT_RESET_STATE_ENGINE
+               case ide_dma_begin:
+#endif
+                       pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
+                       udelay(10);
                        break;
+
                default:
                        break;
        }
@@ -681,6 +883,87 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
+static void __init init_hpt370(struct pci_dev *dev)
+{
+       int adjust, i;
+       u16 freq;
+       u32 pll;
+       byte reg5bh;
+
+       /* default to pci clock. make sure MA15/16 are set to output
+        * to prevent drives having problems with 40-pin cables. */
+       pci_write_config_byte(dev, 0x5b, 0x23);
+
+       /* set up the PLL. we need to adjust it so that it's stable. 
+        * freq = Tpll * 192 / Tpci */
+       pci_read_config_word(dev, 0x78, &freq);
+       freq &= 0x1FF;
+       if (freq < 0x9c) {
+         pll = F_LOW_PCI_33;
+         dev->sysdata = (void *) thirty_three_base_hpt370;
+         printk("HPT370: using 33MHz PCI clock\n");
+       } else if (freq < 0xb0)
+         pll = F_LOW_PCI_40;
+       else if (freq < 0xc8) {
+         pll = F_LOW_PCI_50;
+         dev->sysdata = (void *) fifty_base_hpt370;
+         printk("HPT370: using 50MHz PCI clock\n");
+       } else {
+         pll = F_LOW_PCI_66;
+         dev->sysdata = (void *) sixty_six_base_hpt370;
+         printk("HPT370: using 66MHz PCI clock\n");
+       }
+       
+       /* only try the pll if we don't have a table for the clock
+        * speed that we're running at. NOTE: the internal PLL will
+        * result in slow reads when using a 33MHz PCI clock. we also
+        * don't like to use the PLL because it will cause glitches
+        * on PRST/SRST when the HPT state engine gets reset. */
+       if (dev->sysdata) 
+               goto init_hpt370_done;
+       
+       /* adjust PLL based upon PCI clock, enable it, and wait for
+          stabilization. */
+       adjust = 0;
+       freq = (pll < F_LOW_PCI_50) ? 2 : 4;
+       while (adjust++ < 6) {
+               pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
+                                      pll | 0x100);
+
+               /* wait for clock stabilization */
+               for (i = 0; i < 0x50000; i++) {
+                       pci_read_config_byte(dev, 0x5b, &reg5bh);
+                       if (reg5bh & 0x80) {
+                               /* spin looking for the clock to destabilize */
+                               for (i = 0; i < 0x1000; ++i) {
+                                       pci_read_config_byte(dev, 0x5b, 
+                                                            &reg5bh);
+                                       if ((reg5bh & 0x80) == 0)
+                                               goto pll_recal;
+                               }
+                               pci_read_config_dword(dev, 0x5c, &pll);
+                               pci_write_config_dword(dev, 0x5c, 
+                                                      pll & ~0x100);
+                               pci_write_config_byte(dev, 0x5b, 0x21);
+                               dev->sysdata = (void *) fifty_base_hpt370;
+                               printk("HPT370: using 50MHz internal PLL\n");
+                               goto init_hpt370_done;
+                       }
+               }
+pll_recal:
+               if (adjust & 1)
+                       pll -= (adjust >> 1);
+               else
+                       pll += (adjust >> 1);
+       } 
+
+init_hpt370_done:
+       /* reset state engine */
+       pci_write_config_byte(dev, 0x50, 0x37); 
+       pci_write_config_byte(dev, 0x54, 0x37); 
+       udelay(100);
+}
+
 unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
 {
        byte test = 0;
@@ -689,14 +972,8 @@
                pci_write_config_byte(dev, PCI_ROM_ADDRESS, 
dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
 
        pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
-
-#if 0
-       if (test != 0x08)
-               pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x08);
-#else
        if (test != (L1_CACHE_BYTES / 4))
                pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
-#endif
 
        pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
        if (test != 0x78)
@@ -710,17 +987,15 @@
        if (test != 0x08)
                pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
 
+       if (pci_rev_check_hpt3xx(dev)) 
+               init_hpt370(dev);
+
+       hpt_devs[n_hpt_devs++] = dev;
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
        if (!hpt366_proc) {
                hpt366_proc = 1;
-               bmide_dev = dev;
-               if (pci_rev_check_hpt3xx(dev))
-                       bmide2_dev = dev;
                hpt366_display_info = &hpt366_get_info;
        }
-       if ((hpt366_proc) && ((dev->devfn - bmide_dev->devfn) == 1)) {
-               bmide2_dev = dev;
-       }
 #endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
 
        return dev->irq;
@@ -729,37 +1004,121 @@
 unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
 {
        byte ata66 = 0;
+       int is33 = 0;
 
        pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
+       if (hwif->channel) {
+               is33 = ata66 & 1;
+       } else {
+               is33 = ata66 & 2;
+       }
+
 #ifdef DEBUG
        printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
-               ata66, (ata66 & 0x02) ? "33" : "66",
+               ata66, is33 ? "33" : "66",
                PCI_FUNC(hwif->pci_dev->devfn));
 #endif /* DEBUG */
-       return ((ata66 & 0x02) ? 0 : 1);
+       return (!is33);
+}
+
+/* 
+ * set/get power state for a drive.
+ * turning the power off does the following things:
+ *   1) soft-reset the drive
+ *   2) tri-states the ide bus
+ *
+ * when we turn things back on, we need to re-initialize things.
+ */
+#define TRISTATE_BIT  0x8000
+static int hpt3xx_busproc(ide_hwif_t *hwif, int state)
+{
+       byte tristate, resetmask, bus_reg;
+       u16 tri_reg;
+
+       if (!hwif)
+               return -EINVAL;
+
+       hwif->bus_state = state;
+
+       if (hwif->channel) { 
+               /* secondary channel */
+               tristate = 0x56;
+               resetmask = 0x80; 
+       } else { 
+               /* primary channel */
+               tristate = 0x52;
+               resetmask = 0x40;
+       }
+
+       /* grab status */
+       pci_read_config_word(hwif->pci_dev, tristate, &tri_reg);
+       pci_read_config_byte(hwif->pci_dev, 0x59, &bus_reg);
+
+       /* set the state. we don't set it if we don't need to do so.
+        * make sure that the drive knows that it has failed if it's off */
+       switch (state) {
+       case BUSSTATE_ON:
+               hwif->drives[0].failures = 0;
+               hwif->drives[1].failures = 0;
+               if ((bus_reg & resetmask) == 0)
+                       return 0;
+               tri_reg &= ~TRISTATE_BIT;
+               bus_reg &= ~resetmask;
+               break;
+       case BUSSTATE_OFF:
+               hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+               hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+               if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
+                       return 0;
+               tri_reg &= ~TRISTATE_BIT;
+               bus_reg |= resetmask;
+               break;
+       case BUSSTATE_TRISTATE:
+               hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+               hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+               if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
+                       return 0;
+               tri_reg |= TRISTATE_BIT;
+               bus_reg |= resetmask;
+               break;
+       }
+       pci_write_config_byte(hwif->pci_dev, 0x59, bus_reg);
+       pci_write_config_word(hwif->pci_dev, tristate, tri_reg);
+
+       return 0;
 }
 
 void __init ide_init_hpt366 (ide_hwif_t *hwif)
 {
+       int hpt_rev;
+
        hwif->tuneproc  = &hpt3xx_tune_drive;
        hwif->speedproc = &hpt3xx_tune_chipset;
        hwif->quirkproc = &hpt3xx_quirkproc;
        hwif->intrproc  = &hpt3xx_intrproc;
        hwif->maskproc  = &hpt3xx_maskproc;
 
-       if (pci_rev2_check_hpt3xx(hwif->pci_dev)) {
-               /* do nothing now but will split device types */
+#ifdef HPT_SERIALIZE_IO
+       /* serialize access to this device */
+       if (hwif->mate)
+               hwif->serialized = hwif->mate->serialized = 1;
+#endif
+
+       hpt_rev = pci_rev_check_hpt3xx(hwif->pci_dev);
+       if (hpt_rev) {
+               /* set up ioctl for power status. note: power affects both
+                * drives on each channel */
+               hwif->busproc = &hpt3xx_busproc;
        }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
        if (hwif->dma_base) {
-               if (pci_rev_check_hpt3xx(hwif->pci_dev)) {
+               if (hpt_rev) {
                        byte reg5ah = 0;
                        pci_read_config_byte(hwif->pci_dev, 0x5a, &reg5ah);
                        if (reg5ah & 0x10)      /* interrupt force enable */
                                pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & 
~0x10);
                        hwif->dmaproc = &hpt370_dmaproc;
-                       hwif->rwproc = &hpt370_rw_proc;
                } else {
                        hwif->dmaproc = &hpt366_dmaproc;
                }
diff -ruN dist-2.4.13+patches/drivers/ide/serverworks.c 
linux-2.4/drivers/ide/serverworks.c
--- dist-2.4.13+patches/drivers/ide/serverworks.c       Mon Oct  1 16:43:56 2001
+++ linux-2.4/drivers/ide/serverworks.c Fri Oct 26 19:39:02 2001
@@ -1,16 +1,26 @@
 /*
- * linux/drivers/ide/serverworks.c             Version 0.2     17 Oct 2000
+ * linux/drivers/ide/serverworks.c             Version 0.3     26 Oct 2001
  *
- *  Copyright (C) 2000 Cobalt Networks, Inc. <[EMAIL PROTECTED]>
- *  May be copied or modified under the terms of the GNU General Public License
+ * May be copied or modified under the terms of the GNU General Public License
  *
- *  interface borrowed from alim15x3.c:
- *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
- *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+ * Copyright (C) 1998-2000 Michel Aubry
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
+ * Copyright (C) 1998-2000 Andre Hedrick <[EMAIL PROTECTED]>
+ * Portions copyright (c) 2001 Sun Microsystems
  *
- *  Copyright (C) 1998-2000 Andre Hedrick <[EMAIL PROTECTED]>
  *
- *  IDE support for the ServerWorks OSB4 IDE chipset
+ * RCC/ServerWorks IDE driver for Linux
+ *
+ *   OSB4: `Open South Bridge' IDE Interface (fn 1)
+ *         supports UDMA mode 2 (33 MB/s)
+ *
+ *   CSB5: `Champion South Bridge' IDE Interface (fn 1)
+ *         all revisions support UDMA mode 4 (66 MB/s)
+ *         revision A2.0 and up support UDMA mode 5 (100 MB/s)
+ *
+ *         *** The CSB5 does not provide ANY register ***
+ *         *** to detect 80-conductor cable presence. ***
+ *
  *
  * here's the default lspci:
  *
@@ -83,15 +93,15 @@
 
 #include "ide_modes.h"
 
-#define SVWKS_DEBUG_DRIVE_INFO         0
-
-#define DISPLAY_SVWKS_TIMINGS
+#define DISPLAY_SVWKS_TIMINGS  1
+#undef SVWKS_DEBUG_DRIVE_INFO
 
 #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 
 static struct pci_dev *bmide_dev;
+static byte svwks_revision = 0;
 
 static int svwks_get_info(char *, char **, off_t, int);
 extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */
@@ -103,7 +113,7 @@
        u32 bibma = pci_resource_start(bmide_dev, 4);
        u32 reg40, reg44;
        u16 reg48, reg56;
-       u8  c0 = 0, c1 = 0, reg54;
+       u8  reg54, c0=0, c1=0;
 
        pci_read_config_dword(bmide_dev, 0x40, &reg40);
        pci_read_config_dword(bmide_dev, 0x44, &reg44);
@@ -120,20 +130,23 @@
 
        switch(bmide_dev->device) {
                case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
-                       p += sprintf(p, "\n                                ServerWorks 
CSB5 Chipset.\n");
+                       p += sprintf(p, "\n                            "
+                                    "ServerWorks CSB5 Chipset (rev %02x)\n",
+                                    svwks_revision);
                        break;
-               case PCI_DEVICE_ID_SERVERWORKS_OSB4:
-                       p += sprintf(p, "\n                                ServerWorks 
OSB4 Chipset.\n");
+               case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
+                       p += sprintf(p, "\n                            "
+                                    "ServerWorks OSB4 Chipset (rev %02x)\n",
+                                    svwks_revision);
                        break;
                default:
-                       p += sprintf(p, "\n                                ServerWorks 
0x%04x Chipset.\n", bmide_dev->device);
+                       p += sprintf(p, "\n                            "
+                                    "ServerWorks %04x Chipset (rev %02x)\n",
+                                    bmide_dev->device, svwks_revision);
                        break;
        }
 
        p += sprintf(p, "------------------------------- General Status 
---------------------------------\n");
-#if 0
-       p += sprintf(p, "                                     : %s\n", "str");
-#endif
        p += sprintf(p, "--------------- Primary Channel ---------------- Secondary 
Channel -------------\n");
        p += sprintf(p, "                %sabled                         %sabled\n",
                        (c0&0x80) ? "dis" : " en",
@@ -191,11 +204,7 @@
                                ((reg44&0x00210000)==0x00210000)?"1":
                                ((reg44&0x00770000)==0x00770000)?"0":
                                ((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
-#if 0
-       if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
-               p += sprintf(p, "PIO  enabled:   %s                %s               %s 
                %s\n",
-       if (bmide_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4)
-#endif
+
                p += sprintf(p, "PIO  enabled:   %s                %s               %s 
                %s\n",
                        ((reg40&0x00002000)==0x00002000)?"4":
                                ((reg40&0x00002200)==0x00002200)?"3":
@@ -221,7 +230,7 @@
 }
 #endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-static byte svwks_revision = 0;
+#define SVWKS_CSB5_REVISION_NEW        0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
 
 byte svwks_proc = 0;
 
@@ -292,6 +301,7 @@
                        pio_timing |= pio_modes[speed - XFER_PIO_0];
                        csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
                        break;
+
 #ifdef CONFIG_BLK_DEV_IDEDMA
                case XFER_MW_DMA_2:
                case XFER_MW_DMA_1:
@@ -307,9 +317,9 @@
                case XFER_UDMA_2:
                case XFER_UDMA_1:
                case XFER_UDMA_0:
-                       pio_timing |= pio_modes[pio];
-                       csb5_pio   |= (pio << (4*drive->dn));
-                       dma_timing |= dma_modes[2];
+                       pio_timing   |= pio_modes[pio];
+                       csb5_pio     |= (pio << (4*drive->dn));
+                       dma_timing   |= dma_modes[2];
                        ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << 
(4*unit));
                        ultra_enable |= (0x01 << drive->dn);
 #endif
@@ -322,9 +332,9 @@
                drive->name, ultra_timing, dma_timing, pio_timing);
 #endif
 
-#if OSB4_DEBUG_DRIVE_INFO
+#if SVWKS_DEBUG_DRIVE_INFO
        printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* OSB4_DEBUG_DRIVE_INFO */
+#endif /* SVWKS_DEBUG_DRIVE_INFO */
 
        if (!drive->init_speed)
                drive->init_speed = speed;
@@ -338,11 +348,10 @@
        pci_write_config_byte(dev, drive_pci3, ultra_timing);
        pci_write_config_byte(dev, 0x54, ultra_enable);
        
-       if (speed > XFER_PIO_4) {
+       if (speed > XFER_PIO_4)
                outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-       } else {
+       else
                outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-       }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
        err = ide_config_drive_speed(drive, speed);
@@ -354,25 +363,24 @@
 {
        unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
        unsigned short xfer_pio = drive->id->eide_pio_modes;
-       byte                    timing, speed, pio;
+       byte timing, speed, pio;
 
        pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
 
        if (xfer_pio> 4)
                xfer_pio = 0;
 
-       if (drive->id->eide_pio_iordy > 0) {
+       if (drive->id->eide_pio_iordy > 0)
                for (xfer_pio = 5;
                        xfer_pio>0 &&
                        drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
                        xfer_pio--);
-       } else {
+       else
                xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
                           (drive->id->eide_pio_modes & 2) ? 0x04 :
                           (drive->id->eide_pio_modes & 1) ? 0x03 :
                           (drive->id->tPIO & 2) ? 0x02 :
                           (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
-       }
 
        timing = (xfer_pio >= pio) ? xfer_pio : pio;
 
@@ -407,12 +415,10 @@
 {
        struct hd_driveid *id   = drive->id;
        struct pci_dev *dev     = HWIF(drive)->pci_dev;
-       byte udma_66            = eighty_ninty_three(drive);
-       byte                    speed;
-
-       int ultra66             = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 
1 : 0;
-       /* need specs to figure out if osb4 is capable of ata/66/100 */
-       int ultra100            = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 
1 : 0;
+       byte udma_66    = eighty_ninty_three(drive);
+       int ultra66     = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
+       int ultra100    = (ultra66 && svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 1 : 
+0;
+       byte speed;
 
        if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
                speed = XFER_UDMA_5;
@@ -499,7 +505,7 @@
        switch (func) {
                case ide_dma_check:
                        return config_drive_xfer_rate(drive);
-               default :
+               default:
                        break;
        }
        /* Other cases are done by generic IDE-DMA code. */
@@ -509,30 +515,43 @@
 
 unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
 {
-       unsigned int reg64;
+       unsigned int reg;
+       byte btr;
 
+       /* save revision id to determine DMA capability */
        pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
 
-       if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
-               isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, 
PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+       /* force Master Latency Timer value to 64 PCICLKs */
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
 
-               pci_read_config_dword(isa_dev, 0x64, &reg64);
-#ifdef DEBUG
-               printk("%s: reg64 == 0x%08x\n", name, reg64);
-#endif
+       /* OSB4 : South Bridge and IDE */
+       if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+               isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+                         PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+               if (isa_dev) {
+                       pci_read_config_dword(isa_dev, 0x64, &reg);
+                       reg &= ~0x00002000; /* disable 600ns interrupt mask */
+                       reg |=  0x00004000; /* enable UDMA/33 support */
+                       pci_write_config_dword(isa_dev, 0x64, reg);
+               }
+       }
 
-//             reg64 &= ~0x0000A000;
-//#ifdef CONFIG_SMP
-//             reg64 |= 0x00008000;
-//#endif
-       /* Assume the APIC was set up properly by the BIOS for now . If it
-          wasnt we need to do a fix up _way_ earlier. Bits 15,10,3 control
-          APIC enable, routing and decode */
-          
-               reg64 &= ~0x00002000;   
-               pci_write_config_dword(isa_dev, 0x64, reg64);
+       /* setup CSB5 : South Bridge and IDE */
+       else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) {
+               /* setup the UDMA Control register
+                *
+                * 1. clear bit 6 to enable DMA
+                * 2. enable DMA modes with bits 0-1
+                *      00 : legacy
+                *      01 : udma2
+                *      10 : udma2/udma4
+                *      11 : udma2/udma4/udma5
+                */
+               pci_read_config_byte(dev, 0x5A, &btr);
+               btr &= ~0x40;
+               btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+               pci_write_config_byte(dev, 0x5A, btr);
        }
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
 
 #if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
        if (!svwks_proc) {
@@ -551,26 +570,46 @@
  * Bit 14 clear = primary IDE channel does not have 80-pin cable.
  * Bit 14 set   = primary IDE channel has 80-pin cable.
  */
-
 static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
 {
-       struct pci_dev *dev     = hwif->pci_dev;
-       if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL        &&
-           dev->vendor           == PCI_VENDOR_ID_SERVERWORKS &&
-           dev->device           == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+       struct pci_dev *dev = hwif->pci_dev;
+       if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+           dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
+           dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
                return ((1 << (hwif->channel + 14)) &
                        dev->subsystem_device) ? 1 : 0;
-
        return 0;
+}
 
+/* Sun Cobalt Alpine hardware avoids the 80-pin cable
+ * detect issue by attaching the drives directly to the board.
+ * This check follows the Dell precedent (how scary is that?!)
+ *
+ * WARNING: this only works on Alpine hardware!
+ */
+static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+{
+       struct pci_dev *dev = hwif->pci_dev;
+       if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
+           dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
+           dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+               return ((1 << (hwif->channel + 14)) &
+                       dev->subsystem_device) ? 1 : 0;
+       return 0;
 }
 
 unsigned int __init ata66_svwks (ide_hwif_t *hwif)
 {
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev = hwif->pci_dev;
+
+       /* Dell PowerEdge */
        if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
                return ata66_svwks_dell (hwif);
-       
+
+       /* Cobalt Alpine */
+       if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
+               return ata66_svwks_cobalt (hwif);
+
        return 0;
 }
 
@@ -586,9 +625,7 @@
        hwif->drives[0].autotune = 1;
        hwif->drives[1].autotune = 1;
        hwif->autodma = 0;
-       return;
 #else /* CONFIG_BLK_DEV_IDEDMA */
-
        if (hwif->dma_base) {
                if (!noautodma)
                        hwif->autodma = 1;

Reply via email to