From owner-svn-src-head@FreeBSD.ORG  Thu Apr 21 20:56:34 2011
Return-Path: <owner-svn-src-head@FreeBSD.ORG>
Delivered-To: svn-src-head@freebsd.org
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 9325E1065672;
	Thu, 21 Apr 2011 20:56:34 +0000 (UTC) (envelope-from mav@FreeBSD.org)
Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c])
	by mx1.freebsd.org (Postfix) with ESMTP id 699558FC1A;
	Thu, 21 Apr 2011 20:56:34 +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 p3LKuYuS012126;
	Thu, 21 Apr 2011 20:56:34 GMT (envelope-from mav@svn.freebsd.org)
Received: (from mav@localhost)
	by svn.freebsd.org (8.14.3/8.14.3/Submit) id p3LKuYbT012124;
	Thu, 21 Apr 2011 20:56:34 GMT (envelope-from mav@svn.freebsd.org)
Message-Id: <201104212056.p3LKuYbT012124@svn.freebsd.org>
From: Alexander Motin <mav@FreeBSD.org>
Date: Thu, 21 Apr 2011 20:56:34 +0000 (UTC)
To: src-committers@freebsd.org, svn-src-all@freebsd.org,
	svn-src-head@freebsd.org
X-SVN-Group: head
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Cc: 
Subject: svn commit: r220929 - head/sys/dev/ata/chipsets
X-BeenThere: svn-src-head@freebsd.org
X-Mailman-Version: 2.1.5
Precedence: list
List-Id: SVN commit messages for the src tree for head/-current
	<svn-src-head.freebsd.org>
List-Unsubscribe: <http://lists.freebsd.org/mailman/listinfo/svn-src-head>,
	<mailto:svn-src-head-request@freebsd.org?subject=unsubscribe>
List-Archive: <http://lists.freebsd.org/pipermail/svn-src-head>
List-Post: <mailto:svn-src-head@freebsd.org>
List-Help: <mailto:svn-src-head-request@freebsd.org?subject=help>
List-Subscribe: <http://lists.freebsd.org/mailman/listinfo/svn-src-head>,
	<mailto:svn-src-head-request@freebsd.org?subject=subscribe>
X-List-Received-Date: Thu, 21 Apr 2011 20:56:34 -0000

Author: mav
Date: Thu Apr 21 20:56:34 2011
New Revision: 220929
URL: http://svn.freebsd.org/changeset/base/220929

Log:
  According to ATA specifications, when ATAPI master is the only device, it
  should respond with all zeroes to any access to slave registers. Test with
  PATA devices confirmed such behavior. Unluckily, Intel SATA controllers in
  legacy emulation mode behave differently, not making any difference between
  ATA and ATAPI devices. It causes false positive slave device detection and,
  as result, command timeouts.
  
  To workaround this problem, mask result of legacy-emulated soft-reset with
  the device presence information received from the SATA-specific registers.

Modified:
  head/sys/dev/ata/chipsets/ata-intel.c

Modified: head/sys/dev/ata/chipsets/ata-intel.c
==============================================================================
--- head/sys/dev/ata/chipsets/ata-intel.c	Thu Apr 21 19:56:06 2011	(r220928)
+++ head/sys/dev/ata/chipsets/ata-intel.c	Thu Apr 21 20:56:34 2011	(r220929)
@@ -392,8 +392,9 @@ ata_intel_reset(device_t dev)
 	device_t parent = device_get_parent(dev);
 	struct ata_pci_controller *ctlr = device_get_softc(parent);
 	struct ata_channel *ch = device_get_softc(dev);
-	int mask, pmask, timeout, devs;
+	int mask, pshift, timeout, devs;
 	u_char *smap;
+	uint16_t pcs;
 
 	/* In combined mode, skip SATA stuff for PATA channel. */
 	if ((ch->flags & ATA_SATA) == 0)
@@ -412,26 +413,35 @@ ata_intel_reset(device_t dev)
 
 	/* Wait up to 1 sec for "connect well". */
 	if (ctlr->chip->cfg1 & (INTEL_6CH | INTEL_6CH2))
-		pmask = mask << 8;
+		pshift = 8;
 	else
-		pmask = mask << 4;
+		pshift = 4;
 	for (timeout = 0; timeout < 100 ; timeout++) {
-		if (((pci_read_config(parent, 0x92, 2) & pmask) == pmask) &&
-		    (ATA_IDX_INB(ch, ATA_STATUS) != 0xff))
+		pcs = (pci_read_config(parent, 0x92, 2) >> pshift) & mask;
+		if ((pcs == mask) && (ATA_IDX_INB(ch, ATA_STATUS) != 0xff))
 			break;
 		ata_udelay(10000);
 	}
 
+	if (bootverbose)
+		device_printf(dev, "SATA reset: ports status=0x%02x\n", pcs);
 	/* If any device found, do soft-reset. */
 	if (ch->hw.pm_read != NULL) {
-		devs = ata_sata_phy_reset(dev, 0, 2);
+		devs = ata_sata_phy_reset(dev, 0, 2) ? ATA_ATA_MASTER : 0;
 		if ((ch->flags & ATA_NO_SLAVE) == 0)
-			devs += ata_sata_phy_reset(dev, 1, 2);
-	} else
-		devs = 1;
-	if (devs)
+			devs |= ata_sata_phy_reset(dev, 1, 2) ?
+			    ATA_ATA_SLAVE : 0;
+	} else {
+		devs = (pcs & (1 << smap[0])) ? ATA_ATA_MASTER : 0;
+		if ((ch->flags & ATA_NO_SLAVE) == 0)
+			devs |= (pcs & (1 << smap[1])) ?
+			    ATA_ATA_SLAVE : 0;
+	}
+	if (devs) {
 		ata_generic_reset(dev);
-	else
+		/* Reset may give fake slave when only ATAPI master present. */
+		ch->devices &= (devs | (devs * ATA_ATAPI_MASTER));
+	} else
 		ch->devices = 0;
 }