xref: /openbsd/sys/dev/sbus/qla_sbus.c (revision 09467b48)
1 /*	$OpenBSD: qla_sbus.c,v 1.2 2014/07/12 18:48:52 tedu Exp $	*/
2 /*
3  * Copyright (c) 2014 Mark Kettenis
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/device.h>
20 #include <sys/malloc.h>
21 #include <sys/systm.h>
22 
23 #include <machine/bus.h>
24 #include <machine/intr.h>
25 #include <machine/autoconf.h>
26 
27 #include <dev/sbus/sbusvar.h>
28 #include <dev/pci/pcireg.h>
29 #include <dev/pci/pcivar.h>
30 #include <dev/pci/pcidevs.h>
31 
32 #include <scsi/scsi_all.h>
33 #include <scsi/scsiconf.h>
34 
35 #include <dev/ic/qlareg.h>
36 #include <dev/ic/qlavar.h>
37 
38 #define QLA_SBUS_REG_OFFSET	0x100
39 #define QLA_SBUS_REG_SIZE	0x300
40 
41 int	qla_sbus_match(struct device *, void *, void *);
42 void	qla_sbus_attach(struct device *, struct device *, void *);
43 
44 struct cfattach qla_sbus_ca = {
45 	sizeof(struct qla_softc),
46 	qla_sbus_match,
47 	qla_sbus_attach
48 };
49 
50 int
51 qla_sbus_match(struct device *parent, void *cf, void *aux)
52 {
53 	struct sbus_attach_args *sa = aux;
54 
55 	if (strcmp("SUNW,qlc", sa->sa_name) == 0 ||
56 	    strcmp("QLGC,qla", sa->sa_name) == 0)
57 		return 2;
58 
59 	return 0;
60 }
61 
62 void
63 qla_sbus_attach(struct device *parent, struct device *self, void *aux)
64 {
65 	struct qla_softc *sc = (void *)self;
66 	struct sbus_attach_args *sa = aux;
67 	struct sparc_bus_space_tag *iot;
68 	bus_space_handle_t ioh;
69 	pcireg_t id, class;
70 	char devinfo[256];
71 
72 	if (sa->sa_nintr < 1) {
73 		printf(": no interrupt\n");
74 		return;
75 	}
76 
77 	if (sa->sa_nreg < 1) {
78 		printf(": no registers\n");
79 		return;
80 	}
81 
82 	/*
83 	 * These cards have a standard PCI chips that sit behind an
84 	 * FPGA with some bridging logic.  Since the PCI bus is
85 	 * little-endian, we need a little-endian bus tag.  So we
86 	 * build one here.
87 	 */
88 	iot = malloc(sizeof(*iot), M_DEVBUF, M_NOWAIT);
89 	if (iot == NULL) {
90 		printf(": can't allocate bus tag\n");
91 		return;
92 	}
93 	*iot = *sa->sa_bustag;
94 	iot->asi = ASI_PRIMARY_LITTLE;
95 
96 	if (sbus_bus_map(iot, sa->sa_slot, sa->sa_offset,
97 	    sa->sa_size, 0, 0, &ioh) != 0) {
98 		printf(": can't map registers\n");
99 		goto free;
100 	}
101 
102 	/*
103 	 * PCI config space is mapped at the start of the SBus
104 	 * register space.  We use it to identify the ISP chip.
105 	 */
106 	id = bus_space_read_4(iot, ioh, PCI_ID_REG);
107 	class = bus_space_read_4(iot, ioh, PCI_CLASS_REG);
108 
109 	pci_devinfo(id, class, 0, devinfo, sizeof(devinfo));
110 	printf(": %s\n", devinfo);
111 
112 	switch (PCI_PRODUCT(id)) {
113 	case PCI_PRODUCT_QLOGIC_ISP2200:
114 		sc->sc_isp_gen = QLA_GEN_ISP2200;
115 		sc->sc_isp_type = QLA_ISP2200;
116 		break;
117 
118 	case PCI_PRODUCT_QLOGIC_ISP2300:
119 		sc->sc_isp_gen = QLA_GEN_ISP23XX;
120 		sc->sc_isp_type = QLA_ISP2300;
121 		break;
122 
123 	case PCI_PRODUCT_QLOGIC_ISP2312:
124 		sc->sc_isp_gen = QLA_GEN_ISP23XX;
125 		sc->sc_isp_type = QLA_ISP2312;
126 		break;
127 
128 	default:
129 		printf("%s: unsupported ISP chip\n", DEVNAME(sc));
130 		goto unmap;
131 	}
132 
133 	if (bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_BIO, 0,
134 	    qla_intr, sc, sc->sc_dev.dv_xname) == NULL) {
135 		printf("%s: can't establish interrupt\n", DEVNAME(sc));
136 		goto unmap;
137 	}
138 
139 	if (bus_space_subregion(iot, ioh, QLA_SBUS_REG_OFFSET,
140 	    QLA_SBUS_REG_SIZE, &sc->sc_ioh) != 0) {
141 		printf("%s: can't submap registers\n", DEVNAME(sc));
142 		goto unmap;
143 	}
144 
145 	sc->sc_iot = iot;
146 	sc->sc_ios = QLA_SBUS_REG_SIZE;
147 	sc->sc_dmat = sa->sa_dmatag;
148 
149 	qla_attach(sc);
150 	return;
151 
152 unmap:
153 	bus_space_unmap(iot, ioh, sa->sa_size);
154 free:
155 	free(iot, M_DEVBUF, 0);
156 }
157