1 | /* $NetBSD: ciss_pci.c,v 1.13 2016/07/14 04:00:46 msaitoh Exp $ */ |
2 | /* $OpenBSD: ciss_pci.c,v 1.9 2005/12/13 15:56:01 brad Exp $ */ |
3 | |
4 | /* |
5 | * Copyright (c) 2005 Michael Shalayeff |
6 | * All rights reserved. |
7 | * |
8 | * Permission to use, copy, modify, and distribute this software for any |
9 | * purpose with or without fee is hereby granted, provided that the above |
10 | * copyright notice and this permission notice appear in all copies. |
11 | * |
12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
16 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN |
17 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT |
18 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
19 | */ |
20 | |
21 | #include <sys/cdefs.h> |
22 | __KERNEL_RCSID(0, "$NetBSD: ciss_pci.c,v 1.13 2016/07/14 04:00:46 msaitoh Exp $" ); |
23 | |
24 | #include <sys/param.h> |
25 | #include <sys/systm.h> |
26 | #include <sys/kernel.h> |
27 | #include <sys/malloc.h> |
28 | #include <sys/device.h> |
29 | |
30 | #include <dev/pci/pcidevs.h> |
31 | #include <dev/pci/pcivar.h> |
32 | |
33 | #include <sys/bus.h> |
34 | |
35 | #include <dev/scsipi/scsipi_all.h> |
36 | #include <dev/scsipi/scsipi_disk.h> |
37 | #include <dev/scsipi/scsipiconf.h> |
38 | |
39 | #include <dev/ic/cissreg.h> |
40 | #include <dev/ic/cissvar.h> |
41 | |
42 | #define CISS_BAR 0x10 |
43 | |
44 | int ciss_pci_match(device_t, cfdata_t, void *); |
45 | void ciss_pci_attach(device_t, device_t, void *); |
46 | |
47 | CFATTACH_DECL_NEW(ciss_pci, sizeof(struct ciss_softc), |
48 | ciss_pci_match, ciss_pci_attach, NULL, NULL); |
49 | |
50 | const struct { |
51 | int vendor; |
52 | int product; |
53 | const char *name; |
54 | } ciss_pci_devices[] = { |
55 | { |
56 | PCI_VENDOR_COMPAQ, |
57 | PCI_PRODUCT_COMPAQ_CSA532, |
58 | "Compaq Smart Array 532" |
59 | }, |
60 | { |
61 | PCI_VENDOR_COMPAQ, |
62 | PCI_PRODUCT_COMPAQ_CSA5300, |
63 | "Compaq Smart Array 5300 V1" |
64 | }, |
65 | { |
66 | PCI_VENDOR_COMPAQ, |
67 | PCI_PRODUCT_COMPAQ_CSA5300_2, |
68 | "Compaq Smart Array 5300 V2" |
69 | }, |
70 | { |
71 | PCI_VENDOR_COMPAQ, |
72 | PCI_PRODUCT_COMPAQ_CSA5312, |
73 | "Compaq Smart Array 5312" |
74 | }, |
75 | { |
76 | PCI_VENDOR_COMPAQ, |
77 | PCI_PRODUCT_COMPAQ_CSA5i, |
78 | "Compaq Smart Array 5i" |
79 | }, |
80 | { |
81 | PCI_VENDOR_COMPAQ, |
82 | PCI_PRODUCT_COMPAQ_CSA5i_2, |
83 | "Compaq Smart Array 5i V2" |
84 | }, |
85 | { |
86 | PCI_VENDOR_COMPAQ, |
87 | PCI_PRODUCT_COMPAQ_CSA6i, |
88 | "Compaq Smart Array 6i" |
89 | }, |
90 | { |
91 | PCI_VENDOR_COMPAQ, |
92 | PCI_PRODUCT_COMPAQ_CSA641, |
93 | "Compaq Smart Array 641" |
94 | }, |
95 | { |
96 | PCI_VENDOR_COMPAQ, |
97 | PCI_PRODUCT_COMPAQ_CSA642, |
98 | "Compaq Smart Array 642" |
99 | }, |
100 | { |
101 | PCI_VENDOR_COMPAQ, |
102 | PCI_PRODUCT_COMPAQ_CSA6400, |
103 | "Compaq Smart Array 6400" |
104 | }, |
105 | { |
106 | PCI_VENDOR_COMPAQ, |
107 | PCI_PRODUCT_COMPAQ_CSA6400EM, |
108 | "Compaq Smart Array 6400EM" |
109 | }, |
110 | { |
111 | PCI_VENDOR_COMPAQ, |
112 | PCI_PRODUCT_COMPAQ_CSA6422, |
113 | "Compaq Smart Array 6422" |
114 | }, |
115 | { |
116 | PCI_VENDOR_COMPAQ, |
117 | PCI_PRODUCT_COMPAQ_CSA64XX, |
118 | "Compaq Smart Array 64XX" |
119 | }, |
120 | { |
121 | PCI_VENDOR_HP, |
122 | PCI_PRODUCT_HP_HPSAE200, |
123 | "Smart Array E200" |
124 | }, |
125 | { |
126 | PCI_VENDOR_HP, |
127 | PCI_PRODUCT_HP_HPSAE200I_1, |
128 | "HP Smart Array E200I-1" |
129 | }, |
130 | { |
131 | PCI_VENDOR_HP, |
132 | PCI_PRODUCT_HP_HPSAE200I_2, |
133 | "HP Smart Array E200I-2" |
134 | }, |
135 | { |
136 | PCI_VENDOR_HP, |
137 | PCI_PRODUCT_HP_HPSAE200I_3, |
138 | "HP Smart Array E200I-3" |
139 | }, |
140 | { |
141 | PCI_VENDOR_HP, |
142 | PCI_PRODUCT_HP_HPSAP600, |
143 | "HP Smart Array P600" |
144 | }, |
145 | { |
146 | PCI_VENDOR_HP, |
147 | PCI_PRODUCT_HP_HPSAP800, |
148 | "HP Smart Array P800" |
149 | }, |
150 | { |
151 | PCI_VENDOR_HP, |
152 | PCI_PRODUCT_HP_HPSAV100, |
153 | "HP Smart Array V100" |
154 | }, |
155 | { |
156 | PCI_VENDOR_HP, |
157 | PCI_PRODUCT_HP_HPSA_1, |
158 | "HP Smart Array 1" |
159 | }, |
160 | { |
161 | PCI_VENDOR_HP, |
162 | PCI_PRODUCT_HP_HPSA_2, |
163 | "HP Smart Array 2" |
164 | }, |
165 | { |
166 | PCI_VENDOR_HP, |
167 | PCI_PRODUCT_HP_HPSA_3, |
168 | "HP Smart Array 3" |
169 | }, |
170 | { |
171 | PCI_VENDOR_HP, |
172 | PCI_PRODUCT_HP_HPSA_4, |
173 | "HP Smart Array 4" |
174 | }, |
175 | { |
176 | PCI_VENDOR_HP, |
177 | PCI_PRODUCT_HP_HPSA_5, |
178 | "HP Smart Array 5" |
179 | }, |
180 | { |
181 | PCI_VENDOR_HP, |
182 | PCI_PRODUCT_HP_HPSA_6, |
183 | "HP Smart Array 6" |
184 | }, |
185 | { |
186 | PCI_VENDOR_HP, |
187 | PCI_PRODUCT_HP_HPSA_7, |
188 | "HP Smart Array 7" |
189 | }, |
190 | { |
191 | PCI_VENDOR_HP, |
192 | PCI_PRODUCT_HP_HPSA_8, |
193 | "HP Smart Array 8" |
194 | }, |
195 | { |
196 | PCI_VENDOR_HP, |
197 | PCI_PRODUCT_HP_HPSA_9, |
198 | "HP Smart Array 9" |
199 | }, |
200 | { |
201 | PCI_VENDOR_HP, |
202 | PCI_PRODUCT_HP_HPSA_10, |
203 | "HP Smart Array 10" |
204 | }, |
205 | { |
206 | PCI_VENDOR_HP, |
207 | PCI_PRODUCT_HP_HPSA_11, |
208 | "HP Smart Array 11" |
209 | }, |
210 | { |
211 | PCI_VENDOR_HP, |
212 | PCI_PRODUCT_HP_HPSA_12, |
213 | "HP Smart Array 12" |
214 | }, |
215 | { |
216 | PCI_VENDOR_HP, |
217 | PCI_PRODUCT_HP_HPSA_13, |
218 | "HP Smart Array 13" |
219 | }, |
220 | { |
221 | 0, |
222 | 0, |
223 | NULL |
224 | } |
225 | }; |
226 | |
227 | int |
228 | ciss_pci_match(device_t parent, cfdata_t match, void *aux) |
229 | { |
230 | struct pci_attach_args *pa = aux; |
231 | pcireg_t reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); |
232 | int i; |
233 | |
234 | for (i = 0; ciss_pci_devices[i].vendor; i++) |
235 | { |
236 | if ((PCI_VENDOR(pa->pa_id) == ciss_pci_devices[i].vendor && |
237 | PCI_PRODUCT(pa->pa_id) == ciss_pci_devices[i].product) || |
238 | (PCI_VENDOR(reg) == ciss_pci_devices[i].vendor && |
239 | PCI_PRODUCT(reg) == ciss_pci_devices[i].product)) |
240 | return 1; |
241 | } |
242 | |
243 | return 0; |
244 | } |
245 | |
246 | void |
247 | ciss_pci_attach(device_t parent, device_t self, void *aux) |
248 | { |
249 | struct ciss_softc *sc = device_private(self); |
250 | struct pci_attach_args *pa = aux; |
251 | bus_size_t size, cfgsz; |
252 | pci_intr_handle_t ih; |
253 | const char *intrstr; |
254 | int cfg_bar, memtype; |
255 | pcireg_t reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); |
256 | int i; |
257 | char intrbuf[PCI_INTRSTR_LEN]; |
258 | |
259 | sc->sc_dev = self; |
260 | |
261 | aprint_naive("\n" ); |
262 | for (i = 0; ciss_pci_devices[i].vendor; i++) |
263 | { |
264 | if ((PCI_VENDOR(pa->pa_id) == ciss_pci_devices[i].vendor && |
265 | PCI_PRODUCT(pa->pa_id) == ciss_pci_devices[i].product) || |
266 | (PCI_VENDOR(reg) == ciss_pci_devices[i].vendor && |
267 | PCI_PRODUCT(reg) == ciss_pci_devices[i].product)) |
268 | { |
269 | aprint_normal(": %s\n" , ciss_pci_devices[i].name); |
270 | break; |
271 | } |
272 | } |
273 | |
274 | memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, CISS_BAR); |
275 | if (memtype != (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT) && |
276 | memtype != (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT)) { |
277 | aprint_error_dev(self, "wrong BAR type\n" ); |
278 | return; |
279 | } |
280 | if (pci_mapreg_map(pa, CISS_BAR, memtype, 0, |
281 | &sc->sc_iot, &sc->sc_ioh, NULL, &size)) { |
282 | aprint_error_dev(self, "can't map controller i/o space\n" ); |
283 | return; |
284 | } |
285 | sc->sc_dmat = pa->pa_dmat; |
286 | |
287 | sc->iem = CISS_INTR_OPQ_SA5; |
288 | reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); |
289 | if (PCI_VENDOR(reg) == PCI_VENDOR_COMPAQ && |
290 | (PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA5i || |
291 | PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA532 || |
292 | PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA5312)) |
293 | sc->iem = CISS_INTR_OPQ_SA5B; |
294 | |
295 | cfg_bar = bus_space_read_2(sc->sc_iot, sc->sc_ioh, CISS_CFG_BAR); |
296 | sc->cfgoff = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_CFG_OFF); |
297 | if (cfg_bar != CISS_BAR) { |
298 | if (pci_mapreg_map(pa, cfg_bar, PCI_MAPREG_TYPE_MEM, 0, |
299 | NULL, &sc->cfg_ioh, NULL, &cfgsz)) { |
300 | aprint_error_dev(self, |
301 | "can't map controller config space\n" ); |
302 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); |
303 | return; |
304 | } |
305 | } else { |
306 | sc->cfg_ioh = sc->sc_ioh; |
307 | cfgsz = size; |
308 | } |
309 | |
310 | if (sc->cfgoff + sizeof(struct ciss_config) > cfgsz) { |
311 | aprint_error_dev(self, "unfit config space\n" ); |
312 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); |
313 | if (cfg_bar != CISS_BAR) |
314 | bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); |
315 | return; |
316 | } |
317 | |
318 | /* disable interrupts until ready */ |
319 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_IMR, |
320 | bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IMR) | sc->iem); |
321 | |
322 | if (pci_intr_map(pa, &ih)) { |
323 | aprint_error_dev(self, "can't map interrupt\n" ); |
324 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); |
325 | if (cfg_bar != CISS_BAR) |
326 | bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); |
327 | return; |
328 | } |
329 | intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf)); |
330 | sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ciss_intr, sc); |
331 | if (!sc->sc_ih) { |
332 | aprint_error_dev(sc->sc_dev, "can't establish interrupt" ); |
333 | if (intrstr) |
334 | aprint_error(" at %s" , intrstr); |
335 | aprint_error("\n" ); |
336 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); |
337 | if (cfg_bar != CISS_BAR) |
338 | bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); |
339 | } |
340 | |
341 | aprint_normal_dev(self, "interrupting at %s\n%s" , intrstr, |
342 | device_xname(sc->sc_dev)); |
343 | |
344 | if (ciss_attach(sc)) { |
345 | pci_intr_disestablish(pa->pa_pc, sc->sc_ih); |
346 | sc->sc_ih = NULL; |
347 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); |
348 | if (cfg_bar != CISS_BAR) |
349 | bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); |
350 | return; |
351 | } |
352 | |
353 | /* enable interrupts now */ |
354 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_IMR, |
355 | bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IMR) & ~sc->iem); |
356 | } |
357 | |