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;