Module Name:    src
Committed By:   bouyer
Date:           Fri Aug 10 16:35:00 UTC 2012

Modified Files:
        src/sys/dev/ic: ahcisata_core.c ahcisatavar.h
        src/sys/dev/pci: ahcisata_pci.c

Log Message:
Work around some SATA PMP issues in some AHCI controllers by either
disabling PMP entirely, or special handling in the reset function.
Controller list from linux and FreeBSD.


To generate a diff of this commit:
cvs rdiff -u -r1.40 -r1.41 src/sys/dev/ic/ahcisata_core.c
cvs rdiff -u -r1.10 -r1.11 src/sys/dev/ic/ahcisatavar.h
cvs rdiff -u -r1.27 -r1.28 src/sys/dev/pci/ahcisata_pci.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/ic/ahcisata_core.c
diff -u src/sys/dev/ic/ahcisata_core.c:1.40 src/sys/dev/ic/ahcisata_core.c:1.41
--- src/sys/dev/ic/ahcisata_core.c:1.40	Tue Jul 31 15:50:34 2012
+++ src/sys/dev/ic/ahcisata_core.c	Fri Aug 10 16:35:00 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisata_core.c,v 1.40 2012/07/31 15:50:34 bouyer Exp $	*/
+/*	$NetBSD: ahcisata_core.c,v 1.41 2012/08/10 16:35:00 bouyer Exp $	*/
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.40 2012/07/31 15:50:34 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.41 2012/08/10 16:35:00 bouyer Exp $");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
@@ -225,6 +225,11 @@ ahci_attach(struct ahci_softc *sc)
 		return;
 
 	sc->sc_ahci_cap = AHCI_READ(sc, AHCI_CAP);
+	if (sc->sc_achi_quirks & AHCI_QUIRK_BADPMP) {
+		aprint_verbose_dev(sc->sc_atac.atac_dev,
+		    "ignoring broken port multiplier support\n");
+		sc->sc_ahci_cap &= ~AHCI_CAP_SPM;
+	}
 	sc->sc_atac.atac_nchannels = (sc->sc_ahci_cap & AHCI_CAP_NPMASK) + 1;
 	sc->sc_ncmds = ((sc->sc_ahci_cap & AHCI_CAP_NCS) >> 8) + 1;
 	ahci_rev = AHCI_READ(sc, AHCI_VS);
