upgrade to linux 2.6.10-1.12_FC2
[linux-2.6.git] / drivers / scsi / aic7xxx / aic7xxx_osm_pci.c
1 /*
2  * Linux driver attachment glue for PCI based controllers.
3  *
4  * Copyright (c) 2000-2001 Adaptec Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions, and the following disclaimer,
12  *    without modification.
13  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14  *    substantially similar to the "NO WARRANTY" disclaimer below
15  *    ("Disclaimer") and any redistribution must be conditioned upon
16  *    including a substantially similar Disclaimer requirement for further
17  *    binary redistribution.
18  * 3. Neither the names of the above-listed copyright holders nor the names
19  *    of any contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * Alternatively, this software may be distributed under the terms of the
23  * GNU General Public License ("GPL") version 2 as published by the Free
24  * Software Foundation.
25  *
26  * NO WARRANTY
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
30  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
35  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
36  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGES.
38  *
39  * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#47 $
40  */
41
42 #include "aic7xxx_osm.h"
43 #include "aic7xxx_pci.h"
44
45 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
46 struct pci_device_id
47 {
48 };
49 #endif
50
51 static int      ahc_linux_pci_dev_probe(struct pci_dev *pdev,
52                                         const struct pci_device_id *ent);
53 static int      ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc,
54                                                 u_long *base);
55 static int      ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
56                                                  u_long *bus_addr,
57                                                  uint8_t __iomem **maddr);
58 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
59 static void     ahc_linux_pci_dev_remove(struct pci_dev *pdev);
60
61 /* Define the macro locally since it's different for different class of chips.
62 */
63 #define ID(x)   ID_C(x, PCI_CLASS_STORAGE_SCSI)
64
65 static struct pci_device_id ahc_linux_pci_id_table[] = {
66         /* aic7850 based controllers */
67         ID(ID_AHA_2902_04_10_15_20C_30C),
68         /* aic7860 based controllers */
69         ID(ID_AHA_2930CU),
70         ID(ID_AHA_1480A & ID_DEV_VENDOR_MASK),
71         ID(ID_AHA_2940AU_0 & ID_DEV_VENDOR_MASK),
72         ID(ID_AHA_2940AU_CN & ID_DEV_VENDOR_MASK),
73         ID(ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK),
74         /* aic7870 based controllers */
75         ID(ID_AHA_2940),
76         ID(ID_AHA_3940),
77         ID(ID_AHA_398X),
78         ID(ID_AHA_2944),
79         ID(ID_AHA_3944),
80         ID(ID_AHA_4944),
81         /* aic7880 based controllers */
82         ID(ID_AHA_2940U & ID_DEV_VENDOR_MASK),
83         ID(ID_AHA_3940U & ID_DEV_VENDOR_MASK),
84         ID(ID_AHA_2944U & ID_DEV_VENDOR_MASK),
85         ID(ID_AHA_3944U & ID_DEV_VENDOR_MASK),
86         ID(ID_AHA_398XU & ID_DEV_VENDOR_MASK),
87         ID(ID_AHA_4944U & ID_DEV_VENDOR_MASK),
88         ID(ID_AHA_2930U & ID_DEV_VENDOR_MASK),
89         ID(ID_AHA_2940U_PRO & ID_DEV_VENDOR_MASK),
90         ID(ID_AHA_2940U_CN & ID_DEV_VENDOR_MASK),
91         /* aic7890 based controllers */
92         ID(ID_AHA_2930U2),
93         ID(ID_AHA_2940U2B),
94         ID(ID_AHA_2940U2_OEM),
95         ID(ID_AHA_2940U2),
96         ID(ID_AHA_2950U2B),
97         ID16(ID_AIC7890_ARO & ID_AIC7895_ARO_MASK),
98         ID(ID_AAA_131U2),
99         /* aic7890 based controllers */
100         ID(ID_AHA_29160),
101         ID(ID_AHA_29160_CPQ),
102         ID(ID_AHA_29160N),
103         ID(ID_AHA_29160C),
104         ID(ID_AHA_29160B),
105         ID(ID_AHA_19160B),
106         ID(ID_AIC7892_ARO),
107         /* aic7892 based controllers */
108         ID(ID_AHA_2940U_DUAL),
109         ID(ID_AHA_3940AU),
110         ID(ID_AHA_3944AU),
111         ID(ID_AIC7895_ARO),
112         ID(ID_AHA_3950U2B_0),
113         ID(ID_AHA_3950U2B_1),
114         ID(ID_AHA_3950U2D_0),
115         ID(ID_AHA_3950U2D_1),
116         ID(ID_AIC7896_ARO),
117         /* aic7899 based controllers */
118         ID(ID_AHA_3960D),
119         ID(ID_AHA_3960D_CPQ),
120         ID(ID_AIC7899_ARO),
121         /* Generic chip probes for devices we don't know exactly. */
122         ID(ID_AIC7850 & ID_DEV_VENDOR_MASK),
123         ID(ID_AIC7855 & ID_DEV_VENDOR_MASK),
124         ID(ID_AIC7859 & ID_DEV_VENDOR_MASK),
125         ID(ID_AIC7860 & ID_DEV_VENDOR_MASK),
126         ID(ID_AIC7870 & ID_DEV_VENDOR_MASK),
127         ID(ID_AIC7880 & ID_DEV_VENDOR_MASK),
128         ID16(ID_AIC7890 & ID_9005_GENERIC_MASK),
129         ID16(ID_AIC7892 & ID_9005_GENERIC_MASK),
130         ID(ID_AIC7895 & ID_DEV_VENDOR_MASK),
131         ID16(ID_AIC7896 & ID_9005_GENERIC_MASK),
132         ID16(ID_AIC7899 & ID_9005_GENERIC_MASK),
133         ID(ID_AIC7810 & ID_DEV_VENDOR_MASK),
134         ID(ID_AIC7815 & ID_DEV_VENDOR_MASK),
135         { 0 }
136 };
137
138 MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table);
139
140 struct pci_driver aic7xxx_pci_driver = {
141         .name           = "aic7xxx",
142         .probe          = ahc_linux_pci_dev_probe,
143         .remove         = ahc_linux_pci_dev_remove,
144         .id_table       = ahc_linux_pci_id_table
145 };
146
147 static void
148 ahc_linux_pci_dev_remove(struct pci_dev *pdev)
149 {
150         struct ahc_softc *ahc;
151         u_long l;
152
153         /*
154          * We should be able to just perform
155          * the free directly, but check our
156          * list for extra sanity.
157          */
158         ahc_list_lock(&l);
159         ahc = ahc_find_softc((struct ahc_softc *)pci_get_drvdata(pdev));
160         if (ahc != NULL) {
161                 u_long s;
162
163                 TAILQ_REMOVE(&ahc_tailq, ahc, links);
164                 ahc_list_unlock(&l);
165                 ahc_lock(ahc, &s);
166                 ahc_intr_enable(ahc, FALSE);
167                 ahc_unlock(ahc, &s);
168                 ahc_free(ahc);
169         } else
170                 ahc_list_unlock(&l);
171 }
172 #endif /* !LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) */
173
174 static int
175 ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
176 {
177         char             buf[80];
178         const uint64_t   mask_39bit = 0x7FFFFFFFFFULL;
179         struct           ahc_softc *ahc;
180         ahc_dev_softc_t  pci;
181         struct           ahc_pci_identity *entry;
182         char            *name;
183         int              error;
184
185         /*
186          * Some BIOSen report the same device multiple times.
187          */
188         TAILQ_FOREACH(ahc, &ahc_tailq, links) {
189                 struct pci_dev *probed_pdev;
190
191                 probed_pdev = ahc->dev_softc;
192                 if (probed_pdev->bus->number == pdev->bus->number
193                  && probed_pdev->devfn == pdev->devfn)
194                         break;
195         }
196         if (ahc != NULL) {
197                 /* Skip duplicate. */
198                 return (-ENODEV);
199         }
200
201         pci = pdev;
202         entry = ahc_find_pci_device(pci);
203         if (entry == NULL)
204                 return (-ENODEV);
205
206         /*
207          * Allocate a softc for this card and
208          * set it up for attachment by our
209          * common detect routine.
210          */
211         sprintf(buf, "ahc_pci:%d:%d:%d",
212                 ahc_get_pci_bus(pci),
213                 ahc_get_pci_slot(pci),
214                 ahc_get_pci_function(pci));
215         name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
216         if (name == NULL)
217                 return (-ENOMEM);
218         strcpy(name, buf);
219         ahc = ahc_alloc(NULL, name);
220         if (ahc == NULL)
221                 return (-ENOMEM);
222 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
223         if (pci_enable_device(pdev)) {
224                 ahc_free(ahc);
225                 return (-ENODEV);
226         }
227         pci_set_master(pdev);
228
229         if (sizeof(dma_addr_t) > 4
230          && ahc_linux_get_memsize() > 0x80000000
231          && pci_set_dma_mask(pdev, mask_39bit) == 0) {
232                 ahc->flags |= AHC_39BIT_ADDRESSING;
233                 ahc->platform_data->hw_dma_mask = mask_39bit;
234         } else {
235                 if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
236                         printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n");
237                         return (-ENODEV);
238                 }
239                 ahc->platform_data->hw_dma_mask = DMA_32BIT_MASK;
240         }
241 #endif
242         ahc->dev_softc = pci;
243         error = ahc_pci_config(ahc, entry);
244         if (error != 0) {
245                 ahc_free(ahc);
246                 return (-error);
247         }
248 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
249         pci_set_drvdata(pdev, ahc);
250         if (aic7xxx_detect_complete) {
251 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
252                 ahc_linux_register_host(ahc, &aic7xxx_driver_template);
253 #else
254                 printf("aic7xxx: ignoring PCI device found after "
255                        "initialization\n");
256                 return (-ENODEV);
257 #endif
258         }
259 #endif
260         return (0);
261 }
262
263 int
264 ahc_linux_pci_init(void)
265 {
266 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
267         /* Translate error or zero return into zero or one */
268         return pci_module_init(&aic7xxx_pci_driver) ? 0 : 1;
269 #else
270         struct pci_dev *pdev;
271         u_int class;
272         int found;
273
274         /* If we don't have a PCI bus, we can't find any adapters. */
275         if (pci_present() == 0)
276                 return (0);
277
278         found = 0;
279         pdev = NULL;
280         class = PCI_CLASS_STORAGE_SCSI << 8;
281         while ((pdev = pci_find_class(class, pdev)) != NULL) {
282                 ahc_dev_softc_t pci;
283                 int error;
284
285                 pci = pdev;
286                 error = ahc_linux_pci_dev_probe(pdev, /*pci_devid*/NULL);
287                 if (error == 0)
288                         found++;
289         }
290         return (found);
291 #endif
292 }
293
294 void
295 ahc_linux_pci_exit(void)
296 {
297         pci_unregister_driver(&aic7xxx_pci_driver);
298 }
299
300 static int
301 ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, u_long *base)
302 {
303         if (aic7xxx_allow_memio == 0)
304                 return (ENOMEM);
305
306 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
307         *base = pci_resource_start(ahc->dev_softc, 0);
308 #else
309         *base = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS, 4);
310         *base &= PCI_BASE_ADDRESS_IO_MASK;
311 #endif
312         if (*base == 0)
313                 return (ENOMEM);
314 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
315         if (check_region(*base, 256) != 0)
316                 return (ENOMEM);
317         request_region(*base, 256, "aic7xxx");
318 #else
319         if (request_region(*base, 256, "aic7xxx") == 0)
320                 return (ENOMEM);
321 #endif
322         return (0);
323 }
324
325 static int
326 ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
327                                  u_long *bus_addr,
328                                  uint8_t __iomem **maddr)
329 {
330         u_long  start;
331         int     error;
332
333         error = 0;
334         start = pci_resource_start(ahc->dev_softc, 1);
335         if (start != 0) {
336                 *bus_addr = start;
337 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
338                 if (request_mem_region(start, 0x1000, "aic7xxx") == 0)
339                         error = ENOMEM;
340 #endif
341                 if (error == 0) {
342                         *maddr = ioremap_nocache(start, 256);
343                         if (*maddr == NULL) {
344                                 error = ENOMEM;
345 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
346                                 release_mem_region(start, 0x1000);
347 #endif
348                         }
349                 }
350         } else
351                 error = ENOMEM;
352         return (error);
353 }
354
355 int
356 ahc_pci_map_registers(struct ahc_softc *ahc)
357 {
358         uint32_t command;
359         u_long   base;
360         uint8_t __iomem *maddr;
361         int      error;
362
363         /*
364          * If its allowed, we prefer memory mapped access.
365          */
366         command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4);
367         command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN);
368         base = 0;
369         maddr = NULL;
370         error = ahc_linux_pci_reserve_mem_region(ahc, &base, &maddr);
371         if (error == 0) {
372                 ahc->platform_data->mem_busaddr = base;
373                 ahc->tag = BUS_SPACE_MEMIO;
374                 ahc->bsh.maddr = maddr;
375                 ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND,
376                                      command | PCIM_CMD_MEMEN, 4);
377
378                 /*
379                  * Do a quick test to see if memory mapped
380                  * I/O is functioning correctly.
381                  */
382                 if (ahc_pci_test_register_access(ahc) != 0) {
383
384                         printf("aic7xxx: PCI Device %d:%d:%d "
385                                "failed memory mapped test.  Using PIO.\n",
386                                ahc_get_pci_bus(ahc->dev_softc),
387                                ahc_get_pci_slot(ahc->dev_softc),
388                                ahc_get_pci_function(ahc->dev_softc));
389                         iounmap(maddr);
390 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
391                         release_mem_region(ahc->platform_data->mem_busaddr,
392                                            0x1000);
393 #endif
394                         ahc->bsh.maddr = NULL;
395                         maddr = NULL;
396                 } else
397                         command |= PCIM_CMD_MEMEN;
398         } else {
399                 printf("aic7xxx: PCI%d:%d:%d MEM region 0x%lx "
400                        "unavailable. Cannot memory map device.\n",
401                        ahc_get_pci_bus(ahc->dev_softc),
402                        ahc_get_pci_slot(ahc->dev_softc),
403                        ahc_get_pci_function(ahc->dev_softc),
404                        base);
405         }
406
407         /*
408          * We always prefer memory mapped access.
409          */
410         if (maddr == NULL) {
411
412                 error = ahc_linux_pci_reserve_io_region(ahc, &base);
413                 if (error == 0) {
414                         ahc->tag = BUS_SPACE_PIO;
415                         ahc->bsh.ioport = base;
416                         command |= PCIM_CMD_PORTEN;
417                 } else {
418                         printf("aic7xxx: PCI%d:%d:%d IO region 0x%lx[0..255] "
419                                "unavailable. Cannot map device.\n",
420                                ahc_get_pci_bus(ahc->dev_softc),
421                                ahc_get_pci_slot(ahc->dev_softc),
422                                ahc_get_pci_function(ahc->dev_softc),
423                                base);
424                 }
425         }
426         ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4);
427         return (error);
428 }
429
430 int
431 ahc_pci_map_int(struct ahc_softc *ahc)
432 {
433         int error;
434
435         error = request_irq(ahc->dev_softc->irq, ahc_linux_isr,
436                             SA_SHIRQ, "aic7xxx", ahc);
437         if (error == 0)
438                 ahc->platform_data->irq = ahc->dev_softc->irq;
439         
440         return (-error);
441 }
442
443 void
444 ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state)
445 {
446 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
447         pci_set_power_state(ahc->dev_softc, new_state);
448 #else
449         uint32_t cap;
450         u_int cap_offset;
451
452         /*
453          * Traverse the capability list looking for
454          * the power management capability.
455          */
456         cap = 0;
457         cap_offset = ahc_pci_read_config(ahc->dev_softc,
458                                          PCIR_CAP_PTR, /*bytes*/1);
459         while (cap_offset != 0) {
460
461                 cap = ahc_pci_read_config(ahc->dev_softc,
462                                           cap_offset, /*bytes*/4);
463                 if ((cap & 0xFF) == 1
464                  && ((cap >> 16) & 0x3) > 0) {
465                         uint32_t pm_control;
466
467                         pm_control = ahc_pci_read_config(ahc->dev_softc,
468                                                          cap_offset + 4,
469                                                          /*bytes*/4);
470                         pm_control &= ~0x3;
471                         pm_control |= new_state;
472                         ahc_pci_write_config(ahc->dev_softc,
473                                              cap_offset + 4,
474                                              pm_control, /*bytes*/2);
475                         break;
476                 }
477                 cap_offset = (cap >> 8) & 0xFF;
478         }
479 #endif 
480 }