--- /dev/null
+From b78152e9dbab6d6175e2adcbd8c62959e8f0f922 Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj@kernel.org>
+Date: Wed, 22 Oct 2008 00:45:57 +0900
+Subject: [PATCH] sata_via: load DEVICE register when CTL changes
+References: bnc#441718
+
+VIA controllers clear DEVICE register when IEN changes. Make sure
+DEVICE is updated along with CTL.
+
+This change is separated from Joseph Chan's larger patch.
+
+ http://thread.gmane.org/gmane.linux.kernel.commits.mm/40640
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Cc: Joseph Chan <JosephChan@via.com.tw>
+Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
+Signed-off-by: Tejun Heo <teheo@suse.de>
+---
+ drivers/ata/sata_via.c | 35 ++++++++++++++++++++++++++++++++---
+ 1 files changed, 32 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
+index 1cfa745..5b72e73 100644
+--- a/drivers/ata/sata_via.c
++++ b/drivers/ata/sata_via.c
+@@ -70,6 +70,7 @@ enum {
+ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+ static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+ static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
++static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
+ static void svia_noop_freeze(struct ata_port *ap);
+ static int vt6420_prereset(struct ata_link *link, unsigned long deadline);
+ static int vt6421_pata_cable_detect(struct ata_port *ap);
+@@ -103,21 +104,26 @@ static struct scsi_host_template svia_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+ };
+
+-static struct ata_port_operations vt6420_sata_ops = {
++static struct ata_port_operations svia_base_ops = {
+ .inherits = &ata_bmdma_port_ops,
++ .sff_tf_load = svia_tf_load,
++};
++
++static struct ata_port_operations vt6420_sata_ops = {
++ .inherits = &svia_base_ops,
+ .freeze = svia_noop_freeze,
+ .prereset = vt6420_prereset,
+ };
+
+ static struct ata_port_operations vt6421_pata_ops = {
+- .inherits = &ata_bmdma_port_ops,
++ .inherits = &svia_base_ops,
+ .cable_detect = vt6421_pata_cable_detect,
+ .set_piomode = vt6421_set_pio_mode,
+ .set_dmamode = vt6421_set_dma_mode,
+ };
+
+ static struct ata_port_operations vt6421_sata_ops = {
+- .inherits = &ata_bmdma_port_ops,
++ .inherits = &svia_base_ops,
+ .scr_read = svia_scr_read,
+ .scr_write = svia_scr_write,
+ };
+@@ -168,6 +174,29 @@ static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
+ return 0;
+ }
+
++/**
++ * svia_tf_load - send taskfile registers to host controller
++ * @ap: Port to which output is sent
++ * @tf: ATA taskfile register set
++ *
++ * Outputs ATA taskfile to standard ATA host controller.
++ *
++ * This is to fix the internal bug of via chipsets, which will
++ * reset the device register after changing the IEN bit on ctl
++ * register.
++ */
++static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
++{
++ struct ata_taskfile ttf;
++
++ if (tf->ctl != ap->last_ctl) {
++ ttf = *tf;
++ ttf.flags |= ATA_TFLAG_DEVICE;
++ tf = &ttf;
++ }
++ ata_sff_tf_load(ap, tf);
++}
++
+ static void svia_noop_freeze(struct ata_port *ap)
+ {
+ /* Some VIA controllers choke if ATA_NIEN is manipulated in
+--
+1.5.4.5
+