GIT 11fdf7e4fd51f0fd962a8d134c361ea647acbbdd git+ssh://master.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev.git#ALL commit cfd15b0011498986ef14b6c53f5eaba89d2171f3 Author: Uwe Koziolek Date: Wed Nov 8 09:57:00 2006 +0100 [PATCH] sata_sis: slave support on SiS965 SiS965 and SiS180 chips must support slave mode, SiS965L and SiS964 chips must not support slave mode. SCR_STATUS for SATA ports in powerdown state fixed. Now returning 0x0113 instead of 0x0117. Avoids problem on detecting sata_sis controller. Signed-off-by: Uwe Koziolek Signed-off-by: Jeff Garzik commit 4a009323d99b0de62548e4209b34ca9515427ad7 Author: Daniel Wolstenholme Date: Wed Nov 8 08:17:12 2006 -0500 [libata] sata_vsc: Add MSI support I've added a new vsc_sata_host_priv data structure (basically copied from the sata_mv driver) which has an hp_flags bitfield with a bit to indicate whether MSI is being used. This is used in the new vsc_sata_host_stop() routine to call pci_disable_msi() if MSI is on, pci_intx() if not. Signed-off-by: Daniel Wolstenholme Signed-off-by: Jeff Garzik commit eb370951bd2d115afc0dec86e33c2e3d53ce38ae Author: Tejun Heo Date: Thu Nov 2 12:17:23 2006 +0900 [PATCH] ahci: preserve PORTS_IMPL over host resets Instead of writing 0xf blindly, preserve the content of write-once PORTS_IMPL register over host resets. This patch is taken from Jeff Garzik's AHCI init update patch. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit c0caf70d9c12cf353152d91ad359e77a4491b9b8 Author: Alan Cox Date: Fri Nov 3 13:18:06 2006 +0000 [PATCH] pdc202xx_old: Fix name clashes with PA-RISC pdc_* functions are part of the global namespace for the PDC on PA-RISC systems and this means our choice of pdc_ causes collisions between the PDC globals and our static functions. Rename them to pdc202xx where they are for both 2024x and 2026x. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik commit 1903869a25a3c2be5ddbdcea497897f6d057aa7d Author: Kristen Carlson Accardi Date: Thu Sep 28 11:29:12 2006 -0700 [PATCH] libata: ACPI _SDD support _SDD (Set Device Data) is an ACPI method that is used to tell the firmware what the identify data is of the device that is attached to the port. It is an optional method, and it's ok for it to be missing. Because of this, we always return success from the routine that calls this method, even if the execution fails. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Jeff Garzik commit 99ac9616e0084130fe09db84a2b4e6a9a0850eab Author: Kristen Carlson Accardi Date: Thu Sep 28 11:29:01 2006 -0700 [PATCH] libata: ACPI and _GTF support _GTF is an acpi method that is used to reinitialize the drive. It returns a task file containing ata commands that are sent back to the drive to restore it to boot up defaults. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Jeff Garzik commit e39dc83a74c1312362fb98da9d66dbd6c8c8981b Author: Erik Benada Date: Tue Aug 29 18:07:19 2006 -0400 [libata sata_promise] support PATA ports on SATA controllers Add support for PATA port on Promise PDC2037x controllers. I tried to minimize changes to libata code. I just added flags for each port to ata_probe_ent structure and modified ata_host_init() function. Promise SATA driver was changed to use new ata_probe_ent->port_flags, check for presence of PATA port and pdc_phy_reset will use different reset code for PATA and SATA ports. Signed-off-by: Jeff Garzik commit e45dd65cea001c0fb891e34127ee77596d2ec8ae Author: Jeff Garzik Date: Wed Nov 1 05:10:42 2006 -0500 [libata] ahci: Match PCI class code for AHCI Signed-off-by: Jeff Garzik commit 081f0cec5a2b9e8e5a7839ddc0e58758f31f1883 Author: Tejun Heo Date: Wed Nov 1 18:39:55 2006 +0900 [PATCH] libata: move dev->max_sectors configuration into ata_dev_configure() Move dev->max_sectors configuration from ata_scsi_dev_config() to ata_dev_configure(). * more consistent. * allows LLDs to peek at the default dev->max_sectors value. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 04ff7de2ef6702f6ca02f584c10a4fc53a9bd23e Author: Tejun Heo Date: Wed Nov 1 18:39:27 2006 +0900 [PATCH] libata: implement ATA_EHI_SETMODE and ATA_EHI_POST_SETMODE libata EH used to perform ata_set_mode() iff the EH session performed reset as indicated by ATA_EHI_DID_RESET. This is incorrect because ->dev_config() called by revalidation is allowed to modify transfer mode which ata_set_mode() should take care of. This patch implements the following two flags. * ATA_EHI_SETMODE: set during EH to schedule ata_set_mode(). Both new device attachment and revalidation set this flag. * ATA_EHI_POST_SETMODE: set while the device is revalidated after ata_set_mode(). Post-setmode revalidation is different from initial configuaration and EH revalidation in that ->dev_config() is not allowed tune transfer mode. LLD can use this flag to determine whether it's allowed to tune transfer mode. Note that POST_SETMODE ->dev_config() is guaranteed to be preceded by non-POST_SETMODE ->dev_config(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit d8fddafb1ee66add83b6f387077ea47ab16fd38c Author: Tejun Heo Date: Wed Nov 1 18:38:52 2006 +0900 [PATCH] libata: implement ATA_EHI_PRINTINFO Implement ehi flag ATA_EHI_PRINTINFO. This flag is set when device configuration needs to print out device info. This used to be handled by @print_info argument to ata_dev_configure() but LLDs also need to know about it in ->dev_config() callback. This patch replaces @print_info w/ ATA_EHI_PRINTINFO and make sata_sil print workaround messages only on the initial configuration. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit a4398b81a663fe5834f6280dec21285691b3c8fd Author: Tejun Heo Date: Wed Nov 1 18:00:24 2006 +0900 [PATCH] ahci: update ahci-vt8251 reset sequence ahci-vt8251 * requires hardreset after PHY status change * doesn't clear BSY on signature FIS after hardreset * needs SError cleared for the port to operate after hardreset This patch implements ahci_vt8251_hardreset() and sets ATA_FLAG_HRST_TO_RESUME to handle the above behaviors. This fixes EH including hotplug on vt8251. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit ebf4a9a0e31ffa4a798fd3d02e19688383b05623 Author: Tejun Heo Date: Wed Nov 1 17:59:53 2006 +0900 [PATCH] libata: separate out and export sata_port_hardreset() Separate out sata_port_hardreset() from sata_std_hardreset(). This will be used by LLD hardreset implementation and later by PMP. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 5dce250d7f1d14a8aed44bcce2156a7d37904274 Author: Tejun Heo Date: Wed Nov 1 17:58:33 2006 +0900 [PATCH] ahci: kill AHCI_FLAG_RESET_NEEDS_CLO Now that ahci_softreset() is fixed to automatically perform CLO if BSY/DRQ is set on entry, AHCI_FLAG_RESET_NEEDS_CLO is redundant. Kill it. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit ee0fd6c1b95105832d463f7318b874ad448e476a Author: Tejun Heo Date: Mon Oct 16 08:47:18 2006 +0900 [PATCH] sata_sil24: add PMP related constants Add PMP related constants. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit cf7c8abee32c3c89dede1c980164c18d5d16f1eb Author: Tejun Heo Date: Mon Oct 16 08:47:18 2006 +0900 [PATCH] sata_sil24: rename PMP related constants Rename PMP related constants for consistency. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 37adf9d6fe99c6cef703a6fc480d9f77b113afec Author: Tejun Heo Date: Sat Sep 30 18:07:17 2006 +0900 [PATCH] libata: make user scan wait for scan to complete Make user scan wait for scan to complete. This way user can wait for warm plug request to complete and is prevented from causing EH event storm by repetitively issuing scan request while EH is in progress. Signed-off-by: Tejun Heo Cc: Fajun Chen Signed-off-by: Jeff Garzik commit ef6e7a2fb9a1824dbaf4480d588d46418ec780e4 Author: Tejun Heo Date: Thu Sep 28 17:49:22 2006 +0900 [PATCH] sata_nv: SRST sometimes fails after hotplug, use HRST_TO_RESUME NV controllers sometimes fail to perform softreset after hotplug. Make it use hardreset to resume link. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit a798862e84965db08ebfefae977678c74ed7246f Author: Tejun Heo Date: Mon Oct 9 11:10:26 2006 +0900 [PATCH] libata: move ata_irq_on() into libata-sff.c ata_irq_on() isn't used outside of libata core layer. The function is TF/SFF interface specific but currently used by core path with some hack too. Move it from include/linux/libata.h to drivers/ata/libata-sff.c. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik commit 837ea5742e7e4e88f86a2730c41135c4b024f623 Author: Tejun Heo Date: Mon Oct 9 18:32:15 2006 +0900 [PATCH] libata: handle 0xff status properly libata waits for !BSY even when the status register reports 0xff. This causes long boot delays when D8 isn't pulled down properly. This patch does the followings. * don't wait if status register is 0xff in all wait functions * make ata_busy_sleep() return 0 on success and -errno on failure. -ENODEV is returned on 0xff status and -EBUSY on other failures. * make ata_bus_softreset() succeed on 0xff status. 0xff status is not reset failure. It indicates no device. This removes unnecessary retries on such ports. Note that the code change assumes unoccupied port reporting 0xff status does not produce valid device signature. Signed-off-by: Tejun Heo Cc: Joe Jin Signed-off-by: Jeff Garzik commit a95b5f4bb76206e00b6e5891a69fb2f9bddf8e99 Author: Paul Mundt Date: Fri Oct 27 19:08:48 2006 -0700 [PATCH] ata: Generic platform_device libata driver needs a changelog Signed-off-by: Paul Mundt Acked-by: Russell King Cc: Jeff Garzik Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit b6adc823321b23afae8144bec1bf431d8a8c690a Author: Alan Cox Date: Fri Oct 27 19:08:46 2006 -0700 [PATCH] libata: Revamp blacklist support to allow multiple kinds of blacklisting flaws Signed-off-by: Alan Cox Cc: Jeff Garzik Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 5e9631a59e1bb3a7821639939193324669a29de0 Author: Robert Hancock Date: Fri Oct 27 19:08:41 2006 -0700 [PATCH] sata_nv ADMA/NCQ support for nForce4 This patch adds support for ADMA mode on NVIDIA nForce4 (CK804/MCP04) SATA controllers to the sata_nv driver. Benefits of ADMA mode include: - NCQ support - Reduced CPU overhead (controller DMAs command information from memory instead of them being pushed in by the CPU) - Full 64-bit DMA support ADMA mode is enabled by default in this version. To disable it, set the module parameter adma_enabled=0. Signed-off-by: Robert Hancock Cc: Jeff Garzik Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit b1098249dd9a92cdcc309c6eba398607269c9c51 Author: Jeff Garzik Date: Sat Oct 21 15:54:13 2006 -0400 [libata] pata_marvell: minor and trivial cleanups - use pci_iomap() [Alan, version 0.0.5t] - fix Alan's version 0.0.5t change - line length, trailing whitespace, case indentation cleanups - don't use deprecated ->eng_timeout() in a driver that uses new EH Signed-off-by: Jeff Garzik commit 8fd672c9a1026ef6f1168093a0edc81126e2a2cb Author: Alan Cox Date: Mon Oct 16 16:40:06 2006 +0100 [PATCH] pata_marvell: Marvell 6101/6145 PATA driver This is a legacy mode PATA driver for the 6101/45 and will also drive the SATA ports 1 & 2 in legacy mode as well if desired. Tested and confirmed working by users. The chip supports AHCI type behaviour for SATA and has a more advanced PATA interface as well so this driver will get it working but not get best performance for now. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik commit a1451c48034c96ec9ec3b66ef8889ad336b986fb Author: Henrik Kretzschmar Date: Tue Oct 10 14:29:24 2006 -0700 [PATCH] pci_module_init() conversion for pata_pdc2027x pci_module_init() conversion for pata_pdc2027x Signed-off-by: Henrik Kretzschmar Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 395bf956214fb584e43e8c049be7a959a38fad67 Author: Alan Cox Date: Tue Oct 10 14:28:11 2006 -0700 [PATCH] libata: add 40pin "short" cable support, honour drive side speed detection [deweerdt@free.fr: build fix] Signed-off-by: Alan Cox Signed-off-by: Frederik Deweerdt Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit ea2513390991c9f7b203bb3068e485e07e8a10af Author: Alan Cox Date: Tue Oct 10 14:28:12 2006 -0700 [PATCH] pci_module_init-convertion-in-ata_genericc fix Acked-by: Alan Cox but please apply as follows to keep revision id straight Cc: Henrik Kretzschmar Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit b0453137b19c83d8f3b5707efb74d893ee6a1590 Author: Henrik Kretzschmar Date: Tue Oct 10 14:28:12 2006 -0700 [PATCH] pci_module_init convertion in ata_generic.c pci_module_init convertion in ata_generic.c. Signed-off-by: Henrik Kretzschmar Acked-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik commit 0c837e57bdd0dd3292113dc62c7e629a2aa1a6e3 Author: Alan Cox Date: Fri Sep 29 18:30:05 2006 +0100 [PATCH] libata: Winbond support Winbond 83759A support in non-multichip mode (afaik nobody ever used multichip mode anyway). The 83759 is not supported by this driver as it is already handled elsewhere and doens't use the same interfaces. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik Documentation/kernel-parameters.txt | 5 drivers/ata/Kconfig | 38 + drivers/ata/Makefile | 5 drivers/ata/ahci.c | 120 ++++ drivers/ata/ata_generic.c | 4 drivers/ata/ata_piix.c | 31 + drivers/ata/libata-acpi.c | 698 ++++++++++++++++++++++++++ drivers/ata/libata-core.c | 249 ++++++--- drivers/ata/libata-eh.c | 20 + drivers/ata/libata-scsi.c | 27 - drivers/ata/libata-sff.c | 31 + drivers/ata/libata.h | 20 + drivers/ata/pata_ali.c | 2 drivers/ata/pata_marvell.c | 220 ++++++++ drivers/ata/pata_pdc2027x.c | 2 drivers/ata/pata_pdc202xx_old.c | 58 +- drivers/ata/pata_platform.c | 295 +++++++++++ drivers/ata/pata_winbond.c | 306 +++++++++++ drivers/ata/sata_nv.c | 943 ++++++++++++++++++++++++++++++++++- drivers/ata/sata_promise.c | 36 + drivers/ata/sata_sil.c | 11 drivers/ata/sata_sil24.c | 18 - drivers/ata/sata_sis.c | 17 - drivers/ata/sata_vsc.c | 43 +- include/linux/ata.h | 14 - include/linux/libata.h | 54 +- include/linux/pata_platform.h | 13 27 files changed, 3049 insertions(+), 231 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index dd00fd5..6911912 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -48,6 +48,7 @@ parameter is applicable: ISAPNP ISA PnP code is enabled. ISDN Appropriate ISDN support is enabled. JOY Appropriate joystick support is enabled. + LIBATA Libata driver is enabled LP Printer support is enabled. LOOP Loopback device support is enabled. M68k M68k architecture is enabled. @@ -1011,6 +1012,10 @@ and is between 256 and 4096 characters. emulation library even if a 387 maths coprocessor is present. + noacpi [LIBATA] Disables use of ACPI in libata suspend/resume + when set. + Format: + noalign [KNL,ARM] noapic [SMP,APIC] Tells the kernel to not make use of any diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 03f6338..647e67c 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -148,6 +148,19 @@ config SATA_INTEL_COMBINED depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX) default y +config SATA_ACPI + bool + depends on ACPI && PCI + default y + help + This option adds support for SATA-related ACPI objects. + These ACPI objects add the ability to retrieve taskfiles + from the ACPI BIOS and write them to the disk controller. + These objects may be related to performance, security, + power management, or other areas. + You can disable this at kernel boot time by using the + option libata.noacpi=1 + config PATA_ALI tristate "ALi PATA support (Experimental)" depends on PCI && EXPERIMENTAL @@ -328,6 +341,15 @@ config PATA_TRIFLEX If unsure, say N. +config PATA_MARVELL + tristate "Marvell PATA support via legacy mode" + depends on PCI + help + This option enables limited support for the Marvell 88SE6145 ATA + controller. + + If unsure, say N. + config PATA_MPIIX tristate "Intel PATA MPIIX support" depends on PCI @@ -483,6 +505,22 @@ config PATA_WINBOND If unsure, say N. +config PATA_WINBOND_VLB + tristate "Winbond W83759A VLB PATA support (Experimental)" + depends on ISA && EXPERIMENTAL + help + Support for the Winbond W83759A controller on Vesa Local Bus + systems. + +config PATA_PLATFORM + tristate "Generic platform device PATA support" + depends on EMBEDDED + help + This option enables support for generic directly connected ATA + devices commonly found on embedded systems. + + If unsure, say N. + endif endmenu diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 72243a6..4b994d4 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_PATA_NETCELL) += pata_netce obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o obj-$(CONFIG_PATA_OPTI) += pata_opti.o obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o +obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o obj-$(CONFIG_PATA_PCMCIA) += pata_pcmcia.o @@ -51,12 +52,14 @@ obj-$(CONFIG_PATA_SERVERWORKS) += pata_s obj-$(CONFIG_PATA_SIL680) += pata_sil680.o obj-$(CONFIG_PATA_VIA) += pata_via.o obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o +obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o obj-$(CONFIG_PATA_SIS) += pata_sis.o obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o +obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o # Should be last but one libata driver obj-$(CONFIG_ATA_GENERIC) += ata_generic.o # Should be last libata driver obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o - +libata-$(CONFIG_SATA_ACPI) += libata-acpi.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 234197e..f24d197 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -166,8 +166,7 @@ enum { AHCI_FLAG_MSI = (1 << 0), /* ap->flags bits */ - AHCI_FLAG_RESET_NEEDS_CLO = (1 << 24), - AHCI_FLAG_NO_NCQ = (1 << 25), + AHCI_FLAG_NO_NCQ = (1 << 24), }; struct ahci_cmd_hdr { @@ -214,6 +213,7 @@ static u8 ahci_check_status(struct ata_p static void ahci_freeze(struct ata_port *ap); static void ahci_thaw(struct ata_port *ap); static void ahci_error_handler(struct ata_port *ap); +static void ahci_vt8251_error_handler(struct ata_port *ap); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); static int ahci_port_resume(struct ata_port *ap); @@ -273,6 +273,37 @@ static const struct ata_port_operations .port_stop = ahci_port_stop, }; +static const struct ata_port_operations ahci_vt8251_ops = { + .port_disable = ata_port_disable, + + .check_status = ahci_check_status, + .check_altstatus = ahci_check_status, + .dev_select = ata_noop_dev_select, + + .tf_read = ahci_tf_read, + + .qc_prep = ahci_qc_prep, + .qc_issue = ahci_qc_issue, + + .irq_handler = ahci_interrupt, + .irq_clear = ahci_irq_clear, + + .scr_read = ahci_scr_read, + .scr_write = ahci_scr_write, + + .freeze = ahci_freeze, + .thaw = ahci_thaw, + + .error_handler = ahci_vt8251_error_handler, + .post_internal_cmd = ahci_post_internal_cmd, + + .port_suspend = ahci_port_suspend, + .port_resume = ahci_port_resume, + + .port_start = ahci_port_start, + .port_stop = ahci_port_stop, +}; + static const struct ata_port_info ahci_port_info[] = { /* board_ahci */ { @@ -290,10 +321,10 @@ static const struct ata_port_info ahci_p .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_SKIP_D2H_BSY | - AHCI_FLAG_RESET_NEEDS_CLO | AHCI_FLAG_NO_NCQ, + ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ - .port_ops = &ahci_ops, + .port_ops = &ahci_vt8251_ops, }, }; @@ -348,6 +379,10 @@ static const struct pci_device_id ahci_p { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */ { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */ + /* Generic, PCI class code for AHCI */ + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + 0x010601, 0xffffff, board_ahci }, + { } /* terminate list */ }; @@ -362,6 +397,11 @@ static struct pci_driver ahci_pci_driver }; +static inline int ahci_nr_ports(u32 cap) +{ + return (cap & 0x1f) + 1; +} + static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port) { return base + 0x100 + (port * 0x80); @@ -571,11 +611,12 @@ static int ahci_deinit_port(void __iomem static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev) { - u32 cap_save, tmp; + u32 cap_save, impl_save, tmp; cap_save = readl(mmio + HOST_CAP); cap_save &= ( (1<<28) | (1<<17) ); cap_save |= (1 << 27); + impl_save = readl(mmio + HOST_PORTS_IMPL); /* global controller reset */ tmp = readl(mmio + HOST_CTL); @@ -596,10 +637,21 @@ static int ahci_reset_controller(void __ return -EIO; } + /* turn on AHCI mode */ writel(HOST_AHCI_EN, mmio + HOST_CTL); (void) readl(mmio + HOST_CTL); /* flush */ + + /* These write-once registers are normally cleared on reset. + * Restore BIOS values... which we HOPE were present before + * reset. + */ + if (!impl_save) { + impl_save = (1 << ahci_nr_ports(cap_save)) - 1; + dev_printk(KERN_WARNING, &pdev->dev, + "PORTS_IMPL is zero, forcing 0x%x\n", impl_save); + } writel(cap_save, mmio + HOST_CAP); - writel(0xf, mmio + HOST_PORTS_IMPL); + writel(impl_save, mmio + HOST_PORTS_IMPL); (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ if (pdev->vendor == PCI_VENDOR_ID_INTEL) { @@ -705,17 +757,6 @@ static int ahci_clo(struct ata_port *ap) return 0; } -static int ahci_prereset(struct ata_port *ap) -{ - if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) && - (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) { - /* ATA_BUSY hasn't cleared, so send a CLO */ - ahci_clo(ap); - } - - return ata_std_prereset(ap); -} - static int ahci_softreset(struct ata_port *ap, unsigned int *class) { struct ahci_port_priv *pp = ap->private_data; @@ -853,6 +894,31 @@ static int ahci_hardreset(struct ata_por return rc; } +static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class) +{ + void __iomem *mmio = ap->host->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + int rc; + + DPRINTK("ENTER\n"); + + ahci_stop_engine(port_mmio); + + rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context)); + + /* vt8251 needs SError cleared for the port to operate */ + ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR)); + + ahci_start_engine(port_mmio); + + DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); + + /* vt8251 doesn't clear BSY on signature FIS reception, + * request follow-up softreset. + */ + return rc ?: -EAGAIN; +} + static void ahci_postreset(struct ata_port *ap, unsigned int *class) { void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; @@ -1168,7 +1234,23 @@ static void ahci_error_handler(struct at } /* perform recovery */ - ata_do_eh(ap, ahci_prereset, ahci_softreset, ahci_hardreset, + ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset, + ahci_postreset); +} + +static void ahci_vt8251_error_handler(struct ata_port *ap) +{ + void __iomem *mmio = ap->host->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + + if (!(ap->pflags & ATA_PFLAG_FROZEN)) { + /* restart engine */ + ahci_stop_engine(port_mmio); + ahci_start_engine(port_mmio); + } + + /* perform recovery */ + ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset, ahci_postreset); } @@ -1374,7 +1456,7 @@ static int ahci_host_init(struct ata_pro hpriv->cap = readl(mmio + HOST_CAP); hpriv->port_map = readl(mmio + HOST_PORTS_IMPL); - probe_ent->n_ports = (hpriv->cap & 0x1f) + 1; + probe_ent->n_ports = ahci_nr_ports(hpriv->cap); VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n", hpriv->cap, hpriv->port_map, probe_ent->n_ports); diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 377425e..75e0bb5 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -26,7 +26,7 @@ #include #include #define DRV_NAME "ata_generic" -#define DRV_VERSION "0.2.6" +#define DRV_VERSION "0.2.7" /* * A generic parallel ATA driver using libata @@ -230,7 +230,7 @@ static struct pci_driver ata_generic_pci static int __init ata_generic_init(void) { - return pci_module_init(&ata_generic_pci_driver); + return pci_register_driver(&ata_generic_pci_driver); } diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 720174d..14b726b 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -93,7 +93,7 @@ #include #include #define DRV_NAME "ata_piix" -#define DRV_VERSION "2.00ac6" +#define DRV_VERSION "2.00ac7" enum { PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ @@ -571,6 +571,23 @@ module_param(force_pcs, int, 0444); MODULE_PARM_DESC(force_pcs, "force honoring or ignoring PCS to work around " "device mis-detection (0=default, 1=ignore PCS, 2=honor PCS)"); +struct ich_laptop { + u16 device; + u16 subvendor; + u16 subdevice; +}; + +/* + * List of laptops that use short cables rather than 80 wire + */ + +static const struct ich_laptop ich_laptop[] = { + /* devid, subvendor, subdev */ + { 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */ + /* end marker */ + { 0, } +}; + /** * piix_pata_cbl_detect - Probe host controller cable detect info * @ap: Port for which cable detect info is desired @@ -585,12 +602,24 @@ MODULE_PARM_DESC(force_pcs, "force honor static void ich_pata_cbl_detect(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); + const struct ich_laptop *lap = &ich_laptop[0]; u8 tmp, mask; /* no 80c support in host controller? */ if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0) goto cbl40; + /* Check for specials - Acer Aspire 5602WLMi */ + while (lap->device) { + if (lap->device == pdev->device && + lap->subvendor == pdev->subsystem_vendor && + lap->subdevice == pdev->subsystem_device) { + ap->cbl = ATA_CBL_PATA40_SHORT; + return; + } + lap++; + } + /* check BIOS cable detect results */ mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC; pci_read_config_byte(pdev, PIIX_IOCFG, &tmp); diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c new file mode 100644 index 0000000..f2fd0dd --- /dev/null +++ b/drivers/ata/libata-acpi.c @@ -0,0 +1,698 @@ +/* + * libata-acpi.c + * Provides ACPI support for PATA/SATA. + * + * Copyright (C) 2006 Intel Corp. + * Copyright (C) 2006 Randy Dunlap + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "libata.h" + +#include +#include +#include +#include +#include +#include +#include + +#define SATA_ROOT_PORT(x) (((x) >> 16) & 0xffff) +#define SATA_PORT_NUMBER(x) ((x) & 0xffff) /* or NO_PORT_MULT */ +#define NO_PORT_MULT 0xffff +#define SATA_ADR_RSVD 0xffffffff + +#define REGS_PER_GTF 7 +struct taskfile_array { + u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ +}; + + +/** + * sata_get_dev_handle - finds acpi_handle and PCI device.function + * @dev: device to locate + * @handle: returned acpi_handle for @dev + * @pcidevfn: return PCI device.func for @dev + * + * This function is somewhat SATA-specific. Or at least the + * PATA & SATA versions of this function are different, + * so it's not entirely generic code. + * + * Returns 0 on success, <0 on error. + */ +static int sata_get_dev_handle(struct device *dev, acpi_handle *handle, + acpi_integer *pcidevfn) +{ + struct pci_dev *pci_dev; + acpi_integer addr; + + pci_dev = to_pci_dev(dev); /* NOTE: PCI-specific */ + /* Please refer to the ACPI spec for the syntax of _ADR. */ + addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); + *pcidevfn = addr; + *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr); + if (!*handle) + return -ENODEV; + return 0; +} + +/** + * pata_get_dev_handle - finds acpi_handle and PCI device.function + * @dev: device to locate + * @handle: returned acpi_handle for @dev + * @pcidevfn: return PCI device.func for @dev + * + * The PATA and SATA versions of this function are different. + * + * Returns 0 on success, <0 on error. + */ +static int pata_get_dev_handle(struct device *dev, acpi_handle *handle, + acpi_integer *pcidevfn) +{ + unsigned int bus, devnum, func; + acpi_integer addr; + acpi_handle dev_handle, parent_handle; + struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER, + .pointer = NULL}; + acpi_status status; + struct acpi_device_info *dinfo = NULL; + int ret = -ENODEV; + struct pci_dev *pdev = to_pci_dev(dev); + + bus = pdev->bus->number; + devnum = PCI_SLOT(pdev->devfn); + func = PCI_FUNC(pdev->devfn); + + dev_handle = DEVICE_ACPI_HANDLE(dev); + parent_handle = DEVICE_ACPI_HANDLE(dev->parent); + + status = acpi_get_object_info(parent_handle, &buffer); + if (ACPI_FAILURE(status)) + goto err; + + dinfo = buffer.pointer; + if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && + dinfo->address == bus) { + /* ACPI spec for _ADR for PCI bus: */ + addr = (acpi_integer)(devnum << 16 | func); + *pcidevfn = addr; + *handle = dev_handle; + } else { + goto err; + } + + if (!*handle) + goto err; + ret = 0; +err: + kfree(dinfo); + return ret; +} + +struct walk_info { /* can be trimmed some */ + struct device *dev; + struct acpi_device *adev; + acpi_handle handle; + acpi_integer pcidevfn; + unsigned int drivenum; + acpi_handle obj_handle; + struct ata_port *ataport; + struct ata_device *atadev; + u32 sata_adr; + int status; + char basepath[ACPI_PATHNAME_MAX]; + int basepath_len; +}; + +static acpi_status get_devices(acpi_handle handle, + u32 level, void *context, void **return_value) +{ + acpi_status status; + struct walk_info *winfo = context; + struct acpi_buffer namebuf = {ACPI_ALLOCATE_BUFFER, NULL}; + char *pathname; + struct acpi_buffer buffer; + struct acpi_device_info *dinfo; + + status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &namebuf); + if (status) + goto ret; + pathname = namebuf.pointer; + + buffer.length = ACPI_ALLOCATE_BUFFER; + buffer.pointer = NULL; + status = acpi_get_object_info(handle, &buffer); + if (ACPI_FAILURE(status)) + goto out2; + + dinfo = buffer.pointer; + + /* find full device path name for pcidevfn */ + if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && + dinfo->address == winfo->pcidevfn) { + if (ata_msg_probe(winfo->ataport)) + ata_dev_printk(winfo->atadev, KERN_DEBUG, + ":%s: matches pcidevfn (0x%llx)\n", + pathname, winfo->pcidevfn); + strlcpy(winfo->basepath, pathname, + sizeof(winfo->basepath)); + winfo->basepath_len = strlen(pathname); + goto out; + } + + /* if basepath is not yet known, ignore this object */ + if (!winfo->basepath_len) + goto out; + + /* if this object is in scope of basepath, maybe use it */ + if (strncmp(pathname, winfo->basepath, + winfo->basepath_len) == 0) { + if (!(dinfo->valid & ACPI_VALID_ADR)) + goto out; + if (ata_msg_probe(winfo->ataport)) + ata_dev_printk(winfo->atadev, KERN_DEBUG, + "GOT ONE: (%s) root_port = 0x%llx," + " port_num = 0x%llx\n", pathname, + SATA_ROOT_PORT(dinfo->address), + SATA_PORT_NUMBER(dinfo->address)); + /* heuristics: */ + if (SATA_PORT_NUMBER(dinfo->address) != NO_PORT_MULT) + if (ata_msg_probe(winfo->ataport)) + ata_dev_printk(winfo->atadev, + KERN_DEBUG, "warning: don't" + " know how to handle SATA port" + " multiplier\n"); + if (SATA_ROOT_PORT(dinfo->address) == + winfo->ataport->port_no && + SATA_PORT_NUMBER(dinfo->address) == NO_PORT_MULT) { + if (ata_msg_probe(winfo->ataport)) + ata_dev_printk(winfo->atadev, + KERN_DEBUG, + "THIS ^^^^^ is the requested" + " SATA drive (handle = 0x%p)\n", + handle); + winfo->sata_adr = dinfo->address; + winfo->obj_handle = handle; + } + } +out: + kfree(dinfo); +out2: + kfree(pathname); + +ret: + return status; +} + +/* Get the SATA drive _ADR object. */ +static int get_sata_adr(struct device *dev, acpi_handle handle, + acpi_integer pcidevfn, unsigned int drive, + struct ata_port *ap, + struct ata_device *atadev, u32 *dev_adr) +{ + acpi_status status; + struct walk_info *winfo; + int err = -ENOMEM; + + winfo = kzalloc(sizeof(struct walk_info), GFP_KERNEL); + if (!winfo) + goto out; + + winfo->dev = dev; + winfo->atadev = atadev; + winfo->ataport = ap; + if (acpi_bus_get_device(handle, &winfo->adev) < 0) + if (ata_msg_probe(ap)) + ata_dev_printk(winfo->atadev, KERN_DEBUG, + "acpi_bus_get_device failed\n"); + winfo->handle = handle; + winfo->pcidevfn = pcidevfn; + winfo->drivenum = drive; + + status = acpi_get_devices(NULL, get_devices, winfo, NULL); + if (ACPI_FAILURE(status)) { + if (ata_msg_probe(ap)) + ata_dev_printk(winfo->atadev, KERN_DEBUG, + "%s: acpi_get_devices failed\n", + __FUNCTION__); + err = -ENODEV; + } else { + *dev_adr = winfo->sata_adr; + atadev->obj_handle = winfo->obj_handle; + err = 0; + } + kfree(winfo); +out: + return err; +} + +/** + * do_drive_get_GTF - get the drive bootup default taskfile settings + * @ap: the ata_port for the drive + * @ix: target ata_device (drive) index + * @gtf_length: number of bytes of _GTF data returned at @gtf_address + * @gtf_address: buffer containing _GTF taskfile arrays + * + * This applies to both PATA and SATA drives. + * + * The _GTF method has no input parameters. + * It returns a variable number of register set values (registers + * hex 1F1..1F7, taskfiles). + * The is not known in advance, so have ACPI-CA + * allocate the buffer as needed and return it, then free it later. + * + * The returned @gtf_length and @gtf_address are only valid if the + * function return value is 0. + */ +static int do_drive_get_GTF(struct ata_port *ap, int ix, + unsigned int *gtf_length, unsigned long *gtf_address, + unsigned long *obj_loc) +{ + acpi_status status; + acpi_handle dev_handle = NULL; + acpi_handle chan_handle, drive_handle; + acpi_integer pcidevfn = 0; + u32 dev_adr; + struct acpi_buffer output; + union acpi_object *out_obj; + struct device *dev = ap->host->dev; + struct ata_device *atadev = &ap->device[ix]; + int err = -ENODEV; + + *gtf_length = 0; + *gtf_address = 0UL; + *obj_loc = 0UL; + + if (noacpi) + return 0; + + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: ENTER: ap->id: %d, port#: %d\n", + __FUNCTION__, ap->id, ap->port_no); + + if (!ata_dev_enabled(atadev) || (ap->flags & ATA_FLAG_DISABLED)) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, "%s: ERR: " + "ata_dev_present: %d, PORT_DISABLED: %lu\n", + __FUNCTION__, ata_dev_enabled(atadev), + ap->flags & ATA_FLAG_DISABLED); + goto out; + } + + /* Don't continue if device has no _ADR method. + * _GTF is intended for known motherboard devices. */ + if (!(ap->cbl == ATA_CBL_SATA)) { + err = pata_get_dev_handle(dev, &dev_handle, &pcidevfn); + if (err < 0) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: pata_get_dev_handle failed (%d)\n", + __FUNCTION__, err); + goto out; + } + } else { + err = sata_get_dev_handle(dev, &dev_handle, &pcidevfn); + if (err < 0) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: sata_get_dev_handle failed (%d\n", + __FUNCTION__, err); + goto out; + } + } + + /* Get this drive's _ADR info. if not already known. */ + if (!atadev->obj_handle) { + if (!(ap->cbl == ATA_CBL_SATA)) { + /* get child objects of dev_handle == channel objects, + * + _their_ children == drive objects */ + /* channel is ap->port_no */ + chan_handle = acpi_get_child(dev_handle, + ap->port_no); + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: chan adr=%d: chan_handle=0x%p\n", + __FUNCTION__, ap->port_no, + chan_handle); + if (!chan_handle) { + err = -ENODEV; + goto out; + } + /* TBD: could also check ACPI object VALID bits */ + drive_handle = acpi_get_child(chan_handle, ix); + if (!drive_handle) { + err = -ENODEV; + goto out; + } + dev_adr = ix; + atadev->obj_handle = drive_handle; + } else { /* for SATA mode */ + dev_adr = SATA_ADR_RSVD; + err = get_sata_adr(dev, dev_handle, pcidevfn, 0, + ap, atadev, &dev_adr); + } + if (err < 0 || dev_adr == SATA_ADR_RSVD || + !atadev->obj_handle) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: get_sata/pata_adr failed: " + "err=%d, dev_adr=%u, obj_handle=0x%p\n", + __FUNCTION__, err, dev_adr, + atadev->obj_handle); + goto out; + } + } + + /* Setting up output buffer */ + output.length = ACPI_ALLOCATE_BUFFER; + output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ + + /* _GTF has no input parameters */ + err = -EIO; + status = acpi_evaluate_object(atadev->obj_handle, "_GTF", + NULL, &output); + if (ACPI_FAILURE(status)) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: Run _GTF error: status = 0x%x\n", + __FUNCTION__, status); + goto out; + } + + if (!output.length || !output.pointer) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, "%s: Run _GTF: " + "length or ptr is NULL (0x%llx, 0x%p)\n", + __FUNCTION__, + (unsigned long long)output.length, + output.pointer); + kfree(output.pointer); + goto out; + } + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER) { + kfree(output.pointer); + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, "%s: Run _GTF: " + "error: expected object type of " + " ACPI_TYPE_BUFFER, got 0x%x\n", + __FUNCTION__, out_obj->type); + err = -ENOENT; + goto out; + } + + if (!out_obj->buffer.length || !out_obj->buffer.pointer || + out_obj->buffer.length % REGS_PER_GTF) { + if (ata_msg_drv(ap)) + ata_dev_printk(atadev, KERN_ERR, + "%s: unexpected GTF length (%d) or addr (0x%p)\n", + __FUNCTION__, out_obj->buffer.length, + out_obj->buffer.pointer); + err = -ENOENT; + goto out; + } + + *gtf_length = out_obj->buffer.length; + *gtf_address = (unsigned long)out_obj->buffer.pointer; + *obj_loc = (unsigned long)out_obj; + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, "%s: returning " + "gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n", + __FUNCTION__, *gtf_length, *gtf_address, *obj_loc); + err = 0; +out: + return err; +} + +/** + * taskfile_load_raw - send taskfile registers to host controller + * @ap: Port to which output is sent + * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7) + * + * Outputs ATA taskfile to standard ATA host controller using MMIO + * or PIO as indicated by the ATA_FLAG_MMIO flag. + * Writes the control, feature, nsect, lbal, lbam, and lbah registers. + * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect, + * hob_lbal, hob_lbam, and hob_lbah. + * + * This function waits for idle (!BUSY and !DRQ) after writing + * registers. If the control register has a new value, this + * function also waits for idle after writing control and before + * writing the remaining registers. + * + * LOCKING: TBD: + * Inherited from caller. + */ +static void taskfile_load_raw(struct ata_port *ap, + struct ata_device *atadev, + const struct taskfile_array *gtf) +{ + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, "%s: (0x1f1-1f7): hex: " + "%02x %02x %02x %02x %02x %02x %02x\n", + __FUNCTION__, + gtf->tfa[0], gtf->tfa[1], gtf->tfa[2], + gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]); + + if ((gtf->tfa[0] == 0) && (gtf->tfa[1] == 0) && (gtf->tfa[2] == 0) + && (gtf->tfa[3] == 0) && (gtf->tfa[4] == 0) && (gtf->tfa[5] == 0) + && (gtf->tfa[6] == 0)) + return; + + if (ap->ops->qc_issue) { + struct ata_taskfile tf; + unsigned int err; + + ata_tf_init(atadev, &tf); + + /* convert gtf to tf */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */ + tf.protocol = atadev->class == ATA_DEV_ATAPI ? + ATA_PROT_ATAPI_NODATA : ATA_PROT_NODATA; + tf.feature = gtf->tfa[0]; /* 0x1f1 */ + tf.nsect = gtf->tfa[1]; /* 0x1f2 */ + tf.lbal = gtf->tfa[2]; /* 0x1f3 */ + tf.lbam = gtf->tfa[3]; /* 0x1f4 */ + tf.lbah = gtf->tfa[4]; /* 0x1f5 */ + tf.device = gtf->tfa[5]; /* 0x1f6 */ + tf.command = gtf->tfa[6]; /* 0x1f7 */ + + err = ata_exec_internal(atadev, &tf, NULL, DMA_NONE, NULL, 0); + if (err && ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_ERR, + "%s: ata_exec_internal failed: %u\n", + __FUNCTION__, err); + } else + if (ata_msg_warn(ap)) + ata_dev_printk(atadev, KERN_WARNING, + "%s: SATA driver is missing qc_issue function" + " entry points\n", + __FUNCTION__); +} + +/** + * do_drive_set_taskfiles - write the drive taskfile settings from _GTF + * @ap: the ata_port for the drive + * @atadev: target ata_device + * @gtf_length: total number of bytes of _GTF taskfiles + * @gtf_address: location of _GTF taskfile arrays + * + * This applies to both PATA and SATA drives. + * + * Write {gtf_address, length gtf_length} in groups of + * REGS_PER_GTF bytes. + */ +static int do_drive_set_taskfiles(struct ata_port *ap, + struct ata_device *atadev, unsigned int gtf_length, + unsigned long gtf_address) +{ + int err = -ENODEV; + int gtf_count = gtf_length / REGS_PER_GTF; + int ix; + struct taskfile_array *gtf; + + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: ENTER: ap->id: %d, port#: %d\n", + __FUNCTION__, ap->id, ap->port_no); + + if (noacpi || !(ap->cbl == ATA_CBL_SATA)) + return 0; + + if (!ata_dev_enabled(atadev) || (ap->flags & ATA_FLAG_DISABLED)) + goto out; + if (!gtf_count) /* shouldn't be here */ + goto out; + + if (gtf_length % REGS_PER_GTF) { + if (ata_msg_drv(ap)) + ata_dev_printk(atadev, KERN_ERR, + "%s: unexpected GTF length (%d)\n", + __FUNCTION__, gtf_length); + goto out; + } + + for (ix = 0; ix < gtf_count; ix++) { + gtf = (struct taskfile_array *) + (gtf_address + ix * REGS_PER_GTF); + + /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */ + taskfile_load_raw(ap, atadev, gtf); + } + + err = 0; +out: + return err; +} + +/** + * ata_acpi_exec_tfs - get then write drive taskfile settings + * @ap: the ata_port for the drive + * + * This applies to both PATA and SATA drives. + */ +int ata_acpi_exec_tfs(struct ata_port *ap) +{ + int ix; + int ret =0; + unsigned int gtf_length; + unsigned long gtf_address; + unsigned long obj_loc; + + if (noacpi) + return 0; + + for (ix = 0; ix < ATA_MAX_DEVICES; ix++) { + if (!ata_dev_enabled(&ap->device[ix])) + continue; + + ret = do_drive_get_GTF(ap, ix, + >f_length, >f_address, &obj_loc); + if (ret < 0) { + if (ata_msg_probe(ap)) + ata_port_printk(ap, KERN_DEBUG, + "%s: get_GTF error (%d)\n", + __FUNCTION__, ret); + break; + } + + ret = do_drive_set_taskfiles(ap, &ap->device[ix], + gtf_length, gtf_address); + kfree((void *)obj_loc); + if (ret < 0) { + if (ata_msg_probe(ap)) + ata_port_printk(ap, KERN_DEBUG, + "%s: set_taskfiles error (%d)\n", + __FUNCTION__, ret); + break; + } + } + + return ret; +} + +/** + * ata_acpi_push_id - send Identify data to drive + * @ap: the ata_port for the drive + * @ix: drive index + * + * _SDD ACPI object: for SATA mode only + * Must be after Identify (Packet) Device -- uses its data + * ATM this function never returns a failure. It is an optional + * method and if it fails for whatever reason, we should still + * just keep going. + */ +int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) +{ + acpi_handle handle; + acpi_integer pcidevfn; + int err; + struct device *dev = ap->host->dev; + struct ata_device *atadev = &ap->device[ix]; + u32 dev_adr; + acpi_status status; + struct acpi_object_list input; + union acpi_object in_params[1]; + + if (noacpi) + return 0; + + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: ap->id: %d, ix = %d, port#: %d\n", + __FUNCTION__, ap->id, ix, ap->port_no); + + /* Don't continue if not a SATA device. */ + if (!(ap->cbl == ATA_CBL_SATA)) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: Not a SATA device\n", __FUNCTION__); + goto out; + } + + /* Don't continue if device has no _ADR method. + * _SDD is intended for known motherboard devices. */ + err = sata_get_dev_handle(dev, &handle, &pcidevfn); + if (err < 0) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: sata_get_dev_handle failed (%d\n", + __FUNCTION__, err); + goto out; + } + + /* Get this drive's _ADR info, if not already known */ + if (!atadev->obj_handle) { + dev_adr = SATA_ADR_RSVD; + err = get_sata_adr(dev, handle, pcidevfn, ix, ap, atadev, + &dev_adr); + if (err < 0 || dev_adr == SATA_ADR_RSVD || + !atadev->obj_handle) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "%s: get_sata_adr failed: " + "err=%d, dev_adr=%u, obj_handle=0x%p\n", + __FUNCTION__, err, dev_adr, + atadev->obj_handle); + goto out; + } + } + + /* Give the drive Identify data to the drive via the _SDD method */ + /* _SDD: set up input parameters */ + input.count = 1; + input.pointer = in_params; + in_params[0].type = ACPI_TYPE_BUFFER; + in_params[0].buffer.length = sizeof(atadev->id[0] * ATA_ID_WORDS); + in_params[0].buffer.pointer = (u8 *)atadev->id; + /* Output buffer: _SDD has no output */ + + /* It's OK for _SDD to be missing too. */ + swap_buf_le16(atadev->id, ATA_ID_WORDS); + status = acpi_evaluate_object(atadev->obj_handle, "_SDD", &input, NULL); + swap_buf_le16(atadev->id, ATA_ID_WORDS); + + err = ACPI_FAILURE(status) ? -EIO : 0; + if (err < 0) { + if (ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_DEBUG, + "ata%u(%u): %s _SDD error: status = 0x%x\n", + ap->id, ap->device->devno, + __FUNCTION__, status); + } + + /* always return success */ +out: + return 0; +} + + diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index a8fd0c3..fe710c0 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -90,6 +90,10 @@ static int ata_probe_timeout = ATA_TMOUT module_param(ata_probe_timeout, int, 0444); MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)"); +int noacpi; +module_param(noacpi, int, 0444); +MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in suspend/resume when set"); + MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("Library module for ATA devices"); MODULE_LICENSE("GPL"); @@ -1345,7 +1349,10 @@ static void ata_dev_config_ncq(struct at desc[0] = '\0'; return; } - + if (ata_device_blacklisted(dev) & ATA_HORKAGE_NONCQ) { + snprintf(desc, desc_sz, "NCQ (not used)"); + return; + } if (ap->flags & ATA_FLAG_NCQ) { hdepth = min(ap->scsi_host->can_queue, ATA_MAX_QUEUE - 1); dev->flags |= ATA_DFLAG_NCQ; @@ -1374,7 +1381,6 @@ static void ata_set_port_max_cmd_len(str /** * ata_dev_configure - Configure the specified ATA/ATAPI device * @dev: Target device to configure - * @print_info: Enable device info printout * * Configure @dev according to @dev->id. Generic and low-level * driver specific fixups are also applied. @@ -1385,9 +1391,10 @@ static void ata_set_port_max_cmd_len(str * RETURNS: * 0 on success, -errno otherwise */ -int ata_dev_configure(struct ata_device *dev, int print_info) +int ata_dev_configure(struct ata_device *dev) { struct ata_port *ap = dev->ap; + int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; const u16 *id = dev->id; unsigned int xfer_mask; char revbuf[7]; /* XYZ-99\0 */ @@ -1530,6 +1537,11 @@ int ata_dev_configure(struct ata_device cdb_intr_string); } + /* determine max_sectors */ + dev->max_sectors = ATA_MAX_SECTORS; + if (dev->flags & ATA_DFLAG_LBA48) + dev->max_sectors = ATA_MAX_SECTORS_LBA48; + if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { /* Let the user know. We don't want to disallow opens for rescue purposes, or in case the vendor is just a blithering @@ -1556,6 +1568,14 @@ int ata_dev_configure(struct ata_device if (ap->ops->dev_config) ap->ops->dev_config(ap, dev); + /* set _SDD */ + rc = ata_acpi_push_id(ap, dev->devno); + if (rc) { + ata_dev_printk(dev, KERN_WARNING, "failed to set _SDD(%d)\n", + rc); + goto err_out_nosup; + } + if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n", __FUNCTION__, ata_chk_status(ap)); @@ -1601,6 +1621,9 @@ int ata_bus_probe(struct ata_port *ap) /* reset and determine device classes */ ap->ops->phy_reset(ap); + /* retrieve and execute the ATA task file of _GTF */ + ata_acpi_exec_tfs(ap); + for (i = 0; i < ATA_MAX_DEVICES; i++) { dev = &ap->device[i]; @@ -1635,7 +1658,9 @@ int ata_bus_probe(struct ata_port *ap) if (rc) goto fail; - rc = ata_dev_configure(dev, 1); + ap->eh_context.i.flags |= ATA_EHI_PRINTINFO; + rc = ata_dev_configure(dev); + ap->eh_context.i.flags &= ~ATA_EHI_PRINTINFO; if (rc) goto fail; } @@ -2153,6 +2178,7 @@ int ata_down_xfermask_limit(struct ata_d static int ata_dev_set_mode(struct ata_device *dev) { + struct ata_eh_context *ehc = &dev->ap->eh_context; unsigned int err_mask; int rc; @@ -2167,7 +2193,9 @@ static int ata_dev_set_mode(struct ata_d return -EIO; } + ehc->i.flags |= ATA_EHI_POST_SETMODE; rc = ata_dev_revalidate(dev, 0); + ehc->i.flags &= ~ATA_EHI_POST_SETMODE; if (rc) return rc; @@ -2325,11 +2353,14 @@ static inline void ata_tf_to_host(struct * Sleep until ATA Status register bit BSY clears, * or a timeout occurs. * - * LOCKING: None. + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. */ - -unsigned int ata_busy_sleep (struct ata_port *ap, - unsigned long tmout_pat, unsigned long tmout) +int ata_busy_sleep(struct ata_port *ap, + unsigned long tmout_pat, unsigned long tmout) { unsigned long timer_start, timeout; u8 status; @@ -2337,27 +2368,32 @@ unsigned int ata_busy_sleep (struct ata_ status = ata_busy_wait(ap, ATA_BUSY, 300); timer_start = jiffies; timeout = timer_start + tmout_pat; - while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) { + while (status != 0xff && (status & ATA_BUSY) && + time_before(jiffies, timeout)) { msleep(50); status = ata_busy_wait(ap, ATA_BUSY, 3); } - if (status & ATA_BUSY) + if (status != 0xff && (status & ATA_BUSY)) ata_port_printk(ap, KERN_WARNING, "port is slow to respond, please be patient " "(Status 0x%x)\n", status); timeout = timer_start + tmout; - while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) { + while (status != 0xff && (status & ATA_BUSY) && + time_before(jiffies, timeout)) { msleep(50); status = ata_chk_status(ap); } + if (status == 0xff) + return -ENODEV; + if (status & ATA_BUSY) { ata_port_printk(ap, KERN_ERR, "port failed to respond " "(%lu secs, Status 0x%x)\n", tmout / HZ, status); - return 1; + return -EBUSY; } return 0; @@ -2448,10 +2484,8 @@ static unsigned int ata_bus_softreset(st * the bus shows 0xFF because the odd clown forgets the D7 * pulldown resistor. */ - if (ata_check_status(ap) == 0xFF) { - ata_port_printk(ap, KERN_ERR, "SRST failed (status 0xFF)\n"); - return AC_ERR_OTHER; - } + if (ata_check_status(ap) == 0xFF) + return 0; ata_bus_post_reset(ap, devmask); @@ -2777,9 +2811,9 @@ int ata_std_softreset(struct ata_port *a } /** - * sata_std_hardreset - reset host port via SATA phy reset + * sata_port_hardreset - reset port via SATA phy reset * @ap: port to reset - * @class: resulting class of attached device + * @timing: timing parameters { interval, duratinon, timeout } in msec * * SATA phy-reset host port using DET bits of SControl register. * @@ -2789,10 +2823,8 @@ int ata_std_softreset(struct ata_port *a * RETURNS: * 0 on success, -errno otherwise. */ -int sata_std_hardreset(struct ata_port *ap, unsigned int *class) +int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing) { - struct ata_eh_context *ehc = &ap->eh_context; - const unsigned long *timing = sata_ehc_deb_timing(ehc); u32 scontrol; int rc; @@ -2805,24 +2837,24 @@ int sata_std_hardreset(struct ata_port * * and Sil3124. */ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) - return rc; + goto out; scontrol = (scontrol & 0x0f0) | 0x304; if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) - return rc; + goto out; sata_set_spd(ap); } /* issue phy wake/reset */ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) - return rc; + goto out; scontrol = (scontrol & 0x0f0) | 0x301; if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol))) - return rc; + goto out; /* Couldn't find anything in SATA I/II specs, but AHCI-1.1 * 10.4.2 says at least 1 ms. @@ -2830,7 +2862,40 @@ int sata_std_hardreset(struct ata_port * msleep(1); /* bring phy back */ - sata_phy_resume(ap, timing); + rc = sata_phy_resume(ap, timing); + out: + DPRINTK("EXIT, rc=%d\n", rc); + return rc; +} + +/** + * sata_std_hardreset - reset host port via SATA phy reset + * @ap: port to reset + * @class: resulting class of attached device + * + * SATA phy-reset host port using DET bits of SControl register, + * wait for !BSY and classify the attached device. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int sata_std_hardreset(struct ata_port *ap, unsigned int *class) +{ + const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context); + int rc; + + DPRINTK("ENTER\n"); + + /* do hardreset */ + rc = sata_port_hardreset(ap, timing); + if (rc) { + ata_port_printk(ap, KERN_ERR, + "COMRESET failed (errno=%d)\n", rc); + return rc; + } /* TODO: phy layer with polling, timeouts, etc. */ if (ata_port_offline(ap)) { @@ -3005,7 +3070,7 @@ int ata_dev_revalidate(struct ata_device memcpy(dev->id, id, sizeof(id[0]) * ATA_ID_WORDS); /* configure device according to the new ID */ - rc = ata_dev_configure(dev, 0); + rc = ata_dev_configure(dev); if (rc == 0) return 0; @@ -3014,37 +3079,55 @@ int ata_dev_revalidate(struct ata_device return rc; } -static const char * const ata_dma_blacklist [] = { - "WDC AC11000H", NULL, - "WDC AC22100H", NULL, - "WDC AC32500H", NULL, - "WDC AC33100H", NULL, - "WDC AC31600H", NULL, - "WDC AC32100H", "24.09P07", - "WDC AC23200L", "21.10N21", - "Compaq CRD-8241B", NULL, - "CRD-8400B", NULL, - "CRD-8480B", NULL, - "CRD-8482B", NULL, - "CRD-84", NULL, - "SanDisk SDP3B", NULL, - "SanDisk SDP3B-64", NULL, - "SANYO CD-ROM CRD", NULL, - "HITACHI CDR-8", NULL, - "HITACHI CDR-8335", NULL, - "HITACHI CDR-8435", NULL, - "Toshiba CD-ROM XM-6202B", NULL, - "TOSHIBA CD-ROM XM-1702BC", NULL, - "CD-532E-A", NULL, - "E-IDE CD-ROM CR-840", NULL, - "CD-ROM Drive/F5A", NULL, - "WPI CDD-820", NULL, - "SAMSUNG CD-ROM SC-148C", NULL, - "SAMSUNG CD-ROM SC", NULL, - "SanDisk SDP3B-64", NULL, - "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL, - "_NEC DV5800A", NULL, - "SAMSUNG CD-ROM SN-124", "N001" +struct ata_blacklist_entry { + const char *model_num; + const char *model_rev; + unsigned long horkage; +}; + +static const struct ata_blacklist_entry ata_device_blacklist [] = { + /* Devices with DMA related problems under Linux */ + { "WDC AC11000H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC22100H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC32500H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC33100H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC31600H", NULL, ATA_HORKAGE_NODMA }, + { "WDC AC32100H", "24.09P07", ATA_HORKAGE_NODMA }, + { "WDC AC23200L", "21.10N21", ATA_HORKAGE_NODMA }, + { "Compaq CRD-8241B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-8400B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-8480B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-8482B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-84", NULL, ATA_HORKAGE_NODMA }, + { "SanDisk SDP3B", NULL, ATA_HORKAGE_NODMA }, + { "SanDisk SDP3B-64", NULL, ATA_HORKAGE_NODMA }, + { "SANYO CD-ROM CRD", NULL, ATA_HORKAGE_NODMA }, + { "HITACHI CDR-8", NULL, ATA_HORKAGE_NODMA }, + { "HITACHI CDR-8335", NULL, ATA_HORKAGE_NODMA }, + { "HITACHI CDR-8435", NULL, ATA_HORKAGE_NODMA }, + { "Toshiba CD-ROM XM-6202B", NULL, ATA_HORKAGE_NODMA }, + { "TOSHIBA CD-ROM XM-1702BC", NULL, ATA_HORKAGE_NODMA }, + { "CD-532E-A", NULL, ATA_HORKAGE_NODMA }, + { "E-IDE CD-ROM CR-840",NULL, ATA_HORKAGE_NODMA }, + { "CD-ROM Drive/F5A", NULL, ATA_HORKAGE_NODMA }, + { "WPI CDD-820", NULL, ATA_HORKAGE_NODMA }, + { "SAMSUNG CD-ROM SC-148C", NULL, ATA_HORKAGE_NODMA }, + { "SAMSUNG CD-ROM SC", NULL, ATA_HORKAGE_NODMA }, + { "SanDisk SDP3B-64", NULL, ATA_HORKAGE_NODMA }, + { "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL,ATA_HORKAGE_NODMA }, + { "_NEC DV5800A", NULL, ATA_HORKAGE_NODMA }, + { "SAMSUNG CD-ROM SN-124","N001", ATA_HORKAGE_NODMA }, + + /* Devices we expect to fail diagnostics */ + + /* Devices where NCQ should be avoided */ + /* NCQ is slow */ + { "WDC WD740ADFD-00", NULL, ATA_HORKAGE_NONCQ }, + + /* Devices with NCQ limits */ + + /* End Marker */ + { } }; static int ata_strim(char *s, size_t len) @@ -3059,20 +3142,12 @@ static int ata_strim(char *s, size_t len return len; } -static int ata_dma_blacklisted(const struct ata_device *dev) +unsigned long ata_device_blacklisted(const struct ata_device *dev) { unsigned char model_num[40]; unsigned char model_rev[16]; unsigned int nlen, rlen; - int i; - - /* We don't support polling DMA. - * DMA blacklist those ATAPI devices with CDB-intr (and use PIO) - * if the LLDD handles only interrupts in the HSM_ST_LAST state. - */ - if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) && - (dev->flags & ATA_DFLAG_CDB_INTR)) - return 1; + const struct ata_blacklist_entry *ad = ata_device_blacklist; ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num)); @@ -3081,17 +3156,30 @@ static int ata_dma_blacklisted(const str nlen = ata_strim(model_num, sizeof(model_num)); rlen = ata_strim(model_rev, sizeof(model_rev)); - for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i += 2) { - if (!strncmp(ata_dma_blacklist[i], model_num, nlen)) { - if (ata_dma_blacklist[i+1] == NULL) - return 1; - if (!strncmp(ata_dma_blacklist[i], model_rev, rlen)) - return 1; + while (ad->model_num) { + if (!strncmp(ad->model_num, model_num, nlen)) { + if (ad->model_rev == NULL) + return ad->horkage; + if (!strncmp(ad->model_rev, model_rev, rlen)) + return ad->horkage; } + ad++; } return 0; } +static int ata_dma_blacklisted(const struct ata_device *dev) +{ + /* We don't support polling DMA. + * DMA blacklist those ATAPI devices with CDB-intr (and use PIO) + * if the LLDD handles only interrupts in the HSM_ST_LAST state. + */ + if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) && + (dev->flags & ATA_DFLAG_CDB_INTR)) + return 1; + return (ata_device_blacklisted(dev) & ATA_HORKAGE_NODMA) ? 1 : 0; +} + /** * ata_dev_xfermask - Compute supported xfermask of the given device * @dev: Device to compute xfermask for @@ -3119,6 +3207,13 @@ static void ata_dev_xfermask(struct ata_ */ if (ap->cbl == ATA_CBL_PATA40) xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA); + /* Apply drive side cable rule. Unknown or 80 pin cables reported + * host side are checked drive side as well. Cases where we know a + * 40wire cable is used safely for 80 are not checked here. + */ + if (ata_drive_40wire(dev->id) && (ap->cbl == ATA_CBL_PATA_UNK || ap->cbl == ATA_CBL_PATA80)) + xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA); + xfer_mask &= ata_pack_xfermask(dev->pio_mask, dev->mwdma_mask, dev->udma_mask); @@ -5298,13 +5393,13 @@ void ata_port_init(struct ata_port *ap, ap->pio_mask = ent->pinfo2->pio_mask; ap->mwdma_mask = ent->pinfo2->mwdma_mask; ap->udma_mask = ent->pinfo2->udma_mask; - ap->flags |= ent->pinfo2->flags; + ap->flags |= ent->pinfo2->flags | ent->_port_flags[port_no]; ap->ops = ent->pinfo2->port_ops; } else { ap->pio_mask = ent->pio_mask; ap->mwdma_mask = ent->mwdma_mask; ap->udma_mask = ent->udma_mask; - ap->flags |= ent->port_flags; + ap->flags |= ent->port_flags | ent->_port_flags[port_no]; ap->ops = ent->port_ops; } ap->hw_sata_spd_limit = UINT_MAX; @@ -6120,6 +6215,7 @@ EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_std_prereset); EXPORT_SYMBOL_GPL(ata_std_softreset); +EXPORT_SYMBOL_GPL(sata_port_hardreset); EXPORT_SYMBOL_GPL(sata_std_hardreset); EXPORT_SYMBOL_GPL(ata_std_postreset); EXPORT_SYMBOL_GPL(ata_dev_classify); @@ -6146,6 +6242,7 @@ EXPORT_SYMBOL_GPL(ata_host_suspend); EXPORT_SYMBOL_GPL(ata_host_resume); EXPORT_SYMBOL_GPL(ata_id_string); EXPORT_SYMBOL_GPL(ata_id_c_string); +EXPORT_SYMBOL_GPL(ata_device_blacklisted); EXPORT_SYMBOL_GPL(ata_scsi_simulate); EXPORT_SYMBOL_GPL(ata_pio_need_iordy); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 02b2b27..4776488 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1653,6 +1653,11 @@ static int ata_eh_revalidate_and_attach( ata_eh_done(ap, dev, ATA_EH_REVALIDATE); + /* Configuration may have changed, reconfigure + * transfer mode. + */ + ehc->i.flags |= ATA_EHI_SETMODE; + /* schedule the scsi_rescan_device() here */ queue_work(ata_aux_wq, &(ap->scsi_rescan_task)); } else if (dev->class == ATA_DEV_UNKNOWN && @@ -1661,8 +1666,11 @@ static int ata_eh_revalidate_and_attach( dev->class = ehc->classes[dev->devno]; rc = ata_dev_read_id(dev, &dev->class, 1, dev->id); - if (rc == 0) - rc = ata_dev_configure(dev, 1); + if (rc == 0) { + ehc->i.flags |= ATA_EHI_PRINTINFO; + rc = ata_dev_configure(dev); + ehc->i.flags &= ~ATA_EHI_PRINTINFO; + } if (rc) { dev->class = ATA_DEV_UNKNOWN; @@ -1672,6 +1680,9 @@ static int ata_eh_revalidate_and_attach( spin_lock_irqsave(ap->lock, flags); ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; spin_unlock_irqrestore(ap->lock, flags); + + /* new device discovered, configure transfer mode */ + ehc->i.flags |= ATA_EHI_SETMODE; } } @@ -1987,13 +1998,14 @@ static int ata_eh_recover(struct ata_por if (rc) goto dev_fail; - /* configure transfer mode if the port has been reset */ - if (ehc->i.flags & ATA_EHI_DID_RESET) { + /* configure transfer mode if necessary */ + if (ehc->i.flags & ATA_EHI_SETMODE) { rc = ata_set_mode(ap, &dev); if (rc) { down_xfermask = 1; goto dev_fail; } + ehc->i.flags &= ~ATA_EHI_SETMODE; } /* suspend devices */ diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 7af2a4b..a0b6ee1 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -807,23 +807,10 @@ static void ata_scsi_sdev_config(struct static void ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev) { - unsigned int max_sectors; + /* configure max sectors */ + blk_queue_max_sectors(sdev->request_queue, dev->max_sectors); - /* TODO: 2048 is an arbitrary number, not the - * hardware maximum. This should be increased to - * 65534 when Jens Axboe's patch for dynamically - * determining max_sectors is merged. - */ - max_sectors = ATA_MAX_SECTORS; - if (dev->flags & ATA_DFLAG_LBA48) - max_sectors = ATA_MAX_SECTORS_LBA48; - if (dev->max_sectors) - max_sectors = dev->max_sectors; - - blk_queue_max_sectors(sdev->request_queue, max_sectors); - - /* - * SATA DMA transfers must be multiples of 4 byte, so + /* SATA DMA transfers must be multiples of 4 byte, so * we need to pad ATAPI transfers using an extra sg. * Decrement max hw segments accordingly. */ @@ -3180,10 +3167,12 @@ static int ata_scsi_user_scan(struct Scs rc = -EINVAL; } - if (rc == 0) + if (rc == 0) { ata_port_schedule_eh(ap); - - spin_unlock_irqrestore(ap->lock, flags); + spin_unlock_irqrestore(ap->lock, flags); + ata_port_wait_eh(ap); + } else + spin_unlock_irqrestore(ap->lock, flags); return rc; } diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 7645f2b..37471d3 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -39,6 +39,35 @@ #include #include "libata.h" /** + * ata_irq_on - Enable interrupts on a port. + * @ap: Port on which interrupts are enabled. + * + * Enable interrupts on a legacy IDE device using MMIO or PIO, + * wait for idle, clear any pending interrupts. + * + * LOCKING: + * Inherited from caller. + */ +u8 ata_irq_on(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ap->flags & ATA_FLAG_MMIO) + writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); + else + outb(ap->ctl, ioaddr->ctl_addr); + tmp = ata_wait_idle(ap); + + ap->ops->irq_clear(ap); + + return tmp; +} + +/** * ata_tf_load_pio - send taskfile registers to host controller * @ap: Port to which output is sent * @tf: ATA taskfile register set @@ -732,7 +761,7 @@ void ata_bmdma_drive_eh(struct ata_port qc->tf.protocol == ATA_PROT_ATAPI_DMA)) { u8 host_stat; - host_stat = ata_bmdma_status(ap); + host_stat = ap->ops->bmdma_status(ap); ata_ehi_push_desc(&ehc->i, "BMDMA stat 0x%x", host_stat); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 0ed263b..078c1a5 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -43,6 +43,7 @@ extern struct workqueue_struct *ata_aux_ extern int atapi_enabled; extern int atapi_dmadir; extern int libata_fua; +extern int noacpi; extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc); extern void ata_dev_disable(struct ata_device *dev); @@ -54,7 +55,7 @@ extern unsigned int ata_do_simple_cmd(st extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, int post_reset, u16 *id); extern int ata_dev_revalidate(struct ata_device *dev, int post_reset); -extern int ata_dev_configure(struct ata_device *dev, int print_info); +extern int ata_dev_configure(struct ata_device *dev); extern int sata_down_spd_limit(struct ata_port *ap); extern int sata_set_spd_needed(struct ata_port *ap); extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0); @@ -75,6 +76,20 @@ extern void ata_port_init(struct ata_por extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port); +/* libata-acpi.c */ +#ifdef CONFIG_SATA_ACPI +extern int ata_acpi_exec_tfs(struct ata_port *ap); +extern int ata_acpi_push_id(struct ata_port *ap, unsigned int ix); +#else +static inline int ata_acpi_exec_tfs(struct ata_port *ap) +{ + return 0; +} +static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) +{ + return 0; +} +#endif /* libata-scsi.c */ extern struct scsi_transport_template ata_scsi_transport_template; @@ -120,4 +135,7 @@ extern void ata_scsi_error(struct Scsi_H extern void ata_port_wait_eh(struct ata_port *ap); extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); +/* libata-sff.c */ +extern u8 ata_irq_on(struct ata_port *ap); + #endif /* __LIBATA_H__ */ diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 1d695df..9860178 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -78,7 +78,7 @@ static int ali_c2_cable_detect(struct at implement the detect logic */ if (ali_cable_override(pdev)) - return ATA_CBL_PATA80; + return ATA_CBL_PATA40_SHORT; /* Host view cable detect 0x4A bit 0 primary bit 1 secondary Bit set for 40 pin */ diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c new file mode 100644 index 0000000..1ea6407 --- /dev/null +++ b/drivers/ata/pata_marvell.c @@ -0,0 +1,220 @@ +/* + * Marvell PATA driver. + * + * For the moment we drive the PATA port in legacy mode. That + * isn't making full use of the device functionality but it is + * easy to get working. + * + * (c) 2006 Red Hat + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_marvell" +#define DRV_VERSION "0.0.5u" + +/** + * marvell_pre_reset - check for 40/80 pin + * @ap: Port + * + * Perform the PATA port setup we need. + */ + +static int marvell_pre_reset(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u32 devices; + void __iomem *barp; + int i; + + /* Check if our port is enabled */ + + barp = pci_iomap(pdev, 5, 0x10); + if (barp == NULL) + return -ENOMEM; + printk("BAR5:"); + for(i = 0; i <= 0x0F; i++) + printk("%02X:%02X ", i, readb(barp + i)); + printk("\n"); + + devices = readl(barp + 0x0C); + pci_iounmap(pdev, barp); + + if ((pdev->device == 0x6145) && (ap->port_no == 0) && + (!(devices & 0x10))) /* PATA enable ? */ + return -ENOENT; + + /* Cable type */ + switch(ap->port_no) + { + case 0: + /* Might be backward, docs unclear */ + if (inb(ap->ioaddr.bmdma_addr + 1) & 1) + ap->cbl = ATA_CBL_PATA80; + else + ap->cbl = ATA_CBL_PATA40; + + case 1: /* Legacy SATA port */ + ap->cbl = ATA_CBL_SATA; + break; + } + return ata_std_prereset(ap); +} + +/** + * marvell_error_handler - Setup and error handler + * @ap: Port to handle + * + * LOCKING: + * None (inherited from caller). + */ + +static void marvell_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, marvell_pre_reset, ata_std_softreset, + NULL, ata_std_postreset); +} + +/* No PIO or DMA methods needed for this device */ + +static struct scsi_host_template marvell_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .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, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + /* Use standard CHS mapping rules */ + .bios_param = ata_std_bios_param, +}; + +static const struct ata_port_operations marvell_ops = { + .port_disable = ata_port_disable, + + /* Task file is PCI ATA format, use helpers */ + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = marvell_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + /* BMDMA handling is PCI ATA format, use helpers */ + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_pio_data_xfer, + + /* Timeout handling */ + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + /* Generic PATA PCI ATA helpers */ + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = ata_host_stop, +}; + + +/** + * marvell_init_one - Register Marvell ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in marvell_pci_tbl matching with @pdev + * + * Called from kernel PCI layer. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *id) +{ + static struct ata_port_info info = { + .sht = &marvell_sht, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x3f, + + .port_ops = &marvell_ops, + }; + static struct ata_port_info info_sata = { + .sht = &marvell_sht, + /* Slave possible as its magically mapped not real */ + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + + .port_ops = &marvell_ops, + }; + struct ata_port_info *port_info[2] = { &info, &info_sata }; + int n_port = 2; + + if (pdev->device == 0x6101) + n_port = 1; + + return ata_pci_init_one(pdev, port_info, n_port); +} + +static const struct pci_device_id marvell_pci_tbl[] = { + { PCI_DEVICE(0x11AB, 0x6101), }, + { PCI_DEVICE(0x11AB, 0x6145), }, + { } /* terminate list */ +}; + +static struct pci_driver marvell_pci_driver = { + .name = DRV_NAME, + .id_table = marvell_pci_tbl, + .probe = marvell_init_one, + .remove = ata_pci_remove_one, +}; + +static int __init marvell_init(void) +{ + return pci_register_driver(&marvell_pci_driver); +} + +static void __exit marvell_exit(void) +{ + pci_unregister_driver(&marvell_pci_driver); +} + +module_init(marvell_init); +module_exit(marvell_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("SCSI low-level driver for Marvell ATA in legacy mode"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, marvell_pci_tbl); +MODULE_VERSION(DRV_VERSION); + diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index d894d99..56e0287 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -853,7 +853,7 @@ static void __devexit pdc2027x_remove_on */ static int __init pdc2027x_init(void) { - return pci_module_init(&pdc2027x_pci_driver); + return pci_register_driver(&pdc2027x_pci_driver); } /** diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 5ba9eb2..450c6a1 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -21,7 +21,7 @@ #include #include #define DRV_NAME "pata_pdc202xx_old" -#define DRV_VERSION "0.2.1" +#define DRV_VERSION "0.2.2" /** * pdc2024x_pre_reset - probe begin @@ -63,7 +63,7 @@ static void pdc2026x_error_handler(struc } /** - * pdc_configure_piomode - set chip PIO timing + * pdc202xx_configure_piomode - set chip PIO timing * @ap: ATA interface * @adev: ATA device * @pio: PIO mode @@ -73,7 +73,7 @@ static void pdc2026x_error_handler(struc * versa */ -static void pdc_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio) +static void pdc202xx_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); int port = 0x60 + 4 * ap->port_no + 2 * adev->devno; @@ -98,7 +98,7 @@ static void pdc_configure_piomode(struct } /** - * pdc_set_piomode - set initial PIO mode data + * pdc202xx_set_piomode - set initial PIO mode data * @ap: ATA interface * @adev: ATA device * @@ -106,13 +106,13 @@ static void pdc_configure_piomode(struct * but we want to set the PIO timing by default. */ -static void pdc_set_piomode(struct ata_port *ap, struct ata_device *adev) +static void pdc202xx_set_piomode(struct ata_port *ap, struct ata_device *adev) { - pdc_configure_piomode(ap, adev, adev->pio_mode - XFER_PIO_0); + pdc202xx_configure_piomode(ap, adev, adev->pio_mode - XFER_PIO_0); } /** - * pdc_configure_dmamode - set DMA mode in chip + * pdc202xx_configure_dmamode - set DMA mode in chip * @ap: ATA interface * @adev: ATA device * @@ -120,7 +120,7 @@ static void pdc_set_piomode(struct ata_p * to occur. */ -static void pdc_set_dmamode(struct ata_port *ap, struct ata_device *adev) +static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); int port = 0x60 + 4 * ap->port_no + 2 * adev->devno; @@ -184,7 +184,7 @@ static void pdc2026x_bmdma_start(struct /* The DMA clocks may have been trashed by a reset. FIXME: make conditional and move to qc_issue ? */ - pdc_set_dmamode(ap, qc->dev); + pdc202xx_set_dmamode(ap, qc->dev); /* Cases the state machine will not complete correctly without help */ if ((tf->flags & ATA_TFLAG_LBA48) || tf->protocol == ATA_PROT_ATAPI_DMA) @@ -254,7 +254,7 @@ static void pdc2026x_dev_config(struct a adev->max_sectors = 256; } -static struct scsi_host_template pdc_sht = { +static struct scsi_host_template pdc202xx_sht = { .module = THIS_MODULE, .name = DRV_NAME, .ioctl = ata_scsi_ioctl, @@ -274,8 +274,8 @@ static struct scsi_host_template pdc_sht static struct ata_port_operations pdc2024x_port_ops = { .port_disable = ata_port_disable, - .set_piomode = pdc_set_piomode, - .set_dmamode = pdc_set_dmamode, + .set_piomode = pdc202xx_set_piomode, + .set_dmamode = pdc202xx_set_dmamode, .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -307,8 +307,8 @@ static struct ata_port_operations pdc202 static struct ata_port_operations pdc2026x_port_ops = { .port_disable = ata_port_disable, - .set_piomode = pdc_set_piomode, - .set_dmamode = pdc_set_dmamode, + .set_piomode = pdc202xx_set_piomode, + .set_dmamode = pdc202xx_set_dmamode, .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -339,11 +339,11 @@ static struct ata_port_operations pdc202 .host_stop = ata_host_stop }; -static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id) +static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id) { static struct ata_port_info info[3] = { { - .sht = &pdc_sht, + .sht = &pdc202xx_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -351,7 +351,7 @@ static int pdc_init_one(struct pci_dev * .port_ops = &pdc2024x_port_ops }, { - .sht = &pdc_sht, + .sht = &pdc202xx_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -359,7 +359,7 @@ static int pdc_init_one(struct pci_dev * .port_ops = &pdc2026x_port_ops }, { - .sht = &pdc_sht, + .sht = &pdc202xx_sht, .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, .pio_mask = 0x1f, .mwdma_mask = 0x07, @@ -385,7 +385,7 @@ static int pdc_init_one(struct pci_dev * return ata_pci_init_one(dev, port_info, 2); } -static const struct pci_device_id pdc[] = { +static const struct pci_device_id pdc202xx[] = { { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 }, { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 }, { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1 }, @@ -395,28 +395,28 @@ static const struct pci_device_id pdc[] { }, }; -static struct pci_driver pdc_pci_driver = { +static struct pci_driver pdc202xx_pci_driver = { .name = DRV_NAME, - .id_table = pdc, - .probe = pdc_init_one, + .id_table = pdc202xx, + .probe = pdc202xx_init_one, .remove = ata_pci_remove_one }; -static int __init pdc_init(void) +static int __init pdc202xx_init(void) { - return pci_register_driver(&pdc_pci_driver); + return pci_register_driver(&pdc202xx_pci_driver); } -static void __exit pdc_exit(void) +static void __exit pdc202xx_exit(void) { - pci_unregister_driver(&pdc_pci_driver); + pci_unregister_driver(&pdc202xx_pci_driver); } MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for Promise 2024x and 20262-20267"); MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(pci, pdc); +MODULE_DEVICE_TABLE(pci, pdc202xx); MODULE_VERSION(DRV_VERSION); -module_init(pdc_init); -module_exit(pdc_exit); +module_init(pdc202xx_init); +module_exit(pdc202xx_exit); diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c new file mode 100644 index 0000000..63d6687 --- /dev/null +++ b/drivers/ata/pata_platform.c @@ -0,0 +1,295 @@ +/* + * Generic platform device PATA driver + * + * Copyright (C) 2006 Paul Mundt + * + * Based on pata_pcmcia: + * + * Copyright 2005-2006 Red Hat Inc , all rights reserved. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_platform" +#define DRV_VERSION "0.1.2" + +static int pio_mask = 1; + +/* + * Provide our own set_mode() as we don't want to change anything that has + * already been configured.. + */ +static void pata_platform_set_mode(struct ata_port *ap) +{ + int i; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + + if (ata_dev_enabled(dev)) { + /* We don't really care */ + dev->pio_mode = dev->xfer_mode = XFER_PIO_0; + dev->xfer_shift = ATA_SHIFT_PIO; + dev->flags |= ATA_DFLAG_PIO; + } + } +} + +static void pata_platform_host_stop(struct ata_host *host) +{ + int i; + + /* + * Unmap the bases for MMIO + */ + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + if (ap->flags & ATA_FLAG_MMIO) { + iounmap((void __iomem *)ap->ioaddr.ctl_addr); + iounmap((void __iomem *)ap->ioaddr.cmd_addr); + } + } +} + +static struct scsi_host_template pata_platform_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .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, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations pata_platform_port_ops = { + .set_mode = pata_platform_set_mode, + + .port_disable = ata_port_disable, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = ata_pio_data_xfer_noirq, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = pata_platform_host_stop +}; + +static void pata_platform_setup_port(struct ata_ioports *ioaddr, + struct pata_platform_info *info) +{ + unsigned int shift = 0; + + /* Fixup the port shift for platforms that need it */ + if (info && info->ioport_shift) + shift = info->ioport_shift; + + ioaddr->data_addr = ioaddr->cmd_addr + (ATA_REG_DATA << shift); + ioaddr->error_addr = ioaddr->cmd_addr + (ATA_REG_ERR << shift); + ioaddr->feature_addr = ioaddr->cmd_addr + (ATA_REG_FEATURE << shift); + ioaddr->nsect_addr = ioaddr->cmd_addr + (ATA_REG_NSECT << shift); + ioaddr->lbal_addr = ioaddr->cmd_addr + (ATA_REG_LBAL << shift); + ioaddr->lbam_addr = ioaddr->cmd_addr + (ATA_REG_LBAM << shift); + ioaddr->lbah_addr = ioaddr->cmd_addr + (ATA_REG_LBAH << shift); + ioaddr->device_addr = ioaddr->cmd_addr + (ATA_REG_DEVICE << shift); + ioaddr->status_addr = ioaddr->cmd_addr + (ATA_REG_STATUS << shift); + ioaddr->command_addr = ioaddr->cmd_addr + (ATA_REG_CMD << shift); +} + +/** + * pata_platform_probe - attach a platform interface + * @pdev: platform device + * + * Register a platform bus IDE interface. Such interfaces are PIO and we + * assume do not support IRQ sharing. + * + * Platform devices are expected to contain 3 resources per port: + * + * - I/O Base (IORESOURCE_IO or IORESOURCE_MEM) + * - CTL Base (IORESOURCE_IO or IORESOURCE_MEM) + * - IRQ (IORESOURCE_IRQ) + * + * If the base resources are both mem types, the ioremap() is handled + * here. For IORESOURCE_IO, it's assumed that there's no remapping + * necessary. + */ +static int __devinit pata_platform_probe(struct platform_device *pdev) +{ + struct resource *io_res, *ctl_res; + struct ata_probe_ent ae; + unsigned int mmio; + int ret; + + /* + * Simple resource validation .. + */ + if (unlikely(pdev->num_resources != 3)) { + dev_err(&pdev->dev, "invalid number of resources\n"); + return -EINVAL; + } + + /* + * Get the I/O base first + */ + io_res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (io_res == NULL) { + io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(io_res == NULL)) + return -EINVAL; + } + + /* + * Then the CTL base + */ + ctl_res = platform_get_resource(pdev, IORESOURCE_IO, 1); + if (ctl_res == NULL) { + ctl_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (unlikely(ctl_res == NULL)) + return -EINVAL; + } + + /* + * Check for MMIO + */ + mmio = (( io_res->flags == IORESOURCE_MEM) && + (ctl_res->flags == IORESOURCE_MEM)); + + /* + * Now that that's out of the way, wire up the port.. + */ + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &pdev->dev; + ae.port_ops = &pata_platform_port_ops; + ae.sht = &pata_platform_sht; + ae.n_ports = 1; + ae.pio_mask = pio_mask; + ae.irq = platform_get_irq(pdev, 0); + ae.irq_flags = 0; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; + + /* + * Handle the MMIO case + */ + if (mmio) { + ae.port_flags |= ATA_FLAG_MMIO; + + ae.port[0].cmd_addr = (unsigned long)ioremap(io_res->start, + io_res->end - io_res->start + 1); + if (unlikely(!ae.port[0].cmd_addr)) { + dev_err(&pdev->dev, "failed to remap IO base\n"); + return -ENXIO; + } + + ae.port[0].ctl_addr = (unsigned long)ioremap(ctl_res->start, + ctl_res->end - ctl_res->start + 1); + if (unlikely(!ae.port[0].ctl_addr)) { + dev_err(&pdev->dev, "failed to remap CTL base\n"); + ret = -ENXIO; + goto bad_remap; + } + } else { + ae.port[0].cmd_addr = io_res->start; + ae.port[0].ctl_addr = ctl_res->start; + } + + ae.port[0].altstatus_addr = ae.port[0].ctl_addr; + + pata_platform_setup_port(&ae.port[0], pdev->dev.platform_data); + + if (unlikely(ata_device_add(&ae) == 0)) { + ret = -ENODEV; + goto add_failed; + } + + return 0; + +add_failed: + if (ae.port[0].ctl_addr && mmio) + iounmap((void __iomem *)ae.port[0].ctl_addr); +bad_remap: + if (ae.port[0].cmd_addr && mmio) + iounmap((void __iomem *)ae.port[0].cmd_addr); + + return ret; +} + +/** + * pata_platform_remove - unplug a platform interface + * @pdev: platform device + * + * A platform bus ATA device has been unplugged. Perform the needed + * cleanup. Also called on module unload for any active devices. + */ +static int __devexit pata_platform_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ata_host *host = dev_get_drvdata(dev); + + ata_host_remove(host); + dev_set_drvdata(dev, NULL); + + return 0; +} + +static struct platform_driver pata_platform_driver = { + .probe = pata_platform_probe, + .remove = __devexit_p(pata_platform_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init pata_platform_init(void) +{ + return platform_driver_register(&pata_platform_driver); +} + +static void __exit pata_platform_exit(void) +{ + platform_driver_unregister(&pata_platform_driver); +} +module_init(pata_platform_init); +module_exit(pata_platform_exit); + +module_param(pio_mask, int, 0); + +MODULE_AUTHOR("Paul Mundt"); +MODULE_DESCRIPTION("low-level driver for platform device ATA"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c new file mode 100644 index 0000000..48941d0 --- /dev/null +++ b/drivers/ata/pata_winbond.c @@ -0,0 +1,306 @@ +/* + * pata_winbond.c - Winbond VLB ATA controllers + * (C) 2006 Red Hat + * + * Support for the Winbond 83759A when operating in advanced mode. + * Multichip mode is not currently supported. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_winbond" +#define DRV_VERSION "0.0.1" + +#define NR_HOST 4 /* Two winbond controllers, two channels each */ + +struct winbond_data { + unsigned long config; + struct platform_device *platform_dev; +}; + +static struct ata_host *winbond_host[NR_HOST]; +static struct winbond_data winbond_data[NR_HOST]; +static int nr_winbond_host; + +#ifdef MODULE +static int probe_winbond = 1; +#else +static int probe_winbond; +#endif + +static spinlock_t winbond_lock = SPIN_LOCK_UNLOCKED; + +static void winbond_writecfg(unsigned long port, u8 reg, u8 val) +{ + unsigned long flags; + spin_lock_irqsave(&winbond_lock, flags); + outb(reg, port + 0x01); + outb(val, port + 0x02); + spin_unlock_irqrestore(&winbond_lock, flags); +} + +static u8 winbond_readcfg(unsigned long port, u8 reg) +{ + u8 val; + + unsigned long flags; + spin_lock_irqsave(&winbond_lock, flags); + outb(reg, port + 0x01); + val = inb(port + 0x02); + spin_unlock_irqrestore(&winbond_lock, flags); + + return val; +} + +static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + struct ata_timing t; + struct winbond_data *winbond = ap->host->private_data; + int active, recovery; + u8 reg; + int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2); + + reg = winbond_readcfg(winbond->config, 0x81); + + /* Get the timing data in cycles */ + if (reg & 0x40) /* Fast VLB bus, assume 50MHz */ + ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); + else + ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); + + active = (FIT(t.active, 3, 17) - 1) & 0x0F; + recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F; + timing = (active << 4) | recovery; + winbond_writecfg(winbond->config, timing, reg); + + /* Load the setup timing */ + + reg = 0x35; + if (adev->class != ATA_DEV_ATA) + reg |= 0x08; /* FIFO off */ + if (!ata_pio_need_iordy(adev)) + reg |= 0x02; /* IORDY off */ + reg |= (FIT(t.setup, 0, 3) << 6); + winbond_writecfg(winbond->config, timing + 1, reg); +} + + +static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) +{ + struct ata_port *ap = adev->ap; + int slop = buflen & 3; + + if (ata_id_has_dword_io(adev->id)) { + if (write_data) + outsl(ap->ioaddr.data_addr, buf, buflen >> 2); + else + insl(ap->ioaddr.data_addr, buf, buflen >> 2); + + if (unlikely(slop)) { + u32 pad; + if (write_data) { + memcpy(&pad, buf + buflen - slop, slop); + outl(le32_to_cpu(pad), ap->ioaddr.data_addr); + } else { + pad = cpu_to_le16(inl(ap->ioaddr.data_addr)); + memcpy(buf + buflen - slop, &pad, slop); + } + } + } else + ata_pio_data_xfer(adev, buf, buflen, write_data); +} + +static struct scsi_host_template winbond_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .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, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations winbond_port_ops = { + .port_disable = ata_port_disable, + .set_piomode = winbond_set_piomode, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = winbond_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = ata_host_stop +}; + +/** + * winbond_init_one - attach a winbond interface + * @type: Type to display + * @io: I/O port start + * @irq: interrupt line + * @fast: True if on a > 33Mhz VLB + * + * Register a VLB bus IDE interface. Such interfaces are PIO and we + * assume do not support IRQ sharing. + */ + +static __init int winbond_init_one(unsigned long port) +{ + struct ata_probe_ent ae; + struct platform_device *pdev; + int ret; + u8 reg; + int i; + + reg = winbond_readcfg(port, 0x81); + reg |= 0x80; /* jumpered mode off */ + winbond_writecfg(port, 0x81, reg); + reg = winbond_readcfg(port, 0x83); + reg |= 0xF0; /* local control */ + winbond_writecfg(port, 0x83, reg); + reg = winbond_readcfg(port, 0x85); + reg |= 0xF0; /* programmable timing */ + winbond_writecfg(port, 0x85, reg); + + reg = winbond_readcfg(port, 0x81); + + if (!(reg & 0x03)) /* Disabled */ + return 0; + + for (i = 0; i < 2 ; i ++) { + + if (reg & (1 << i)) { + /* + * Fill in a probe structure first of all + */ + + pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0); + if (pdev == NULL) + return -ENOMEM; + + memset(&ae, 0, sizeof(struct ata_probe_ent)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &pdev->dev; + + ae.port_ops = &winbond_port_ops; + ae.pio_mask = 0x1F; + + ae.sht = &winbond_sht; + + ae.n_ports = 1; + ae.irq = 14 + i; + ae.irq_flags = 0; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; + ae.port[0].cmd_addr = 0x1F0 - (0x80 * i); + ae.port[0].altstatus_addr = ae.port[0].cmd_addr + 0x0206; + ae.port[0].ctl_addr = ae.port[0].altstatus_addr; + ata_std_ports(&ae.port[0]); + /* + * Hook in a private data structure per channel + */ + ae.private_data = &winbond_data[nr_winbond_host]; + winbond_data[nr_winbond_host].config = port; + winbond_data[nr_winbond_host].platform_dev = pdev; + + ret = ata_device_add(&ae); + if (ret == 0) { + platform_device_unregister(pdev); + return -ENODEV; + } + winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev); + } + } + + return 0; +} + +/** + * winbond_init - attach winbond interfaces + * + * Attach winbond IDE interfaces by scanning the ports it may occupy. + */ + +static __init int winbond_init(void) +{ + static const unsigned long config[2] = { 0x130, 0x1B0 }; + + int ct = 0; + int i; + + if (probe_winbond == 0) + return -ENODEV; + + /* + * Check both base addresses + */ + + for (i = 0; i < 2; i++) { + if (probe_winbond & (1< @@ -40,10 +45,13 @@ #include #include #include #include +#include #include #define DRV_NAME "sata_nv" -#define DRV_VERSION "2.0" +#define DRV_VERSION "3.1" + +#define NV_ADMA_DMA_BOUNDARY 0xffffffffUL enum { NV_PORTS = 2, @@ -78,8 +86,137 @@ enum { // For PCI config register 20 NV_MCP_SATA_CFG_20 = 0x50, NV_MCP_SATA_CFG_20_SATA_SPACE_EN = 0x04, + NV_MCP_SATA_CFG_20_PORT0_EN = (1 << 17), + NV_MCP_SATA_CFG_20_PORT1_EN = (1 << 16), + NV_MCP_SATA_CFG_20_PORT0_PWB_EN = (1 << 14), + NV_MCP_SATA_CFG_20_PORT1_PWB_EN = (1 << 12), + + NV_ADMA_MAX_CPBS = 32, + NV_ADMA_CPB_SZ = 128, + NV_ADMA_APRD_SZ = 16, + NV_ADMA_SGTBL_LEN = (1024 - NV_ADMA_CPB_SZ) / + NV_ADMA_APRD_SZ, + NV_ADMA_SGTBL_TOTAL_LEN = NV_ADMA_SGTBL_LEN + 5, + NV_ADMA_SGTBL_SZ = NV_ADMA_SGTBL_LEN * NV_ADMA_APRD_SZ, + NV_ADMA_PORT_PRIV_DMA_SZ = NV_ADMA_MAX_CPBS * + (NV_ADMA_CPB_SZ + NV_ADMA_SGTBL_SZ), + + /* BAR5 offset to ADMA general registers */ + NV_ADMA_GEN = 0x400, + NV_ADMA_GEN_CTL = 0x00, + NV_ADMA_NOTIFIER_CLEAR = 0x30, + + /* BAR5 offset to ADMA ports */ + NV_ADMA_PORT = 0x480, + + /* size of ADMA port register space */ + NV_ADMA_PORT_SIZE = 0x100, + + /* ADMA port registers */ + NV_ADMA_CTL = 0x40, + NV_ADMA_CPB_COUNT = 0x42, + NV_ADMA_NEXT_CPB_IDX = 0x43, + NV_ADMA_STAT = 0x44, + NV_ADMA_CPB_BASE_LOW = 0x48, + NV_ADMA_CPB_BASE_HIGH = 0x4C, + NV_ADMA_APPEND = 0x50, + NV_ADMA_NOTIFIER = 0x68, + NV_ADMA_NOTIFIER_ERROR = 0x6C, + + /* NV_ADMA_CTL register bits */ + NV_ADMA_CTL_HOTPLUG_IEN = (1 << 0), + NV_ADMA_CTL_CHANNEL_RESET = (1 << 5), + NV_ADMA_CTL_GO = (1 << 7), + NV_ADMA_CTL_AIEN = (1 << 8), + NV_ADMA_CTL_READ_NON_COHERENT = (1 << 11), + NV_ADMA_CTL_WRITE_NON_COHERENT = (1 << 12), + + /* CPB response flag bits */ + NV_CPB_RESP_DONE = (1 << 0), + NV_CPB_RESP_ATA_ERR = (1 << 3), + NV_CPB_RESP_CMD_ERR = (1 << 4), + NV_CPB_RESP_CPB_ERR = (1 << 7), + + /* CPB control flag bits */ + NV_CPB_CTL_CPB_VALID = (1 << 0), + NV_CPB_CTL_QUEUE = (1 << 1), + NV_CPB_CTL_APRD_VALID = (1 << 2), + NV_CPB_CTL_IEN = (1 << 3), + NV_CPB_CTL_FPDMA = (1 << 4), + + /* APRD flags */ + NV_APRD_WRITE = (1 << 1), + NV_APRD_END = (1 << 2), + NV_APRD_CONT = (1 << 3), + + /* NV_ADMA_STAT flags */ + NV_ADMA_STAT_TIMEOUT = (1 << 0), + NV_ADMA_STAT_HOTUNPLUG = (1 << 1), + NV_ADMA_STAT_HOTPLUG = (1 << 2), + NV_ADMA_STAT_CPBERR = (1 << 4), + NV_ADMA_STAT_SERROR = (1 << 5), + NV_ADMA_STAT_CMD_COMPLETE = (1 << 6), + NV_ADMA_STAT_IDLE = (1 << 8), + NV_ADMA_STAT_LEGACY = (1 << 9), + NV_ADMA_STAT_STOPPED = (1 << 10), + NV_ADMA_STAT_DONE = (1 << 12), + NV_ADMA_STAT_ERR = NV_ADMA_STAT_CPBERR | + NV_ADMA_STAT_TIMEOUT, + + /* port flags */ + NV_ADMA_PORT_REGISTER_MODE = (1 << 0), + +}; + +/* ADMA Physical Region Descriptor - one SG segment */ +struct nv_adma_prd { + __le64 addr; + __le32 len; + u8 flags; + u8 packet_len; + __le16 reserved; +}; + +enum nv_adma_regbits { + CMDEND = (1 << 15), /* end of command list */ + WNB = (1 << 14), /* wait-not-BSY */ + IGN = (1 << 13), /* ignore this entry */ + CS1n = (1 << (4 + 8)), /* std. PATA signals follow... */ + DA2 = (1 << (2 + 8)), + DA1 = (1 << (1 + 8)), + DA0 = (1 << (0 + 8)), +}; + +/* ADMA Command Parameter Block + The first 5 SG segments are stored inside the Command Parameter Block itself. + If there are more than 5 segments the remainder are stored in a separate + memory area indicated by next_aprd. */ +struct nv_adma_cpb { + u8 resp_flags; /* 0 */ + u8 reserved1; /* 1 */ + u8 ctl_flags; /* 2 */ + /* len is length of taskfile in 64 bit words */ + u8 len; /* 3 */ + u8 tag; /* 4 */ + u8 next_cpb_idx; /* 5 */ + __le16 reserved2; /* 6-7 */ + __le16 tf[12]; /* 8-31 */ + struct nv_adma_prd aprd[5]; /* 32-111 */ + __le64 next_aprd; /* 112-119 */ + __le64 reserved3; /* 120-127 */ }; + +struct nv_adma_port_priv { + struct nv_adma_cpb *cpb; + dma_addr_t cpb_dma; + struct nv_adma_prd *aprd; + dma_addr_t aprd_dma; + u8 flags; +}; + +#define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT))))) + static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static void nv_ck804_host_stop(struct ata_host *host); static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance); @@ -93,13 +230,27 @@ static void nv_nf2_thaw(struct ata_port static void nv_ck804_freeze(struct ata_port *ap); static void nv_ck804_thaw(struct ata_port *ap); static void nv_error_handler(struct ata_port *ap); +static int nv_adma_slave_config(struct scsi_device *sdev); +static void nv_adma_qc_prep(struct ata_queued_cmd *qc); +static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc); +static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance); +static void nv_adma_irq_clear(struct ata_port *ap); +static int nv_adma_port_start(struct ata_port *ap); +static void nv_adma_port_stop(struct ata_port *ap); +static void nv_adma_error_handler(struct ata_port *ap); +static void nv_adma_host_stop(struct ata_host *host); +static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc); +static void nv_adma_bmdma_start(struct ata_queued_cmd *qc); +static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc); +static u8 nv_adma_bmdma_status(struct ata_port *ap); enum nv_host_type { GENERIC, NFORCE2, NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */ - CK804 + CK804, + ADMA }; static const struct pci_device_id nv_pci_tbl[] = { @@ -160,6 +311,25 @@ static struct scsi_host_template nv_sht .bios_param = ata_std_bios_param, }; +static struct scsi_host_template nv_adma_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = NV_ADMA_MAX_CPBS, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = NV_ADMA_DMA_BOUNDARY, + .slave_configure = nv_adma_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + static const struct ata_port_operations nv_generic_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, @@ -241,11 +411,39 @@ static const struct ata_port_operations .host_stop = nv_ck804_host_stop, }; +static const struct ata_port_operations nv_adma_ops = { + .port_disable = ata_port_disable, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .exec_command = ata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, + .bmdma_setup = nv_adma_bmdma_setup, + .bmdma_start = nv_adma_bmdma_start, + .bmdma_stop = nv_adma_bmdma_stop, + .bmdma_status = nv_adma_bmdma_status, + .qc_prep = nv_adma_qc_prep, + .qc_issue = nv_adma_qc_issue, + .freeze = nv_ck804_freeze, + .thaw = nv_ck804_thaw, + .error_handler = nv_adma_error_handler, + .post_internal_cmd = nv_adma_bmdma_stop, + .data_xfer = ata_mmio_data_xfer, + .irq_handler = nv_adma_interrupt, + .irq_clear = nv_adma_irq_clear, + .scr_read = nv_scr_read, + .scr_write = nv_scr_write, + .port_start = nv_adma_port_start, + .port_stop = nv_adma_port_stop, + .host_stop = nv_adma_host_stop, +}; + static struct ata_port_info nv_port_info[] = { /* generic */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -254,7 +452,8 @@ static struct ata_port_info nv_port_info /* nforce2/3 */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, @@ -263,12 +462,23 @@ static struct ata_port_info nv_port_info /* ck804 */ { .sht = &nv_sht, - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_HRST_TO_RESUME, .pio_mask = NV_PIO_MASK, .mwdma_mask = NV_MWDMA_MASK, .udma_mask = NV_UDMA_MASK, .port_ops = &nv_ck804_ops, }, + /* ADMA */ + { + .sht = &nv_adma_sht, + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_NCQ, + .pio_mask = NV_PIO_MASK, + .mwdma_mask = NV_MWDMA_MASK, + .udma_mask = NV_UDMA_MASK, + .port_ops = &nv_adma_ops, + }, }; MODULE_AUTHOR("NVIDIA"); @@ -277,6 +487,614 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, nv_pci_tbl); MODULE_VERSION(DRV_VERSION); +static int adma_enabled = 1; + +static int nv_adma_slave_config(struct scsi_device *sdev) +{ + struct ata_port *ap = ata_shost_to_port(sdev->host); + u64 bounce_limit; + unsigned long segment_boundary; + unsigned short sg_tablesize; + int rc; + + rc = ata_scsi_slave_config(sdev); + + if (sdev->id >= ATA_MAX_DEVICES || sdev->channel || sdev->lun) + /* Not a proper libata device, ignore */ + return rc; + + if (ap->device[sdev->id].class == ATA_DEV_ATAPI) { + /* + * NVIDIA reports that ADMA mode does not support ATAPI commands. + * Therefore ATAPI commands are sent through the legacy interface. + * However, the legacy interface only supports 32-bit DMA. + * Restrict DMA parameters as required by the legacy interface + * when an ATAPI device is connected. + */ + bounce_limit = ATA_DMA_MASK; + segment_boundary = ATA_DMA_BOUNDARY; + /* Subtract 1 since an extra entry may be needed for padding, see + libata-scsi.c */ + sg_tablesize = LIBATA_MAX_PRD - 1; + } + else { + bounce_limit = *ap->dev->dma_mask; + segment_boundary = NV_ADMA_DMA_BOUNDARY; + sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN; + } + + blk_queue_bounce_limit(sdev->request_queue, bounce_limit); + blk_queue_segment_boundary(sdev->request_queue, segment_boundary); + blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize); + ata_port_printk(ap, KERN_INFO, + "bounce limit 0x%llX, segment boundary 0x%lX, hw segs %hu\n", + (unsigned long long)bounce_limit, segment_boundary, sg_tablesize); + return rc; +} + +static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, u16 *cpb) +{ + unsigned int idx = 0; + + cpb[idx++] = cpu_to_le16((ATA_REG_DEVICE << 8) | tf->device | WNB); + + if ((tf->flags & ATA_TFLAG_LBA48) == 0) { + cpb[idx++] = cpu_to_le16(IGN); + cpb[idx++] = cpu_to_le16(IGN); + cpb[idx++] = cpu_to_le16(IGN); + cpb[idx++] = cpu_to_le16(IGN); + cpb[idx++] = cpu_to_le16(IGN); + } + else { + cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->hob_feature); + cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->hob_nsect); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->hob_lbal); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->hob_lbam); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->hob_lbah); + } + cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->feature); + cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->nsect); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->lbal); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->lbam); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->lbah); + + cpb[idx++] = cpu_to_le16((ATA_REG_CMD << 8) | tf->command | CMDEND); + + return idx; +} + +static inline void __iomem *__nv_adma_ctl_block(void __iomem *mmio, + unsigned int port_no) +{ + mmio += NV_ADMA_PORT + port_no * NV_ADMA_PORT_SIZE; + return mmio; +} + +static inline void __iomem *nv_adma_ctl_block(struct ata_port *ap) +{ + return __nv_adma_ctl_block(ap->host->mmio_base, ap->port_no); +} + +static inline void __iomem *nv_adma_gen_block(struct ata_port *ap) +{ + return (ap->host->mmio_base + NV_ADMA_GEN); +} + +static inline void __iomem *nv_adma_notifier_clear_block(struct ata_port *ap) +{ + return (nv_adma_gen_block(ap) + NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no)); +} + +static void nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) +{ + struct nv_adma_port_priv *pp = ap->private_data; + int complete = 0, have_err = 0; + u16 flags = pp->cpb[cpb_num].resp_flags; + + VPRINTK("CPB %d, flags=0x%x\n", cpb_num, flags); + + if (flags & NV_CPB_RESP_DONE) { + VPRINTK("CPB flags done, flags=0x%x\n", flags); + complete = 1; + } + if (flags & NV_CPB_RESP_ATA_ERR) { + ata_port_printk(ap, KERN_ERR, "CPB flags ATA err, flags=0x%x\n", flags); + have_err = 1; + complete = 1; + } + if (flags & NV_CPB_RESP_CMD_ERR) { + ata_port_printk(ap, KERN_ERR, "CPB flags CMD err, flags=0x%x\n", flags); + have_err = 1; + complete = 1; + } + if (flags & NV_CPB_RESP_CPB_ERR) { + ata_port_printk(ap, KERN_ERR, "CPB flags CPB err, flags=0x%x\n", flags); + have_err = 1; + complete = 1; + } + if(complete || force_err) + { + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num); + if(likely(qc)) { + u8 ata_status = 0; + /* Only use the ATA port status for non-NCQ commands. + For NCQ commands the current status may have nothing to do with + the command just completed. */ + if(qc->tf.protocol != ATA_PROT_NCQ) + ata_status = readb(nv_adma_ctl_block(ap) + (ATA_REG_STATUS * 4)); + + if(have_err || force_err) + ata_status |= ATA_ERR; + + qc->err_mask |= ac_err_mask(ata_status); + DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num, + qc->err_mask); + ata_qc_complete(qc); + } + } +} + +static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) +{ + struct ata_host *host = dev_instance; + int i, handled = 0; + + spin_lock(&host->lock); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { + struct nv_adma_port_priv *pp = ap->private_data; + void __iomem *mmio = nv_adma_ctl_block(ap); + u16 status; + u32 gen_ctl; + int have_global_err = 0; + u32 notifier, notifier_error; + + /* if in ATA register mode, use standard ata interrupt handler */ + if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) { + struct ata_queued_cmd *qc; + VPRINTK("in ATA register mode\n"); + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) + handled += ata_host_intr(ap, qc); + else { + /* No request pending? Clear interrupt status + anyway, in case there's one pending. */ + ap->ops->check_status(ap); + handled++; + } + continue; + } + + notifier = readl(mmio + NV_ADMA_NOTIFIER); + notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); + + gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL); + + /* Seems necessary to clear notifiers even when they were 0. + Otherwise we seem to stop receiving further interrupts. + Unsure why. */ + writel(notifier | notifier_error, nv_adma_notifier_clear_block(ap)); + + if( !NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no) && !notifier && + !notifier_error) + /* Nothing to do */ + continue; + + status = readw(mmio + NV_ADMA_STAT); + + /* Clear status. Ensure the controller sees the clearing before we start + looking at any of the CPB statuses, so that any CPB completions after + this point in the handler will raise another interrupt. */ + writew(status, mmio + NV_ADMA_STAT); + readw(mmio + NV_ADMA_STAT); /* flush posted write */ + rmb(); + + /* freeze if hotplugged */ + if (unlikely(status & (NV_ADMA_STAT_HOTPLUG | NV_ADMA_STAT_HOTUNPLUG))) { + ata_port_printk(ap, KERN_NOTICE, "Hotplug event, freezing\n"); + ata_port_freeze(ap); + handled++; + continue; + } + + if (status & NV_ADMA_STAT_TIMEOUT) { + ata_port_printk(ap, KERN_ERR, "timeout, stat=0x%x\n", status); + have_global_err = 1; + } + if (status & NV_ADMA_STAT_CPBERR) { + ata_port_printk(ap, KERN_ERR, "CPB error, stat=0x%x\n", status); + have_global_err = 1; + } + if ((status & NV_ADMA_STAT_DONE) || have_global_err) { + /** Check CPBs for completed commands */ + + if(ata_tag_valid(ap->active_tag)) + /* Non-NCQ command */ + nv_adma_check_cpb(ap, ap->active_tag, have_global_err || + (notifier_error & (1 << ap->active_tag))); + else { + int pos; + u32 active = ap->sactive; + while( (pos = ffs(active)) ) { + pos--; + nv_adma_check_cpb(ap, pos, have_global_err || + (notifier_error & (1 << pos)) ); + active &= ~(1 << pos ); + } + } + } + + handled++; /* irq handled if we got here */ + } + } + + spin_unlock(&host->lock); + + return IRQ_RETVAL(handled); +} + +static void nv_adma_irq_clear(struct ata_port *ap) +{ + void __iomem *mmio = nv_adma_ctl_block(ap); + u16 status = readw(mmio + NV_ADMA_STAT); + u32 notifier = readl(mmio + NV_ADMA_NOTIFIER); + u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); + + /* clear ADMA status */ + writew(status, mmio + NV_ADMA_STAT); + writel(notifier | notifier_error, + nv_adma_notifier_clear_block(ap)); + + /** clear legacy status */ + ap->flags &= ~ATA_FLAG_MMIO; + ata_bmdma_irq_clear(ap); + ap->flags |= ATA_FLAG_MMIO; +} + +static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + + if(pp->flags & NV_ADMA_PORT_REGISTER_MODE) { + WARN_ON(1); + return; + } + + qc->ap->flags &= ~ATA_FLAG_MMIO; + ata_bmdma_setup(qc); + qc->ap->flags |= ATA_FLAG_MMIO; +} + +static void nv_adma_bmdma_start(struct ata_queued_cmd *qc) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + + if(pp->flags & NV_ADMA_PORT_REGISTER_MODE) { + WARN_ON(1); + return; + } + + qc->ap->flags &= ~ATA_FLAG_MMIO; + ata_bmdma_start(qc); + qc->ap->flags |= ATA_FLAG_MMIO; +} + +static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + + if(pp->flags & NV_ADMA_PORT_REGISTER_MODE) + return; + + qc->ap->flags &= ~ATA_FLAG_MMIO; + ata_bmdma_stop(qc); + qc->ap->flags |= ATA_FLAG_MMIO; +} + +static u8 nv_adma_bmdma_status(struct ata_port *ap) +{ + u8 status; + struct nv_adma_port_priv *pp = ap->private_data; + + WARN_ON(pp->flags & NV_ADMA_PORT_REGISTER_MODE); + + ap->flags &= ~ATA_FLAG_MMIO; + status = ata_bmdma_status(ap); + ap->flags |= ATA_FLAG_MMIO; + return status; +} + +static void nv_adma_register_mode(struct ata_port *ap) +{ + void __iomem *mmio = nv_adma_ctl_block(ap); + struct nv_adma_port_priv *pp = ap->private_data; + u16 tmp; + + if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) + return; + + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); + + pp->flags |= NV_ADMA_PORT_REGISTER_MODE; +} + +static void nv_adma_mode(struct ata_port *ap) +{ + void __iomem *mmio = nv_adma_ctl_block(ap); + struct nv_adma_port_priv *pp = ap->private_data; + u16 tmp; + + if (!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) + return; + + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp | NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); + + pp->flags &= ~NV_ADMA_PORT_REGISTER_MODE; +} + +static int nv_adma_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host->dev; + struct nv_adma_port_priv *pp; + int rc; + void *mem; + dma_addr_t mem_dma; + void __iomem *mmio = nv_adma_ctl_block(ap); + u16 tmp; + + VPRINTK("ENTER\n"); + + rc = ata_port_start(ap); + if (rc) + return rc; + + pp = kzalloc(sizeof(*pp), GFP_KERNEL); + if (!pp) { + rc = -ENOMEM; + goto err_out; + } + + mem = dma_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ, + &mem_dma, GFP_KERNEL); + + if (!mem) { + rc = -ENOMEM; + goto err_out_kfree; + } + memset(mem, 0, NV_ADMA_PORT_PRIV_DMA_SZ); + + /* + * First item in chunk of DMA memory: + * 128-byte command parameter block (CPB) + * one for each command tag + */ + pp->cpb = mem; + pp->cpb_dma = mem_dma; + + writel(mem_dma & 0xFFFFFFFF, mmio + NV_ADMA_CPB_BASE_LOW); + writel((mem_dma >> 16 ) >> 16, mmio + NV_ADMA_CPB_BASE_HIGH); + + mem += NV_ADMA_MAX_CPBS * NV_ADMA_CPB_SZ; + mem_dma += NV_ADMA_MAX_CPBS * NV_ADMA_CPB_SZ; + + /* + * Second item: block of ADMA_SGTBL_LEN s/g entries + */ + pp->aprd = mem; + pp->aprd_dma = mem_dma; + + ap->private_data = pp; + + /* clear any outstanding interrupt conditions */ + writew(0xffff, mmio + NV_ADMA_STAT); + + /* initialize port variables */ + pp->flags = NV_ADMA_PORT_REGISTER_MODE; + + /* clear CPB fetch count */ + writew(0, mmio + NV_ADMA_CPB_COUNT); + + /* clear GO for register mode */ + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL); + + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); + readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + udelay(1); + writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); + readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + + return 0; + +err_out_kfree: + kfree(pp); +err_out: + ata_port_stop(ap); + return rc; +} + +static void nv_adma_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host->dev; + struct nv_adma_port_priv *pp = ap->private_data; + void __iomem *mmio = nv_adma_ctl_block(ap); + + VPRINTK("ENTER\n"); + + writew(0, mmio + NV_ADMA_CTL); + + ap->private_data = NULL; + dma_free_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ, pp->cpb, pp->cpb_dma); + kfree(pp); + ata_port_stop(ap); +} + + +static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port) +{ + void __iomem *mmio = probe_ent->mmio_base; + struct ata_ioports *ioport = &probe_ent->port[port]; + + VPRINTK("ENTER\n"); + + mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE; + + ioport->cmd_addr = (unsigned long) mmio; + ioport->data_addr = (unsigned long) mmio + (ATA_REG_DATA * 4); + ioport->error_addr = + ioport->feature_addr = (unsigned long) mmio + (ATA_REG_ERR * 4); + ioport->nsect_addr = (unsigned long) mmio + (ATA_REG_NSECT * 4); + ioport->lbal_addr = (unsigned long) mmio + (ATA_REG_LBAL * 4); + ioport->lbam_addr = (unsigned long) mmio + (ATA_REG_LBAM * 4); + ioport->lbah_addr = (unsigned long) mmio + (ATA_REG_LBAH * 4); + ioport->device_addr = (unsigned long) mmio + (ATA_REG_DEVICE * 4); + ioport->status_addr = + ioport->command_addr = (unsigned long) mmio + (ATA_REG_STATUS * 4); + ioport->altstatus_addr = + ioport->ctl_addr = (unsigned long) mmio + 0x20; +} + +static int nv_adma_host_init(struct ata_probe_ent *probe_ent) +{ + struct pci_dev *pdev = to_pci_dev(probe_ent->dev); + unsigned int i; + u32 tmp32; + + VPRINTK("ENTER\n"); + + /* enable ADMA on the ports */ + pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32); + tmp32 |= NV_MCP_SATA_CFG_20_PORT0_EN | + NV_MCP_SATA_CFG_20_PORT0_PWB_EN | + NV_MCP_SATA_CFG_20_PORT1_EN | + NV_MCP_SATA_CFG_20_PORT1_PWB_EN; + + pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32); + + for (i = 0; i < probe_ent->n_ports; i++) + nv_adma_setup_port(probe_ent, i); + + for (i = 0; i < probe_ent->n_ports; i++) { + void __iomem *mmio = __nv_adma_ctl_block(probe_ent->mmio_base, i); + u16 tmp; + + /* enable interrupt, clear reset if not already clear */ + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL); + } + + return 0; +} + +static void nv_adma_fill_aprd(struct ata_queued_cmd *qc, + struct scatterlist *sg, + int idx, + struct nv_adma_prd *aprd) +{ + u32 flags; + + memset(aprd, 0, sizeof(struct nv_adma_prd)); + + flags = 0; + if (qc->tf.flags & ATA_TFLAG_WRITE) + flags |= NV_APRD_WRITE; + if (idx == qc->n_elem - 1) + flags |= NV_APRD_END; + else if (idx != 4) + flags |= NV_APRD_CONT; + + aprd->addr = cpu_to_le64(((u64)sg_dma_address(sg))); + aprd->len = cpu_to_le32(((u32)sg_dma_len(sg))); /* len in bytes */ + aprd->flags = cpu_to_le32(flags); +} + +static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + unsigned int idx; + struct nv_adma_prd *aprd; + struct scatterlist *sg; + + VPRINTK("ENTER\n"); + + idx = 0; + + ata_for_each_sg(sg, qc) { + aprd = (idx < 5) ? &cpb->aprd[idx] : &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (idx-5)]; + nv_adma_fill_aprd(qc, sg, idx, aprd); + idx++; + } + if (idx > 5) + cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag))); +} + +static void nv_adma_qc_prep(struct ata_queued_cmd *qc) +{ + struct nv_adma_port_priv *pp = qc->ap->private_data; + struct nv_adma_cpb *cpb = &pp->cpb[qc->tag]; + u8 ctl_flags = NV_CPB_CTL_CPB_VALID | + NV_CPB_CTL_APRD_VALID | + NV_CPB_CTL_IEN; + + VPRINTK("qc->flags = 0x%lx\n", qc->flags); + + if (!(qc->flags & ATA_QCFLAG_DMAMAP) || + qc->tf.protocol == ATA_PROT_ATAPI_DMA) { + ata_qc_prep(qc); + return; + } + + memset(cpb, 0, sizeof(struct nv_adma_cpb)); + + cpb->len = 3; + cpb->tag = qc->tag; + cpb->next_cpb_idx = 0; + + /* turn on NCQ flags for NCQ commands */ + if (qc->tf.protocol == ATA_PROT_NCQ) + ctl_flags |= NV_CPB_CTL_QUEUE | NV_CPB_CTL_FPDMA; + + nv_adma_tf_to_cpb(&qc->tf, cpb->tf); + + nv_adma_fill_sg(qc, cpb); + + /* Be paranoid and don't let the device see NV_CPB_CTL_CPB_VALID until we are + finished filling in all of the contents */ + wmb(); + cpb->ctl_flags = ctl_flags; +} + +static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc) +{ + void __iomem *mmio = nv_adma_ctl_block(qc->ap); + + VPRINTK("ENTER\n"); + + if (!(qc->flags & ATA_QCFLAG_DMAMAP) || + qc->tf.protocol == ATA_PROT_ATAPI_DMA) { + /* use ATA register mode */ + VPRINTK("no dmamap or ATAPI, using ATA register mode: 0x%lx\n", qc->flags); + nv_adma_register_mode(qc->ap); + return ata_qc_issue_prot(qc); + } else + nv_adma_mode(qc->ap); + + /* write append register, command tag in lower 8 bits + and (number of cpbs to append -1) in top 8 bits */ + wmb(); + writew(qc->tag, mmio + NV_ADMA_APPEND); + + DPRINTK("Issued tag %u\n",qc->tag); + + return 0; +} + static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; @@ -466,6 +1284,56 @@ static void nv_error_handler(struct ata_ nv_hardreset, ata_std_postreset); } +static void nv_adma_error_handler(struct ata_port *ap) +{ + struct nv_adma_port_priv *pp = ap->private_data; + if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) { + void __iomem *mmio = nv_adma_ctl_block(ap); + int i; + u16 tmp; + + u32 notifier = readl(mmio + NV_ADMA_NOTIFIER); + u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); + u32 gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL); + u32 status = readw(mmio + NV_ADMA_STAT); + + ata_port_printk(ap, KERN_ERR, "EH in ADMA mode, notifier 0x%X " + "notifier_error 0x%X gen_ctl 0x%X status 0x%X\n", + notifier, notifier_error, gen_ctl, status); + + for( i=0;icpb[i]; + if( cpb->ctl_flags || cpb->resp_flags ) + ata_port_printk(ap, KERN_ERR, + "CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n", + i, cpb->ctl_flags, cpb->resp_flags); + } + + /* Push us back into port register mode for error handling. */ + nv_adma_register_mode(ap); + + ata_port_printk(ap, KERN_ERR, "Resetting port\n"); + + /* Mark all of the CPBs as invalid to prevent them from being executed */ + for( i=0;icpb[i].ctl_flags &= ~NV_CPB_CTL_CPB_VALID; + + /* clear CPB fetch count */ + writew(0, mmio + NV_ADMA_CPB_COUNT); + + /* Reset channel */ + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); + readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + udelay(1); + writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); + readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + } + + ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, + nv_hardreset, ata_std_postreset); +} + static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; @@ -475,6 +1343,8 @@ static int nv_init_one (struct pci_dev * int rc; u32 bar; unsigned long base; + unsigned long type = ent->driver_data; + int mask_set = 0; // Make sure this is a SATA controller by counting the number of bars // (NVIDIA SATA controllers will always have six bars). Otherwise, @@ -483,7 +1353,7 @@ static int nv_init_one (struct pci_dev * if (pci_resource_start(pdev, bar) == 0) return -ENODEV; - if (!printed_version++) + if ( !printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); @@ -496,16 +1366,26 @@ static int nv_init_one (struct pci_dev * goto err_out_disable; } - rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); - if (rc) - goto err_out_regions; - rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); - if (rc) - goto err_out_regions; + if(type >= CK804 && adma_enabled) { + dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n"); + type = ADMA; + if(!pci_set_dma_mask(pdev, DMA_64BIT_MASK) && + !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) + mask_set = 1; + } + + if(!mask_set) { + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + } rc = -ENOMEM; - ppi[0] = ppi[1] = &nv_port_info[ent->driver_data]; + ppi[0] = ppi[1] = &nv_port_info[type]; probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) goto err_out_regions; @@ -522,7 +1402,7 @@ static int nv_init_one (struct pci_dev * probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET; /* enable SATA space for CK804 */ - if (ent->driver_data == CK804) { + if (type >= CK804) { u8 regval; pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val); @@ -532,6 +1412,12 @@ static int nv_init_one (struct pci_dev * pci_set_master(pdev); + if (type == ADMA) { + rc = nv_adma_host_init(probe_ent); + if (rc) + goto err_out_iounmap; + } + rc = ata_device_add(probe_ent); if (rc != NV_PORTS) goto err_out_iounmap; @@ -566,6 +1452,33 @@ static void nv_ck804_host_stop(struct at ata_pci_host_stop(host); } +static void nv_adma_host_stop(struct ata_host *host) +{ + struct pci_dev *pdev = to_pci_dev(host->dev); + int i; + u32 tmp32; + + for (i = 0; i < host->n_ports; i++) { + void __iomem *mmio = __nv_adma_ctl_block(host->mmio_base, i); + u16 tmp; + + /* disable interrupt */ + tmp = readw(mmio + NV_ADMA_CTL); + writew(tmp & ~NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL); + } + + /* disable ADMA on the ports */ + pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32); + tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN | + NV_MCP_SATA_CFG_20_PORT0_PWB_EN | + NV_MCP_SATA_CFG_20_PORT1_EN | + NV_MCP_SATA_CFG_20_PORT1_PWB_EN); + + pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32); + + nv_ck804_host_stop(host); +} + static int __init nv_init(void) { return pci_register_driver(&nv_pci_driver); @@ -578,3 +1491,5 @@ static void __exit nv_exit(void) module_init(nv_init); module_exit(nv_exit); +module_param_named(adma, adma_enabled, bool, 0444); +MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: true)"); diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 72eda51..c94cf9c 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -175,7 +175,7 @@ static const struct ata_port_info pdc_po /* board_2037x */ { .sht = &pdc_ata_sht, - .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA, + .flags = PDC_COMMON_FLAGS /* | ATA_FLAG_SATA */, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -355,23 +355,27 @@ static void pdc_reset_port(struct ata_po static void pdc_sata_phy_reset(struct ata_port *ap) { pdc_reset_port(ap); - sata_phy_reset(ap); + if (ap->flags & ATA_FLAG_SATA) + sata_phy_reset(ap); + else + pdc_pata_phy_reset(ap); } static void pdc_pata_cbl_detect(struct ata_port *ap) { u8 tmp; - void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03; + void __iomem *mmio = + (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03; tmp = readb(mmio); - + if (tmp & 0x01) { ap->cbl = ATA_CBL_PATA40; ap->udma_mask &= ATA_UDMA_MASK_40C; } else ap->cbl = ATA_CBL_PATA80; } - + static void pdc_pata_phy_reset(struct ata_port *ap) { pdc_pata_cbl_detect(ap); @@ -679,6 +683,7 @@ static int pdc_ata_init_one (struct pci_ unsigned int board_idx = (unsigned int) ent->driver_data; int pci_dev_busy = 0; int rc; + u8 tmp; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); @@ -743,6 +748,9 @@ static int pdc_ata_init_one (struct pci_ probe_ent->port[0].scr_addr = base + 0x400; probe_ent->port[1].scr_addr = base + 0x500; + probe_ent->_port_flags[0] = ATA_FLAG_SATA; + probe_ent->_port_flags[1] = ATA_FLAG_SATA; + /* notice 4-port boards */ switch (board_idx) { case board_40518: @@ -757,13 +765,29 @@ static int pdc_ata_init_one (struct pci_ probe_ent->port[2].scr_addr = base + 0x600; probe_ent->port[3].scr_addr = base + 0x700; + + probe_ent->_port_flags[2] = ATA_FLAG_SATA; + probe_ent->_port_flags[3] = ATA_FLAG_SATA; break; case board_2057x: /* Override hotplug offset for SATAII150 */ hp->hotplug_offset = PDC2_SATA_PLUG_CSR; /* Fall through */ case board_2037x: - probe_ent->n_ports = 2; + /* Some boards have also PATA port */ + tmp = readb(mmio_base + PDC_FLASH_CTL+1); + if (!(tmp & 0x80)) + { + probe_ent->n_ports = 3; + + pdc_ata_setup_port(&probe_ent->port[2], base + 0x300); + + probe_ent->_port_flags[2] = ATA_FLAG_SLAVE_POSS; + + printk(KERN_INFO DRV_NAME " PATA port found\n"); + } + else + probe_ent->n_ports = 2; break; case board_20771: probe_ent->n_ports = 2; diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index ca8d993..f844a1f 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -534,6 +534,7 @@ static void sil_thaw(struct ata_port *ap */ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) { + int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; unsigned int n, quirks = 0; unsigned char model_num[41]; @@ -549,16 +550,18 @@ static void sil_dev_config(struct ata_po if (slow_down || ((ap->flags & SIL_FLAG_MOD15WRITE) && (quirks & SIL_QUIRK_MOD15WRITE))) { - ata_dev_printk(dev, KERN_INFO, "applying Seagate errata fix " - "(mod15write workaround)\n"); + if (print_info) + ata_dev_printk(dev, KERN_INFO, "applying Seagate " + "errata fix (mod15write workaround)\n"); dev->max_sectors = 15; return; } /* limit to udma5 */ if (quirks & SIL_QUIRK_UDMA5MAX) { - ata_dev_printk(dev, KERN_INFO, - "applying Maxtor errata fix %s\n", model_num); + if (print_info) + ata_dev_printk(dev, KERN_INFO, "applying Maxtor " + "errata fix %s\n", model_num); dev->udma_mask &= ATA_UDMA5; return; } diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 169e200..5aa288d 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -100,10 +100,14 @@ enum { */ PORT_REGS_SIZE = 0x2000, - PORT_LRAM = 0x0000, /* 31 LRAM slots and PM regs */ + PORT_LRAM = 0x0000, /* 31 LRAM slots and PMP regs */ PORT_LRAM_SLOT_SZ = 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */ - PORT_PM = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */ + PORT_PMP = 0x0f80, /* 8 bytes PMP * 16 (128 bytes) */ + PORT_PMP_STATUS = 0x0000, /* port device status offset */ + PORT_PMP_QACTIVE = 0x0004, /* port device QActive offset */ + PORT_PMP_SIZE = 0x0008, /* 8 bytes per PMP */ + /* 32 bit regs */ PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */ PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */ @@ -126,6 +130,7 @@ enum { PORT_PHY_CFG = 0x1050, PORT_SLOT_STAT = 0x1800, PORT_CMD_ACTIVATE = 0x1c00, /* 64 bit cmd activate * 31 (248 bytes) */ + PORT_CONTEXT = 0x1e04, PORT_EXEC_DIAG = 0x1e00, /* 32bit exec diag * 16 (64 bytes, 0-10 used on 3124) */ PORT_PSD_DIAG = 0x1e40, /* 32bit psd diag * 16 (64 bytes, 0-8 used on 3124) */ PORT_SCONTROL = 0x1f00, @@ -139,9 +144,9 @@ enum { PORT_CS_INIT = (1 << 2), /* port initialize */ PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */ PORT_CS_CDB16 = (1 << 5), /* 0=12b cdb, 1=16b cdb */ - PORT_CS_RESUME = (1 << 6), /* port resume */ + PORT_CS_PMP_RESUME = (1 << 6), /* PMP resume */ PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */ - PORT_CS_PM_EN = (1 << 13), /* port multiplier enable */ + PORT_CS_PMP_EN = (1 << 13), /* port multiplier enable */ PORT_CS_RDY = (1 << 31), /* port ready to accept commands */ /* PORT_IRQ_STAT/ENABLE_SET/CLR */ @@ -562,7 +567,7 @@ static int sil24_softreset(struct ata_po /* do SRST */ prb->ctrl = cpu_to_le16(PRB_CTRL_SRST); - prb->fis[1] = 0; /* no PM yet */ + prb->fis[1] = 0; /* no PMP yet */ writel((u32)paddr, port + PORT_CMD_ACTIVATE); writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4); @@ -1050,7 +1055,8 @@ static void sil24_init_controller(struct writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); /* Clear port multiplier enable and resume bits */ - writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR); + writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, + port + PORT_CTRL_CLR); } /* Turn on interrupts */ diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 9d1235b..9c25a1e 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -173,7 +173,7 @@ static u32 sis_scr_cfg_read (struct ata_ if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) pci_read_config_dword(pdev, cfg_addr+0x10, &val2); - return val|val2; + return (val|val2) & 0xfffffffb; /* avoid problems with powerdowned ports */ } static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val) @@ -212,7 +212,7 @@ static u32 sis_scr_read (struct ata_port if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) val2 = inl(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10); - return val | val2; + return (val | val2) & 0xfffffffb; } static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) @@ -239,7 +239,7 @@ static int sis_init_one (struct pci_dev static int printed_version; struct ata_probe_ent *probe_ent = NULL; int rc; - u32 genctl; + u32 genctl, val; struct ata_port_info pi = sis_port_info, *ppi[2] = { &pi, &pi }; int pci_dev_busy = 0; u8 pmr; @@ -285,17 +285,24 @@ static int sis_init_one (struct pci_dev if (ent->device != 0x182) { if ((pmr & SIS_PMR_COMBINED) == 0) { dev_printk(KERN_INFO, &pdev->dev, - "Detected SiS 180/181 chipset in SATA mode\n"); + "Detected SiS 180/181/964 chipset in SATA mode\n"); port2_start = 64; } else { dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 180/181 chipset in combined mode\n"); port2_start=0; + pi.flags |= ATA_FLAG_SLAVE_POSS; } } else { - dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182 chipset\n"); + pci_read_config_dword ( pdev, 0x6C, &val); + if (val & (1L << 31)) { + dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965 chipset\n"); + pi.flags |= ATA_FLAG_SLAVE_POSS; + } + else + dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965L chipset\n"); port2_start = 0x20; } diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index e654b99..8d6a288 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -94,8 +94,14 @@ enum { VSC_SATA_INT_ERROR_P | VSC_SATA_INT_ERROR_R | \ VSC_SATA_INT_ERROR_E | VSC_SATA_INT_ERROR_M | \ VSC_SATA_INT_PHY_CHANGE), + + /* Host private flags (hp_flags) */ + VSC_SATA_HP_FLAG_MSI = (1 << 0), }; +struct vsc_sata_host_priv { + u32 hp_flags; +}; #define is_vsc_sata_int_err(port_idx, int_status) \ (int_status & (VSC_SATA_INT_ERROR << (8 * port_idx))) @@ -118,6 +124,19 @@ static void vsc_sata_scr_write (struct a } +static void vsc_sata_host_stop(struct ata_host_set *host_set) +{ + struct vsc_sata_host_priv *hpriv = host_set->private_data; + struct pci_dev *pdev = to_pci_dev(host_set->dev); + + if (hpriv->hp_flags & VSC_SATA_HP_FLAG_MSI) + pci_disable_msi(pdev); + else + pci_intx(pdev, 0); + kfree (hpriv); + ata_pci_host_stop(host_set); +} + static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl) { void __iomem *mask_addr; @@ -307,7 +326,7 @@ static const struct ata_port_operations .scr_write = vsc_sata_scr_write, .port_start = ata_port_start, .port_stop = ata_port_stop, - .host_stop = ata_pci_host_stop, + .host_stop = vsc_sata_host_stop, }; static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base) @@ -336,6 +355,7 @@ static int __devinit vsc_sata_init_one ( { static int printed_version; struct ata_probe_ent *probe_ent = NULL; + struct vsc_sata_host_priv *hpriv; unsigned long base; int pci_dev_busy = 0; void __iomem *mmio_base; @@ -377,6 +397,7 @@ static int __devinit vsc_sata_init_one ( rc = -ENOMEM; goto err_out_regions; } + memset(probe_ent, 0, sizeof(*probe_ent)); probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); @@ -388,19 +409,33 @@ static int __devinit vsc_sata_init_one ( } base = (unsigned long) mmio_base; + hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) { + rc = -ENOMEM; + goto err_out_iounmap; + } + memset(hpriv, 0, sizeof(*hpriv)); + /* * Due to a bug in the chip, the default cache line size can't be used */ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80); + if (pci_enable_msi(pdev) == 0) { + hpriv->hp_flags |= VSC_SATA_HP_FLAG_MSI; + pci_intx(pdev, 0); + } + else + probe_ent->irq_flags = IRQF_SHARED; + probe_ent->sht = &vsc_sata_sht; probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO; probe_ent->port_ops = &vsc_sata_ops; probe_ent->n_ports = 4; probe_ent->irq = pdev->irq; - probe_ent->irq_flags = IRQF_SHARED; probe_ent->mmio_base = mmio_base; + probe_ent->private_data = hpriv; /* We don't care much about the PIO/UDMA masks, but the core won't like us * if we don't fill these @@ -427,10 +462,12 @@ static int __devinit vsc_sata_init_one ( /* FIXME: check ata_device_add return value */ ata_device_add(probe_ent); - kfree(probe_ent); + kfree(probe_ent); return 0; +err_out_iounmap: + pci_iounmap(pdev, mmio_base); err_out_free_ent: kfree(probe_ent); err_out_regions: diff --git a/include/linux/ata.h b/include/linux/ata.h index d894419..1df9416 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -200,8 +200,9 @@ enum { ATA_CBL_NONE = 0, ATA_CBL_PATA40 = 1, ATA_CBL_PATA80 = 2, - ATA_CBL_PATA_UNK = 3, - ATA_CBL_SATA = 4, + ATA_CBL_PATA40_SHORT = 3, /* 40 wire cable to high UDMA spec */ + ATA_CBL_PATA_UNK = 4, + ATA_CBL_SATA = 5, /* SATA Status and Control Registers */ SCR_STATUS = 0, @@ -342,6 +343,15 @@ static inline int ata_id_is_cfa(const u1 return 0; } +static inline int ata_drive_40wire(const u16 *dev_id) +{ + if (ata_id_major_version(dev_id) >= 5 && ata_id_is_sata(dev_id)) + return 0; /* SATA */ + if (dev_id[93] & 0x4000) + return 0; /* 80 wire */ + return 1; +} + static inline int atapi_cdb_len(const u16 *dev_id) { u16 tmp = dev_id[0] & 0x3; diff --git a/include/linux/libata.h b/include/linux/libata.h index abd2deb..e950c3a 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -35,6 +35,7 @@ #include #include #include #include +#include /* * Define if arch has non-standard setup. This is a _PCI_ standard @@ -283,6 +284,9 @@ enum { ATA_EHI_QUIET = (1 << 3), /* be quiet */ ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */ + ATA_EHI_PRINTINFO = (1 << 17), /* print configuration info */ + ATA_EHI_SETMODE = (1 << 18), /* configure transfer mode */ + ATA_EHI_POST_SETMODE = (1 << 19), /* revaildating after setmode */ ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, @@ -307,6 +311,8 @@ enum { (some horkage may be drive/controller pair dependant */ ATA_HORKAGE_DIAGNOSTIC = (1 << 0), /* Failed boot diag */ + ATA_HORKAGE_NODMA = (1 << 1), /* DMA problems */ + ATA_HORKAGE_NONCQ = (1 << 2), /* Don't use NCQ */ }; enum hsm_task_states { @@ -377,6 +383,7 @@ struct ata_probe_ent { unsigned int irq_flags; unsigned long port_flags; unsigned long _host_flags; + unsigned long _port_flags[ATA_MAX_PORTS]; void __iomem *mmio_base; void *private_data; @@ -495,6 +502,10 @@ struct ata_device { /* error history */ struct ata_ering ering; unsigned int horkage; /* List of broken features */ +#ifdef CONFIG_SATA_ACPI + /* ACPI objects info */ + acpi_handle obj_handle; +#endif }; /* Offset into struct ata_device. Fields above it are maintained @@ -700,6 +711,8 @@ extern int sata_phy_debounce(struct ata_ extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param); extern int ata_std_prereset(struct ata_port *ap); extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes); +extern int sata_port_hardreset(struct ata_port *ap, + const unsigned long *timing); extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class); extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes); extern void ata_port_disable(struct ata_port *); @@ -744,9 +757,8 @@ extern int ata_scsi_device_suspend(struc extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg); extern void ata_host_resume(struct ata_host *host); extern int ata_ratelimit(void); -extern unsigned int ata_busy_sleep(struct ata_port *ap, - unsigned long timeout_pat, - unsigned long timeout); +extern int ata_busy_sleep(struct ata_port *ap, + unsigned long timeout_pat, unsigned long timeout); extern void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data, unsigned long delay); extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, @@ -787,6 +799,7 @@ extern void ata_id_string(const u16 *id, unsigned int ofs, unsigned int len); extern void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); +extern unsigned long ata_device_blacklisted(const struct ata_device *dev); extern void ata_bmdma_setup (struct ata_queued_cmd *qc); extern void ata_bmdma_start (struct ata_queued_cmd *qc); extern void ata_bmdma_stop(struct ata_queued_cmd *qc); @@ -1061,7 +1074,7 @@ static inline u8 ata_busy_wait(struct at udelay(10); status = ata_chk_status(ap); max--; - } while ((status & bits) && (max > 0)); + } while (status != 0xff && (status & bits) && (max > 0)); return status; } @@ -1082,7 +1095,7 @@ static inline u8 ata_wait_idle(struct at { u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - if (status & (ATA_BUSY | ATA_DRQ)) { + if (status != 0xff && (status & (ATA_BUSY | ATA_DRQ))) { unsigned long l = ap->ioaddr.status_addr; if (ata_msg_warn(ap)) printk(KERN_WARNING "ATA: abnormal status 0x%X on port 0x%lX\n", @@ -1148,37 +1161,6 @@ static inline void ata_qc_reinit(struct } /** - * ata_irq_on - Enable interrupts on a port. - * @ap: Port on which interrupts are enabled. - * - * Enable interrupts on a legacy IDE device using MMIO or PIO, - * wait for idle, clear any pending interrupts. - * - * LOCKING: - * Inherited from caller. - */ - -static inline u8 ata_irq_on(struct ata_port *ap) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - u8 tmp; - - ap->ctl &= ~ATA_NIEN; - ap->last_ctl = ap->ctl; - - if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); - else - outb(ap->ctl, ioaddr->ctl_addr); - tmp = ata_wait_idle(ap); - - ap->ops->irq_clear(ap); - - return tmp; -} - - -/** * ata_irq_ack - Acknowledge a device interrupt. * @ap: Port on which interrupts are enabled. * diff --git a/include/linux/pata_platform.h b/include/linux/pata_platform.h new file mode 100644 index 0000000..2d5fd64 --- /dev/null +++ b/include/linux/pata_platform.h @@ -0,0 +1,13 @@ +#ifndef __LINUX_PATA_PLATFORM_H +#define __LINUX_PATA_PLATFORM_H + +struct pata_platform_info { + /* + * I/O port shift, for platforms with ports that are + * constantly spaced and need larger than the 1-byte + * spacing used by ata_std_ports(). + */ + unsigned int ioport_shift; +}; + +#endif /* __LINUX_PATA_PLATFORM_H */