@@ -655,6 +660,7 @@ ahci_do_reset_drive(struct ata_channel *
 	if (drive > 0) {
 		KASSERT(sc->sc_ahci_cap & AHCI_CAP_SPM);
 	}
+again:
 	/* polled command, assume interrupts are disabled */
 	/* use slot 0 to send reset, the channel is idle */
 	cmd_h = &achp->ahcic_cmdh[0];
@@ -687,6 +693,16 @@ ahci_do_reset_drive(struct ata_channel *
 	switch(ahci_exec_fis(chp, 31, flags)) {
 	case ERR_DF:
 	case TIMEOUT:
+		if ((sc->sc_achi_quirks & AHCI_QUIRK_BADPMPRESET) != 0 &&
+		    drive == PMP_PORT_CTL) {
+			/*
+			 * some controllers fails to reset when
+			 * targeting a PMP but a single drive is attached.
+			 * try again with port 0
+			 */
+			drive = 0;
+			goto again;
+		}
 		aprint_error("%s channel %d: clearing WDCTL_RST failed "
 		    "for drive %d\n", AHCINAME(sc), chp->ch_channel, drive);
 		if (sigp)

Index: src/sys/dev/ic/ahcisatavar.h
diff -u src/sys/dev/ic/ahcisatavar.h:1.10 src/sys/dev/ic/ahcisatavar.h:1.11
--- src/sys/dev/ic/ahcisatavar.h:1.10	Tue Jul 31 15:50:34 2012
+++ src/sys/dev/ic/ahcisatavar.h	Fri Aug 10 16:35:00 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisatavar.h,v 1.10 2012/07/31 15:50:34 bouyer Exp $	*/
+/*	$NetBSD: ahcisatavar.h,v 1.11 2012/08/10 16:35:00 bouyer Exp $	*/
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -54,6 +54,11 @@ struct ahci_softc {
 	bus_dma_segment_t sc_cmd_hdr_seg;
 	int sc_cmd_hdr_nseg;
 	int sc_atac_capflags;
+	int sc_achi_quirks;
+#define AHCI_PCI_QUIRK_FORCE	__BIT(0)  /* force attach */
+#define AHCI_PCI_QUIRK_BAD64	__BIT(1)  /* broken 64-bit DMA */
+#define AHCI_QUIRK_BADPMP	__BIT(2)  /* broken PMP support, ignore */
+#define AHCI_QUIRK_BADPMPRESET	__BIT(2)  /* broken PMP support for reset */
 
 	int32_t sc_ahci_cap;	/* copy of AHCI_CAP */
 	int sc_ncmds; /* number of command slots */

Index: src/sys/dev/pci/ahcisata_pci.c
diff -u src/sys/dev/pci/ahcisata_pci.c:1.27 src/sys/dev/pci/ahcisata_pci.c:1.28
--- src/sys/dev/pci/ahcisata_pci.c:1.27	Mon Jan 30 19:41:18 2012
+++ src/sys/dev/pci/ahcisata_pci.c	Fri Aug 10 16:35:00 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisata_pci.c,v 1.27 2012/01/30 19:41:18 drochner Exp $	*/
+/*	$NetBSD: ahcisata_pci.c,v 1.28 2012/08/10 16:35:00 bouyer Exp $	*/
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ahcisata_pci.c,v 1.27 2012/01/30 19:41:18 drochner Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_pci.c,v 1.28 2012/08/10 16:35:00 bouyer Exp $");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
@@ -45,58 +45,147 @@ __KERNEL_RCSID(0, "$NetBSD: ahcisata_pci
 struct ahci_pci_quirk { 
 	pci_vendor_id_t  vendor;	/* Vendor ID */
 	pci_product_id_t product;	/* Product ID */
-	int              quirks;	/* quirks; see below */
+	int              quirks;	/* quirks; same as sc_achi_quirks */
 };
 
-#define AHCI_PCI_QUIRK_FORCE	__BIT(0)	/* force attach */
-#define AHCI_PCI_QUIRK_BAD64	__BIT(1)	/* broken 64-bit DMA */
-
 static const struct ahci_pci_quirk ahci_pci_quirks[] = {
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_SATA,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_SATA2,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_SATA3,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_SATA4,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_AHCI_1,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_AHCI_2,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_AHCI_3,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_AHCI_4,
+	    AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_SATA,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_SATA2,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_SATA3,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_SATA4,
+	     AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_1,
+	     AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_2,
+	     AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_3,
+	     AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_4,
+	     AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_5,
+	     AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_6,
+	     AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_7,
+	     AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_AHCI_8,
+	     AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_1,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_2,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_3,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_4,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_5,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_6,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_7,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_8,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_9,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_10,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_11,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_AHCI_12,
+	    AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_1,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_2,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_3,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_4,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_5,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_6,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_7,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_8,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_9,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_10,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_11,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_AHCI_12,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_1,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_2,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_3,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_4,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_5,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_6,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_7,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_8,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_9,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_10,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_11,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_AHCI_12,
+	    AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M5288,
 	    AHCI_PCI_QUIRK_FORCE },
 	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_88SE6121,
-	    AHCI_PCI_QUIRK_FORCE },
+	    AHCI_PCI_QUIRK_FORCE | AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_MARVELL, PCI_PRODUCT_MARVELL_88SE6145,
+	    AHCI_QUIRK_BADPMP },
 	{ PCI_VENDOR_MARVELL2, PCI_PRODUCT_MARVELL2_88SE9128,
 	    AHCI_PCI_QUIRK_FORCE },
 	/* ATI SB600 AHCI 64-bit DMA only works on some boards/BIOSes */
 	{ PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB600_SATA_1,
-	    AHCI_PCI_QUIRK_BAD64 },
+	    AHCI_PCI_QUIRK_BAD64 | AHCI_QUIRK_BADPMPRESET },
+	{ PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB700_SATA_AHCI,
+	    AHCI_QUIRK_BADPMPRESET },
+	{ PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB700_SATA_RAID,
+	    AHCI_QUIRK_BADPMPRESET },
+	{ PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB700_SATA_RAID5,
+	    AHCI_QUIRK_BADPMPRESET },
+	{ PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB700_SATA_FC,
+	    AHCI_QUIRK_BADPMPRESET },
+	{ PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB700_SATA_AHCI2,
+	    AHCI_QUIRK_BADPMPRESET },
+	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237R_SATA,
+	    AHCI_QUIRK_BADPMP },
+	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8251_SATA,
+	    AHCI_QUIRK_BADPMP },
 };
 
 struct ahci_pci_softc {
@@ -106,7 +195,7 @@ struct ahci_pci_softc {
 	void * sc_ih;
 };
 
-static bool ahci_pci_has_quirk(pci_vendor_id_t, pci_product_id_t, int);
+static int  ahci_pci_has_quirk(pci_vendor_id_t, pci_product_id_t);
 static int  ahci_pci_match(device_t, cfdata_t, void *);
 static void ahci_pci_attach(device_t, device_t, void *);
 static int  ahci_pci_detach(device_t, int);
@@ -116,16 +205,16 @@ static bool ahci_pci_resume(device_t, co
 CFATTACH_DECL_NEW(ahcisata_pci, sizeof(struct ahci_pci_softc),
     ahci_pci_match, ahci_pci_attach, ahci_pci_detach, NULL);
 
-static bool
-ahci_pci_has_quirk(pci_vendor_id_t vendor, pci_product_id_t product, int quirk)
+static int
+ahci_pci_has_quirk(pci_vendor_id_t vendor, pci_product_id_t product)
 {
 	int i;
 
 	for (i = 0; i < __arraycount(ahci_pci_quirks); i++)
 		if (vendor == ahci_pci_quirks[i].vendor &&
 		    product == ahci_pci_quirks[i].product)
-			return (ahci_pci_quirks[i].quirks & quirk) != 0;
-	return false;
+			return ahci_pci_quirks[i].quirks;
+	return 0;
 }
 
 static int
@@ -138,9 +227,8 @@ ahci_pci_match(device_t parent, cfdata_t
 	int ret = 0;
 	bool force;
 
-	force = ahci_pci_has_quirk(PCI_VENDOR(pa->pa_id),
-				   PCI_PRODUCT(pa->pa_id),
-				   AHCI_PCI_QUIRK_FORCE);
+	force = ((ahci_pci_has_quirk( PCI_VENDOR(pa->pa_id),
+	    PCI_PRODUCT(pa->pa_id)) & AHCI_PCI_QUIRK_FORCE) != 0);
 
 	/* if wrong class and not forced by quirks, don't match */
 	if ((PCI_CLASS(pa->pa_class) != PCI_CLASS_MASS_STORAGE ||
@@ -204,10 +292,12 @@ ahci_pci_attach(device_t parent, device_
 
 	sc->sc_dmat = pa->pa_dmat;
 
+	sc->sc_achi_quirks = ahci_pci_has_quirk(PCI_VENDOR(pa->pa_id),
+					    PCI_PRODUCT(pa->pa_id));
+	/* from FreeBSD: marvell controllers have broken PMP support */
+
 	ahci_cap_64bit = (AHCI_READ(sc, AHCI_CAP) & AHCI_CAP_64BIT) != 0;
-	ahci_bad_64bit = ahci_pci_has_quirk(PCI_VENDOR(pa->pa_id),
-					    PCI_PRODUCT(pa->pa_id),
-					    AHCI_PCI_QUIRK_BAD64);
+	ahci_bad_64bit = ((sc->sc_achi_quirks & AHCI_PCI_QUIRK_BAD64) != 0);
 
 	if (pci_dma64_available(pa) && ahci_cap_64bit) {
 		if (!ahci_bad_64bit)

Reply via email to