diff -Nru a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
--- a/Documentation/DocBook/Makefile Mon Apr 26 02:12:40 2004
+++ b/Documentation/DocBook/Makefile Mon Apr 26 02:12:40 2004
@@ -82,10 +82,12 @@
libata.sgml: libata.tmpl $(TOPDIR)/drivers/scsi/libata-core.c \
$(TOPDIR)/drivers/scsi/libata-scsi.c \
$(TOPDIR)/drivers/scsi/sata_sil.c \
+ $(TOPDIR)/drivers/scsi/ata_piix.c \
$(TOPDIR)/drivers/scsi/sata_via.c
$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/scsi/libata-core.c \
$(TOPDIR)/drivers/scsi/libata-scsi.c \
$(TOPDIR)/drivers/scsi/sata_sil.c \
+ $(TOPDIR)/drivers/scsi/ata_piix.c \
$(TOPDIR)/drivers/scsi/sata_via.c \
< libata.tmpl > libata.sgml
diff -Nru a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl
--- a/Documentation/DocBook/libata.tmpl Mon Apr 26 02:12:40 2004
+++ b/Documentation/DocBook/libata.tmpl Mon Apr 26 02:12:40 2004
@@ -73,6 +73,11 @@
!Idrivers/scsi/libata-scsi.c
+
+ ata_piix Internals
+!Idrivers/scsi/ata_piix.c
+
+
ata_sil Internals
!Idrivers/scsi/sata_sil.c
diff -Nru a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
--- a/drivers/ide/pci/piix.c Mon Apr 26 02:12:40 2004
+++ b/drivers/ide/pci/piix.c Mon Apr 26 02:12:40 2004
@@ -880,7 +880,9 @@
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15},
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16},
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17},
+#ifndef CONFIG_SCSI_SATA
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18},
+#endif /* !CONFIG_SCSI_SATA */
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19},
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20},
{ 0, },
diff -Nru a/drivers/pci/quirks.c b/drivers/pci/quirks.c
--- a/drivers/pci/quirks.c Mon Apr 26 02:12:40 2004
+++ b/drivers/pci/quirks.c Mon Apr 26 02:12:40 2004
@@ -719,6 +719,62 @@
}
}
+#ifdef CONFIG_SCSI_SATA
+static void __init quirk_intel_ide_combined(struct pci_dev *pdev)
+{
+ u8 prog, comb, tmp;
+
+ /*
+ * Narrow down to Intel SATA PCI devices.
+ */
+ switch (pdev->device) {
+ /* PCI ids taken from drivers/scsi/ata_piix.c */
+ case 0x24d1:
+ case 0x24df:
+ case 0x25a3:
+ case 0x25b0:
+ case 0x2651:
+ case 0x2652:
+ break;
+ default:
+ /* we do not handle this PCI device */
+ return;
+ }
+
+ /*
+ * Read combined mode register.
+ */
+ pci_read_config_byte(pdev, 0x90, &tmp); /* combined mode reg */
+ tmp &= 0x6; /* interesting bits 2:1, PATA primary/secondary */
+ if (tmp == 0x4) /* bits 10x */
+ comb = (1 << 0); /* SATA port 0, PATA port 1 */
+ else if (tmp == 0x6) /* bits 11x */
+ comb = (1 << 2); /* PATA port 0, SATA port 1 */
+ else
+ return; /* not in combined mode */
+
+ /*
+ * Read programming interface register.
+ * (Tells us if it's legacy or native mode)
+ */
+ pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
+
+ /* if SATA port is in native mode, we're ok. */
+ if (prog & comb)
+ return;
+
+ /* SATA port is in legacy mode. Reserve port so that
+ * IDE driver does not attempt to use it. If request_region
+ * fails, it will be obvious at boot time, so we don't bother
+ * checking return values.
+ */
+ if (comb == (1 << 0))
+ request_region(0x1f0, 8, "libata"); /* port 0 */
+ else
+ request_region(0x170, 8, "libata"); /* port 1 */
+}
+#endif /* CONFIG_SCSI_SATA */
+
/*
* The main table of quirks.
*/
@@ -807,6 +863,14 @@
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc },
+
+#ifdef CONFIG_SCSI_SATA
+ /* Fixup BIOSes that configure Parallel ATA (PATA / IDE) and
+ * Serial ATA (SATA) into the same PCI ID.
+ */
+ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
+ quirk_intel_ide_combined },
+#endif /* CONFIG_SCSI_SATA */
{ 0 }
};
diff -Nru a/drivers/scsi/Config.in b/drivers/scsi/Config.in
--- a/drivers/scsi/Config.in Mon Apr 26 02:12:40 2004
+++ b/drivers/scsi/Config.in Mon Apr 26 02:12:40 2004
@@ -70,7 +70,9 @@
dep_tristate 'AMI MegaRAID2 support' CONFIG_SCSI_MEGARAID2 $CONFIG_SCSI
dep_mbool 'Serial ATA (SATA) support' CONFIG_SCSI_SATA $CONFIG_SCSI
dep_tristate ' ServerWorks Frodo / Apple K2 SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SVW $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
-dep_tristate ' Promise SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_PROMISE $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
+dep_tristate ' Intel PIIX/ICH SATA support' CONFIG_SCSI_ATA_PIIX $CONFIG_SCSI_SATA $CONFIG_PCI
+dep_tristate ' Promise SATA TX2/TX4 support (EXPERIMENTAL)' CONFIG_SCSI_SATA_PROMISE $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
+dep_tristate ' Promise SATA SX4 support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SX4 $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
dep_tristate ' Silicon Image SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SIL $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
dep_tristate ' SiS 964/180 SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SIS $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
dep_tristate ' VIA SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_VIA $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile
--- a/drivers/scsi/Makefile Mon Apr 26 02:12:40 2004
+++ b/drivers/scsi/Makefile Mon Apr 26 02:12:40 2004
@@ -131,11 +131,13 @@
obj-$(CONFIG_SCSI_LASI700) += lasi700.o 53c700.o
obj-$(CONFIG_SCSI_NSP32) += nsp32.o
obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o
+obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o
obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o
obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o
obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o
obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o
obj-$(CONFIG_SCSI_SATA_SIS) += libata.o sata_sis.o
+obj-$(CONFIG_SCSI_SATA_SX4) += libata.o sata_sx4.o
subdir-$(CONFIG_ARCH_ACORN) += ../acorn/scsi
obj-$(CONFIG_ARCH_ACORN) += ../acorn/scsi/acorn-scsi.o
diff -Nru a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/ata_piix.c Mon Apr 26 02:12:40 2004
@@ -0,0 +1,595 @@
+/*
+
+ ata_piix.c - Intel PATA/SATA controllers
+
+
+ Copyright 2003-2004 Red Hat Inc
+ Copyright 2003-2004 Jeff Garzik
+
+
+ Copyright header from piix.c:
+
+ Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+ Copyright (C) 1998-2000 Andre Hedrick
+ Copyright (C) 2003 Red Hat Inc
+
+ May be copied or modified under the terms of the GNU General Public License
+
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "scsi.h"
+#include "hosts.h"
+#include
+
+#define DRV_NAME "ata_piix"
+#define DRV_VERSION "1.02"
+
+enum {
+ PIIX_IOCFG = 0x54, /* IDE I/O configuration register */
+ ICH5_PMR = 0x90, /* port mapping register */
+ ICH5_PCS = 0x92, /* port control and status */
+
+ PIIX_FLAG_CHECKINTR = (1 << 29), /* make sure PCI INTx enabled */
+ PIIX_FLAG_COMBINED = (1 << 30), /* combined mode possible */
+
+ /* combined mode. if set, PATA is channel 0.
+ * if clear, PATA is channel 1.
+ */
+ PIIX_COMB_PATA_P0 = (1 << 1),
+ PIIX_COMB = (1 << 2), /* combined mode enabled? */
+
+ PIIX_PORT_PRESENT = (1 << 0),
+ PIIX_PORT_ENABLED = (1 << 4),
+
+ PIIX_80C_PRI = (1 << 5) | (1 << 4),
+ PIIX_80C_SEC = (1 << 7) | (1 << 6),
+
+ ich5_pata = 0,
+ ich5_sata = 1,
+ piix4_pata = 2,
+};
+
+static int piix_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+
+static void piix_pata_phy_reset(struct ata_port *ap);
+static void piix_sata_phy_reset(struct ata_port *ap);
+static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev,
+ unsigned int pio);
+static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev,
+ unsigned int udma);
+
+static unsigned int in_module_init = 1;
+
+static struct pci_device_id piix_pci_tbl[] = {
+#ifdef ATA_ENABLE_PATA
+ { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata },
+ { 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
+ { 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
+#endif
+
+ /* NOTE: The following PCI ids must be kept in sync with the
+ * list in drivers/pci/quirks.c.
+ */
+
+ { 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+ { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+ { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+ { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+
+ /* ICH6 operates in two modes, "looks-like-ICH5" mode,
+ * and enhanced mode, with queueing and other fancy stuff.
+ * This is distinguished by PCI class code.
+ */
+ { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_IDE << 8, 0xffff00, ich5_sata },
+ { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_IDE << 8, 0xffff00, ich5_sata },
+
+ { } /* terminate list */
+};
+
+static struct pci_driver piix_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = piix_pci_tbl,
+ .probe = piix_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static Scsi_Host_Template piix_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .detect = ata_scsi_detect,
+ .release = ata_scsi_release,
+ .queuecommand = ata_scsi_queuecmd,
+ .eh_strategy_handler = ata_scsi_error,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .use_new_eh_code = ATA_SHT_NEW_EH_CODE,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations piix_pata_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = piix_set_piomode,
+ .set_udmamode = piix_set_udmamode,
+
+ .tf_load = ata_tf_load_pio,
+ .tf_read = ata_tf_read_pio,
+ .check_status = ata_check_status_pio,
+ .exec_command = ata_exec_command_pio,
+
+ .phy_reset = piix_pata_phy_reset,
+
+ .bmdma_start = ata_bmdma_start_pio,
+ .fill_sg = ata_fill_sg,
+ .eng_timeout = ata_eng_timeout,
+
+ .irq_handler = ata_interrupt,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+};
+
+static struct ata_port_operations piix_sata_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = piix_set_piomode,
+ .set_udmamode = piix_set_udmamode,
+
+ .tf_load = ata_tf_load_pio,
+ .tf_read = ata_tf_read_pio,
+ .check_status = ata_check_status_pio,
+ .exec_command = ata_exec_command_pio,
+
+ .phy_reset = piix_sata_phy_reset,
+
+ .bmdma_start = ata_bmdma_start_pio,
+ .fill_sg = ata_fill_sg,
+ .eng_timeout = ata_eng_timeout,
+
+ .irq_handler = ata_interrupt,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+};
+
+static struct ata_port_info piix_port_info[] = {
+ /* ich5_pata */
+ {
+ .sht = &piix_sht,
+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
+ PIIX_FLAG_CHECKINTR,
+ .pio_mask = 0x03, /* pio3-4 */
+ .udma_mask = ATA_UDMA_MASK_40C, /* FIXME: cbl det */
+ .port_ops = &piix_pata_ops,
+ },
+
+ /* ich5_sata */
+ {
+ .sht = &piix_sht,
+ .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST |
+ PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR,
+ .pio_mask = 0x03, /* pio3-4 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &piix_sata_ops,
+ },
+
+ /* piix4_pata */
+ {
+ .sht = &piix_sht,
+ .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x03, /* pio3-4 */
+ .udma_mask = ATA_UDMA_MASK_40C, /* FIXME: cbl det */
+ .port_ops = &piix_pata_ops,
+ },
+};
+
+static struct pci_bits piix_enable_bits[] = {
+ { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
+ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
+};
+
+MODULE_AUTHOR("Andre Hedrick, Alan Cox, Andrzej Krzysztofowicz, Jeff Garzik");
+MODULE_DESCRIPTION("SCSI low-level driver for Intel PIIX/ICH ATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
+
+/**
+ * piix_pata_cbl_detect - Probe host controller cable detect info
+ * @ap: Port for which cable detect info is desired
+ *
+ * Read 80c cable indicator from SATA PCI device's PCI config
+ * register. This register is normally set by firmware (BIOS).
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static void piix_pata_cbl_detect(struct ata_port *ap)
+{
+ struct pci_dev *pdev = ap->host_set->pdev;
+ u8 tmp, mask;
+
+ /* no 80c support in host controller? */
+ if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0)
+ goto cbl40;
+
+ /* check BIOS cable detect results */
+ mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
+ pci_read_config_byte(pdev, PIIX_IOCFG, &tmp);
+ if ((tmp & mask) == 0)
+ goto cbl40;
+
+ ap->cbl = ATA_CBL_PATA80;
+ return;
+
+cbl40:
+ ap->cbl = ATA_CBL_PATA40;
+ ap->udma_mask &= ATA_UDMA_MASK_40C;
+}
+
+/**
+ * piix_pata_phy_reset - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * Probe PATA phy.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void piix_pata_phy_reset(struct ata_port *ap)
+{
+ if (!pci_test_config_bits(ap->host_set->pdev,
+ &piix_enable_bits[ap->port_no])) {
+ ata_port_disable(ap);
+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
+ return;
+ }
+
+ piix_pata_cbl_detect(ap);
+
+ ata_port_probe(ap);
+
+ ata_bus_reset(ap);
+}
+
+/**
+ * piix_sata_probe - Probe PCI device for present SATA devices
+ * @pdev: PCI device to probe
+ *
+ * Reads SATA PCI device's PCI config register Port Configuration
+ * and Status (PCS) to determine port and device availability.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ *
+ * RETURNS:
+ * Non-zero if device detected, zero otherwise.
+ */
+static int piix_sata_probe (struct ata_port *ap)
+{
+ struct pci_dev *pdev = ap->host_set->pdev;
+ int combined = (ap->flags & ATA_FLAG_SLAVE_POSS);
+ int orig_mask, mask, i;
+ u8 pcs;
+
+ mask = (PIIX_PORT_PRESENT << ap->port_no) |
+ (PIIX_PORT_ENABLED << ap->port_no);
+
+ pci_read_config_byte(pdev, ICH5_PCS, &pcs);
+ orig_mask = (int) pcs & 0xff;
+
+ /* TODO: this is vaguely wrong for ICH6 combined mode,
+ * where only two of the four SATA ports are mapped
+ * onto a single ATA channel. It is also vaguely inaccurate
+ * for ICH5, which has only two ports. However, this is ok,
+ * as further device presence detection code will handle
+ * any false positives produced here.
+ */
+
+ for (i = 0; i < 4; i++) {
+ mask = (PIIX_PORT_PRESENT << i) | (PIIX_PORT_ENABLED << i);
+
+ if ((orig_mask & mask) == mask)
+ if (combined || (i == ap->port_no))
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * piix_sata_phy_reset - Probe specified port on SATA host controller
+ * @ap: Port to probe
+ *
+ * Probe SATA phy.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void piix_sata_phy_reset(struct ata_port *ap)
+{
+ if (!pci_test_config_bits(ap->host_set->pdev,
+ &piix_enable_bits[ap->port_no])) {
+ ata_port_disable(ap);
+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
+ return;
+ }
+
+ if (!piix_sata_probe(ap)) {
+ ata_port_disable(ap);
+ printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id);
+ return;
+ }
+
+ ap->cbl = ATA_CBL_SATA;
+
+ ata_port_probe(ap);
+
+ ata_bus_reset(ap);
+}
+
+/**
+ * piix_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ * @pio: PIO mode, 0 - 4
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev,
+ unsigned int pio)
+{
+ struct pci_dev *dev = ap->host_set->pdev;
+ unsigned int is_slave = (adev->flags & ATA_DFLAG_MASTER) ? 0 : 1;
+ unsigned int master_port= ap->port_no ? 0x42 : 0x40;
+ unsigned int slave_port = 0x44;
+ u16 master_data;
+ u8 slave_data;
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ pci_read_config_word(dev, master_port, &master_data);
+ if (is_slave) {
+ master_data |= 0x4000;
+ /* enable PPE, IE and TIME */
+ master_data |= 0x0070;
+ pci_read_config_byte(dev, slave_port, &slave_data);
+ slave_data &= (ap->port_no ? 0x0f : 0xf0);
+ slave_data |=
+ (timings[pio][0] << 2) |
+ (timings[pio][1] << (ap->port_no ? 4 : 0));
+ } else {
+ master_data &= 0xccf8;
+ /* enable PPE, IE and TIME */
+ master_data |= 0x0007;
+ 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);
+}
+
+/**
+ * piix_set_udmamode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ * @udma: udma mode, 0 - 6
+ *
+ * Set UDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev,
+ unsigned int udma)
+{
+ struct pci_dev *dev = ap->host_set->pdev;
+ u8 maslave = ap->port_no ? 0x42 : 0x40;
+ u8 speed = udma;
+ unsigned int drive_dn = (ap->port_no ? 2 : 0) + adev->devno;
+ 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;
+ int sitre;
+ u16 reg4042, reg44, reg48, reg4a, reg54;
+ u8 reg55;
+
+ pci_read_config_word(dev, maslave, ®4042);
+ DPRINTK("reg4042 = 0x%04x\n", reg4042);
+ sitre = (reg4042 & 0x4000) ? 1 : 0;
+ pci_read_config_word(dev, 0x44, ®44);
+ pci_read_config_word(dev, 0x48, ®48);
+ pci_read_config_word(dev, 0x4a, ®4a);
+ pci_read_config_word(dev, 0x54, ®54);
+ pci_read_config_byte(dev, 0x55, ®55);
+
+ switch(speed) {
+ case XFER_UDMA_4:
+ case XFER_UDMA_2: u_speed = 2 << (drive_dn * 4); break;
+ case XFER_UDMA_6:
+ 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;
+ default:
+ BUG();
+ return;
+ }
+
+ if (!(reg48 & u_flag))
+ pci_write_config_word(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 & u_speed)) {
+ pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+ pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+ }
+ if (speed > XFER_UDMA_2) {
+ if (!(reg54 & v_flag)) {
+ pci_write_config_word(dev, 0x54, reg54|v_flag);
+ }
+ } else {
+ pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+ }
+}
+
+/* move to PCI layer, integrate w/ MSI stuff */
+static void pci_enable_intx(struct pci_dev *pdev)
+{
+ u16 pci_command;
+
+ pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+ if (pci_command & PCI_COMMAND_INTX_DISABLE) {
+ pci_command &= ~PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+ }
+}
+
+/**
+ * piix_init_one - Register PIIX ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in piix_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer. We probe for combined mode (sigh),
+ * and then hand over control to libata, for it to do the rest.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_port_info *port_info[2];
+ unsigned int combined = 0, n_ports = 1;
+ unsigned int pata_chan = 0, sata_chan = 0;
+
+ if (!printed_version++)
+ printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+ /* no hotplugging support (FIXME) */
+ if (!in_module_init)
+ return -ENODEV;
+
+ port_info[0] = &piix_port_info[ent->driver_data];
+ port_info[1] = NULL;
+
+ if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) {
+ u8 tmp;
+ pci_read_config_byte(pdev, ICH5_PMR, &tmp);
+
+ if (tmp & PIIX_COMB) {
+ combined = 1;
+ if (tmp & PIIX_COMB_PATA_P0)
+ sata_chan = 1;
+ else
+ pata_chan = 1;
+ }
+ }
+
+ /* On ICH5, some BIOSen disable the interrupt using the
+ * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
+ * On ICH6, this bit has the same effect, but only when
+ * MSI is disabled (and it is disabled, as we don't use
+ * message-signalled interrupts currently).
+ */
+ if (port_info[0]->host_flags & PIIX_FLAG_CHECKINTR)
+ pci_enable_intx(pdev);
+
+ if (combined) {
+ port_info[sata_chan] = &piix_port_info[ent->driver_data];
+ port_info[sata_chan]->host_flags |= ATA_FLAG_SLAVE_POSS;
+ port_info[pata_chan] = &piix_port_info[ich5_pata];
+ n_ports++;
+
+ printk(KERN_WARNING DRV_NAME ": combined mode detected\n");
+ }
+
+ return ata_pci_init_one(pdev, port_info, n_ports);
+}
+
+/**
+ * piix_init -
+ *
+ * LOCKING:
+ *
+ * RETURNS:
+ *
+ */
+
+static int __init piix_init(void)
+{
+ int rc;
+
+ DPRINTK("pci_module_init\n");
+ rc = pci_module_init(&piix_pci_driver);
+ if (rc)
+ return rc;
+
+ in_module_init = 0;
+
+ DPRINTK("scsi_register_host\n");
+ rc = scsi_register_module(MODULE_SCSI_HA, &piix_sht);
+ if (rc) {
+ rc = -ENODEV;
+ goto err_out;
+ }
+
+ DPRINTK("done\n");
+ return 0;
+
+err_out:
+ pci_unregister_driver(&piix_pci_driver);
+ return rc;
+}
+
+/**
+ * piix_exit -
+ *
+ * LOCKING:
+ *
+ */
+
+static void __exit piix_exit(void)
+{
+ scsi_unregister_module(MODULE_SCSI_HA, &piix_sht);
+ pci_unregister_driver(&piix_pci_driver);
+}
+
+module_init(piix_init);
+module_exit(piix_exit);
+
diff -Nru a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
--- a/drivers/scsi/libata-core.c Mon Apr 26 02:12:40 2004
+++ b/drivers/scsi/libata-core.c Mon Apr 26 02:12:40 2004
@@ -34,6 +34,8 @@
#include
#include
#include
+#include
+#include
#include
#include "scsi.h"
#include "hosts.h"
@@ -43,14 +45,10 @@
#include "libata.h"
-static void atapi_cdb_send(struct ata_port *ap);
static unsigned int ata_busy_sleep (struct ata_port *ap,
unsigned long tmout_pat,
unsigned long tmout);
static void __ata_dev_select (struct ata_port *ap, unsigned int device);
-#if 0 /* to be used eventually */
-static void ata_qc_push (struct ata_queued_cmd *qc, unsigned int append);
-#endif
static void ata_dma_complete(struct ata_port *ap, u8 host_stat,
unsigned int done_late);
static void ata_host_set_pio(struct ata_port *ap);
@@ -58,6 +56,7 @@
static void ata_dev_set_pio(struct ata_port *ap, unsigned int device);
static void ata_dev_set_udma(struct ata_port *ap, unsigned int device);
static void ata_set_mode(struct ata_port *ap);
+static int ata_qc_issue_prot(struct ata_queued_cmd *qc);
static unsigned int ata_unique_id = 1;
static LIST_HEAD(ata_probe_list);
@@ -75,13 +74,6 @@
"THR_IDLE",
"THR_PROBE_SUCCESS",
"THR_PROBE_START",
- "THR_PIO_POLL",
- "THR_PIO_TMOUT",
- "THR_PIO",
- "THR_PIO_LAST",
- "THR_PIO_LAST_POLL",
- "THR_PIO_ERR",
- "THR_PACKET",
};
/**
@@ -316,8 +308,6 @@
static void ata_tf_to_host(struct ata_port *ap, struct ata_taskfile *tf)
{
- init_MUTEX_LOCKED(&ap->sem);
-
ap->ops->tf_load(ap, tf);
ata_exec(ap, tf);
@@ -338,8 +328,6 @@
void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf)
{
- init_MUTEX_LOCKED(&ap->sem);
-
ap->ops->tf_load(ap, tf);
ap->ops->exec_command(ap, tf);
}
@@ -441,6 +429,77 @@
}
/**
+ * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
+ * @tf: Taskfile to convert
+ * @fis: Buffer into which data will output
+ *
+ * Converts a standard ATA taskfile to a Serial ATA
+ * FIS structure (Register - Host to Device).
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp)
+{
+ fis[0] = 0x27; /* Register - Host to Device FIS */
+ fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
+ bit 7 indicates Command FIS */
+ fis[2] = tf->command;
+ fis[3] = tf->feature;
+
+ fis[4] = tf->lbal;
+ fis[5] = tf->lbam;
+ fis[6] = tf->lbah;
+ fis[7] = tf->device;
+
+ fis[8] = tf->hob_lbal;
+ fis[9] = tf->hob_lbam;
+ fis[10] = tf->hob_lbah;
+ fis[11] = tf->hob_feature;
+
+ fis[12] = tf->nsect;
+ fis[13] = tf->hob_nsect;
+ fis[14] = 0;
+ fis[15] = tf->ctl;
+
+ fis[16] = 0;
+ fis[17] = 0;
+ fis[18] = 0;
+ fis[19] = 0;
+}
+
+/**
+ * ata_tf_from_fis - Convert SATA FIS to ATA taskfile
+ * @fis: Buffer from which data will be input
+ * @tf: Taskfile to output
+ *
+ * Converts a standard ATA taskfile to a Serial ATA
+ * FIS structure (Register - Host to Device).
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf)
+{
+ tf->command = fis[2]; /* status */
+ tf->feature = fis[3]; /* error */
+
+ tf->lbal = fis[4];
+ tf->lbam = fis[5];
+ tf->lbah = fis[6];
+ tf->device = fis[7];
+
+ tf->hob_lbal = fis[8];
+ tf->hob_lbam = fis[9];
+ tf->hob_lbah = fis[10];
+
+ tf->nsect = fis[12];
+ tf->hob_nsect = fis[13];
+}
+
+/**
* ata_prot_to_cmd - determine which read/write opcodes to use
* @protocol: ATA_PROT_xxx taskfile protocol
* @lba48: true is lba48 is present
@@ -1854,6 +1913,7 @@
int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
struct scatterlist *sg = qc->sg;
unsigned int have_sg = (qc->flags & ATA_QCFLAG_SG);
+ dma_addr_t dma_address;
assert(sg == &qc->sgent);
assert(qc->n_elem == 1);
@@ -1866,9 +1926,10 @@
if (!have_sg)
return 0;
- sg_dma_address(sg) = pci_map_single(ap->host_set->pdev,
- cmd->request_buffer,
- cmd->request_bufflen, dir);
+ dma_address = pci_map_single(ap->host_set->pdev, cmd->request_buffer,
+ cmd->request_bufflen, dir);
+
+ sg_dma_address(sg) = dma_address;
DPRINTK("mapped buffer of %d bytes for %s\n", cmd->request_bufflen,
qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
@@ -1926,20 +1987,20 @@
static unsigned long ata_pio_poll(struct ata_port *ap)
{
u8 status;
- unsigned int poll_state = THR_UNKNOWN;
- unsigned int reg_state = THR_UNKNOWN;
- const unsigned int tmout_state = THR_PIO_TMOUT;
-
- switch (ap->thr_state) {
- case THR_PIO:
- case THR_PIO_POLL:
- poll_state = THR_PIO_POLL;
- reg_state = THR_PIO;
- break;
- case THR_PIO_LAST:
- case THR_PIO_LAST_POLL:
- poll_state = THR_PIO_LAST_POLL;
- reg_state = THR_PIO_LAST;
+ unsigned int poll_state = PIO_ST_UNKNOWN;
+ unsigned int reg_state = PIO_ST_UNKNOWN;
+ const unsigned int tmout_state = PIO_ST_TMOUT;
+
+ switch (ap->pio_task_state) {
+ case PIO_ST:
+ case PIO_ST_POLL:
+ poll_state = PIO_ST_POLL;
+ reg_state = PIO_ST;
+ break;
+ case PIO_ST_LAST:
+ case PIO_ST_LAST_POLL:
+ poll_state = PIO_ST_LAST_POLL;
+ reg_state = PIO_ST_LAST;
break;
default:
BUG();
@@ -1948,41 +2009,19 @@
status = ata_chk_status(ap);
if (status & ATA_BUSY) {
- if (time_after(jiffies, ap->thr_timeout)) {
- ap->thr_state = tmout_state;
+ if (time_after(jiffies, ap->pio_task_timeout)) {
+ ap->pio_task_state = tmout_state;
return 0;
}
- ap->thr_state = poll_state;
- if (current->need_resched)
- return 0;
+ ap->pio_task_state = poll_state;
return ATA_SHORT_PAUSE;
}
- ap->thr_state = reg_state;
+ ap->pio_task_state = reg_state;
return 0;
}
/**
- * ata_pio_start -
- * @qc:
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-static void ata_pio_start (struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
-
- assert(qc->tf.protocol == ATA_PROT_PIO);
-
- qc->flags |= ATA_QCFLAG_POLL;
- qc->tf.ctl |= ATA_NIEN; /* disable interrupts */
- ata_tf_to_host_nolock(ap, &qc->tf);
- ata_thread_wake(ap, THR_PIO);
-}
-
-/**
* ata_pio_complete -
* @ap:
*
@@ -1992,7 +2031,6 @@
static void ata_pio_complete (struct ata_port *ap)
{
struct ata_queued_cmd *qc;
- unsigned long flags;
u8 drv_stat;
/*
@@ -2001,31 +2039,29 @@
* a chk-status or two. If not, the drive is probably seeking
* or something. Snooze for a couple msecs, then
* chk-status again. If still busy, fall back to
- * THR_PIO_POLL state.
+ * PIO_ST_POLL state.
*/
drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
msleep(2);
drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
- ap->thr_state = THR_PIO_LAST_POLL;
- ap->thr_timeout = jiffies + ATA_TMOUT_PIO;
+ ap->pio_task_state = PIO_ST_LAST_POLL;
+ ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
return;
}
}
drv_stat = ata_wait_idle(ap);
if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
- ap->thr_state = THR_PIO_ERR;
+ ap->pio_task_state = PIO_ST_ERR;
return;
}
qc = ata_qc_from_tag(ap, ap->active_tag);
assert(qc != NULL);
- spin_lock_irqsave(&ap->host_set->lock, flags);
- ap->thr_state = THR_IDLE;
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ ap->pio_task_state = PIO_ST_IDLE;
ata_irq_on(ap);
@@ -2053,22 +2089,22 @@
* a chk-status or two. If not, the drive is probably seeking
* or something. Snooze for a couple msecs, then
* chk-status again. If still busy, fall back to
- * THR_PIO_POLL state.
+ * PIO_ST_POLL state.
*/
status = ata_busy_wait(ap, ATA_BUSY, 5);
if (status & ATA_BUSY) {
msleep(2);
status = ata_busy_wait(ap, ATA_BUSY, 10);
if (status & ATA_BUSY) {
- ap->thr_state = THR_PIO_POLL;
- ap->thr_timeout = jiffies + ATA_TMOUT_PIO;
+ ap->pio_task_state = PIO_ST_POLL;
+ ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
return;
}
}
/* handle BSY=0, DRQ=0 as error */
if ((status & ATA_DRQ) == 0) {
- ap->thr_state = THR_PIO_ERR;
+ ap->pio_task_state = PIO_ST_ERR;
return;
}
@@ -2079,7 +2115,7 @@
sg = qc->sg;
if (qc->cursect == (qc->nsect - 1))
- ap->thr_state = THR_PIO_LAST;
+ ap->pio_task_state = PIO_ST_LAST;
buf = kmap(sg[qc->cursg].page) +
sg[qc->cursg].offset + (qc->cursg_ofs * ATA_SECT_SIZE);
@@ -2107,20 +2143,48 @@
kunmap(sg[qc->cursg].page);
}
-#if 0 /* to be used eventually */
-/**
- * ata_eng_schedule - run an iteration of the pio/dma/whatever engine
- * @ap: port on which activity will occur
- * @eng: instance of engine
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-static void ata_eng_schedule (struct ata_port *ap, struct ata_engine *eng)
+static void ata_pio_task(void *_data)
{
- /* FIXME */
+ struct ata_port *ap = _data;
+ unsigned long timeout = 0;
+
+ switch (ap->pio_task_state) {
+ case PIO_ST:
+ ata_pio_sector(ap);
+ break;
+
+ case PIO_ST_LAST:
+ ata_pio_complete(ap);
+ break;
+
+ case PIO_ST_POLL:
+ case PIO_ST_LAST_POLL:
+ timeout = ata_pio_poll(ap);
+ break;
+
+ case PIO_ST_TMOUT:
+ printk(KERN_ERR "ata%d: FIXME: PIO_ST_TMOUT\n", /* FIXME */
+ ap->id);
+ timeout = 11 * HZ;
+ break;
+
+ case PIO_ST_ERR:
+ printk(KERN_ERR "ata%d: FIXME: PIO_ST_ERR\n", /* FIXME */
+ ap->id);
+ timeout = 11 * HZ;
+ break;
+ }
+
+ if (timeout) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(timeout);
+ }
+
+ if ((ap->pio_task_state != PIO_ST_IDLE) &&
+ (ap->pio_task_state != PIO_ST_TMOUT) &&
+ (ap->pio_task_state != PIO_ST_ERR))
+ schedule_task(&ap->pio_task);
}
-#endif
/**
* ata_eng_timeout - Handle timeout of queued command
@@ -2246,8 +2310,6 @@
qc->ap = ap;
qc->dev = dev;
qc->cursect = qc->cursg = qc->cursg_ofs = 0;
- INIT_LIST_HEAD(&qc->node);
- init_MUTEX_LOCKED(&qc->sem);
ata_tf_init(ap, &qc->tf, dev->devno);
@@ -2306,52 +2368,33 @@
do_clear = 1;
}
- up(&qc->sem);
+ if (qc->waiting)
+ complete(qc->waiting);
if (likely(do_clear))
clear_bit(tag, &ap->qactive);
}
-#if 0 /* to be used eventually */
/**
- * ata_qc_push -
- * @qc:
- * @append:
+ * ata_qc_issue - issue taskfile to device
+ * @qc: command to issue to device
*
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-static void ata_qc_push (struct ata_queued_cmd *qc, unsigned int append)
-{
- struct ata_port *ap = qc->ap;
- struct ata_engine *eng = &ap->eng;
-
- if (likely(append))
- list_add_tail(&qc->node, &eng->q);
- else
- list_add(&qc->node, &eng->q);
-
- if (!test_and_set_bit(ATA_EFLG_ACTIVE, &eng->flags))
- ata_eng_schedule(ap, eng);
-}
-#endif
-
-/**
- * ata_qc_issue -
- * @qc:
+ * Prepare an ATA command to submission to device.
+ * This includes mapping the data into a DMA-able
+ * area, filling in the S/G table, and finally
+ * writing the taskfile to hardware, starting the command.
*
* LOCKING:
+ * spin_lock_irqsave(host_set lock)
*
* RETURNS:
- *
+ * Zero on success, negative on error.
*/
+
int ata_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct scsi_cmnd *cmd = qc->scsicmd;
- unsigned int dma = qc->flags & ATA_QCFLAG_DMA;
-
- ata_dev_select(ap, qc->dev->devno, 1, 0);
/* set up SG table */
if (cmd->use_sg) {
@@ -2367,20 +2410,60 @@
qc->ap->active_tag = qc->tag;
qc->flags |= ATA_QCFLAG_ACTIVE;
- if (likely(dma)) {
- ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
- ap->ops->bmdma_start(qc); /* initiate bmdma */
- } else
- /* load tf registers, initiate polling pio */
- ata_pio_start(qc);
-
- return 0;
+ return ata_qc_issue_prot(qc);
err_out:
return -1;
}
/**
+ * ata_qc_issue_prot - issue taskfile to device in proto-dependent manner
+ * @qc: command to issue to device
+ *
+ * Using various libata functions and hooks, this function
+ * starts an ATA command. ATA commands are grouped into
+ * classes called "protocols", and issuing each type of protocol
+ * is slightly different.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ *
+ * RETURNS:
+ * Zero on success, negative on error.
+ */
+
+static int ata_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ ata_dev_select(ap, qc->dev->devno, 1, 0);
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_NODATA:
+ ata_tf_to_host_nolock(ap, &qc->tf);
+ break;
+
+ case ATA_PROT_DMA:
+ ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
+ ap->ops->bmdma_start(qc); /* initiate bmdma */
+ break;
+
+ case ATA_PROT_PIO: /* load tf registers, initiate polling pio */
+ qc->flags |= ATA_QCFLAG_POLL;
+ qc->tf.ctl |= ATA_NIEN; /* disable interrupts */
+ ata_tf_to_host_nolock(ap, &qc->tf);
+ ap->pio_task_state = PIO_ST;
+ schedule_task(&ap->pio_task);
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
* ata_bmdma_start_mmio -
* @qc:
*
@@ -2616,36 +2699,6 @@
}
/**
- * ata_thread_wake -
- * @ap:
- * @thr_state:
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- */
-
-void ata_thread_wake(struct ata_port *ap, unsigned int thr_state)
-{
- assert(ap->thr_state == THR_IDLE);
- ap->thr_state = thr_state;
- up(&ap->thr_sem);
-}
-
-/**
- * ata_thread_timer -
- * @opaque:
- *
- * LOCKING:
- */
-
-static void ata_thread_timer(unsigned long opaque)
-{
- struct ata_port *ap = (struct ata_port *) opaque;
-
- up(&ap->thr_sem);
-}
-
-/**
* ata_thread_iter -
* @ap:
*
@@ -2668,7 +2721,6 @@
break;
case THR_PROBE_START:
- down(&ap->sem);
ap->thr_state = THR_PORT_RESET;
break;
@@ -2687,40 +2739,8 @@
break;
case THR_AWAIT_DEATH:
- timeout = -1;
- break;
-
case THR_IDLE:
- timeout = 30 * HZ;
- break;
-
- case THR_PIO:
- ata_pio_sector(ap);
- break;
-
- case THR_PIO_LAST:
- ata_pio_complete(ap);
- break;
-
- case THR_PIO_POLL:
- case THR_PIO_LAST_POLL:
- timeout = ata_pio_poll(ap);
- break;
-
- case THR_PIO_TMOUT:
- printk(KERN_ERR "ata%d: FIXME: THR_PIO_TMOUT\n", /* FIXME */
- ap->id);
- timeout = 11 * HZ;
- break;
-
- case THR_PIO_ERR:
- printk(KERN_ERR "ata%d: FIXME: THR_PIO_ERR\n", /* FIXME */
- ap->id);
- timeout = 11 * HZ;
- break;
-
- case THR_PACKET:
- atapi_cdb_send(ap);
+ timeout = -1;
break;
default:
@@ -2734,95 +2754,23 @@
return timeout;
}
-/**
- * ata_thread -
- * @data:
- *
- * LOCKING:
- *
- * RETURNS:
- *
- */
-
-static int ata_thread (void *data)
+void atapi_start(struct ata_queued_cmd *qc)
{
- struct ata_port *ap = data;
- long timeout;
-
- daemonize ();
- reparent_to_init();
- spin_lock_irq(¤t->sigmask_lock);
- sigemptyset(¤t->blocked);
- recalc_sigpending(current);
- spin_unlock_irq(¤t->sigmask_lock);
-
- sprintf(current->comm, "katad-%u", ap->id);
-
- while (1) {
- cond_resched();
-
- timeout = ata_thread_iter(ap);
-
- if (signal_pending (current)) {
- spin_lock_irq(¤t->sigmask_lock);
- flush_signals(current);
- spin_unlock_irq(¤t->sigmask_lock);
- }
-
- if ((timeout < 0) || (ap->time_to_die))
- break;
-
- /* note sleeping for full timeout not guaranteed (that's ok) */
- if (timeout) {
- mod_timer(&ap->thr_timer, jiffies + timeout);
- down_interruptible(&ap->thr_sem);
-
- if (signal_pending (current)) {
- spin_lock_irq(¤t->sigmask_lock);
- flush_signals(current);
- spin_unlock_irq(¤t->sigmask_lock);
- }
-
- if (ap->time_to_die)
- break;
- }
- }
-
- printk(KERN_DEBUG "ata%u: thread exiting\n", ap->id);
- ap->thr_pid = -1;
- del_timer_sync(&ap->thr_timer);
- complete_and_exit (&ap->thr_exited, 0);
-}
-
-/**
- * ata_thread_kill - kill per-port kernel thread
- * @ap: port those thread is to be killed
- *
- * LOCKING:
- *
- */
+ struct ata_port *ap = qc->ap;
-static int ata_thread_kill(struct ata_port *ap)
-{
- int ret = 0;
+ qc->flags |= ATA_QCFLAG_ACTIVE;
+ ap->active_tag = qc->tag;
- if (ap->thr_pid >= 0) {
- ap->time_to_die = 1;
- wmb();
- ret = kill_proc(ap->thr_pid, SIGTERM, 1);
- if (ret)
- printk(KERN_ERR "ata%d: unable to kill kernel thread\n",
- ap->id);
- else
- wait_for_completion(&ap->thr_exited);
- }
+ ata_dev_select(ap, qc->dev->devno, 1, 0);
+ ata_tf_to_host_nolock(ap, &qc->tf);
+ schedule_task(&ap->packet_task);
- return ret;
+ VPRINTK("EXIT\n");
}
/**
- * atapi_cdb_send - Write CDB bytes to hardware
- * @ap: Port to which ATAPI device is attached.
+ * atapi_packet_task - Write CDB bytes to hardware
+ * @_data: Port to which ATAPI device is attached.
*
* When device has indicated its readiness to accept
* a CDB, this function is called. Send the CDB.
@@ -2834,8 +2782,9 @@
* Kernel thread context (may sleep)
*/
-static void atapi_cdb_send(struct ata_port *ap)
+static void atapi_packet_task(void *_data)
{
+ struct ata_port *ap = _data;
struct ata_queued_cmd *qc;
u8 status;
@@ -2860,30 +2809,17 @@
qc->scsicmd->cmnd, ap->host->max_cmd_len / 4);
/* if we are DMA'ing, irq handler takes over from here */
- if (qc->tf.feature == ATAPI_PKT_DMA)
- goto out;
-
- /* sleep-wait for BSY to clear */
- DPRINTK("busy wait 2\n");
- if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB))
- goto err_out;
-
- /* wait for BSY,DRQ to clear */
- status = ata_wait_idle(ap);
- if (status & (ATA_BUSY | ATA_DRQ))
- goto err_out;
-
- /* transaction completed, indicate such to scsi stack */
- ata_qc_complete(qc, status, 0);
- ata_irq_on(ap);
+ if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+ /* FIXME: start DMA here */
+ } else {
+ ap->pio_task_state = PIO_ST;
+ schedule_task(&ap->pio_task);
+ }
-out:
- ap->thr_state = THR_IDLE;
return;
err_out:
ata_qc_complete(qc, ATA_ERR, 0);
- goto out;
}
int ata_port_start (struct ata_port *ap)
@@ -2893,7 +2829,7 @@
ap->prd = pci_alloc_consistent(pdev, ATA_PRD_TBL_SZ, &ap->prd_dma);
if (!ap->prd)
return -ENOMEM;
-
+
DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma);
return 0;
@@ -2906,6 +2842,23 @@
pci_free_consistent(pdev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
}
+static void ata_probe_task(void *_data)
+{
+ struct ata_port *ap = _data;
+ long timeout;
+
+ timeout = ata_thread_iter(ap);
+ if (timeout < 0)
+ return;
+
+ if (timeout > 0) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(timeout);
+ }
+
+ schedule_task(&ap->probe_task);
+}
+
/**
* ata_host_remove -
* @ap:
@@ -2968,18 +2921,14 @@
/* ata_engine init */
ap->eng.flags = 0;
INIT_LIST_HEAD(&ap->eng.q);
+ INIT_TQUEUE(&ap->packet_task, atapi_packet_task, ap);
+ INIT_TQUEUE(&ap->pio_task, ata_pio_task, ap);
+ INIT_TQUEUE(&ap->probe_task, ata_probe_task, ap);
for (i = 0; i < ATA_MAX_DEVICES; i++)
ap->device[i].devno = i;
- init_completion(&ap->thr_exited);
init_MUTEX_LOCKED(&ap->probe_sem);
- init_MUTEX_LOCKED(&ap->sem);
- init_MUTEX_LOCKED(&ap->thr_sem);
-
- init_timer(&ap->thr_timer);
- ap->thr_timer.function = ata_thread_timer;
- ap->thr_timer.data = (unsigned long) ap;
#ifdef ATA_IRQ_TRAP
ap->stats.unhandled_irq = 1;
@@ -3022,17 +2971,8 @@
if (rc)
goto err_out;
- ap->thr_pid = kernel_thread(ata_thread, ap, CLONE_FS | CLONE_FILES);
- if (ap->thr_pid < 0) {
- printk(KERN_ERR "ata%d: unable to start kernel thread\n",
- ap->id);
- goto err_out_free;
- }
-
return ap;
-err_out_free:
- ap->ops->port_stop(ap);
err_out:
scsi_unregister(host);
return NULL;
@@ -3111,7 +3051,7 @@
ap = host_set->ports[i];
DPRINTK("ata%u: probe begin\n", ap->id);
- up(&ap->sem); /* start probe */
+ schedule_task(&ap->probe_task); /* start probe */
DPRINTK("ata%u: probe-wait begin\n", ap->id);
down(&ap->probe_sem); /* wait for end */
@@ -3192,8 +3132,6 @@
DPRINTK("ENTER\n");
- ata_thread_kill(ap); /* FIXME: check return val */
-
ap->ops->port_disable(ap);
ata_host_remove(ap, 0);
@@ -3272,14 +3210,28 @@
goto err_out;
if (legacy_mode) {
- if (!request_region(0x1f0, 8, "libata"))
- printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n");
- else
+ if (!request_region(0x1f0, 8, "libata")) {
+ struct resource *conflict, res;
+ res.start = 0x1f0;
+ res.end = 0x1f0 + 8 - 1;
+ conflict = ____request_resource(&ioport_resource, &res);
+ if (!strcmp(conflict->name, "libata"))
+ legacy_mode |= (1 << 0);
+ else
+ printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n");
+ } else
legacy_mode |= (1 << 0);
- if (!request_region(0x170, 8, "libata"))
- printk(KERN_WARNING "ata: 0x170 IDE port busy\n");
- else
+ if (!request_region(0x170, 8, "libata")) {
+ struct resource *conflict, res;
+ res.start = 0x170;
+ res.end = 0x170 + 8 - 1;
+ conflict = ____request_resource(&ioport_resource, &res);
+ if (!strcmp(conflict->name, "libata"))
+ legacy_mode |= (1 << 1);
+ else
+ printk(KERN_WARNING "ata: 0x170 IDE port busy\n");
+ } else
legacy_mode |= (1 << 1);
}
@@ -3517,7 +3469,12 @@
return 0;
}
+static void __exit ata_exit(void)
+{
+}
+
module_init(ata_init);
+module_exit(ata_exit);
/*
* libata is essentially a library of internal helper functions for
@@ -3536,6 +3493,8 @@
EXPORT_SYMBOL_GPL(ata_tf_load_mmio);
EXPORT_SYMBOL_GPL(ata_tf_read_pio);
EXPORT_SYMBOL_GPL(ata_tf_read_mmio);
+EXPORT_SYMBOL_GPL(ata_tf_to_fis);
+EXPORT_SYMBOL_GPL(ata_tf_from_fis);
EXPORT_SYMBOL_GPL(ata_check_status_pio);
EXPORT_SYMBOL_GPL(ata_check_status_mmio);
EXPORT_SYMBOL_GPL(ata_exec_command_pio);
diff -Nru a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
--- a/drivers/scsi/libata-scsi.c Mon Apr 26 02:12:40 2004
+++ b/drivers/scsi/libata-scsi.c Mon Apr 26 02:12:40 2004
@@ -864,8 +864,7 @@
struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct ata_queued_cmd *qc;
- u8 *scsicmd = cmd->cmnd, status;
- unsigned int doing_dma = 0;
+ u8 *scsicmd = cmd->cmnd;
VPRINTK("ENTER, drv_stat = 0x%x\n", ata_chk_status(ap));
@@ -905,52 +904,17 @@
qc->tf.command = ATA_CMD_PACKET;
- /* set up SG table */
if (cmd->sc_data_direction == SCSI_DATA_NONE) {
- ap->active_tag = qc->tag;
- qc->flags |= ATA_QCFLAG_ACTIVE | ATA_QCFLAG_POLL;
qc->tf.protocol = ATA_PROT_ATAPI;
-
- ata_dev_select(ap, dev->devno, 1, 0);
-
- DPRINTK("direction: none\n");
+ qc->flags |= ATA_QCFLAG_POLL;
qc->tf.ctl |= ATA_NIEN; /* disable interrupts */
- ata_tf_to_host_nolock(ap, &qc->tf);
} else {
- qc->flags |= ATA_QCFLAG_SG; /* data is present; dma-map it */
- qc->tf.feature = ATAPI_PKT_DMA;
qc->tf.protocol = ATA_PROT_ATAPI_DMA;
-
- doing_dma = 1;
-
- /* select device, send command to hardware */
- if (ata_qc_issue(qc))
- goto err_out;
- }
-
- status = ata_busy_wait(ap, ATA_BUSY, 1000);
- if (status & ATA_BUSY) {
- ata_thread_wake(ap, THR_PACKET);
- return;
+ qc->flags |= ATA_QCFLAG_SG; /* data is present; dma-map it */
+ qc->tf.feature |= ATAPI_PKT_DMA;
}
- if ((status & ATA_DRQ) == 0)
- goto err_out;
- /* FIXME: mmio-ize */
- DPRINTK("writing cdb\n");
- outsl(ap->ioaddr.data_addr, scsicmd, ap->host->max_cmd_len / 4);
-
- if (!doing_dma)
- ata_thread_wake(ap, THR_PACKET);
-
- VPRINTK("EXIT\n");
- return;
-
-err_out:
- if (!doing_dma)
- ata_irq_on(ap); /* re-enable interrupts */
- ata_bad_cdb(cmd, done);
- DPRINTK("EXIT - badcmd\n");
+ atapi_start(qc);
}
/**
diff -Nru a/drivers/scsi/libata.h b/drivers/scsi/libata.h
--- a/drivers/scsi/libata.h Mon Apr 26 02:12:40 2004
+++ b/drivers/scsi/libata.h Mon Apr 26 02:12:40 2004
@@ -45,7 +45,7 @@
extern void ata_dev_select(struct ata_port *ap, unsigned int device,
unsigned int wait, unsigned int can_sleep);
extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf);
-extern void ata_thread_wake(struct ata_port *ap, unsigned int thr_state);
+extern void atapi_start(struct ata_queued_cmd *qc);
/* libata-scsi.c */
diff -Nru a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
--- a/drivers/scsi/sata_promise.c Mon Apr 26 02:12:40 2004
+++ b/drivers/scsi/sata_promise.c Mon Apr 26 02:12:40 2004
@@ -33,16 +33,14 @@
#include "hosts.h"
#include
#include
+#include "sata_promise.h"
#define DRV_NAME "sata_promise"
-#define DRV_VERSION "0.92"
+#define DRV_VERSION "1.00"
enum {
- PDC_PRD_TBL = 0x44, /* Direct command DMA table addr */
-
PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
- PDC_HDMA_PKT_SUBMIT = 0x100, /* Host DMA packet pointer addr */
PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
PDC_TBG_MODE = 0x41, /* TBG mode */
PDC_FLASH_CTL = 0x44, /* Flash control register */
@@ -51,141 +49,38 @@
PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */
PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */
PDC_SLEW_CTL = 0x470, /* slew rate control reg */
- PDC_HDMA_CTLSTAT = 0x12C, /* Host DMA control / status */
-
- PDC_20621_SEQCTL = 0x400,
- PDC_20621_SEQMASK = 0x480,
- PDC_20621_GENERAL_CTL = 0x484,
- PDC_20621_PAGE_SIZE = (32 * 1024),
-
- /* chosen, not constant, values; we design our own DIMM mem map */
- PDC_20621_DIMM_WINDOW = 0x0C, /* page# for 32K DIMM window */
- PDC_20621_DIMM_BASE = 0x00200000,
- PDC_20621_DIMM_DATA = (64 * 1024),
- PDC_DIMM_DATA_STEP = (256 * 1024),
- PDC_DIMM_WINDOW_STEP = (8 * 1024),
- PDC_DIMM_HOST_PRD = (6 * 1024),
- PDC_DIMM_HOST_PKT = (128 * 0),
- PDC_DIMM_HPKT_PRD = (128 * 1),
- PDC_DIMM_ATA_PKT = (128 * 2),
- PDC_DIMM_APKT_PRD = (128 * 3),
- PDC_DIMM_HEADER_SZ = PDC_DIMM_APKT_PRD + 128,
- PDC_PAGE_WINDOW = 0x40,
- PDC_PAGE_DATA = PDC_PAGE_WINDOW +
- (PDC_20621_DIMM_DATA / PDC_20621_PAGE_SIZE),
- PDC_PAGE_SET = PDC_DIMM_DATA_STEP / PDC_20621_PAGE_SIZE,
-
- PDC_CHIP0_OFS = 0xC0000, /* offset of chip #0 */
- PDC_20621_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
- (1<<23),
PDC_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
(1<<8) | (1<<9) | (1<<10),
board_2037x = 0, /* FastTrak S150 TX2plus */
board_20319 = 1, /* FastTrak S150 TX4 */
- board_20621 = 2, /* FastTrak S150 SX4 */
PDC_HAS_PATA = (1 << 1), /* PDC20375 has PATA */
- PDC_FLAG_20621 = (1 << 30), /* we have a 20621 */
PDC_RESET = (1 << 11), /* HDMA reset */
-
- PDC_MAX_HDMA = 32,
- PDC_HDMA_Q_MASK = (PDC_MAX_HDMA - 1),
-
- PDC_DIMM0_SPD_DEV_ADDRESS = 0x50,
- PDC_DIMM1_SPD_DEV_ADDRESS = 0x51,
- PDC_MAX_DIMM_MODULE = 0x02,
- PDC_I2C_CONTROL_OFFSET = 0x48,
- PDC_I2C_ADDR_DATA_OFFSET = 0x4C,
- PDC_DIMM0_CONTROL_OFFSET = 0x80,
- PDC_DIMM1_CONTROL_OFFSET = 0x84,
- PDC_SDRAM_CONTROL_OFFSET = 0x88,
- PDC_I2C_WRITE = 0x00000000,
- PDC_I2C_READ = 0x00000040,
- PDC_I2C_START = 0x00000080,
- PDC_I2C_MASK_INT = 0x00000020,
- PDC_I2C_COMPLETE = 0x00010000,
- PDC_I2C_NO_ACK = 0x00100000,
- PDC_DIMM_SPD_SUBADDRESS_START = 0x00,
- PDC_DIMM_SPD_SUBADDRESS_END = 0x7F,
- PDC_DIMM_SPD_ROW_NUM = 3,
- PDC_DIMM_SPD_COLUMN_NUM = 4,
- PDC_DIMM_SPD_MODULE_ROW = 5,
- PDC_DIMM_SPD_TYPE = 11,
- PDC_DIMM_SPD_FRESH_RATE = 12,
- PDC_DIMM_SPD_BANK_NUM = 17,
- PDC_DIMM_SPD_CAS_LATENCY = 18,
- PDC_DIMM_SPD_ATTRIBUTE = 21,
- PDC_DIMM_SPD_ROW_PRE_CHARGE = 27,
- PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,
- PDC_DIMM_SPD_RAS_CAS_DELAY = 29,
- PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,
- PDC_DIMM_SPD_SYSTEM_FREQ = 126,
- PDC_CTL_STATUS = 0x08,
- PDC_DIMM_WINDOW_CTLR = 0x0C,
- PDC_TIME_CONTROL = 0x3C,
- PDC_TIME_PERIOD = 0x40,
- PDC_TIME_COUNTER = 0x44,
- PDC_GENERAL_CTLR = 0x484,
- PCI_PLL_INIT = 0x8A531824,
- PCI_X_TCOUNT = 0xEE1E5CFF
};
struct pdc_port_priv {
- u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
u8 *pkt;
dma_addr_t pkt_dma;
};
-struct pdc_host_priv {
- void *dimm_mmio;
-
- unsigned int doing_hdma;
- unsigned int hdma_prod;
- unsigned int hdma_cons;
- struct {
- struct ata_queued_cmd *qc;
- unsigned int seq;
- unsigned long pkt_ofs;
- } hdma[32];
-};
-
-
static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static void pdc_dma_start(struct ata_queued_cmd *qc);
-static void pdc20621_dma_start(struct ata_queued_cmd *qc);
static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
-static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
static void pdc_eng_timeout(struct ata_port *ap);
-static void pdc_20621_phy_reset (struct ata_port *ap);
static int pdc_port_start(struct ata_port *ap);
static void pdc_port_stop(struct ata_port *ap);
static void pdc_phy_reset(struct ata_port *ap);
static void pdc_fill_sg(struct ata_queued_cmd *qc);
-static void pdc20621_fill_sg(struct ata_queued_cmd *qc);
static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
-static void pdc20621_host_stop(struct ata_host_set *host_set);
static inline void pdc_dma_complete (struct ata_port *ap,
struct ata_queued_cmd *qc, int have_err);
-static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
-static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe,
- u32 device, u32 subaddr, u32 *pdata);
-static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);
-static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);
-#ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe,
- void *psource, u32 offset, u32 size);
-#endif
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
- void *psource, u32 offset, u32 size);
-
static Scsi_Host_Template pdc_sata_sht = {
.module = THIS_MODULE,
@@ -223,22 +118,6 @@
.port_stop = pdc_port_stop,
};
-static struct ata_port_operations pdc_20621_ops = {
- .port_disable = ata_port_disable,
- .tf_load = pdc_tf_load_mmio,
- .tf_read = ata_tf_read_mmio,
- .check_status = ata_check_status_mmio,
- .exec_command = pdc_exec_command_mmio,
- .phy_reset = pdc_20621_phy_reset,
- .bmdma_start = pdc20621_dma_start,
- .fill_sg = pdc20621_fill_sg,
- .eng_timeout = pdc_eng_timeout,
- .irq_handler = pdc20621_interrupt,
- .port_start = pdc_port_start,
- .port_stop = pdc_port_stop,
- .host_stop = pdc20621_host_stop,
-};
-
static struct ata_port_info pdc_port_info[] = {
/* board_2037x */
{
@@ -259,18 +138,6 @@
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &pdc_sata_ops,
},
-
- /* board_20621 */
- {
- .sht = &pdc_sata_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SRST | ATA_FLAG_MMIO |
- PDC_FLAG_20621,
- .pio_mask = 0x03, /* pio3-4 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
- .port_ops = &pdc_20621_ops,
- },
-
};
static struct pci_device_id pdc_sata_pci_tbl[] = {
@@ -286,8 +153,6 @@
board_20319 },
{ PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20621 },
{ } /* terminate list */
};
@@ -300,15 +165,6 @@
};
-static void pdc20621_host_stop(struct ata_host_set *host_set)
-{
- struct pdc_host_priv *hpriv = host_set->private_data;
- void *dimm_mmio = hpriv->dimm_mmio;
-
- iounmap(dimm_mmio);
- kfree(hpriv);
-}
-
static int pdc_port_start(struct ata_port *ap)
{
struct pci_dev *pdev = ap->host_set->pdev;
@@ -356,14 +212,6 @@
}
-static void pdc_20621_phy_reset (struct ata_port *ap)
-{
- VPRINTK("ENTER\n");
- ap->cbl = ATA_CBL_SATA;
- ata_port_probe(ap);
- ata_bus_reset(ap);
-}
-
static void pdc_reset_port(struct ata_port *ap)
{
void *mmio = (void *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
@@ -408,587 +256,6 @@
writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
}
-enum pdc_packet_bits {
- PDC_PKT_READ = (1 << 2),
- PDC_PKT_NODATA = (1 << 3),
-
- PDC_PKT_SIZEMASK = (1 << 7) | (1 << 6) | (1 << 5),
- PDC_PKT_CLEAR_BSY = (1 << 4),
- PDC_PKT_WAIT_DRDY = (1 << 3) | (1 << 4),
- PDC_LAST_REG = (1 << 3),
-
- PDC_REG_DEVCTL = (1 << 3) | (1 << 2) | (1 << 1),
-};
-
-static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf,
- dma_addr_t sg_table,
- unsigned int devno, u8 *buf)
-{
- u8 dev_reg;
- u32 *buf32 = (u32 *) buf;
-
- /* set control bits (byte 0), zero delay seq id (byte 3),
- * and seq id (byte 2)
- */
- switch (tf->protocol) {
- case ATA_PROT_DMA:
- if (!(tf->flags & ATA_TFLAG_WRITE))
- buf32[0] = cpu_to_le32(PDC_PKT_READ);
- else
- buf32[0] = 0;
- break;
-
- case ATA_PROT_NODATA:
- buf32[0] = cpu_to_le32(PDC_PKT_NODATA);
- break;
-
- default:
- BUG();
- break;
- }
-
- buf32[1] = cpu_to_le32(sg_table); /* S/G table addr */
- buf32[2] = 0; /* no next-packet */
-
- if (devno == 0)
- dev_reg = ATA_DEVICE_OBS;
- else
- dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
-
- /* select device */
- buf[12] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
- buf[13] = dev_reg;
-
- /* device control register */
- buf[14] = (1 << 5) | PDC_REG_DEVCTL;
- buf[15] = tf->ctl;
-
- return 16; /* offset of next byte */
-}
-
-static inline unsigned int pdc_pkt_footer(struct ata_taskfile *tf, u8 *buf,
- unsigned int i)
-{
- if (tf->flags & ATA_TFLAG_DEVICE) {
- buf[i++] = (1 << 5) | ATA_REG_DEVICE;
- buf[i++] = tf->device;
- }
-
- /* and finally the command itself; also includes end-of-pkt marker */
- buf[i++] = (1 << 5) | PDC_LAST_REG | ATA_REG_CMD;
- buf[i++] = tf->command;
-
- return i;
-}
-
-static inline unsigned int pdc_prep_lba28(struct ata_taskfile *tf, u8 *buf, unsigned int i)
-{
- /* the "(1 << 5)" should be read "(count << 5)" */
-
- /* ATA command block registers */
- buf[i++] = (1 << 5) | ATA_REG_FEATURE;
- buf[i++] = tf->feature;
-
- buf[i++] = (1 << 5) | ATA_REG_NSECT;
- buf[i++] = tf->nsect;
-
- buf[i++] = (1 << 5) | ATA_REG_LBAL;
- buf[i++] = tf->lbal;
-
- buf[i++] = (1 << 5) | ATA_REG_LBAM;
- buf[i++] = tf->lbam;
-
- buf[i++] = (1 << 5) | ATA_REG_LBAH;
- buf[i++] = tf->lbah;
-
- return i;
-}
-
-static inline unsigned int pdc_prep_lba48(struct ata_taskfile *tf, u8 *buf, unsigned int i)
-{
- /* the "(2 << 5)" should be read "(count << 5)" */
-
- /* ATA command block registers */
- buf[i++] = (2 << 5) | ATA_REG_FEATURE;
- buf[i++] = tf->hob_feature;
- buf[i++] = tf->feature;
-
- buf[i++] = (2 << 5) | ATA_REG_NSECT;
- buf[i++] = tf->hob_nsect;
- buf[i++] = tf->nsect;
-
- buf[i++] = (2 << 5) | ATA_REG_LBAL;
- buf[i++] = tf->hob_lbal;
- buf[i++] = tf->lbal;
-
- buf[i++] = (2 << 5) | ATA_REG_LBAM;
- buf[i++] = tf->hob_lbam;
- buf[i++] = tf->lbam;
-
- buf[i++] = (2 << 5) | ATA_REG_LBAH;
- buf[i++] = tf->hob_lbah;
- buf[i++] = tf->lbah;
-
- return i;
-}
-
-static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
- unsigned int portno,
- unsigned int total_len)
-{
- u32 addr;
- unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
- u32 *buf32 = (u32 *) buf;
-
- /* output ATA packet S/G table */
- addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
- (PDC_DIMM_DATA_STEP * portno);
- VPRINTK("ATA sg addr 0x%x, %d\n", addr, addr);
- buf32[dw] = cpu_to_le32(addr);
- buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
-
- VPRINTK("ATA PSG @ %x == (0x%x, 0x%x)\n",
- PDC_20621_DIMM_BASE +
- (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_APKT_PRD,
- buf32[dw], buf32[dw + 1]);
-}
-
-static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
- unsigned int portno,
- unsigned int total_len)
-{
- u32 addr;
- unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
- u32 *buf32 = (u32 *) buf;
-
- /* output Host DMA packet S/G table */
- addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
- (PDC_DIMM_DATA_STEP * portno);
-
- buf32[dw] = cpu_to_le32(addr);
- buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
-
- VPRINTK("HOST PSG @ %x == (0x%x, 0x%x)\n",
- PDC_20621_DIMM_BASE +
- (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_HPKT_PRD,
- buf32[dw], buf32[dw + 1]);
-}
-
-static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,
- unsigned int devno, u8 *buf,
- unsigned int portno)
-{
- unsigned int i, dw;
- u32 *buf32 = (u32 *) buf;
- u8 dev_reg;
-
- unsigned int dimm_sg = PDC_20621_DIMM_BASE +
- (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_APKT_PRD;
- VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
-
- i = PDC_DIMM_ATA_PKT;
-
- /*
- * Set up ATA packet
- */
- if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
- buf[i++] = PDC_PKT_READ;
- else if (tf->protocol == ATA_PROT_NODATA)
- buf[i++] = PDC_PKT_NODATA;
- else
- buf[i++] = 0;
- buf[i++] = 0; /* reserved */
- buf[i++] = portno + 1; /* seq. id */
- buf[i++] = 0xff; /* delay seq. id */
-
- /* dimm dma S/G, and next-pkt */
- dw = i >> 2;
- buf32[dw] = cpu_to_le32(dimm_sg);
- buf32[dw + 1] = 0;
- i += 8;
-
- if (devno == 0)
- dev_reg = ATA_DEVICE_OBS;
- else
- dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
-
- /* select device */
- buf[i++] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
- buf[i++] = dev_reg;
-
- /* device control register */
- buf[i++] = (1 << 5) | PDC_REG_DEVCTL;
- buf[i++] = tf->ctl;
-
- return i;
-}
-
-static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,
- unsigned int portno)
-{
- unsigned int dw;
- u32 tmp, *buf32 = (u32 *) buf;
-
- unsigned int host_sg = PDC_20621_DIMM_BASE +
- (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_HOST_PRD;
- unsigned int dimm_sg = PDC_20621_DIMM_BASE +
- (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_HPKT_PRD;
- VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
- VPRINTK("host_sg == 0x%x, %d\n", host_sg, host_sg);
-
- dw = PDC_DIMM_HOST_PKT >> 2;
-
- /*
- * Set up Host DMA packet
- */
- if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
- tmp = PDC_PKT_READ;
- else
- tmp = 0;
- tmp |= ((portno + 1 + 4) << 16); /* seq. id */
- tmp |= (0xff << 24); /* delay seq. id */
- buf32[dw + 0] = cpu_to_le32(tmp);
- buf32[dw + 1] = cpu_to_le32(host_sg);
- buf32[dw + 2] = cpu_to_le32(dimm_sg);
- buf32[dw + 3] = 0;
-
- VPRINTK("HOST PKT @ %x == (0x%x 0x%x 0x%x 0x%x)\n",
- PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * portno) +
- PDC_DIMM_HOST_PKT,
- buf32[dw + 0],
- buf32[dw + 1],
- buf32[dw + 2],
- buf32[dw + 3]);
-}
-
-static void pdc20621_fill_sg(struct ata_queued_cmd *qc)
-{
- struct scatterlist *sg = qc->sg;
- struct ata_port *ap = qc->ap;
- struct pdc_port_priv *pp = ap->private_data;
- void *mmio = ap->host_set->mmio_base;
- struct pdc_host_priv *hpriv = ap->host_set->private_data;
- void *dimm_mmio = hpriv->dimm_mmio;
- unsigned int portno = ap->port_no;
- unsigned int i, last, idx, total_len = 0, sgt_len;
- u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
-
- VPRINTK("ata%u: ENTER\n", ap->id);
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- /*
- * Build S/G table
- */
- last = qc->n_elem;
- idx = 0;
- for (i = 0; i < last; i++) {
- buf[idx++] = cpu_to_le32(sg_dma_address(&sg[i]));
- buf[idx++] = cpu_to_le32(sg_dma_len(&sg[i]));
- total_len += sg[i].length;
- }
- buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT);
- sgt_len = idx * 4;
-
- /*
- * Build ATA, host DMA packets
- */
- pdc20621_host_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
- pdc20621_host_pkt(&qc->tf, &pp->dimm_buf[0], portno);
-
- pdc20621_ata_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
- i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
-
- if (qc->tf.flags & ATA_TFLAG_LBA48)
- i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
- else
- i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
-
- pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
-
- /* copy three S/G tables and two packets to DIMM MMIO window */
- memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
- &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
- memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP) +
- PDC_DIMM_HOST_PRD,
- &pp->dimm_buf[PDC_DIMM_HEADER_SZ], sgt_len);
-
- /* force host FIFO dump */
- writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
-
- readl(dimm_mmio); /* MMIO PCI posting flush */
-
- VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len);
-}
-
-static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
- unsigned int seq,
- u32 pkt_ofs)
-{
- struct ata_port *ap = qc->ap;
- struct ata_host_set *host_set = ap->host_set;
- void *mmio = host_set->mmio_base;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
- readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
-
- writel(pkt_ofs, mmio + PDC_HDMA_PKT_SUBMIT);
- readl(mmio + PDC_HDMA_PKT_SUBMIT); /* flush */
-}
-
-static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
- unsigned int seq,
- u32 pkt_ofs)
-{
- struct ata_port *ap = qc->ap;
- struct pdc_host_priv *pp = ap->host_set->private_data;
- unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK;
-
- if (!pp->doing_hdma) {
- __pdc20621_push_hdma(qc, seq, pkt_ofs);
- pp->doing_hdma = 1;
- return;
- }
-
- pp->hdma[idx].qc = qc;
- pp->hdma[idx].seq = seq;
- pp->hdma[idx].pkt_ofs = pkt_ofs;
- pp->hdma_prod++;
-}
-
-static void pdc20621_pop_hdma(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct pdc_host_priv *pp = ap->host_set->private_data;
- unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK;
-
- /* if nothing on queue, we're done */
- if (pp->hdma_prod == pp->hdma_cons) {
- pp->doing_hdma = 0;
- return;
- }
-
- __pdc20621_push_hdma(pp->hdma[idx].qc, pp->hdma[idx].seq,
- pp->hdma[idx].pkt_ofs);
- pp->hdma_cons++;
-}
-
-#ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- unsigned int port_no = ap->port_no;
- struct pdc_host_priv *hpriv = ap->host_set->private_data;
- void *dimm_mmio = hpriv->dimm_mmio;
-
- dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
- dimm_mmio += PDC_DIMM_HOST_PKT;
-
- printk(KERN_ERR "HDMA[0] == 0x%08X\n", readl(dimm_mmio));
- printk(KERN_ERR "HDMA[1] == 0x%08X\n", readl(dimm_mmio + 4));
- printk(KERN_ERR "HDMA[2] == 0x%08X\n", readl(dimm_mmio + 8));
- printk(KERN_ERR "HDMA[3] == 0x%08X\n", readl(dimm_mmio + 12));
-}
-#else
-static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { }
-#endif /* ATA_VERBOSE_DEBUG */
-
-static void pdc20621_dma_start(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct ata_host_set *host_set = ap->host_set;
- unsigned int port_no = ap->port_no;
- void *mmio = host_set->mmio_base;
- unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
- u8 seq = (u8) (port_no + 1);
- unsigned int doing_hdma = 0, port_ofs;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- VPRINTK("ata%u: ENTER\n", ap->id);
-
- port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
-
- /* if writing, we (1) DMA to DIMM, then (2) do ATA command */
- if (rw) {
- doing_hdma = 1;
- seq += 4;
- }
-
- wmb(); /* flush PRD, pkt writes */
-
- if (doing_hdma) {
- pdc20621_dump_hdma(qc);
- pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT);
- VPRINTK("queued ofs 0x%x (%u), seq %u\n",
- port_ofs + PDC_DIMM_HOST_PKT,
- port_ofs + PDC_DIMM_HOST_PKT,
- seq);
- } else {
- writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
- readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
-
- writel(port_ofs + PDC_DIMM_ATA_PKT,
- (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- VPRINTK("submitted ofs 0x%x (%u), seq %u\n",
- port_ofs + PDC_DIMM_ATA_PKT,
- port_ofs + PDC_DIMM_ATA_PKT,
- seq);
- }
-}
-
-static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
- struct ata_queued_cmd *qc,
- unsigned int doing_hdma,
- void *mmio)
-{
- unsigned int port_no = ap->port_no;
- unsigned int port_ofs =
- PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
- u8 status;
- unsigned int handled = 0;
-
- VPRINTK("ENTER\n");
-
- if ((qc->tf.protocol == ATA_PROT_DMA) && /* read */
- (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
-
- /* step two - DMA from DIMM to host */
- if (doing_hdma) {
- VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id,
- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
- pdc_dma_complete(ap, qc, 0);
- pdc20621_pop_hdma(qc);
- }
-
- /* step one - exec ATA command */
- else {
- u8 seq = (u8) (port_no + 1 + 4);
- VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->id,
- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
-
- /* submit hdma pkt */
- pdc20621_dump_hdma(qc);
- pdc20621_push_hdma(qc, seq,
- port_ofs + PDC_DIMM_HOST_PKT);
- }
- handled = 1;
-
- } else if (qc->tf.protocol == ATA_PROT_DMA) { /* write */
-
- /* step one - DMA from host to DIMM */
- if (doing_hdma) {
- u8 seq = (u8) (port_no + 1);
- VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->id,
- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
-
- /* submit ata pkt */
- writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
- readl(mmio + PDC_20621_SEQCTL + (seq * 4));
- writel(port_ofs + PDC_DIMM_ATA_PKT,
- (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- }
-
- /* step two - execute ATA command */
- else {
- VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id,
- readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
- pdc_dma_complete(ap, qc, 0);
- pdc20621_pop_hdma(qc);
- }
- handled = 1;
-
- /* command completion, but no data xfer */
- } else if (qc->tf.protocol == ATA_PROT_NODATA) {
-
- status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
- DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
- ata_qc_complete(qc, status, 0);
- handled = 1;
-
- } else {
- ap->stats.idle_irq++;
- }
-
- return handled;
-}
-
-static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
-{
- struct ata_host_set *host_set = dev_instance;
- struct ata_port *ap;
- u32 mask = 0;
- unsigned int i, tmp, port_no;
- unsigned int handled = 0;
- void *mmio_base;
-
- VPRINTK("ENTER\n");
-
- if (!host_set || !host_set->mmio_base) {
- VPRINTK("QUICK EXIT\n");
- return IRQ_NONE;
- }
-
- mmio_base = host_set->mmio_base;
-
- /* reading should also clear interrupts */
- mmio_base += PDC_CHIP0_OFS;
- mask = readl(mmio_base + PDC_20621_SEQMASK);
- VPRINTK("mask == 0x%x\n", mask);
-
- if (mask == 0xffffffff) {
- VPRINTK("QUICK EXIT 2\n");
- return IRQ_NONE;
- }
- mask &= 0xffff; /* only 16 tags possible */
- if (!mask) {
- VPRINTK("QUICK EXIT 3\n");
- return IRQ_NONE;
- }
-
- spin_lock(&host_set->lock);
-
- for (i = 1; i < 9; i++) {
- port_no = i - 1;
- if (port_no > 3)
- port_no -= 4;
- if (port_no >= host_set->n_ports)
- ap = NULL;
- else
- ap = host_set->ports[port_no];
- tmp = mask & (1 << i);
- VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
- if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
- struct ata_queued_cmd *qc;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && ((qc->flags & ATA_QCFLAG_POLL) == 0))
- handled += pdc20621_host_intr(ap, qc, (i > 4),
- mmio_base);
- }
- }
-
- spin_unlock(&host_set->lock);
-
- VPRINTK("mask == 0x%x\n", mask);
-
- VPRINTK("EXIT\n");
-
- return IRQ_RETVAL(handled);
-}
-
static void pdc_fill_sg(struct ata_queued_cmd *qc)
{
struct pdc_port_priv *pp = qc->ap->private_data;
@@ -1211,456 +478,11 @@
}
-#ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
- u32 offset, u32 size)
-{
- u32 window_size;
- u16 idx;
- u8 page_mask;
- long dist;
- void *mmio = pe->mmio_base;
- struct pdc_host_priv *hpriv = pe->private_data;
- void *dimm_mmio = hpriv->dimm_mmio;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- page_mask = 0x00;
- window_size = 0x2000 * 4; /* 32K byte uchar size */
- idx = (u16) (offset / window_size);
-
- writel(0x01, mmio + PDC_GENERAL_CTLR);
- readl(mmio + PDC_GENERAL_CTLR);
- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
- readl(mmio + PDC_DIMM_WINDOW_CTLR);
-
- offset -= (idx * window_size);
- idx++;
- dist = ((long) (window_size - (offset + size))) >= 0 ? size :
- (long) (window_size - offset);
- memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4),
- dist);
-
- psource += dist;
- size -= dist;
- for (; (long) size >= (long) window_size ;) {
- writel(0x01, mmio + PDC_GENERAL_CTLR);
- readl(mmio + PDC_GENERAL_CTLR);
- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
- readl(mmio + PDC_DIMM_WINDOW_CTLR);
- memcpy_fromio((char *) psource, (char *) (dimm_mmio),
- window_size / 4);
- psource += window_size;
- size -= window_size;
- idx ++;
- }
-
- if (size) {
- writel(0x01, mmio + PDC_GENERAL_CTLR);
- readl(mmio + PDC_GENERAL_CTLR);
- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
- readl(mmio + PDC_DIMM_WINDOW_CTLR);
- memcpy_fromio((char *) psource, (char *) (dimm_mmio),
- size / 4);
- }
-}
-#endif
-
-
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
- u32 offset, u32 size)
-{
- u32 window_size;
- u16 idx;
- u8 page_mask;
- long dist;
- void *mmio = pe->mmio_base;
- struct pdc_host_priv *hpriv = pe->private_data;
- void *dimm_mmio = hpriv->dimm_mmio;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- page_mask = 0x00;
- window_size = 0x2000 * 4; /* 32K byte uchar size */
- idx = (u16) (offset / window_size);
-
- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
- readl(mmio + PDC_DIMM_WINDOW_CTLR);
- offset -= (idx * window_size);
- idx++;
- dist = ((long) (window_size - (offset + size))) >= 0 ? size :
- (long) (window_size - offset);
- memcpy_toio((char *) (dimm_mmio + offset / 4), (char *) psource, dist);
- writel(0x01, mmio + PDC_GENERAL_CTLR);
- readl(mmio + PDC_GENERAL_CTLR);
-
- psource += dist;
- size -= dist;
- for (; (long) size >= (long) window_size ;) {
- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
- readl(mmio + PDC_DIMM_WINDOW_CTLR);
- memcpy_toio((char *) (dimm_mmio), (char *) psource,
- window_size / 4);
- writel(0x01, mmio + PDC_GENERAL_CTLR);
- readl(mmio + PDC_GENERAL_CTLR);
- psource += window_size;
- size -= window_size;
- idx ++;
- }
-
- if (size) {
- writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
- readl(mmio + PDC_DIMM_WINDOW_CTLR);
- memcpy_toio((char *) (dimm_mmio), (char *) psource, size / 4);
- writel(0x01, mmio + PDC_GENERAL_CTLR);
- readl(mmio + PDC_GENERAL_CTLR);
- }
-}
-
-
-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
- u32 subaddr, u32 *pdata)
-{
- void *mmio = pe->mmio_base;
- u32 i2creg = 0;
- u32 status;
- u32 count =0;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- i2creg |= device << 24;
- i2creg |= subaddr << 16;
-
- /* Set the device and subaddress */
- writel(i2creg, mmio + PDC_I2C_ADDR_DATA_OFFSET);
- readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
-
- /* Write Control to perform read operation, mask int */
- writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT,
- mmio + PDC_I2C_CONTROL_OFFSET);
-
- for (count = 0; count <= 1000; count ++) {
- status = readl(mmio + PDC_I2C_CONTROL_OFFSET);
- if (status & PDC_I2C_COMPLETE) {
- status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
- break;
- } else if (count == 1000)
- return 0;
- }
-
- *pdata = (status >> 8) & 0x000000ff;
- return 1;
-}
-
-
-static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
-{
- u32 data=0 ;
- if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
- PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
- if (data == 100)
- return 100;
- } else
- return 0;
-
- if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
- if(data <= 0x75)
- return 133;
- } else
- return 0;
-
- return 0;
-}
-
-
-static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
-{
- u32 spd0[50];
- u32 data = 0;
- int size, i;
- u8 bdimmsize;
- void *mmio = pe->mmio_base;
- static const struct {
- unsigned int reg;
- unsigned int ofs;
- } pdc_i2c_read_data [] = {
- { PDC_DIMM_SPD_TYPE, 11 },
- { PDC_DIMM_SPD_FRESH_RATE, 12 },
- { PDC_DIMM_SPD_COLUMN_NUM, 4 },
- { PDC_DIMM_SPD_ATTRIBUTE, 21 },
- { PDC_DIMM_SPD_ROW_NUM, 3 },
- { PDC_DIMM_SPD_BANK_NUM, 17 },
- { PDC_DIMM_SPD_MODULE_ROW, 5 },
- { PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 },
- { PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 },
- { PDC_DIMM_SPD_RAS_CAS_DELAY, 29 },
- { PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 },
- { PDC_DIMM_SPD_CAS_LATENCY, 18 },
- };
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- for(i=0; i spd0[28])
- ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10;
- data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
-
- if (spd0[18] & 0x08)
- data |= ((0x03) << 14);
- else if (spd0[18] & 0x04)
- data |= ((0x02) << 14);
- else if (spd0[18] & 0x01)
- data |= ((0x01) << 14);
- else
- data |= (0 << 14);
-
- /*
- Calculate the size of bDIMMSize (power of 2) and
- merge the DIMM size by program start/end address.
- */
-
- bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;
- size = (1 << bdimmsize) >> 20; /* size = xxx(MB) */
- data |= (((size / 16) - 1) << 16);
- data |= (0 << 23);
- data |= 8;
- writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET);
- readl(mmio + PDC_DIMM0_CONTROL_OFFSET);
- return size;
-}
-
-
-static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
-{
- u32 data, spd0;
- int error, i;
- void *mmio = pe->mmio_base;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- /*
- Set To Default : DIMM Module Global Control Register (0x022259F1)
- DIMM Arbitration Disable (bit 20)
- DIMM Data/Control Output Driving Selection (bit12 - bit15)
- Refresh Enable (bit 17)
- */
-
- data = 0x022259F1;
- writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
- readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
-
- /* Turn on for ECC */
- pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
- PDC_DIMM_SPD_TYPE, &spd0);
- if (spd0 == 0x02) {
- data |= (0x01 << 16);
- writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
- readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
- printk(KERN_ERR "Local DIMM ECC Enabled\n");
- }
-
- /* DIMM Initialization Select/Enable (bit 18/19) */
- data &= (~(1<<18));
- data |= (1<<19);
- writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
-
- error = 1;
- for (i = 1; i <= 10; i++) { /* polling ~5 secs */
- data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
- if (!(data & (1<<19))) {
- error = 0;
- break;
- }
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout((i * 100) * HZ / 1000);
- }
- return error;
-}
-
-
-static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
-{
- int speed, size, length;
- u32 addr,spd0,pci_status;
- u32 tmp=0;
- u32 time_period=0;
- u32 tcount=0;
- u32 ticks=0;
- u32 clock=0;
- u32 fparam=0;
- void *mmio = pe->mmio_base;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- /* Initialize PLL based upon PCI Bus Frequency */
-
- /* Initialize Time Period Register */
- writel(0xffffffff, mmio + PDC_TIME_PERIOD);
- time_period = readl(mmio + PDC_TIME_PERIOD);
- VPRINTK("Time Period Register (0x40): 0x%x\n", time_period);
-
- /* Enable timer */
- writel(0x00001a0, mmio + PDC_TIME_CONTROL);
- readl(mmio + PDC_TIME_CONTROL);
-
- /* Wait 3 seconds */
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(3 * HZ);
-
- /*
- When timer is enabled, counter is decreased every internal
- clock cycle.
- */
-
- tcount = readl(mmio + PDC_TIME_COUNTER);
- VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount);
-
- /*
- If SX4 is on PCI-X bus, after 3 seconds, the timer counter
- register should be >= (0xffffffff - 3x10^8).
- */
- if(tcount >= PCI_X_TCOUNT) {
- ticks = (time_period - tcount);
- VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks);
-
- clock = (ticks / 300000);
- VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock);
-
- clock = (clock * 33);
- VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock);
-
- /* PLL F Param (bit 22:16) */
- fparam = (1400000 / clock) - 2;
- VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam);
-
- /* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
- pci_status = (0x8a001824 | (fparam << 16));
- } else
- pci_status = PCI_PLL_INIT;
-
- /* Initialize PLL. */
- VPRINTK("pci_status: 0x%x\n", pci_status);
- writel(pci_status, mmio + PDC_CTL_STATUS);
- readl(mmio + PDC_CTL_STATUS);
-
- /*
- Read SPD of DIMM by I2C interface,
- and program the DIMM Module Controller.
- */
- if (!(speed = pdc20621_detect_dimm(pe))) {
- printk(KERN_ERR "Detect Local DIMM Fail\n");
- return 1; /* DIMM error */
- }
- VPRINTK("Local DIMM Speed = %d\n", speed);
-
- /* Programming DIMM0 Module Control Register (index_CID0:80h) */
- size = pdc20621_prog_dimm0(pe);
- VPRINTK("Local DIMM Size = %dMB\n",size);
-
- /* Programming DIMM Module Global Control Register (index_CID0:88h) */
- if (pdc20621_prog_dimm_global(pe)) {
- printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
- return 1;
- }
-
-#ifdef ATA_VERBOSE_DEBUG
- {
- u8 test_parttern1[40] = {0x55,0xAA,'P','r','o','m','i','s','e',' ',
- 'N','o','t',' ','Y','e','t',' ','D','e','f','i','n','e','d',' ',
- '1','.','1','0',
- '9','8','0','3','1','6','1','2',0,0};
- u8 test_parttern2[40] = {0};
-
- pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40);
- pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40);
-
- pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);
- pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
- printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
- test_parttern2[1], &(test_parttern2[2]));
- pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040,
- 40);
- printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
- test_parttern2[1], &(test_parttern2[2]));
-
- pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);
- pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
- printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
- test_parttern2[1], &(test_parttern2[2]));
- }
-#endif
-
- /* ECC initiliazation. */
-
- pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
- PDC_DIMM_SPD_TYPE, &spd0);
- if (spd0 == 0x02) {
- VPRINTK("Start ECC initialization\n");
- addr = 0;
- length = size * 1024 * 1024;
- while (addr < length) {
- pdc20621_put_to_dimm(pe, (void *) &tmp, addr,
- sizeof(u32));
- addr += sizeof(u32);
- }
- VPRINTK("Finish ECC initialization\n");
- }
- return 0;
-}
-
-
-static void pdc_20621_init(struct ata_probe_ent *pe)
-{
- u32 tmp;
- void *mmio = pe->mmio_base;
-
- /* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
-
- /*
- * Select page 0x40 for our 32k DIMM window
- */
- tmp = readl(mmio + PDC_20621_DIMM_WINDOW) & 0xffff0000;
- tmp |= PDC_PAGE_WINDOW; /* page 40h; arbitrarily selected */
- writel(tmp, mmio + PDC_20621_DIMM_WINDOW);
-
- /*
- * Reset Host DMA
- */
- tmp = readl(mmio + PDC_HDMA_CTLSTAT);
- tmp |= PDC_RESET;
- writel(tmp, mmio + PDC_HDMA_CTLSTAT);
- readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
-
- udelay(10);
-
- tmp = readl(mmio + PDC_HDMA_CTLSTAT);
- tmp &= ~PDC_RESET;
- writel(tmp, mmio + PDC_HDMA_CTLSTAT);
- readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
-}
-
static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
{
void *mmio = pe->mmio_base;
u32 tmp;
- if (chip_id == board_20621)
- BUG();
-
/*
* Except for the hotplug stuff, this is voodoo from the
* Promise driver. Label this entire section
@@ -1688,7 +510,7 @@
readl(mmio + PDC_TBG_MODE); /* flush */
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(10));
+ schedule_timeout(msecs_to_jiffies(10) + 1);
/* adjust slew rate control register. */
tmp = readl(mmio + PDC_SLEW_CTL);
@@ -1702,10 +524,8 @@
static int printed_version;
struct ata_probe_ent *probe_ent = NULL;
unsigned long base;
- void *mmio_base, *dimm_mmio = NULL;
- struct pdc_host_priv *hpriv = NULL;
+ void *mmio_base;
unsigned int board_idx = (unsigned int) ent->driver_data;
- unsigned int have_20621 = (board_idx == board_20621);
int rc;
if (!printed_version++)
@@ -1745,25 +565,6 @@
}
base = (unsigned long) mmio_base;
- if (have_20621) {
- hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
- memset(hpriv, 0, sizeof(*hpriv));
-
- dimm_mmio = ioremap(pci_resource_start(pdev, 4),
- pci_resource_len(pdev, 4));
- if (!dimm_mmio) {
- kfree(hpriv);
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
-
- hpriv->dimm_mmio = dimm_mmio;
- }
-
probe_ent->sht = pdc_port_info[board_idx].sht;
probe_ent->host_flags = pdc_port_info[board_idx].host_flags;
probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
@@ -1774,32 +575,22 @@
probe_ent->irq_flags = SA_SHIRQ;
probe_ent->mmio_base = mmio_base;
- if (have_20621) {
- probe_ent->private_data = hpriv;
- base += PDC_CHIP0_OFS;
- }
-
pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);
- if (!have_20621) {
- probe_ent->port[0].scr_addr = base + 0x400;
- probe_ent->port[1].scr_addr = base + 0x500;
- }
+ probe_ent->port[0].scr_addr = base + 0x400;
+ probe_ent->port[1].scr_addr = base + 0x500;
/* notice 4-port boards */
switch (board_idx) {
case board_20319:
- case board_20621:
probe_ent->n_ports = 4;
pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
- if (!have_20621) {
- probe_ent->port[2].scr_addr = base + 0x600;
- probe_ent->port[3].scr_addr = base + 0x700;
- }
+ probe_ent->port[2].scr_addr = base + 0x600;
+ probe_ent->port[3].scr_addr = base + 0x700;
break;
case board_2037x:
probe_ent->n_ports = 2;
@@ -1812,25 +603,12 @@
pci_set_master(pdev);
/* initialize adapter */
- if (have_20621) {
- /* initialize local dimm */
- if (pdc20621_dimm_init(probe_ent)) {
- rc = -ENOMEM;
- goto err_out_iounmap_dimm;
- }
- pdc_20621_init(probe_ent);
- } else
- pdc_host_init(board_idx, probe_ent);
+ pdc_host_init(board_idx, probe_ent);
ata_add_to_probe_list(probe_ent);
return 0;
-err_out_iounmap_dimm: /* only get to this label if 20621 */
- kfree(hpriv);
- iounmap(dimm_mmio);
-err_out_iounmap:
- iounmap(mmio_base);
err_out_free_ent:
kfree(probe_ent);
err_out_regions:
@@ -1871,7 +649,7 @@
MODULE_AUTHOR("Jeff Garzik");
-MODULE_DESCRIPTION("Promise SATA low-level driver");
+MODULE_DESCRIPTION("Promise SATA TX2/TX4 low-level driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);
diff -Nru a/drivers/scsi/sata_promise.h b/drivers/scsi/sata_promise.h
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/sata_promise.h Mon Apr 26 02:12:40 2004
@@ -0,0 +1,154 @@
+/*
+ * sata_promise.h - Promise SATA common definitions and inline funcs
+ *
+ * Copyright 2003-2004 Red Hat, Inc.
+ *
+ * The contents of this file are subject to the Open
+ * Software License version 1.1 that can be found at
+ * http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ * by reference.
+ *
+ * Alternatively, the contents of this file may be used under the terms
+ * of the GNU General Public License version 2 (the "GPL") as distributed
+ * in the kernel source COPYING file, in which case the provisions of
+ * the GPL are applicable instead of the above. If you wish to allow
+ * the use of your version of this file only under the terms of the
+ * GPL and not to allow others to use your version of this file under
+ * the OSL, indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by the GPL.
+ * If you do not delete the provisions above, a recipient may use your
+ * version of this file under either the OSL or the GPL.
+ *
+ */
+
+#ifndef __SATA_PROMISE_H__
+#define __SATA_PROMISE_H__
+
+#include
+
+enum pdc_packet_bits {
+ PDC_PKT_READ = (1 << 2),
+ PDC_PKT_NODATA = (1 << 3),
+
+ PDC_PKT_SIZEMASK = (1 << 7) | (1 << 6) | (1 << 5),
+ PDC_PKT_CLEAR_BSY = (1 << 4),
+ PDC_PKT_WAIT_DRDY = (1 << 3) | (1 << 4),
+ PDC_LAST_REG = (1 << 3),
+
+ PDC_REG_DEVCTL = (1 << 3) | (1 << 2) | (1 << 1),
+};
+
+static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf,
+ dma_addr_t sg_table,
+ unsigned int devno, u8 *buf)
+{
+ u8 dev_reg;
+ u32 *buf32 = (u32 *) buf;
+
+ /* set control bits (byte 0), zero delay seq id (byte 3),
+ * and seq id (byte 2)
+ */
+ switch (tf->protocol) {
+ case ATA_PROT_DMA:
+ if (!(tf->flags & ATA_TFLAG_WRITE))
+ buf32[0] = cpu_to_le32(PDC_PKT_READ);
+ else
+ buf32[0] = 0;
+ break;
+
+ case ATA_PROT_NODATA:
+ buf32[0] = cpu_to_le32(PDC_PKT_NODATA);
+ break;
+
+ default:
+ BUG();
+ break;
+ }
+
+ buf32[1] = cpu_to_le32(sg_table); /* S/G table addr */
+ buf32[2] = 0; /* no next-packet */
+
+ if (devno == 0)
+ dev_reg = ATA_DEVICE_OBS;
+ else
+ dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
+
+ /* select device */
+ buf[12] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
+ buf[13] = dev_reg;
+
+ /* device control register */
+ buf[14] = (1 << 5) | PDC_REG_DEVCTL;
+ buf[15] = tf->ctl;
+
+ return 16; /* offset of next byte */
+}
+
+static inline unsigned int pdc_pkt_footer(struct ata_taskfile *tf, u8 *buf,
+ unsigned int i)
+{
+ if (tf->flags & ATA_TFLAG_DEVICE) {
+ buf[i++] = (1 << 5) | ATA_REG_DEVICE;
+ buf[i++] = tf->device;
+ }
+
+ /* and finally the command itself; also includes end-of-pkt marker */
+ buf[i++] = (1 << 5) | PDC_LAST_REG | ATA_REG_CMD;
+ buf[i++] = tf->command;
+
+ return i;
+}
+
+static inline unsigned int pdc_prep_lba28(struct ata_taskfile *tf, u8 *buf, unsigned int i)
+{
+ /* the "(1 << 5)" should be read "(count << 5)" */
+
+ /* ATA command block registers */
+ buf[i++] = (1 << 5) | ATA_REG_FEATURE;
+ buf[i++] = tf->feature;
+
+ buf[i++] = (1 << 5) | ATA_REG_NSECT;
+ buf[i++] = tf->nsect;
+
+ buf[i++] = (1 << 5) | ATA_REG_LBAL;
+ buf[i++] = tf->lbal;
+
+ buf[i++] = (1 << 5) | ATA_REG_LBAM;
+ buf[i++] = tf->lbam;
+
+ buf[i++] = (1 << 5) | ATA_REG_LBAH;
+ buf[i++] = tf->lbah;
+
+ return i;
+}
+
+static inline unsigned int pdc_prep_lba48(struct ata_taskfile *tf, u8 *buf, unsigned int i)
+{
+ /* the "(2 << 5)" should be read "(count << 5)" */
+
+ /* ATA command block registers */
+ buf[i++] = (2 << 5) | ATA_REG_FEATURE;
+ buf[i++] = tf->hob_feature;
+ buf[i++] = tf->feature;
+
+ buf[i++] = (2 << 5) | ATA_REG_NSECT;
+ buf[i++] = tf->hob_nsect;
+ buf[i++] = tf->nsect;
+
+ buf[i++] = (2 << 5) | ATA_REG_LBAL;
+ buf[i++] = tf->hob_lbal;
+ buf[i++] = tf->lbal;
+
+ buf[i++] = (2 << 5) | ATA_REG_LBAM;
+ buf[i++] = tf->hob_lbam;
+ buf[i++] = tf->lbam;
+
+ buf[i++] = (2 << 5) | ATA_REG_LBAH;
+ buf[i++] = tf->hob_lbah;
+ buf[i++] = tf->lbah;
+
+ return i;
+}
+
+
+#endif /* __SATA_PROMISE_H__ */
diff -Nru a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c
--- a/drivers/scsi/sata_sis.c Mon Apr 26 02:12:40 2004
+++ b/drivers/scsi/sata_sis.c Mon Apr 26 02:12:40 2004
@@ -45,7 +45,8 @@
static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static struct pci_device_id sis_pci_tbl[] = {
- { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+ { PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+ { PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
{ } /* terminate list */
};
diff -Nru a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/sata_sx4.c Mon Apr 26 02:12:40 2004
@@ -0,0 +1,1449 @@
+/*
+ * sata_promise.c - Promise SATA
+ *
+ * Copyright 2003-2004 Red Hat, Inc.
+ *
+ * The contents of this file are subject to the Open
+ * Software License version 1.1 that can be found at
+ * http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ * by reference.
+ *
+ * Alternatively, the contents of this file may be used under the terms
+ * of the GNU General Public License version 2 (the "GPL") as distributed
+ * in the kernel source COPYING file, in which case the provisions of
+ * the GPL are applicable instead of the above. If you wish to allow
+ * the use of your version of this file only under the terms of the
+ * GPL and not to allow others to use your version of this file under
+ * the OSL, indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by the GPL.
+ * If you do not delete the provisions above, a recipient may use your
+ * version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "scsi.h"
+#include "hosts.h"
+#include
+#include
+#include "sata_promise.h"
+
+#define DRV_NAME "sata_sx4"
+#define DRV_VERSION "0.50"
+
+
+enum {
+ PDC_PRD_TBL = 0x44, /* Direct command DMA table addr */
+
+ PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
+ PDC_HDMA_PKT_SUBMIT = 0x100, /* Host DMA packet pointer addr */
+ PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
+ PDC_HDMA_CTLSTAT = 0x12C, /* Host DMA control / status */
+
+ PDC_20621_SEQCTL = 0x400,
+ PDC_20621_SEQMASK = 0x480,
+ PDC_20621_GENERAL_CTL = 0x484,
+ PDC_20621_PAGE_SIZE = (32 * 1024),
+
+ /* chosen, not constant, values; we design our own DIMM mem map */
+ PDC_20621_DIMM_WINDOW = 0x0C, /* page# for 32K DIMM window */
+ PDC_20621_DIMM_BASE = 0x00200000,
+ PDC_20621_DIMM_DATA = (64 * 1024),
+ PDC_DIMM_DATA_STEP = (256 * 1024),
+ PDC_DIMM_WINDOW_STEP = (8 * 1024),
+ PDC_DIMM_HOST_PRD = (6 * 1024),
+ PDC_DIMM_HOST_PKT = (128 * 0),
+ PDC_DIMM_HPKT_PRD = (128 * 1),
+ PDC_DIMM_ATA_PKT = (128 * 2),
+ PDC_DIMM_APKT_PRD = (128 * 3),
+ PDC_DIMM_HEADER_SZ = PDC_DIMM_APKT_PRD + 128,
+ PDC_PAGE_WINDOW = 0x40,
+ PDC_PAGE_DATA = PDC_PAGE_WINDOW +
+ (PDC_20621_DIMM_DATA / PDC_20621_PAGE_SIZE),
+ PDC_PAGE_SET = PDC_DIMM_DATA_STEP / PDC_20621_PAGE_SIZE,
+
+ PDC_CHIP0_OFS = 0xC0000, /* offset of chip #0 */
+
+ PDC_20621_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
+ (1<<23),
+
+ board_20621 = 0, /* FastTrak S150 SX4 */
+
+ PDC_RESET = (1 << 11), /* HDMA reset */
+
+ PDC_MAX_HDMA = 32,
+ PDC_HDMA_Q_MASK = (PDC_MAX_HDMA - 1),
+
+ PDC_DIMM0_SPD_DEV_ADDRESS = 0x50,
+ PDC_DIMM1_SPD_DEV_ADDRESS = 0x51,
+ PDC_MAX_DIMM_MODULE = 0x02,
+ PDC_I2C_CONTROL_OFFSET = 0x48,
+ PDC_I2C_ADDR_DATA_OFFSET = 0x4C,
+ PDC_DIMM0_CONTROL_OFFSET = 0x80,
+ PDC_DIMM1_CONTROL_OFFSET = 0x84,
+ PDC_SDRAM_CONTROL_OFFSET = 0x88,
+ PDC_I2C_WRITE = 0x00000000,
+ PDC_I2C_READ = 0x00000040,
+ PDC_I2C_START = 0x00000080,
+ PDC_I2C_MASK_INT = 0x00000020,
+ PDC_I2C_COMPLETE = 0x00010000,
+ PDC_I2C_NO_ACK = 0x00100000,
+ PDC_DIMM_SPD_SUBADDRESS_START = 0x00,
+ PDC_DIMM_SPD_SUBADDRESS_END = 0x7F,
+ PDC_DIMM_SPD_ROW_NUM = 3,
+ PDC_DIMM_SPD_COLUMN_NUM = 4,
+ PDC_DIMM_SPD_MODULE_ROW = 5,
+ PDC_DIMM_SPD_TYPE = 11,
+ PDC_DIMM_SPD_FRESH_RATE = 12,
+ PDC_DIMM_SPD_BANK_NUM = 17,
+ PDC_DIMM_SPD_CAS_LATENCY = 18,
+ PDC_DIMM_SPD_ATTRIBUTE = 21,
+ PDC_DIMM_SPD_ROW_PRE_CHARGE = 27,
+ PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,
+ PDC_DIMM_SPD_RAS_CAS_DELAY = 29,
+ PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,
+ PDC_DIMM_SPD_SYSTEM_FREQ = 126,
+ PDC_CTL_STATUS = 0x08,
+ PDC_DIMM_WINDOW_CTLR = 0x0C,
+ PDC_TIME_CONTROL = 0x3C,
+ PDC_TIME_PERIOD = 0x40,
+ PDC_TIME_COUNTER = 0x44,
+ PDC_GENERAL_CTLR = 0x484,
+ PCI_PLL_INIT = 0x8A531824,
+ PCI_X_TCOUNT = 0xEE1E5CFF
+};
+
+
+struct pdc_port_priv {
+ u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
+ u8 *pkt;
+ dma_addr_t pkt_dma;
+};
+
+struct pdc_host_priv {
+ void *dimm_mmio;
+
+ unsigned int doing_hdma;
+ unsigned int hdma_prod;
+ unsigned int hdma_cons;
+ struct {
+ struct ata_queued_cmd *qc;
+ unsigned int seq;
+ unsigned long pkt_ofs;
+ } hdma[32];
+};
+
+
+static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static void pdc20621_dma_start(struct ata_queued_cmd *qc);
+static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static void pdc_eng_timeout(struct ata_port *ap);
+static void pdc_20621_phy_reset (struct ata_port *ap);
+static int pdc_port_start(struct ata_port *ap);
+static void pdc_port_stop(struct ata_port *ap);
+static void pdc20621_fill_sg(struct ata_queued_cmd *qc);
+static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+static void pdc20621_host_stop(struct ata_host_set *host_set);
+static inline void pdc_dma_complete (struct ata_port *ap,
+ struct ata_queued_cmd *qc, int have_err);
+static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
+static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
+static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe,
+ u32 device, u32 subaddr, u32 *pdata);
+static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);
+static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);
+#ifdef ATA_VERBOSE_DEBUG
+static void pdc20621_get_from_dimm(struct ata_probe_ent *pe,
+ void *psource, u32 offset, u32 size);
+#endif
+static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
+ void *psource, u32 offset, u32 size);
+
+
+static Scsi_Host_Template pdc_sata_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .detect = ata_scsi_detect,
+ .release = ata_scsi_release,
+ .queuecommand = ata_scsi_queuecmd,
+ .eh_strategy_handler = ata_scsi_error,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .use_new_eh_code = ATA_SHT_NEW_EH_CODE,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations pdc_20621_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = pdc_tf_load_mmio,
+ .tf_read = ata_tf_read_mmio,
+ .check_status = ata_check_status_mmio,
+ .exec_command = pdc_exec_command_mmio,
+ .phy_reset = pdc_20621_phy_reset,
+ .bmdma_start = pdc20621_dma_start,
+ .fill_sg = pdc20621_fill_sg,
+ .eng_timeout = pdc_eng_timeout,
+ .irq_handler = pdc20621_interrupt,
+ .port_start = pdc_port_start,
+ .port_stop = pdc_port_stop,
+ .host_stop = pdc20621_host_stop,
+};
+
+static struct ata_port_info pdc_port_info[] = {
+ /* board_20621 */
+ {
+ .sht = &pdc_sata_sht,
+ .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_SRST | ATA_FLAG_MMIO,
+ .pio_mask = 0x03, /* pio3-4 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &pdc_20621_ops,
+ },
+
+};
+
+static struct pci_device_id pdc_sata_pci_tbl[] = {
+ { PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_20621 },
+ { } /* terminate list */
+};
+
+
+static struct pci_driver pdc_sata_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pdc_sata_pci_tbl,
+ .probe = pdc_sata_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+
+static void pdc20621_host_stop(struct ata_host_set *host_set)
+{
+ struct pdc_host_priv *hpriv = host_set->private_data;
+ void *dimm_mmio = hpriv->dimm_mmio;
+
+ iounmap(dimm_mmio);
+ kfree(hpriv);
+}
+
+static int pdc_port_start(struct ata_port *ap)
+{
+ struct pci_dev *pdev = ap->host_set->pdev;
+ struct pdc_port_priv *pp;
+ int rc;
+
+ rc = ata_port_start(ap);
+ if (rc)
+ return rc;
+
+ pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+ if (!pp) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ memset(pp, 0, sizeof(*pp));
+
+ pp->pkt = pci_alloc_consistent(pdev, 128, &pp->pkt_dma);
+ if (!pp->pkt) {
+ rc = -ENOMEM;
+ goto err_out_kfree;
+ }
+
+ ap->private_data = pp;
+
+ return 0;
+
+err_out_kfree:
+ kfree(pp);
+err_out:
+ ata_port_stop(ap);
+ return rc;
+}
+
+
+static void pdc_port_stop(struct ata_port *ap)
+{
+ struct pci_dev *pdev = ap->host_set->pdev;
+ struct pdc_port_priv *pp = ap->private_data;
+
+ ap->private_data = NULL;
+ pci_free_consistent(pdev, 128, pp->pkt, pp->pkt_dma);
+ kfree(pp);
+ ata_port_stop(ap);
+}
+
+
+static void pdc_20621_phy_reset (struct ata_port *ap)
+{
+ VPRINTK("ENTER\n");
+ ap->cbl = ATA_CBL_SATA;
+ ata_port_probe(ap);
+ ata_bus_reset(ap);
+}
+
+static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
+ unsigned int portno,
+ unsigned int total_len)
+{
+ u32 addr;
+ unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
+ u32 *buf32 = (u32 *) buf;
+
+ /* output ATA packet S/G table */
+ addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
+ (PDC_DIMM_DATA_STEP * portno);
+ VPRINTK("ATA sg addr 0x%x, %d\n", addr, addr);
+ buf32[dw] = cpu_to_le32(addr);
+ buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
+
+ VPRINTK("ATA PSG @ %x == (0x%x, 0x%x)\n",
+ PDC_20621_DIMM_BASE +
+ (PDC_DIMM_WINDOW_STEP * portno) +
+ PDC_DIMM_APKT_PRD,
+ buf32[dw], buf32[dw + 1]);
+}
+
+static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
+ unsigned int portno,
+ unsigned int total_len)
+{
+ u32 addr;
+ unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
+ u32 *buf32 = (u32 *) buf;
+
+ /* output Host DMA packet S/G table */
+ addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
+ (PDC_DIMM_DATA_STEP * portno);
+
+ buf32[dw] = cpu_to_le32(addr);
+ buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
+
+ VPRINTK("HOST PSG @ %x == (0x%x, 0x%x)\n",
+ PDC_20621_DIMM_BASE +
+ (PDC_DIMM_WINDOW_STEP * portno) +
+ PDC_DIMM_HPKT_PRD,
+ buf32[dw], buf32[dw + 1]);
+}
+
+static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,
+ unsigned int devno, u8 *buf,
+ unsigned int portno)
+{
+ unsigned int i, dw;
+ u32 *buf32 = (u32 *) buf;
+ u8 dev_reg;
+
+ unsigned int dimm_sg = PDC_20621_DIMM_BASE +
+ (PDC_DIMM_WINDOW_STEP * portno) +
+ PDC_DIMM_APKT_PRD;
+ VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
+
+ i = PDC_DIMM_ATA_PKT;
+
+ /*
+ * Set up ATA packet
+ */
+ if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
+ buf[i++] = PDC_PKT_READ;
+ else if (tf->protocol == ATA_PROT_NODATA)
+ buf[i++] = PDC_PKT_NODATA;
+ else
+ buf[i++] = 0;
+ buf[i++] = 0; /* reserved */
+ buf[i++] = portno + 1; /* seq. id */
+ buf[i++] = 0xff; /* delay seq. id */
+
+ /* dimm dma S/G, and next-pkt */
+ dw = i >> 2;
+ buf32[dw] = cpu_to_le32(dimm_sg);
+ buf32[dw + 1] = 0;
+ i += 8;
+
+ if (devno == 0)
+ dev_reg = ATA_DEVICE_OBS;
+ else
+ dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
+
+ /* select device */
+ buf[i++] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
+ buf[i++] = dev_reg;
+
+ /* device control register */
+ buf[i++] = (1 << 5) | PDC_REG_DEVCTL;
+ buf[i++] = tf->ctl;
+
+ return i;
+}
+
+static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,
+ unsigned int portno)
+{
+ unsigned int dw;
+ u32 tmp, *buf32 = (u32 *) buf;
+
+ unsigned int host_sg = PDC_20621_DIMM_BASE +
+ (PDC_DIMM_WINDOW_STEP * portno) +
+ PDC_DIMM_HOST_PRD;
+ unsigned int dimm_sg = PDC_20621_DIMM_BASE +
+ (PDC_DIMM_WINDOW_STEP * portno) +
+ PDC_DIMM_HPKT_PRD;
+ VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
+ VPRINTK("host_sg == 0x%x, %d\n", host_sg, host_sg);
+
+ dw = PDC_DIMM_HOST_PKT >> 2;
+
+ /*
+ * Set up Host DMA packet
+ */
+ if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
+ tmp = PDC_PKT_READ;
+ else
+ tmp = 0;
+ tmp |= ((portno + 1 + 4) << 16); /* seq. id */
+ tmp |= (0xff << 24); /* delay seq. id */
+ buf32[dw + 0] = cpu_to_le32(tmp);
+ buf32[dw + 1] = cpu_to_le32(host_sg);
+ buf32[dw + 2] = cpu_to_le32(dimm_sg);
+ buf32[dw + 3] = 0;
+
+ VPRINTK("HOST PKT @ %x == (0x%x 0x%x 0x%x 0x%x)\n",
+ PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * portno) +
+ PDC_DIMM_HOST_PKT,
+ buf32[dw + 0],
+ buf32[dw + 1],
+ buf32[dw + 2],
+ buf32[dw + 3]);
+}
+
+static void pdc20621_fill_sg(struct ata_queued_cmd *qc)
+{
+ struct scatterlist *sg = qc->sg;
+ struct ata_port *ap = qc->ap;
+ struct pdc_port_priv *pp = ap->private_data;
+ void *mmio = ap->host_set->mmio_base;
+ struct pdc_host_priv *hpriv = ap->host_set->private_data;
+ void *dimm_mmio = hpriv->dimm_mmio;
+ unsigned int portno = ap->port_no;
+ unsigned int i, last, idx, total_len = 0, sgt_len;
+ u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
+
+ VPRINTK("ata%u: ENTER\n", ap->id);
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ /*
+ * Build S/G table
+ */
+ last = qc->n_elem;
+ idx = 0;
+ for (i = 0; i < last; i++) {
+ buf[idx++] = cpu_to_le32(sg_dma_address(&sg[i]));
+ buf[idx++] = cpu_to_le32(sg_dma_len(&sg[i]));
+ total_len += sg[i].length;
+ }
+ buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT);
+ sgt_len = idx * 4;
+
+ /*
+ * Build ATA, host DMA packets
+ */
+ pdc20621_host_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
+ pdc20621_host_pkt(&qc->tf, &pp->dimm_buf[0], portno);
+
+ pdc20621_ata_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
+ i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
+
+ if (qc->tf.flags & ATA_TFLAG_LBA48)
+ i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
+ else
+ i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
+
+ pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
+
+ /* copy three S/G tables and two packets to DIMM MMIO window */
+ memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
+ &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
+ memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP) +
+ PDC_DIMM_HOST_PRD,
+ &pp->dimm_buf[PDC_DIMM_HEADER_SZ], sgt_len);
+
+ /* force host FIFO dump */
+ writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
+
+ readl(dimm_mmio); /* MMIO PCI posting flush */
+
+ VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len);
+}
+
+static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
+ unsigned int seq,
+ u32 pkt_ofs)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_host_set *host_set = ap->host_set;
+ void *mmio = host_set->mmio_base;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+ readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
+
+ writel(pkt_ofs, mmio + PDC_HDMA_PKT_SUBMIT);
+ readl(mmio + PDC_HDMA_PKT_SUBMIT); /* flush */
+}
+
+static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
+ unsigned int seq,
+ u32 pkt_ofs)
+{
+ struct ata_port *ap = qc->ap;
+ struct pdc_host_priv *pp = ap->host_set->private_data;
+ unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK;
+
+ if (!pp->doing_hdma) {
+ __pdc20621_push_hdma(qc, seq, pkt_ofs);
+ pp->doing_hdma = 1;
+ return;
+ }
+
+ pp->hdma[idx].qc = qc;
+ pp->hdma[idx].seq = seq;
+ pp->hdma[idx].pkt_ofs = pkt_ofs;
+ pp->hdma_prod++;
+}
+
+static void pdc20621_pop_hdma(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pdc_host_priv *pp = ap->host_set->private_data;
+ unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK;
+
+ /* if nothing on queue, we're done */
+ if (pp->hdma_prod == pp->hdma_cons) {
+ pp->doing_hdma = 0;
+ return;
+ }
+
+ __pdc20621_push_hdma(pp->hdma[idx].qc, pp->hdma[idx].seq,
+ pp->hdma[idx].pkt_ofs);
+ pp->hdma_cons++;
+}
+
+#ifdef ATA_VERBOSE_DEBUG
+static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned int port_no = ap->port_no;
+ struct pdc_host_priv *hpriv = ap->host_set->private_data;
+ void *dimm_mmio = hpriv->dimm_mmio;
+
+ dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
+ dimm_mmio += PDC_DIMM_HOST_PKT;
+
+ printk(KERN_ERR "HDMA[0] == 0x%08X\n", readl(dimm_mmio));
+ printk(KERN_ERR "HDMA[1] == 0x%08X\n", readl(dimm_mmio + 4));
+ printk(KERN_ERR "HDMA[2] == 0x%08X\n", readl(dimm_mmio + 8));
+ printk(KERN_ERR "HDMA[3] == 0x%08X\n", readl(dimm_mmio + 12));
+}
+#else
+static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { }
+#endif /* ATA_VERBOSE_DEBUG */
+
+static void pdc20621_dma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_host_set *host_set = ap->host_set;
+ unsigned int port_no = ap->port_no;
+ void *mmio = host_set->mmio_base;
+ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+ u8 seq = (u8) (port_no + 1);
+ unsigned int doing_hdma = 0, port_ofs;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ VPRINTK("ata%u: ENTER\n", ap->id);
+
+ port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
+
+ /* if writing, we (1) DMA to DIMM, then (2) do ATA command */
+ if (rw) {
+ doing_hdma = 1;
+ seq += 4;
+ }
+
+ wmb(); /* flush PRD, pkt writes */
+
+ if (doing_hdma) {
+ pdc20621_dump_hdma(qc);
+ pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT);
+ VPRINTK("queued ofs 0x%x (%u), seq %u\n",
+ port_ofs + PDC_DIMM_HOST_PKT,
+ port_ofs + PDC_DIMM_HOST_PKT,
+ seq);
+ } else {
+ writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+ readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
+
+ writel(port_ofs + PDC_DIMM_ATA_PKT,
+ (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ VPRINTK("submitted ofs 0x%x (%u), seq %u\n",
+ port_ofs + PDC_DIMM_ATA_PKT,
+ port_ofs + PDC_DIMM_ATA_PKT,
+ seq);
+ }
+}
+
+static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
+ struct ata_queued_cmd *qc,
+ unsigned int doing_hdma,
+ void *mmio)
+{
+ unsigned int port_no = ap->port_no;
+ unsigned int port_ofs =
+ PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
+ u8 status;
+ unsigned int handled = 0;
+
+ VPRINTK("ENTER\n");
+
+ if ((qc->tf.protocol == ATA_PROT_DMA) && /* read */
+ (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
+
+ /* step two - DMA from DIMM to host */
+ if (doing_hdma) {
+ VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id,
+ readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+ pdc_dma_complete(ap, qc, 0);
+ pdc20621_pop_hdma(qc);
+ }
+
+ /* step one - exec ATA command */
+ else {
+ u8 seq = (u8) (port_no + 1 + 4);
+ VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->id,
+ readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+
+ /* submit hdma pkt */
+ pdc20621_dump_hdma(qc);
+ pdc20621_push_hdma(qc, seq,
+ port_ofs + PDC_DIMM_HOST_PKT);
+ }
+ handled = 1;
+
+ } else if (qc->tf.protocol == ATA_PROT_DMA) { /* write */
+
+ /* step one - DMA from host to DIMM */
+ if (doing_hdma) {
+ u8 seq = (u8) (port_no + 1);
+ VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->id,
+ readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+
+ /* submit ata pkt */
+ writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+ readl(mmio + PDC_20621_SEQCTL + (seq * 4));
+ writel(port_ofs + PDC_DIMM_ATA_PKT,
+ (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ }
+
+ /* step two - execute ATA command */
+ else {
+ VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id,
+ readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+ pdc_dma_complete(ap, qc, 0);
+ pdc20621_pop_hdma(qc);
+ }
+ handled = 1;
+
+ /* command completion, but no data xfer */
+ } else if (qc->tf.protocol == ATA_PROT_NODATA) {
+
+ status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+ DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
+ ata_qc_complete(qc, status, 0);
+ handled = 1;
+
+ } else {
+ ap->stats.idle_irq++;
+ }
+
+ return handled;
+}
+
+static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+ struct ata_host_set *host_set = dev_instance;
+ struct ata_port *ap;
+ u32 mask = 0;
+ unsigned int i, tmp, port_no;
+ unsigned int handled = 0;
+ void *mmio_base;
+
+ VPRINTK("ENTER\n");
+
+ if (!host_set || !host_set->mmio_base) {
+ VPRINTK("QUICK EXIT\n");
+ return IRQ_NONE;
+ }
+
+ mmio_base = host_set->mmio_base;
+
+ /* reading should also clear interrupts */
+ mmio_base += PDC_CHIP0_OFS;
+ mask = readl(mmio_base + PDC_20621_SEQMASK);
+ VPRINTK("mask == 0x%x\n", mask);
+
+ if (mask == 0xffffffff) {
+ VPRINTK("QUICK EXIT 2\n");
+ return IRQ_NONE;
+ }
+ mask &= 0xffff; /* only 16 tags possible */
+ if (!mask) {
+ VPRINTK("QUICK EXIT 3\n");
+ return IRQ_NONE;
+ }
+
+ spin_lock(&host_set->lock);
+
+ for (i = 1; i < 9; i++) {
+ port_no = i - 1;
+ if (port_no > 3)
+ port_no -= 4;
+ if (port_no >= host_set->n_ports)
+ ap = NULL;
+ else
+ ap = host_set->ports[port_no];
+ tmp = mask & (1 << i);
+ VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
+ if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+ struct ata_queued_cmd *qc;
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc && ((qc->flags & ATA_QCFLAG_POLL) == 0))
+ handled += pdc20621_host_intr(ap, qc, (i > 4),
+ mmio_base);
+ }
+ }
+
+ spin_unlock(&host_set->lock);
+
+ VPRINTK("mask == 0x%x\n", mask);
+
+ VPRINTK("EXIT\n");
+
+ return IRQ_RETVAL(handled);
+}
+
+static inline void pdc_dma_complete (struct ata_port *ap,
+ struct ata_queued_cmd *qc,
+ int have_err)
+{
+ u8 err_bit = have_err ? ATA_ERR : 0;
+
+ /* get drive status; clear intr; complete txn */
+ ata_qc_complete(ata_qc_from_tag(ap, ap->active_tag),
+ ata_wait_idle(ap) | err_bit, 0);
+}
+
+static void pdc_eng_timeout(struct ata_port *ap)
+{
+ u8 drv_stat;
+ struct ata_queued_cmd *qc;
+
+ DPRINTK("ENTER\n");
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (!qc) {
+ printk(KERN_ERR "ata%u: BUG: timeout without command\n",
+ ap->id);
+ goto out;
+ }
+
+ /* hack alert! We cannot use the supplied completion
+ * function from inside the ->eh_strategy_handler() thread.
+ * libata is the only user of ->eh_strategy_handler() in
+ * any kernel, so the default scsi_done() assumes it is
+ * not being called from the SCSI EH.
+ */
+ qc->scsidone = scsi_finish_command;
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+ printk(KERN_ERR "ata%u: DMA timeout\n", ap->id);
+ ata_qc_complete(ata_qc_from_tag(ap, ap->active_tag),
+ ata_wait_idle(ap) | ATA_ERR, 0);
+ break;
+
+ case ATA_PROT_NODATA:
+ drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+
+ printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x\n",
+ ap->id, qc->tf.command, drv_stat);
+
+ ata_qc_complete(qc, drv_stat, 1);
+ break;
+
+ default:
+ drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+
+ printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n",
+ ap->id, qc->tf.command, drv_stat);
+
+ ata_qc_complete(qc, drv_stat, 1);
+ break;
+ }
+
+out:
+ DPRINTK("EXIT\n");
+}
+
+static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ if (tf->protocol == ATA_PROT_PIO)
+ ata_tf_load_mmio(ap, tf);
+}
+
+
+static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ if (tf->protocol == ATA_PROT_PIO)
+ ata_exec_command_mmio(ap, tf);
+}
+
+
+static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+ port->cmd_addr = base;
+ port->data_addr = base;
+ port->feature_addr =
+ port->error_addr = base + 0x4;
+ port->nsect_addr = base + 0x8;
+ port->lbal_addr = base + 0xc;
+ port->lbam_addr = base + 0x10;
+ port->lbah_addr = base + 0x14;
+ port->device_addr = base + 0x18;
+ port->command_addr =
+ port->status_addr = base + 0x1c;
+ port->altstatus_addr =
+ port->ctl_addr = base + 0x38;
+}
+
+
+#ifdef ATA_VERBOSE_DEBUG
+static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
+ u32 offset, u32 size)
+{
+ u32 window_size;
+ u16 idx;
+ u8 page_mask;
+ long dist;
+ void *mmio = pe->mmio_base;
+ struct pdc_host_priv *hpriv = pe->private_data;
+ void *dimm_mmio = hpriv->dimm_mmio;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ page_mask = 0x00;
+ window_size = 0x2000 * 4; /* 32K byte uchar size */
+ idx = (u16) (offset / window_size);
+
+ writel(0x01, mmio + PDC_GENERAL_CTLR);
+ readl(mmio + PDC_GENERAL_CTLR);
+ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+ readl(mmio + PDC_DIMM_WINDOW_CTLR);
+
+ offset -= (idx * window_size);
+ idx++;
+ dist = ((long) (window_size - (offset + size))) >= 0 ? size :
+ (long) (window_size - offset);
+ memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4),
+ dist);
+
+ psource += dist;
+ size -= dist;
+ for (; (long) size >= (long) window_size ;) {
+ writel(0x01, mmio + PDC_GENERAL_CTLR);
+ readl(mmio + PDC_GENERAL_CTLR);
+ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+ readl(mmio + PDC_DIMM_WINDOW_CTLR);
+ memcpy_fromio((char *) psource, (char *) (dimm_mmio),
+ window_size / 4);
+ psource += window_size;
+ size -= window_size;
+ idx ++;
+ }
+
+ if (size) {
+ writel(0x01, mmio + PDC_GENERAL_CTLR);
+ readl(mmio + PDC_GENERAL_CTLR);
+ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+ readl(mmio + PDC_DIMM_WINDOW_CTLR);
+ memcpy_fromio((char *) psource, (char *) (dimm_mmio),
+ size / 4);
+ }
+}
+#endif
+
+
+static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
+ u32 offset, u32 size)
+{
+ u32 window_size;
+ u16 idx;
+ u8 page_mask;
+ long dist;
+ void *mmio = pe->mmio_base;
+ struct pdc_host_priv *hpriv = pe->private_data;
+ void *dimm_mmio = hpriv->dimm_mmio;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ page_mask = 0x00;
+ window_size = 0x2000 * 4; /* 32K byte uchar size */
+ idx = (u16) (offset / window_size);
+
+ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+ readl(mmio + PDC_DIMM_WINDOW_CTLR);
+ offset -= (idx * window_size);
+ idx++;
+ dist = ((long) (window_size - (offset + size))) >= 0 ? size :
+ (long) (window_size - offset);
+ memcpy_toio((char *) (dimm_mmio + offset / 4), (char *) psource, dist);
+ writel(0x01, mmio + PDC_GENERAL_CTLR);
+ readl(mmio + PDC_GENERAL_CTLR);
+
+ psource += dist;
+ size -= dist;
+ for (; (long) size >= (long) window_size ;) {
+ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+ readl(mmio + PDC_DIMM_WINDOW_CTLR);
+ memcpy_toio((char *) (dimm_mmio), (char *) psource,
+ window_size / 4);
+ writel(0x01, mmio + PDC_GENERAL_CTLR);
+ readl(mmio + PDC_GENERAL_CTLR);
+ psource += window_size;
+ size -= window_size;
+ idx ++;
+ }
+
+ if (size) {
+ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+ readl(mmio + PDC_DIMM_WINDOW_CTLR);
+ memcpy_toio((char *) (dimm_mmio), (char *) psource, size / 4);
+ writel(0x01, mmio + PDC_GENERAL_CTLR);
+ readl(mmio + PDC_GENERAL_CTLR);
+ }
+}
+
+
+static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
+ u32 subaddr, u32 *pdata)
+{
+ void *mmio = pe->mmio_base;
+ u32 i2creg = 0;
+ u32 status;
+ u32 count =0;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ i2creg |= device << 24;
+ i2creg |= subaddr << 16;
+
+ /* Set the device and subaddress */
+ writel(i2creg, mmio + PDC_I2C_ADDR_DATA_OFFSET);
+ readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
+
+ /* Write Control to perform read operation, mask int */
+ writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT,
+ mmio + PDC_I2C_CONTROL_OFFSET);
+
+ for (count = 0; count <= 1000; count ++) {
+ status = readl(mmio + PDC_I2C_CONTROL_OFFSET);
+ if (status & PDC_I2C_COMPLETE) {
+ status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
+ break;
+ } else if (count == 1000)
+ return 0;
+ }
+
+ *pdata = (status >> 8) & 0x000000ff;
+ return 1;
+}
+
+
+static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
+{
+ u32 data=0 ;
+ if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+ PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
+ if (data == 100)
+ return 100;
+ } else
+ return 0;
+
+ if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
+ if(data <= 0x75)
+ return 133;
+ } else
+ return 0;
+
+ return 0;
+}
+
+
+static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
+{
+ u32 spd0[50];
+ u32 data = 0;
+ int size, i;
+ u8 bdimmsize;
+ void *mmio = pe->mmio_base;
+ static const struct {
+ unsigned int reg;
+ unsigned int ofs;
+ } pdc_i2c_read_data [] = {
+ { PDC_DIMM_SPD_TYPE, 11 },
+ { PDC_DIMM_SPD_FRESH_RATE, 12 },
+ { PDC_DIMM_SPD_COLUMN_NUM, 4 },
+ { PDC_DIMM_SPD_ATTRIBUTE, 21 },
+ { PDC_DIMM_SPD_ROW_NUM, 3 },
+ { PDC_DIMM_SPD_BANK_NUM, 17 },
+ { PDC_DIMM_SPD_MODULE_ROW, 5 },
+ { PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 },
+ { PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 },
+ { PDC_DIMM_SPD_RAS_CAS_DELAY, 29 },
+ { PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 },
+ { PDC_DIMM_SPD_CAS_LATENCY, 18 },
+ };
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ for(i=0; i spd0[28])
+ ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10;
+ data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
+
+ if (spd0[18] & 0x08)
+ data |= ((0x03) << 14);
+ else if (spd0[18] & 0x04)
+ data |= ((0x02) << 14);
+ else if (spd0[18] & 0x01)
+ data |= ((0x01) << 14);
+ else
+ data |= (0 << 14);
+
+ /*
+ Calculate the size of bDIMMSize (power of 2) and
+ merge the DIMM size by program start/end address.
+ */
+
+ bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;
+ size = (1 << bdimmsize) >> 20; /* size = xxx(MB) */
+ data |= (((size / 16) - 1) << 16);
+ data |= (0 << 23);
+ data |= 8;
+ writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET);
+ readl(mmio + PDC_DIMM0_CONTROL_OFFSET);
+ return size;
+}
+
+
+static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
+{
+ u32 data, spd0;
+ int error, i;
+ void *mmio = pe->mmio_base;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ /*
+ Set To Default : DIMM Module Global Control Register (0x022259F1)
+ DIMM Arbitration Disable (bit 20)
+ DIMM Data/Control Output Driving Selection (bit12 - bit15)
+ Refresh Enable (bit 17)
+ */
+
+ data = 0x022259F1;
+ writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+ readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+
+ /* Turn on for ECC */
+ pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+ PDC_DIMM_SPD_TYPE, &spd0);
+ if (spd0 == 0x02) {
+ data |= (0x01 << 16);
+ writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+ readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+ printk(KERN_ERR "Local DIMM ECC Enabled\n");
+ }
+
+ /* DIMM Initialization Select/Enable (bit 18/19) */
+ data &= (~(1<<18));
+ data |= (1<<19);
+ writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+
+ error = 1;
+ for (i = 1; i <= 10; i++) { /* polling ~5 secs */
+ data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+ if (!(data & (1<<19))) {
+ error = 0;
+ break;
+ }
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((i * 100) * HZ / 1000 + 1);
+ }
+ return error;
+}
+
+
+static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
+{
+ int speed, size, length;
+ u32 addr,spd0,pci_status;
+ u32 tmp=0;
+ u32 time_period=0;
+ u32 tcount=0;
+ u32 ticks=0;
+ u32 clock=0;
+ u32 fparam=0;
+ void *mmio = pe->mmio_base;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ /* Initialize PLL based upon PCI Bus Frequency */
+
+ /* Initialize Time Period Register */
+ writel(0xffffffff, mmio + PDC_TIME_PERIOD);
+ time_period = readl(mmio + PDC_TIME_PERIOD);
+ VPRINTK("Time Period Register (0x40): 0x%x\n", time_period);
+
+ /* Enable timer */
+ writel(0x00001a0, mmio + PDC_TIME_CONTROL);
+ readl(mmio + PDC_TIME_CONTROL);
+
+ /* Wait 3 seconds */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(3 * HZ);
+
+ /*
+ When timer is enabled, counter is decreased every internal
+ clock cycle.
+ */
+
+ tcount = readl(mmio + PDC_TIME_COUNTER);
+ VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount);
+
+ /*
+ If SX4 is on PCI-X bus, after 3 seconds, the timer counter
+ register should be >= (0xffffffff - 3x10^8).
+ */
+ if(tcount >= PCI_X_TCOUNT) {
+ ticks = (time_period - tcount);
+ VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks);
+
+ clock = (ticks / 300000);
+ VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock);
+
+ clock = (clock * 33);
+ VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock);
+
+ /* PLL F Param (bit 22:16) */
+ fparam = (1400000 / clock) - 2;
+ VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam);
+
+ /* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
+ pci_status = (0x8a001824 | (fparam << 16));
+ } else
+ pci_status = PCI_PLL_INIT;
+
+ /* Initialize PLL. */
+ VPRINTK("pci_status: 0x%x\n", pci_status);
+ writel(pci_status, mmio + PDC_CTL_STATUS);
+ readl(mmio + PDC_CTL_STATUS);
+
+ /*
+ Read SPD of DIMM by I2C interface,
+ and program the DIMM Module Controller.
+ */
+ if (!(speed = pdc20621_detect_dimm(pe))) {
+ printk(KERN_ERR "Detect Local DIMM Fail\n");
+ return 1; /* DIMM error */
+ }
+ VPRINTK("Local DIMM Speed = %d\n", speed);
+
+ /* Programming DIMM0 Module Control Register (index_CID0:80h) */
+ size = pdc20621_prog_dimm0(pe);
+ VPRINTK("Local DIMM Size = %dMB\n",size);
+
+ /* Programming DIMM Module Global Control Register (index_CID0:88h) */
+ if (pdc20621_prog_dimm_global(pe)) {
+ printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
+ return 1;
+ }
+
+#ifdef ATA_VERBOSE_DEBUG
+ {
+ u8 test_parttern1[40] = {0x55,0xAA,'P','r','o','m','i','s','e',' ',
+ 'N','o','t',' ','Y','e','t',' ','D','e','f','i','n','e','d',' ',
+ '1','.','1','0',
+ '9','8','0','3','1','6','1','2',0,0};
+ u8 test_parttern2[40] = {0};
+
+ pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40);
+ pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40);
+
+ pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);
+ pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+ printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
+ test_parttern2[1], &(test_parttern2[2]));
+ pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040,
+ 40);
+ printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
+ test_parttern2[1], &(test_parttern2[2]));
+
+ pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);
+ pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+ printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
+ test_parttern2[1], &(test_parttern2[2]));
+ }
+#endif
+
+ /* ECC initiliazation. */
+
+ pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+ PDC_DIMM_SPD_TYPE, &spd0);
+ if (spd0 == 0x02) {
+ VPRINTK("Start ECC initialization\n");
+ addr = 0;
+ length = size * 1024 * 1024;
+ while (addr < length) {
+ pdc20621_put_to_dimm(pe, (void *) &tmp, addr,
+ sizeof(u32));
+ addr += sizeof(u32);
+ }
+ VPRINTK("Finish ECC initialization\n");
+ }
+ return 0;
+}
+
+
+static void pdc_20621_init(struct ata_probe_ent *pe)
+{
+ u32 tmp;
+ void *mmio = pe->mmio_base;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ /*
+ * Select page 0x40 for our 32k DIMM window
+ */
+ tmp = readl(mmio + PDC_20621_DIMM_WINDOW) & 0xffff0000;
+ tmp |= PDC_PAGE_WINDOW; /* page 40h; arbitrarily selected */
+ writel(tmp, mmio + PDC_20621_DIMM_WINDOW);
+
+ /*
+ * Reset Host DMA
+ */
+ tmp = readl(mmio + PDC_HDMA_CTLSTAT);
+ tmp |= PDC_RESET;
+ writel(tmp, mmio + PDC_HDMA_CTLSTAT);
+ readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
+
+ udelay(10);
+
+ tmp = readl(mmio + PDC_HDMA_CTLSTAT);
+ tmp &= ~PDC_RESET;
+ writel(tmp, mmio + PDC_HDMA_CTLSTAT);
+ readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
+}
+
+static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_probe_ent *probe_ent = NULL;
+ unsigned long base;
+ void *mmio_base, *dimm_mmio = NULL;
+ struct pdc_host_priv *hpriv = NULL;
+ unsigned int board_idx = (unsigned int) ent->driver_data;
+ int rc;
+
+ if (!printed_version++)
+ printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+ /*
+ * If this driver happens to only be useful on Apple's K2, then
+ * we should check that here as it has a normal Serverworks ID
+ */
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc)
+ goto err_out;
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ memset(probe_ent, 0, sizeof(*probe_ent));
+ probe_ent->pdev = pdev;
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ mmio_base = ioremap(pci_resource_start(pdev, 3),
+ pci_resource_len(pdev, 3));
+ if (mmio_base == NULL) {
+ rc = -ENOMEM;
+ goto err_out_free_ent;
+ }
+ base = (unsigned long) mmio_base;
+
+ hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv) {
+ rc = -ENOMEM;
+ goto err_out_iounmap;
+ }
+ memset(hpriv, 0, sizeof(*hpriv));
+
+ dimm_mmio = ioremap(pci_resource_start(pdev, 4),
+ pci_resource_len(pdev, 4));
+ if (!dimm_mmio) {
+ kfree(hpriv);
+ rc = -ENOMEM;
+ goto err_out_iounmap;
+ }
+
+ hpriv->dimm_mmio = dimm_mmio;
+
+ probe_ent->sht = pdc_port_info[board_idx].sht;
+ probe_ent->host_flags = pdc_port_info[board_idx].host_flags;
+ probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
+ probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask;
+ probe_ent->port_ops = pdc_port_info[board_idx].port_ops;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = SA_SHIRQ;
+ probe_ent->mmio_base = mmio_base;
+
+ probe_ent->private_data = hpriv;
+ base += PDC_CHIP0_OFS;
+
+ pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
+ pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);
+
+ /* notice 4-port boards */
+ switch (board_idx) {
+ case board_20621:
+ probe_ent->n_ports = 4;
+
+ pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
+ pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
+ break;
+ default:
+ BUG();
+ break;
+ }
+
+ pci_set_master(pdev);
+
+ /* initialize adapter */
+ /* initialize local dimm */
+ if (pdc20621_dimm_init(probe_ent)) {
+ rc = -ENOMEM;
+ goto err_out_iounmap_dimm;
+ }
+ pdc_20621_init(probe_ent);
+
+ ata_add_to_probe_list(probe_ent);
+
+ return 0;
+
+err_out_iounmap_dimm: /* only get to this label if 20621 */
+ kfree(hpriv);
+ iounmap(dimm_mmio);
+err_out_iounmap:
+ iounmap(mmio_base);
+err_out_free_ent:
+ kfree(probe_ent);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out:
+ pci_disable_device(pdev);
+ return rc;
+}
+
+
+static int __init pdc_sata_init(void)
+{
+ int rc;
+
+ rc = pci_module_init(&pdc_sata_pci_driver);
+ if (rc)
+ return rc;
+
+ rc = scsi_register_module(MODULE_SCSI_HA, &pdc_sata_sht);
+ if (rc) {
+ rc = -ENODEV;
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ pci_unregister_driver(&pdc_sata_pci_driver);
+ return rc;
+}
+
+
+static void __exit pdc_sata_exit(void)
+{
+ scsi_unregister_module(MODULE_SCSI_HA, &pdc_sata_sht);
+ pci_unregister_driver(&pdc_sata_pci_driver);
+}
+
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("Promise SATA low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);
+
+module_init(pdc_sata_init);
+module_exit(pdc_sata_exit);
diff -Nru a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
--- a/drivers/scsi/sata_vsc.c Mon Apr 26 02:12:40 2004
+++ b/drivers/scsi/sata_vsc.c Mon Apr 26 02:12:40 2004
@@ -44,6 +44,8 @@
#define VSC_SATA_TF_CTL_OFFSET 0x29
/* DMA base */
+#define VSC_SATA_UP_DESCRIPTOR_OFFSET 0x64
+#define VSC_SATA_UP_DATA_BUFFER_OFFSET 0x6C
#define VSC_SATA_DMA_CMD_OFFSET 0x70
/* SCRs base */
@@ -235,6 +237,8 @@
port->ctl_addr = base + VSC_SATA_TF_CTL_OFFSET;
port->bmdma_addr = base + VSC_SATA_DMA_CMD_OFFSET;
port->scr_addr = base + VSC_SATA_SCR_STATUS_OFFSET;
+ writel(0, base + VSC_SATA_UP_DESCRIPTOR_OFFSET);
+ writel(0, base + VSC_SATA_UP_DATA_BUFFER_OFFSET);
}
diff -Nru a/include/linux/ioport.h b/include/linux/ioport.h
--- a/include/linux/ioport.h Mon Apr 26 02:12:40 2004
+++ b/include/linux/ioport.h Mon Apr 26 02:12:40 2004
@@ -85,6 +85,7 @@
extern int check_resource(struct resource *root, unsigned long, unsigned long);
extern int request_resource(struct resource *root, struct resource *new);
+extern struct resource * ____request_resource(struct resource *root, struct resource *new);
extern int release_resource(struct resource *new);
extern int allocate_resource(struct resource *root, struct resource *new,
unsigned long size,
diff -Nru a/include/linux/libata.h b/include/linux/libata.h
--- a/include/linux/libata.h Mon Apr 26 02:12:40 2004
+++ b/include/linux/libata.h Mon Apr 26 02:12:40 2004
@@ -27,6 +27,7 @@
#include
#include
#include
+#include
/*
* compile-time options
@@ -145,13 +146,6 @@
THR_IDLE = (THR_PROBE_FAILED + 1),
THR_PROBE_SUCCESS = (THR_IDLE + 1),
THR_PROBE_START = (THR_PROBE_SUCCESS + 1),
- THR_PIO_POLL = (THR_PROBE_START + 1),
- THR_PIO_TMOUT = (THR_PIO_POLL + 1),
- THR_PIO = (THR_PIO_TMOUT + 1),
- THR_PIO_LAST = (THR_PIO + 1),
- THR_PIO_LAST_POLL = (THR_PIO_LAST + 1),
- THR_PIO_ERR = (THR_PIO_LAST_POLL + 1),
- THR_PACKET = (THR_PIO_ERR + 1),
/* SATA port states */
PORT_UNKNOWN = 0,
@@ -164,6 +158,17 @@
ATA_QCFLAG_TIMEOUT = (1 << 0),
};
+enum pio_task_states {
+ PIO_ST_UNKNOWN,
+ PIO_ST_IDLE,
+ PIO_ST_POLL,
+ PIO_ST_TMOUT,
+ PIO_ST,
+ PIO_ST_LAST,
+ PIO_ST_LAST_POLL,
+ PIO_ST_ERR,
+};
+
/* forward declarations */
struct ata_port_operations;
struct ata_port;
@@ -224,7 +229,6 @@
struct scsi_cmnd *scsicmd;
void (*scsidone)(struct scsi_cmnd *);
- struct list_head node;
unsigned long flags; /* ATA_QCFLAG_xxx */
unsigned int tag;
unsigned int n_elem;
@@ -239,7 +243,7 @@
ata_qc_cb_t callback;
- struct semaphore sem;
+ struct completion *waiting;
void *private_data;
};
@@ -307,16 +311,17 @@
struct ata_host_stats stats;
struct ata_host_set *host_set;
- struct semaphore sem;
struct semaphore probe_sem;
unsigned int thr_state;
- int time_to_die;
- pid_t thr_pid;
- struct completion thr_exited;
- struct semaphore thr_sem;
- struct timer_list thr_timer;
- unsigned long thr_timeout;
+
+ struct tq_struct packet_task;
+
+ struct tq_struct pio_task;
+ unsigned int pio_task_state;
+ unsigned long pio_task_timeout;
+
+ struct tq_struct probe_task;
void *private_data;
};
@@ -392,6 +397,8 @@
extern void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
extern void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf);
extern void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+extern void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp);
+extern void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf);
extern u8 ata_check_status_pio(struct ata_port *ap);
extern u8 ata_check_status_mmio(struct ata_port *ap);
extern void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf);
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h Mon Apr 26 02:12:40 2004
+++ b/include/linux/pci_ids.h Mon Apr 26 02:12:40 2004
@@ -528,7 +528,6 @@
#define PCI_DEVICE_ID_SI_6202 0x0002
#define PCI_DEVICE_ID_SI_503 0x0008
#define PCI_DEVICE_ID_SI_ACPI 0x0009
-#define PCI_DEVICE_ID_SI_180 0x0180
#define PCI_DEVICE_ID_SI_5597_VGA 0x0200
#define PCI_DEVICE_ID_SI_6205 0x0205
#define PCI_DEVICE_ID_SI_501 0x0406
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c Mon Apr 26 02:12:40 2004
+++ b/kernel/ksyms.c Mon Apr 26 02:12:40 2004
@@ -448,6 +448,7 @@
#endif
/* resource handling */
+EXPORT_SYMBOL_GPL(____request_resource); /* may disappear in a few months */
EXPORT_SYMBOL(request_resource);
EXPORT_SYMBOL(release_resource);
EXPORT_SYMBOL(allocate_resource);
diff -Nru a/kernel/resource.c b/kernel/resource.c
--- a/kernel/resource.c Mon Apr 26 02:12:40 2004
+++ b/kernel/resource.c Mon Apr 26 02:12:40 2004
@@ -166,6 +166,16 @@
return conflict ? -EBUSY : 0;
}
+struct resource *____request_resource(struct resource *root, struct resource *new)
+{
+ struct resource *conflict;
+
+ write_lock(&resource_lock);
+ conflict = __request_resource(root, new);
+ write_unlock(&resource_lock);
+ return conflict;
+}
+
int release_resource(struct resource *old)
{
int retval;