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)