xref: /openbsd-src/sys/dev/pci/ami_pci.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: ami_pci.c,v 1.7 2001/06/23 21:43:07 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  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Michael Shalayeff.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31  * THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/device.h>
39 
40 #include <dev/pci/pcidevs.h>
41 #include <dev/pci/pcivar.h>
42 
43 #include <machine/bus.h>
44 
45 #include <scsi/scsi_all.h>
46 #include <scsi/scsi_disk.h>
47 #include <scsi/scsiconf.h>
48 
49 #include <dev/ic/amireg.h>
50 #include <dev/ic/amivar.h>
51 
52 #define	AMI_BAR		0x10
53 #define	AMI_SUBSYSID	0x2c
54 #define	PCI_EBCR	0x40
55 #define	AMI_WAKEUP	0x64
56 
57 /* "Quartz" i960 Config space */
58 #define	AMI_PCI_INIT	0x9c
59 #define		AMI_INITSTAT(i)	(((i) >>  8) & 0xff)
60 #define		AMI_INITTARG(i)	(((i) >> 16) & 0xff)
61 #define		AMI_INITCHAN(i)	(((i) >> 24) & 0xff)
62 #define	AMI_PCI_SIG	0xa0
63 #define		AMI_SIGNATURE	0x3344
64 #define	AMI_PCI_SGL	0xa4
65 #define		AMI_SGL_LHC	0x00000299
66 #define		AMI_SGL_HLC	0x00000199
67 
68 int	ami_pci_match __P((struct device *, void *, void *));
69 void	ami_pci_attach __P((struct device *, struct device *, void *));
70 
71 struct cfattach ami_pci_ca = {
72 	sizeof(struct ami_softc), ami_pci_match, ami_pci_attach
73 };
74 
75 static const
76 struct	ami_pci_device {
77 	int	vendor;
78 	int	product;
79 	int	flags;
80 #define	AMI_CHECK_SIGN	0x001
81 } ami_pci_devices[] = {
82 	{ PCI_VENDOR_AMI,	PCI_PRODUCT_AMI_MEGARAID,	0 },
83 	{ PCI_VENDOR_AMI,	PCI_PRODUCT_AMI_MEGARAID428,	0 },
84 	{ PCI_VENDOR_AMI,	PCI_PRODUCT_AMI_MEGARAID434,	0 },
85 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_80960RP_ATU, AMI_CHECK_SIGN },
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 	{ 0 }
104 };
105 
106 static const
107 struct ami_pci_vendor {
108 	u_int16_t id;
109 	char name[8];
110 } ami_pci_vendors[] = {
111 	{ 0x101e, "AMI" },
112 	{ 0x1028, "Dell" },
113 	{ 0x103c, "HP" },
114 	{ 0 }
115 };
116 
117 int
118 ami_pci_match(parent, match, aux)
119 	struct device *parent;
120 	void *match;
121 	void *aux;
122 {
123 	struct pci_attach_args *pa = aux;
124 	const struct ami_pci_device *pami;
125 
126 	if (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_I2O_STANDARD)
127 		return (0);
128 
129 	for (pami = ami_pci_devices; pami->vendor; pami++) {
130 		if (pami->vendor == PCI_VENDOR(pa->pa_id) &&
131 		    pami->product == PCI_PRODUCT(pa->pa_id) &&
132 		    (!pami->flags & AMI_CHECK_SIGN ||
133 		     (pci_conf_read(pa->pa_pc, pa->pa_tag, AMI_PCI_SIG) &
134 			  0xffff) == AMI_SIGNATURE))
135 			return (1);
136 	}
137 	return (0);
138 }
139 
140 void
141 ami_pci_attach(parent, self, aux)
142 	struct device *parent, *self;
143 	void *aux;
144 {
145 	struct ami_softc *sc = (struct ami_softc *)self;
146 	struct pci_attach_args *pa = aux;
147 	pci_intr_handle_t ih;
148 	const char *intrstr, *model = NULL, *lhc;
149 	const struct ami_pci_subsys *ssp;
150 	bus_size_t size;
151 	pcireg_t csr;
152 #if 0
153 	/* reset */
154 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_EBCR,
155 	    pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_EBCR) | 0x20);
156 	pci_conf_write(pa->pa_pc, pa->pa_tag, AMI_WAKEUP, 0);
157 #endif
158 	csr = pci_mapreg_type(pa->pa_pc, pa->pa_tag, AMI_BAR);
159 	if (pci_mapreg_map(pa, AMI_BAR, csr, 0,
160 	    &sc->iot, &sc->ioh, NULL, &size, 0)) {
161 		printf(": can't map controller pci space\n");
162 		return;
163 	}
164 
165 	if (csr == PCI_MAPREG_TYPE_IO) {
166 		sc->sc_init = ami_schwartz_init;
167 		sc->sc_exec = ami_schwartz_exec;
168 		sc->sc_done = ami_schwartz_done;
169 	} else {
170 		sc->sc_init = ami_quartz_init;
171 		sc->sc_exec = ami_quartz_exec;
172 		sc->sc_done = ami_quartz_done;
173 	}
174 	sc->dmat = pa->pa_dmat;
175 
176 	/* enable bus mastering (should not it be mi?) */
177 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
178 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
179 	    csr | PCI_COMMAND_MASTER_ENABLE);
180 
181 	if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
182 	    pa->pa_intrline, &ih)) {
183 		printf(": can't map interrupt\n");
184 		bus_space_unmap(sc->iot, sc->ioh, size);
185 		return;
186 	}
187 	intrstr = pci_intr_string(pa->pa_pc, ih);
188 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ami_intr, sc,
189 	    sc->sc_dev.dv_xname);
190 	if (!sc->sc_ih) {
191 		printf(": can't establish interrupt");
192 		if (intrstr)
193 			printf(" at %s", intrstr);
194 		printf("\n");
195 		bus_space_unmap(sc->iot, sc->ioh, size);
196 	}
197 
198 	printf(": %s", intrstr);
199 
200 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
201 	for (ssp = ami_pci_subsys; ssp->id; ssp++)
202 		if (ssp->id == csr) {
203 			model = ssp->name;
204 			break;
205 		}
206 
207 	if (!model && PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMI)
208 		switch (PCI_PRODUCT(pa->pa_id)) {
209 		case PCI_PRODUCT_AMI_MEGARAID428:
210 			model = "AMI 428";
211 			break;
212 		case PCI_PRODUCT_AMI_MEGARAID434:
213 			model = "AMI 434";
214 			break;
215 		}
216 
217 	/* XXX 438 is netraid 3si for hp cards, but we get to know
218 	   they are hp too late in md code */
219 
220 	if (!model) {
221 		const struct ami_pci_vendor *vp;
222 		static char modelbuf[12];
223 
224 		for (vp = ami_pci_vendors;
225 		     vp->id && vp->id != (csr & 0xffff); vp++);
226 		if (vp->id)
227 			sprintf(modelbuf, "%s %x", vp->name,
228 			    (csr >> 16) & 0xffff);
229 		else
230 			sprintf(modelbuf, "unknown 0x%08x", csr);
231 		model = modelbuf;
232 	}
233 
234 	switch (pci_conf_read(pa->pa_pc, pa->pa_tag, AMI_PCI_SGL)) {
235 	case AMI_SGL_LHC:	lhc = "64b/lhc";	break;
236 	case AMI_SGL_HLC:	lhc = "64b/hlc";	break;
237 	default:		lhc = "32b";
238 	}
239 
240 	printf(" %s/%s\n%s", model, lhc, sc->sc_dev.dv_xname);
241 
242 	if (ami_attach(sc)) {
243 		pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
244 		sc->sc_ih = NULL;
245 		bus_space_unmap(sc->iot, sc->ioh, size);
246 	}
247 }
248