* [PATCH] IDE GET/SET_BUSSTATE ioctls
[not found] <Pine.LNX.4.10.10103272243300.17821-100000@master.linux-ide.org>
@ 2001-06-01 1:21 ` Tim Hockin
2001-06-01 1:32 ` [PATCH] HPT370 misc Tim Hockin
2001-06-01 1:34 ` [PATCH] HPT370 misc (for real this time) Tim Hockin
2 siblings, 0 replies; 4+ messages in thread
From: Tim Hockin @ 2001-06-01 1:21 UTC (permalink / raw)
To: Andre Hedrick; +Cc: linux-kernel, alan
[-- Attachment #1: Type: text/plain, Size: 1154 bytes --]
Andre,
We spoke a while back about a GET/SET BUSSTATE API for IDE. Attached is my
(very simple) patch adding 2 ioctls, and obsoleting 1. I will send the
implementation of this for the HPT370 in a different message. Please let
me know if there are any problems with this preventing general inclusion.
This patch also includes support for a configurable 'max failures'
parameter, and one change for better DMA error reporting.
Tim
Andre Hedrick wrote:
>
> Bring it on! ;-)
>
> On Tue, 27 Mar 2001, Tim Hockin wrote:
>
> > Andre,
> >
> > I'm doing some work toward hotswap IDE, and I had a query for you. On
> > 2.2.x we added a HDIO_GET_BUSSTATE and HDIO_SET_BUSSTATE ioctl() pair. Now
> > I see in 2.4 that there is an HDIO_TRISTATE_HWIF ioctl(), but no way to
> > un-tristate or query the status.
> >
> > Are there plans to add the converse APIs? I see no one has yet implemented
> > the HWIF_TRISTATE_BUS ioctl() - would you accept my patch to
> > implement the HDIO_{GET,SET}_BUSSTATE, and implementation of it on the
> > HPT366 driver?
--
Tim Hockin
Systems Software Engineer
Sun Microsystems, Cobalt Server Appliances
thockin@sun.com
[-- Attachment #2: ide-failures,tristate.diff --]
[-- Type: text/plain, Size: 7241 bytes --]
diff -ruN dist-2.4.5/include/linux/hdreg.h cobalt-2.4.5/include/linux/hdreg.h
--- dist-2.4.5/include/linux/hdreg.h Fri May 25 18:01:27 2001
+++ cobalt-2.4.5/include/linux/hdreg.h Thu May 31 14:33:16 2001
@@ -181,9 +181,10 @@
#define HDIO_GET_DMA 0x030b /* get use-dma flag */
#define HDIO_GET_NICE 0x030c /* get nice flags */
#define HDIO_GET_IDENTITY 0x030d /* get IDE identification info */
+#define HDIO_GET_BUSSTATE 0x030e /* get the bus state of the hwif */
#define HDIO_DRIVE_RESET 0x031c /* execute a device reset */
-#define HDIO_TRISTATE_HWIF 0x031d /* execute a channel tristate */
+#define HDIO_TRISTATE_HWIF 0x031d /* OBSOLETE - use SET_BUSSTATE */
#define HDIO_DRIVE_TASK 0x031e /* execute task and special drive command */
#define HDIO_DRIVE_CMD 0x031f /* execute a special drive command */
@@ -200,6 +201,14 @@
#define HDIO_SCAN_HWIF 0x0328 /* register and (re)scan interface */
#define HDIO_SET_NICE 0x0329 /* set nice flags */
#define HDIO_UNREGISTER_HWIF 0x032a /* unregister interface */
+#define HDIO_SET_BUSSTATE 0x032b /* set the bus state of the hwif */
+
+/* bus states */
+enum {
+ BUSSTATE_OFF = 0,
+ BUSSTATE_ON,
+ BUSSTATE_TRISTATE
+};
/* BIG GEOMETRY */
struct hd_big_geometry {
diff -ruN dist-2.4.5/include/linux/ide.h cobalt-2.4.5/include/linux/ide.h
--- dist-2.4.5/include/linux/ide.h Fri May 25 18:02:42 2001
+++ cobalt-2.4.5/include/linux/ide.h Thu May 31 14:33:16 2001
@@ -349,6 +350,8 @@
byte init_speed; /* transfer rate set at boot */
byte current_speed; /* current transfer rate set */
byte dn; /* now wide spread use */
+ unsigned int failures; /* current failure count */
+ unsigned int max_failures; /* maximum allowed failure count */
} ide_drive_t;
/*
@@ -397,6 +400,11 @@
typedef void (ide_rw_proc_t) (ide_drive_t *, ide_dma_action_t);
/*
+ * ide soft-power support
+ */
+typedef int (ide_busproc_t) (struct hwif_s *, int);
+
+/*
* hwif_chipset_t is used to keep track of the specific hardware
* chipset used by each IDE interface, if known.
*/
@@ -467,6 +475,8 @@
#endif
byte straight8; /* Alan's straight 8 check */
void *hwif_data; /* extra hwif data */
+ ide_busproc_t *busproc; /* driver soft-power interface */
+ byte bus_state; /* power state of the IDE bus */
} ide_hwif_t;
diff -ruN dist-2.4.5/drivers/ide/ide.c cobalt-2.4.5/drivers/ide/ide.c
--- dist-2.4.5/drivers/ide/ide.c Tue May 1 16:05:00 2001
+++ cobalt-2.4.5/drivers/ide/ide.c Thu May 31 14:32:16 2001
@@ -161,6 +161,9 @@
#include <linux/kmod.h>
#endif /* CONFIG_KMOD */
+/* default maximum number of failures */
+#define IDE_DEFAULT_MAX_FAILURES 1
+
static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR };
static int idebus_parameter; /* holds the "idebus=" parameter */
@@ -248,6 +251,7 @@
hwif->name[1] = 'd';
hwif->name[2] = 'e';
hwif->name[3] = '0' + index;
+ hwif->bus_state = BUSSTATE_ON;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
@@ -262,6 +266,7 @@
drive->name[0] = 'h';
drive->name[1] = 'd';
drive->name[2] = 'a' + (index * MAX_DRIVES) + unit;
+ drive->max_failures = IDE_DEFAULT_MAX_FAILURES;
init_waitqueue_head(&drive->wqueue);
}
}
@@ -636,11 +641,14 @@
return ide_started; /* continue polling */
}
printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
+ drive->failures++;
} else {
printk("%s: reset: ", hwif->name);
- if ((tmp = GET_ERR()) == 1)
+ if ((tmp = GET_ERR()) == 1) {
printk("success\n");
- else {
+ drive->failures = 0;
+ } else {
+ drive->failures++;
#if FANCY_STATUS_DUMPS
printk("master: ");
switch (tmp & 0x7f) {
@@ -1048,6 +1056,12 @@
int i;
unsigned long flags;
+ /* bail early if we've exceeded max_failures */
+ if (drive->max_failures && (drive->failures > drive->max_failures)) {
+ *startstop = ide_stopped;
+ return 1;
+ }
+
udelay(1); /* spec allows drive 400ns to assert "BUSY" */
if ((stat = GET_STAT()) & BUSY_STAT) {
__save_flags(flags); /* local CPU only */
@@ -1144,6 +1158,11 @@
#ifdef DEBUG
printk("%s: start_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
#endif
+ /* bail early if we've exceeded max_failures */
+ if (drive->max_failures && (drive->failures > drive->max_failures)) {
+ goto kill_rq;
+ }
+
if (unit >= MAX_DRIVES) {
printk("%s: bad device number: %s\n", hwif->name, kdevname(rq->rq_dev));
goto kill_rq;
@@ -2089,6 +2108,8 @@
hwif->quirkproc = old_hwif.quirkproc;
hwif->rwproc = old_hwif.rwproc;
hwif->dmaproc = old_hwif.dmaproc;
+ hwif->busproc = old_hwif.busproc;
+ hwif->bus_state = old_hwif.bus_state;
hwif->dma_base = old_hwif.dma_base;
hwif->dma_extra = old_hwif.dma_extra;
hwif->config_data = old_hwif.config_data;
@@ -2669,6 +2690,20 @@
case BLKELVGET:
case BLKELVSET:
return blk_ioctl(inode->i_rdev, cmd, arg);
+
+ case HDIO_GET_BUSSTATE:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (put_user(HWIF(drive)->bus_state, (long *)arg))
+ return -EFAULT;
+ return 0;
+
+ case HDIO_SET_BUSSTATE:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (HWIF(drive)->busproc)
+ HWIF(drive)->busproc(HWIF(drive), arg);
+ return 0;
default:
if (drive->driver != NULL)
diff -ruN dist-2.4.5/drivers/ide/ide-dma.c cobalt-2.4.5/drivers/ide/ide-dma.c
--- dist-2.4.5/drivers/ide/ide-dma.c Mon Jan 15 13:08:15 2001
+++ cobalt-2.4.5/drivers/ide/ide-dma.c Thu May 31 14:32:16 2001
@@ -206,7 +206,8 @@
}
return ide_stopped;
}
- printk("%s: dma_intr: bad DMA status\n", drive->name);
+ printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n",
+ drive->name, dma_stat);
}
return ide_error(drive, "dma_intr", stat);
}
@@ -514,7 +515,7 @@
dma_stat = inb(dma_base+2); /* get DMA status */
outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */
ide_destroy_dmatable(drive); /* purge DMA mappings */
- return (dma_stat & 7) != 4; /* verify good DMA status */
+ return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; /* verify good DMA status */
case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
dma_stat = inb(dma_base+2);
#if 0 /* do not set unless you know what you are doing */
diff -ruN dist-2.4.5/drivers/ide/ide-disk.c cobalt-2.4.5/drivers/ide/ide-disk.c
--- dist-2.4.5/drivers/ide/ide-disk.c Fri Feb 9 11:30:23 2001
+++ cobalt-2.4.5/drivers/ide/ide-disk.c Thu May 31 14:32:16 2001
@@ -692,6 +692,8 @@
ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor], NULL);
ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL);
ide_add_setting(drive, "lun", SETTING_RW, -1, -1, TYPE_INT, 0, 7, 1, 1, &drive->lun, NULL);
+ ide_add_setting(drive, "failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->failures, NULL);
+ ide_add_setting(drive, "max_failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL);
}
/*
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH] HPT370 misc
[not found] <Pine.LNX.4.10.10103272243300.17821-100000@master.linux-ide.org>
2001-06-01 1:21 ` [PATCH] IDE GET/SET_BUSSTATE ioctls Tim Hockin
@ 2001-06-01 1:32 ` Tim Hockin
2001-06-01 1:34 ` [PATCH] HPT370 misc (for real this time) Tim Hockin
2 siblings, 0 replies; 4+ messages in thread
From: Tim Hockin @ 2001-06-01 1:32 UTC (permalink / raw)
To: Andre Hedrick; +Cc: Linux Kernel Mailing List, alan
Andre,
Attached is a patch for hpt366.c for the following:
better support for multiple controllers
better /proc output
66 MHz PCI timings
implement the HDIO_GET/SET_BUSSTATE ioctls (see previous patch)
This patch does rely on the PCI busspeed patch (sent to lkml earlier).
Please let me know if you have any problems with this for general
inclusion.
Tim
--
Tim Hockin
Systems Software Engineer
Sun Microsystems, Cobalt Server Appliances
thockin@sun.com
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH] HPT370 misc (for real this time)
[not found] <Pine.LNX.4.10.10103272243300.17821-100000@master.linux-ide.org>
2001-06-01 1:21 ` [PATCH] IDE GET/SET_BUSSTATE ioctls Tim Hockin
2001-06-01 1:32 ` [PATCH] HPT370 misc Tim Hockin
@ 2001-06-01 1:34 ` Tim Hockin
2001-06-02 22:37 ` Andre Hedrick
2 siblings, 1 reply; 4+ messages in thread
From: Tim Hockin @ 2001-06-01 1:34 UTC (permalink / raw)
To: Andre Hedrick; +Cc: Linux Kernel Mailing List, alan
[-- Attachment #1: Type: text/plain, Size: 462 bytes --]
Andre,
Attached is a patch for hpt366.c for the following:
better support for multiple controllers
better /proc output
66 MHz PCI timings
implement the HDIO_GET/SET_BUSSTATE ioctls (see previous patch)
This patch does rely on the PCI busspeed patch (sent to lkml earlier).
Please let me know if you have any problems with this for general
inclusion.
Tim
--
Tim Hockin
Systems Software Engineer
Sun Microsystems, Cobalt Server Appliances
thockin@sun.com
[-- Attachment #2: hpt.diff --]
[-- Type: text/plain, Size: 14722 bytes --]
diff -ruN dist-2.4.5/drivers/ide/hpt366.c cobalt-2.4.5/drivers/ide/hpt366.c
--- dist-2.4.5/drivers/ide/hpt366.c Sat May 19 17:43:06 2001
+++ cobalt-2.4.5/drivers/ide/hpt366.c Thu May 31 14:32:15 2001
@@ -11,6 +11,17 @@
*
* Note that final HPT370 support was done by force extraction of GPL.
*
+ * add function for getting/setting power status of drive
+ * Adrian Sun <asun@cobalt.com>
+ *
+ * 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 <duncan@cobalt.com>
+ *
+ * fixup /proc output for multiple controllers
+ * Tim Hockin <thockin@sun.com>
*/
#include <linux/config.h>
@@ -28,6 +39,7 @@
#include <linux/init.h>
#include <linux/ide.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -170,62 +182,126 @@
{ 0, 0x06514e57, 0x06514e57 }
};
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+ { XFER_UDMA_5, 0x14846231, 0x14846231 },
+ { XFER_UDMA_4, 0x14886231, 0x14886231 },
+ { XFER_UDMA_3, 0x148c6231, 0x148c6231 },
+ { XFER_UDMA_2, 0x148c6231, 0x148c6231 },
+ { XFER_UDMA_1, 0x14906231, 0x14906231 },
+ { XFER_UDMA_0, 0x14986231, 0x14986231 },
+
+ { 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 }
+};
+
#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
+
+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, "Bus speed: %d MHz\n", dev->bus->bus_speed);
+ 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 ");
+
+ if (pci_rev2_check_hpt3xx(dev)) {
+ u8 c2, c3;
+ c0 = inb_p(iobase + 0x63);
+ c1 = inb_p(iobase + 0x67);
+ c2 = inb_p(iobase + 0x6b);
+ c3 = inb_p(iobase + 0x6f);
+
+ 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;
@@ -320,35 +396,76 @@
static void hpt370_tune_chipset (ide_drive_t *drive, byte speed, int direction)
{
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);
+ byte reg5bh = 0x22;
+ 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_pci = 0x40 + (drive->dn * 4);
byte drive_fast = 0;
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ int bus_freq = dev->bus->bus_speed;
- 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.
*/
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);
+ if (drive_fast & 0x02)
+ pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x02);
- pci_read_config_dword(HWIF(drive)->pci_dev, drive_pci, &drive_conf);
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x5b, reg5bh);
+ /*
+ * enable the internal PLL IFF required by drive timing,
+ * otherwise speed is based off PCI bus frequency
+ *
+ * internal PLL is required in two cases:
+ * 1. UDMA mode 5 write timing when PCI bus is at 33MHz (too slow)
+ * 2. PCI bus frequency is at 66MHz
+ *
+ * enabled by default
+ * to disable set bit 1 (0x02) of register 0x5b
+ */
+ if (bus_freq == 66 || (speed == XFER_UDMA_5 && direction)) {
+ reg5bh &= ~(0x02);
+ }
+ pci_write_config_byte(dev, 0x5b, reg5bh);
- list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
/*
- * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
+ * get drive timing values to be written to IDE Timing Register for
+ * the channel to which this drive is attached. Values depend on
+ * frequency of the PCI bus.
+ *
+ * since we don't know the actual magic algorithm, we can only know
+ * what to do at 66 or 33 MHz.
*/
- list_conf &= ~0x80000000;
+ if (bus_freq != 33 && bus_freq != 66) {
+ int n = bus_freq;
+ static int warned;
+
+ if (bus_freq <= 49) {
+ n = 33;
+ } else {
+ n = 66;
+ }
+ if (!warned) {
+ printk("HPT366: I don't know how to handle a %d MHz "
+ "bus - setting up for %d MHz\n", bus_freq, n);
+ warned = 1;
+ }
+ bus_freq = n;
+ }
+ if (bus_freq == 33) {
+ list_conf = pci_bus_clock_list(speed, direction,
+ thirty_three_base_hpt370);
+ } else if (bus_freq != 66) {
+ list_conf = pci_bus_clock_list(speed, direction,
+ sixty_six_base_hpt370);
+ }
+
+ pci_read_config_dword(dev, drive_pci, &drive_conf);
+ list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+
+ 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);
}
@@ -493,9 +610,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]);
}
}
@@ -632,14 +752,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)
@@ -653,17 +767,12 @@
if (test != 0x08)
pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+ 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;
@@ -672,31 +781,118 @@
unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
{
byte ata66 = 0;
+ int is33 = 0;
+ if (pci_rev_check_hpt3xx(hwif->pci_dev)) {
+ /* strobe bit 0 of reg 5b to latch cable detect signals */
+ pci_read_config_byte(hwif->pci_dev, 0x5b, &ata66);
+ pci_write_config_byte(hwif->pci_dev, 0x5b, ata66 | 1);
+ udelay(10);
+ pci_write_config_byte(hwif->pci_dev, 0x5b, ata66 & ~1);
+ udelay(10);
+ }
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 */
+ 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, ®5ah);
if (reg5ah & 0x10) /* interrupt force enable */
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] HPT370 misc (for real this time)
2001-06-01 1:34 ` [PATCH] HPT370 misc (for real this time) Tim Hockin
@ 2001-06-02 22:37 ` Andre Hedrick
0 siblings, 0 replies; 4+ messages in thread
From: Andre Hedrick @ 2001-06-02 22:37 UTC (permalink / raw)
To: Tim Hockin; +Cc: Linux Kernel Mailing List, alan
+ p += sprintf(p, "\nController: %d\n", i);
+ p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
+ p += sprintf(p, "Bus speed: %d MHz\n", dev->bus->bus_speed);
^^^^^^^^^^^^^^^^^^^
DNE -- Does Not Exist
+ p += sprintf(p, "--------------- Primary Channel "
+ "--------------- Secondary Channel "
+ "--------------\n");
+
Andre Hedrick
Linux ATA Development
ASL Kernel Development
-----------------------------------------------------------------------------
ASL, Inc. Toll free: 1-877-ASL-3535
1757 Houret Court Fax: 1-408-941-2071
Milpitas, CA 95035 Web: www.aslab.com
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2001-06-02 22:38 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <Pine.LNX.4.10.10103272243300.17821-100000@master.linux-ide.org>
2001-06-01 1:21 ` [PATCH] IDE GET/SET_BUSSTATE ioctls Tim Hockin
2001-06-01 1:32 ` [PATCH] HPT370 misc Tim Hockin
2001-06-01 1:34 ` [PATCH] HPT370 misc (for real this time) Tim Hockin
2001-06-02 22:37 ` Andre Hedrick
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox