kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / dev / raid / aac / aac_pci.c
1 /*-
2  * Copyright (c) 2000 Michael Smith
3  * Copyright (c) 2001 Scott Long
4  * Copyright (c) 2000 BSDi
5  * Copyright (c) 2001 Adaptec, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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.
16  *
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
27  * SUCH DAMAGE.
28  *
29  *      $FreeBSD: src/sys/dev/aac/aac_pci.c,v 1.3.2.18 2003/04/08 13:22:08 scottl Exp $
30  *      $DragonFly: src/sys/dev/raid/aac/aac_pci.c,v 1.3 2003/08/07 21:17:07 dillon Exp $
31  */
32
33 /*
34  * PCI bus interface and resource allocation.
35  */
36
37 #include "opt_aac.h"
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42
43 #include "aac_compat.h"
44 #include <sys/bus.h>
45 #include <sys/conf.h>
46 #include <sys/devicestat.h>
47 #include <sys/disk.h>
48
49 #include <machine/bus_memio.h>
50 #include <machine/bus.h>
51 #include <machine/resource.h>
52 #include <sys/rman.h>
53
54 #include <bus/pci/pcireg.h>
55 #include <bus/pci/pcivar.h>
56
57 #include "aacreg.h"
58 #include "aac_ioctl.h"
59 #include "aacvar.h"
60
61 static int      aac_pci_probe(device_t dev);
62 static int      aac_pci_attach(device_t dev);
63
64 static device_method_t aac_methods[] = {
65         /* Device interface */
66         DEVMETHOD(device_probe,         aac_pci_probe),
67         DEVMETHOD(device_attach,        aac_pci_attach),
68         DEVMETHOD(device_detach,        aac_detach),
69         DEVMETHOD(device_suspend,       aac_suspend),
70         DEVMETHOD(device_resume,        aac_resume),
71
72         DEVMETHOD(bus_print_child,      bus_generic_print_child),
73         DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
74         { 0, 0 }
75 };
76
77 static driver_t aac_pci_driver = {
78         "aac",
79         aac_methods,
80         sizeof(struct aac_softc)
81 };
82
83 devclass_t      aac_devclass;
84
85 DRIVER_MODULE(aac, pci, aac_pci_driver, aac_devclass, 0, 0);
86
87 struct aac_ident
88 {
89         u_int16_t               vendor;
90         u_int16_t               device;
91         u_int16_t               subvendor;
92         u_int16_t               subdevice;
93         int                     hwif;
94         int                     quirks;
95         char                    *desc;
96 } aac_identifiers[] = {
97         {0x1028, 0x0001, 0x1028, 0x0001, AAC_HWIF_I960RX, 0,
98         "Dell PERC 2/Si"},
99         {0x1028, 0x0002, 0x1028, 0x0002, AAC_HWIF_I960RX, 0,
100         "Dell PERC 3/Di"},
101         {0x1028, 0x0003, 0x1028, 0x0003, AAC_HWIF_I960RX, 0,
102         "Dell PERC 3/Si"},
103         {0x1028, 0x0004, 0x1028, 0x00d0, AAC_HWIF_I960RX, 0,
104         "Dell PERC 3/Si"},
105         {0x1028, 0x0002, 0x1028, 0x00d1, AAC_HWIF_I960RX, 0,
106         "Dell PERC 3/Di"},
107         {0x1028, 0x0002, 0x1028, 0x00d9, AAC_HWIF_I960RX, 0,
108         "Dell PERC 3/Di"},
109         {0x1028, 0x0008, 0x1028, 0x00cf, AAC_HWIF_I960RX, 0,
110         "Dell PERC 3/Di"},
111         {0x1028, 0x000a, 0x1028, 0x0106, AAC_HWIF_I960RX, 0,
112         "Dell PERC 3/Di"},
113         {0x1028, 0x000a, 0x1028, 0x011b, AAC_HWIF_I960RX, 0,
114         "Dell PERC 3/Di"},
115         {0x1028, 0x000a, 0x1028, 0x0121, AAC_HWIF_I960RX, 0,
116         "Dell PERC 3/Di"},
117         {0x1011, 0x0046, 0x9005, 0x0364, AAC_HWIF_STRONGARM, 0,
118         "Adaptec AAC-364"},
119         {0x1011, 0x0046, 0x9005, 0x0365, AAC_HWIF_STRONGARM, 0,
120         "Adaptec SCSI RAID 5400S"},
121         {0x1011, 0x0046, 0x9005, 0x1364, AAC_HWIF_STRONGARM, AAC_FLAGS_PERC2QC,
122         "Dell PERC 2/QC"},
123         {0x1011, 0x0046, 0x103c, 0x10c2, AAC_HWIF_STRONGARM, 0,
124         "HP NetRaid-4M"},
125         {0x9005, 0x0285, 0x9005, 0x0285, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
126         "Adaptec SCSI RAID 2200S"},
127         {0x9005, 0x0285, 0x1028, 0x0287, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
128         "Dell PERC 320/DC"},
129         {0x9005, 0x0285, 0x9005, 0x0286, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
130         "Adaptec SCSI RAID 2120S"},
131         {0, 0, 0, 0, 0, 0, 0}
132 };
133
134 /*
135  * Determine whether this is one of our supported adapters.
136  */
137 static int
138 aac_pci_probe(device_t dev)
139 {
140         struct aac_ident *m;
141
142         debug_called(1);
143
144         for (m = aac_identifiers; m->vendor != 0; m++) {
145                 if ((m->vendor == pci_get_vendor(dev)) &&
146                     (m->device == pci_get_device(dev)) &&
147                     ((m->subvendor == 0) || (m->subvendor ==
148                                              pci_get_subvendor(dev))) &&
149                     ((m->subdevice == 0) || ((m->subdevice ==
150                                               pci_get_subdevice(dev))))) {
151                 
152                         device_set_desc(dev, m->desc);
153                         return(-10);    /* allow room to be overridden */
154                 }
155         }
156         return(ENXIO);
157 }
158
159 /*
160  * Allocate resources for our device, set up the bus interface.
161  */
162 static int
163 aac_pci_attach(device_t dev)
164 {
165         struct aac_softc *sc;
166         int i, error;
167         u_int32_t command;
168
169         debug_called(1);
170
171         /*
172          * Initialise softc.
173          */
174         sc = device_get_softc(dev);
175         bzero(sc, sizeof(*sc));
176         sc->aac_dev = dev;
177
178         /* assume failure is 'not configured' */
179         error = ENXIO;
180
181         /* 
182          * Verify that the adapter is correctly set up in PCI space.
183          */
184         command = pci_read_config(sc->aac_dev, PCIR_COMMAND, 2);
185         command |= PCIM_CMD_BUSMASTEREN;
186         pci_write_config(dev, PCIR_COMMAND, command, 2);
187         command = pci_read_config(sc->aac_dev, PCIR_COMMAND, 2);
188         if (!(command & PCIM_CMD_BUSMASTEREN)) {
189                 device_printf(sc->aac_dev, "can't enable bus-master feature\n");
190                 goto out;
191         }
192         if ((command & PCIM_CMD_MEMEN) == 0) {
193                 device_printf(sc->aac_dev, "memory window not available\n");
194                 goto out;
195         }
196
197         /*
198          * Allocate the PCI register window.
199          */
200         sc->aac_regs_rid = 0x10;        /* first base address register */
201         if ((sc->aac_regs_resource = bus_alloc_resource(sc->aac_dev,
202                                                         SYS_RES_MEMORY,
203                                                         &sc->aac_regs_rid,
204                                                         0, ~0, 1,
205                                                         RF_ACTIVE)) == NULL) {
206                 device_printf(sc->aac_dev,
207                               "couldn't allocate register window\n");
208                 goto out;
209         }
210         sc->aac_btag = rman_get_bustag(sc->aac_regs_resource);
211         sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource);
212
213         /* 
214          * Allocate and connect our interrupt.
215          */
216         sc->aac_irq_rid = 0;
217         if ((sc->aac_irq = bus_alloc_resource(sc->aac_dev, SYS_RES_IRQ,
218                                               &sc->aac_irq_rid, 0, ~0, 1,
219                                               RF_SHAREABLE |
220                                               RF_ACTIVE)) == NULL) {
221                 device_printf(sc->aac_dev, "can't allocate interrupt\n");
222                 goto out;
223         }
224 #ifndef INTR_ENTROPY
225 #define INTR_ENTROPY 0
226 #endif
227         if (bus_setup_intr(sc->aac_dev, sc->aac_irq, INTR_TYPE_BIO|INTR_ENTROPY,
228                            aac_intr, sc, &sc->aac_intr)) {
229                 device_printf(sc->aac_dev, "can't set up interrupt\n");
230                 goto out;
231         }
232
233         /* assume failure is 'out of memory' */
234         error = ENOMEM;
235
236         /*
237          * Allocate the parent bus DMA tag appropriate for our PCI interface.
238          * 
239          * Note that some of these controllers are 64-bit capable.
240          */
241         if (bus_dma_tag_create(NULL,                    /* parent */
242                                PAGE_SIZE, 0,            /* algnmnt, boundary */
243                                BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
244                                BUS_SPACE_MAXADDR,       /* highaddr */
245                                NULL, NULL,              /* filter, filterarg */
246                                BUS_SPACE_MAXSIZE_32BIT, /* maxsize */
247                                AAC_MAXSGENTRIES,        /* nsegments */
248                                BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
249                                0,                       /* flags */
250                                &sc->aac_parent_dmat)) {
251                 device_printf(sc->aac_dev, "can't allocate parent DMA tag\n");
252                 goto out;
253         }
254
255         /* 
256          * Detect the hardware interface version, set up the bus interface
257          * indirection.
258          */
259         sc->aac_hwif = AAC_HWIF_UNKNOWN;
260         for (i = 0; aac_identifiers[i].vendor != 0; i++) {
261                 if ((aac_identifiers[i].vendor == pci_get_vendor(dev)) &&
262                     (aac_identifiers[i].device == pci_get_device(dev)) &&
263                     (aac_identifiers[i].subvendor == pci_get_subvendor(dev)) &&
264                     (aac_identifiers[i].subdevice == pci_get_subdevice(dev))) {
265                         sc->aac_hwif = aac_identifiers[i].hwif;
266                         switch(sc->aac_hwif) {
267                         case AAC_HWIF_I960RX:
268                                 debug(2, "set hardware up for i960Rx");
269                                 sc->aac_if = aac_rx_interface;
270                                 break;
271
272                         case AAC_HWIF_STRONGARM:
273                                 debug(2, "set hardware up for StrongARM");
274                                 sc->aac_if = aac_sa_interface;
275                                 break;
276                         case AAC_HWIF_FALCON:
277                                 debug(2, "set hardware up for Falcon/PPC");
278                                 sc->aac_if = aac_fa_interface;
279                                 break;
280                         }
281
282                         /* Set up quirks */
283                         sc->flags = aac_identifiers[i].quirks;
284
285                         break;
286                 }
287         }
288         if (sc->aac_hwif == AAC_HWIF_UNKNOWN) {
289                 device_printf(sc->aac_dev, "unknown hardware type\n");
290                 error = ENXIO;
291                 goto out;
292         }
293
294
295         /*
296          * Do bus-independent initialisation.
297          */
298         error = aac_attach(sc);
299         
300 out:
301         if (error)
302                 aac_free(sc);
303         return(error);
304 }