1 | /* $NetBSD: icp_pci.c,v 1.23 2016/09/27 03:33:32 pgoyette Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2002 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Andrew Doran. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. |
34 | * |
35 | * Redistribution and use in source and binary forms, with or without |
36 | * modification, are permitted provided that the following conditions |
37 | * are met: |
38 | * 1. Redistributions of source code must retain the above copyright |
39 | * notice, this list of conditions and the following disclaimer. |
40 | * 2. Redistributions in binary form must reproduce the above copyright |
41 | * notice, this list of conditions and the following disclaimer in the |
42 | * documentation and/or other materials provided with the distribution. |
43 | * 3. All advertising materials mentioning features or use of this software |
44 | * must display the following acknowledgement: |
45 | * This product includes software developed by Niklas Hallqvist. |
46 | * 4. The name of the author may not be used to endorse or promote products |
47 | * derived from this software without specific prior written permission. |
48 | * |
49 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
50 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
51 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
52 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
53 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
54 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
55 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
56 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
57 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
58 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
59 | * |
60 | * from OpenBSD: icp_pci.c,v 1.11 2001/06/12 15:40:30 niklas Exp |
61 | */ |
62 | |
63 | /* |
64 | * This driver would not have written if it was not for the hardware donations |
65 | * from both ICP-Vortex and Öko.neT. I want to thank them for their support. |
66 | * |
67 | * Re-worked for NetBSD by Andrew Doran. Test hardware kindly supplied by |
68 | * Intel. |
69 | */ |
70 | |
71 | #include <sys/cdefs.h> |
72 | __KERNEL_RCSID(0, "$NetBSD: icp_pci.c,v 1.23 2016/09/27 03:33:32 pgoyette Exp $" ); |
73 | |
74 | #include <sys/param.h> |
75 | #include <sys/systm.h> |
76 | #include <sys/device.h> |
77 | #include <sys/kernel.h> |
78 | #include <sys/queue.h> |
79 | #include <sys/buf.h> |
80 | #include <sys/endian.h> |
81 | #include <sys/conf.h> |
82 | |
83 | #include <sys/bus.h> |
84 | |
85 | #include <dev/pci/pcireg.h> |
86 | #include <dev/pci/pcivar.h> |
87 | #include <dev/pci/pcidevs.h> |
88 | |
89 | #include <dev/ic/icpreg.h> |
90 | #include <dev/ic/icpvar.h> |
91 | |
92 | /* Product numbers for Fibre-Channel are greater than or equal to 0x200 */ |
93 | #define ICP_PCI_PRODUCT_FC 0x200 |
94 | |
95 | /* Mapping registers for various areas */ |
96 | #define ICP_PCI_DPMEM 0x10 |
97 | #define ICP_PCINEW_IOMEM 0x10 |
98 | #define ICP_PCINEW_IO 0x14 |
99 | #define ICP_PCINEW_DPMEM 0x18 |
100 | |
101 | /* PCI SRAM structure */ |
102 | #define ICP_MAGIC 0x00 /* u_int32_t, controller ID from BIOS */ |
103 | #define ICP_NEED_DEINIT 0x04 /* u_int16_t, switch between BIOS/driver */ |
104 | #define ICP_SWITCH_SUPPORT 0x06 /* u_int8_t, see ICP_NEED_DEINIT */ |
105 | #define ICP_OS_USED 0x10 /* u_int8_t [16], OS code per service */ |
106 | #define ICP_FW_MAGIC 0x3c /* u_int8_t, controller ID from firmware */ |
107 | #define ICP_SRAM_SZ 0x40 |
108 | |
109 | /* DPRAM PCI controllers */ |
110 | #define ICP_DPR_IF 0x00 /* interface area */ |
111 | #define ICP_6SR (0xff0 - ICP_SRAM_SZ) |
112 | #define ICP_SEMA1 0xff1 /* volatile u_int8_t, command semaphore */ |
113 | #define ICP_IRQEN 0xff5 /* u_int8_t, board interrupts enable */ |
114 | #define ICP_EVENT 0xff8 /* u_int8_t, release event */ |
115 | #define ICP_IRQDEL 0xffc /* u_int8_t, acknowledge board interrupt */ |
116 | #define ICP_DPRAM_SZ 0x1000 |
117 | |
118 | /* PLX register structure (new PCI controllers) */ |
119 | #define ICP_CFG_REG 0x00 /* u_int8_t, DPRAM cfg. (2: < 1MB, 0: any) */ |
120 | #define ICP_SEMA0_REG 0x40 /* volatile u_int8_t, command semaphore */ |
121 | #define ICP_SEMA1_REG 0x41 /* volatile u_int8_t, status semaphore */ |
122 | #define ICP_PLX_STATUS 0x44 /* volatile u_int16_t, command status */ |
123 | #define ICP_PLX_SERVICE 0x46 /* u_int16_t, service */ |
124 | #define ICP_PLX_INFO 0x48 /* u_int32_t [2], additional info */ |
125 | #define ICP_LDOOR_REG 0x60 /* u_int8_t, PCI to local doorbell */ |
126 | #define ICP_EDOOR_REG 0x64 /* volatile u_int8_t, local to PCI doorbell */ |
127 | #define ICP_CONTROL0 0x68 /* u_int8_t, control0 register (unused) */ |
128 | #define ICP_CONTROL1 0x69 /* u_int8_t, board interrupts enable */ |
129 | #define ICP_PLX_SZ 0x80 |
130 | |
131 | /* DPRAM new PCI controllers */ |
132 | #define ICP_IC 0x00 /* interface */ |
133 | #define ICP_PCINEW_6SR (0x4000 - ICP_SRAM_SZ) |
134 | /* SRAM structure */ |
135 | #define ICP_PCINEW_SZ 0x4000 |
136 | |
137 | /* i960 register structure (PCI MPR controllers) */ |
138 | #define ICP_MPR_SEMA0 0x10 /* volatile u_int8_t, command semaphore */ |
139 | #define ICP_MPR_SEMA1 0x12 /* volatile u_int8_t, status semaphore */ |
140 | #define ICP_MPR_STATUS 0x14 /* volatile u_int16_t, command status */ |
141 | #define ICP_MPR_SERVICE 0x16 /* u_int16_t, service */ |
142 | #define ICP_MPR_INFO 0x18 /* u_int32_t [2], additional info */ |
143 | #define ICP_MPR_LDOOR 0x20 /* u_int8_t, PCI to local doorbell */ |
144 | #define ICP_MPR_EDOOR 0x2c /* volatile u_int8_t, locl to PCI doorbell */ |
145 | #define ICP_EDOOR_EN 0x34 /* u_int8_t, board interrupts enable */ |
146 | #define ICP_SEVERITY 0xefc /* u_int8_t, event severity */ |
147 | #define ICP_EVT_BUF 0xf00 /* u_int8_t [256], event buffer */ |
148 | #define ICP_I960_SZ 0x1000 |
149 | |
150 | /* DPRAM PCI MPR controllers */ |
151 | #define ICP_I960R 0x00 /* 4KB i960 registers */ |
152 | #define ICP_MPR_IC ICP_I960_SZ |
153 | /* interface area */ |
154 | #define ICP_MPR_6SR (ICP_I960_SZ + 0x3000 - ICP_SRAM_SZ) |
155 | /* SRAM structure */ |
156 | #define ICP_MPR_SZ 0x4000 |
157 | |
158 | int icp_pci_match(device_t, cfdata_t, void *); |
159 | void icp_pci_attach(device_t, device_t, void *); |
160 | int icp_pci_rescan(device_t, const char *, const int *); |
161 | void icp_pci_enable_intr(struct icp_softc *); |
162 | int icp_pci_find_class(struct pci_attach_args *); |
163 | |
164 | void icp_pci_copy_cmd(struct icp_softc *, struct icp_ccb *); |
165 | u_int8_t icp_pci_get_status(struct icp_softc *); |
166 | void icp_pci_intr(struct icp_softc *, struct icp_intr_ctx *); |
167 | void icp_pci_release_event(struct icp_softc *, struct icp_ccb *); |
168 | void icp_pci_set_sema0(struct icp_softc *); |
169 | int icp_pci_test_busy(struct icp_softc *); |
170 | |
171 | void icp_pcinew_copy_cmd(struct icp_softc *, struct icp_ccb *); |
172 | u_int8_t icp_pcinew_get_status(struct icp_softc *); |
173 | void icp_pcinew_intr(struct icp_softc *, struct icp_intr_ctx *); |
174 | void icp_pcinew_release_event(struct icp_softc *, struct icp_ccb *); |
175 | void icp_pcinew_set_sema0(struct icp_softc *); |
176 | int icp_pcinew_test_busy(struct icp_softc *); |
177 | |
178 | void icp_mpr_copy_cmd(struct icp_softc *, struct icp_ccb *); |
179 | u_int8_t icp_mpr_get_status(struct icp_softc *); |
180 | void icp_mpr_intr(struct icp_softc *, struct icp_intr_ctx *); |
181 | void icp_mpr_release_event(struct icp_softc *, struct icp_ccb *); |
182 | void icp_mpr_set_sema0(struct icp_softc *); |
183 | int icp_mpr_test_busy(struct icp_softc *); |
184 | |
185 | CFATTACH_DECL3_NEW(icp_pci, sizeof(struct icp_softc), |
186 | icp_pci_match, icp_pci_attach, NULL, NULL, icp_pci_rescan, NULL, 0); |
187 | |
188 | struct icp_pci_ident { |
189 | u_short gpi_vendor; |
190 | u_short gpi_product; |
191 | u_short gpi_class; |
192 | } const icp_pci_ident[] = { |
193 | { PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_60x0, ICP_PCI }, |
194 | { PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6000B, ICP_PCI }, |
195 | |
196 | { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GDT_RAID1, ICP_MPR }, |
197 | { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GDT_RAID2, ICP_MPR }, |
198 | }; |
199 | |
200 | int |
201 | icp_pci_find_class(struct pci_attach_args *pa) |
202 | { |
203 | const struct icp_pci_ident *gpi, *maxgpi; |
204 | |
205 | gpi = icp_pci_ident; |
206 | maxgpi = gpi + sizeof(icp_pci_ident) / sizeof(icp_pci_ident[0]); |
207 | |
208 | for (; gpi < maxgpi; gpi++) |
209 | if (PCI_VENDOR(pa->pa_id) == gpi->gpi_vendor && |
210 | PCI_PRODUCT(pa->pa_id) == gpi->gpi_product) |
211 | return (gpi->gpi_class); |
212 | |
213 | /* |
214 | * ICP-Vortex only make RAID controllers, so we employ a heuristic |
215 | * to match unlisted boards. |
216 | */ |
217 | if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_VORTEX) |
218 | return (PCI_PRODUCT(pa->pa_id) < 0x100 ? ICP_PCINEW : ICP_MPR); |
219 | |
220 | return (-1); |
221 | } |
222 | |
223 | int |
224 | icp_pci_match(device_t parent, cfdata_t match, void *aux) |
225 | { |
226 | struct pci_attach_args *pa; |
227 | |
228 | pa = aux; |
229 | |
230 | if (PCI_CLASS(pa->pa_class) == PCI_CLASS_I2O) |
231 | return (0); |
232 | |
233 | return (icp_pci_find_class(pa) != -1); |
234 | } |
235 | |
236 | void |
237 | icp_pci_attach(device_t parent, device_t self, void *aux) |
238 | { |
239 | struct pci_attach_args *pa; |
240 | struct icp_softc *icp; |
241 | bus_space_tag_t dpmemt, iomemt, iot; |
242 | bus_space_handle_t dpmemh, iomemh, ioh; |
243 | bus_addr_t dpmembase, iomembase, iobase; |
244 | bus_size_t dpmemsize, iomemsize, iosize; |
245 | u_int32_t status; |
246 | #define DPMEM_MAPPED 1 |
247 | #define IOMEM_MAPPED 2 |
248 | #define IO_MAPPED 4 |
249 | #define INTR_ESTABLISHED 8 |
250 | int retries; |
251 | u_int8_t protocol; |
252 | pci_intr_handle_t ih; |
253 | const char *intrstr; |
254 | char intrbuf[PCI_INTRSTR_LEN]; |
255 | |
256 | pa = aux; |
257 | status = 0; |
258 | icp = device_private(self); |
259 | icp->icp_dv = self; |
260 | icp->icp_class = icp_pci_find_class(pa); |
261 | |
262 | aprint_naive(": RAID controller\n" ); |
263 | aprint_normal(": " ); |
264 | |
265 | if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_VORTEX && |
266 | PCI_PRODUCT(pa->pa_id) >= ICP_PCI_PRODUCT_FC) |
267 | icp->icp_class |= ICP_FC; |
268 | |
269 | if (pci_mapreg_map(pa, |
270 | ICP_CLASS(icp) == ICP_PCINEW ? ICP_PCINEW_DPMEM : ICP_PCI_DPMEM, |
271 | PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, &dpmemt, |
272 | &dpmemh, &dpmembase, &dpmemsize)) { |
273 | if (pci_mapreg_map(pa, |
274 | ICP_CLASS(icp) == ICP_PCINEW ? ICP_PCINEW_DPMEM : |
275 | ICP_PCI_DPMEM, |
276 | PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT_1M, 0, |
277 | &dpmemt, &dpmemh, &dpmembase, &dpmemsize)) { |
278 | aprint_error("cannot map DPMEM\n" ); |
279 | goto bail_out; |
280 | } |
281 | } |
282 | status |= DPMEM_MAPPED; |
283 | icp->icp_dpmemt = dpmemt; |
284 | icp->icp_dpmemh = dpmemh; |
285 | icp->icp_dpmembase = dpmembase; |
286 | icp->icp_dmat = pa->pa_dmat; |
287 | |
288 | /* |
289 | * The ICP_PCINEW series also has two other regions to map. |
290 | */ |
291 | if (ICP_CLASS(icp) == ICP_PCINEW) { |
292 | if (pci_mapreg_map(pa, ICP_PCINEW_IOMEM, PCI_MAPREG_TYPE_MEM, |
293 | 0, &iomemt, &iomemh, &iomembase, &iomemsize)) { |
294 | aprint_error("cannot map memory mapped I/O ports\n" ); |
295 | goto bail_out; |
296 | } |
297 | status |= IOMEM_MAPPED; |
298 | |
299 | if (pci_mapreg_map(pa, ICP_PCINEW_IO, PCI_MAPREG_TYPE_IO, 0, |
300 | &iot, &ioh, &iobase, &iosize)) { |
301 | aprint_error("cannot map I/O ports\n" ); |
302 | goto bail_out; |
303 | } |
304 | status |= IO_MAPPED; |
305 | icp->icp_iot = iot; |
306 | icp->icp_ioh = ioh; |
307 | icp->icp_iobase = iobase; |
308 | } |
309 | |
310 | switch (ICP_CLASS(icp)) { |
311 | case ICP_PCI: |
312 | bus_space_set_region_4(dpmemt, dpmemh, 0, 0, |
313 | ICP_DPR_IF_SZ >> 2); |
314 | if (bus_space_read_1(dpmemt, dpmemh, 0) != 0) { |
315 | aprint_error("cannot write to DPMEM\n" ); |
316 | goto bail_out; |
317 | } |
318 | |
319 | #if 0 |
320 | /* disable board interrupts, deinit services */ |
321 | icph_writeb(0xff, &dp6_ptr->io.irqdel); |
322 | icph_writeb(0x00, &dp6_ptr->io.irqen); |
323 | icph_writeb(0x00, &dp6_ptr->u.ic.S_Status); |
324 | icph_writeb(0x00, &dp6_ptr->u.ic.Cmd_Index); |
325 | |
326 | icph_writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]); |
327 | icph_writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx); |
328 | icph_writeb(0, &dp6_ptr->io.event); |
329 | retries = INIT_RETRIES; |
330 | icph_delay(20); |
331 | while (icph_readb(&dp6_ptr->u.ic.S_Status) != 0xff) { |
332 | if (--retries == 0) { |
333 | printk("initialization error (DEINIT failed)\n" ); |
334 | icph_munmap(ha->brd); |
335 | return 0; |
336 | } |
337 | icph_delay(1); |
338 | } |
339 | prot_ver = (unchar)icph_readl(&dp6_ptr->u.ic.S_Info[0]); |
340 | icph_writeb(0, &dp6_ptr->u.ic.S_Status); |
341 | icph_writeb(0xff, &dp6_ptr->io.irqdel); |
342 | if (prot_ver != PROTOCOL_VERSION) { |
343 | printk("illegal protocol version\n" ); |
344 | icph_munmap(ha->brd); |
345 | return 0; |
346 | } |
347 | |
348 | ha->type = ICP_PCI; |
349 | ha->ic_all_size = sizeof(dp6_ptr->u); |
350 | |
351 | /* special command to controller BIOS */ |
352 | icph_writel(0x00, &dp6_ptr->u.ic.S_Info[0]); |
353 | icph_writel(0x00, &dp6_ptr->u.ic.S_Info[1]); |
354 | icph_writel(0x01, &dp6_ptr->u.ic.S_Info[2]); |
355 | icph_writel(0x00, &dp6_ptr->u.ic.S_Info[3]); |
356 | icph_writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx); |
357 | icph_writeb(0, &dp6_ptr->io.event); |
358 | retries = INIT_RETRIES; |
359 | icph_delay(20); |
360 | while (icph_readb(&dp6_ptr->u.ic.S_Status) != 0xfe) { |
361 | if (--retries == 0) { |
362 | printk("initialization error\n" ); |
363 | icph_munmap(ha->brd); |
364 | return 0; |
365 | } |
366 | icph_delay(1); |
367 | } |
368 | icph_writeb(0, &dp6_ptr->u.ic.S_Status); |
369 | icph_writeb(0xff, &dp6_ptr->io.irqdel); |
370 | #endif |
371 | |
372 | icp->icp_ic_all_size = ICP_DPRAM_SZ; |
373 | |
374 | icp->icp_copy_cmd = icp_pci_copy_cmd; |
375 | icp->icp_get_status = icp_pci_get_status; |
376 | icp->icp_intr = icp_pci_intr; |
377 | icp->icp_release_event = icp_pci_release_event; |
378 | icp->icp_set_sema0 = icp_pci_set_sema0; |
379 | icp->icp_test_busy = icp_pci_test_busy; |
380 | |
381 | break; |
382 | |
383 | case ICP_PCINEW: |
384 | bus_space_set_region_4(dpmemt, dpmemh, 0, 0, |
385 | ICP_DPR_IF_SZ >> 2); |
386 | if (bus_space_read_1(dpmemt, dpmemh, 0) != 0) { |
387 | aprint_error("cannot write to DPMEM\n" ); |
388 | goto bail_out; |
389 | } |
390 | |
391 | #if 0 |
392 | /* disable board interrupts, deinit services */ |
393 | outb(0x00,PTR2USHORT(&ha->plx->control1)); |
394 | outb(0xff,PTR2USHORT(&ha->plx->edoor_reg)); |
395 | |
396 | icph_writeb(0x00, &dp6c_ptr->u.ic.S_Status); |
397 | icph_writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index); |
398 | |
399 | icph_writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]); |
400 | icph_writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx); |
401 | |
402 | outb(1,PTR2USHORT(&ha->plx->ldoor_reg)); |
403 | |
404 | retries = INIT_RETRIES; |
405 | icph_delay(20); |
406 | while (icph_readb(&dp6c_ptr->u.ic.S_Status) != 0xff) { |
407 | if (--retries == 0) { |
408 | printk("initialization error (DEINIT failed)\n" ); |
409 | icph_munmap(ha->brd); |
410 | return 0; |
411 | } |
412 | icph_delay(1); |
413 | } |
414 | prot_ver = (unchar)icph_readl(&dp6c_ptr->u.ic.S_Info[0]); |
415 | icph_writeb(0, &dp6c_ptr->u.ic.Status); |
416 | if (prot_ver != PROTOCOL_VERSION) { |
417 | printk("illegal protocol version\n" ); |
418 | icph_munmap(ha->brd); |
419 | return 0; |
420 | } |
421 | |
422 | ha->type = ICP_PCINEW; |
423 | ha->ic_all_size = sizeof(dp6c_ptr->u); |
424 | |
425 | /* special command to controller BIOS */ |
426 | icph_writel(0x00, &dp6c_ptr->u.ic.S_Info[0]); |
427 | icph_writel(0x00, &dp6c_ptr->u.ic.S_Info[1]); |
428 | icph_writel(0x01, &dp6c_ptr->u.ic.S_Info[2]); |
429 | icph_writel(0x00, &dp6c_ptr->u.ic.S_Info[3]); |
430 | icph_writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx); |
431 | |
432 | outb(1,PTR2USHORT(&ha->plx->ldoor_reg)); |
433 | |
434 | retries = INIT_RETRIES; |
435 | icph_delay(20); |
436 | while (icph_readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) { |
437 | if (--retries == 0) { |
438 | printk("initialization error\n" ); |
439 | icph_munmap(ha->brd); |
440 | return 0; |
441 | } |
442 | icph_delay(1); |
443 | } |
444 | icph_writeb(0, &dp6c_ptr->u.ic.S_Status); |
445 | #endif |
446 | |
447 | icp->icp_ic_all_size = ICP_PCINEW_SZ; |
448 | |
449 | icp->icp_copy_cmd = icp_pcinew_copy_cmd; |
450 | icp->icp_get_status = icp_pcinew_get_status; |
451 | icp->icp_intr = icp_pcinew_intr; |
452 | icp->icp_release_event = icp_pcinew_release_event; |
453 | icp->icp_set_sema0 = icp_pcinew_set_sema0; |
454 | icp->icp_test_busy = icp_pcinew_test_busy; |
455 | |
456 | break; |
457 | |
458 | case ICP_MPR: |
459 | bus_space_write_4(dpmemt, dpmemh, ICP_MPR_IC, ICP_MPR_MAGIC); |
460 | if (bus_space_read_4(dpmemt, dpmemh, ICP_MPR_IC) != |
461 | ICP_MPR_MAGIC) { |
462 | aprint_error( |
463 | "cannot access DPMEM at 0x%lx (shadowed?)\n" , |
464 | (u_long)dpmembase); |
465 | goto bail_out; |
466 | } |
467 | |
468 | /* |
469 | * XXX Here the Linux driver has a weird remapping logic I |
470 | * don't understand. My controller does not need it, and I |
471 | * cannot see what purpose it serves, therefore I did not |
472 | * do anything similar. |
473 | */ |
474 | |
475 | bus_space_set_region_4(dpmemt, dpmemh, ICP_I960_SZ, 0, |
476 | ICP_DPR_IF_SZ >> 2); |
477 | |
478 | /* Disable everything. */ |
479 | bus_space_write_1(dpmemt, dpmemh, ICP_EDOOR_EN, |
480 | bus_space_read_1(dpmemt, dpmemh, ICP_EDOOR_EN) | 4); |
481 | bus_space_write_1(dpmemt, dpmemh, ICP_MPR_EDOOR, 0xff); |
482 | bus_space_write_1(dpmemt, dpmemh, ICP_MPR_IC + ICP_S_STATUS, |
483 | 0); |
484 | bus_space_write_1(dpmemt, dpmemh, ICP_MPR_IC + ICP_CMD_INDEX, |
485 | 0); |
486 | |
487 | bus_space_write_4(dpmemt, dpmemh, ICP_MPR_IC + ICP_S_INFO, |
488 | htole32(dpmembase)); |
489 | bus_space_write_1(dpmemt, dpmemh, ICP_MPR_IC + ICP_S_CMD_INDX, |
490 | 0xff); |
491 | bus_space_write_1(dpmemt, dpmemh, ICP_MPR_LDOOR, 1); |
492 | |
493 | DELAY(20); |
494 | retries = 1000000; |
495 | while (bus_space_read_1(dpmemt, dpmemh, |
496 | ICP_MPR_IC + ICP_S_STATUS) != 0xff) { |
497 | if (--retries == 0) { |
498 | aprint_error("DEINIT failed\n" ); |
499 | goto bail_out; |
500 | } |
501 | DELAY(1); |
502 | } |
503 | |
504 | protocol = (u_int8_t)bus_space_read_4(dpmemt, dpmemh, |
505 | ICP_MPR_IC + ICP_S_INFO); |
506 | bus_space_write_1(dpmemt, dpmemh, ICP_MPR_IC + ICP_S_STATUS, |
507 | 0); |
508 | if (protocol != ICP_PROTOCOL_VERSION) { |
509 | aprint_error("unsupported protocol %d\n" , protocol); |
510 | goto bail_out; |
511 | } |
512 | |
513 | /* special commnd to controller BIOS */ |
514 | bus_space_write_4(dpmemt, dpmemh, ICP_MPR_IC + ICP_S_INFO, 0); |
515 | bus_space_write_4(dpmemt, dpmemh, |
516 | ICP_MPR_IC + ICP_S_INFO + sizeof(u_int32_t), 0); |
517 | bus_space_write_4(dpmemt, dpmemh, |
518 | ICP_MPR_IC + ICP_S_INFO + 2 * sizeof(u_int32_t), 1); |
519 | bus_space_write_4(dpmemt, dpmemh, |
520 | ICP_MPR_IC + ICP_S_INFO + 3 * sizeof(u_int32_t), 0); |
521 | bus_space_write_1(dpmemt, dpmemh, ICP_MPR_IC + ICP_S_CMD_INDX, |
522 | 0xfe); |
523 | bus_space_write_1(dpmemt, dpmemh, ICP_MPR_LDOOR, 1); |
524 | |
525 | DELAY(20); |
526 | retries = 1000000; |
527 | while (bus_space_read_1(dpmemt, dpmemh, |
528 | ICP_MPR_IC + ICP_S_STATUS) != 0xfe) { |
529 | if (--retries == 0) { |
530 | aprint_error("initialization error\n" ); |
531 | goto bail_out; |
532 | } |
533 | DELAY(1); |
534 | } |
535 | |
536 | bus_space_write_1(dpmemt, dpmemh, ICP_MPR_IC + ICP_S_STATUS, |
537 | 0); |
538 | |
539 | icp->icp_copy_cmd = icp_mpr_copy_cmd; |
540 | icp->icp_get_status = icp_mpr_get_status; |
541 | icp->icp_intr = icp_mpr_intr; |
542 | icp->icp_release_event = icp_mpr_release_event; |
543 | icp->icp_set_sema0 = icp_mpr_set_sema0; |
544 | icp->icp_test_busy = icp_mpr_test_busy; |
545 | break; |
546 | } |
547 | |
548 | if (pci_intr_map(pa, &ih)) { |
549 | aprint_error("couldn't map interrupt\n" ); |
550 | goto bail_out; |
551 | } |
552 | intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf)); |
553 | icp->icp_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, icp_intr, icp); |
554 | if (icp->icp_ih == NULL) { |
555 | aprint_error("couldn't establish interrupt" ); |
556 | if (intrstr != NULL) |
557 | aprint_error(" at %s" , intrstr); |
558 | aprint_error("\n" ); |
559 | goto bail_out; |
560 | } |
561 | status |= INTR_ESTABLISHED; |
562 | |
563 | if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL) |
564 | aprint_normal("Intel Storage RAID controller\n" ); |
565 | else |
566 | aprint_normal("ICP-Vortex RAID controller\n" ); |
567 | |
568 | icp->icp_pci_bus = pa->pa_bus; |
569 | icp->icp_pci_device = pa->pa_device; |
570 | icp->icp_pci_device_id = PCI_PRODUCT(pa->pa_id); |
571 | icp->icp_pci_subdevice_id = pci_conf_read(pa->pa_pc, pa->pa_tag, |
572 | PCI_SUBSYS_ID_REG); |
573 | |
574 | if (icp_init(icp, intrstr)) |
575 | goto bail_out; |
576 | |
577 | icp_pci_enable_intr(icp); |
578 | return; |
579 | |
580 | bail_out: |
581 | if ((status & DPMEM_MAPPED) != 0) |
582 | bus_space_unmap(dpmemt, dpmemh, dpmemsize); |
583 | if ((status & IOMEM_MAPPED) != 0) |
584 | bus_space_unmap(iomemt, iomemh, iomembase); |
585 | if ((status & IO_MAPPED) != 0) |
586 | bus_space_unmap(iot, ioh, iosize); |
587 | if ((status & INTR_ESTABLISHED) != 0) |
588 | pci_intr_disestablish(pa->pa_pc, icp->icp_ih); |
589 | } |
590 | |
591 | int |
592 | icp_pci_rescan(device_t self, const char *attr, const int *flags) |
593 | { |
594 | |
595 | icp_rescan_all(device_private(self)); |
596 | return 0; |
597 | } |
598 | |
599 | /* |
600 | * Enable interrupts. |
601 | */ |
602 | void |
603 | icp_pci_enable_intr(struct icp_softc *icp) |
604 | { |
605 | |
606 | switch (ICP_CLASS(icp)) { |
607 | case ICP_PCI: |
608 | bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_IRQDEL, |
609 | 1); |
610 | bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, |
611 | ICP_CMD_INDEX, 0); |
612 | bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_IRQEN, |
613 | 1); |
614 | break; |
615 | |
616 | case ICP_PCINEW: |
617 | bus_space_write_1(icp->icp_iot, icp->icp_ioh, ICP_EDOOR_REG, |
618 | 0xff); |
619 | bus_space_write_1(icp->icp_iot, icp->icp_ioh, ICP_CONTROL1, 3); |
620 | break; |
621 | |
622 | case ICP_MPR: |
623 | bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, |
624 | ICP_MPR_EDOOR, 0xff); |
625 | bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_EDOOR_EN, |
626 | bus_space_read_1(icp->icp_dpmemt, icp->icp_dpmemh, |
627 | ICP_EDOOR_EN) & ~4); |
628 | break; |
629 | } |
630 | } |
631 | |
632 | /* |
633 | * "Old" PCI controller-specific functions. |
634 | */ |
635 | |
636 | void |
637 | icp_pci_copy_cmd(struct icp_softc *icp, struct icp_ccb *ccb) |
638 | { |
639 | |
640 | /* XXX Not yet implemented */ |
641 | } |
642 | |
643 | u_int8_t |
644 | icp_pci_get_status(struct icp_softc *icp) |
645 | { |
646 | |
647 | /* XXX Not yet implemented */ |
648 | return (0); |
649 | } |
650 | |
651 | void |
652 | icp_pci_intr(struct icp_softc *icp, struct icp_intr_ctx *ctx) |
653 | { |
654 | |
655 | /* XXX Not yet implemented */ |
656 | } |
657 | |
658 | void |
659 | icp_pci_release_event(struct icp_softc *icp, |
660 | struct icp_ccb *ccb) |
661 | { |
662 | |
663 | /* XXX Not yet implemented */ |
664 | } |
665 | |
666 | void |
667 | icp_pci_set_sema0(struct icp_softc *icp) |
668 | { |
669 | |
670 | bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_SEMA0, 1); |
671 | } |
672 | |
673 | int |
674 | icp_pci_test_busy(struct icp_softc *icp) |
675 | { |
676 | |
677 | /* XXX Not yet implemented */ |
678 | return (0); |
679 | } |
680 | |
681 | /* |
682 | * "New" PCI controller-specific functions. |
683 | */ |
684 | |
685 | void |
686 | icp_pcinew_copy_cmd(struct icp_softc *icp, |
687 | struct icp_ccb *ccb) |
688 | { |
689 | |
690 | /* XXX Not yet implemented */ |
691 | } |
692 | |
693 | u_int8_t |
694 | icp_pcinew_get_status(struct icp_softc *icp) |
695 | { |
696 | |
697 | /* XXX Not yet implemented */ |
698 | return (0); |
699 | } |
700 | |
701 | void |
702 | icp_pcinew_intr(struct icp_softc *icp, |
703 | struct icp_intr_ctx *ctx) |
704 | { |
705 | |
706 | /* XXX Not yet implemented */ |
707 | } |
708 | |
709 | void |
710 | icp_pcinew_release_event(struct icp_softc *icp, |
711 | struct icp_ccb *ccb) |
712 | { |
713 | |
714 | /* XXX Not yet implemented */ |
715 | } |
716 | |
717 | void |
718 | icp_pcinew_set_sema0(struct icp_softc *icp) |
719 | { |
720 | |
721 | bus_space_write_1(icp->icp_iot, icp->icp_ioh, ICP_SEMA0_REG, 1); |
722 | } |
723 | |
724 | int |
725 | icp_pcinew_test_busy(struct icp_softc *icp) |
726 | { |
727 | |
728 | /* XXX Not yet implemented */ |
729 | return (0); |
730 | } |
731 | |
732 | /* |
733 | * MPR PCI controller-specific functions |
734 | */ |
735 | |
736 | void |
737 | icp_mpr_copy_cmd(struct icp_softc *icp, struct icp_ccb *ic) |
738 | { |
739 | |
740 | bus_space_write_2(icp->icp_dpmemt, icp->icp_dpmemh, |
741 | ICP_MPR_IC + ICP_COMM_QUEUE + 0 * ICP_COMM_Q_SZ + ICP_OFFSET, |
742 | ICP_DPR_CMD); |
743 | bus_space_write_2(icp->icp_dpmemt, icp->icp_dpmemh, |
744 | ICP_MPR_IC + ICP_COMM_QUEUE + 0 * ICP_COMM_Q_SZ + ICP_SERV_ID, |
745 | ic->ic_service); |
746 | bus_space_write_region_4(icp->icp_dpmemt, icp->icp_dpmemh, |
747 | ICP_MPR_IC + ICP_DPR_CMD, (u_int32_t *)&ic->ic_cmd, |
748 | ic->ic_cmdlen >> 2); |
749 | } |
750 | |
751 | u_int8_t |
752 | icp_mpr_get_status(struct icp_softc *icp) |
753 | { |
754 | |
755 | return (bus_space_read_1(icp->icp_dpmemt, icp->icp_dpmemh, |
756 | ICP_MPR_EDOOR)); |
757 | } |
758 | |
759 | void |
760 | icp_mpr_intr(struct icp_softc *icp, struct icp_intr_ctx *ctx) |
761 | { |
762 | |
763 | if ((ctx->istatus & 0x80) != 0) { /* error flag */ |
764 | ctx->istatus &= ~0x80; |
765 | ctx->cmd_status = bus_space_read_2(icp->icp_dpmemt, |
766 | icp->icp_dpmemh, ICP_MPR_STATUS); |
767 | } else |
768 | ctx->cmd_status = ICP_S_OK; |
769 | |
770 | ctx->service = bus_space_read_2(icp->icp_dpmemt, icp->icp_dpmemh, |
771 | ICP_MPR_SERVICE); |
772 | ctx->info = bus_space_read_4(icp->icp_dpmemt, icp->icp_dpmemh, |
773 | ICP_MPR_INFO); |
774 | ctx->info2 = bus_space_read_4(icp->icp_dpmemt, icp->icp_dpmemh, |
775 | ICP_MPR_INFO + sizeof(u_int32_t)); |
776 | |
777 | if (ctx->istatus == ICP_ASYNCINDEX) { |
778 | if (ctx->service != ICP_SCREENSERVICE && |
779 | (icp->icp_fw_vers & 0xff) >= 0x1a) { |
780 | int i; |
781 | |
782 | icp->icp_evt.severity = |
783 | bus_space_read_1(icp->icp_dpmemt, |
784 | icp->icp_dpmemh, ICP_SEVERITY); |
785 | for (i = 0; |
786 | i < sizeof(icp->icp_evt.event_string); i++) { |
787 | icp->icp_evt.event_string[i] = |
788 | bus_space_read_1(icp->icp_dpmemt, |
789 | icp->icp_dpmemh, ICP_EVT_BUF + i); |
790 | if (icp->icp_evt.event_string[i] == '\0') |
791 | break; |
792 | } |
793 | } |
794 | } |
795 | |
796 | bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_MPR_EDOOR, |
797 | 0xff); |
798 | bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_MPR_SEMA1, 0); |
799 | } |
800 | |
801 | void |
802 | icp_mpr_release_event(struct icp_softc *icp, struct icp_ccb *ic) |
803 | { |
804 | |
805 | bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_MPR_LDOOR, 1); |
806 | } |
807 | |
808 | void |
809 | icp_mpr_set_sema0(struct icp_softc *icp) |
810 | { |
811 | |
812 | bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_MPR_SEMA0, 1); |
813 | } |
814 | |
815 | int |
816 | icp_mpr_test_busy(struct icp_softc *icp) |
817 | { |
818 | |
819 | return (bus_space_read_1(icp->icp_dpmemt, icp->icp_dpmemh, |
820 | ICP_MPR_SEMA0) & 1); |
821 | } |
822 | |