Merge branch 'vendor/MPFR' into gcc441
[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.19 2003/11/01 18:44:51 scottl Exp $
30  *      $DragonFly: src/sys/dev/raid/aac/aac_pci.c,v 1.13 2008/01/20 03:40:35 pavalos 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 #include <sys/module.h>
43
44 #include <sys/bus.h>
45 #include <sys/conf.h>
46 #include <sys/devicestat.h>
47 #include <sys/disk.h>
48 #include <sys/rman.h>
49
50 #include <bus/pci/pcireg.h>
51 #include <bus/pci/pcivar.h>
52
53 #include "aacreg.h"
54 #include "aac_ioctl.h"
55 #include "aacvar.h"
56
57 static int      aac_pci_probe(device_t dev);
58 static int      aac_pci_attach(device_t dev);
59
60 static device_method_t aac_methods[] = {
61         /* Device interface */
62         DEVMETHOD(device_probe,         aac_pci_probe),
63         DEVMETHOD(device_attach,        aac_pci_attach),
64         DEVMETHOD(device_detach,        aac_detach),
65         DEVMETHOD(device_suspend,       aac_suspend),
66         DEVMETHOD(device_resume,        aac_resume),
67
68         DEVMETHOD(bus_print_child,      bus_generic_print_child),
69         DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
70         { 0, 0 }
71 };
72
73 static driver_t aac_pci_driver = {
74         "aac",
75         aac_methods,
76         sizeof(struct aac_softc)
77 };
78
79 devclass_t      aac_devclass;
80
81 DRIVER_MODULE(aac, pci, aac_pci_driver, aac_devclass, 0, 0);
82
83 static struct aac_ident
84 {
85         u_int16_t               vendor;
86         u_int16_t               device;
87         u_int16_t               subvendor;
88         u_int16_t               subdevice;
89         int                     hwif;
90         int                     quirks;
91         char                    *desc;
92 } aac_identifiers[] = {
93         {0x1028, 0x0001, 0x1028, 0x0001, AAC_HWIF_I960RX, 0,
94         "Dell PERC 2/Si"},
95         {0x1028, 0x0002, 0x1028, 0x0002, AAC_HWIF_I960RX, 0,
96         "Dell PERC 3/Di"},
97         {0x1028, 0x0003, 0x1028, 0x0003, AAC_HWIF_I960RX, 0,
98         "Dell PERC 3/Si"},
99         {0x1028, 0x0004, 0x1028, 0x00d0, AAC_HWIF_I960RX, 0,
100         "Dell PERC 3/Si"},
101         {0x1028, 0x0002, 0x1028, 0x00d1, AAC_HWIF_I960RX, 0,
102         "Dell PERC 3/Di"},
103         {0x1028, 0x0002, 0x1028, 0x00d9, AAC_HWIF_I960RX, 0,
104         "Dell PERC 3/Di"},
105         {0x1028, 0x000a, 0x1028, 0x0106, AAC_HWIF_I960RX, 0,
106         "Dell PERC 3/Di"},
107         {0x1028, 0x000a, 0x1028, 0x011b, AAC_HWIF_I960RX, 0,
108         "Dell PERC 3/Di"},
109         {0x1028, 0x000a, 0x1028, 0x0121, AAC_HWIF_I960RX, 0,
110         "Dell PERC 3/Di"},
111         {0x1011, 0x0046, 0x9005, 0x0364, AAC_HWIF_STRONGARM, 0,
112         "Adaptec AAC-364"},
113         {0x1011, 0x0046, 0x9005, 0x0365, AAC_HWIF_STRONGARM,
114          AAC_FLAGS_BROKEN_MEMMAP, "Adaptec SCSI RAID 5400S"},
115         {0x1011, 0x0046, 0x9005, 0x1364, AAC_HWIF_STRONGARM, AAC_FLAGS_PERC2QC,
116         "Dell PERC 2/QC"},
117         {0x1011, 0x0046, 0x103c, 0x10c2, AAC_HWIF_STRONGARM, 0,
118         "HP NetRaid-4M"},
119         {0x9005, 0x0285, 0x9005, 0x0285, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
120         "Adaptec SCSI RAID 2200S"},
121         {0x9005, 0x0285, 0x1028, 0x0287, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
122         "Dell PERC 320/DC"},
123         {0x9005, 0x0285, 0x9005, 0x0286, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
124         "Adaptec SCSI RAID 2120S"},
125         {0x9005, 0x0285, 0x9005, 0x0290, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
126          "Adaptec SATA RAID 2410SA"},
127         {0x9005, 0x0285, 0x1028, 0x0291, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
128          "Dell CERC SATA RAID 2"},
129         {0x9005, 0x0285, 0x9005, 0x0292, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
130          "Adaptec SATA RAID 2810SA"},
131         {0x9005, 0x0285, 0x9005, 0x0293, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
132          "Adaptec SATA RAID 21610SA"},
133         {0x9005, 0x0285, 0x103c, 0x3227, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB,
134          "HP ML110 G2 (Adaptec 2610SA)"},
135         {0x9005, 0x0286, 0x9005, 0x028c, AAC_HWIF_RKT, 0,
136          "Adaptec SCSI RAID 2230S"},
137         {0x9005, 0x0286, 0x9005, 0x028d, AAC_HWIF_RKT, 0,
138          "Adaptec SCSI RAID 2130S"},
139
140         {0x9005, 0x0285, 0x9005, 0x0287, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB |
141          AAC_FLAGS_256FIBS, "Adaptec SCSI RAID 2200S"},
142         {0x9005, 0x0285, 0x17aa, 0x0286, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB |
143          AAC_FLAGS_256FIBS, "Legend S220"},
144         {0x9005, 0x0285, 0x17aa, 0x0287, AAC_HWIF_I960RX, AAC_FLAGS_NO4GB |
145          AAC_FLAGS_256FIBS, "Legend S230"},
146         {0x9005, 0x0285, 0x9005, 0x0288, AAC_HWIF_I960RX, 0,
147          "Adaptec SCSI RAID 3230S"},
148         {0x9005, 0x0285, 0x9005, 0x0289, AAC_HWIF_I960RX, 0,
149          "Adaptec SCSI RAID 3240S"},
150         {0x9005, 0x0285, 0x9005, 0x028a, AAC_HWIF_I960RX, 0,
151          "Adaptec SCSI RAID 2020ZCR"},
152         {0x9005, 0x0285, 0x9005, 0x028b, AAC_HWIF_I960RX, 0,
153          "Adaptec SCSI RAID 2025ZCR"},
154         {0x9005, 0x0286, 0x9005, 0x029b, AAC_HWIF_RKT, 0,
155          "Adaptec SATA RAID 2820SA"},
156         {0x9005, 0x0286, 0x9005, 0x029c, AAC_HWIF_RKT, 0,
157          "Adaptec SATA RAID 2620SA"},
158         {0x9005, 0x0286, 0x9005, 0x029d, AAC_HWIF_RKT, 0,
159          "Adaptec SATA RAID 2420SA"},
160         {0x9005, 0x0286, 0x9005, 0x029e, AAC_HWIF_RKT, 0,
161          "ICP ICP9024RO SCSI RAID"},
162         {0x9005, 0x0286, 0x9005, 0x029f, AAC_HWIF_RKT, 0,
163          "ICP ICP9014RO SCSI RAID"},
164         {0x9005, 0x0285, 0x9005, 0x0294, AAC_HWIF_I960RX, 0,
165          "Adaptec SATA RAID 2026ZCR"},
166         {0x9005, 0x0285, 0x103c, 0x3227, AAC_HWIF_I960RX, 0,
167          "Adaptec SATA RAID 2610SA"},
168         {0x9005, 0x0285, 0x9005, 0x0296, AAC_HWIF_I960RX, 0,
169          "Adaptec SCSI RAID 2240S"},
170         {0x9005, 0x0285, 0x9005, 0x0297, AAC_HWIF_I960RX, 0,
171          "Adaptec SAS RAID 4005SAS"},
172         {0x9005, 0x0285, 0x1014, 0x02f2, AAC_HWIF_I960RX, 0,
173          "IBM ServeRAID 8i"},
174         {0x9005, 0x0285, 0x9005, 0x0298, AAC_HWIF_I960RX, 0,
175          "Adaptec SAS RAID 4000SAS"},
176         {0x9005, 0x0285, 0x9005, 0x0299, AAC_HWIF_I960RX, 0,
177          "Adaptec SAS RAID 4800SAS"},
178         {0x9005, 0x0285, 0x9005, 0x029a, AAC_HWIF_I960RX, 0,
179          "Adaptec SAS RAID 4805SAS"},
180         {0x9005, 0x0285, 0x9005, 0x028e, AAC_HWIF_I960RX, 0,
181          "Adaptec SATA RAID 2020SA ZCR"},
182         {0x9005, 0x0285, 0x9005, 0x028f, AAC_HWIF_I960RX, 0,
183          "Adaptec SATA RAID 2025SA ZCR"},
184         {0x9005, 0x0285, 0x9005, 0x02a4, AAC_HWIF_I960RX, 0,
185          "ICP ICP9085LI SAS RAID"},
186         {0x9005, 0x0285, 0x9005, 0x02a5, AAC_HWIF_I960RX, 0,
187          "ICP ICP5085BR SAS RAID"},
188         {0x9005, 0x0286, 0x9005, 0x02a0, AAC_HWIF_RKT, 0,
189          "ICP ICP9047MA SATA RAID"},
190         {0x9005, 0x0286, 0x9005, 0x02a1, AAC_HWIF_RKT, 0,
191          "ICP ICP9087MA SATA RAID"},
192         {0x9005, 0x0285, 0x9005, 0x02bb, AAC_HWIF_I960RX, 0,
193          "Adaptec RAID 3405"},
194         {0x9005, 0x0285, 0x9005, 0x02bc, AAC_HWIF_I960RX, 0,
195          "Adaptec RAID 3805"},
196         {0x9005, 0x0286, 0x1014, 0x9580, AAC_HWIF_RKT, 0,
197          "IBM ServeRAID-8k"},
198         {0, 0, 0, 0, 0, 0, 0}
199 };
200
201 static struct aac_ident *
202 aac_find_ident(device_t dev)
203 {
204         struct aac_ident *m;
205
206         for (m = aac_identifiers; m->vendor != 0; m++) {
207                 if ((m->vendor == pci_get_vendor(dev)) &&
208                     (m->device == pci_get_device(dev)) &&
209                     (m->subvendor == pci_get_subvendor(dev)) &&
210                     (m->subdevice == pci_get_subdevice(dev)))
211                 return (m);
212         }
213
214         return (NULL);
215 }
216
217 /*
218  * Determine whether this is one of our supported adapters.
219  */
220 static int
221 aac_pci_probe(device_t dev)
222 {
223         struct aac_ident *id;
224
225         debug_called(1);
226
227         if ((id = aac_find_ident(dev)) != NULL) {
228                 device_set_desc(dev, id->desc);
229                 return(BUS_PROBE_DEFAULT);
230         }
231         return(ENXIO);
232 }
233
234 /*
235  * Allocate resources for our device, set up the bus interface.
236  */
237 static int
238 aac_pci_attach(device_t dev)
239 {
240         struct aac_softc *sc;
241         struct aac_ident *id;
242         int error;
243         u_int32_t command;
244
245         debug_called(1);
246
247         /*
248          * Initialise softc.
249          */
250         sc = device_get_softc(dev);
251         bzero(sc, sizeof(*sc));
252         sc->aac_dev = dev;
253
254         /* assume failure is 'not configured' */
255         error = ENXIO;
256
257         /* 
258          * Verify that the adapter is correctly set up in PCI space.
259          */
260         command = pci_read_config(sc->aac_dev, PCIR_COMMAND, 2);
261         command |= PCIM_CMD_BUSMASTEREN;
262         pci_write_config(dev, PCIR_COMMAND, command, 2);
263         command = pci_read_config(sc->aac_dev, PCIR_COMMAND, 2);
264         if (!(command & PCIM_CMD_BUSMASTEREN)) {
265                 device_printf(sc->aac_dev, "can't enable bus-master feature\n");
266                 goto out;
267         }
268         if ((command & PCIM_CMD_MEMEN) == 0) {
269                 device_printf(sc->aac_dev, "memory window not available\n");
270                 goto out;
271         }
272
273         /*
274          * Allocate the PCI register window.
275          */
276         sc->aac_regs_rid = PCIR_BAR(0);
277         if ((sc->aac_regs_resource = bus_alloc_resource_any(sc->aac_dev,
278                                                             SYS_RES_MEMORY,
279                                                             &sc->aac_regs_rid,
280                                                             RF_ACTIVE)) ==
281                                                             NULL) {
282                 device_printf(sc->aac_dev,
283                               "couldn't allocate register window\n");
284                 goto out;
285         }
286         sc->aac_btag = rman_get_bustag(sc->aac_regs_resource);
287         sc->aac_bhandle = rman_get_bushandle(sc->aac_regs_resource);
288
289         /* assume failure is 'out of memory' */
290         error = ENOMEM;
291
292         /*
293          * Allocate the parent bus DMA tag appropriate for our PCI interface.
294          * 
295          * Note that some of these controllers are 64-bit capable.
296          */
297         if (bus_dma_tag_create(NULL,                    /* parent */
298                                PAGE_SIZE, 0,            /* algnmnt, boundary */
299                                BUS_SPACE_MAXADDR,       /* lowaddr */
300                                BUS_SPACE_MAXADDR,       /* highaddr */
301                                NULL, NULL,              /* filter, filterarg */
302                                BUS_SPACE_MAXSIZE_32BIT, /* maxsize */
303                                BUS_SPACE_UNRESTRICTED,  /* nsegments */
304                                BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
305                                0,                       /* flags */
306                                &sc->aac_parent_dmat)) {
307                 device_printf(sc->aac_dev, "can't allocate parent DMA tag\n");
308                 goto out;
309         }
310
311         /* 
312          * Detect the hardware interface version, set up the bus interface
313          * indirection.
314          */
315         id = aac_find_ident(dev);
316         sc->aac_hwif = id->hwif;
317         switch(sc->aac_hwif) {
318         case AAC_HWIF_I960RX:
319                 debug(2, "set hardware up for i960Rx");
320                 sc->aac_if = aac_rx_interface;
321                 break;
322         case AAC_HWIF_STRONGARM:
323                 debug(2, "set hardware up for StrongARM");
324                 sc->aac_if = aac_sa_interface;
325                 break;
326         case AAC_HWIF_FALCON:
327                 debug(2, "set hardware up for Falcon/PPC");
328                 sc->aac_if = aac_fa_interface;
329                 break;
330         case AAC_HWIF_RKT:
331                 debug(2, "set hardware up for Rocket/MIPS");
332                 sc->aac_if = aac_rkt_interface;
333                 break;
334         default:
335                 sc->aac_hwif = AAC_HWIF_UNKNOWN;
336                 device_printf(sc->aac_dev, "unknown hardware type\n");
337                 error = ENXIO;
338                 goto out;
339         }
340
341         /* Set up quirks */
342         sc->flags = id->quirks;
343
344         /*
345          * Do bus-independent initialisation.
346          */
347         error = aac_attach(sc);
348
349 out:
350         if (error)
351                 aac_free(sc);
352         return(error);
353 }
354
355 /*
356  * Do nothing driver that will attach to the SCSI channels of a Dell PERC
357  * controller.  This is needed to keep the power management subsystem from
358  * trying to power down these devices.
359  */
360 static int aacch_probe(device_t dev);
361 static int aacch_attach(device_t dev);
362 static int aacch_detach(device_t dev);
363
364 static device_method_t aacch_methods[] = {
365         /* Device interface */
366         DEVMETHOD(device_probe,         aacch_probe),
367         DEVMETHOD(device_attach,        aacch_attach),
368         DEVMETHOD(device_detach,        aacch_detach),
369         { 0, 0 }
370 };
371
372 struct aacch_softc {
373         device_t        dev;
374 };
375
376 static driver_t aacch_driver = {
377         "aacch",
378         aacch_methods,
379         sizeof(struct aacch_softc)
380 };
381
382 static devclass_t       aacch_devclass;
383 DRIVER_MODULE(aacch, pci, aacch_driver, aacch_devclass, 0, 0);
384
385 static int
386 aacch_probe(device_t dev)
387 {
388
389         if ((pci_get_vendor(dev) != 0x9005) ||
390             (pci_get_device(dev) != 0x00c5))
391                 return (ENXIO);
392
393         device_set_desc(dev, "AAC RAID Channel");
394         return (-10);
395 }
396
397 static int
398 aacch_attach(device_t dev)
399 {
400         struct aacch_softc *sc;
401
402         sc = device_get_softc(dev);
403
404         sc->dev = dev;
405
406         return (0);
407 }
408
409 static int
410 aacch_detach(device_t dev)
411 {
412
413         return (0);
414 }