Browse Source

Merge master.kernel.org:/pub/scm/linux/kernel/git/bart/ide-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/bart/ide-2.6: (23 commits)
  ide-acpi support warning fix
  ACPI support for IDE devices
  IDE Driver for Delkin/Lexar/etc.. cardbus CF adapter
  ide: it8213 IDE driver update (version 2)
  ide: add it8213 IDE driver
  tc86c001: add missing __init tag for tc86c001_ide_init()
  tc86c001: mark init_chipset_tc86c001() with __devinit tag
  tc86c001: init_hwif_tc86c001() can be static
  ide: add Toshiba TC86C001 IDE driver (take 2)
  pdc202xx_new: remove check_in_drive_lists abomination
  pdc202xx_new: remove useless code
  slc90e66: carry over fixes from piix driver
  piix: tuneproc() fixes/cleanups
  piix: fix 82371MX enablebits
  hpt366: HPT36x PCI clock detection fix
  hpt366: init code rewrite
  hpt366: clean up DMA timeout handling for HPT370
  hpt366: merge HPT37x speedproc handlers
  hpt366: cache channel's MCR address
  hpt366: switch to using pci_get_slot
  ...
Linus Torvalds 18 years ago
parent
commit
905adce409

+ 24 - 0
drivers/ide/Kconfig

@@ -167,6 +167,13 @@ config BLK_DEV_IDECS
 	  Support for Compact Flash cards, outboard IDE disks, tape drives,
 	  and CD-ROM drives connected through a PCMCIA card.
 
+config BLK_DEV_DELKIN
+	tristate "Cardbus IDE support (Delkin/ASKA/Workbit)"
+	depends on CARDBUS && PCI
+	help
+	  Support for Delkin, ASKA, and Workbit Cardbus CompactFlash
+	  Adapters.  This may also work for similar SD and XD adapters.
+
 config BLK_DEV_IDECD
 	tristate "Include IDE/ATAPI CDROM support"
 	---help---
@@ -264,6 +271,13 @@ config BLK_DEV_IDESCSI
 	  If both this SCSI emulation and native ATAPI support are compiled
 	  into the kernel, the native support will be used.
 
+config BLK_DEV_IDEACPI
+	bool "IDE ACPI support"
+	depends on ACPI
+	---help---
+	  Implement ACPI support for generic IDE devices. On modern
+	  machines ACPI support is required to properly handle ACPI S3 states.
+
 config IDE_TASK_IOCTL
 	bool "IDE Taskfile Access"
 	help
@@ -606,6 +620,11 @@ config BLK_DEV_PIIX
 	  the kernel to change PIO, DMA and UDMA speeds and to configure
 	  the chip to optimum performance.
 
+config BLK_DEV_IT8213
+	tristate "IT8213 IDE support"
+	help
+	 This driver adds support for the ITE 8213 IDE controller.
+
 config BLK_DEV_IT821X
 	tristate "IT821X IDE support"
 	help
@@ -742,6 +761,11 @@ config BLK_DEV_VIA82CXXX
 	  This allows the kernel to change PIO, DMA and UDMA speeds and to
 	  configure the chip to optimum performance.
 
+config BLK_DEV_TC86C001
+	tristate "Toshiba TC86C001 support"
+	help
+	This driver adds support for Toshiba TC86C001 GOKU-S chip.
+
 endif
 
 config BLK_DEV_IDE_PMAC

+ 1 - 0
drivers/ide/Makefile

@@ -22,6 +22,7 @@ ide-core-$(CONFIG_BLK_DEV_IDEPCI)	+= setup-pci.o
 ide-core-$(CONFIG_BLK_DEV_IDEDMA)	+= ide-dma.o
 ide-core-$(CONFIG_PROC_FS)		+= ide-proc.o
 ide-core-$(CONFIG_BLK_DEV_IDEPNP)	+= ide-pnp.o
+ide-core-$(CONFIG_BLK_DEV_IDEACPI)	+= ide-acpi.o
 
 # built-in only drivers from arm/
 ide-core-$(CONFIG_IDE_ARM)		+= arm/ide_arm.o

+ 697 - 0
drivers/ide/ide-acpi.c

