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