xref: /openbsd/sys/dev/pci/ami_pci.c (revision 0f9891f1)
1 /*	$OpenBSD: ami_pci.c,v 1.46 2024/05/24 06:02:53 jsg Exp $	*/
2 
3 /*
4  * Copyright (c) 2001 Michael Shalayeff
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/device.h>
32 #include <sys/rwlock.h>
33 
34 #include <dev/pci/pcidevs.h>
35 #include <dev/pci/pcivar.h>
36 
37 #include <machine/bus.h>
38 
39 #include <scsi/scsi_all.h>
40 #include <scsi/scsi_disk.h>
41 #include <scsi/scsiconf.h>
42 
43 #include <dev/biovar.h>
44 #include <dev/ic/amireg.h>
45 #include <dev/ic/amivar.h>
46 
47 #define	AMI_BAR		PCI_MAPREG_START
48 #define	AMI_PCI_MEMSIZE	0x1000
49 
50 /* "Quartz" i960 Config space */
51 #define	AMI_PCI_INIT	0x9c
52 #define		AMI_INITSTAT(i)	(((i) >>  8) & 0xff)
53 #define		AMI_INITTARG(i)	(((i) >> 16) & 0xff)
54 #define		AMI_INITCHAN(i)	(((i) >> 24) & 0xff)
55 #define	AMI_PCI_SIG	0xa0
56 #define		AMI_SIGNATURE_1	0xcccc		/* older adapters */
57 #define		AMI_SIGNATURE_2	0x3344		/* newer adapters */
58 #define	AMI_PCI_SGL	0xa4
59 #define		AMI_SGL_LHC	0x00000299
60 #define		AMI_SGL_HLC	0x00000199
61 
62 int	ami_pci_find_device(void *);
63 int	ami_pci_match(struct device *, void *, void *);
64 void	ami_pci_attach(struct device *, struct device *, void *);
65 
66 const struct cfattach ami_pci_ca = {
67 	sizeof(struct ami_softc), ami_pci_match, ami_pci_attach
68 };
69 
70 static const
71 struct	ami_pci_device {
72 	int	vendor;
73 	int	product;
74 	int	flags;
75 } ami_pci_devices[] = {
76 	{ PCI_VENDOR_AMI,	PCI_PRODUCT_AMI_MEGARAID,	0 },
77 	{ PCI_VENDOR_AMI,	PCI_PRODUCT_AMI_MEGARAID428,	AMI_BROKEN },
78 	{ PCI_VENDOR_AMI,	PCI_PRODUCT_AMI_MEGARAID434,	AMI_BROKEN },
79 	{ PCI_VENDOR_DELL,	PCI_PRODUCT_DELL_PERC_4DI,	0 },
80 	{ PCI_VENDOR_DELL,	PCI_PRODUCT_DELL_PERC_4DI_2,	0 },
81 	{ PCI_VENDOR_DELL,	PCI_PRODUCT_DELL_PERC_4EDI,	0 },
82 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_80960RP_ATU,
83 	    AMI_CHECK_SIGN | AMI_BROKEN },
84 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID,		0 },
85 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_320,	0 },
86 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_3202E,	0 },
87 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID_SATA,	0 },
88 	{ 0 }
89 };
90 
91 static const
92 struct	ami_pci_subsys {
93 	pcireg_t	id;
94 	const char	*name;
95 	int		flags;
96 } ami_pci_subsys[] = {
97 	/* only those of a special name or quirk are listed here */
98 	{ 0x004d1025,	"ACER MegaRAID ROMB-2E", 0},
99 	{ 0x0511101e,	"AMI MegaRAID i4", AMI_BROKEN },
100 	{ 0x04931028,	"Dell PERC3/DC", 0 },
101 	{ 0x05181028,	"Dell PERC4/DC", 0 },
102 	{ 0x09a0101e,	"Dell 466v1", 0 },
103 	{ 0x11111111,	"Dell 466v2", 0 },
104 	{ 0x11121111,	"Dell 438", 0 },
105 	{ 0x11111028,	"Dell 466v3", 0 },
106 	{ 0x10651734,	"FSC MegaRAID PCI Express ROMB", 0 },
107 	{ 0x10c6103c,	"HP 438", 0 },
108 	{ 0x10c7103c,	"HP T5/T6", 0 },
109 	{ 0x10cc103c,	"HP T7", 0 },
110 	{ 0x10cd103c,	"HP 466", 0 },
111 	{ 0x45231000,	"LSI 523", 0 },
112 	{ 0x05328086,	"Intel RAID SRCU42X", 0 },
113 	{ 0x05238086,	"Intel RAID SRCS16", 0 },
114 	{ 0x00028086,	"Intel RAID SRCU42E", 0 },
115 	{ 0x05308086,	"Intel RAID SRCZCRX", 0 },
116 	{ 0x30088086,	"Intel RAID SRCS28X", 0 },
117 	{ 0x34318086,	"Intel RAID SROMBU42E", 0 },
118 	{ 0x34998086,	"Intel RAID SROMBU42E", 0 },
119 	{ 0x05208086,	"Intel RAID SRCU51L", 0 },
120 	{ 0x82871033,	"NEC MegaRAID PCI Express ROMB", 0 },
121 	{ 0, NULL, 0 }
122 };
123 
124 static const
125 struct ami_pci_vendor {
126 	u_int16_t id;
127 	char name[8];
128 } ami_pci_vendors[] = {
129 	{ 0x101e, "AMI" },
130 	{ 0x1028, "Dell" },
131 	{ 0x103c, "HP" },
132 	{ 0x1000, "LSI" },
133 	{ 0x8086, "Intel" },
134 	{ 0 }
135 };
136 
137 int
ami_pci_find_device(void * aux)138 ami_pci_find_device(void *aux)
139 {
140 	struct pci_attach_args *pa = aux;
141 	int i;
142 
143 	for (i = 0; ami_pci_devices[i].vendor; i++) {
144 		if (ami_pci_devices[i].vendor == PCI_VENDOR(pa->pa_id) &&
145 		    ami_pci_devices[i].product == PCI_PRODUCT(pa->pa_id)) {
146 #ifdef AMI_DEBUG
147 		    	printf(" apfd %i ", i);
148 #endif /* AMI_DEBUG */
149 			return (i);
150 		}
151 	}
152 
153 	return (-1);
154 }
155 
156 int
ami_pci_match(struct device * parent,void * match,void * aux)157 ami_pci_match(struct device *parent, void *match, void *aux)
158 {
159 	struct pci_attach_args *pa = aux;
160 	pcireg_t sig;
161 	int i;
162 
163 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_I2O)
164 		return (0);
165 
166 	if ((i = ami_pci_find_device(aux)) != -1) {
167 #ifdef AMI_DEBUG
168 		printf("\nvendor: %04x  product: %04x\n",
169 			ami_pci_devices[i].vendor,
170 			ami_pci_devices[i].product);
171 #endif /* AMI_DEBUG */
172 
173 		if (!(ami_pci_devices[i].flags & AMI_CHECK_SIGN))
174 			return (1);
175 		/* some cards have 0x11223344, but some only 16bit */
176 		sig = pci_conf_read(pa->pa_pc, pa->pa_tag,
177 		    AMI_PCI_SIG) & 0xffff;
178 		if (sig == AMI_SIGNATURE_1 ||
179 		    sig == AMI_SIGNATURE_2)
180 			return (1);
181 	}
182 
183 	return (0);
184 }
185 
186 void
ami_pci_attach(struct device * parent,struct device * self,void * aux)187 ami_pci_attach(struct device *parent, struct device *self, void *aux)
188 {
189 	struct ami_softc *sc = (struct ami_softc *)self;
190 	struct pci_attach_args *pa = aux;
191 	pci_intr_handle_t ih;
192 	const char *intrstr, *model = NULL, *lhc;
193 	const struct ami_pci_subsys *ssp;
194 	bus_size_t size;
195 	pcireg_t csr;
196 	int i;
197 
198 	csr = pci_mapreg_type(pa->pa_pc, pa->pa_tag, AMI_BAR);
199 	if (pci_mapreg_map(pa, AMI_BAR, csr, 0,
200 	    &sc->sc_iot, &sc->sc_ioh, NULL, &size, AMI_PCI_MEMSIZE)) {
201 		printf(": can't map controller pci space\n");
202 		return;
203 	}
204 
205 	if (PCI_MAPREG_TYPE(csr) == PCI_MAPREG_TYPE_IO) {
206 		sc->sc_init = ami_schwartz_init;
207 		sc->sc_exec = ami_schwartz_exec;
208 		sc->sc_done = ami_schwartz_done;
209 		sc->sc_poll = ami_schwartz_poll;
210 	} else {
211 		sc->sc_init = ami_quartz_init;
212 		sc->sc_exec = ami_quartz_exec;
213 		sc->sc_done = ami_quartz_done;
214 		sc->sc_poll = ami_quartz_poll;
215 		sc->sc_flags |= AMI_QUARTZ;
216 	}
217 	sc->sc_dmat = pa->pa_dmat;
218 
219 	if (pci_intr_map(pa, &ih)) {
220 		printf(": can't map interrupt\n");
221 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
222 		return;
223 	}
224 	intrstr = pci_intr_string(pa->pa_pc, ih);
225 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ami_intr, sc,
226 	    sc->sc_dev.dv_xname);
227 	if (!sc->sc_ih) {
228 		printf(": can't establish interrupt");
229 		if (intrstr)
230 			printf(" at %s", intrstr);
231 		printf("\n");
232 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
233 		return;
234 	}
235 
236 	printf(": %s\n", intrstr);
237 
238 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
239 	for (ssp = ami_pci_subsys; ssp->id; ssp++) {
240 		if (ssp->id == csr) {
241 			model = ssp->name;
242 			sc->sc_flags |= ssp->flags;
243 			break;
244 		}
245 	}
246 
247 	if (!model && PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMI) {
248 		switch (PCI_PRODUCT(pa->pa_id)) {
249 		case PCI_PRODUCT_AMI_MEGARAID428:
250 			model = "AMI 428";
251 			break;
252 		case PCI_PRODUCT_AMI_MEGARAID434:
253 			model = "AMI 434";
254 			break;
255 		}
256 	}
257 
258 	/*
259 	 * XXX 438 is netraid 3si for hp cards, but we get to know
260 	 * they are hp too late in md code
261 	 */
262 	if (!model) {
263 		const struct ami_pci_vendor *vp;
264 		static char modelbuf[32];
265 
266 		for (vp = ami_pci_vendors;
267 		     vp->id && vp->id != (csr & 0xffff); vp++);
268 		if (vp->id)
269 			snprintf(modelbuf, sizeof(modelbuf), "%s %x", vp->name,
270 			    (csr >> 16) & 0xffff);
271 		else
272 			snprintf(modelbuf, sizeof(modelbuf), "unknown 0x%08x",
273 			    csr);
274 		model = modelbuf;
275 	}
276 
277 	switch (pci_conf_read(pa->pa_pc, pa->pa_tag, AMI_PCI_SGL)) {
278 	case AMI_SGL_LHC:	lhc = "64b/lhc";	break;
279 	case AMI_SGL_HLC:	lhc = "64b/hlc";	break;
280 	default:		lhc = "32b";
281 	}
282 
283 	if ((i = ami_pci_find_device(aux)) != -1) {
284 		if (ami_pci_devices[i].flags & AMI_BROKEN)
285 			sc->sc_flags |= AMI_BROKEN;
286 	} else {
287 		/* this device existed at _match() should never happen */
288 		panic("ami device disappeared between match() and attach()");
289 	}
290 
291 	printf("%s: %s, %s", sc->sc_dev.dv_xname, model, lhc);
292 
293 	if (ami_attach(sc)) {
294 		pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
295 		sc->sc_ih = NULL;
296 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
297 	}
298 }
299