@@ -0,0 +1,697 @@
+/*
+ * ide-acpi.c
+ * Provides ACPI support for IDE drives.
+ *
+ * Copyright (C) 2005 Intel Corp.
+ * Copyright (C) 2005 Randy Dunlap
+ * Copyright (C) 2006 SUSE Linux Products GmbH
+ * Copyright (C) 2006 Hannes Reinecke
+ */
+
+#include <linux/ata.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <acpi/acpi.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acnames.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/acexcep.h>
+#include <acpi/acmacros.h>
+#include <acpi/actypes.h>
+
+#define REGS_PER_GTF		7
+struct taskfile_array {
+	u8	tfa[REGS_PER_GTF];	/* regs. 0x1f1 - 0x1f7 */
+};
+
+struct GTM_buffer {
+	u32	PIO_speed0;
+	u32	DMA_speed0;
+	u32	PIO_speed1;
+	u32	DMA_speed1;
+	u32	GTM_flags;
+};
+
+struct ide_acpi_drive_link {
+	ide_drive_t	*drive;
+	acpi_handle	 obj_handle;
+	u8		 idbuff[512];
+};
+
+struct ide_acpi_hwif_link {
+	ide_hwif_t			*hwif;
+	acpi_handle			 obj_handle;
+	struct GTM_buffer		 gtm;
+	struct ide_acpi_drive_link	 master;
+	struct ide_acpi_drive_link	 slave;
+};
+
+#undef DEBUGGING
+/* note: adds function name and KERN_DEBUG */
+#ifdef DEBUGGING
+#define DEBPRINT(fmt, args...)	\
+		printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define DEBPRINT(fmt, args...)	do {} while (0)
+#endif	/* DEBUGGING */
+
+extern int ide_noacpi;
+extern int ide_noacpitfs;
+extern int ide_noacpionboot;
+
+/**
+ * ide_get_dev_handle - finds acpi_handle and PCI device.function
+ * @dev: device to locate
+ * @handle: returned acpi_handle for @dev
+ * @pcidevfn: return PCI device.func for @dev
+ *
+ * Returns the ACPI object handle to the corresponding PCI device.
+ *
+ * Returns 0 on success, <0 on error.
+ */
+static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
+			       acpi_integer *pcidevfn)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	unsigned int bus, devnum, func;
+	acpi_integer addr;
+	acpi_handle dev_handle;
+	struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER,
+					.pointer = NULL};
+	acpi_status status;
+	struct acpi_device_info	*dinfo = NULL;
+	int ret = -ENODEV;
+
+	bus = pdev->bus->number;
+	devnum = PCI_SLOT(pdev->devfn);
+	func = PCI_FUNC(pdev->devfn);
+	/* ACPI _ADR encoding for PCI bus: */
+	addr = (acpi_integer)(devnum << 16 | func);
+
+	DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func);
+
+	dev_handle = DEVICE_ACPI_HANDLE(dev);
+	if (!dev_handle) {
+		DEBPRINT("no acpi handle for device\n");
+		goto err;
+	}
+
+	status = acpi_get_object_info(dev_handle, &buffer);
+	if (ACPI_FAILURE(status)) {
+		DEBPRINT("get_object_info for device failed\n");
+		goto err;
+	}
+	dinfo = buffer.pointer;
+	if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
+	    dinfo->address == addr) {
+		*pcidevfn = addr;
+		*handle = dev_handle;
+	} else {
+		DEBPRINT("get_object_info for device has wrong "
+			" address: %llu, should be %u\n",
+			dinfo ? (unsigned long long)dinfo->address : -1ULL,
+			(unsigned int)addr);
+		goto err;
+	}
+
+	DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n",
+		 devnum, func, (unsigned long long)addr, *handle);
+	ret = 0;
+err:
+	kfree(dinfo);
+	return ret;
+}
+
+/**
+ * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif
+ * @hwif: device to locate
+ *
+ * Retrieves the object handle for a given hwif.
+ *
+ * Returns handle on success, 0 on error.
+ */
+static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
+{
+	struct device		*dev = hwif->gendev.parent;
+	acpi_handle		dev_handle;
+	acpi_integer		pcidevfn;
+	acpi_handle		chan_handle;
+	int			err;
+
+	DEBPRINT("ENTER: device %s\n", hwif->name);
+
+	if (!dev) {
+		DEBPRINT("no PCI device for %s\n", hwif->name);
+		return NULL;
+	}
+
+	err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn);
+	if (err < 0) {
+		DEBPRINT("ide_get_dev_handle failed (%d)\n", err);
+		return NULL;
+	}
+
+	/* get child objects of dev_handle == channel objects,
+	 * + _their_ children == drive objects */
+	/* channel is hwif->channel */
+	chan_handle = acpi_get_child(dev_handle, hwif->channel);
+	DEBPRINT("chan adr=%d: handle=0x%p\n",
+		 hwif->channel, chan_handle);
+
+	return chan_handle;
+}
+
+/**
+ * ide_acpi_drive_get_handle - Get ACPI object handle for a given drive
+ * @drive: device to locate
+ *
+ * Retrieves the object handle of a given drive. According to the ACPI
+ * spec the drive is a child of the hwif.
+ *
+ * Returns handle on success, 0 on error.
+ */
+static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive)
+{
+	ide_hwif_t	*hwif = HWIF(drive);
+	int		 port;
+	acpi_handle	 drive_handle;
+
+	if (!hwif->acpidata)
+		return NULL;
+
+	if (!hwif->acpidata->obj_handle)
+		return NULL;
+
+	port = hwif->channel ? drive->dn - 2: drive->dn;
+
+	DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
+		 drive->name, hwif->channel, port);
+
+
+	/* TBD: could also check ACPI object VALID bits */
+	drive_handle = acpi_get_child(hwif->acpidata->obj_handle, port);
+	DEBPRINT("drive %s handle 0x%p\n", drive->name, drive_handle);
+
+	return drive_handle;
+}
+
+/**
+ * do_drive_get_GTF - get the drive bootup default taskfile settings
+ * @drive: the drive for which the taskfile settings should be retrieved
+ * @gtf_length: number of bytes of _GTF data returned at @gtf_address
+ * @gtf_address: buffer containing _GTF taskfile arrays
+ *
+ * The _GTF method has no input parameters.
+ * It returns a variable number of register set values (registers
+ * hex 1F1..1F7, taskfiles).
+ * The <variable number> is not known in advance, so have ACPI-CA
+ * allocate the buffer as needed and return it, then free it later.
+ *
+ * The returned @gtf_length and @gtf_address are only valid if the
+ * function return value is 0.
+ */
+static int do_drive_get_GTF(ide_drive_t *drive,
+		     unsigned int *gtf_length, unsigned long *gtf_address,
+		     unsigned long *obj_loc)
+{
+	acpi_status			status;
+	struct acpi_buffer		output;
+	union acpi_object 		*out_obj;
+	ide_hwif_t			*hwif = HWIF(drive);
+	struct device			*dev = hwif->gendev.parent;
+	int				err = -ENODEV;
+	int				port;
+
+	*gtf_length = 0;
+	*gtf_address = 0UL;
+	*obj_loc = 0UL;
+
+	if (ide_noacpi)
+		return 0;
+
+	if (!dev) {
+		DEBPRINT("no PCI device for %s\n", hwif->name);
+		goto out;
+	}
+
+	if (!hwif->acpidata) {
+		DEBPRINT("no ACPI data for %s\n", hwif->name);
+		goto out;
+	}
+
+	port = hwif->channel ? drive->dn - 2: drive->dn;
+
+	if (!drive->acpidata) {
+		if (port == 0) {
+			drive->acpidata = &hwif->acpidata->master;
+			hwif->acpidata->master.drive = drive;
+		} else {
+			drive->acpidata = &hwif->acpidata->slave;
+			hwif->acpidata->slave.drive = drive;
+		}
+	}
+
+	DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
+		 hwif->name, dev->bus_id, port, hwif->channel);
+
+	if (!drive->present) {
+		DEBPRINT("%s drive %d:%d not present\n",
+			 hwif->name, hwif->channel, port);
+		goto out;
+	}
+
+	/* Get this drive's _ADR info. if not already known. */
+	if (!drive->acpidata->obj_handle) {
+		drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
+		if (!drive->acpidata->obj_handle) {
+			DEBPRINT("No ACPI object found for %s\n",
+				 drive->name);
+			goto out;
+		}
+	}
+
+	/* Setting up output buffer */
+	output.length = ACPI_ALLOCATE_BUFFER;
+	output.pointer = NULL;	/* ACPI-CA sets this; save/free it later */
+
+	/* _GTF has no input parameters */
+	err = -EIO;
+	status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF",
+				      NULL, &output);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_DEBUG
+		       "%s: Run _GTF error: status = 0x%x\n",
+		       __FUNCTION__, status);
+		goto out;
+	}
+
+	if (!output.length || !output.pointer) {
+		DEBPRINT("Run _GTF: "
+		       "length or ptr is NULL (0x%llx, 0x%p)\n",
+		       (unsigned long long)output.length,
+		       output.pointer);
+		goto out;
+	}
+
+	out_obj = output.pointer;
+	if (out_obj->type != ACPI_TYPE_BUFFER) {
+		DEBPRINT("Run _GTF: error: "
+		       "expected object type of ACPI_TYPE_BUFFER, "
+		       "got 0x%x\n", out_obj->type);
+		err = -ENOENT;
+		kfree(output.pointer);
+		goto out;
+	}
+
+	if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+	    out_obj->buffer.length % REGS_PER_GTF) {
+		printk(KERN_ERR
+		       "%s: unexpected GTF length (%d) or addr (0x%p)\n",
+		       __FUNCTION__, out_obj->buffer.length,
+		       out_obj->buffer.pointer);
+		err = -ENOENT;
+		kfree(output.pointer);
+		goto out;
+	}
+
+	*gtf_length = out_obj->buffer.length;
+	*gtf_address = (unsigned long)out_obj->buffer.pointer;
+	*obj_loc = (unsigned long)out_obj;
+	DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n",
+		 *gtf_length, *gtf_address, *obj_loc);
+	err = 0;
+out:
+	return err;
+}
+
+/**
+ * taskfile_load_raw - send taskfile registers to drive
+ * @drive: drive to which output is sent
+ * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
+ *
+ * Outputs IDE taskfile to the drive.
+ */
+static int taskfile_load_raw(ide_drive_t *drive,
+			      const struct taskfile_array *gtf)
+{
+	ide_task_t args;
+	int err = 0;
+
+	DEBPRINT("(0x1f1-1f7): hex: "
+	       "%02x %02x %02x %02x %02x %02x %02x\n",
+	       gtf->tfa[0], gtf->tfa[1], gtf->tfa[2],
+	       gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
+
+	memset(&args, 0, sizeof(ide_task_t));
+	args.command_type = IDE_DRIVE_TASK_NO_DATA;
+	args.data_phase   = TASKFILE_IN;
+	args.handler      = &task_no_data_intr;
+
+	/* convert gtf to IDE Taskfile */
+	args.tfRegister[1] = gtf->tfa[0];	/* 0x1f1 */
+	args.tfRegister[2] = gtf->tfa[1];	/* 0x1f2 */
+	args.tfRegister[3] = gtf->tfa[2];	/* 0x1f3 */
+	args.tfRegister[4] = gtf->tfa[3];	/* 0x1f4 */
+	args.tfRegister[5] = gtf->tfa[4];	/* 0x1f5 */
+	args.tfRegister[6] = gtf->tfa[5];	/* 0x1f6 */
+	args.tfRegister[7] = gtf->tfa[6];	/* 0x1f7 */
+
+	if (ide_noacpitfs) {
+		DEBPRINT("_GTF execution disabled\n");
+		return err;
+	}
+
+	err = ide_raw_taskfile(drive, &args, NULL);
+	if (err)
+		printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n",
+		       __FUNCTION__, err);
+
+	return err;
+}
+
+/**
+ * do_drive_set_taskfiles - write the drive taskfile settings from _GTF
+ * @drive: the drive to which the taskfile command should be sent
+ * @gtf_length: total number of bytes of _GTF taskfiles
+ * @gtf_address: location of _GTF taskfile arrays
+ *
+ * Write {gtf_address, length gtf_length} in groups of
+ * REGS_PER_GTF bytes.
+ */
+static int do_drive_set_taskfiles(ide_drive_t *drive,
+				  unsigned int gtf_length,
+				  unsigned long gtf_address)
+{
+	int			rc = -ENODEV, err;
+	int			gtf_count = gtf_length / REGS_PER_GTF;
+	int			ix;
+	struct taskfile_array	*gtf;
+
+	if (ide_noacpi)
+		return 0;
+
+	DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn);
+
+	if (!drive->present)
+		goto out;
+	if (!gtf_count)		/* shouldn't be here */
+		goto out;
+
+	DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n",
+		 gtf_length, gtf_length, gtf_count, gtf_address);
+
+	if (gtf_length % REGS_PER_GTF) {
+		printk(KERN_ERR "%s: unexpected GTF length (%d)\n",
+		       __FUNCTION__, gtf_length);
+		goto out;
+	}
+
+	rc = 0;
+	for (ix = 0; ix < gtf_count; ix++) {
+		gtf = (struct taskfile_array *)
+			(gtf_address + ix * REGS_PER_GTF);
+
+		/* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */
+		err = taskfile_load_raw(drive, gtf);
+		if (err)
+			rc = err;
+	}
+
+out:
+	return rc;
+}
+
+/**
+ * ide_acpi_exec_tfs - get then write drive taskfile settings
+ * @drive: the drive for which the taskfile settings should be
+ *         written.
+ *
+ * According to the ACPI spec this should be called after _STM
+ * has been evaluated for the interface. Some ACPI vendors interpret
+ * that as a hard requirement and modify the taskfile according
+ * to the Identify Drive information passed down with _STM.
+ * So one should really make sure to call this only after _STM has
+ * been executed.
+ */
+int ide_acpi_exec_tfs(ide_drive_t *drive)
+{
+	int		ret;
+	unsigned int	gtf_length;
+	unsigned long	gtf_address;
+	unsigned long	obj_loc;
+
+	if (ide_noacpi)
+		return 0;
+
+	DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn);
+
+	ret = do_drive_get_GTF(drive, &gtf_length, &gtf_address, &obj_loc);
+	if (ret < 0) {
+		DEBPRINT("get_GTF error (%d)\n", ret);
+		return ret;
+	}
+
+	DEBPRINT("call set_taskfiles, drive=%s\n", drive->name);
+
+	ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address);
+	kfree((void *)obj_loc);
+	if (ret < 0) {
+		DEBPRINT("set_taskfiles error (%d)\n", ret);
+	}
+
+	DEBPRINT("ret=%d\n", ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ide_acpi_exec_tfs);
+
+/**
+ * ide_acpi_get_timing - get the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _GTM ACPI method for the target channel.
+ *
+ */
+void ide_acpi_get_timing(ide_hwif_t *hwif)
+{
+	acpi_status		status;
+	struct acpi_buffer	output;
+	union acpi_object 	*out_obj;
+
+	if (ide_noacpi)
+		return;
+
+	DEBPRINT("ENTER:\n");
+
+	if (!hwif->acpidata) {
+		DEBPRINT("no ACPI data for %s\n", hwif->name);
+		return;
+	}
+
+	/* Setting up output buffer for _GTM */
+	output.length = ACPI_ALLOCATE_BUFFER;
+	output.pointer = NULL;	/* ACPI-CA sets this; save/free it later */
+
+	/* _GTM has no input parameters */
+	status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM",
+				      NULL, &output);
+
+	DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n",
+		 status, output.pointer,
+		 (unsigned long long)output.length);
+
+	if (ACPI_FAILURE(status)) {
+		DEBPRINT("Run _GTM error: status = 0x%x\n", status);
+		return;
+	}
+
+	if (!output.length || !output.pointer) {
+		DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n",
+		       (unsigned long long)output.length,
+		       output.pointer);
+		kfree(output.pointer);
+		return;
+	}
+
+	out_obj = output.pointer;
+	if (out_obj->type != ACPI_TYPE_BUFFER) {
+		kfree(output.pointer);
+		DEBPRINT("Run _GTM: error: "
+		       "expected object type of ACPI_TYPE_BUFFER, "
+		       "got 0x%x\n", out_obj->type);
+		return;
+	}
+
+	if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+	    out_obj->buffer.length != sizeof(struct GTM_buffer)) {
+		kfree(output.pointer);
+		printk(KERN_ERR
+			"%s: unexpected _GTM length (0x%x)[should be 0x%zx] or "
+			"addr (0x%p)\n",
+			__FUNCTION__, out_obj->buffer.length,
+			sizeof(struct GTM_buffer), out_obj->buffer.pointer);
+		return;
+	}
+
+	memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer,
+	       sizeof(struct GTM_buffer));
+
+	DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%Zx\n",
+		 out_obj->buffer.pointer, out_obj->buffer.length,
+		 sizeof(struct GTM_buffer));
+
+	DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+		 hwif->acpidata->gtm.PIO_speed0,
+		 hwif->acpidata->gtm.DMA_speed0,
+		 hwif->acpidata->gtm.PIO_speed1,
+		 hwif->acpidata->gtm.DMA_speed1,
+		 hwif->acpidata->gtm.GTM_flags);
+
+	kfree(output.pointer);
+}
+EXPORT_SYMBOL_GPL(ide_acpi_get_timing);
+
+/**
+ * ide_acpi_push_timing - set the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _STM ACPI method for the target channel.
+ *
+ * _STM requires Identify Drive data, which has to passed as an argument.
+ * Unfortunately hd_driveid is a mangled version which we can't readily
+ * use; hence we'll get the information afresh.
+ */
+void ide_acpi_push_timing(ide_hwif_t *hwif)
+{
+	acpi_status		status;
+	struct acpi_object_list	input;
+	union acpi_object 	in_params[3];
+	struct ide_acpi_drive_link	*master = &hwif->acpidata->master;
+	struct ide_acpi_drive_link	*slave = &hwif->acpidata->slave;
+
+	if (ide_noacpi)
+		return;
+
+	DEBPRINT("ENTER:\n");
+
+	if (!hwif->acpidata) {
+		DEBPRINT("no ACPI data for %s\n", hwif->name);
+		return;
+	}
+
+	/* Give the GTM buffer + drive Identify data to the channel via the
+	 * _STM method: */
+	/* setup input parameters buffer for _STM */
+	input.count = 3;
+	input.pointer = in_params;
+	in_params[0].type = ACPI_TYPE_BUFFER;
+	in_params[0].buffer.length = sizeof(struct GTM_buffer);
+	in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
+	in_params[1].type = ACPI_TYPE_BUFFER;
+	in_params[1].buffer.length = sizeof(struct hd_driveid);
+	in_params[1].buffer.pointer = (u8 *)&master->idbuff;
+	in_params[2].type = ACPI_TYPE_BUFFER;
+	in_params[2].buffer.length = sizeof(struct hd_driveid);
+	in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
+	/* Output buffer: _STM has no output */
+
+	status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM",
+				      &input, NULL);
+
+	if (ACPI_FAILURE(status)) {
+		DEBPRINT("Run _STM error: status = 0x%x\n", status);
+	}
+	DEBPRINT("_STM status: %d\n", status);
+}
+EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
+
+/**
+ * ide_acpi_init - initialize the ACPI link for an IDE interface
+ * @hwif: target IDE interface (channel)
+ *
+ * The ACPI spec is not quite clear when the drive identify buffer
+ * should be obtained. Calling IDENTIFY DEVICE during shutdown
+ * is not the best of ideas as the drive might already being put to
+ * sleep. And obviously we can't call it during resume.
+ * So we get the information during startup; but this means that
+ * any changes during run-time will be lost after resume.
+ */
+void ide_acpi_init(ide_hwif_t *hwif)
+{
+	int unit;
+	int			err;
+	struct ide_acpi_drive_link	*master;
+	struct ide_acpi_drive_link	*slave;
+
+	hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
+	if (!hwif->acpidata)
+		return;
+
+	hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif);
+	if (!hwif->acpidata->obj_handle) {
+		DEBPRINT("no ACPI object for %s found\n", hwif->name);
+		kfree(hwif->acpidata);
+		hwif->acpidata = NULL;
+		return;
+	}
+
+	/*
+	 * The ACPI spec mandates that we send information
+	 * for both drives, regardless whether they are connected
+	 * or not.
+	 */
+	hwif->acpidata->master.drive = &hwif->drives[0];
+	hwif->drives[0].acpidata = &hwif->acpidata->master;
+	master = &hwif->acpidata->master;
+
+	hwif->acpidata->slave.drive = &hwif->drives[1];
+	hwif->drives[1].acpidata = &hwif->acpidata->slave;
+	slave = &hwif->acpidata->slave;
+
+
+	/*
+	 * Send IDENTIFY for each drive
+	 */
+	if (master->drive->present) {
+		err = taskfile_lib_get_identify(master->drive, master->idbuff);
+		if (err) {
+			DEBPRINT("identify device %s failed (%d)\n",
+				 master->drive->name, err);
+		}
+	}
+
+	if (slave->drive->present) {
+		err = taskfile_lib_get_identify(slave->drive, slave->idbuff);
+		if (err) {
+			DEBPRINT("identify device %s failed (%d)\n",
+				 slave->drive->name, err);
+		}
+	}
+
+	if (ide_noacpionboot) {
+		DEBPRINT("ACPI methods disabled on boot\n");
+		return;
+	}
+
+	/*
+	 * ACPI requires us to call _STM on startup
+	 */
+	ide_acpi_get_timing(hwif);
+	ide_acpi_push_timing(hwif);
+
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+
+		if (drive->present) {
+			/* Execute ACPI startup code */
+			ide_acpi_exec_tfs(drive);
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(ide_acpi_init);

+ 3 - 0
drivers/ide/ide-probe.c

@@ -1384,6 +1384,9 @@ static int hwif_init(ide_hwif_t *hwif)
 
 done:
 	init_gendisk(hwif);
+
+	ide_acpi_init(hwif);
+
 	hwif->present = 1;	/* success */
 	return 1;
 

+ 36 - 0
drivers/ide/ide.c

@@ -187,6 +187,12 @@ int noautodma = 1;
 
 EXPORT_SYMBOL(noautodma);
 
+#ifdef CONFIG_BLK_DEV_IDEACPI
+int ide_noacpi = 0;
+int ide_noacpitfs = 1;
+int ide_noacpionboot = 1;
+#endif
+
 /*
  * This is declared extern in ide.h, for access by other IDE modules:
  */
@@ -1214,10 +1220,15 @@ EXPORT_SYMBOL(system_bus_clock);
 static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 {
 	ide_drive_t *drive = dev->driver_data;
+	ide_hwif_t *hwif = HWIF(drive);
 	struct request rq;
 	struct request_pm_state rqpm;
 	ide_task_t args;
 
+	/* Call ACPI _GTM only once */
+	if (!(drive->dn % 2))
+		ide_acpi_get_timing(hwif);
+
 	memset(&rq, 0, sizeof(rq));
 	memset(&rqpm, 0, sizeof(rqpm));
 	memset(&args, 0, sizeof(args));
@@ -1235,10 +1246,17 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 static int generic_ide_resume(struct device *dev)
 {
 	ide_drive_t *drive = dev->driver_data;
+	ide_hwif_t *hwif = HWIF(drive);
 	struct request rq;
 	struct request_pm_state rqpm;
 	ide_task_t args;
 
+	/* Call ACPI _STM only once */
+	if (!(drive->dn % 2))
+		ide_acpi_push_timing(hwif);
+
+	ide_acpi_exec_tfs(drive);
+
 	memset(&rq, 0, sizeof(rq));
 	memset(&rqpm, 0, sizeof(rqpm));
 	memset(&args, 0, sizeof(args));
@@ -1543,6 +1561,24 @@ static int __init ide_setup(char *s)
 	}
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 
+#ifdef CONFIG_BLK_DEV_IDEACPI
+	if (!strcmp(s, "ide=noacpi")) {
+		//printk(" : Disable IDE ACPI support.\n");
+		ide_noacpi = 1;
+		return 1;
+	}
+	if (!strcmp(s, "ide=acpigtf")) {
+		//printk(" : Enable IDE ACPI _GTF support.\n");
+		ide_noacpitfs = 0;
+		return 1;
+	}
+	if (!strcmp(s, "ide=acpionboot")) {
+		//printk(" : Call IDE ACPI methods on boot.\n");
+		ide_noacpionboot = 0;
+		return 1;
+	}
+#endif /* CONFIG_BLK_DEV_IDEACPI */
+
 	/*
 	 * Look for drive options:  "hdx="
 	 */

+ 3 - 1
drivers/ide/pci/Makefile

@@ -9,9 +9,10 @@ obj-$(CONFIG_BLK_DEV_CS5530)		+= cs5530.o
 obj-$(CONFIG_BLK_DEV_CS5535)		+= cs5535.o
 obj-$(CONFIG_BLK_DEV_SC1200)		+= sc1200.o
 obj-$(CONFIG_BLK_DEV_CY82C693)		+= cy82c693.o
+obj-$(CONFIG_BLK_DEV_DELKIN)		+= delkin_cb.o
 obj-$(CONFIG_BLK_DEV_HPT34X)		+= hpt34x.o
 obj-$(CONFIG_BLK_DEV_HPT366)		+= hpt366.o
-#obj-$(CONFIG_BLK_DEV_HPT37X)		+= hpt37x.o
+obj-$(CONFIG_BLK_DEV_IT8213)		+= it8213.o
 obj-$(CONFIG_BLK_DEV_IT821X)		+= it821x.o
 obj-$(CONFIG_BLK_DEV_JMICRON)		+= jmicron.o
 obj-$(CONFIG_BLK_DEV_NS87415)		+= ns87415.o
@@ -26,6 +27,7 @@ obj-$(CONFIG_BLK_DEV_SIIMAGE)		+= siimage.o
 obj-$(CONFIG_BLK_DEV_SIS5513)		+= sis5513.o
 obj-$(CONFIG_BLK_DEV_SL82C105)		+= sl82c105.o
 obj-$(CONFIG_BLK_DEV_SLC90E66)		+= slc90e66.o
+obj-$(CONFIG_BLK_DEV_TC86C001)		+= tc86c001.o
 obj-$(CONFIG_BLK_DEV_TRIFLEX)		+= triflex.o
 obj-$(CONFIG_BLK_DEV_TRM290)		+= trm290.o
 obj-$(CONFIG_BLK_DEV_VIA82CXXX)		+= via82cxxx.o

+ 140 - 0
drivers/ide/pci/delkin_cb.c

@@ -0,0 +1,140 @@
+/*
+ *  linux/drivers/ide/pci/delkin_cb.c
+ *
+ *  Created 20 Oct 2004 by Mark Lord
+ *
+ *  Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter
+ *
+ *  Modeled after the 16-bit PCMCIA driver: ide-cs.c
+ *
+ *  This is slightly peculiar, in that it is a PCI driver,
+ *  but is NOT an IDE PCI driver -- the IDE layer does not directly
+ *  support hot insertion/removal of PCI interfaces, so this driver
+ *  is unable to use the IDE PCI interfaces.  Instead, it uses the
+ *  same interfaces as the ide-cs (PCMCIA) driver uses.
+ *  On the plus side, the driver is also smaller/simpler this way.
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+#include <linux/autoconf.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+/*
+ * No chip documentation has yet been found,
+ * so these configuration values were pulled from
+ * a running Win98 system using "debug".
+ * This gives around 3MByte/second read performance,
+ * which is about 2/3 of what the chip is capable of.
+ *
+ * There is also a 4KByte mmio region on the card,
+ * but its purpose has yet to be reverse-engineered.
+ */
+static const u8 setup[] = {
+	0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00,
+	0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13,
+};
+
+static int __devinit
+delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+	unsigned long base;
+	hw_regs_t hw;
+	ide_hwif_t *hwif = NULL;
+	ide_drive_t *drive;
+	int i, rc;
+
+	rc = pci_enable_device(dev);
+	if (rc) {
+		printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc);
+		return rc;
+	}
+	rc = pci_request_regions(dev, "delkin_cb");
+	if (rc) {
+		printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc);
+		pci_disable_device(dev);
+		return rc;
+	}
+	base = pci_resource_start(dev, 0);
+	outb(0x02, base + 0x1e);	/* set nIEN to block interrupts */
+	inb(base + 0x17);		/* read status to clear interrupts */
+	for (i = 0; i < sizeof(setup); ++i) {
+		if (setup[i])
+			outb(setup[i], base + i);
+	}
+	pci_release_regions(dev);	/* IDE layer handles regions itself */
+
+	memset(&hw, 0, sizeof(hw));
+	ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
+	hw.irq = dev->irq;
+	hw.chipset = ide_pci;		/* this enables IRQ sharing */
+
+	rc = ide_register_hw_with_fixup(&hw, &hwif, ide_undecoded_slave);
+	if (rc < 0) {
+		printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
+		pci_disable_device(dev);
+		return -ENODEV;
+	}
+	pci_set_drvdata(dev, hwif);
+	hwif->pci_dev = dev;
+	drive = &hwif->drives[0];
+	if (drive->present) {
+		drive->io_32bit = 1;
+		drive->unmask   = 1;
+	}
+	return 0;
+}
+
+static void
+delkin_cb_remove (struct pci_dev *dev)
+{
+	ide_hwif_t *hwif = pci_get_drvdata(dev);
+
+	if (hwif)
+		ide_unregister(hwif->index);
+	pci_disable_device(dev);
+}
+
+static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = {
+	{ 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl);
+
+static struct pci_driver driver = {
+	.name		= "Delkin-ASKA-Workbit Cardbus IDE",
+	.id_table	= delkin_cb_pci_tbl,
+	.probe		= delkin_cb_probe,
+	.remove		= delkin_cb_remove,
+};
+
+static int
+delkin_cb_init (void)
+{
+	return pci_module_init(&driver);
+}
+
+static void
+delkin_cb_exit (void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(delkin_cb_init);
+module_exit(delkin_cb_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE");
+MODULE_LICENSE("GPL");
+

+ 819 - 764
drivers/ide/pci/hpt366.c

@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/hpt366.c		Version 0.36	April 25, 2003
+ * linux/drivers/ide/pci/hpt366.c		Version 1.01	Dec 23, 2006
  *
  * Copyright (C) 1999-2003		Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
@@ -60,13 +60,10 @@
  *   channel caused the cached register value to get out of sync with the
  *   actual one, the channels weren't serialized, the turnaround shouldn't
  *   be done on 66 MHz PCI bus
- * - avoid calibrating PLL twice as the second time results in a wrong PCI
- *   frequency and thus in the wrong timings for the secondary channel
- * - disable UltraATA/133 for HPT372 by default (50 MHz DPLL clock do not
- *   allow for this speed anyway)
- * - add support for HPT302N and HPT371N clocking (the same as for HPT372N)
- * - HPT371/N are single channel chips, so avoid touching the primary channel
- *   which exists only virtually (there's no pins for it)
+ * - disable UltraATA/100 for HPT370 by default as the 33 MHz clock being used
+ *   does not allow for this speed anyway
+ * - avoid touching disabled channels (e.g. HPT371/N are single channel chips,
+ *   their primary channel is kind of virtual, it isn't tied to any pins)
  * - fix/remove bad/unused timing tables and use one set of tables for the whole
  *   HPT37x chip family; save space by introducing the separate transfer mode
  *   table in which the mode lookup is done
@@ -76,11 +73,47 @@
  *   and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead
  * - pass to init_chipset() handlers a copy of the IDE PCI device structure as
  *   they tamper with its fields
- *		<source@mvista.com>
- *
+ * - pass  to the init_setup handlers a copy of the ide_pci_device_t structure
+ *   since they may tamper with its fields
+ * - prefix the driver startup messages with the real chip name
+ * - claim the extra 240 bytes of I/O space for all chips
+ * - optimize the rate masking/filtering and the drive list lookup code
+ * - use pci_get_slot() to get to the function 1 of HPT36x/374
+ * - cache offset of the channel's misc. control registers (MCRs) being used
+ *   throughout the driver
+ * - only touch the relevant MCR when detecting the cable type on HPT374's
+ *   function 1
+ * - rename all the register related variables consistently
+ * - move all the interrupt twiddling code from the speedproc handlers into
+ *   init_hwif_hpt366(), also grouping all the DMA related code together there
+ * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and
+ *   separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
+ *   when setting an UltraDMA mode
+ * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
+ *   the best possible one
+ * - clean up DMA timeout handling for HPT370
+ * - switch to using the enumeration type to differ between the numerous chip
+ *   variants, matching PCI device/revision ID with the chip type early, at the
+ *   init_setup stage
+ * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies,
+ *   stop duplicating it for each channel by storing the pointer in the pci_dev
+ *   structure: first, at the init_setup stage, point it to a static "template"
+ *   with only the chip type and its specific base DPLL frequency, the highest
+ *   supported DMA mode, and the chip settings table pointer filled, then, at
+ *   the init_chipset stage, allocate per-chip instance  and fill it with the
+ *   rest of the necessary information
+ * - get rid of the constant thresholds in the HPT37x PCI clock detection code,
+ *   switch  to calculating  PCI clock frequency based on the chip's base DPLL
+ *   frequency
+ * - switch to using the  DPLL clock and enable UltraATA/133 mode by default on
+ *   anything  newer than HPT370/A
+ * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(),
+ *   also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips;
+ *   unify HPT36x/37x timing setup code and the speedproc handlers by joining
+ *   the register setting lists into the table indexed by the clock selected
+ *	Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com>
  */
 
-
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -332,93 +365,159 @@ static u32 sixty_six_base_hpt37x[] = {
 };
 
 #define HPT366_DEBUG_DRIVE_INFO		0
-#define HPT374_ALLOW_ATA133_6		0
-#define HPT371_ALLOW_ATA133_6		0
-#define HPT302_ALLOW_ATA133_6		0
-#define HPT372_ALLOW_ATA133_6		0
-#define HPT370_ALLOW_ATA100_5		1
+#define HPT374_ALLOW_ATA133_6		1
+#define HPT371_ALLOW_ATA133_6		1
+#define HPT302_ALLOW_ATA133_6		1
+#define HPT372_ALLOW_ATA133_6		1
+#define HPT370_ALLOW_ATA100_5		0
 #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
+/* Supported ATA clock frequencies */
+enum ata_clock {
+	ATA_CLOCK_25MHZ,
+	ATA_CLOCK_33MHZ,
+	ATA_CLOCK_40MHZ,
+	ATA_CLOCK_50MHZ,
+	ATA_CLOCK_66MHZ,
+	NUM_ATA_CLOCKS
+};
 
 /*
- *	Hold all the highpoint quirks and revision information in one
- *	place.
+ *	Hold all the HighPoint chip information in one place.
  */
 
-struct hpt_info
-{
+struct hpt_info {
+	u8 chip_type;		/* Chip type */
 	u8 max_mode;		/* Speeds allowed */
-	int revision;		/* Chipset revision */
-	int flags;		/* Chipset properties */
-#define PLL_MODE	1
-#define IS_3xxN 	2
-#define PCI_66MHZ	4
-				/* Speed table */
-	u32 *speed;
+	u8 dpll_clk;		/* DPLL clock in MHz */
+	u8 pci_clk;		/* PCI  clock in MHz */
+	u32 **settings; 	/* Chipset settings table */
 };
 
-/*
- *	This wants fixing so that we do everything not by classrev
- *	(which breaks on the newest chips) but by creating an
- *	enumeration of chip variants and using that
- */
+/* Supported HighPoint chips */
+enum {
+	HPT36x,
+	HPT370,
+	HPT370A,
+	HPT374,
+	HPT372,
+	HPT372A,
+	HPT302,
+	HPT371,
+	HPT372N,
+	HPT302N,
+	HPT371N
+};
+
+static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = {
+	twenty_five_base_hpt36x,
+	thirty_three_base_hpt36x,
+	forty_base_hpt36x,
+	NULL,
+	NULL
+};
+
+static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = {
+	NULL,
+	thirty_three_base_hpt37x,
+	NULL,
+	fifty_base_hpt37x,
+	sixty_six_base_hpt37x
+};
+
+static struct hpt_info hpt36x __devinitdata = {
+	.chip_type	= HPT36x,
+	.max_mode	= (HPT366_ALLOW_ATA66_4 || HPT366_ALLOW_ATA66_3) ? 2 : 1,
+	.dpll_clk	= 0,	/* no DPLL */
+	.settings	= hpt36x_settings
+};
+
+static struct hpt_info hpt370 __devinitdata = {
+	.chip_type	= HPT370,
+	.max_mode	= HPT370_ALLOW_ATA100_5 ? 3 : 2,
+	.dpll_clk	= 48,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt370a __devinitdata = {
+	.chip_type	= HPT370A,
+	.max_mode	= HPT370_ALLOW_ATA100_5 ? 3 : 2,
+	.dpll_clk	= 48,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt374 __devinitdata = {
+	.chip_type	= HPT374,
+	.max_mode	= HPT374_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 48,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt372 __devinitdata = {
+	.chip_type	= HPT372,
+	.max_mode	= HPT372_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 55,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt372a __devinitdata = {
+	.chip_type	= HPT372A,
+	.max_mode	= HPT372_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 66,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt302 __devinitdata = {
+	.chip_type	= HPT302,
+	.max_mode	= HPT302_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 66,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt371 __devinitdata = {
+	.chip_type	= HPT371,
+	.max_mode	= HPT371_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 66,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt372n __devinitdata = {
+	.chip_type	= HPT372N,
+	.max_mode	= HPT372_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 77,
+	.settings	= hpt37x_settings
+};
+
+static struct hpt_info hpt302n __devinitdata = {
+	.chip_type	= HPT302N,
+	.max_mode	= HPT302_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 77,
+};
 
-static __devinit u32 hpt_revision (struct pci_dev *dev)
+static struct hpt_info hpt371n __devinitdata = {
+	.chip_type	= HPT371N,
+	.max_mode	= HPT371_ALLOW_ATA133_6 ? 4 : 3,
+	.dpll_clk	= 77,
+	.settings	= hpt37x_settings
+};
+
+static int check_in_drive_list(ide_drive_t *drive, const char **list)
 {
-	u32 class_rev;
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-	switch(dev->device) {
-		/* Remap new 372N onto 372 */
-		case PCI_DEVICE_ID_TTI_HPT372N:
-			class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
-		case PCI_DEVICE_ID_TTI_HPT374:
-			class_rev = PCI_DEVICE_ID_TTI_HPT374; break;
-		case PCI_DEVICE_ID_TTI_HPT371:
-			class_rev = PCI_DEVICE_ID_TTI_HPT371; break;
-		case PCI_DEVICE_ID_TTI_HPT302:
-			class_rev = PCI_DEVICE_ID_TTI_HPT302; break;
-		case PCI_DEVICE_ID_TTI_HPT372:
-			class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
-		default:
-			break;
-	}
-	return class_rev;
-}
+	struct hd_driveid *id = drive->id;
 
-static int check_in_drive_lists(ide_drive_t *drive, const char **list);
+	while (*list)
+		if (!strcmp(*list++,id->model))
+			return 1;
+	return 0;
+}
 
-static u8 hpt3xx_ratemask (ide_drive_t *drive)
+static u8 hpt3xx_ratemask(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif	= drive->hwif;
-	struct hpt_info *info	= ide_get_hwifdata(hwif);
-	u8 mode			= 0;
-
-	/* FIXME: TODO - move this to set info->mode once at boot */
-
-	if (info->revision >= 8) {		/* HPT374 */
-		mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
-	} else if (info->revision >= 7) {	/* HPT371 */
-		mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
-	} else if (info->revision >= 6) {	/* HPT302 */
-		mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
-	} else if (info->revision >= 5) {	/* HPT372 */
-		mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
-	} else if (info->revision >= 4) {	/* HPT370A */
-		mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
-	} else if (info->revision >= 3) {	/* HPT370 */
-		mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
-		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
-	} else {				/* HPT366 and HPT368 */
-		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
-	}
+	struct hpt_info *info	= pci_get_drvdata(HWIF(drive)->pci_dev);
+	u8 mode			= info->max_mode;
+
 	if (!eighty_ninty_three(drive) && mode)
 		mode = min(mode, (u8)1);
 	return mode;
@@ -429,75 +528,61 @@ static u8 hpt3xx_ratemask (ide_drive_t *drive)
  *	either PIO or UDMA modes 0,4,5
  */
  
-static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
+static u8 hpt3xx_ratefilter(ide_drive_t *drive, u8 speed)
 {
-	ide_hwif_t *hwif	= drive->hwif;
-	struct hpt_info *info	= ide_get_hwifdata(hwif);
+	struct hpt_info *info	= pci_get_drvdata(HWIF(drive)->pci_dev);
+	u8 chip_type		= info->chip_type;
 	u8 mode			= hpt3xx_ratemask(drive);
 
 	if (drive->media != ide_disk)
 		return min(speed, (u8)XFER_PIO_4);
 
-	switch(mode) {
+	switch (mode) {
 		case 0x04:
-			speed = min(speed, (u8)XFER_UDMA_6);
+			speed = min_t(u8, speed, XFER_UDMA_6);
 			break;
 		case 0x03:
-			speed = min(speed, (u8)XFER_UDMA_5);
-			if (info->revision >= 5)
+			speed = min_t(u8, speed, XFER_UDMA_5);
+			if (chip_type >= HPT374)
 				break;
-			if (check_in_drive_lists(drive, bad_ata100_5))
-				speed = min(speed, (u8)XFER_UDMA_4);
-			break;
+			if (!check_in_drive_list(drive, bad_ata100_5))
+				goto check_bad_ata33;
+			/* fall thru */
 		case 0x02:
-			speed = min(speed, (u8)XFER_UDMA_4);
-	/*
-	 * CHECK ME, Does this need to be set to 5 ??
-	 */
-			if (info->revision >= 3)
-				break;
-			if ((check_in_drive_lists(drive, bad_ata66_4)) ||
-			    (!(HPT366_ALLOW_ATA66_4)))
-				speed = min(speed, (u8)XFER_UDMA_3);
-			if ((check_in_drive_lists(drive, bad_ata66_3)) ||
-			    (!(HPT366_ALLOW_ATA66_3)))
-				speed = min(speed, (u8)XFER_UDMA_2);
-			break;
+			speed = min_t(u8, speed, XFER_UDMA_4);
+
+			/*
+			 * CHECK ME, Does this need to be changed to HPT374 ??
+			 */
+			if (chip_type >= HPT370)
+				goto check_bad_ata33;
+			if (HPT366_ALLOW_ATA66_4 &&
+			    !check_in_drive_list(drive, bad_ata66_4))
+				goto check_bad_ata33;
+
+			speed = min_t(u8, speed, XFER_UDMA_3);
+			if (HPT366_ALLOW_ATA66_3 &&
+			    !check_in_drive_list(drive, bad_ata66_3))
+				goto check_bad_ata33;
+			/* fall thru */
 		case 0x01:
-			speed = min(speed, (u8)XFER_UDMA_2);
-	/*
-	 * CHECK ME, Does this need to be set to 5 ??
-	 */
-			if (info->revision >= 3)
+			speed = min_t(u8, speed, XFER_UDMA_2);
+
+		check_bad_ata33:
+			if (chip_type >= HPT370A)
 				break;
-			if (check_in_drive_lists(drive, bad_ata33))
-				speed = min(speed, (u8)XFER_MW_DMA_2);
-			break;
+			if (!check_in_drive_list(drive, bad_ata33))
+				break;
+			/* fall thru */
 		case 0x00:
 		default:
-			speed = min(speed, (u8)XFER_MW_DMA_2);
+			speed = min_t(u8, speed, XFER_MW_DMA_2);
 			break;
 	}
 	return speed;
 }
 
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (quirk_drives == list) {
-		while (*list)
-			if (strstr(id->model, *list++))
-				return 1;
-	} else {
-		while (*list)
-			if (!strcmp(*list++,id->model))
-				return 1;
-	}
-	return 0;
-}
-
-static u32 pci_bus_clock_list(u8 speed, u32 *chipset_table)
+static u32 get_speed_setting(u8 speed, struct hpt_info *info)
 {
 	int i;
 
@@ -510,228 +595,161 @@ static u32 pci_bus_clock_list(u8 speed, u32 *chipset_table)
 	for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
 		if (xfer_speeds[i] == speed)
 			break;
-	return chipset_table[i];
+	/*
+	 * NOTE: info->settings only points to the pointer
+	 * to the list of the actual register values
+	 */
+	return (*info->settings)[i];
 }
 
 static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 {
-	ide_hwif_t *hwif	= drive->hwif;
-	struct pci_dev *dev	= hwif->pci_dev;
-	struct hpt_info	*info	= ide_get_hwifdata(hwif);
-	u8 speed		= hpt3xx_ratefilter(drive, xferspeed);
-	u8 regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
-	u8 regfast		= (hwif->channel) ? 0x55 : 0x51;
-	u8 drive_fast		= 0;
-	u32 reg1 = 0, reg2	= 0;
-
-	/*
-	 * Disable the "fast interrupt" prediction.
-	 */
-	pci_read_config_byte(dev, regfast, &drive_fast);
-	if (drive_fast & 0x80)
-		pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
-
-	reg2 = pci_bus_clock_list(speed, info->speed);
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev  *dev	= hwif->pci_dev;
+	struct hpt_info	*info	= pci_get_drvdata(dev);
+	u8  speed		= hpt3xx_ratefilter(drive, xferspeed);
+	u8  itr_addr		= drive->dn ? 0x44 : 0x40;
+	u32 itr_mask		= speed < XFER_MW_DMA_0 ? 0x30070000 :
+				 (speed < XFER_UDMA_0   ? 0xc0070000 : 0xc03800ff);
+	u32 new_itr		= get_speed_setting(speed, info);
+	u32 old_itr		= 0;
 
 	/*
-	 * Disable on-chip PIO FIFO/buffer
-	 *  (to avoid problems handling I/O errors later)
+	 * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
+	 * to avoid problems handling I/O errors later
 	 */
-	pci_read_config_dword(dev, regtime, &reg1);
-	if (speed >= XFER_MW_DMA_0) {
-		reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
-	} else {
-		reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
-	}	
-	reg2 &= ~0x80000000;
+	pci_read_config_dword(dev, itr_addr, &old_itr);
+	new_itr  = (new_itr & ~itr_mask) | (old_itr & itr_mask);
+	new_itr &= ~0xc0000000;
 
-	pci_write_config_dword(dev, regtime, reg2);
+	pci_write_config_dword(dev, itr_addr, new_itr);
 
 	return ide_config_drive_speed(drive, speed);
 }
 
-static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 {
-	ide_hwif_t *hwif	= drive->hwif;
-	struct pci_dev *dev = hwif->pci_dev;
-	struct hpt_info	*info	= ide_get_hwifdata(hwif);
-	u8 speed	= hpt3xx_ratefilter(drive, xferspeed);
-	u8 regfast	= (drive->hwif->channel) ? 0x55 : 0x51;
-	u8 drive_pci	= 0x40 + (drive->dn * 4);
-	u8 new_fast	= 0, drive_fast = 0;
-	u32 list_conf	= 0, drive_conf = 0;
-	u32 conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-
-	/*
-	 * Disable the "fast interrupt" prediction.
-	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
-	 */
-	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(dev, regfast, new_fast);
-
-	list_conf = pci_bus_clock_list(speed, info->speed);
-
-	pci_read_config_dword(dev, drive_pci, &drive_conf);
-	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev  *dev	= hwif->pci_dev;
+	struct hpt_info	*info	= pci_get_drvdata(dev);
+	u8  speed		= hpt3xx_ratefilter(drive, xferspeed);
+	u8  itr_addr		= 0x40 + (drive->dn * 4);
+	u32 itr_mask		= speed < XFER_MW_DMA_0 ? 0x303c0000 :
+				 (speed < XFER_UDMA_0   ? 0xc03c0000 : 0xc1c001ff);
+	u32 new_itr		= get_speed_setting(speed, info);
+	u32 old_itr		= 0;
+
+	pci_read_config_dword(dev, itr_addr, &old_itr);
+	new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
 	
 	if (speed < XFER_MW_DMA_0)
-		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
-	pci_write_config_dword(dev, drive_pci, list_conf);
+		new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+	pci_write_config_dword(dev, itr_addr, new_itr);
 
 	return ide_config_drive_speed(drive, speed);
 }
 
-static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed)
 {
-	ide_hwif_t *hwif	= drive->hwif;
-	struct pci_dev *dev	= hwif->pci_dev;
-	struct hpt_info	*info	= ide_get_hwifdata(hwif);
-	u8 speed	= hpt3xx_ratefilter(drive, xferspeed);
-	u8 regfast	= (drive->hwif->channel) ? 0x55 : 0x51;
-	u8 drive_fast	= 0, drive_pci = 0x40 + (drive->dn * 4);
-	u32 list_conf	= 0, drive_conf = 0;
-	u32 conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-
-	/*
-	 * Disable the "fast interrupt" prediction.
-	 * don't holdoff on interrupts. (== 0x01 despite what the docs say)
-	 */
-	pci_read_config_byte(dev, regfast, &drive_fast);
-	drive_fast &= ~0x07;
-	pci_write_config_byte(dev, regfast, drive_fast);
-
-	list_conf = pci_bus_clock_list(speed, info->speed);
-	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(dev, drive_pci, list_conf);
-
-	return ide_config_drive_speed(drive, speed);
-}
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hpt_info	*info	= pci_get_drvdata(hwif->pci_dev);
 
-static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed)
-{
-	ide_hwif_t *hwif	= drive->hwif;
-	struct hpt_info	*info	= ide_get_hwifdata(hwif);
-
-	if (info->revision >= 8)
-		return hpt372_tune_chipset(drive, speed); /* not a typo */
-	else if (info->revision >= 5)
-		return hpt372_tune_chipset(drive, speed);
-	else if (info->revision >= 3)
-		return hpt370_tune_chipset(drive, speed);
+	if (info->chip_type >= HPT370)
+		return hpt37x_tune_chipset(drive, speed);
 	else	/* hpt368: hpt_minimum_revision(dev, 2) */
 		return hpt36x_tune_chipset(drive, speed);
 }
 
-static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio)
+static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio)
 {
-	pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
-	(void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio));
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	(void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
 }
 
 /*
  * This allows the configuration of ide_pci chipset registers
  * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initially for designed for
+ * after the drive is reported by the OS.  Initially designed for
  * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
  *
- * check_in_drive_lists(drive, bad_ata66_4)
- * check_in_drive_lists(drive, bad_ata66_3)
- * check_in_drive_lists(drive, bad_ata33)
- *
  */
-static int config_chipset_for_dma (ide_drive_t *drive)
+static int config_chipset_for_dma(ide_drive_t *drive)
 {
 	u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
-	ide_hwif_t *hwif = drive->hwif;
-	struct hpt_info	*info	= ide_get_hwifdata(hwif);
 
 	if (!speed)
 		return 0;
 
-	/* If we don't have any timings we can't do a lot */
-	if (info->speed == NULL)
-		return 0;
-
 	(void) hpt3xx_tune_chipset(drive, speed);
 	return ide_dma_enable(drive);
 }
 
-static int hpt3xx_quirkproc (ide_drive_t *drive)
+static int hpt3xx_quirkproc(ide_drive_t *drive)
 {
-	return ((int) check_in_drive_lists(drive, quirk_drives));
+	struct hd_driveid *id	= drive->id;
+	const  char **list	= quirk_drives;
+
+	while (*list)
+		if (strstr(id->model, *list++))
+			return 1;
+	return 0;
 }
 
-static void hpt3xx_intrproc (ide_drive_t *drive)
+static void hpt3xx_intrproc(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = drive->hwif;
+	ide_hwif_t *hwif = HWIF(drive);
 
 	if (drive->quirk_list)
 		return;
 	/* drives in the quirk_list may not like intr setups/cleanups */
-	hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+	hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
 }
 
-static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
+static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
 {
-	ide_hwif_t *hwif = drive->hwif;
-	struct hpt_info *info = ide_get_hwifdata(hwif);
-	struct pci_dev *dev = hwif->pci_dev;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev	*dev	= hwif->pci_dev;
+	struct hpt_info *info	= pci_get_drvdata(dev);
 
 	if (drive->quirk_list) {
-		if (info->revision >= 3) {
-			u8 reg5a = 0;
-			pci_read_config_byte(dev, 0x5a, &reg5a);
-			if (((reg5a & 0x10) >> 4) != mask)
-				pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+		if (info->chip_type >= HPT370) {
+			u8 scr1 = 0;
+
+			pci_read_config_byte(dev, 0x5a, &scr1);
+			if (((scr1 & 0x10) >> 4) != mask) {
+				if (mask)
+					scr1 |=  0x10;
+				else
+					scr1 &= ~0x10;
+				pci_write_config_byte(dev, 0x5a, scr1);
+			}
 		} else {
-			if (mask) {
+			if (mask)
 				disable_irq(hwif->irq);
-			} else {
-				enable_irq(hwif->irq);
-			}
+			else
+				enable_irq (hwif->irq);
 		}
-	} else {
-		if (IDE_CONTROL_REG)
-			hwif->OUTB(mask ? (drive->ctl | 2) :
-						 (drive->ctl & ~2),
-						 IDE_CONTROL_REG);
-	}
+	} else
+		hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
+			   IDE_CONTROL_REG);
 }
 
-static int hpt366_config_drive_xfer_rate (ide_drive_t *drive)
+static int hpt366_config_drive_xfer_rate(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif	= drive->hwif;
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct hd_driveid *id	= drive->id;
 
 	drive->init_speed = 0;
 
 	if ((id->capability & 1) && drive->autodma) {
-
-		if (ide_use_dma(drive)) {
-			if (config_chipset_for_dma(drive))
-				return hwif->ide_dma_on(drive);
-		}
+		if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+			return hwif->ide_dma_on(drive);
 
 		goto fast_ata_pio;
 
 	} else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
-		hpt3xx_tune_drive(drive, 5);
+		hpt3xx_tune_drive(drive, 255);
 		return hwif->ide_dma_off_quietly(drive);
 	}
 	/* IORDY not supported */
@@ -739,31 +757,48 @@ fast_ata_pio:
 }
 
 /*
- * This is specific to the HPT366 UDMA bios chipset
+ * This is specific to the HPT366 UDMA chipset
  * by HighPoint|Triones Technologies, Inc.
  */
-static int hpt366_ide_dma_lostirq (ide_drive_t *drive)
+static int hpt366_ide_dma_lostirq(ide_drive_t *drive)
 {
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	u8 reg50h = 0, reg52h = 0, reg5ah = 0;
-
-	pci_read_config_byte(dev, 0x50, &reg50h);
-	pci_read_config_byte(dev, 0x52, &reg52h);
-	pci_read_config_byte(dev, 0x5a, &reg5ah);
-	printk("%s: (%s)  reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
-		drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
-	if (reg5ah & 0x10)
-		pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	u8 mcr1 = 0, mcr3 = 0, scr1 = 0;
+
+	pci_read_config_byte(dev, 0x50, &mcr1);
+	pci_read_config_byte(dev, 0x52, &mcr3);
+	pci_read_config_byte(dev, 0x5a, &scr1);
+	printk("%s: (%s)  mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n",
+		drive->name, __FUNCTION__, mcr1, mcr3, scr1);
+	if (scr1 & 0x10)
+		pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
 	return __ide_dma_lostirq(drive);
 }
 
-static void hpt370_clear_engine (ide_drive_t *drive)
+static void hpt370_clear_engine(ide_drive_t *drive)
 {
-	u8 regstate = HWIF(drive)->channel ? 0x54 : 0x50;
-	pci_write_config_byte(HWIF(drive)->pci_dev, regstate, 0x37);
+	ide_hwif_t *hwif = HWIF(drive);
+
+	pci_write_config_byte(hwif->pci_dev, hwif->select_data, 0x37);
 	udelay(10);
 }
 
+static void hpt370_irq_timeout(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u16 bfifo		= 0;
+	u8  dma_cmd;
+
+	pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
+	printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff);
+
+	/* get DMA command mode */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
+	hpt370_clear_engine(drive);
+}
+
 static void hpt370_ide_dma_start(ide_drive_t *drive)
 {
 #ifdef HPT_RESET_STATE_ENGINE
@@ -772,64 +807,35 @@ static void hpt370_ide_dma_start(ide_drive_t *drive)
 	ide_dma_start(drive);
 }
 
-static int hpt370_ide_dma_end (ide_drive_t *drive)
+static int hpt370_ide_dma_end(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
-	u8 dma_stat		= hwif->INB(hwif->dma_status);
+	u8  dma_stat		= hwif->INB(hwif->dma_status);
 
 	if (dma_stat & 0x01) {
 		/* wait a little */
 		udelay(20);
 		dma_stat = hwif->INB(hwif->dma_status);
+		if (dma_stat & 0x01)
+			hpt370_irq_timeout(drive);
 	}
-	if ((dma_stat & 0x01) != 0) 
-		/* fallthrough */
-		(void) HWIF(drive)->ide_dma_timeout(drive);
-
 	return __ide_dma_end(drive);
 }
 
-static void hpt370_lostirq_timeout (ide_drive_t *drive)
+static int hpt370_ide_dma_timeout(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 bfifo = 0, reginfo	= hwif->channel ? 0x56 : 0x52;
-	u8 dma_stat = 0, dma_cmd = 0;
-
-	pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
-	printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo);
-	hpt370_clear_engine(drive);
-	/* get dma command mode */
-	dma_cmd = hwif->INB(hwif->dma_command);
-	/* stop dma */
-	hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
-	dma_stat = hwif->INB(hwif->dma_status);
-	/* clear errors */
-	hwif->OUTB(dma_stat | 0x6, hwif->dma_status);
-}
-
-static int hpt370_ide_dma_timeout (ide_drive_t *drive)
-{
-	hpt370_lostirq_timeout(drive);
-	hpt370_clear_engine(drive);
+	hpt370_irq_timeout(drive);
 	return __ide_dma_timeout(drive);
 }
 
-static int hpt370_ide_dma_lostirq (ide_drive_t *drive)
-{
-	hpt370_lostirq_timeout(drive);
-	hpt370_clear_engine(drive);
-	return __ide_dma_lostirq(drive);
-}
-
 /* returns 1 if DMA IRQ issued, 0 otherwise */
 static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	u16 bfifo		= 0;
-	u8 reginfo		= hwif->channel ? 0x56 : 0x52;
-	u8 dma_stat;
+	u8  dma_stat;
 
-	pci_read_config_word(hwif->pci_dev, reginfo, &bfifo);
+	pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
 	if (bfifo & 0x1FF) {
 //		printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
 		return 0;
@@ -837,7 +843,7 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
 
 	dma_stat = hwif->INB(hwif->dma_status);
 	/* return 1 if INTR asserted */
-	if ((dma_stat & 4) == 4)
+	if (dma_stat & 4)
 		return 1;
 
 	if (!drive->waiting_for_dma)
@@ -846,17 +852,17 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
 	return 0;
 }
 
-static int hpt374_ide_dma_end (ide_drive_t *drive)
+static int hpt374_ide_dma_end(ide_drive_t *drive)
 {
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
 	ide_hwif_t *hwif	= HWIF(drive);
-	u8 msc_stat = 0, mscreg	= hwif->channel ? 0x54 : 0x50;
-	u8 bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01;
-
-	pci_read_config_byte(dev, 0x6a, &bwsr_stat);
-	pci_read_config_byte(dev, mscreg, &msc_stat);
-	if ((bwsr_stat & bwsr_mask) == bwsr_mask)
-		pci_write_config_byte(dev, mscreg, msc_stat|0x30);
+	struct pci_dev	*dev	= hwif->pci_dev;
+	u8 mcr	= 0, mcr_addr	= hwif->select_data;
+	u8 bwsr = 0, mask	= hwif->channel ? 0x02 : 0x01;
+
+	pci_read_config_byte(dev, 0x6a, &bwsr);
+	pci_read_config_byte(dev, mcr_addr, &mcr);
+	if (bwsr & mask)
+		pci_write_config_byte(dev, mcr_addr, mcr | 0x30);
 	return __ide_dma_end(drive);
 }
 
@@ -866,40 +872,37 @@ static int hpt374_ide_dma_end (ide_drive_t *drive)
  *	@mode: clocking mode (0x21 for write, 0x23 otherwise)
  *
  *	Switch the DPLL clock on the HPT3xxN devices. This is a	right mess.
- *	NOTE: avoid touching the disabled primary channel on HPT371N -- it
- *	doesn't physically exist anyway...
  */
 
 static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
 {
-	u8 mcr1, scr2 = hwif->INB(hwif->dma_master + 0x7b);
+	u8 scr2 = hwif->INB(hwif->dma_master + 0x7b);
 
 	if ((scr2 & 0x7f) == mode)
 		return;
 
-	/* MISC. control register 1 has the channel enable bit... */
-	mcr1 = hwif->INB(hwif->dma_master + 0x70);
-
 	/* Tristate the bus */
-	if (mcr1 & 0x04)
-		hwif->OUTB(0x80, hwif->dma_master + 0x73);
+	hwif->OUTB(0x80, hwif->dma_master + 0x73);
 	hwif->OUTB(0x80, hwif->dma_master + 0x77);
 
 	/* Switch clock and reset channels */
 	hwif->OUTB(mode, hwif->dma_master + 0x7b);
 	hwif->OUTB(0xc0, hwif->dma_master + 0x79);
 
-	/* Reset state machines */
-	if (mcr1 & 0x04)
-		hwif->OUTB(0x37, hwif->dma_master + 0x70);
-	hwif->OUTB(0x37, hwif->dma_master + 0x74);
+	/*
+	 * Reset the state machines.
+	 * NOTE: avoid accidentally enabling the disabled channels.
+	 */
+	hwif->OUTB(hwif->INB(hwif->dma_master + 0x70) | 0x32,
+		   hwif->dma_master + 0x70);
+	hwif->OUTB(hwif->INB(hwif->dma_master + 0x74) | 0x32,
+		   hwif->dma_master + 0x74);
 
 	/* Complete reset */
 	hwif->OUTB(0x00, hwif->dma_master + 0x79);
 
 	/* Reconnect channels to bus */
-	if (mcr1 & 0x04)
-		hwif->OUTB(0x00, hwif->dma_master + 0x73);
+	hwif->OUTB(0x00, hwif->dma_master + 0x73);
 	hwif->OUTB(0x00, hwif->dma_master + 0x77);
 }
 
@@ -914,14 +917,12 @@ static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
 
 static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 wantclock		= rq_data_dir(rq) ? 0x23 : 0x21;
-
-	hpt3xxn_set_clock(hwif, wantclock);
+	hpt3xxn_set_clock(HWIF(drive), rq_data_dir(rq) ? 0x23 : 0x21);
 }
 
 /* 
  * Set/get power state for a drive.
+ * NOTE: affects both drives on each channel.
  *
  * When we turn the power back on, we need to re-initialize things.
  */
@@ -929,26 +930,18 @@ static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
 
 static int hpt3xx_busproc(ide_drive_t *drive, int state)
 {
-	ide_hwif_t *hwif	= drive->hwif;
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-	u8  tristate, resetmask, bus_reg = 0;
-	u16 tri_reg = 0;
+	u8  mcr_addr		= hwif->select_data + 2;
+	u8  resetmask		= hwif->channel ? 0x80 : 0x40;
+	u8  bsr2		= 0;
+	u16 mcr			= 0;
 
 	hwif->bus_state = state;
 
-	if (hwif->channel) { 
-		/* secondary channel */
-		tristate  = 0x56;
-		resetmask = 0x80;
-	} else { 
-		/* primary channel */
-		tristate  = 0x52;
-		resetmask = 0x40;
-	}
-
 	/* Grab the status. */
-	pci_read_config_word(dev, tristate, &tri_reg);
-	pci_read_config_byte(dev, 0x59, &bus_reg);
+	pci_read_config_word(dev, mcr_addr, &mcr);
+	pci_read_config_byte(dev, 0x59, &bsr2);
 
 	/*
 	 * Set the state. We don't set it if we don't need to do so.
@@ -956,22 +949,22 @@ static int hpt3xx_busproc(ide_drive_t *drive, int state)
 	 */
 	switch (state) {
 	case BUSSTATE_ON:
-		if (!(bus_reg & resetmask))
+		if (!(bsr2 & resetmask))
 			return 0;
 		hwif->drives[0].failures = hwif->drives[1].failures = 0;
 
-		pci_write_config_byte(dev, 0x59, bus_reg & ~resetmask);
-		pci_write_config_word(dev, tristate, tri_reg & ~TRISTATE_BIT);
+		pci_write_config_byte(dev, 0x59, bsr2 & ~resetmask);
+		pci_write_config_word(dev, mcr_addr, mcr & ~TRISTATE_BIT);
 		return 0;
 	case BUSSTATE_OFF:
-		if ((bus_reg & resetmask) && !(tri_reg & TRISTATE_BIT))
+		if ((bsr2 & resetmask) && !(mcr & TRISTATE_BIT))
 			return 0;
-		tri_reg &= ~TRISTATE_BIT;
+		mcr &= ~TRISTATE_BIT;
 		break;
 	case BUSSTATE_TRISTATE:
-		if ((bus_reg & resetmask) &&  (tri_reg & TRISTATE_BIT))
+		if ((bsr2 & resetmask) &&  (mcr & TRISTATE_BIT))
 			return 0;
-		tri_reg |= TRISTATE_BIT;
+		mcr |= TRISTATE_BIT;
 		break;
 	default:
 		return -EINVAL;
@@ -980,268 +973,320 @@ static int hpt3xx_busproc(ide_drive_t *drive, int state)
 	hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
 	hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
 
-	pci_write_config_word(dev, tristate, tri_reg);
-	pci_write_config_byte(dev, 0x59, bus_reg | resetmask);
+	pci_write_config_word(dev, mcr_addr, mcr);
+	pci_write_config_byte(dev, 0x59, bsr2 | resetmask);
 	return 0;
 }
 
-static void __devinit hpt366_clocking(ide_hwif_t *hwif)
+/**
+ *	hpt37x_calibrate_dpll	-	calibrate the DPLL
+ *	@dev: PCI device
+ *
+ *	Perform a calibration cycle on the DPLL.
+ *	Returns 1 if this succeeds
+ */
+static int __devinit hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high)
 {
-	u32 reg1	= 0;
-	struct hpt_info *info = ide_get_hwifdata(hwif);
+	u32 dpll = (f_high << 16) | f_low | 0x100;
+	u8  scr2;
+	int i;
 
-	pci_read_config_dword(hwif->pci_dev, 0x40, &reg1);
+	pci_write_config_dword(dev, 0x5c, dpll);
 
-	/* detect bus speed by looking at control reg timing: */
-	switch((reg1 >> 8) & 7) {
-		case 5:
-			info->speed = forty_base_hpt36x;
-			break;
-		case 9:
-			info->speed = twenty_five_base_hpt36x;
-			break;
-		case 7:
-		default:
-			info->speed = thirty_three_base_hpt36x;
+	/* Wait for oscillator ready */
+	for(i = 0; i < 0x5000; ++i) {
+		udelay(50);
+		pci_read_config_byte(dev, 0x5b, &scr2);
+		if (scr2 & 0x80)
 			break;
 	}
+	/* See if it stays ready (we'll just bail out if it's not yet) */
+	for(i = 0; i < 0x1000; ++i) {
+		pci_read_config_byte(dev, 0x5b, &scr2);
+		/* DPLL destabilized? */
+		if(!(scr2 & 0x80))
+			return 0;
+	}
+	/* Turn off tuning, we have the DPLL set */
+	pci_read_config_dword (dev, 0x5c, &dpll);
+	pci_write_config_dword(dev, 0x5c, (dpll & ~0x100));
+	return 1;
 }
 
-static void __devinit hpt37x_clocking(ide_hwif_t *hwif)
+static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
 {
-	struct hpt_info *info = ide_get_hwifdata(hwif);
-	struct pci_dev *dev = hwif->pci_dev;
-	int adjust, i;
-	u16 freq = 0;
-	u32 pll, temp = 0;
-	u8 reg5bh = 0, mcr1 = 0;
-	
+	struct hpt_info *info	= kmalloc(sizeof(struct hpt_info), GFP_KERNEL);
+	unsigned long io_base	= pci_resource_start(dev, 4);
+	u8 pci_clk,  dpll_clk	= 0;	/* PCI and DPLL clock in MHz */
+	enum ata_clock	clock;
+
+	if (info == NULL) {
+		printk(KERN_ERR "%s: out of memory!\n", name);
+		return -ENOMEM;
+	}
+
 	/*
-	 * default to pci clock. make sure MA15/16 are set to output
-	 * to prevent drives having problems with 40-pin cables. Needed
-	 * for some drives such as IBM-DTLA which will not enter ready
-	 * state on reset when PDIAG is a input.
-	 *
-	 * ToDo: should we set 0x21 when using PLL mode ?
+	 * Copy everything from a static "template" structure
+	 * to just allocated per-chip hpt_info structure.
 	 */
-	pci_write_config_byte(dev, 0x5b, 0x23);
+	*info = *(struct hpt_info *)pci_get_drvdata(dev);
 
 	/*
-	 * We'll have to read f_CNT value in order to determine
-	 * the PCI clock frequency according to the following ratio:
-	 *
-	 * f_CNT = Fpci * 192 / Fdpll
-	 *
-	 * First try reading the register in which the HighPoint BIOS
-	 * saves f_CNT value before  reprogramming the DPLL from its
-	 * default setting (which differs for the various chips).
-	 * NOTE: This register is only accessible via I/O space.
-	 *
-	 * In case the signature check fails, we'll have to resort to
-	 * reading the f_CNT register itself in hopes that nobody has
-	 * touched the DPLL yet...
+	 * FIXME: Not portable. Also, why do we enable the ROM in the first place?
+	 * We don't seem to be using it.
 	 */
-	temp = inl(pci_resource_start(dev, 4) + 0x90);
-	if ((temp & 0xFFFFF000) != 0xABCDE000) {
-		printk(KERN_WARNING "HPT37X: no clock data saved by BIOS\n");
-
-		/* Calculate the average value of f_CNT */
-		for (temp = i = 0; i < 128; i++) {
-			pci_read_config_word(dev, 0x78, &freq);
-			temp += freq & 0x1ff;
-			mdelay(1);
-		}
-		freq = temp / 128;
-	} else
-		freq = temp & 0x1ff;
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+
+	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+	pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+	pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
 
 	/*
-	 * HPT3xxN chips use different PCI clock information.
-	 * Currently we always set up the PLL for them.
+	 * First, try to estimate the PCI clock frequency...
 	 */
+	if (info->chip_type >= HPT370) {
+		u8  scr1  = 0;
+		u16 f_cnt = 0;
+		u32 temp  = 0;
 
-	if (info->flags & IS_3xxN) {
-		if(freq < 0x55)
-			pll = F_LOW_PCI_33;
-		else if(freq < 0x70)
-			pll = F_LOW_PCI_40;
-		else if(freq < 0x7F)
-			pll = F_LOW_PCI_50;
-		else
-			pll = F_LOW_PCI_66;
+		/* Interrupt force enable. */
+		pci_read_config_byte(dev, 0x5a, &scr1);
+		if (scr1 & 0x10)
+			pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
 
-		printk(KERN_INFO "HPT3xxN detected, FREQ: %d, PLL: %d\n", freq, pll);
-	}
-	else
-	{
-		if(freq < 0x9C)
-			pll = F_LOW_PCI_33;
-		else if(freq < 0xb0)
-			pll = F_LOW_PCI_40;
-		else if(freq <0xc8)
-			pll = F_LOW_PCI_50;
+		/*
+		 * HighPoint does this for HPT372A.
+		 * NOTE: This register is only writeable via I/O space.
+		 */
+		if (info->chip_type == HPT372A)
+			outb(0x0e, io_base + 0x9c);
+
+		/*
+		 * 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);
+
+		/*
+		 * We'll have to read f_CNT value in order to determine
+		 * the PCI clock frequency according to the following ratio:
+		 *
+		 * f_CNT = Fpci * 192 / Fdpll
+		 *
+		 * First try reading the register in which the HighPoint BIOS
+		 * saves f_CNT value before  reprogramming the DPLL from its
+		 * default setting (which differs for the various chips).
+		 * NOTE: This register is only accessible via I/O space.
+		 *
+		 * In case the signature check fails, we'll have to resort to
+		 * reading the f_CNT register itself in hopes that nobody has
+		 * touched the DPLL yet...
+		 */
+		temp = inl(io_base + 0x90);
+		if ((temp & 0xFFFFF000) != 0xABCDE000) {
+			int i;
+
+			printk(KERN_WARNING "%s: no clock data saved by BIOS\n",
+			       name);
+
+			/* Calculate the average value of f_CNT. */
+			for (temp = i = 0; i < 128; i++) {
+				pci_read_config_word(dev, 0x78, &f_cnt);
+				temp += f_cnt & 0x1ff;
+				mdelay(1);
+			}
+			f_cnt = temp / 128;
+		} else
+			f_cnt = temp & 0x1ff;
+
+		dpll_clk = info->dpll_clk;
+		pci_clk  = (f_cnt * dpll_clk) / 192;
+
+		/* Clamp PCI clock to bands. */
+		if (pci_clk < 40)
+			pci_clk = 33;
+		else if(pci_clk < 45)
+			pci_clk = 40;
+		else if(pci_clk < 55)
+			pci_clk = 50;
 		else
-			pll = F_LOW_PCI_66;
-	
-		if (pll == F_LOW_PCI_33) {
-			info->speed = thirty_three_base_hpt37x;
-			printk(KERN_DEBUG "HPT37X: using 33MHz PCI clock\n");
-		} else if (pll == F_LOW_PCI_40) {
-			/* Unsupported */
-		} else if (pll == F_LOW_PCI_50) {
-			info->speed = fifty_base_hpt37x;
-			printk(KERN_DEBUG "HPT37X: using 50MHz PCI clock\n");
-		} else {
-			info->speed = sixty_six_base_hpt37x;
-			printk(KERN_DEBUG "HPT37X: using 66MHz PCI clock\n");
+			pci_clk = 66;
+
+		printk(KERN_INFO "%s: DPLL base: %d MHz, f_CNT: %d, "
+		       "assuming %d MHz PCI\n", name, dpll_clk, f_cnt, pci_clk);
+	} else {
+		u32 itr1 = 0;
+
+		pci_read_config_dword(dev, 0x40, &itr1);
+
+		/* Detect PCI clock by looking at cmd_high_time. */
+		switch((itr1 >> 8) & 0x07) {
+			case 0x09:
+				pci_clk = 40;
+				break;
+			case 0x05:
+				pci_clk = 25;
+				break;
+			case 0x07:
+			default:
+				pci_clk = 33;
+				break;
 		}
 	}
 
-	if (pll == F_LOW_PCI_66)
-		info->flags |= PCI_66MHZ;
+	/* Let's assume we'll use PCI clock for the ATA clock... */
+	switch (pci_clk) {
+		case 25:
+			clock = ATA_CLOCK_25MHZ;
+			break;
+		case 33:
+		default:
+			clock = ATA_CLOCK_33MHZ;
+			break;
+		case 40:
+			clock = ATA_CLOCK_40MHZ;
+			break;
+		case 50:
+			clock = ATA_CLOCK_50MHZ;
+			break;
+		case 66:
+			clock = ATA_CLOCK_66MHZ;
+			break;
+	}
 
 	/*
-	 * 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.
+	 * Only try the DPLL if we don't have a table for the PCI clock that
+	 * we are running at for HPT370/A, always use it  for anything newer...
 	 *
-	 * ToDo: Use 66MHz PLL when ATA133 devices are present on a
-	 * 372 device so we can get ATA133 support
+	 * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI.
+	 * We also  don't like using  the DPLL because this causes glitches
+	 * on PRST-/SRST- when the state engine gets reset...
 	 */
-	if (info->speed)
-		goto init_hpt37X_done;
+	if (info->chip_type >= HPT374 || info->settings[clock] == NULL) {
+		u16 f_low, delta = pci_clk < 50 ? 2 : 4;
+		int adjust;
+
+		 /*
+		  * Select 66 MHz DPLL clock only if UltraATA/133 mode is
+		  * supported/enabled, use 50 MHz DPLL clock otherwise...
+		  */
+		if (info->max_mode == 0x04) {
+			dpll_clk = 66;
+			clock = ATA_CLOCK_66MHZ;
+		} else if (dpll_clk) {	/* HPT36x chips don't have DPLL */
+			dpll_clk = 50;
+			clock = ATA_CLOCK_50MHZ;
+		}
 
-	info->flags |= PLL_MODE;
-	
-	/*
-	 * Adjust the PLL based upon the 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);
-
-				info->speed = fifty_base_hpt37x;
-				printk("HPT37X: using 50MHz internal PLL\n");
-				goto init_hpt37X_done;
-			}
+		if (info->settings[clock] == NULL) {
+			printk(KERN_ERR "%s: unknown bus timing!\n", name);
+			kfree(info);
+			return -EIO;
 		}
-pll_recal:
-		if (adjust & 1)
-			pll -= (adjust >> 1);
-		else
-			pll += (adjust >> 1);
-	} 
 
-init_hpt37X_done:
-	if (!info->speed)
-		printk(KERN_ERR "HPT37x%s: unknown bus timing [%d %d].\n",
-		       (info->flags & IS_3xxN) ? "N" : "", pll, freq);
-	/*
-	 * Reset the state engines.
-	 * NOTE: avoid accidentally enabling the primary channel on HPT371N.
-	 */
-	pci_read_config_byte(dev, 0x50, &mcr1);
-	if (mcr1 & 0x04)
-		pci_write_config_byte(dev, 0x50, 0x37);
-	pci_write_config_byte(dev, 0x54, 0x37);
-	udelay(100);
-}
+		/* Select the DPLL clock. */
+		pci_write_config_byte(dev, 0x5b, 0x21);
 
-static int __devinit init_hpt37x(struct pci_dev *dev)
-{
-	u8 reg5ah;
+		/*
+		 * Adjust the DPLL based upon PCI clock, enable it,
+		 * and wait for stabilization...
+		 */
+		f_low = (pci_clk * 48) / dpll_clk;
 
-	pci_read_config_byte(dev, 0x5a, &reg5ah);
-	/* interrupt force enable */
-	pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
-	return 0;
-}
+		for (adjust = 0; adjust < 8; adjust++) {
+			if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta))
+				break;
 
-static int __devinit init_hpt366(struct pci_dev *dev)
-{
-	u32 reg1	= 0;
-	u8 drive_fast	= 0;
+			/*
+			 * See if it'll settle at a fractionally different clock
+			 */
+			if (adjust & 1)
+				f_low -= adjust >> 1;
+			else
+				f_low += adjust >> 1;
+		}
+		if (adjust == 8) {
+			printk(KERN_ERR "%s: DPLL did not stabilize!\n", name);
+			kfree(info);
+			return -EIO;
+		}
 
-	/*
-	 * Disable the "fast interrupt" prediction.
-	 */
-	pci_read_config_byte(dev, 0x51, &drive_fast);
-	if (drive_fast & 0x80)
-		pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
-	pci_read_config_dword(dev, 0x40, &reg1);
-									
-	return 0;
-}
+		printk("%s: using %d MHz DPLL clock\n", name, dpll_clk);
+	} else {
+		/* Mark the fact that we're not using the DPLL. */
+		dpll_clk = 0;
 
-static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
-{
-	int ret = 0;
+		printk("%s: using %d MHz PCI clock\n", name, pci_clk);
+	}
 
 	/*
-	 * FIXME: Not portable. Also, why do we enable the ROM in the first place?
-	 * We don't seem to be using it.
+	 * Advance the table pointer to a slot which points to the list
+	 * of the register values settings matching the clock being used.
 	 */
-	if (dev->resource[PCI_ROM_RESOURCE].start)
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
-			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+	info->settings += clock;
 
-	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
-	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
-	pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
-	pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+	/* Store the clock frequencies. */
+	info->dpll_clk	= dpll_clk;
+	info->pci_clk	= pci_clk;
 
-	if (hpt_revision(dev) >= 3)
-		ret = init_hpt37x(dev);
-	else
-		ret = init_hpt366(dev);
+	/* Point to this chip's own instance of the hpt_info structure. */
+	pci_set_drvdata(dev, info);
 
-	if (ret)
-		return ret;
+	if (info->chip_type >= HPT370) {
+		u8  mcr1, mcr4;
+
+		/*
+		 * Reset the state engines.
+		 * NOTE: Avoid accidentally enabling the disabled channels.
+		 */
+		pci_read_config_byte (dev, 0x50, &mcr1);
+		pci_read_config_byte (dev, 0x54, &mcr4);
+		pci_write_config_byte(dev, 0x50, (mcr1 | 0x32));
+		pci_write_config_byte(dev, 0x54, (mcr4 | 0x32));
+		udelay(100);
+	}
+
+	/*
+	 * On  HPT371N, if ATA clock is 66 MHz we must set bit 2 in
+	 * the MISC. register to stretch the UltraDMA Tss timing.
+	 * NOTE: This register is only writeable via I/O space.
+	 */
+	if (info->chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
+
+		outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c);
 
 	return dev->irq;
 }
 
 static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
 {
-	struct pci_dev *dev		= hwif->pci_dev;
-	struct hpt_info *info		= ide_get_hwifdata(hwif);
-	u8 ata66 = 0, regmask		= (hwif->channel) ? 0x01 : 0x02;
+	struct pci_dev	*dev		= hwif->pci_dev;
+	struct hpt_info *info		= pci_get_drvdata(dev);
 	int serialize			= HPT_SERIALIZE_IO;
-	
+	u8  scr1 = 0, ata66		= (hwif->channel) ? 0x01 : 0x02;
+	u8  chip_type			= info->chip_type;
+	u8  new_mcr, old_mcr 		= 0;
+
+	/* Cache the channel's MISC. control registers' offset */
+	hwif->select_data		= hwif->channel ? 0x54 : 0x50;
+
 	hwif->tuneproc			= &hpt3xx_tune_drive;
 	hwif->speedproc			= &hpt3xx_tune_chipset;
 	hwif->quirkproc			= &hpt3xx_quirkproc;
 	hwif->intrproc			= &hpt3xx_intrproc;
 	hwif->maskproc			= &hpt3xx_maskproc;
-	
+	hwif->busproc			= &hpt3xx_busproc;
+
 	/*
 	 * HPT3xxN chips have some complications:
 	 *
 	 * - on 33 MHz PCI we must clock switch
 	 * - on 66 MHz PCI we must NOT use the PCI clock
 	 */
-	if ((info->flags & (IS_3xxN | PCI_66MHZ)) == IS_3xxN) {
+	if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) {
 		/*
 		 * Clock is shared between the channels,
 		 * so we'll have to serialize them... :-(
@@ -1250,200 +1295,171 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
 		hwif->rw_disk = &hpt3xxn_rw_disk;
 	}
 
+	/* Serialize access to this device if needed */
+	if (serialize && hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
+
+	/*
+	 * Disable the "fast interrupt" prediction.  Don't hold off
+	 * on interrupts. (== 0x01 despite what the docs say)
+	 */
+	pci_read_config_byte(dev, hwif->select_data + 1, &old_mcr);
+
+	if (info->chip_type >= HPT374)
+		new_mcr = old_mcr & ~0x07;
+	else if (info->chip_type >= HPT370) {
+		new_mcr = old_mcr;
+		new_mcr &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+		new_mcr &= ~0x01;
+#else
+		new_mcr |=  0x01;
+#endif
+	} else					/* HPT366 and HPT368  */
+		new_mcr = old_mcr & ~0x80;
+
+	if (new_mcr != old_mcr)
+		pci_write_config_byte(dev, hwif->select_data + 1, new_mcr);
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+
 	/*
 	 * The HPT37x uses the CBLID pins as outputs for MA15/MA16
-	 * address lines to access an external eeprom.  To read valid
+	 * address lines to access an external EEPROM.  To read valid
 	 * cable detect state the pins must be enabled as inputs.
 	 */
-	if (info->revision >= 8 && (PCI_FUNC(dev->devfn) & 1)) {
+	if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
 		/*
 		 * HPT374 PCI function 1
 		 * - set bit 15 of reg 0x52 to enable TCBLID as input
 		 * - set bit 15 of reg 0x56 to enable FCBLID as input
 		 */
-		u16 mcr3, mcr6;
-		pci_read_config_word(dev, 0x52, &mcr3);
-		pci_read_config_word(dev, 0x56, &mcr6);
-		pci_write_config_word(dev, 0x52, mcr3 | 0x8000);
-		pci_write_config_word(dev, 0x56, mcr6 | 0x8000);
+		u8  mcr_addr = hwif->select_data + 2;
+		u16 mcr;
+
+		pci_read_config_word (dev, mcr_addr, &mcr);
+		pci_write_config_word(dev, mcr_addr, (mcr | 0x8000));
 		/* now read cable id register */
-		pci_read_config_byte(dev, 0x5a, &ata66);
-		pci_write_config_word(dev, 0x52, mcr3);
-		pci_write_config_word(dev, 0x56, mcr6);
-	} else if (info->revision >= 3) {
+		pci_read_config_byte (dev, 0x5a, &scr1);
+		pci_write_config_word(dev, mcr_addr, mcr);
+	} else if (chip_type >= HPT370) {
 		/*
 		 * HPT370/372 and 374 pcifn 0
-		 * - clear bit 0 of 0x5b to enable P/SCBLID as inputs
+		 * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
 		 */
-		u8 scr2;
-		pci_read_config_byte(dev, 0x5b, &scr2);
-		pci_write_config_byte(dev, 0x5b, scr2 & ~1);
-		/* now read cable id register */
-		pci_read_config_byte(dev, 0x5a, &ata66);
-		pci_write_config_byte(dev, 0x5b, scr2);
-	} else {
-		pci_read_config_byte(dev, 0x5a, &ata66);
-	}
+		u8 scr2 = 0;
 
-#ifdef DEBUG
-	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
-		ata66, (ata66 & regmask) ? "33" : "66",
-		PCI_FUNC(hwif->pci_dev->devfn));
-#endif /* DEBUG */
-
-	/* Serialize access to this device */
-	if (serialize && hwif->mate)
-		hwif->serialized = hwif->mate->serialized = 1;
+		pci_read_config_byte (dev, 0x5b, &scr2);
+		pci_write_config_byte(dev, 0x5b, (scr2 & ~1));
+		/* now read cable id register */
+		pci_read_config_byte (dev, 0x5a, &scr1);
+		pci_write_config_byte(dev, 0x5b,  scr2);
+	} else
+		pci_read_config_byte (dev, 0x5a, &scr1);
 
-	/*
-	 * Set up ioctl for power status.
-	 * NOTE:  power affects both drives on each channel.
-	 */
-	hwif->busproc = &hpt3xx_busproc;
+	if (!hwif->udma_four)
+		hwif->udma_four = (scr1 & ata66) ? 0 : 1;
 
-	if (!hwif->dma_base) {
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-		return;
-	}
+	hwif->ide_dma_check		= &hpt366_config_drive_xfer_rate;
 
-	hwif->ultra_mask = 0x7f;
-	hwif->mwdma_mask = 0x07;
-
-	if (!(hwif->udma_four))
-		hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
-	hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
-
-	if (info->revision >= 8) {
-		hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
-		hwif->ide_dma_end = &hpt374_ide_dma_end;
-	} else if (info->revision >= 5) {
-		hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
-		hwif->ide_dma_end = &hpt374_ide_dma_end;
-	} else if (info->revision >= 3) {
-		hwif->dma_start = &hpt370_ide_dma_start;
-		hwif->ide_dma_end = &hpt370_ide_dma_end;
-		hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
-		hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
-	} else if (info->revision >= 2)
-		hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
-	else
-		hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+	if (chip_type >= HPT374) {
+		hwif->ide_dma_test_irq	= &hpt374_ide_dma_test_irq;
+		hwif->ide_dma_end	= &hpt374_ide_dma_end;
+	} else if (chip_type >= HPT370) {
+		hwif->dma_start 	= &hpt370_ide_dma_start;
+		hwif->ide_dma_end	= &hpt370_ide_dma_end;
+		hwif->ide_dma_timeout	= &hpt370_ide_dma_timeout;
+	} else
+		hwif->ide_dma_lostirq	= &hpt366_ide_dma_lostirq;
 
 	if (!noautodma)
 		hwif->autodma = 1;
-	hwif->drives[0].autodma = hwif->autodma;
-	hwif->drives[1].autodma = hwif->autodma;
+	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
 }
 
 static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
 {
-	struct hpt_info	*info	= ide_get_hwifdata(hwif);
-	u8 masterdma	= 0, slavedma = 0;
-	u8 dma_new	= 0, dma_old = 0;
-	u8 primary	= hwif->channel ? 0x4b : 0x43;
-	u8 secondary	= hwif->channel ? 0x4f : 0x47;
+	struct pci_dev	*dev		= hwif->pci_dev;
+	u8 masterdma	= 0, slavedma	= 0;
+	u8 dma_new	= 0, dma_old	= 0;
 	unsigned long flags;
 
 	if (!dmabase)
 		return;
 		
-	if(info->speed == NULL) {
-		printk(KERN_WARNING "hpt366: no known IDE timings, disabling DMA.\n");
-		return;
-	}
-
-	dma_old = hwif->INB(dmabase+2);
+	dma_old = hwif->INB(dmabase + 2);
 
 	local_irq_save(flags);
 
 	dma_new = dma_old;
-	pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
-	pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
+	pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma);
+	pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47,  &slavedma);
 
 	if (masterdma & 0x30)	dma_new |= 0x20;
-	if (slavedma & 0x30)	dma_new |= 0x40;
+	if ( slavedma & 0x30)	dma_new |= 0x40;
 	if (dma_new != dma_old)
-		hwif->OUTB(dma_new, dmabase+2);
+		hwif->OUTB(dma_new, dmabase + 2);
 
 	local_irq_restore(flags);
 
 	ide_setup_dma(hwif, dmabase, 8);
 }
 
-/*
- *	We "borrow" this hook in order to set the data structures
- *	up early enough before dma or init_hwif calls are made.
- */
-
-static void __devinit init_iops_hpt366(ide_hwif_t *hwif)
-{
-	struct hpt_info *info	= kzalloc(sizeof(struct hpt_info), GFP_KERNEL);
-	struct pci_dev  *dev	= hwif->pci_dev;
-	u16 did			= dev->device;
-	u8  rid			= 0;
-
-	if(info == NULL) {
-		printk(KERN_WARNING "hpt366: out of memory.\n");
-		return;
-	}
-	ide_set_hwifdata(hwif, info);
-
-	/* Avoid doing the same thing twice. */
-	if (hwif->channel && hwif->mate) {
-		memcpy(info, ide_get_hwifdata(hwif->mate), sizeof(struct hpt_info));
-		return;
-	}
-
-	pci_read_config_byte(dev, PCI_CLASS_REVISION, &rid);
-
-	if (( did == PCI_DEVICE_ID_TTI_HPT366  && rid == 6) ||
-	    ((did == PCI_DEVICE_ID_TTI_HPT372  ||
-	      did == PCI_DEVICE_ID_TTI_HPT302  ||
-	      did == PCI_DEVICE_ID_TTI_HPT371) && rid > 1) ||
-	      did == PCI_DEVICE_ID_TTI_HPT372N)
-		info->flags |= IS_3xxN;
-
-	info->revision = hpt_revision(dev);
-
-	if (info->revision >= 3)
-		hpt37x_clocking(hwif);
-	else
-		hpt366_clocking(hwif);
-}
-
 static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
 {
-	struct pci_dev *findev = NULL;
+	struct pci_dev *dev2;
 
 	if (PCI_FUNC(dev->devfn) & 1)
 		return -ENODEV;
 
-	while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
-		if ((findev->vendor == dev->vendor) &&
-		    (findev->device == dev->device) &&
-		    ((findev->devfn - dev->devfn) == 1) &&
-		    (PCI_FUNC(findev->devfn) & 1)) {
-			if (findev->irq != dev->irq) {
-				/* FIXME: we need a core pci_set_interrupt() */
-				findev->irq = dev->irq;
-				printk(KERN_WARNING "%s: pci-config space interrupt "
-					"fixed.\n", d->name);
-			}
-			return ide_setup_pci_devices(dev, findev, d);
+	pci_set_drvdata(dev, &hpt374);
+
+	if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
+		int ret;
+
+		pci_set_drvdata(dev2, &hpt374);
+
+		if (dev2->irq != dev->irq) {
+			/* FIXME: we need a core pci_set_interrupt() */
+			dev2->irq = dev->irq;
+			printk(KERN_WARNING "%s: PCI config space interrupt "
+			       "fixed.\n", d->name);
 		}
+		ret = ide_setup_pci_devices(dev, dev2, d);
+		if (ret < 0)
+			pci_dev_put(dev2);
+		return ret;
 	}
 	return ide_setup_pci_device(dev, d);
 }
 
-static int __devinit init_setup_hpt37x(struct pci_dev *dev, ide_pci_device_t *d)
+static int __devinit init_setup_hpt372n(struct pci_dev *dev, ide_pci_device_t *d)
 {
+	pci_set_drvdata(dev, &hpt372n);
+
 	return ide_setup_pci_device(dev, d);
 }
 
 static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
 {
-	u8 mcr1 = 0;
+	struct hpt_info *info;
+	u8 rev = 0, mcr1 = 0;
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+	if (rev > 1) {
+		d->name = "HPT371N";
+
+		info = &hpt371n;
+	} else
+		info = &hpt371;
 
 	/*
 	 * HPT371 chips physically have only one channel, the secondary one,
@@ -1453,59 +1469,94 @@ static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
 	 */
 	pci_read_config_byte(dev, 0x50, &mcr1);
 	if (mcr1 & 0x04)
-		pci_write_config_byte(dev, 0x50, (mcr1 & ~0x04));
+		pci_write_config_byte(dev, 0x50, mcr1 & ~0x04);
+
+	pci_set_drvdata(dev, info);
+
+	return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_hpt372a(struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct hpt_info *info;
+	u8 rev = 0;
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+	if (rev > 1) {
+		d->name = "HPT372N";
+
+		info = &hpt372n;
+	} else
+		info = &hpt372a;
+	pci_set_drvdata(dev, info);
+
+	return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_hpt302(struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct hpt_info *info;
+	u8 rev = 0;
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+	if (rev > 1) {
+		d->name = "HPT302N";
+
+		info = &hpt302n;
+	} else
+		info = &hpt302;
+	pci_set_drvdata(dev, info);
 
 	return ide_setup_pci_device(dev, d);
 }
 
 static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
 {
-	struct pci_dev *findev = NULL;
-	u8 pin1 = 0, pin2 = 0;
-	unsigned int class_rev;
-	char *chipset_names[] = {"HPT366", "HPT366",  "HPT368",
-				 "HPT370", "HPT370A", "HPT372",
-				 "HPT372N" };
+	struct pci_dev *dev2;
+	u8 rev = 0;
+	static char   *chipset_names[] = { "HPT366", "HPT366",  "HPT368",
+					   "HPT370", "HPT370A", "HPT372",
+					   "HPT372N" };
+	static struct hpt_info *info[] = { &hpt36x,  &hpt36x,  &hpt36x,
+					   &hpt370,  &hpt370a, &hpt372,
+					   &hpt372n  };
 
 	if (PCI_FUNC(dev->devfn) & 1)
 		return -ENODEV;
 
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
+	pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
 
-	if(dev->device == PCI_DEVICE_ID_TTI_HPT372N)
-		class_rev = 6;
+	if (rev > 6)
+		rev = 6;
 		
-	if(class_rev <= 6)
-		d->name = chipset_names[class_rev];
-
-	switch(class_rev) {
-		case 6:
-		case 5:
-		case 4:
-		case 3:
-			goto init_single;
-		default:
-			break;
-	}
+	d->name = chipset_names[rev];
+
+	pci_set_drvdata(dev, info[rev]);
+
+	if (rev > 2)
+		goto init_single;
 
 	d->channels = 1;
 
-	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
-	while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
-		if ((findev->vendor == dev->vendor) &&
-		    (findev->device == dev->device) &&
-		    ((findev->devfn - dev->devfn) == 1) &&
-		    (PCI_FUNC(findev->devfn) & 1)) {
-			pci_read_config_byte(findev, PCI_INTERRUPT_PIN, &pin2);
-			if ((pin1 != pin2) && (dev->irq == findev->irq)) {
-				d->bootable = ON_BOARD;
-				printk("%s: onboard version of chipset, "
-					"pin1=%d pin2=%d\n", d->name,
-					pin1, pin2);
-			}
-			return ide_setup_pci_devices(dev, findev, d);
+	if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
+	  	u8  pin1 = 0, pin2 = 0;
+		int ret;
+
+		pci_set_drvdata(dev2, info[rev]);
+
+		pci_read_config_byte(dev,  PCI_INTERRUPT_PIN, &pin1);
+		pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
+		if (pin1 != pin2 && dev->irq == dev2->irq) {
+			d->bootable = ON_BOARD;
+			printk("%s: onboard version of chipset, pin1=%d pin2=%d\n",
+			       d->name, pin1, pin2);
 		}
+		ret = ide_setup_pci_devices(dev, dev2, d);
+		if (ret < 0)
+			pci_dev_put(dev2);
+		return ret;
 	}
 init_single:
 	return ide_setup_pci_device(dev, d);
@@ -1516,64 +1567,68 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
 		.name		= "HPT366",
 		.init_setup	= init_setup_hpt366,
 		.init_chipset	= init_chipset_hpt366,
-		.init_iops	= init_iops_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.channels	= 2,
 		.autodma	= AUTODMA,
+		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
 		.bootable	= OFF_BOARD,
 		.extra		= 240
 	},{	/* 1 */
 		.name		= "HPT372A",
-		.init_setup	= init_setup_hpt37x,
+		.init_setup	= init_setup_hpt372a,
 		.init_chipset	= init_chipset_hpt366,
-		.init_iops	= init_iops_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.channels	= 2,
 		.autodma	= AUTODMA,
+		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
 		.bootable	= OFF_BOARD,
+		.extra		= 240
 	},{	/* 2 */
 		.name		= "HPT302",
-		.init_setup	= init_setup_hpt37x,
+		.init_setup	= init_setup_hpt302,
 		.init_chipset	= init_chipset_hpt366,
-		.init_iops	= init_iops_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.channels	= 2,
 		.autodma	= AUTODMA,
+		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
 		.bootable	= OFF_BOARD,
+		.extra		= 240
 	},{	/* 3 */
 		.name		= "HPT371",
 		.init_setup	= init_setup_hpt371,
 		.init_chipset	= init_chipset_hpt366,
-		.init_iops	= init_iops_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
 		.bootable	= OFF_BOARD,
+		.extra		= 240
 	},{	/* 4 */
 		.name		= "HPT374",
 		.init_setup	= init_setup_hpt374,
 		.init_chipset	= init_chipset_hpt366,
-		.init_iops	= init_iops_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.channels	= 2,	/* 4 */
 		.autodma	= AUTODMA,
+		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
 		.bootable	= OFF_BOARD,
+		.extra		= 240
 	},{	/* 5 */
 		.name		= "HPT372N",
-		.init_setup	= init_setup_hpt37x,
+		.init_setup	= init_setup_hpt372n,
 		.init_chipset	= init_chipset_hpt366,
-		.init_iops	= init_iops_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
 		.channels	= 2,	/* 4 */
 		.autodma	= AUTODMA,
+		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
 		.bootable	= OFF_BOARD,
+		.extra		= 240
 	}
 };
 

+ 362 - 0
drivers/ide/pci/it8213.c

@@ -0,0 +1,362 @@
+/*
+ * ITE 8213 IDE driver
+ *
+ * Copyright (C) 2006 Jack Lee
+ * Copyright (C) 2006 Alan Cox
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+/*
+ *	it8213_ratemask	-	Compute available modes
+ *	@drive: IDE drive
+ *
+ *	Compute the available speeds for the devices on the interface. This
+ *	is all modes to ATA133 clipped by drive cable setup.
+ */
+
+static u8 it8213_ratemask (ide_drive_t *drive)
+{
+	u8 mode	= 4;
+	if (!eighty_ninty_three(drive))
+		mode = min_t(u8, mode, 1);
+	return mode;
+}
+
+/**
+ *	it8213_dma_2_pio		-	return the PIO mode matching DMA
+ *	@xfer_rate: transfer speed
+ *
+ *	Returns the nearest equivalent PIO timing for the PIO or DMA
+ *	mode requested by the controller.
+ */
+
+static u8 it8213_dma_2_pio (u8 xfer_rate) {
+	switch(xfer_rate) {
+		case XFER_UDMA_6:
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+/*
+ *	it8213_tuneproc	-	tune a drive
+ *	@drive: drive to tune
+ *	@pio: desired PIO mode
+ *
+ *	Set the interface PIO mode.
+ */
+
+static void it8213_tuneproc (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= drive->dn & 1;
+	int master_port		= 0x40;
+	int slave_port		= 0x44;
+	unsigned long flags;
+	u16 master_data;
+	u8 slave_data;
+	static DEFINE_SPINLOCK(tune_lock);
+	int control = 0;
+
+	static const u8 timings[][2]= {
+					{ 0, 0 },
+					{ 0, 0 },
+					{ 1, 0 },
+					{ 2, 1 },
+					{ 2, 3 }, };
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+
+	spin_lock_irqsave(&tune_lock, flags);
+	pci_read_config_word(dev, master_port, &master_data);
+
+	if (pio > 1)
+		control |= 1;	/* Programmable timing on */
+	if (drive->media != ide_disk)
+		control |= 4;	/* ATAPI */
+	if (pio > 2)
+		control |= 2;	/* IORDY */
+	if (is_slave) {
+		master_data |=  0x4000;
+		master_data &= ~0x0070;
+		if (pio > 1)
+			master_data = master_data | (control << 4);
+		pci_read_config_byte(dev, slave_port, &slave_data);
+		slave_data = slave_data & 0xf0;
+		slave_data = slave_data | (timings[pio][0] << 2) | timings[pio][1];
+	} else {
+		master_data &= ~0x3307;
+		if (pio > 1)
+			master_data = master_data | control;
+		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+	}
+	pci_write_config_word(dev, master_port, master_data);
+	if (is_slave)
+		pci_write_config_byte(dev, slave_port, slave_data);
+	spin_unlock_irqrestore(&tune_lock, flags);
+}
+
+/**
+ *	it8213_tune_chipset	-	set controller timings
+ *	@drive: Drive to set up
+ *	@xferspeed: speed we want to achieve
+ *
+ *	Tune the ITE chipset for the desired mode. If we can't achieve
+ *	the desired mode then tune for a lower one, but ultimately
+ *	make the thing work.
+ */
+
+static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 maslave		= 0x40;
+	u8 speed		= ide_rate_filter(it8213_ratemask(drive), xferspeed);
+	int a_speed		= 3 << (drive->dn * 4);
+	int u_flag		= 1 << drive->dn;
+	int v_flag		= 0x01 << drive->dn;
+	int w_flag		= 0x10 << drive->dn;
+	int u_speed		= 0;
+	u16			reg4042, reg4a;
+	u8			reg48, reg54, reg55;
+
+	pci_read_config_word(dev, maslave, &reg4042);
+	pci_read_config_byte(dev, 0x48, &reg48);
+	pci_read_config_word(dev, 0x4a, &reg4a);
+	pci_read_config_byte(dev, 0x54, &reg54);
+	pci_read_config_byte(dev, 0x55, &reg55);
+
+	switch(speed) {
+		case XFER_UDMA_6:
+		case XFER_UDMA_4:
+		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_5:
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+			break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_SW_DMA_2:
+			break;
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+			break;
+		default:
+			return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		if (!(reg48 & u_flag))
+			pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+		if (speed >= XFER_UDMA_5) {
+			pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
+		} else {
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+		}
+
+		if ((reg4a & a_speed) != u_speed)
+			pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
+		if (speed > XFER_UDMA_2) {
+			if (!(reg54 & v_flag))
+				pci_write_config_byte(dev, 0x54, reg54 | v_flag);
+		} else
+			pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+	} else {
+		if (reg48 & u_flag)
+			pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+		if (reg54 & v_flag)
+			pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+		if (reg55 & w_flag)
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+	}
+	it8213_tuneproc(drive, it8213_dma_2_pio(speed));
+	return ide_config_drive_speed(drive, speed);
+}
+
+/*
+ *	config_chipset_for_dma	-	configure for DMA
+ *	@drive: drive to configure
+ *
+ *	Called by the IDE layer when it wants the timings set up.
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, it8213_ratemask(drive));
+
+	if (!speed)
+		return 0;
+
+	it8213_tune_chipset(drive, speed);
+
+	return ide_dma_enable(drive);
+}
+
+/**
+ *	it8213_configure_drive_for_dma	-	set up for DMA transfers
+ *	@drive: drive we are going to set up
+ *
+ *	Set up the drive for DMA, tune the controller and drive as
+ *	required. If the drive isn't suitable for DMA or we hit
+ *	other problems then we will drop down to PIO and set up
+ *	PIO appropriately
+ */
+
+static int it8213_config_drive_for_dma (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = drive->hwif;
+
+	if (ide_use_dma(drive)) {
+		if (config_chipset_for_dma(drive))
+			return hwif->ide_dma_on(drive);
+	}
+
+	hwif->speedproc(drive, XFER_PIO_0
+			+ ide_get_best_pio_mode(drive, 255, 4, NULL));
+
+ 	return hwif->ide_dma_off_quietly(drive);
+}
+
+/**
+ *	init_hwif_it8213	-	set up hwif structs
+ *	@hwif: interface to set up
+ *
+ *	We do the basic set up of the interface structure. The IT8212
+ *	requires several custom handlers so we override the default
+ *	ide DMA handlers appropriately
+ */
+
+static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
+{
+	u8 reg42h = 0, ata66 = 0;
+
+	hwif->speedproc = &it8213_tune_chipset;
+	hwif->tuneproc	= &it8213_tuneproc;
+
+	hwif->autodma = 0;
+
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x06;
+	hwif->swdma_mask = 0x04;
+
+	pci_read_config_byte(hwif->pci_dev, 0x42, &reg42h);
+	ata66 = (reg42h & 0x02) ? 0 : 1;
+
+	hwif->ide_dma_check = &it8213_config_drive_for_dma;
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66;
+
+	/*
+	 *	The BIOS often doesn't set up DMA on this controller
+	 *	so we always do it.
+	 */
+	if (!noautodma)
+		hwif->autodma = 1;
+
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+
+#define DECLARE_ITE_DEV(name_str)			\
+	{						\
+		.name		= name_str,		\
+		.init_hwif	= init_hwif_it8213,	\
+		.channels	= 1,			\
+		.autodma	= AUTODMA,		\
+		.enablebits	= {{0x41,0x80,0x80}}, \
+		.bootable	= ON_BOARD,		\
+	}
+
+static ide_pci_device_t it8213_chipsets[] __devinitdata = {
+	/* 0 */ DECLARE_ITE_DEV("IT8213"),
+};
+
+
+/**
+ *	it8213_init_one	-	pci layer discovery entry
+ *	@dev: PCI device
+ *	@id: ident table entry
+ *
+ *	Called by the PCI code when it finds an ITE8213 controller. As
+ *	this device follows the standard interfaces we can use the
+ *	standard helper functions to do almost all the work for us.
+ */
+
+static int __devinit it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_setup_pci_device(dev, &it8213_chipsets[id->driver_data]);
+	return 0;
+}
+
+
+static struct pci_device_id it8213_pci_tbl[] = {
+	{ PCI_VENDOR_ID_ITE, 0x8213, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, it8213_pci_tbl);
+
+static struct pci_driver driver = {
+	.name		= "ITE8213_IDE",
+	.id_table	= it8213_pci_tbl,
+	.probe		= it8213_init_one,
+};
+
+static int __init it8213_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+module_init(it8213_ide_init);
+
+MODULE_AUTHOR("Jack Lee, Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for the ITE 8213");
+MODULE_LICENSE("GPL");

+ 8 - 48
drivers/ide/pci/pdc202xx_new.c

@@ -92,26 +92,6 @@ static u8 pdcnew_ratemask(ide_drive_t *drive)
 	return	mode;
 }
 
-static int check_in_drive_lists(ide_drive_t *drive, const char **list)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (pdc_quirk_drives == list) {
-		while (*list) {
-			if (strstr(id->model, *list++)) {
-				return 2;
-			}
-		}
-	} else {
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
 /**
  * get_indexed_reg - Get indexed register
  * @hwif: for the port address
@@ -249,13 +229,6 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed)
 	return err;
 }
 
-/*   0    1    2    3    4    5    6   7   8
- * 960, 480, 390, 300, 240, 180, 120, 90, 60
- *           180, 150, 120,  90,  60
- * DMA_Speed
- * 180, 120,  90,  90,  90,  60,  30
- *  11,   5,   4,   3,   2,   1,   0
- */
 static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
 {
 	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
@@ -313,12 +286,10 @@ static int pdcnew_config_drive_xfer_rate(ide_drive_t *drive)
 
 	drive->init_speed = 0;
 
-	if (id && (id->capability & 1) && drive->autodma) {
+	if ((id->capability & 1) && drive->autodma) {
 
-		if (ide_use_dma(drive)) {
-			if (config_chipset_for_dma(drive))
-				return hwif->ide_dma_on(drive);
-		}
+		if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+			return hwif->ide_dma_on(drive);
 
 		goto fast_ata_pio;
 
@@ -333,21 +304,12 @@ fast_ata_pio:
 
 static int pdcnew_quirkproc(ide_drive_t *drive)
 {
-	return check_in_drive_lists(drive, pdc_quirk_drives);
-}
+	const char **list, *model = drive->id->model;
 
-static int pdcnew_ide_dma_lostirq(ide_drive_t *drive)
-{
-	if (HWIF(drive)->resetproc != NULL)
-		HWIF(drive)->resetproc(drive);
-	return __ide_dma_lostirq(drive);
-}
-
-static int pdcnew_ide_dma_timeout(ide_drive_t *drive)
-{
-	if (HWIF(drive)->resetproc != NULL)
-		HWIF(drive)->resetproc(drive);
-	return __ide_dma_timeout(drive);
+	for (list = pdc_quirk_drives; *list != NULL; list++)
+		if (strstr(model, *list) != NULL)
+			return 2;
+	return 0;
 }
 
 static void pdcnew_reset(ide_drive_t *drive)
@@ -599,8 +561,6 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
 	hwif->err_stops_fifo = 1;
 
 	hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
-	hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
-	hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
 
 	if (!hwif->udma_four)
 		hwif->udma_four = pdcnew_cable_detect(hwif) ? 0 : 1;

+ 6 - 21
drivers/ide/pci/pdc202xx_old.c

@@ -123,26 +123,6 @@ static u8 pdc202xx_ratemask (ide_drive_t *drive)
 	return mode;
 }
 
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (pdc_quirk_drives == list) {
-		while (*list) {
-			if (strstr(id->model, *list++)) {
-				return 2;
-			}
-		}
-	} else {
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
 static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
@@ -377,7 +357,12 @@ fast_ata_pio:
 
 static int pdc202xx_quirkproc (ide_drive_t *drive)
 {
-	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+	const char **list, *model = drive->id->model;
+
+	for (list = pdc_quirk_drives; *list != NULL; list++)
+		if (strstr(model, *list) != NULL)
+			return 2;
+	return 0;
 }
 
 static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)

+ 18 - 13
drivers/ide/pci/piix.c

@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/pci/piix.c	Version 0.45	May 12, 2006
+ *  linux/drivers/ide/pci/piix.c	Version 0.46	December 3, 2006
  *
  *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
  *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
@@ -163,7 +163,7 @@ static u8 piix_ratemask (ide_drive_t *drive)
 	 *	if the drive cannot see an 80pin cable.
 	 */
 	if (!eighty_ninty_three(drive))
-		mode = min(mode, (u8)1);
+		mode = min_t(u8, mode, 1);
 	return mode;
 }
 
@@ -216,7 +216,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-	int is_slave		= (&hwif->drives[1] == drive);
+	int is_slave		= drive->dn & 1;
 	int master_port		= hwif->channel ? 0x42 : 0x40;
 	int slave_port		= 0x44;
 	unsigned long flags;
@@ -225,7 +225,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
 	static DEFINE_SPINLOCK(tune_lock);
 	int control = 0;
 
-				 /* ISP  RTC */
+				     /* ISP  RTC */
 	static const u8 timings[][2]= {
 					{ 0, 0 },
 					{ 0, 0 },
@@ -233,7 +233,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
 					{ 2, 1 },
 					{ 2, 3 }, };
 
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 
 	/*
 	 * Master vs slave is synchronized above us but the slave register is
@@ -243,25 +243,24 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
 	spin_lock_irqsave(&tune_lock, flags);
 	pci_read_config_word(dev, master_port, &master_data);
 
-	if (pio >= 2)
+	if (pio > 1)
 		control |= 1;	/* Programmable timing on */
 	if (drive->media == ide_disk)
 		control |= 4;	/* Prefetch, post write */
-	if (pio >= 3)
+	if (pio > 2)
 		control |= 2;	/* IORDY */
 	if (is_slave) {
-		master_data = master_data | 0x4000;
+		master_data |=  0x4000;
+		master_data &= ~0x0070;
 		if (pio > 1) {
 			/* enable PPE, IE and TIME */
 			master_data = master_data | (control << 4);
-		} else {
-			master_data &= ~0x0070;
 		}
 		pci_read_config_byte(dev, slave_port, &slave_data);
 		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
 		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
 	} else {
-		master_data = master_data & 0xccf8;
+		master_data &= ~0x3307;
 		if (pio > 1) {
 			/* enable PPE, IE and TIME */
 			master_data = master_data | control;
@@ -539,13 +538,19 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = {
 	/*  0 */ DECLARE_PIIX_DEV("PIIXa"),
 	/*  1 */ DECLARE_PIIX_DEV("PIIXb"),
 
-	{	/* 2 */
+	/*  2 */
+	{	/*
+		 * MPIIX actually has only a single IDE channel mapped to
+		 * the primary or secondary ports depending on the value
+		 * of the bit 14 of the IDETIM register at offset 0x6c
+		 */
 		.name		= "MPIIX",
 		.init_hwif	= init_hwif_piix,
 		.channels	= 2,
 		.autodma	= NODMA,
-		.enablebits	= {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},
+		.enablebits	= {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
 		.bootable	= ON_BOARD,
+		.flags		= IDEPCI_FLAG_ISA_PORTS
 	},
 
 	/*  3 */ DECLARE_PIIX_DEV("PIIX3"),

+ 34 - 21
drivers/ide/pci/slc90e66.c

@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/pci/slc90e66.c	Version 0.12	May 12, 2006
+ *  linux/drivers/ide/pci/slc90e66.c	Version 0.13	December 30, 2006
  *
  *  Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
  *  Copyright (C) 2006 MontaVista Software, Inc. <source@mvista.com>
@@ -26,7 +26,7 @@ static u8 slc90e66_ratemask (ide_drive_t *drive)
 	u8 mode	= 2;
 
 	if (!eighty_ninty_three(drive))
-		mode = min(mode, (u8)1);
+		mode = min_t(u8, mode, 1);
 	return mode;
 }
 
@@ -65,36 +65,47 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-	int is_slave		= (&hwif->drives[1] == drive);
+	int is_slave		= drive->dn & 1;
 	int master_port		= hwif->channel ? 0x42 : 0x40;
 	int slave_port		= 0x44;
 	unsigned long flags;
 	u16 master_data;
 	u8 slave_data;
-				 /* ISP  RTC */
+ 	int control = 0;
+				     /* ISP  RTC */
 	static const u8 timings[][2]= {
-				    { 0, 0 },
-				    { 0, 0 },
-				    { 1, 0 },
-				    { 2, 1 },
-				    { 2, 3 }, };
+					{ 0, 0 },
+					{ 0, 0 },
+					{ 1, 0 },
+					{ 2, 1 },
+					{ 2, 3 }, };
 
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 	spin_lock_irqsave(&ide_lock, flags);
 	pci_read_config_word(dev, master_port, &master_data);
+
+	if (pio > 1)
+		control |= 1;	/* Programmable timing on */
+	if (drive->media == ide_disk)
+		control |= 4;	/* Prefetch, post write */
+	if (pio > 2)
+		control |= 2;	/* IORDY */
 	if (is_slave) {
-		master_data = master_data | 0x4000;
-		if (pio > 1)
+		master_data |=  0x4000;
+		master_data &= ~0x0070;
+		if (pio > 1) {
 			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0070;
+			master_data = master_data | (control << 4);
+		}
 		pci_read_config_byte(dev, slave_port, &slave_data);
 		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
 		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
 	} else {
-		master_data = master_data & 0xccf8;
-		if (pio > 1)
+		master_data &= ~0x3307;
+		if (pio > 1) {
 			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0007;
+			master_data = master_data | control;
+		}
 		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
 	}
 	pci_write_config_word(dev, master_port, master_data);
@@ -173,7 +184,7 @@ static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
 
 	drive->init_speed = 0;
 
-	if (id && (id->capability & 1) && drive->autodma) {
+	if ((id->capability & 1) && drive->autodma) {
 
 		if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive))
 			return hwif->ide_dma_on(drive);
@@ -201,7 +212,7 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
 		hwif->irq = hwif->channel ? 15 : 14;
 
 	hwif->speedproc = &slc90e66_tune_chipset;
-	hwif->tuneproc = &slc90e66_tune_drive;
+	hwif->tuneproc	= &slc90e66_tune_drive;
 
 	pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
 
@@ -213,14 +224,16 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
 
 	hwif->atapi_dma = 1;
 	hwif->ultra_mask = 0x1f;
-	hwif->mwdma_mask = 0x07;
-	hwif->swdma_mask = 0x07;
+	hwif->mwdma_mask = 0x06;
+	hwif->swdma_mask = 0x04;
 
-	if (!(hwif->udma_four))
+	if (!hwif->udma_four) {
 		/* bit[0(1)]: 0:80, 1:40 */
 		hwif->udma_four = (reg47 & mask) ? 0 : 1;
+	}
 
 	hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate;
+
 	if (!noautodma)
 		hwif->autodma = 1;
 	hwif->drives[0].autodma = hwif->autodma;

+ 309 - 0
drivers/ide/pci/tc86c001.c

@@ -0,0 +1,309 @@
+/*
+ * drivers/ide/pci/tc86c001.c	Version 1.00	Dec 12, 2006
+ *
+ * Copyright (C) 2002 Toshiba Corporation
+ * Copyright (C) 2005-2006 MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static inline u8 tc86c001_ratemask(ide_drive_t *drive)
+{
+	return eighty_ninty_three(drive) ? 2 : 1;
+}
+
+static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long scr_port	= hwif->config_data + (drive->dn ? 0x02 : 0x00);
+	u16 mode, scr		= hwif->INW(scr_port);
+
+	speed = ide_rate_filter(tc86c001_ratemask(drive), speed);
+
+	switch (speed) {
+		case XFER_UDMA_4:	mode = 0x00c0; break;
+		case XFER_UDMA_3:	mode = 0x00b0; break;
+		case XFER_UDMA_2:	mode = 0x00a0; break;
+		case XFER_UDMA_1:	mode = 0x0090; break;
+		case XFER_UDMA_0:	mode = 0x0080; break;
+		case XFER_MW_DMA_2:	mode = 0x0070; break;
+		case XFER_MW_DMA_1:	mode = 0x0060; break;
+		case XFER_MW_DMA_0:	mode = 0x0050; break;
+		case XFER_PIO_4:	mode = 0x0400; break;
+		case XFER_PIO_3:	mode = 0x0300; break;
+		case XFER_PIO_2:	mode = 0x0200; break;
+		case XFER_PIO_1:	mode = 0x0100; break;
+		case XFER_PIO_0:
+		default:		mode = 0x0000; break;
+	}
+
+	scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f;
+	scr |= mode;
+	hwif->OUTW(scr, scr_port);
+
+	return ide_config_drive_speed(drive, speed);
+}
+
+static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio)
+{
+	pio =  ide_get_best_pio_mode(drive, pio, 4, NULL);
+	(void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio);
+}
+
+/*
+ * HACKITY HACK
+ *
+ * This is a workaround for the limitation 5 of the TC86C001 IDE controller:
+ * if a DMA transfer terminates prematurely, the controller leaves the device's
+ * interrupt request (INTRQ) pending and does not generate a PCI interrupt (or
+ * set the interrupt bit in the DMA status register), thus no PCI interrupt
+ * will occur until a DMA transfer has been successfully completed.
+ *
+ * We work around this by initiating dummy, zero-length DMA transfer on
+ * a DMA timeout expiration. I found no better way to do this with the current
+ * IDE core than to temporarily replace a higher level driver's timer expiry
+ * handler with our own backing up to that handler in case our recovery fails.
+ */
+static int tc86c001_timer_expiry(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	ide_expiry_t *expiry	= ide_get_hwifdata(hwif);
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
+
+	/* Restore a higher level driver's expiry handler first. */
+	hwgroup->expiry	= expiry;
+
+	if ((dma_stat & 5) == 1) {	/* DMA active and no interrupt */
+		unsigned long sc_base	= hwif->config_data;
+		unsigned long twcr_port	= sc_base + (drive->dn ? 0x06 : 0x04);
+		u8 dma_cmd		= hwif->INB(hwif->dma_command);
+
+		printk(KERN_WARNING "%s: DMA interrupt possibly stuck, "
+		       "attempting recovery...\n", drive->name);
+
+		/* Stop DMA */
+		hwif->OUTB(dma_cmd & ~0x01, hwif->dma_command);
+
+		/* Setup the dummy DMA transfer */
+		hwif->OUTW(0, sc_base + 0x0a);	/* Sector Count */
+		hwif->OUTW(0, twcr_port);	/* Transfer Word Count 1 or 2 */
+
+		/* Start the dummy DMA transfer */
+		hwif->OUTB(0x00, hwif->dma_command); /* clear R_OR_WCTR for write */
+		hwif->OUTB(0x01, hwif->dma_command); /* set START_STOPBM */
+
+		/*
+		 * If an interrupt was pending, it should come thru shortly.
+		 * If not, a higher level driver's expiry handler should
+		 * eventually cause some kind of recovery from the DMA stall.
+		 */
+		return WAIT_MIN_SLEEP;
+	}
+
+	/* Chain to the restored expiry handler if DMA wasn't active. */
+	if (likely(expiry != NULL))
+		return expiry(drive);
+
+	/* If there was no handler, "emulate" that for ide_timer_expiry()... */
+	return -1;
+}
+
+static void tc86c001_dma_start(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	unsigned long sc_base	= hwif->config_data;
+	unsigned long twcr_port	= sc_base + (drive->dn ? 0x06 : 0x04);
+	unsigned long nsectors	= hwgroup->rq->nr_sectors;
+
+	/*
+	 * We have to manually load the sector count and size into
+	 * the appropriate system control registers for DMA to work
+	 * with LBA48 and ATAPI devices...
+	 */
+	hwif->OUTW(nsectors, sc_base + 0x0a);	/* Sector Count */
+	hwif->OUTW(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */
+
+	/* Install our timeout expiry hook, saving the current handler... */
+	ide_set_hwifdata(hwif, hwgroup->expiry);
+	hwgroup->expiry = &tc86c001_timer_expiry;
+
+	ide_dma_start(drive);
+}
+
+static int tc86c001_busproc(ide_drive_t *drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long sc_base	= hwif->config_data;
+	u16 scr1;
+
+	/* System Control 1 Register bit 11 (ATA Hard Reset) read */
+	scr1 = hwif->INW(sc_base + 0x00);
+
+	switch (state) {
+		case BUSSTATE_ON:
+			if (!(scr1 & 0x0800))
+				return 0;
+			scr1 &= ~0x0800;
+
+			hwif->drives[0].failures = hwif->drives[1].failures = 0;
+			break;
+		case BUSSTATE_OFF:
+			if (scr1 & 0x0800)
+				return 0;
+			scr1 |= 0x0800;
+
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	/* System Control 1 Register bit 11 (ATA Hard Reset) write */
+	hwif->OUTW(scr1, sc_base + 0x00);
+	return 0;
+}
+
+static int config_chipset_for_dma(ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, tc86c001_ratemask(drive));
+
+	if (!speed)
+		return 0;
+
+	(void) tc86c001_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if ((id->capability & 1) && drive->autodma) {
+
+		if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+			return hwif->ide_dma_on(drive);
+
+		goto fast_ata_pio;
+
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+		tc86c001_tune_drive(drive, 255);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	/* IORDY not supported */
+	return 0;
+}
+
+static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
+{
+	unsigned long sc_base	= pci_resource_start(hwif->pci_dev, 5);
+	u16 scr1		= hwif->INW(sc_base + 0x00);;
+
+	/* System Control 1 Register bit 15 (Soft Reset) set */
+	hwif->OUTW(scr1 |  0x8000, sc_base + 0x00);
+
+	/* System Control 1 Register bit 14 (FIFO Reset) set */
+	hwif->OUTW(scr1 |  0x4000, sc_base + 0x00);
+
+	/* System Control 1 Register: reset clear */
+	hwif->OUTW(scr1 & ~0xc000, sc_base + 0x00);
+
+	/* Store the system control register base for convenience... */
+	hwif->config_data = sc_base;
+
+	hwif->tuneproc	= &tc86c001_tune_drive;
+	hwif->speedproc = &tc86c001_tune_chipset;
+	hwif->busproc	= &tc86c001_busproc;
+
+	hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+
+	if (!hwif->dma_base)
+		return;
+
+	/*
+	 * Sector Count Control Register bits 0 and 1 set:
+	 * software sets Sector Count Register for master and slave device
+	 */
+	hwif->OUTW(0x0003, sc_base + 0x0c);
+
+	/* Sector Count Register limit */
+	hwif->rqsize	 = 0xffff;
+
+	hwif->atapi_dma  = 1;
+	hwif->ultra_mask = 0x1f;
+	hwif->mwdma_mask = 0x07;
+
+	hwif->ide_dma_check	= &tc86c001_config_drive_xfer_rate;
+	hwif->dma_start 	= &tc86c001_dma_start;
+
+	if (!hwif->udma_four) {
+		/*
+		 * System Control  1 Register bit 13 (PDIAGN):
+		 * 0=80-pin cable, 1=40-pin cable
+		 */
+		scr1 = hwif->INW(sc_base + 0x00);
+		hwif->udma_four = (scr1 & 0x2000) ? 0 : 1;
+	}
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+}
+
+static unsigned int __devinit init_chipset_tc86c001(struct pci_dev *dev,
+							const char *name)
+{
+	int err = pci_request_region(dev, 5, name);
+
+	if (err)
+		printk(KERN_ERR "%s: system control regs already in use", name);
+	return err;
+}
+
+static ide_pci_device_t tc86c001_chipset __devinitdata = {
+	.name		= "TC86C001",
+	.init_chipset	= init_chipset_tc86c001,
+	.init_hwif	= init_hwif_tc86c001,
+	.channels	= 1,
+	.autodma	= AUTODMA,
+	.bootable	= OFF_BOARD
+};
+
+static int __devinit tc86c001_init_one(struct pci_dev *dev,
+				       const struct pci_device_id *id)
+{
+	return ide_setup_pci_device(dev, &tc86c001_chipset);
+}
+
+static struct pci_device_id tc86c001_pci_tbl[] = {
+	{ PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl);
+
+static struct pci_driver driver = {
+	.name		= "TC86C001",
+	.id_table	= tc86c001_pci_tbl,
+	.probe		= tc86c001_init_one
+};
+
+static int __init tc86c001_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+module_init(tc86c001_ide_init);
+
+MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_DESCRIPTION("PCI driver module for TC86C001 IDE");
+MODULE_LICENSE("GPL");

+ 18 - 0
drivers/pci/quirks.c

@@ -1460,6 +1460,24 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x2609, quirk_intel_pcie_pm);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x260a, quirk_intel_pcie_pm);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x260b, quirk_intel_pcie_pm);
 
+/*
+ * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size
+ * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes.
+ * Re-allocate the region if needed...
+ */
+static void __init quirk_tc86c001_ide(struct pci_dev *dev)
+{
+	struct resource *r = &dev->resource[0];
+
+	if (r->start & 0x8) {
+		r->start = 0;
+		r->end = 0xf;
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2,
+			 PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
+			 quirk_tc86c001_ide);
+
 static void __devinit quirk_netmos(struct pci_dev *dev)
 {
 	unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4;

+ 27 - 0
include/linux/ide.h

@@ -18,6 +18,9 @@
 #include <linux/device.h>
 #include <linux/pci.h>
 #include <linux/completion.h>
+#ifdef CONFIG_BLK_DEV_IDEACPI
+#include <acpi/acpi.h>
+#endif
 #include <asm/byteorder.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -541,6 +544,11 @@ typedef enum {
 struct ide_driver_s;
 struct ide_settings_s;
 
+#ifdef CONFIG_BLK_DEV_IDEACPI
+struct ide_acpi_drive_link;
+struct ide_acpi_hwif_link;
+#endif
+
 typedef struct ide_drive_s {
 	char		name[4];	/* drive name, such as "hda" */
         char            driver_req[10];	/* requests specific driver */
@@ -637,6 +645,9 @@ typedef struct ide_drive_s {
 
 	int		lun;		/* logical unit */
 	int		crc_count;	/* crc counter to reduce drive speed */
+#ifdef CONFIG_BLK_DEV_IDEACPI
+	struct ide_acpi_drive_link *acpidata;
+#endif
 	struct list_head list;
 	struct device	gendev;
 	struct completion gendev_rel_comp;	/* to deal with device release() */
@@ -804,6 +815,10 @@ typedef struct hwif_s {
 	void		*hwif_data;	/* extra hwif data */
 
 	unsigned dma;
+
+#ifdef CONFIG_BLK_DEV_IDEACPI
+	struct ide_acpi_hwif_link *acpidata;
+#endif
 } ____cacheline_internodealigned_in_smp ide_hwif_t;
 
 /*
@@ -1298,6 +1313,18 @@ static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
 static inline void ide_release_dma(ide_hwif_t *drive) {;}
 #endif
 
+#ifdef CONFIG_BLK_DEV_IDEACPI
+extern int ide_acpi_exec_tfs(ide_drive_t *drive);
+extern void ide_acpi_get_timing(ide_hwif_t *hwif);
+extern void ide_acpi_push_timing(ide_hwif_t *hwif);
+extern void ide_acpi_init(ide_hwif_t *hwif);
+#else
+static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; }
+static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; }
+static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; }
+static inline void ide_acpi_init(ide_hwif_t *hwif) { ; }
+#endif
+
 extern int ide_hwif_request_regions(ide_hwif_t *hwif);
 extern void ide_hwif_release_regions(ide_hwif_t* hwif);
 extern void ide_unregister (unsigned int index);

+ 1 - 0
include/linux/pci_ids.h

@@ -1454,6 +1454,7 @@
 
 #define PCI_VENDOR_ID_TOSHIBA_2		0x102f
 #define PCI_DEVICE_ID_TOSHIBA_TC35815CF	0x0030
+#define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE	0x0105
 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC	0x0108
 #define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3