1*9593dc34Smglocker /* $OpenBSD: qla_pci.c,v 1.11 2024/09/04 07:54:52 mglocker Exp $ */ 24cd89cf2Sjmatthew 34cd89cf2Sjmatthew /* 44cd89cf2Sjmatthew * Copyright (c) 2011 David Gwynne <dlg@openbsd.org> 54cd89cf2Sjmatthew * Copyright (c) 2013, 2014 Jonathan Matthew <jmatthew@openbsd.org> 64cd89cf2Sjmatthew * 74cd89cf2Sjmatthew * Permission to use, copy, modify, and distribute this software for any 84cd89cf2Sjmatthew * purpose with or without fee is hereby granted, provided that the above 94cd89cf2Sjmatthew * copyright notice and this permission notice appear in all copies. 104cd89cf2Sjmatthew * 114cd89cf2Sjmatthew * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 124cd89cf2Sjmatthew * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 134cd89cf2Sjmatthew * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 144cd89cf2Sjmatthew * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 154cd89cf2Sjmatthew * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 164cd89cf2Sjmatthew * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 174cd89cf2Sjmatthew * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 184cd89cf2Sjmatthew */ 194cd89cf2Sjmatthew 204cd89cf2Sjmatthew #include <sys/param.h> 214cd89cf2Sjmatthew #include <sys/systm.h> 224cd89cf2Sjmatthew #include <sys/device.h> 234cd89cf2Sjmatthew 244cd89cf2Sjmatthew #include <machine/bus.h> 254cd89cf2Sjmatthew 264cd89cf2Sjmatthew #include <dev/pci/pcireg.h> 274cd89cf2Sjmatthew #include <dev/pci/pcivar.h> 284cd89cf2Sjmatthew #include <dev/pci/pcidevs.h> 294cd89cf2Sjmatthew 304cd89cf2Sjmatthew #ifdef __sparc64__ 314cd89cf2Sjmatthew #include <dev/ofw/openfirm.h> 324cd89cf2Sjmatthew #endif 334cd89cf2Sjmatthew 344cd89cf2Sjmatthew #include <scsi/scsi_all.h> 354cd89cf2Sjmatthew #include <scsi/scsiconf.h> 364cd89cf2Sjmatthew 374cd89cf2Sjmatthew #include <dev/ic/qlareg.h> 384cd89cf2Sjmatthew #include <dev/ic/qlavar.h> 394cd89cf2Sjmatthew 404cd89cf2Sjmatthew #define QLA_PCI_MEM_BAR 0x14 414cd89cf2Sjmatthew #define QLA_PCI_IO_BAR 0x10 424cd89cf2Sjmatthew 434cd89cf2Sjmatthew int qla_pci_match(struct device *, void *, void *); 444cd89cf2Sjmatthew void qla_pci_attach(struct device *, struct device *, void *); 454cd89cf2Sjmatthew int qla_pci_detach(struct device *, int); 464cd89cf2Sjmatthew 474cd89cf2Sjmatthew struct qla_pci_softc { 484cd89cf2Sjmatthew struct qla_softc psc_qla; 494cd89cf2Sjmatthew 504cd89cf2Sjmatthew pci_chipset_tag_t psc_pc; 514cd89cf2Sjmatthew pcitag_t psc_tag; 524cd89cf2Sjmatthew 534cd89cf2Sjmatthew void *psc_ih; 544cd89cf2Sjmatthew }; 554cd89cf2Sjmatthew 568d2c75e4Smpi const struct cfattach qla_pci_ca = { 574cd89cf2Sjmatthew sizeof(struct qla_pci_softc), 584cd89cf2Sjmatthew qla_pci_match, 594cd89cf2Sjmatthew qla_pci_attach 604cd89cf2Sjmatthew }; 614cd89cf2Sjmatthew 624cd89cf2Sjmatthew #define PREAD(s, r) pci_conf_read((s)->psc_pc, (s)->psc_tag, (r)) 634cd89cf2Sjmatthew #define PWRITE(s, r, v) pci_conf_write((s)->psc_pc, (s)->psc_tag, (r), (v)) 644cd89cf2Sjmatthew 654cd89cf2Sjmatthew static const struct pci_matchid qla_devices[] = { 669eb00056Sjmatthew { PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP2100 }, 67db1d60ccSjmatthew { PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP2200 }, 684cd89cf2Sjmatthew { PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP2300 }, 694cd89cf2Sjmatthew { PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP2312 }, 704cd89cf2Sjmatthew { PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP2322 }, 714cd89cf2Sjmatthew { PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP6312 }, 72833e730fSbrad { PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP6322 }, 734cd89cf2Sjmatthew }; 744cd89cf2Sjmatthew 754cd89cf2Sjmatthew int 764cd89cf2Sjmatthew qla_pci_match(struct device *parent, void *match, void *aux) 774cd89cf2Sjmatthew { 784cd89cf2Sjmatthew return (pci_matchbyid(aux, qla_devices, nitems(qla_devices)) * 2); 794cd89cf2Sjmatthew } 804cd89cf2Sjmatthew 814cd89cf2Sjmatthew void 824cd89cf2Sjmatthew qla_pci_attach(struct device *parent, struct device *self, void *aux) 834cd89cf2Sjmatthew { 844cd89cf2Sjmatthew struct qla_pci_softc *psc = (void *)self; 854cd89cf2Sjmatthew struct qla_softc *sc = &psc->psc_qla; 864cd89cf2Sjmatthew struct pci_attach_args *pa = aux; 874cd89cf2Sjmatthew pci_intr_handle_t ih; 88ba6d46bdSkettenis const char *intrstr; 894cd89cf2Sjmatthew u_int32_t pcictl; 9007286c37Skettenis #ifdef __sparc64__ 9107286c37Skettenis u_int64_t wwn; 9207286c37Skettenis int node; 9307286c37Skettenis #endif 944cd89cf2Sjmatthew 954cd89cf2Sjmatthew pcireg_t bars[] = { QLA_PCI_MEM_BAR, QLA_PCI_IO_BAR }; 964cd89cf2Sjmatthew pcireg_t memtype; 974cd89cf2Sjmatthew int r; 984cd89cf2Sjmatthew 994cd89cf2Sjmatthew psc->psc_pc = pa->pa_pc; 1004cd89cf2Sjmatthew psc->psc_tag = pa->pa_tag; 1014cd89cf2Sjmatthew psc->psc_ih = NULL; 1024cd89cf2Sjmatthew sc->sc_dmat = pa->pa_dmat; 1034cd89cf2Sjmatthew sc->sc_ios = 0; 1044cd89cf2Sjmatthew 1054cd89cf2Sjmatthew for (r = 0; r < nitems(bars); r++) { 1064cd89cf2Sjmatthew memtype = pci_mapreg_type(psc->psc_pc, psc->psc_tag, bars[r]); 1074cd89cf2Sjmatthew if (pci_mapreg_map(pa, bars[r], memtype, 0, 1084cd89cf2Sjmatthew &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_ios, 0) == 0) 1094cd89cf2Sjmatthew break; 1104cd89cf2Sjmatthew 1114cd89cf2Sjmatthew sc->sc_ios = 0; 1124cd89cf2Sjmatthew } 1134cd89cf2Sjmatthew if (sc->sc_ios == 0) { 1144cd89cf2Sjmatthew printf(": unable to map registers\n"); 1154cd89cf2Sjmatthew return; 1164cd89cf2Sjmatthew } 1174cd89cf2Sjmatthew 1184cd89cf2Sjmatthew if (pci_intr_map(pa, &ih)) { 1194cd89cf2Sjmatthew printf(": unable to map interrupt\n"); 1204cd89cf2Sjmatthew goto unmap; 1214cd89cf2Sjmatthew } 122ba6d46bdSkettenis intrstr = pci_intr_string(psc->psc_pc, ih); 1234cd89cf2Sjmatthew psc->psc_ih = pci_intr_establish(psc->psc_pc, ih, IPL_BIO, 12443d6dcd9Sdlg qla_intr, sc, DEVNAME(sc)); 1254cd89cf2Sjmatthew if (psc->psc_ih == NULL) { 126ba6d46bdSkettenis printf(": unable to establish interrupt"); 127ba6d46bdSkettenis if (intrstr != NULL) 128ba6d46bdSkettenis printf(" at %s", intrstr); 129ba6d46bdSkettenis printf("\n"); 1304cd89cf2Sjmatthew goto deintr; 1314cd89cf2Sjmatthew } 1324cd89cf2Sjmatthew 133ba6d46bdSkettenis printf(": %s\n", intrstr); 134ba6d46bdSkettenis 1354cd89cf2Sjmatthew pcictl = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 1364cd89cf2Sjmatthew pcictl |= PCI_COMMAND_INVALIDATE_ENABLE | 1374cd89cf2Sjmatthew PCI_COMMAND_PARITY_ENABLE | PCI_COMMAND_SERR_ENABLE; 1384cd89cf2Sjmatthew /* fw manual says to enable bus master here, then disable it while 1394cd89cf2Sjmatthew * resetting.. hm. 1404cd89cf2Sjmatthew */ 1414cd89cf2Sjmatthew pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, pcictl); 1424cd89cf2Sjmatthew 1434cd89cf2Sjmatthew pcictl = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG); 1444cd89cf2Sjmatthew pcictl &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT); 1454cd89cf2Sjmatthew pcictl &= ~(PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT); 1464cd89cf2Sjmatthew pcictl |= (0x80 << PCI_LATTIMER_SHIFT); 1474cd89cf2Sjmatthew pcictl |= (0x10 << PCI_CACHELINE_SHIFT); 1484cd89cf2Sjmatthew pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG, pcictl); 1494cd89cf2Sjmatthew 1504cd89cf2Sjmatthew pcictl = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); 1514cd89cf2Sjmatthew pcictl &= ~1; 1524cd89cf2Sjmatthew pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, pcictl); 1534cd89cf2Sjmatthew 1544cd89cf2Sjmatthew switch (PCI_PRODUCT(pa->pa_id)) { 1554cd89cf2Sjmatthew case PCI_PRODUCT_QLOGIC_ISP2100: 1564cd89cf2Sjmatthew sc->sc_isp_gen = QLA_GEN_ISP2100; 1574cd89cf2Sjmatthew sc->sc_isp_type = QLA_ISP2100; 1584cd89cf2Sjmatthew break; 1594cd89cf2Sjmatthew 1604cd89cf2Sjmatthew case PCI_PRODUCT_QLOGIC_ISP2200: 1614cd89cf2Sjmatthew sc->sc_isp_gen = QLA_GEN_ISP2200; 1624cd89cf2Sjmatthew sc->sc_isp_type = QLA_ISP2200; 1634cd89cf2Sjmatthew break; 1644cd89cf2Sjmatthew 1654cd89cf2Sjmatthew case PCI_PRODUCT_QLOGIC_ISP2300: 1664cd89cf2Sjmatthew sc->sc_isp_type = QLA_ISP2300; 1674cd89cf2Sjmatthew sc->sc_isp_gen = QLA_GEN_ISP23XX; 1684cd89cf2Sjmatthew break; 1694cd89cf2Sjmatthew 1704cd89cf2Sjmatthew case PCI_PRODUCT_QLOGIC_ISP2312: 1714cd89cf2Sjmatthew case PCI_PRODUCT_QLOGIC_ISP6312: 1724cd89cf2Sjmatthew sc->sc_isp_type = QLA_ISP2312; 1734cd89cf2Sjmatthew sc->sc_isp_gen = QLA_GEN_ISP23XX; 1744cd89cf2Sjmatthew break; 1754cd89cf2Sjmatthew 1764cd89cf2Sjmatthew case PCI_PRODUCT_QLOGIC_ISP2322: 177833e730fSbrad case PCI_PRODUCT_QLOGIC_ISP6322: 1784cd89cf2Sjmatthew sc->sc_isp_type = QLA_ISP2322; 1794cd89cf2Sjmatthew sc->sc_isp_gen = QLA_GEN_ISP23XX; 1804cd89cf2Sjmatthew break; 1814cd89cf2Sjmatthew 1824cd89cf2Sjmatthew default: 1834cd89cf2Sjmatthew printf("unknown pci id %x", pa->pa_id); 1844cd89cf2Sjmatthew return; 1854cd89cf2Sjmatthew } 1864cd89cf2Sjmatthew 18707286c37Skettenis #ifdef __sparc64__ 18807286c37Skettenis node = PCITAG_NODE(pa->pa_tag); 18907286c37Skettenis if (OF_getprop(node, "port-wwn", &wwn, sizeof(wwn)) == sizeof(wwn)) 19007286c37Skettenis sc->sc_port_name = wwn; 19107286c37Skettenis if (OF_getprop(node, "node-wwn", &wwn, sizeof(wwn)) == sizeof(wwn)) 19207286c37Skettenis sc->sc_node_name = wwn; 19307286c37Skettenis #endif 19407286c37Skettenis 1954cd89cf2Sjmatthew sc->sc_port = pa->pa_function; 1964cd89cf2Sjmatthew 1974cd89cf2Sjmatthew if (qla_attach(sc) != 0) { 1984cd89cf2Sjmatthew /* error printed by qla_attach */ 1994cd89cf2Sjmatthew goto deintr; 2004cd89cf2Sjmatthew } 2014cd89cf2Sjmatthew 2024cd89cf2Sjmatthew return; 2034cd89cf2Sjmatthew 2044cd89cf2Sjmatthew deintr: 2054cd89cf2Sjmatthew pci_intr_disestablish(psc->psc_pc, psc->psc_ih); 2064cd89cf2Sjmatthew psc->psc_ih = NULL; 2074cd89cf2Sjmatthew unmap: 2084cd89cf2Sjmatthew bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); 2094cd89cf2Sjmatthew sc->sc_ios = 0; 2104cd89cf2Sjmatthew } 2114cd89cf2Sjmatthew 2124cd89cf2Sjmatthew int 2134cd89cf2Sjmatthew qla_pci_detach(struct device *self, int flags) 2144cd89cf2Sjmatthew { 2154cd89cf2Sjmatthew struct qla_pci_softc *psc = (struct qla_pci_softc *)self; 2164cd89cf2Sjmatthew struct qla_softc *sc = &psc->psc_qla; 2174cd89cf2Sjmatthew int rv; 2184cd89cf2Sjmatthew 2194cd89cf2Sjmatthew if (psc->psc_ih == NULL) { 220*9593dc34Smglocker /* we didn't attach properly, so nothing to detach */ 2214cd89cf2Sjmatthew return (0); 2224cd89cf2Sjmatthew } 2234cd89cf2Sjmatthew 2244cd89cf2Sjmatthew rv = qla_detach(sc, flags); 2254cd89cf2Sjmatthew if (rv != 0) 2264cd89cf2Sjmatthew return (rv); 2274cd89cf2Sjmatthew 2284cd89cf2Sjmatthew pci_intr_disestablish(psc->psc_pc, psc->psc_ih); 2294cd89cf2Sjmatthew psc->psc_ih = NULL; 2304cd89cf2Sjmatthew 2314cd89cf2Sjmatthew bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); 2324cd89cf2Sjmatthew sc->sc_ios = 0; 2334cd89cf2Sjmatthew 2344cd89cf2Sjmatthew return (0); 2354cd89cf2Sjmatthew } 236