xref: /openbsd-src/sys/dev/pci/qlw_pci.c (revision 9593dc34da13a12012033a17061c846c208061c2)
1*9593dc34Smglocker /*	$OpenBSD: qlw_pci.c,v 1.14 2024/09/04 07:54:52 mglocker Exp $ */
2c0265cf2Skettenis 
3c0265cf2Skettenis /*
4c0265cf2Skettenis  * Copyright (c) 2011 David Gwynne <dlg@openbsd.org>
5c0265cf2Skettenis  * Copyright (c) 2013, 2014 Jonathan Matthew <jmatthew@openbsd.org>
6c0265cf2Skettenis  * Copyright (c) 2014 Mark Kettenis <kettenis@openbsd.org>
7c0265cf2Skettenis  *
8c0265cf2Skettenis  * Permission to use, copy, modify, and distribute this software for any
9c0265cf2Skettenis  * purpose with or without fee is hereby granted, provided that the above
10c0265cf2Skettenis  * copyright notice and this permission notice appear in all copies.
11c0265cf2Skettenis  *
12c0265cf2Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13c0265cf2Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14c0265cf2Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15c0265cf2Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16c0265cf2Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17c0265cf2Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18c0265cf2Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19c0265cf2Skettenis  */
20c0265cf2Skettenis 
21c0265cf2Skettenis #include <sys/param.h>
22c0265cf2Skettenis #include <sys/systm.h>
23c0265cf2Skettenis #include <sys/device.h>
24c0265cf2Skettenis 
25c0265cf2Skettenis #include <machine/bus.h>
26c0265cf2Skettenis 
27c0265cf2Skettenis #include <dev/pci/pcireg.h>
28c0265cf2Skettenis #include <dev/pci/pcivar.h>
29c0265cf2Skettenis #include <dev/pci/pcidevs.h>
30c0265cf2Skettenis 
31c0265cf2Skettenis #ifdef __sparc64__
32c0265cf2Skettenis #include <dev/ofw/openfirm.h>
33c0265cf2Skettenis #endif
34c0265cf2Skettenis 
35c0265cf2Skettenis #include <scsi/scsi_all.h>
36c0265cf2Skettenis #include <scsi/scsiconf.h>
37c0265cf2Skettenis 
38c0265cf2Skettenis #include <dev/ic/qlwreg.h>
39c0265cf2Skettenis #include <dev/ic/qlwvar.h>
40c0265cf2Skettenis 
41c0265cf2Skettenis #ifndef ISP_NOFIRMWARE
42c0265cf2Skettenis #include <dev/microcode/isp/asm_1040.h>
43c0265cf2Skettenis #include <dev/microcode/isp/asm_1080.h>
44c0265cf2Skettenis #include <dev/microcode/isp/asm_12160.h>
45c0265cf2Skettenis #endif
46c0265cf2Skettenis 
47c0265cf2Skettenis #define QLW_PCI_MEM_BAR		0x14
48c0265cf2Skettenis #define QLW_PCI_IO_BAR		0x10
49c0265cf2Skettenis 
50c0265cf2Skettenis int	qlw_pci_match(struct device *, void *, void *);
51c0265cf2Skettenis void	qlw_pci_attach(struct device *, struct device *, void *);
52c0265cf2Skettenis int	qlw_pci_detach(struct device *, int);
53c0265cf2Skettenis 
54c0265cf2Skettenis struct qlw_pci_softc {
55c0265cf2Skettenis 	struct qlw_softc	psc_qlw;
56c0265cf2Skettenis 
57c0265cf2Skettenis 	pci_chipset_tag_t	psc_pc;
58c0265cf2Skettenis 	pcitag_t		psc_tag;
59c0265cf2Skettenis 
60c0265cf2Skettenis 	void			*psc_ih;
61c0265cf2Skettenis };
62c0265cf2Skettenis 
638d2c75e4Smpi const struct cfattach qlw_pci_ca = {
64c0265cf2Skettenis 	sizeof(struct qlw_pci_softc),
65c0265cf2Skettenis 	qlw_pci_match,
66c0265cf2Skettenis 	qlw_pci_attach
67c0265cf2Skettenis };
68c0265cf2Skettenis 
69c0265cf2Skettenis static const struct pci_matchid qlw_devices[] = {
70c0265cf2Skettenis 	{ PCI_VENDOR_QLOGIC,	PCI_PRODUCT_QLOGIC_ISP1020 },
71c0265cf2Skettenis 	{ PCI_VENDOR_QLOGIC,	PCI_PRODUCT_QLOGIC_ISP1240 },
72c0265cf2Skettenis 	{ PCI_VENDOR_QLOGIC,	PCI_PRODUCT_QLOGIC_ISP1080 },
73c0265cf2Skettenis 	{ PCI_VENDOR_QLOGIC,	PCI_PRODUCT_QLOGIC_ISP1280 },
74c0265cf2Skettenis 	{ PCI_VENDOR_QLOGIC,	PCI_PRODUCT_QLOGIC_ISP10160 },
75c0265cf2Skettenis 	{ PCI_VENDOR_QLOGIC,	PCI_PRODUCT_QLOGIC_ISP12160 },
76c0265cf2Skettenis };
77c0265cf2Skettenis 
78c0265cf2Skettenis int
79c0265cf2Skettenis qlw_pci_match(struct device *parent, void *match, void *aux)
80c0265cf2Skettenis {
8105d7a5f2Skettenis 	struct pci_attach_args *pa = aux;
8205d7a5f2Skettenis 
8305d7a5f2Skettenis 	/* Silly AMI MegaRAID exposes its ISP12160 to us. */
845d4e46a1Sjsg 	if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_QLOGIC_ISP12160) {
8505d7a5f2Skettenis 		pcireg_t subid;
8605d7a5f2Skettenis 
8705d7a5f2Skettenis 		subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBVEND_0);
8805d7a5f2Skettenis 		if (PCI_VENDOR(subid) == PCI_VENDOR_AMI)
8905d7a5f2Skettenis 			return (0);
9005d7a5f2Skettenis 	}
9105d7a5f2Skettenis 
92c0265cf2Skettenis 	return (pci_matchbyid(aux, qlw_devices, nitems(qlw_devices)) * 2);
93c0265cf2Skettenis }
94c0265cf2Skettenis 
95c0265cf2Skettenis void
96c0265cf2Skettenis qlw_pci_attach(struct device *parent, struct device *self, void *aux)
97c0265cf2Skettenis {
98c0265cf2Skettenis 	struct qlw_pci_softc *psc = (void *)self;
99c0265cf2Skettenis 	struct qlw_softc *sc = &psc->psc_qlw;
100c0265cf2Skettenis 	struct pci_attach_args *pa = aux;
101c0265cf2Skettenis 	pci_intr_handle_t ih;
102ba6d46bdSkettenis 	const char *intrstr;
103c0265cf2Skettenis 	u_int32_t pcictl;
10442de16feSkettenis #ifdef __sparc64__
10542de16feSkettenis 	int node, initiator;
10642de16feSkettenis #endif
107c0265cf2Skettenis 
108c0265cf2Skettenis 	pcireg_t bars[] = { QLW_PCI_MEM_BAR, QLW_PCI_IO_BAR };
109c0265cf2Skettenis 	pcireg_t memtype;
110c0265cf2Skettenis 	int r;
111c0265cf2Skettenis 
112c0265cf2Skettenis 	psc->psc_pc = pa->pa_pc;
113c0265cf2Skettenis 	psc->psc_tag = pa->pa_tag;
114c0265cf2Skettenis 	psc->psc_ih = NULL;
115c0265cf2Skettenis 	sc->sc_dmat = pa->pa_dmat;
116c0265cf2Skettenis 	sc->sc_ios = 0;
117c0265cf2Skettenis 
118c0265cf2Skettenis 	for (r = 0; r < nitems(bars); r++) {
119c0265cf2Skettenis 		memtype = pci_mapreg_type(psc->psc_pc, psc->psc_tag, bars[r]);
120c0265cf2Skettenis 		if (pci_mapreg_map(pa, bars[r], memtype, 0,
121c0265cf2Skettenis 		    &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_ios, 0) == 0)
122c0265cf2Skettenis 			break;
123c0265cf2Skettenis 
124c0265cf2Skettenis 		sc->sc_ios = 0;
125c0265cf2Skettenis 	}
126c0265cf2Skettenis 	if (sc->sc_ios == 0) {
127c0265cf2Skettenis 		printf(": unable to map registers\n");
128c0265cf2Skettenis 		return;
129c0265cf2Skettenis 	}
130c0265cf2Skettenis 
131c0265cf2Skettenis 	if (pci_intr_map(pa, &ih)) {
132c0265cf2Skettenis 		printf(": unable to map interrupt\n");
133c0265cf2Skettenis 		goto unmap;
134c0265cf2Skettenis 	}
135ba6d46bdSkettenis 	intrstr = pci_intr_string(psc->psc_pc, ih);
136c0265cf2Skettenis 	psc->psc_ih = pci_intr_establish(psc->psc_pc, ih, IPL_BIO,
137c0265cf2Skettenis 	    qlw_intr, sc, DEVNAME(sc));
138c0265cf2Skettenis 	if (psc->psc_ih == NULL) {
139ba6d46bdSkettenis 		printf(": unable to establish interrupt");
140ba6d46bdSkettenis 		if (intrstr != NULL)
141ba6d46bdSkettenis 			printf(" at %s", intrstr);
142ba6d46bdSkettenis 		printf("\n");
143c0265cf2Skettenis 		goto deintr;
144c0265cf2Skettenis 	}
145c0265cf2Skettenis 
146ba6d46bdSkettenis 	printf(": %s\n", intrstr);
147ba6d46bdSkettenis 
148c0265cf2Skettenis 	pcictl = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
149c0265cf2Skettenis 	pcictl |= PCI_COMMAND_INVALIDATE_ENABLE |
150c0265cf2Skettenis 	    PCI_COMMAND_PARITY_ENABLE | PCI_COMMAND_SERR_ENABLE;
151c0265cf2Skettenis 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, pcictl);
152c0265cf2Skettenis 
153c0265cf2Skettenis 	pcictl = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG);
154c0265cf2Skettenis 	pcictl &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
155c0265cf2Skettenis 	pcictl &= ~(PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT);
156c0265cf2Skettenis 	pcictl |= (0x80 << PCI_LATTIMER_SHIFT);
157c0265cf2Skettenis 	pcictl |= (0x10 << PCI_CACHELINE_SHIFT);
158c0265cf2Skettenis 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG, pcictl);
159c0265cf2Skettenis 
160c0265cf2Skettenis 	pcictl = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
161c0265cf2Skettenis 	pcictl &= ~1;
162c0265cf2Skettenis 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, pcictl);
163c0265cf2Skettenis 
164c0265cf2Skettenis 	switch (PCI_PRODUCT(pa->pa_id)) {
165c0265cf2Skettenis 	case PCI_PRODUCT_QLOGIC_ISP1020:
166c0265cf2Skettenis 		sc->sc_isp_gen = QLW_GEN_ISP1040;
167fdfcaeaeSkettenis 		switch (PCI_REVISION(pa->pa_class)) {
168fdfcaeaeSkettenis 		case 0:
169fdfcaeaeSkettenis 			sc->sc_isp_type = QLW_ISP1020;
170fdfcaeaeSkettenis 			break;
171fdfcaeaeSkettenis 		case 1:
172fdfcaeaeSkettenis 			sc->sc_isp_type = QLW_ISP1020A;
173fdfcaeaeSkettenis 			break;
174fdfcaeaeSkettenis 		case 2:
175c0265cf2Skettenis 			sc->sc_isp_type = QLW_ISP1040;
176fdfcaeaeSkettenis 			break;
177fdfcaeaeSkettenis 		case 3:
178fdfcaeaeSkettenis 			sc->sc_isp_type = QLW_ISP1040A;
179fdfcaeaeSkettenis 			break;
180fdfcaeaeSkettenis 		case 4:
181fdfcaeaeSkettenis 			sc->sc_isp_type = QLW_ISP1040B;
182fdfcaeaeSkettenis 			break;
183fdfcaeaeSkettenis 		case 5:
184fdfcaeaeSkettenis 		default:
185fdfcaeaeSkettenis 			sc->sc_isp_type = QLW_ISP1040C;
186fdfcaeaeSkettenis 			break;
187fdfcaeaeSkettenis 		}
188c0265cf2Skettenis 		sc->sc_numbusses = 1;
189d6f4d5a2Skettenis 		if (PCI_REVISION(pa->pa_class) < 2)
190d6f4d5a2Skettenis 			sc->sc_clock = 40; /* ISP1020/1020A */
191d6f4d5a2Skettenis 		else
192d6f4d5a2Skettenis 			sc->sc_clock = 60; /* ISP1040/1040A/1040B/1040C */
193c0265cf2Skettenis 		break;
194c0265cf2Skettenis 
195c0265cf2Skettenis 	case PCI_PRODUCT_QLOGIC_ISP1240:
196c0265cf2Skettenis 		sc->sc_isp_gen = QLW_GEN_ISP1080;
197c0265cf2Skettenis 		sc->sc_isp_type = QLW_ISP1240;
198c0265cf2Skettenis 		sc->sc_numbusses = 2;
199c0265cf2Skettenis 		sc->sc_clock = 60;
200c0265cf2Skettenis 		break;
201c0265cf2Skettenis 
202c0265cf2Skettenis 	case PCI_PRODUCT_QLOGIC_ISP1080:
203c0265cf2Skettenis 		sc->sc_isp_gen = QLW_GEN_ISP1080;
204c0265cf2Skettenis 		sc->sc_isp_type = QLW_ISP1080;
205c0265cf2Skettenis 		sc->sc_numbusses = 1;
206c0265cf2Skettenis 		sc->sc_clock = 100;
207c0265cf2Skettenis 		break;
208c0265cf2Skettenis 
209c0265cf2Skettenis 	case PCI_PRODUCT_QLOGIC_ISP1280:
210c0265cf2Skettenis 		sc->sc_isp_gen = QLW_GEN_ISP1080;
211c0265cf2Skettenis 		sc->sc_isp_type = QLW_ISP1280;
212c0265cf2Skettenis 		sc->sc_numbusses = 2;
213c0265cf2Skettenis 		sc->sc_clock = 100;
214c0265cf2Skettenis 		break;
215c0265cf2Skettenis 
216c0265cf2Skettenis 	case PCI_PRODUCT_QLOGIC_ISP10160:
217c0265cf2Skettenis 		sc->sc_isp_gen = QLW_GEN_ISP12160;
218c0265cf2Skettenis 		sc->sc_isp_type = QLW_ISP10160;
219c0265cf2Skettenis 		sc->sc_numbusses = 1;
220c0265cf2Skettenis 		sc->sc_clock = 100;
221c0265cf2Skettenis 		break;
222c0265cf2Skettenis 
223c0265cf2Skettenis 	case PCI_PRODUCT_QLOGIC_ISP12160:
224c0265cf2Skettenis 		sc->sc_isp_gen = QLW_GEN_ISP12160;
225c0265cf2Skettenis 		sc->sc_isp_type = QLW_ISP12160;
226c0265cf2Skettenis 		sc->sc_numbusses = 2;
227c0265cf2Skettenis 		sc->sc_clock = 100;
228c0265cf2Skettenis 		break;
229c0265cf2Skettenis 
230c0265cf2Skettenis 	default:
231c0265cf2Skettenis 		printf("unknown pci id %x", pa->pa_id);
232c0265cf2Skettenis 		return;
233c0265cf2Skettenis 	}
234c0265cf2Skettenis 
235c0265cf2Skettenis #ifndef ISP_NOFIRMWARE
236c0265cf2Skettenis 	switch (sc->sc_isp_gen) {
237c0265cf2Skettenis 	case QLW_GEN_ISP1040:
238c0265cf2Skettenis 		sc->sc_firmware = isp_1040_risc_code;
239c0265cf2Skettenis 		break;
240c0265cf2Skettenis 	case QLW_GEN_ISP1080:
241c0265cf2Skettenis 		sc->sc_firmware = isp_1080_risc_code;
242c0265cf2Skettenis 		break;
243c0265cf2Skettenis 	case QLW_GEN_ISP12160:
244c0265cf2Skettenis 		sc->sc_firmware = isp_12160_risc_code;
245c0265cf2Skettenis 		break;
246e753b624Skettenis 	default:
247e753b624Skettenis 		break;
248c0265cf2Skettenis 	}
249c0265cf2Skettenis #endif
250c0265cf2Skettenis 
25142de16feSkettenis 	/*
252bfc185c1Svisa 	 * The standard SCSI initiator ID is 7.
25342de16feSkettenis 	 * Add-on cards should have a valid nvram, which will override
25442de16feSkettenis 	 * these defaults.
25542de16feSkettenis 	 */
25642de16feSkettenis 	sc->sc_initiator[0] = sc->sc_initiator[1] = 7;
25742de16feSkettenis 
25842de16feSkettenis #ifdef __sparc64__
25942de16feSkettenis 	/*
26042de16feSkettenis 	 * Walk up the Open Firmware device tree until we find a
26142de16feSkettenis 	 * "scsi-initiator-id" property.
26242de16feSkettenis 	 */
26342de16feSkettenis 	node = PCITAG_NODE(pa->pa_tag);
26442de16feSkettenis 	while (node) {
26542de16feSkettenis 		if (OF_getprop(node, "scsi-initiator-id",
26642de16feSkettenis 		    &initiator, sizeof(initiator)) == sizeof(initiator)) {
2671d0a0664Skettenis 			/*
2681d0a0664Skettenis 			 * Override the SCSI initiator ID provided by
2691d0a0664Skettenis 			 * the nvram.
2701d0a0664Skettenis 			 */
2711d0a0664Skettenis 			sc->sc_flags |= QLW_FLAG_INITIATOR;
27242de16feSkettenis 			sc->sc_initiator[0] = sc->sc_initiator[1] = initiator;
27342de16feSkettenis 			break;
27442de16feSkettenis 		}
27542de16feSkettenis 		node = OF_parent(node);
27642de16feSkettenis 	}
27742de16feSkettenis #endif
27842de16feSkettenis 
279e753b624Skettenis 	sc->sc_host_cmd_ctrl = QLW_HOST_CMD_CTRL_PCI;
280e753b624Skettenis 	sc->sc_mbox_base = QLW_MBOX_BASE_PCI;
281e753b624Skettenis 
282c0265cf2Skettenis 	if (qlw_attach(sc) != 0) {
283c0265cf2Skettenis 		/* error printed by qlw_attach */
284c0265cf2Skettenis 		goto deintr;
285c0265cf2Skettenis 	}
286c0265cf2Skettenis 
287c0265cf2Skettenis 	return;
288c0265cf2Skettenis 
289c0265cf2Skettenis deintr:
290c0265cf2Skettenis 	pci_intr_disestablish(psc->psc_pc, psc->psc_ih);
291c0265cf2Skettenis 	psc->psc_ih = NULL;
292c0265cf2Skettenis unmap:
293c0265cf2Skettenis 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
294c0265cf2Skettenis 	sc->sc_ios = 0;
295c0265cf2Skettenis }
296c0265cf2Skettenis 
297c0265cf2Skettenis int
298c0265cf2Skettenis qlw_pci_detach(struct device *self, int flags)
299c0265cf2Skettenis {
300c0265cf2Skettenis 	struct qlw_pci_softc *psc = (struct qlw_pci_softc *)self;
301c0265cf2Skettenis 	struct qlw_softc *sc = &psc->psc_qlw;
302c0265cf2Skettenis 	int rv;
303c0265cf2Skettenis 
304c0265cf2Skettenis 	if (psc->psc_ih == NULL) {
305*9593dc34Smglocker 		/* we didn't attach properly, so nothing to detach */
306c0265cf2Skettenis 		return (0);
307c0265cf2Skettenis 	}
308c0265cf2Skettenis 
309c0265cf2Skettenis 	rv = qlw_detach(sc, flags);
310c0265cf2Skettenis 	if (rv != 0)
311c0265cf2Skettenis 		return (rv);
312c0265cf2Skettenis 
313c0265cf2Skettenis 	pci_intr_disestablish(psc->psc_pc, psc->psc_ih);
314c0265cf2Skettenis 	psc->psc_ih = NULL;
315c0265cf2Skettenis 
316c0265cf2Skettenis 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
317c0265cf2Skettenis 	sc->sc_ios = 0;
318c0265cf2Skettenis 
319c0265cf2Skettenis 	return (0);
320c0265cf2Skettenis }
321