xref: /openbsd/sys/dev/pci/ami_pci.c (revision db3296cf)
1 /*	$OpenBSD: ami_pci.c,v 1.18 2003/06/02 19:24:22 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 	{ 0 }
86 };
87 
88 static const
89 struct	ami_pci_subsys {
90 	pcireg_t id;
91 	char	name[12];
92 } ami_pci_subsys[] = {
93 	/* only those of a special name are listed here */
94 	{ 0x09A0101E,	"Dell 466v1" },
95 	{ 0x11111111,	"Dell 466v2" },
96 	{ 0x11121111,	"Dell 438" },
97 	{ 0x11111028,	"Dell 466v3" },
98 	{ 0x10c6103c,	"HP 438" },
99 	{ 0x10c7103c,	"HP T5/T6" },
100 	{ 0x10cc103c,	"HP T7" },
101 	{ 0x10cd103c,	"HP 466" },
102 	{ 0 }
103 };
104 
105 static const
106 struct ami_pci_vendor {
107 	u_int16_t id;
108 	char name[8];
109 } ami_pci_vendors[] = {
110 	{ 0x101e, "AMI" },
111 	{ 0x1028, "Dell" },
112 	{ 0x103c, "HP" },
113 	{ 0 }
114 };
115 
116 int
117 ami_pci_match(parent, match, aux)
118 	struct device *parent;
119 	void *match;
120 	void *aux;
121 {
122 	struct pci_attach_args *pa = aux;
123 	const struct ami_pci_device *pami;
124 	pcireg_t sig;
125 
126 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_I2O)
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 			if (!(pami->flags & AMI_CHECK_SIGN))
133 				return (1);
134 			/* some cards have 0x11223344, but some only 16bit */
135 			sig = pci_conf_read(pa->pa_pc, pa->pa_tag,
136 			    AMI_PCI_SIG) & 0xffff;
137 			if (sig == AMI_SIGNATURE_1 ||
138 			    sig == AMI_SIGNATURE_2)
139 				return (1);
140 		}
141 	}
142 	return (0);
143 }
144 
145 void
146 ami_pci_attach(parent, self, aux)
147 	struct device *parent, *self;
148 	void *aux;
149 {
150 	struct ami_softc *sc = (struct ami_softc *)self;
151 	struct pci_attach_args *pa = aux;
152 	pci_intr_handle_t ih;
153 	const char *intrstr, *model = NULL, *lhc;
154 	const struct ami_pci_subsys *ssp;
155 	bus_size_t size;
156 	pcireg_t csr;
157 #if 0
158 	/* reset */
159 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_EBCR,
160 	    pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_EBCR) | 0x20);
161 	pci_conf_write(pa->pa_pc, pa->pa_tag, AMI_WAKEUP, 0);
162 #endif
163 	csr = pci_mapreg_type(pa->pa_pc, pa->pa_tag, AMI_BAR);
164 	csr |= PCI_MAPREG_MEM_TYPE_32BIT;
165 	if (pci_mapreg_map(pa, AMI_BAR, csr, 0,
166 	    &sc->iot, &sc->ioh, NULL, &size, AMI_PCI_MEMSIZE)) {
167 		printf(": can't map controller pci space\n");
168 		return;
169 	}
170 
171 	if (csr == PCI_MAPREG_TYPE_IO) {
172 		sc->sc_init = ami_schwartz_init;
173 		sc->sc_exec = ami_schwartz_exec;
174 		sc->sc_done = ami_schwartz_done;
175 	} else {
176 		sc->sc_init = ami_quartz_init;
177 		sc->sc_exec = ami_quartz_exec;
178 		sc->sc_done = ami_quartz_done;
179 	}
180 	sc->dmat = pa->pa_dmat;
181 
182 	/* enable bus mastering (should not it be mi?) */
183 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
184 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
185 	    csr | PCI_COMMAND_MASTER_ENABLE);
186 
187 	if (pci_intr_map(pa, &ih)) {
188 		printf(": can't map interrupt\n");
189 		bus_space_unmap(sc->iot, sc->ioh, size);
190 		return;
191 	}
192 	intrstr = pci_intr_string(pa->pa_pc, ih);
193 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ami_intr, sc,
194 	    sc->sc_dev.dv_xname);
195 	if (!sc->sc_ih) {
196 		printf(": can't establish interrupt");
197 		if (intrstr)
198 			printf(" at %s", intrstr);
199 		printf("\n");
200 		bus_space_unmap(sc->iot, sc->ioh, size);
201 	}
202 
203 	printf(": %s", intrstr);
204 
205 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
206 	for (ssp = ami_pci_subsys; ssp->id; ssp++)
207 		if (ssp->id == csr) {
208 			model = ssp->name;
209 			break;
210 		}
211 
212 	if (!model && PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMI)
213 		switch (PCI_PRODUCT(pa->pa_id)) {
214 		case PCI_PRODUCT_AMI_MEGARAID428:
215 			model = "AMI 428";
216 			break;
217 		case PCI_PRODUCT_AMI_MEGARAID434:
218 			model = "AMI 434";
219 			break;
220 		}
221 
222 	/* XXX 438 is netraid 3si for hp cards, but we get to know
223 	   they are hp too late in md code */
224 
225 	if (!model) {
226 		const struct ami_pci_vendor *vp;
227 		static char modelbuf[12];
228 
229 		for (vp = ami_pci_vendors;
230 		     vp->id && vp->id != (csr & 0xffff); vp++);
231 		if (vp->id)
232 			snprintf(modelbuf, sizeof modelbuf, "%s %x", vp->name,
233 			    (csr >> 16) & 0xffff);
234 		else
235 			snprintf(modelbuf, sizeof modelbuf, "unknown 0x%08x",
236 			    csr);
237 		model = modelbuf;
238 	}
239 
240 	switch (pci_conf_read(pa->pa_pc, pa->pa_tag, AMI_PCI_SGL)) {
241 	case AMI_SGL_LHC:	lhc = "64b/lhc";	break;
242 	case AMI_SGL_HLC:	lhc = "64b/hlc";	break;
243 	default:		lhc = "32b";
244 	}
245 
246 	printf(" %s/%s\n%s", model, lhc, sc->sc_dev.dv_xname);
247 
248 	if (ami_attach(sc)) {
249 		pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
250 		sc->sc_ih = NULL;
251 		bus_space_unmap(sc->iot, sc->ioh, size);
252 	}
253 }
254