xref: /openbsd-src/sys/dev/pci/qla_pci.c (revision 9593dc34da13a12012033a17061c846c208061c2)
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