2 * Copyright (c) 2000 Michael Smith
3 * Copyright (c) 2001 Scott Long
4 * Copyright (c) 2000 BSDi
5 * Copyright (c) 2001 Adaptec, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * PCI bus interface and resource allocation.
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
42 #include <dev/aac/aac_compat.h>
45 #include <sys/devicestat.h>
48 #include <machine/bus_memio.h>
49 #include <machine/bus.h>
50 #include <machine/resource.h>
53 #include <pci/pcireg.h>
54 #include <pci/pcivar.h>
56 #include <dev/aac/aacreg.h>
57 #include <dev/aac/aac_ioctl.h>
58 #include <dev/aac/aacvar.h>
60 static int aac_pci_probe(device_t dev);
61 static int aac_pci_attach(device_t dev);
63 static device_method_t aac_methods[] = {
64 /* Device interface */
65 DEVMETHOD(device_probe, aac_pci_probe),
66 DEVMETHOD(device_attach, aac_pci_attach),
67 DEVMETHOD(device_detach, aac_detach),
68 DEVMETHOD(device_suspend, aac_suspend),
69 DEVMETHOD(device_resume, aac_resume),
71 DEVMETHOD(bus_print_child, bus_generic_print_child),
72 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
76 static driver_t aac_pci_driver = {
79 sizeof(struct aac_softc)
82 static devclass_t aac_devclass;
84 DRIVER_MODULE(aac, pci, aac_pci_driver, aac_devclass, 0, 0);
95 } aac_identifiers[] = {
96 {0x1028, 0x0001, 0x1028, 0x0001, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
98 {0x1028, 0x0002, 0x1028, 0x0002, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
100 {0x1028, 0x0003, 0x1028, 0x0003, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
102 {0x1028, 0x0004, 0x1028, 0x00d0, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
104 {0x1028, 0x0002, 0x1028, 0x00d1, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
106 {0x1028, 0x0002, 0x1028, 0x00d9, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
108 {0x1028, 0x0008, 0x1028, 0x00cf, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
110 {0x1028, 0x000a, 0x1028, 0x0106, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
112 {0x1028, 0x000a, 0x1028, 0x011b, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
114 {0x1028, 0x000a, 0x1028, 0x0121, AAC_HWIF_I960RX, AAC_QUIRK_NOCAM,
116 {0x1011, 0x0046, 0x9005, 0x0364, AAC_HWIF_STRONGARM, AAC_QUIRK_NOCAM,
118 {0x1011, 0x0046, 0x9005, 0x0365, AAC_HWIF_STRONGARM, 0,
119 "Adaptec SCSI RAID 5400S"},
120 {0x1011, 0x0046, 0x9005, 0x1364, AAC_HWIF_STRONGARM, AAC_QUIRK_NOCAM |
121 AAC_QUIRK_PERC2QC, "Dell PERC 2/QC"},
122 {0x1011, 0x0046, 0x103c, 0x10c2, AAC_HWIF_STRONGARM,
123 AAC_QUIRK_CAM_NORESET, "HP NetRaid-4M"},
124 {0x9005, 0x0285, 0x9005, 0x0285, AAC_HWIF_I960RX, 0,
125 "Adaptec SCSI RAID 2200S"},
126 {0x9005, 0x0285, 0x1028, 0x0287, AAC_HWIF_I960RX, 0,
128 {0x9005, 0x0285, 0x9005, 0x0286, AAC_HWIF_I960RX, 0,
129 "Adaptec SCSI RAID 2120S"},
130 {0, 0, 0, 0, 0, 0, 0}
134 * Determine whether this is one of our supported adapters.
137 aac_pci_probe(device_t dev)
143 for (m = aac_identifiers; m->vendor != 0; m++) {
144 if ((m->vendor == pci_get_vendor(dev)) &&
145 (m->device == pci_get_device(dev)) &&
146 ((m->subvendor == 0) || (m->subvendor ==
147 pci_get_subvendor(dev))) &&
148 ((m->subdevice == 0) || ((m->subdevice ==
149 pci_get_subdevice(dev))))) {
151 device_set_desc(dev, m->desc);
152 return(-10); /* allow room to be overridden */
159 * Allocate resources for our device, set up the bus interface.
162 aac_pci_attach(device_t dev)
164 struct aac_softc *sc;
173 sc = device_get_softc(dev);
174 bzero(sc, sizeof(*sc));
177 /* assume failure is 'not configured' */
181 * Verify that the adapter is correctly set up in PCI space.
183 command = pci_read_config(sc->aac_dev, PCIR_COMMAND, 2);
184 command |= PCIM_CMD_BUSMASTEREN;
185 pci_write_config(dev, PCIR_COMMAND, command, 2);
186 command = pci_read_config(sc->aac_dev, PCIR_COMMAND, 2);
187 if (!(command & PCIM_CMD_BUSMASTEREN)) {
188 device_printf(sc->aac_dev, "can't enable bus-master feature\n");
191 if ((command & PCIM_CMD_MEMEN) == 0) {
192 device_printf(sc->aac_dev, "memory window not available\n");
197 * Allocate the PCI register window.
199 sc->aac_regs_rid = 0x10; /* first base address register */
200 if ((sc->aac_regs_resource = bus_alloc_resource(sc->aac_dev,
204 RF_ACTIVE)) == NULL) {
205 device_printf(sc->aac_dev,
206 "couldn't allocate register window\n");
209 sc->aac_btag = rman_get_bustag(sc->aac_regs_resource);
210 sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource);
213 * Allocate and connect our interrupt.
216 if ((sc->aac_irq = bus_alloc_resource(sc->aac_dev, SYS_RES_IRQ,
217 &sc->aac_irq_rid, 0, ~0, 1,
219 RF_ACTIVE)) == NULL) {
220 device_printf(sc->aac_dev, "can't allocate interrupt\n");
224 #define INTR_ENTROPY 0
226 if (bus_setup_intr(sc->aac_dev, sc->aac_irq, INTR_TYPE_BIO|INTR_ENTROPY,
227 aac_intr, sc, &sc->aac_intr)) {
228 device_printf(sc->aac_dev, "can't set up interrupt\n");
232 /* assume failure is 'out of memory' */
236 * Allocate the parent bus DMA tag appropriate for our PCI interface.
238 * Note that some of these controllers are 64-bit capable.
240 if (bus_dma_tag_create(NULL, /* parent */
241 PAGE_SIZE, 0, /* algnmnt, boundary */
242 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
243 BUS_SPACE_MAXADDR, /* highaddr */
244 NULL, NULL, /* filter, filterarg */
245 MAXBSIZE, /* maxsize */
246 AAC_MAXSGENTRIES, /* nsegments */
247 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
248 BUS_DMA_ALLOCNOW, /* flags */
249 &sc->aac_parent_dmat)) {
250 device_printf(sc->aac_dev, "can't allocate parent DMA tag\n");
255 * Create DMA tag for mapping buffers into controller-addressable space.
257 if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */
258 1, 0, /* algnmnt, boundary */
259 BUS_SPACE_MAXADDR, /* lowaddr */
260 BUS_SPACE_MAXADDR, /* highaddr */
261 NULL, NULL, /* filter, filterarg */
262 MAXBSIZE, AAC_MAXSGENTRIES, /* maxsize, nsegments */
263 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
265 &sc->aac_buffer_dmat)) {
266 device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n");
271 * Create DMA tag for mapping FIBs into controller-addressable space..
273 if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */
274 1, 0, /* algnmnt, boundary */
275 BUS_SPACE_MAXADDR, /* lowaddr */
276 BUS_SPACE_MAXADDR, /* highaddr */
277 NULL, NULL, /* filter, filterarg */
279 sizeof(struct aac_fib), 1, /* maxsize, nsegments */
280 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
282 &sc->aac_fib_dmat)) {
283 device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n");;
288 * Detect the hardware interface version, set up the bus interface
291 sc->aac_hwif = AAC_HWIF_UNKNOWN;
292 for (i = 0; aac_identifiers[i].vendor != 0; i++) {
293 if ((aac_identifiers[i].vendor == pci_get_vendor(dev)) &&
294 (aac_identifiers[i].device == pci_get_device(dev)) &&
295 (aac_identifiers[i].subvendor == pci_get_subvendor(dev)) &&
296 (aac_identifiers[i].subdevice == pci_get_subdevice(dev))) {
297 sc->aac_hwif = aac_identifiers[i].hwif;
298 switch(sc->aac_hwif) {
299 case AAC_HWIF_I960RX:
300 debug(2, "set hardware up for i960Rx");
301 sc->aac_if = aac_rx_interface;
304 case AAC_HWIF_STRONGARM:
305 debug(2, "set hardware up for StrongARM");
306 sc->aac_if = aac_sa_interface;
308 case AAC_HWIF_FALCON:
309 debug(2, "set hardware up for Falcon/PPC");
310 sc->aac_if = aac_fa_interface;
315 sc->quirks = aac_identifiers[i].quirks;
320 if (sc->aac_hwif == AAC_HWIF_UNKNOWN) {
321 device_printf(sc->aac_dev, "unknown hardware type\n");
328 * Do bus-independent initialisation.
330 error = aac_attach(sc);