xref: /openbsd-src/sys/dev/pci/ami_pci.c (revision 0eea0d082377cb9c3ec583313dc4d52b7b6a4d6d)
1 /*	$OpenBSD: ami_pci.c,v 1.19 2004/02/28 02:03:34 mickey 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/kernel.h>
32 #include <sys/malloc.h>
33 #include <sys/device.h>
34 
35 #include <dev/pci/pcidevs.h>
36 #include <dev/pci/pcivar.h>
37 
38 #include <machine/bus.h>
39 
40 #include <scsi/scsi_all.h>
41 #include <scsi/scsi_disk.h>
42 #include <scsi/scsiconf.h>
43 
44 #include <dev/ic/amireg.h>
45 #include <dev/ic/amivar.h>
46 
47 #define	AMI_BAR		0x10
48 #define	AMI_PCI_MEMSIZE	0x1000
49 #define	AMI_SUBSYSID	0x2c
50 #define	PCI_EBCR	0x40
51 #define	AMI_WAKEUP	0x64
52 
53 /* "Quartz" i960 Config space */
54 #define	AMI_PCI_INIT	0x9c
55 #define		AMI_INITSTAT(i)	(((i) >>  8) & 0xff)
56 #define		AMI_INITTARG(i)	(((i) >> 16) & 0xff)
57 #define		AMI_INITCHAN(i)	(((i) >> 24) & 0xff)
58 #define	AMI_PCI_SIG	0xa0
59 #define		AMI_SIGNATURE_1	0xcccc		/* older adapters */
60 #define		AMI_SIGNATURE_2	0x3344		/* newer adapters */
61 #define	AMI_PCI_SGL	0xa4
62 #define		AMI_SGL_LHC	0x00000299
63 #define		AMI_SGL_HLC	0x00000199
64 
65 int	ami_pci_match(struct device *, void *, void *);
66 void	ami_pci_attach(struct device *, struct device *, void *);
67 
68 struct cfattach ami_pci_ca = {
69 	sizeof(struct ami_softc), ami_pci_match, ami_pci_attach
70 };
71 
72 static const
73 struct	ami_pci_device {
74 	int	vendor;
75 	int	product;
76 	int	flags;
77 #define	AMI_CHECK_SIGN	0x001
78 } ami_pci_devices[] = {
79 	{ PCI_VENDOR_AMI,	PCI_PRODUCT_AMI_MEGARAID,	0 },
80 	{ PCI_VENDOR_AMI,	PCI_PRODUCT_AMI_MEGARAID428,	0 },
81 	{ PCI_VENDOR_AMI,	PCI_PRODUCT_AMI_MEGARAID434,	0 },
82 	{ PCI_VENDOR_DELL,	PCI_PRODUCT_DELL_PERC_4DI,	0 },
83 	{ PCI_VENDOR_DELL,	PCI_PRODUCT_DELL_PERC_4DI_2,	0 },
84 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_80960RP_ATU, AMI_CHECK_SIGN },
85 	{ PCI_VENDOR_SYMBIOS,	PCI_PRODUCT_SYMBIOS_MEGARAID,	0 },
86 	{ 0 }
87 };
88 
89 static const
90 struct	ami_pci_subsys {
91 	pcireg_t id;
92 	char	name[12];
93 } ami_pci_subsys[] = {
94 	/* only those of a special name are listed here */
95 	{ 0x09A0101E,	"Dell 466v1" },
96 	{ 0x11111111,	"Dell 466v2" },
97 	{ 0x11121111,	"Dell 438" },
98 	{ 0x11111028,	"Dell 466v3" },
99 	{ 0x10c6103c,	"HP 438" },
100 	{ 0x10c7103c,	"HP T5/T6" },
101 	{ 0x10cc103c,	"HP T7" },
102 	{ 0x10cd103c,	"HP 466" },
103 	{ 0x45231000,	"LSI 523" },
104 	{ 0 }
105 };
106 
107 static const
108 struct ami_pci_vendor {
109 	u_int16_t id;
110 	char name[8];
111 } ami_pci_vendors[] = {
112 	{ 0x101e, "AMI" },
113 	{ 0x1028, "Dell" },
114 	{ 0x103c, "HP" },
115 	{ 0x1000, "LSI" },
116 	{ 0 }
117 };
118 
119 int
120 ami_pci_match(parent, match, aux)
121 	struct device *parent;
122 	void *match;
123 	void *aux;
124 {
125 	struct pci_attach_args *pa = aux;
126 	const struct ami_pci_device *pami;
127 	pcireg_t sig;
128 
129 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_I2O)
130 		return (0);
131 
132 	for (pami = ami_pci_devices; pami->vendor; pami++) {
133 		if (pami->vendor == PCI_VENDOR(pa->pa_id) &&
134 		    pami->product == PCI_PRODUCT(pa->pa_id)) {
135 			if (!(pami->flags & AMI_CHECK_SIGN))
136 				return (1);
137 			/* some cards have 0x11223344, but some only 16bit */
138 			sig = pci_conf_read(pa->pa_pc, pa->pa_tag,
139 			    AMI_PCI_SIG) & 0xffff;
140 			if (sig == AMI_SIGNATURE_1 ||
141 			    sig == AMI_SIGNATURE_2)
142 				return (1);
143 		}
144 	}
145 	return (0);
146 }
147 
148 void
149 ami_pci_attach(parent, self, aux)
150 	struct device *parent, *self;
151 	void *aux;
152 {
153 	struct ami_softc *sc = (struct ami_softc *)self;
154 	struct pci_attach_args *pa = aux;
155 	pci_intr_handle_t ih;
156 	const char *intrstr, *model = NULL, *lhc;
157 	const struct ami_pci_subsys *ssp;
158 	bus_size_t size;
159 	pcireg_t csr;
160 #if 0
161 	/* reset */
162 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_EBCR,
163 	    pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_EBCR) | 0x20);
164 	pci_conf_write(pa->pa_pc, pa->pa_tag, AMI_WAKEUP, 0);
165 #endif
166 	csr = pci_mapreg_type(pa->pa_pc, pa->pa_tag, AMI_BAR);
167 	csr |= PCI_MAPREG_MEM_TYPE_32BIT;
168 	if (pci_mapreg_map(pa, AMI_BAR, csr, 0,
169 	    &sc->iot, &sc->ioh, NULL, &size, AMI_PCI_MEMSIZE)) {
170 		printf(": can't map controller pci space\n");
171 		return;
172 	}
173 
174 	if (csr == PCI_MAPREG_TYPE_IO) {
175 		sc->sc_init = ami_schwartz_init;
176 		sc->sc_exec = ami_schwartz_exec;
177 		sc->sc_done = ami_schwartz_done;
178 	} else {
179 		sc->sc_init = ami_quartz_init;
180 		sc->sc_exec = ami_quartz_exec;
181 		sc->sc_done = ami_quartz_done;
182 	}
183 	sc->dmat = pa->pa_dmat;
184 
185 	/* enable bus mastering (should not it be mi?) */
186 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
187 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
188 	    csr | PCI_COMMAND_MASTER_ENABLE);
189 
190 	if (pci_intr_map(pa, &ih)) {
191 		printf(": can't map interrupt\n");
192 		bus_space_unmap(sc->iot, sc->ioh, size);
193 		return;
194 	}
195 	intrstr = pci_intr_string(pa->pa_pc, ih);
196 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ami_intr, sc,
197 	    sc->sc_dev.dv_xname);
198 	if (!sc->sc_ih) {
199 		printf(": can't establish interrupt");
200 		if (intrstr)
201 			printf(" at %s", intrstr);
202 		printf("\n");
203 		bus_space_unmap(sc->iot, sc->ioh, size);
204 	}
205 
206 	printf(": %s", intrstr);
207 
208 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
209 	for (ssp = ami_pci_subsys; ssp->id; ssp++)
210 		if (ssp->id == csr) {
211 			model = ssp->name;
212 			break;
213 		}
214 
215 	if (!model && PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMI)
216 		switch (PCI_PRODUCT(pa->pa_id)) {
217 		case PCI_PRODUCT_AMI_MEGARAID428:
218 			model = "AMI 428";
219 			break;
220 		case PCI_PRODUCT_AMI_MEGARAID434:
221 			model = "AMI 434";
222 			break;
223 		}
224 
225 	/* XXX 438 is netraid 3si for hp cards, but we get to know
226 	   they are hp too late in md code */
227 
228 	if (!model) {
229 		const struct ami_pci_vendor *vp;
230 		static char modelbuf[32];
231 
232 		for (vp = ami_pci_vendors;
233 		     vp->id && vp->id != (csr & 0xffff); vp++);
234 		if (vp->id)
235 			snprintf(modelbuf, sizeof modelbuf, "%s %x", vp->name,
236 			    (csr >> 16) & 0xffff);
237 		else
238 			snprintf(modelbuf, sizeof modelbuf, "unknown 0x%08x",
239 			    csr);
240 		model = modelbuf;
241 	}
242 
243 	switch (pci_conf_read(pa->pa_pc, pa->pa_tag, AMI_PCI_SGL)) {
244 	case AMI_SGL_LHC:	lhc = "64b/lhc";	break;
245 	case AMI_SGL_HLC:	lhc = "64b/hlc";	break;
246 	default:		lhc = "32b";
247 	}
248 
249 	printf(" %s/%s\n%s", model, lhc, sc->sc_dev.dv_xname);
250 
251 	if (ami_attach(sc)) {
252 		pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
253 		sc->sc_ih = NULL;
254 		bus_space_unmap(sc->iot, sc->ioh, size);
255 	}
256 }
257