1 /* $NetBSD: cac_pci.c,v 1.31 2009/05/12 08:23:00 cegger Exp $ */
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
33 * PCI front-end for cac(4) driver.
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: cac_pci.c,v 1.31 2009/05/12 08:23:00 cegger Exp $");
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/device.h>
43 #include <sys/queue.h>
45 #include <machine/endian.h>
48 #include <dev/pci/pcidevs.h>
49 #include <dev/pci/pcivar.h>
51 #include <dev/ic/cacreg.h>
52 #include <dev/ic/cacvar.h>
54 static struct cac_ccb
*cac_pci_l0_completed(struct cac_softc
*);
55 static int cac_pci_l0_fifo_full(struct cac_softc
*);
56 static void cac_pci_l0_intr_enable(struct cac_softc
*, int);
57 static int cac_pci_l0_intr_pending(struct cac_softc
*);
58 static void cac_pci_l0_submit(struct cac_softc
*, struct cac_ccb
*);
60 static const struct cac_linkage cac_pci_l0
= {
63 cac_pci_l0_intr_enable
,
64 cac_pci_l0_intr_pending
,
68 #define CT_STARTFW 0x01 /* Need to start controller firmware */
70 static struct cac_pci_type
{
73 const struct cac_linkage
*ct_linkage
;
74 const char *ct_typestr
;
75 } const cac_pci_type
[] = {
76 { 0x40300e11, 0, &cac_l0
, "SMART-2/P" },
77 { 0x40310e11, 0, &cac_l0
, "SMART-2SL" },
78 { 0x40320e11, 0, &cac_l0
, "Smart Array 3200" },
79 { 0x40330e11, 0, &cac_l0
, "Smart Array 3100ES" },
80 { 0x40340e11, 0, &cac_l0
, "Smart Array 221" },
81 { 0x40400e11, CT_STARTFW
, &cac_pci_l0
, "Integrated Array" },
82 { 0x40480e11, CT_STARTFW
, &cac_pci_l0
, "RAID LC2" },
83 { 0x40500e11, 0, &cac_pci_l0
, "Smart Array 4200" },
84 { 0x40510e11, 0, &cac_pci_l0
, "Smart Array 4200ES" },
85 { 0x40580e11, 0, &cac_pci_l0
, "Smart Array 431" },
88 static struct cac_pci_product
{
91 } const cac_pci_product
[] = {
92 { PCI_VENDOR_COMPAQ
, PCI_PRODUCT_COMPAQ_SMART2P
},
93 { PCI_VENDOR_DEC
, PCI_PRODUCT_DEC_21554
},
94 { PCI_VENDOR_SYMBIOS
, PCI_PRODUCT_SYMBIOS_1510
},
97 static const struct cac_pci_type
*
98 cac_pci_findtype(struct pci_attach_args
*pa
)
100 const struct cac_pci_type
*ct
;
101 const struct cac_pci_product
*cp
;
105 cp
= cac_pci_product
;
107 while (i
< sizeof(cac_pci_product
) / sizeof(cac_pci_product
[0])) {
108 if (PCI_VENDOR(pa
->pa_id
) == cp
->cp_vendor
&&
109 PCI_PRODUCT(pa
->pa_id
) == cp
->cp_product
)
114 if (i
== sizeof(cac_pci_product
) / sizeof(cac_pci_product
[0]))
117 subsysid
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, PCI_SUBSYS_ID_REG
);
120 while (i
< sizeof(cac_pci_type
) / sizeof(cac_pci_type
[0])) {
121 if (subsysid
== ct
->ct_subsysid
)
126 if (i
== sizeof(cac_pci_type
) / sizeof(cac_pci_type
[0]))
133 cac_pci_match(device_t parent
, cfdata_t match
, void *aux
)
136 return (cac_pci_findtype(aux
) != NULL
);
140 cac_pci_attach(device_t parent
, device_t self
, void *aux
)
142 struct pci_attach_args
*pa
;
143 const struct cac_pci_type
*ct
;
144 struct cac_softc
*sc
;
145 pci_chipset_tag_t pc
;
146 pci_intr_handle_t ih
;
151 aprint_naive(": RAID controller\n");
153 sc
= device_private(self
);
154 pa
= (struct pci_attach_args
*)aux
;
156 ct
= cac_pci_findtype(pa
);
159 * Map the PCI register window.
164 for (i
= 0x10; i
<= 0x14; i
+= 4) {
165 reg
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, i
);
167 if (PCI_MAPREG_TYPE(reg
) == PCI_MAPREG_TYPE_IO
) {
168 if (ior
== -1 && PCI_MAPREG_IO_SIZE(reg
) != 0)
171 if (memr
== -1 && PCI_MAPREG_MEM_SIZE(reg
) != 0)
177 if (pci_mapreg_map(pa
, memr
, PCI_MAPREG_TYPE_MEM
, 0,
178 &sc
->sc_iot
, &sc
->sc_ioh
, NULL
, NULL
))
184 if (pci_mapreg_map(pa
, ior
, PCI_MAPREG_TYPE_IO
, 0,
185 &sc
->sc_iot
, &sc
->sc_ioh
, NULL
, NULL
))
187 if (memr
== -1 && ior
== -1) {
188 aprint_error_dev(self
, "can't map i/o or memory space\n");
192 sc
->sc_dmat
= pa
->pa_dmat
;
194 /* Enable the device. */
195 reg
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, PCI_COMMAND_STATUS_REG
);
196 pci_conf_write(pa
->pa_pc
, pa
->pa_tag
, PCI_COMMAND_STATUS_REG
,
197 reg
| PCI_COMMAND_MASTER_ENABLE
);
199 /* Map and establish the interrupt. */
200 if (pci_intr_map(pa
, &ih
)) {
201 aprint_error("can't map interrupt\n");
204 intrstr
= pci_intr_string(pc
, ih
);
205 sc
->sc_ih
= pci_intr_establish(pc
, ih
, IPL_BIO
, cac_intr
, sc
);
206 if (sc
->sc_ih
== NULL
) {
207 aprint_error("can't establish interrupt");
209 aprint_error(" at %s", intrstr
);
214 aprint_normal(": Compaq %s\n", ct
->ct_typestr
);
216 /* Now attach to the bus-independent code. */
217 memcpy(&sc
->sc_cl
, ct
->ct_linkage
, sizeof(sc
->sc_cl
));
218 cac_init(sc
, intrstr
, (ct
->ct_flags
& CT_STARTFW
) != 0);
221 CFATTACH_DECL(cac_pci
, sizeof(struct cac_softc
),
222 cac_pci_match
, cac_pci_attach
, NULL
, NULL
);
225 cac_pci_l0_submit(struct cac_softc
*sc
, struct cac_ccb
*ccb
)
228 bus_dmamap_sync(sc
->sc_dmat
, sc
->sc_dmamap
,
229 (char *)ccb
- (char *)sc
->sc_ccbs
,
230 sizeof(struct cac_ccb
), BUS_DMASYNC_PREWRITE
| BUS_DMASYNC_PREREAD
);
231 cac_outl(sc
, CAC_42REG_CMD_FIFO
, ccb
->ccb_paddr
);
234 static struct cac_ccb
*
235 cac_pci_l0_completed(struct cac_softc
*sc
)
240 if ((off
= cac_inl(sc
, CAC_42REG_DONE_FIFO
)) == 0xffffffffU
)
243 cac_outl(sc
, CAC_42REG_DONE_FIFO
, 0);
246 printf("%s: failed command list returned: %lx\n",
247 device_xname(&sc
->sc_dv
), (long)off
);
249 off
= (off
& ~3) - sc
->sc_ccbs_paddr
;
250 ccb
= (struct cac_ccb
*)((char *)sc
->sc_ccbs
+ off
);
252 bus_dmamap_sync(sc
->sc_dmat
, sc
->sc_dmamap
, off
, sizeof(struct cac_ccb
),
253 BUS_DMASYNC_PREWRITE
| BUS_DMASYNC_PREREAD
);
255 if ((off
& 3) != 0 && ccb
->ccb_req
.error
== 0)
256 ccb
->ccb_req
.error
= CAC_RET_CMD_REJECTED
;
262 cac_pci_l0_intr_pending(struct cac_softc
*sc
)
265 return ((cac_inl(sc
, CAC_42REG_STATUS
) & CAC_42_EXTINT
) != 0);
269 cac_pci_l0_intr_enable(struct cac_softc
*sc
, int state
)
272 cac_outl(sc
, CAC_42REG_INTR_MASK
, (state
? 0 : 8)); /* XXX */
276 cac_pci_l0_fifo_full(struct cac_softc
*sc
)
279 return (cac_inl(sc
, CAC_42REG_CMD_FIFO
) != 0);