File: /usr/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_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. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * Alternatively, this software may be distributed under the terms of the
17 * GNU General Public License ("GPL").
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#23 $
32 */
33
34 #include "aic7xxx_osm.h"
35
36 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
37 struct pci_device_id
38 {
39 };
40 #endif
41
42 static int ahc_linux_pci_dev_probe(struct pci_dev *pdev,
43 const struct pci_device_id *ent);
44 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
45 static void ahc_linux_pci_dev_remove(struct pci_dev *pdev);
46
47 /* We do our own ID filtering. So, grab all SCSI storage class devices. */
48 static struct pci_device_id ahc_linux_pci_id_table[] = {
49 {
50 0x9004, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
51 PCI_CLASS_STORAGE_SCSI << 8, 0xFFFF00, 0
52 },
53 {
54 0x9005, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
55 PCI_CLASS_STORAGE_SCSI << 8, 0xFFFF00, 0
56 },
57 { 0 }
58 };
59
60 struct pci_driver aic7xxx_pci_driver = {
61 name: "aic7xxx",
62 probe: ahc_linux_pci_dev_probe,
63 remove: ahc_linux_pci_dev_remove,
64 id_table: ahc_linux_pci_id_table
65 };
66
67 static void
68 ahc_linux_pci_dev_remove(struct pci_dev *pdev)
69 {
70 struct ahc_softc *ahc;
71 struct ahc_softc *list_ahc;
72
73 /*
74 * We should be able to just perform
75 * the free directly, but check our
76 * list for extra sanity.
77 */
78 ahc = (struct ahc_softc *)pdev->driver_data;
79 TAILQ_FOREACH(list_ahc, &ahc_tailq, links) {
80 if (list_ahc == ahc) {
81 ahc_free(ahc);
82 break;
83 }
84 }
85 }
86 #endif /* !LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) */
87
88 static int
89 ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
90 {
91 char buf[80];
92 struct ahc_softc *ahc;
93 ahc_dev_softc_t pci;
94 struct ahc_pci_identity *entry;
95 char *name;
96 int error;
97
98 pci = pdev;
99 entry = ahc_find_pci_device(pci);
100 if (entry == NULL)
101 return (-ENODEV);
102
103 /*
104 * Allocate a softc for this card and
105 * set it up for attachment by our
106 * common detect routine.
107 */
108 sprintf(buf, "ahc_pci:%d:%d:%d",
109 ahc_get_pci_bus(pci),
110 ahc_get_pci_slot(pci),
111 ahc_get_pci_function(pci));
112 name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
113 if (name == NULL)
114 return (-ENOMEM);
115 strcpy(name, buf);
116 ahc = ahc_alloc(NULL, name);
117 if (ahc == NULL)
118 return (-ENOMEM);
119 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
120 if (pci_enable_device(pdev)) {
121 ahc_free(ahc);
122 return (-ENODEV);
123 }
124 pci_set_master(pdev);
125
126 if (sizeof(bus_addr_t) > 4
127 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3)
128 && ahc_linux_get_memsize() > 0x80000000
129 && pci_set_dma_mask(pdev, 0x7FFFFFFFFFULL) == 0) {
130 #else
131 && ahc_linux_get_memsize() > 0x80000000) {
132 ahc->dev_softc->dma_mask =
133 (bus_addr_t)(0x7FFFFFFFFFULL
134 & ((1ULL << (sizeof(bus_addr_t) * 8))-1));
135 #endif
136 ahc->flags |= AHC_39BIT_ADDRESSING;
137 ahc->platform_data->hw_dma_mask =
138 (bus_addr_t)(0x7FFFFFFFFFULL
139 & ((1ULL << (sizeof(bus_addr_t) * 8))-1));
140 }
141 #endif
142 ahc->dev_softc = pci;
143 ahc->platform_data->irq = pdev->irq;
144 error = ahc_pci_config(ahc, entry);
145 if (error != 0) {
146 ahc_free(ahc);
147 return (-error);
148 }
149 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
150 pdev->driver_data = ahc;
151 if (aic7xxx_detect_complete)
152 ahc_linux_register_host(ahc, aic7xxx_driver_template);
153 #endif
154 return (0);
155 }
156
157 int
158 ahc_linux_pci_probe(Scsi_Host_Template *template)
159 {
160 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
161 return (pci_module_init(&aic7xxx_pci_driver));
162 #else
163 struct pci_dev *pdev;
164 u_int class;
165 int found;
166
167 /* If we don't have a PCI bus, we can't find any adapters. */
168 if (pci_present() == 0)
169 return (0);
170
171 found = 0;
172 pdev = NULL;
173 class = PCI_CLASS_STORAGE_SCSI << 8;
174 while ((pdev = pci_find_class(class, pdev)) != NULL) {
175 struct ahc_softc *ahc;
176 ahc_dev_softc_t pci;
177 int error;
178
179 pci = pdev;
180
181 /*
182 * Some BIOSen report the same device multiple times.
183 */
184 TAILQ_FOREACH(ahc, &ahc_tailq, links) {
185 struct pci_dev *probed_pdev;
186
187 probed_pdev = ahc->dev_softc;
188 if (probed_pdev->bus->number == pdev->bus->number
189 && probed_pdev->devfn == pdev->devfn)
190 break;
191 }
192 if (ahc != NULL) {
193 /* Skip duplicate. */
194 continue;
195 }
196
197 error = ahc_linux_pci_dev_probe(pdev, /*pci_devid*/NULL);
198 if (error == 0)
199 found++;
200 }
201 return (found);
202 #endif
203 }
204
205 int
206 ahc_pci_map_registers(struct ahc_softc *ahc)
207 {
208 uint32_t command;
209 u_long base;
210 #ifdef MMAPIO
211 u_long start;
212 u_long base_page;
213 u_long base_offset;
214 #endif
215 uint8_t *maddr;
216
217 command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4);
218 base = 0;
219 maddr = NULL;
220 #ifdef MMAPIO
221 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
222 start = pci_resource_start(ahc->dev_softc, 1);
223 base_page = start & PAGE_MASK;
224 base_offset = start - base_page;
225 #else
226 start = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS+4, 4);
227 base_offset = start & PCI_BASE_ADDRESS_MEM_MASK;
228 base_page = base_offset & PAGE_MASK;
229 base_offset -= base_page;
230 #endif
231 if (start != 0) {
232 ahc->platform_data->mem_busaddr = start;
233 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
234 if (request_mem_region(start, 0x1000, "aic7xxx") == 0) {
235 printf("aic7xxx: PCI%d:%d:%d MEM region 0x%lx "
236 "in use. Cannot map device.\n",
237 ahc_get_pci_bus(ahc->dev_softc),
238 ahc_get_pci_slot(ahc->dev_softc),
239 ahc_get_pci_function(ahc->dev_softc),
240 start);
241 } else
242 #endif
243 maddr = ioremap_nocache(base_page, base_offset + 256);
244 if (maddr != NULL) {
245 ahc->tag = BUS_SPACE_MEMIO;
246 ahc->bsh.maddr = maddr + base_offset;
247 command |= PCIM_CMD_MEMEN;
248 ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND,
249 command, 4);
250
251 /*
252 * Do a quick test to see if memory mapped
253 * I/O is functioning correctly.
254 */
255 if (ahc_inb(ahc, HCNTRL) == 0xFF) {
256 printf("aic7xxx: PCI Device %d:%d:%d "
257 "failed memory mapped test\n",
258 ahc_get_pci_bus(ahc->dev_softc),
259 ahc_get_pci_slot(ahc->dev_softc),
260 ahc_get_pci_function(ahc->dev_softc));
261 iounmap((void *)base_page);
262 maddr = NULL;
263 } else {
264 command &= ~PCIM_CMD_PORTEN;
265 ahc_pci_write_config(ahc->dev_softc,
266 PCIR_COMMAND, command, 4);
267 }
268 }
269 }
270 #endif
271
272 /*
273 * We always prefer memory mapped access. Only
274 * complain about our ioport conflicting with
275 * another device if we are going to use it.
276 */
277 if (maddr == NULL) {
278 ahc->tag = BUS_SPACE_PIO;
279 command &= ~(PCIM_CMD_MEMEN|PCIM_CMD_PORTEN);
280 ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4);
281 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
282 base = pci_resource_start(ahc->dev_softc, 0);
283 #else
284 base = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS, 4);
285 base &= PCI_BASE_ADDRESS_IO_MASK;
286 #endif
287 if (base == 0) {
288 printf("aic7xxx: PCI%d:%d:%d No mapping available. "
289 "Cannot map device.\n",
290 ahc_get_pci_bus(ahc->dev_softc),
291 ahc_get_pci_slot(ahc->dev_softc),
292 ahc_get_pci_function(ahc->dev_softc));
293 return (ENXIO);
294 }
295 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
296 if (check_region(base, 256) != 0) {
297 #else
298 if (request_region(base, 256, "aic7xxx") == 0) {
299 #endif
300 printf("aic7xxx: PCI%d:%d:%d IO region 0x%lx[0..255] "
301 "in use. Cannot map device.\n",
302 ahc_get_pci_bus(ahc->dev_softc),
303 ahc_get_pci_slot(ahc->dev_softc),
304 ahc_get_pci_function(ahc->dev_softc),
305 base);
306 base = 0;
307 return (EBUSY);
308 }
309 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
310 request_region(base, 256, "aic7xxx");
311 #endif
312 ahc->bsh.ioport = base;
313 command |= PCIM_CMD_PORTEN;
314 ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4);
315 }
316 return (0);
317 }
318
319 int
320 ahc_pci_map_int(struct ahc_softc *ahc)
321 {
322 int error;
323
324 ahc->platform_data->irq = ahc->dev_softc->irq;
325 error = request_irq(ahc->platform_data->irq, ahc_linux_isr,
326 SA_SHIRQ, "aic7xxx", ahc);
327
328 return (-error);
329 }
330
331 void
332 ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state)
333 {
334 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
335 pci_set_power_state(ahc->dev_softc, new_state);
336 #else
337 uint32_t cap;
338 u_int cap_offset;
339
340 /*
341 * Traverse the capability list looking for
342 * the power management capability.
343 */
344 cap = 0;
345 cap_offset = ahc_pci_read_config(ahc->dev_softc,
346 PCIR_CAP_PTR, /*bytes*/1);
347 while (cap_offset != 0) {
348
349 cap = ahc_pci_read_config(ahc->dev_softc,
350 cap_offset, /*bytes*/4);
351 if ((cap & 0xFF) == 1
352 && ((cap >> 16) & 0x3) > 0) {
353 uint32_t pm_control;
354
355 pm_control = ahc_pci_read_config(ahc->dev_softc,
356 cap_offset + 4,
357 /*bytes*/4);
358 pm_control &= ~0x3;
359 pm_control |= new_state;
360 ahc_pci_write_config(ahc->dev_softc,
361 cap_offset + 4,
362 pm_control, /*bytes*/2);
363 break;
364 }
365 cap_offset = (cap >> 8) & 0xFF;
366 }
367 #endif
368 }
369