Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / drivers / scsi / aic7xxx / aic79xx_osm_pci.c
1 /*
2  * Linux driver attachment glue for PCI based U320 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/aic79xx_osm_pci.c#25 $
40  */
41
42 #include "aic79xx_osm.h"
43 #include "aic79xx_inline.h"
44 #include "aic79xx_pci.h"
45
46 static int      ahd_linux_pci_dev_probe(struct pci_dev *pdev,
47                                         const struct pci_device_id *ent);
48 static int      ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd,
49                                                  u_long *base, u_long *base2);
50 static int      ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
51                                                  u_long *bus_addr,
52                                                  uint8_t __iomem **maddr);
53 static void     ahd_linux_pci_dev_remove(struct pci_dev *pdev);
54
55 /* Define the macro locally since it's different for different class of chips.
56  */
57 #define ID(x)            \
58         ID2C(x),         \
59         ID2C(IDIROC(x))
60
61 static struct pci_device_id ahd_linux_pci_id_table[] = {
62         /* aic7901 based controllers */
63         ID(ID_AHA_29320A),
64         ID(ID_AHA_29320ALP),
65         /* aic7902 based controllers */
66         ID(ID_AHA_29320),
67         ID(ID_AHA_29320B),
68         ID(ID_AHA_29320LP),
69         ID(ID_AHA_39320),
70         ID(ID_AHA_39320_B),
71         ID(ID_AHA_39320A),
72         ID(ID_AHA_39320D),
73         ID(ID_AHA_39320D_HP),
74         ID(ID_AHA_39320D_B),
75         ID(ID_AHA_39320D_B_HP),
76         /* Generic chip probes for devices we don't know exactly. */
77         ID16(ID_AIC7901 & ID_9005_GENERIC_MASK),
78         ID(ID_AIC7901A & ID_DEV_VENDOR_MASK),
79         ID16(ID_AIC7902 & ID_9005_GENERIC_MASK),
80         { 0 }
81 };
82
83 MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table);
84
85 struct pci_driver aic79xx_pci_driver = {
86         .name           = "aic79xx",
87         .probe          = ahd_linux_pci_dev_probe,
88         .remove         = ahd_linux_pci_dev_remove,
89         .id_table       = ahd_linux_pci_id_table
90 };
91
92 static void
93 ahd_linux_pci_dev_remove(struct pci_dev *pdev)
94 {
95         struct ahd_softc *ahd;
96         u_long l;
97
98         /*
99          * We should be able to just perform
100          * the free directly, but check our
101          * list for extra sanity.
102          */
103         ahd_list_lock(&l);
104         ahd = ahd_find_softc((struct ahd_softc *)pci_get_drvdata(pdev));
105         if (ahd != NULL) {
106                 u_long s;
107
108                 TAILQ_REMOVE(&ahd_tailq, ahd, links);
109                 ahd_list_unlock(&l);
110                 ahd_lock(ahd, &s);
111                 ahd_intr_enable(ahd, FALSE);
112                 ahd_unlock(ahd, &s);
113                 ahd_free(ahd);
114         } else
115                 ahd_list_unlock(&l);
116 }
117
118 static int
119 ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
120 {
121         char             buf[80];
122         struct           ahd_softc *ahd;
123         ahd_dev_softc_t  pci;
124         struct           ahd_pci_identity *entry;
125         char            *name;
126         int              error;
127
128         /*
129          * Some BIOSen report the same device multiple times.
130          */
131         TAILQ_FOREACH(ahd, &ahd_tailq, links) {
132                 struct pci_dev *probed_pdev;
133
134                 probed_pdev = ahd->dev_softc;
135                 if (probed_pdev->bus->number == pdev->bus->number
136                  && probed_pdev->devfn == pdev->devfn)
137                         break;
138         }
139         if (ahd != NULL) {
140                 /* Skip duplicate. */
141                 return (-ENODEV);
142         }
143
144         pci = pdev;
145         entry = ahd_find_pci_device(pci);
146         if (entry == NULL)
147                 return (-ENODEV);
148
149         /*
150          * Allocate a softc for this card and
151          * set it up for attachment by our
152          * common detect routine.
153          */
154         sprintf(buf, "ahd_pci:%d:%d:%d",
155                 ahd_get_pci_bus(pci),
156                 ahd_get_pci_slot(pci),
157                 ahd_get_pci_function(pci));
158         name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
159         if (name == NULL)
160                 return (-ENOMEM);
161         strcpy(name, buf);
162         ahd = ahd_alloc(NULL, name);
163         if (ahd == NULL)
164                 return (-ENOMEM);
165         if (pci_enable_device(pdev)) {
166                 ahd_free(ahd);
167                 return (-ENODEV);
168         }
169         pci_set_master(pdev);
170
171         if (sizeof(dma_addr_t) > 4) {
172                 uint64_t   memsize;
173                 const uint64_t mask_39bit = 0x7FFFFFFFFFULL;
174
175                 memsize = ahd_linux_get_memsize();
176
177                 if (memsize >= 0x8000000000ULL
178                  && pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
179                         ahd->flags |= AHD_64BIT_ADDRESSING;
180                         ahd->platform_data->hw_dma_mask = DMA_64BIT_MASK;
181                 } else if (memsize > 0x80000000
182                         && pci_set_dma_mask(pdev, mask_39bit) == 0) {
183                         ahd->flags |= AHD_39BIT_ADDRESSING;
184                         ahd->platform_data->hw_dma_mask = mask_39bit;
185                 }
186         } else {
187                 pci_set_dma_mask(pdev, DMA_32BIT_MASK);
188                 ahd->platform_data->hw_dma_mask = DMA_32BIT_MASK;
189         }
190         ahd->dev_softc = pci;
191         error = ahd_pci_config(ahd, entry);
192         if (error != 0) {
193                 ahd_free(ahd);
194                 return (-error);
195         }
196         pci_set_drvdata(pdev, ahd);
197         if (aic79xx_detect_complete) {
198 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
199                 ahd_linux_register_host(ahd, &aic79xx_driver_template);
200 #else
201                 printf("aic79xx: ignoring PCI device found after "
202                        "initialization\n");
203                 return (-ENODEV);
204 #endif
205         }
206         return (0);
207 }
208
209 int
210 ahd_linux_pci_init(void)
211 {
212         return (pci_module_init(&aic79xx_pci_driver));
213 }
214
215 void
216 ahd_linux_pci_exit(void)
217 {
218         pci_unregister_driver(&aic79xx_pci_driver);
219 }
220
221 static int
222 ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, u_long *base,
223                                  u_long *base2)
224 {
225         *base = pci_resource_start(ahd->dev_softc, 0);
226         /*
227          * This is really the 3rd bar and should be at index 2,
228          * but the Linux PCI code doesn't know how to "count" 64bit
229          * bars.
230          */
231         *base2 = pci_resource_start(ahd->dev_softc, 3);
232         if (*base == 0 || *base2 == 0)
233                 return (ENOMEM);
234         if (request_region(*base, 256, "aic79xx") == 0)
235                 return (ENOMEM);
236         if (request_region(*base2, 256, "aic79xx") == 0) {
237                 release_region(*base2, 256);
238                 return (ENOMEM);
239         }
240         return (0);
241 }
242
243 static int
244 ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
245                                  u_long *bus_addr,
246                                  uint8_t __iomem **maddr)
247 {
248         u_long  start;
249         u_long  base_page;
250         u_long  base_offset;
251         int     error;
252
253         if (aic79xx_allow_memio == 0)
254                 return (ENOMEM);
255
256         if ((ahd->bugs & AHD_PCIX_MMAPIO_BUG) != 0)
257                 return (ENOMEM);
258
259         error = 0;
260         start = pci_resource_start(ahd->dev_softc, 1);
261         base_page = start & PAGE_MASK;
262         base_offset = start - base_page;
263         if (start != 0) {
264                 *bus_addr = start;
265                 if (request_mem_region(start, 0x1000, "aic79xx") == 0)
266                         error = ENOMEM;
267                 if (error == 0) {
268                         *maddr = ioremap_nocache(base_page, base_offset + 256);
269                         if (*maddr == NULL) {
270                                 error = ENOMEM;
271                                 release_mem_region(start, 0x1000);
272                         } else
273                                 *maddr += base_offset;
274                 }
275         } else
276                 error = ENOMEM;
277         return (error);
278 }
279
280 int
281 ahd_pci_map_registers(struct ahd_softc *ahd)
282 {
283         uint32_t command;
284         u_long   base;
285         uint8_t __iomem *maddr;
286         int      error;
287
288         /*
289          * If its allowed, we prefer memory mapped access.
290          */
291         command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, 4);
292         command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN);
293         base = 0;
294         maddr = NULL;
295         error = ahd_linux_pci_reserve_mem_region(ahd, &base, &maddr);
296         if (error == 0) {
297                 ahd->platform_data->mem_busaddr = base;
298                 ahd->tags[0] = BUS_SPACE_MEMIO;
299                 ahd->bshs[0].maddr = maddr;
300                 ahd->tags[1] = BUS_SPACE_MEMIO;
301                 ahd->bshs[1].maddr = maddr + 0x100;
302                 ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND,
303                                      command | PCIM_CMD_MEMEN, 4);
304
305                 if (ahd_pci_test_register_access(ahd) != 0) {
306
307                         printf("aic79xx: PCI Device %d:%d:%d "
308                                "failed memory mapped test.  Using PIO.\n",
309                                ahd_get_pci_bus(ahd->dev_softc),
310                                ahd_get_pci_slot(ahd->dev_softc),
311                                ahd_get_pci_function(ahd->dev_softc));
312                         iounmap(maddr);
313                         release_mem_region(ahd->platform_data->mem_busaddr,
314                                            0x1000);
315                         ahd->bshs[0].maddr = NULL;
316                         maddr = NULL;
317                 } else
318                         command |= PCIM_CMD_MEMEN;
319         } else if (bootverbose) {
320                 printf("aic79xx: PCI%d:%d:%d MEM region 0x%lx "
321                        "unavailable. Cannot memory map device.\n",
322                        ahd_get_pci_bus(ahd->dev_softc),
323                        ahd_get_pci_slot(ahd->dev_softc),
324                        ahd_get_pci_function(ahd->dev_softc),
325                        base);
326         }
327
328         if (maddr == NULL) {
329                 u_long   base2;
330
331                 error = ahd_linux_pci_reserve_io_regions(ahd, &base, &base2);
332                 if (error == 0) {
333                         ahd->tags[0] = BUS_SPACE_PIO;
334                         ahd->tags[1] = BUS_SPACE_PIO;
335                         ahd->bshs[0].ioport = base;
336                         ahd->bshs[1].ioport = base2;
337                         command |= PCIM_CMD_PORTEN;
338                 } else {
339                         printf("aic79xx: PCI%d:%d:%d IO regions 0x%lx and 0x%lx"
340                                "unavailable. Cannot map device.\n",
341                                ahd_get_pci_bus(ahd->dev_softc),
342                                ahd_get_pci_slot(ahd->dev_softc),
343                                ahd_get_pci_function(ahd->dev_softc),
344                                base, base2);
345                 }
346         }
347         ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, 4);
348         return (error);
349 }
350
351 int
352 ahd_pci_map_int(struct ahd_softc *ahd)
353 {
354         int error;
355
356         error = request_irq(ahd->dev_softc->irq, ahd_linux_isr,
357                             SA_SHIRQ, "aic79xx", ahd);
358         if (error == 0)
359                 ahd->platform_data->irq = ahd->dev_softc->irq;
360         
361         return (-error);
362 }
363
364 void
365 ahd_power_state_change(struct ahd_softc *ahd, ahd_power_state new_state)
366 {
367         pci_set_power_state(ahd->dev_softc, new_state);
368 }