aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBart Hartgers <bart.hartgers@gmail.com>2010-06-27 19:04:56 +0100
committerWilly Tarreau <w@1wt.eu>2012-02-11 15:37:24 +0100
commitd1839236f9888ddcb76c2883ca54cdbed416392c (patch)
tree441ff36b568c93d587fc618c3c849203183eea0d
parent4409394ba19d696f04273145fc393c60b1448b80 (diff)
sata_via: Delay on vt6420 when starting ATAPI DMA write
commit a55ab496ea9c820b7192c15ef1fbf3291edfe638 upstream. When writing a disc on certain lite-on dvd-writers (also rebadged as optiarc/LG/...) connected to a vt6420, the ATAPI CDB ends up in the datastream and on the disc, causing silent corruption. Delaying between sending the CDB and starting DMA seems to prevent this. I do not know if there are burners that do not suffer from this, but the patch should be safe for those as well. There are many reports of this issue, but AFAICT no solution was found before. For example: http://lkml.indiana.edu/hypermail/linux/kernel/0802.3/0561.html Signed-off-by: Bart Hartgers <bart.hartgers@gmail.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com> [bwh: Remove version bump for 2.6.32] Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Willy Tarreau <w@1wt.eu>
-rw-r--r--drivers/ata/sata_via.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 96deeb354e1..1410e6aee11 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -40,6 +40,8 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
@@ -72,6 +74,7 @@ static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static void svia_noop_freeze(struct ata_port *ap);
static int vt6420_prereset(struct ata_link *link, unsigned long deadline);
+static void vt6420_bmdma_start(struct ata_queued_cmd *qc);
static int vt6421_pata_cable_detect(struct ata_port *ap);
static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev);
static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev);
@@ -107,6 +110,7 @@ static struct ata_port_operations vt6420_sata_ops = {
.inherits = &ata_bmdma_port_ops,
.freeze = svia_noop_freeze,
.prereset = vt6420_prereset,
+ .bmdma_start = vt6420_bmdma_start,
};
static struct ata_port_operations vt6421_pata_ops = {
@@ -247,6 +251,17 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
return 0;
}
+static void vt6420_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ if ((qc->tf.command == ATA_CMD_PACKET) &&
+ (qc->scsicmd->sc_data_direction == DMA_TO_DEVICE)) {
+ /* Prevents corruption on some ATAPI burners */
+ ata_sff_pause(ap);
+ }
+ ata_bmdma_start(qc);
+}
+
static int vt6421_pata_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);