Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 11 Jun 2010 14:06:35 +0000 (UTC)
From:      Nathan Whitehorn <nwhitehorn@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r209042 - in stable/8/sys/dev/ata: . chipsets
Message-ID:  <201006111406.o5BE6ZAP096069@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: nwhitehorn
Date: Fri Jun 11 14:06:35 2010
New Revision: 209042
URL: http://svn.freebsd.org/changeset/base/209042

Log:
  MFC r208870:
  Some revisions of the Serverworks K2 SATA controller have a data
  corruption bug where if an ATA command is issued before DMA is started,
  data will become available to the controller before it knows what to do
  with it. This results in either data corruption or a controller crash.
  
  This patch remedies the problem by adopting the workaround employed
  by Linux and Darwin: starting the DMA engine prior to sending the ATA
  command.
  
  Reviewed by:	mav
  Approved by:	re (kib)

Modified:
  stable/8/sys/dev/ata/ata-all.h
  stable/8/sys/dev/ata/ata-lowlevel.c
  stable/8/sys/dev/ata/chipsets/ata-serverworks.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)
  stable/8/sys/geom/sched/   (props changed)

Modified: stable/8/sys/dev/ata/ata-all.h
==============================================================================
--- stable/8/sys/dev/ata/ata-all.h	Fri Jun 11 14:05:34 2010	(r209041)
+++ stable/8/sys/dev/ata/ata-all.h	Fri Jun 11 14:06:35 2010	(r209042)
@@ -564,6 +564,7 @@ struct ata_channel {
 #define         ATA_CHECKS_CABLE	0x20
 #define         ATA_NO_ATAPI_DMA	0x40
 #define         ATA_SATA		0x80
+#define         ATA_DMA_BEFORE_CMD	0x100
 
     int				pm_level;	/* power management level */
     int                         devices;        /* what is present */

Modified: stable/8/sys/dev/ata/ata-lowlevel.c
==============================================================================
--- stable/8/sys/dev/ata/ata-lowlevel.c	Fri Jun 11 14:05:34 2010	(r209041)
+++ stable/8/sys/dev/ata/ata-lowlevel.c	Fri Jun 11 14:06:35 2010	(r209042)
@@ -141,6 +141,14 @@ ata_begin_transaction(struct ata_request
 	    goto begin_finished;
 	}
 
+	/* start DMA engine if necessary */
+	if ((ch->flags & ATA_DMA_BEFORE_CMD) &&
+	   ch->dma.start && ch->dma.start(request)) {
+	    device_printf(request->parent, "error starting DMA\n");
+	    request->result = EIO;
+	    goto begin_finished;
+	}
+
 	/* issue command */
 	if (ch->hw.command(request)) {
 	    device_printf(request->parent, "error issuing %s command\n",
@@ -150,7 +158,8 @@ ata_begin_transaction(struct ata_request
 	}
 
 	/* start DMA engine */
-	if (ch->dma.start && ch->dma.start(request)) {
+	if (!(ch->flags & ATA_DMA_BEFORE_CMD) &&
+	   ch->dma.start && ch->dma.start(request)) {
 	    device_printf(request->parent, "error starting DMA\n");
 	    request->result = EIO;
 	    goto begin_finished;

Modified: stable/8/sys/dev/ata/chipsets/ata-serverworks.c
==============================================================================
--- stable/8/sys/dev/ata/chipsets/ata-serverworks.c	Fri Jun 11 14:05:34 2010	(r209041)
+++ stable/8/sys/dev/ata/chipsets/ata-serverworks.c	Fri Jun 11 14:06:35 2010	(r209042)
@@ -241,6 +241,16 @@ ata_serverworks_ch_attach(device_t dev)
 	ATA_OUTL(ctlr->r_res2, ch_offset + 0x88, 0);
 	ATA_OUTL(ctlr->r_res2, ch_offset + 0x80,
 	    ATA_INL(ctlr->r_res2, ch_offset + 0x80) & ~0x00040000);
+
+	/*
+	 * Some controllers have a bug where they will send the command
+	 * to the drive before seeing a DMA start, and then can begin
+	 * receiving data before the DMA start arrives. The controller
+	 * will then become confused and either corrupt the data or crash.
+	 * Remedy this by starting DMA before sending the drive command.
+	 */
+
+	ch->flags |= ATA_DMA_BEFORE_CMD;
     }
 
     /* chip does not reliably do 64K DMA transfers */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201006111406.o5BE6ZAP096069>