From owner-svn-src-all@FreeBSD.ORG Fri Jun 11 14:06:35 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6FB3910656D4; Fri, 11 Jun 2010 14:06:35 +0000 (UTC) (envelope-from nwhitehorn@FreeBSD.org) Received: from svn.freebsd.org (unknown [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 5D6A48FC24; Fri, 11 Jun 2010 14:06:35 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o5BE6Zoa096073; Fri, 11 Jun 2010 14:06:35 GMT (envelope-from nwhitehorn@svn.freebsd.org) Received: (from nwhitehorn@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o5BE6ZAP096069; Fri, 11 Jun 2010 14:06:35 GMT (envelope-from nwhitehorn@svn.freebsd.org) Message-Id: <201006111406.o5BE6ZAP096069@svn.freebsd.org> From: Nathan Whitehorn Date: Fri, 11 Jun 2010 14:06:35 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r209042 - in stable/8/sys/dev/ata: . chipsets X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 11 Jun 2010 14:06:35 -0000 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 */