xref: /openbsd-src/sys/dev/pci/ahci_pci.c (revision 9406b56eb929f42aa2d612f2397127181fa02d3a)
1*9406b56eSkn /*	$OpenBSD: ahci_pci.c,v 1.18 2024/06/16 18:00:08 kn Exp $ */
27acdc34dSpatrick 
37acdc34dSpatrick /*
47acdc34dSpatrick  * Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
57acdc34dSpatrick  * Copyright (c) 2010 Conformal Systems LLC <info@conformal.com>
67acdc34dSpatrick  * Copyright (c) 2010 Jonathan Matthew <jonathan@d14n.org>
77acdc34dSpatrick  *
87acdc34dSpatrick  * Permission to use, copy, modify, and distribute this software for any
97acdc34dSpatrick  * purpose with or without fee is hereby granted, provided that the above
107acdc34dSpatrick  * copyright notice and this permission notice appear in all copies.
117acdc34dSpatrick  *
127acdc34dSpatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
137acdc34dSpatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
147acdc34dSpatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
157acdc34dSpatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
167acdc34dSpatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
177acdc34dSpatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
187acdc34dSpatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
197acdc34dSpatrick  */
207acdc34dSpatrick 
217acdc34dSpatrick #include <sys/param.h>
227acdc34dSpatrick #include <sys/systm.h>
237acdc34dSpatrick #include <sys/device.h>
247acdc34dSpatrick #include <sys/queue.h>
257acdc34dSpatrick #include <sys/mutex.h>
267acdc34dSpatrick 
277acdc34dSpatrick #include <machine/bus.h>
287acdc34dSpatrick 
297acdc34dSpatrick #include <dev/pci/pcireg.h>
307acdc34dSpatrick #include <dev/pci/pcivar.h>
317acdc34dSpatrick #include <dev/pci/pcidevs.h>
327acdc34dSpatrick 
3306133b5aSdlg #include <dev/ic/ahcireg.h>
347acdc34dSpatrick #include <dev/ic/ahcivar.h>
357acdc34dSpatrick 
367acdc34dSpatrick #define AHCI_PCI_BAR		0x24
377acdc34dSpatrick #define AHCI_PCI_ATI_SB600_MAGIC	0x40
387acdc34dSpatrick #define AHCI_PCI_ATI_SB600_LOCKED	0x01
397acdc34dSpatrick 
407acdc34dSpatrick struct ahci_pci_softc {
417acdc34dSpatrick 	struct ahci_softc	psc_ahci;
427acdc34dSpatrick 
437acdc34dSpatrick 	pci_chipset_tag_t	psc_pc;
447acdc34dSpatrick 	pcitag_t		psc_tag;
457acdc34dSpatrick 
467acdc34dSpatrick 	int			psc_flags;
477acdc34dSpatrick };
487acdc34dSpatrick 
497acdc34dSpatrick struct ahci_device {
507acdc34dSpatrick 	pci_vendor_id_t		ad_vendor;
517acdc34dSpatrick 	pci_product_id_t	ad_product;
527acdc34dSpatrick 	int			(*ad_match)(struct pci_attach_args *);
537acdc34dSpatrick 	int			(*ad_attach)(struct ahci_softc *,
547acdc34dSpatrick 				    struct pci_attach_args *);
557acdc34dSpatrick };
567acdc34dSpatrick 
577acdc34dSpatrick const struct ahci_device *ahci_lookup_device(struct pci_attach_args *);
587acdc34dSpatrick 
597acdc34dSpatrick int			ahci_no_match(struct pci_attach_args *);
607acdc34dSpatrick int			ahci_vt8251_attach(struct ahci_softc *,
617acdc34dSpatrick 			    struct pci_attach_args *);
627acdc34dSpatrick void			ahci_ati_sb_idetoahci(struct ahci_softc *,
637acdc34dSpatrick 			    struct pci_attach_args *pa);
647acdc34dSpatrick int			ahci_ati_sb600_attach(struct ahci_softc *,
657acdc34dSpatrick 			    struct pci_attach_args *);
667acdc34dSpatrick int			ahci_ati_sb700_attach(struct ahci_softc *,
677acdc34dSpatrick 			    struct pci_attach_args *);
687acdc34dSpatrick int			ahci_amd_hudson2_attach(struct ahci_softc *,
697acdc34dSpatrick 			    struct pci_attach_args *);
707acdc34dSpatrick int			ahci_intel_attach(struct ahci_softc *,
717acdc34dSpatrick 			    struct pci_attach_args *);
7251a91e86Sgilles int			ahci_samsung_attach(struct ahci_softc *,
7351a91e86Sgilles 			    struct pci_attach_args *);
74*9406b56eSkn int			ahci_storx_attach(struct ahci_softc *,
75*9406b56eSkn 			    struct pci_attach_args *);
767acdc34dSpatrick 
777acdc34dSpatrick static const struct ahci_device ahci_devices[] = {
787acdc34dSpatrick 	{ PCI_VENDOR_AMD,	PCI_PRODUCT_AMD_HUDSON2_SATA_1,
797acdc34dSpatrick 	    NULL,		ahci_amd_hudson2_attach },
807acdc34dSpatrick 	{ PCI_VENDOR_AMD,	PCI_PRODUCT_AMD_HUDSON2_SATA_2,
817acdc34dSpatrick 	    NULL,		ahci_amd_hudson2_attach },
827acdc34dSpatrick 	{ PCI_VENDOR_AMD,	PCI_PRODUCT_AMD_HUDSON2_SATA_3,
837acdc34dSpatrick 	    NULL,		ahci_amd_hudson2_attach },
847acdc34dSpatrick 	{ PCI_VENDOR_AMD,	PCI_PRODUCT_AMD_HUDSON2_SATA_4,
857acdc34dSpatrick 	    NULL,		ahci_amd_hudson2_attach },
867acdc34dSpatrick 	{ PCI_VENDOR_AMD,	PCI_PRODUCT_AMD_HUDSON2_SATA_5,
877acdc34dSpatrick 	    NULL,		ahci_amd_hudson2_attach },
887acdc34dSpatrick 	{ PCI_VENDOR_AMD,	PCI_PRODUCT_AMD_HUDSON2_SATA_6,
897acdc34dSpatrick 	    NULL,		ahci_amd_hudson2_attach },
907acdc34dSpatrick 
917acdc34dSpatrick 	{ PCI_VENDOR_ATI,	PCI_PRODUCT_ATI_SB600_SATA,
927acdc34dSpatrick 	    NULL,		ahci_ati_sb600_attach },
937acdc34dSpatrick 	{ PCI_VENDOR_ATI,	PCI_PRODUCT_ATI_SBX00_SATA_1,
947acdc34dSpatrick 	    NULL,		ahci_ati_sb700_attach },
957acdc34dSpatrick 	{ PCI_VENDOR_ATI,	PCI_PRODUCT_ATI_SBX00_SATA_2,
967acdc34dSpatrick 	    NULL,		ahci_ati_sb700_attach },
977acdc34dSpatrick 	{ PCI_VENDOR_ATI,	PCI_PRODUCT_ATI_SBX00_SATA_3,
987acdc34dSpatrick 	    NULL,		ahci_ati_sb700_attach },
997acdc34dSpatrick 	{ PCI_VENDOR_ATI,	PCI_PRODUCT_ATI_SBX00_SATA_4,
1007acdc34dSpatrick 	    NULL,		ahci_ati_sb700_attach },
1017acdc34dSpatrick 	{ PCI_VENDOR_ATI,	PCI_PRODUCT_ATI_SBX00_SATA_5,
1027acdc34dSpatrick 	    NULL,		ahci_ati_sb700_attach },
1037acdc34dSpatrick 	{ PCI_VENDOR_ATI,	PCI_PRODUCT_ATI_SBX00_SATA_6,
1047acdc34dSpatrick 	    NULL,		ahci_ati_sb700_attach },
1057acdc34dSpatrick 
106c0be473cSkettenis 	{ PCI_VENDOR_ASMEDIA,	PCI_PRODUCT_ASMEDIA_ASM1061_SATA },
107c0be473cSkettenis 
1087acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_6SERIES_AHCI_1,
1097acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1107acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_6SERIES_AHCI_2,
1117acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1127acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_6321ESB_AHCI,
1137acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1147acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801GR_AHCI,
1157acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1167acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801GBM_AHCI,
1177acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1187acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801H_AHCI_6P,
1197acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1207acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801H_AHCI_4P,
1217acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1227acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801HBM_AHCI,
1237acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1247acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801I_AHCI_1,
1257acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1267acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801I_AHCI_2,
1277acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1287acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801I_AHCI_3,
1297acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1307acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801JD_AHCI,
1317acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1327acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82801JI_AHCI,
1337acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1347acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_3400_AHCI_1,
1357acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1367acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_3400_AHCI_2,
1377acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1387acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_3400_AHCI_3,
1397acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1407acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_3400_AHCI_4,
1417acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1427acdc34dSpatrick 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_EP80579_AHCI,
1437acdc34dSpatrick 	    NULL,		ahci_intel_attach },
1447acdc34dSpatrick 
1456f9e3f93Sbrad 	{ PCI_VENDOR_SAMSUNG2,	PCI_PRODUCT_SAMSUNG2_S4LN053X01,
1466f9e3f93Sbrad 	    NULL,		ahci_samsung_attach },
14751a91e86Sgilles 	{ PCI_VENDOR_SAMSUNG2,	PCI_PRODUCT_SAMSUNG2_XP941,
14851a91e86Sgilles 	    NULL,		ahci_samsung_attach },
14911c4459cSdlg 	{ PCI_VENDOR_SAMSUNG2,	PCI_PRODUCT_SAMSUNG2_SM951_AHCI,
150b52691ebSkettenis 	    NULL,		ahci_samsung_attach },
15151a91e86Sgilles 
1527acdc34dSpatrick 	{ PCI_VENDOR_VIATECH,	PCI_PRODUCT_VIATECH_VT8251_SATA,
153*9406b56eSkn 	  ahci_no_match,	ahci_vt8251_attach },
154*9406b56eSkn 
155*9406b56eSkn 	{ PCI_VENDOR_ZHAOXIN,	PCI_PRODUCT_ZHAOXIN_STORX_AHCI,
156*9406b56eSkn 	  NULL,			ahci_storx_attach },
1577acdc34dSpatrick };
1587acdc34dSpatrick 
1597acdc34dSpatrick int			ahci_pci_match(struct device *, void *, void *);
1607acdc34dSpatrick void			ahci_pci_attach(struct device *, struct device *,
1617acdc34dSpatrick 			    void *);
1627acdc34dSpatrick int			ahci_pci_detach(struct device *, int);
1637acdc34dSpatrick int			ahci_pci_activate(struct device *, int);
1647acdc34dSpatrick 
1658d2c75e4Smpi const struct cfattach ahci_pci_ca = {
1667acdc34dSpatrick 	sizeof(struct ahci_pci_softc),
1677acdc34dSpatrick 	ahci_pci_match,
1687acdc34dSpatrick 	ahci_pci_attach,
1697acdc34dSpatrick 	ahci_pci_detach,
1707acdc34dSpatrick 	ahci_pci_activate
1717acdc34dSpatrick };
1727acdc34dSpatrick 
1738d2c75e4Smpi const struct cfattach ahci_jmb_ca = {
1747acdc34dSpatrick 	sizeof(struct ahci_pci_softc),
1757acdc34dSpatrick 	ahci_pci_match,
1767acdc34dSpatrick 	ahci_pci_attach,
1777acdc34dSpatrick 	ahci_pci_detach
1787acdc34dSpatrick };
1797acdc34dSpatrick 
1807acdc34dSpatrick int			ahci_map_regs(struct ahci_pci_softc *,
1817acdc34dSpatrick 			    struct pci_attach_args *);
1827acdc34dSpatrick void			ahci_unmap_regs(struct ahci_pci_softc *);
1837acdc34dSpatrick int			ahci_map_intr(struct ahci_pci_softc *,
1847acdc34dSpatrick 			    struct pci_attach_args *, pci_intr_handle_t);
1857acdc34dSpatrick void			ahci_unmap_intr(struct ahci_pci_softc *);
1867acdc34dSpatrick 
1877acdc34dSpatrick const struct ahci_device *
ahci_lookup_device(struct pci_attach_args * pa)1887acdc34dSpatrick ahci_lookup_device(struct pci_attach_args *pa)
1897acdc34dSpatrick {
1907acdc34dSpatrick 	int				i;
1917acdc34dSpatrick 	const struct ahci_device	*ad;
1927acdc34dSpatrick 
1937acdc34dSpatrick 	for (i = 0; i < (sizeof(ahci_devices) / sizeof(ahci_devices[0])); i++) {
1947acdc34dSpatrick 		ad = &ahci_devices[i];
1957acdc34dSpatrick 		if (ad->ad_vendor == PCI_VENDOR(pa->pa_id) &&
1967acdc34dSpatrick 		    ad->ad_product == PCI_PRODUCT(pa->pa_id))
1977acdc34dSpatrick 			return (ad);
1987acdc34dSpatrick 	}
1997acdc34dSpatrick 
2007acdc34dSpatrick 	return (NULL);
2017acdc34dSpatrick }
2027acdc34dSpatrick 
2037acdc34dSpatrick int
ahci_no_match(struct pci_attach_args * pa)2047acdc34dSpatrick ahci_no_match(struct pci_attach_args *pa)
2057acdc34dSpatrick {
2067acdc34dSpatrick 	return (0);
2077acdc34dSpatrick }
2087acdc34dSpatrick 
2097acdc34dSpatrick int
ahci_vt8251_attach(struct ahci_softc * sc,struct pci_attach_args * pa)2107acdc34dSpatrick ahci_vt8251_attach(struct ahci_softc *sc, struct pci_attach_args *pa)
2117acdc34dSpatrick {
2127acdc34dSpatrick 	sc->sc_flags |= AHCI_F_NO_NCQ;
2137acdc34dSpatrick 
2147acdc34dSpatrick 	return (0);
2157acdc34dSpatrick }
2167acdc34dSpatrick 
2177acdc34dSpatrick void
ahci_ati_sb_idetoahci(struct ahci_softc * sc,struct pci_attach_args * pa)2187acdc34dSpatrick ahci_ati_sb_idetoahci(struct ahci_softc *sc, struct pci_attach_args *pa)
2197acdc34dSpatrick {
2207acdc34dSpatrick 	pcireg_t			magic;
2217acdc34dSpatrick 
2227acdc34dSpatrick 	if (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_IDE) {
2237acdc34dSpatrick 		magic = pci_conf_read(pa->pa_pc, pa->pa_tag,
2247acdc34dSpatrick 		    AHCI_PCI_ATI_SB600_MAGIC);
2257acdc34dSpatrick 		pci_conf_write(pa->pa_pc, pa->pa_tag,
2267acdc34dSpatrick 		    AHCI_PCI_ATI_SB600_MAGIC,
2277acdc34dSpatrick 		    magic | AHCI_PCI_ATI_SB600_LOCKED);
2287acdc34dSpatrick 
2297acdc34dSpatrick 		pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG,
2307acdc34dSpatrick 		    PCI_CLASS_MASS_STORAGE << PCI_CLASS_SHIFT |
2317acdc34dSpatrick 		    PCI_SUBCLASS_MASS_STORAGE_SATA << PCI_SUBCLASS_SHIFT |
232e3ba7f78Skettenis 		    PCI_INTERFACE_SATA_AHCI10 << PCI_INTERFACE_SHIFT |
2337acdc34dSpatrick 		    PCI_REVISION(pa->pa_class) << PCI_REVISION_SHIFT);
2347acdc34dSpatrick 
2357acdc34dSpatrick 		pci_conf_write(pa->pa_pc, pa->pa_tag,
2367acdc34dSpatrick 		    AHCI_PCI_ATI_SB600_MAGIC, magic);
2377acdc34dSpatrick 	}
2387acdc34dSpatrick }
2397acdc34dSpatrick 
2407acdc34dSpatrick int
ahci_ati_sb600_attach(struct ahci_softc * sc,struct pci_attach_args * pa)2417acdc34dSpatrick ahci_ati_sb600_attach(struct ahci_softc *sc, struct pci_attach_args *pa)
2427acdc34dSpatrick {
2437acdc34dSpatrick 	ahci_ati_sb_idetoahci(sc, pa);
2447acdc34dSpatrick 
2457acdc34dSpatrick 	sc->sc_flags |= AHCI_F_IPMS_PROBE;
2467acdc34dSpatrick 
2477acdc34dSpatrick 	return (0);
2487acdc34dSpatrick }
2497acdc34dSpatrick 
2507acdc34dSpatrick int
ahci_ati_sb700_attach(struct ahci_softc * sc,struct pci_attach_args * pa)2517acdc34dSpatrick ahci_ati_sb700_attach(struct ahci_softc *sc, struct pci_attach_args *pa)
2527acdc34dSpatrick {
2537acdc34dSpatrick 	ahci_ati_sb_idetoahci(sc, pa);
2547acdc34dSpatrick 
2557acdc34dSpatrick 	sc->sc_flags |= AHCI_F_IPMS_PROBE;
2567acdc34dSpatrick 
2577acdc34dSpatrick 	return (0);
2587acdc34dSpatrick }
2597acdc34dSpatrick 
2607acdc34dSpatrick int
ahci_amd_hudson2_attach(struct ahci_softc * sc,struct pci_attach_args * pa)2617acdc34dSpatrick ahci_amd_hudson2_attach(struct ahci_softc *sc, struct pci_attach_args *pa)
2627acdc34dSpatrick {
2637acdc34dSpatrick 	ahci_ati_sb_idetoahci(sc, pa);
2647acdc34dSpatrick 
2657acdc34dSpatrick 	sc->sc_flags |= AHCI_F_IPMS_PROBE;
2667acdc34dSpatrick 
2677acdc34dSpatrick 	return (0);
2687acdc34dSpatrick }
2697acdc34dSpatrick 
2707acdc34dSpatrick int
ahci_intel_attach(struct ahci_softc * sc,struct pci_attach_args * pa)2717acdc34dSpatrick ahci_intel_attach(struct ahci_softc *sc, struct pci_attach_args *pa)
2727acdc34dSpatrick {
2737acdc34dSpatrick 	sc->sc_flags |= AHCI_F_NO_PMP;
2746f9e3f93Sbrad 
2757acdc34dSpatrick 	return (0);
2767acdc34dSpatrick }
2777acdc34dSpatrick 
2787acdc34dSpatrick int
ahci_samsung_attach(struct ahci_softc * sc,struct pci_attach_args * pa)27951a91e86Sgilles ahci_samsung_attach(struct ahci_softc *sc, struct pci_attach_args *pa)
28051a91e86Sgilles {
2816f9e3f93Sbrad 	/*
2826f9e3f93Sbrad 	 * Disable MSI with the Samsung S4LN053X01 SSD controller as found
2834cdd44ccSbrad 	 * in some Apple MacBook Air models such as the 6,1 and 6,2, as well
2844cdd44ccSbrad 	 * as the XP941 SSD controller.
2856f9e3f93Sbrad 	 * https://bugzilla.kernel.org/show_bug.cgi?id=60731
2864cdd44ccSbrad 	 * https://bugzilla.kernel.org/show_bug.cgi?id=89171
2876f9e3f93Sbrad 	 */
28851a91e86Sgilles 	sc->sc_flags |= AHCI_F_NO_MSI;
2896f9e3f93Sbrad 
29051a91e86Sgilles 	return (0);
29151a91e86Sgilles }
29251a91e86Sgilles 
29351a91e86Sgilles int
ahci_storx_attach(struct ahci_softc * sc,struct pci_attach_args * pa)294*9406b56eSkn ahci_storx_attach(struct ahci_softc *sc, struct pci_attach_args *pa)
295*9406b56eSkn {
296*9406b56eSkn 	/*
297*9406b56eSkn 	 * Disable MSI with the ZX-100/ZX-200/ZX-E StorX AHCI Controller
298*9406b56eSkn 	 * in the Unchartevice 6640MA notebook, otherwise ahci(4) hangs
299*9406b56eSkn 	 * with SATA speed set to "Gen3" in BIOS.
300*9406b56eSkn 	 */
301*9406b56eSkn 	sc->sc_flags |= AHCI_F_NO_MSI;
302*9406b56eSkn 
303*9406b56eSkn 	return (0);
304*9406b56eSkn }
305*9406b56eSkn 
306*9406b56eSkn int
ahci_pci_match(struct device * parent,void * match,void * aux)3077acdc34dSpatrick ahci_pci_match(struct device *parent, void *match, void *aux)
3087acdc34dSpatrick {
3097acdc34dSpatrick 	struct pci_attach_args		*pa = aux;
3107acdc34dSpatrick 	const struct ahci_device	*ad;
3117acdc34dSpatrick 
3127acdc34dSpatrick 	ad = ahci_lookup_device(pa);
3137acdc34dSpatrick 	if (ad != NULL) {
3147acdc34dSpatrick 		/* the device may need special checks to see if it matches */
3157acdc34dSpatrick 		if (ad->ad_match != NULL)
3167acdc34dSpatrick 			return (ad->ad_match(pa));
3177acdc34dSpatrick 
3187acdc34dSpatrick 		return (2); /* match higher than pciide */
3197acdc34dSpatrick 	}
3207acdc34dSpatrick 
3217acdc34dSpatrick 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE &&
3227acdc34dSpatrick 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_SATA &&
323e3ba7f78Skettenis 	    PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_SATA_AHCI10)
3247acdc34dSpatrick 		return (2);
3257acdc34dSpatrick 
3267acdc34dSpatrick 	return (0);
3277acdc34dSpatrick }
3287acdc34dSpatrick 
3297acdc34dSpatrick void
ahci_pci_attach(struct device * parent,struct device * self,void * aux)3307acdc34dSpatrick ahci_pci_attach(struct device *parent, struct device *self, void *aux)
3317acdc34dSpatrick {
3327acdc34dSpatrick 	struct ahci_pci_softc		*psc = (struct ahci_pci_softc *)self;
3337acdc34dSpatrick 	struct ahci_softc		*sc = &psc->psc_ahci;
3347acdc34dSpatrick 	struct pci_attach_args		*pa = aux;
3357acdc34dSpatrick 	const struct ahci_device	*ad;
3367acdc34dSpatrick 	pci_intr_handle_t		ih;
3377acdc34dSpatrick 
3387acdc34dSpatrick 	psc->psc_pc = pa->pa_pc;
3397acdc34dSpatrick 	psc->psc_tag = pa->pa_tag;
3407acdc34dSpatrick 	sc->sc_dmat = pa->pa_dmat;
3417acdc34dSpatrick 
3427acdc34dSpatrick 	ad = ahci_lookup_device(pa);
3437acdc34dSpatrick 	if (ad != NULL && ad->ad_attach != NULL) {
3447acdc34dSpatrick 		if (ad->ad_attach(sc, pa) != 0) {
3457acdc34dSpatrick 			/* error should be printed by ad_attach */
3467acdc34dSpatrick 			return;
3477acdc34dSpatrick 		}
3487acdc34dSpatrick 	}
3497acdc34dSpatrick 
350283198bfSbrad 	if (sc->sc_flags & AHCI_F_NO_MSI)
351283198bfSbrad 		pa->pa_flags &= ~PCI_FLAGS_MSI_ENABLED;
35251a91e86Sgilles 
353283198bfSbrad 	if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
3547acdc34dSpatrick 		printf(": unable to map interrupt\n");
3557acdc34dSpatrick 		return;
3567acdc34dSpatrick 	}
3577acdc34dSpatrick 	printf(": %s,", pci_intr_string(pa->pa_pc, ih));
3587acdc34dSpatrick 
3597acdc34dSpatrick 	if (ahci_map_regs(psc, pa) != 0) {
3607acdc34dSpatrick 		/* error already printed by ahci_map_regs */
3617acdc34dSpatrick 		return;
3627acdc34dSpatrick 	}
3637acdc34dSpatrick 
3647acdc34dSpatrick 	if (ahci_map_intr(psc, pa, ih) != 0) {
3657acdc34dSpatrick 		/* error already printed by ahci_map_intr */
3667acdc34dSpatrick 		goto unmap;
3677acdc34dSpatrick 	}
3687acdc34dSpatrick 
3697acdc34dSpatrick 	if (ahci_attach(sc) != 0) {
3707acdc34dSpatrick 		/* error printed by ahci_attach */
3717acdc34dSpatrick 		goto unmap;
3727acdc34dSpatrick 	}
3737acdc34dSpatrick 
3747acdc34dSpatrick 	return;
3757acdc34dSpatrick 
3767acdc34dSpatrick unmap:
3777acdc34dSpatrick 	ahci_unmap_regs(psc);
3787acdc34dSpatrick 	return;
3797acdc34dSpatrick }
3807acdc34dSpatrick 
3817acdc34dSpatrick int
ahci_pci_detach(struct device * self,int flags)3827acdc34dSpatrick ahci_pci_detach(struct device *self, int flags)
3837acdc34dSpatrick {
3847acdc34dSpatrick 	struct ahci_pci_softc		*psc = (struct ahci_pci_softc *)self;
3857acdc34dSpatrick 	struct ahci_softc		*sc = &psc->psc_ahci;
3867acdc34dSpatrick 
3877acdc34dSpatrick 	ahci_detach(sc, flags);
3887acdc34dSpatrick 
3897acdc34dSpatrick 	ahci_unmap_intr(psc);
3907acdc34dSpatrick 	ahci_unmap_regs(psc);
3917acdc34dSpatrick 
3927acdc34dSpatrick 	return (0);
3937acdc34dSpatrick }
3947acdc34dSpatrick 
3957acdc34dSpatrick int
ahci_map_regs(struct ahci_pci_softc * psc,struct pci_attach_args * pa)3967acdc34dSpatrick ahci_map_regs(struct ahci_pci_softc *psc, struct pci_attach_args *pa)
3977acdc34dSpatrick {
3987acdc34dSpatrick 	pcireg_t			maptype;
3997acdc34dSpatrick 	struct ahci_softc		*sc = &psc->psc_ahci;
4007acdc34dSpatrick 
4017acdc34dSpatrick 	maptype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, AHCI_PCI_BAR);
4027acdc34dSpatrick 	if (pci_mapreg_map(pa, AHCI_PCI_BAR, maptype, 0, &sc->sc_iot,
4037acdc34dSpatrick 	    &sc->sc_ioh, NULL, &sc->sc_ios, 0) != 0) {
4047acdc34dSpatrick 		printf(" unable to map registers\n");
4057acdc34dSpatrick 		return (1);
4067acdc34dSpatrick 	}
4077acdc34dSpatrick 
4087acdc34dSpatrick 	return (0);
4097acdc34dSpatrick }
4107acdc34dSpatrick 
4117acdc34dSpatrick void
ahci_unmap_regs(struct ahci_pci_softc * psc)4127acdc34dSpatrick ahci_unmap_regs(struct ahci_pci_softc *psc)
4137acdc34dSpatrick {
4147acdc34dSpatrick 	struct ahci_softc		*sc = &psc->psc_ahci;
4157acdc34dSpatrick 
4167acdc34dSpatrick 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
4177acdc34dSpatrick 	sc->sc_ios = 0;
4187acdc34dSpatrick }
4197acdc34dSpatrick 
4207acdc34dSpatrick int
ahci_map_intr(struct ahci_pci_softc * psc,struct pci_attach_args * pa,pci_intr_handle_t ih)4217acdc34dSpatrick ahci_map_intr(struct ahci_pci_softc *psc, struct pci_attach_args *pa,
4227acdc34dSpatrick     pci_intr_handle_t ih)
4237acdc34dSpatrick {
4247acdc34dSpatrick 	struct ahci_softc		*sc = &psc->psc_ahci;
4257acdc34dSpatrick 	sc->sc_ih = pci_intr_establish(psc->psc_pc, ih, IPL_BIO,
4267acdc34dSpatrick 	    ahci_intr, sc, DEVNAME(sc));
4277acdc34dSpatrick 	if (sc->sc_ih == NULL) {
4287acdc34dSpatrick 		printf("%s: unable to map interrupt\n", DEVNAME(sc));
4297acdc34dSpatrick 		return (1);
4307acdc34dSpatrick 	}
4317acdc34dSpatrick 
4327acdc34dSpatrick 	return (0);
4337acdc34dSpatrick }
4347acdc34dSpatrick 
4357acdc34dSpatrick void
ahci_unmap_intr(struct ahci_pci_softc * psc)4367acdc34dSpatrick ahci_unmap_intr(struct ahci_pci_softc *psc)
4377acdc34dSpatrick {
4387acdc34dSpatrick 	struct ahci_softc		*sc = &psc->psc_ahci;
4397acdc34dSpatrick 	pci_intr_disestablish(psc->psc_pc, sc->sc_ih);
4407acdc34dSpatrick }
4417acdc34dSpatrick 
4427acdc34dSpatrick int
ahci_pci_activate(struct device * self,int act)4437acdc34dSpatrick ahci_pci_activate(struct device *self, int act)
4447acdc34dSpatrick {
4457acdc34dSpatrick 	struct ahci_pci_softc		*psc = (struct ahci_pci_softc *)self;
4467acdc34dSpatrick 	struct ahci_softc		*sc = &psc->psc_ahci;
4477acdc34dSpatrick 	return ahci_activate((struct device *)sc, act);
4487acdc34dSpatrick }
449