diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/scsi/aic7xxx/aic7770_osm.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/scsi/aic7xxx/aic7770_osm.c')
-rw-r--r-- | drivers/scsi/aic7xxx/aic7770_osm.c | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c new file mode 100644 index 000000000000..c2b47f2bdffd --- /dev/null +++ b/drivers/scsi/aic7xxx/aic7770_osm.c | |||
@@ -0,0 +1,264 @@ | |||
1 | /* | ||
2 | * Linux driver attachment glue for aic7770 based controllers. | ||
3 | * | ||
4 | * Copyright (c) 2000-2003 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/aic7770_osm.c#14 $ | ||
40 | */ | ||
41 | |||
42 | #include "aic7xxx_osm.h" | ||
43 | |||
44 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) | ||
45 | #include <linux/device.h> | ||
46 | #include <linux/eisa.h> | ||
47 | |||
48 | #define EISA_MFCTR_CHAR0(ID) (char)(((ID>>26) & 0x1F) | '@') /* Bits 26-30 */ | ||
49 | #define EISA_MFCTR_CHAR1(ID) (char)(((ID>>21) & 0x1F) | '@') /* Bits 21-25 */ | ||
50 | #define EISA_MFCTR_CHAR2(ID) (char)(((ID>>16) & 0x1F) | '@') /* Bits 16-20 */ | ||
51 | #define EISA_PRODUCT_ID(ID) (short)((ID>>4) & 0xFFF) /* Bits 4-15 */ | ||
52 | #define EISA_REVISION_ID(ID) (uint8_t)(ID & 0x0F) /* Bits 0-3 */ | ||
53 | |||
54 | static int aic7770_eisa_dev_probe(struct device *dev); | ||
55 | static int aic7770_eisa_dev_remove(struct device *dev); | ||
56 | static struct eisa_driver aic7770_driver = { | ||
57 | .driver = { | ||
58 | .name = "aic7xxx", | ||
59 | .probe = aic7770_eisa_dev_probe, | ||
60 | .remove = aic7770_eisa_dev_remove, | ||
61 | } | ||
62 | }; | ||
63 | |||
64 | typedef struct device *aic7770_dev_t; | ||
65 | #else | ||
66 | #define MINSLOT 1 | ||
67 | #define NUMSLOTS 16 | ||
68 | #define IDOFFSET 0x80 | ||
69 | |||
70 | typedef void *aic7770_dev_t; | ||
71 | #endif | ||
72 | |||
73 | static int aic7770_linux_config(struct aic7770_identity *entry, | ||
74 | aic7770_dev_t dev, u_int eisaBase); | ||
75 | |||
76 | int | ||
77 | ahc_linux_eisa_init(void) | ||
78 | { | ||
79 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) | ||
80 | struct eisa_device_id *eid; | ||
81 | struct aic7770_identity *id; | ||
82 | int i; | ||
83 | |||
84 | if (aic7xxx_probe_eisa_vl == 0) | ||
85 | return -ENODEV; | ||
86 | |||
87 | /* | ||
88 | * Linux requires the EISA IDs to be specified in | ||
89 | * the EISA ID string format. Perform the conversion | ||
90 | * and setup a table with a NUL terminal entry. | ||
91 | */ | ||
92 | aic7770_driver.id_table = malloc(sizeof(struct eisa_device_id) * | ||
93 | (ahc_num_aic7770_devs + 1), | ||
94 | M_DEVBUF, M_NOWAIT); | ||
95 | if (aic7770_driver.id_table == NULL) | ||
96 | return -ENOMEM; | ||
97 | |||
98 | for (eid = (struct eisa_device_id *)aic7770_driver.id_table, | ||
99 | id = aic7770_ident_table, i = 0; | ||
100 | i < ahc_num_aic7770_devs; eid++, id++, i++) { | ||
101 | |||
102 | sprintf(eid->sig, "%c%c%c%03X%01X", | ||
103 | EISA_MFCTR_CHAR0(id->full_id), | ||
104 | EISA_MFCTR_CHAR1(id->full_id), | ||
105 | EISA_MFCTR_CHAR2(id->full_id), | ||
106 | EISA_PRODUCT_ID(id->full_id), | ||
107 | EISA_REVISION_ID(id->full_id)); | ||
108 | eid->driver_data = i; | ||
109 | } | ||
110 | eid->sig[0] = 0; | ||
111 | |||
112 | return eisa_driver_register(&aic7770_driver); | ||
113 | #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) */ | ||
114 | struct aic7770_identity *entry; | ||
115 | u_int slot; | ||
116 | u_int eisaBase; | ||
117 | u_int i; | ||
118 | int ret = -ENODEV; | ||
119 | |||
120 | if (aic7xxx_probe_eisa_vl == 0) | ||
121 | return ret; | ||
122 | |||
123 | eisaBase = 0x1000 + AHC_EISA_SLOT_OFFSET; | ||
124 | for (slot = 1; slot < NUMSLOTS; eisaBase+=0x1000, slot++) { | ||
125 | uint32_t eisa_id; | ||
126 | size_t id_size; | ||
127 | |||
128 | if (request_region(eisaBase, AHC_EISA_IOSIZE, "aic7xxx") == 0) | ||
129 | continue; | ||
130 | |||
131 | eisa_id = 0; | ||
132 | id_size = sizeof(eisa_id); | ||
133 | for (i = 0; i < 4; i++) { | ||
134 | /* VLcards require priming*/ | ||
135 | outb(0x80 + i, eisaBase + IDOFFSET); | ||
136 | eisa_id |= inb(eisaBase + IDOFFSET + i) | ||
137 | << ((id_size-i-1) * 8); | ||
138 | } | ||
139 | release_region(eisaBase, AHC_EISA_IOSIZE); | ||
140 | if (eisa_id & 0x80000000) | ||
141 | continue; /* no EISA card in slot */ | ||
142 | |||
143 | entry = aic7770_find_device(eisa_id); | ||
144 | if (entry != NULL) { | ||
145 | aic7770_linux_config(entry, NULL, eisaBase); | ||
146 | ret = 0; | ||
147 | } | ||
148 | } | ||
149 | return ret; | ||
150 | #endif | ||
151 | } | ||
152 | |||
153 | void | ||
154 | ahc_linux_eisa_exit(void) | ||
155 | { | ||
156 | if(aic7xxx_probe_eisa_vl != 0 && aic7770_driver.id_table != NULL) { | ||
157 | eisa_driver_unregister(&aic7770_driver); | ||
158 | free(aic7770_driver.id_table, M_DEVBUF); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | static int | ||
163 | aic7770_linux_config(struct aic7770_identity *entry, aic7770_dev_t dev, | ||
164 | u_int eisaBase) | ||
165 | { | ||
166 | struct ahc_softc *ahc; | ||
167 | char buf[80]; | ||
168 | char *name; | ||
169 | int error; | ||
170 | |||
171 | /* | ||
172 | * Allocate a softc for this card and | ||
173 | * set it up for attachment by our | ||
174 | * common detect routine. | ||
175 | */ | ||
176 | sprintf(buf, "ahc_eisa:%d", eisaBase >> 12); | ||
177 | name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); | ||
178 | if (name == NULL) | ||
179 | return (ENOMEM); | ||
180 | strcpy(name, buf); | ||
181 | ahc = ahc_alloc(&aic7xxx_driver_template, name); | ||
182 | if (ahc == NULL) | ||
183 | return (ENOMEM); | ||
184 | error = aic7770_config(ahc, entry, eisaBase); | ||
185 | if (error != 0) { | ||
186 | ahc->bsh.ioport = 0; | ||
187 | ahc_free(ahc); | ||
188 | return (error); | ||
189 | } | ||
190 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) | ||
191 | dev->driver_data = (void *)ahc; | ||
192 | if (aic7xxx_detect_complete) | ||
193 | error = ahc_linux_register_host(ahc, &aic7xxx_driver_template); | ||
194 | #endif | ||
195 | return (error); | ||
196 | } | ||
197 | |||
198 | int | ||
199 | aic7770_map_registers(struct ahc_softc *ahc, u_int port) | ||
200 | { | ||
201 | /* | ||
202 | * Lock out other contenders for our i/o space. | ||
203 | */ | ||
204 | if (request_region(port, AHC_EISA_IOSIZE, "aic7xxx") == 0) | ||
205 | return (ENOMEM); | ||
206 | ahc->tag = BUS_SPACE_PIO; | ||
207 | ahc->bsh.ioport = port; | ||
208 | return (0); | ||
209 | } | ||
210 | |||
211 | int | ||
212 | aic7770_map_int(struct ahc_softc *ahc, u_int irq) | ||
213 | { | ||
214 | int error; | ||
215 | int shared; | ||
216 | |||
217 | shared = 0; | ||
218 | if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0) | ||
219 | shared = SA_SHIRQ; | ||
220 | |||
221 | error = request_irq(irq, ahc_linux_isr, shared, "aic7xxx", ahc); | ||
222 | if (error == 0) | ||
223 | ahc->platform_data->irq = irq; | ||
224 | |||
225 | return (-error); | ||
226 | } | ||
227 | |||
228 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) | ||
229 | static int | ||
230 | aic7770_eisa_dev_probe(struct device *dev) | ||
231 | { | ||
232 | struct eisa_device *edev; | ||
233 | |||
234 | edev = to_eisa_device(dev); | ||
235 | return (aic7770_linux_config(aic7770_ident_table + edev->id.driver_data, | ||
236 | dev, edev->base_addr+AHC_EISA_SLOT_OFFSET)); | ||
237 | } | ||
238 | |||
239 | static int | ||
240 | aic7770_eisa_dev_remove(struct device *dev) | ||
241 | { | ||
242 | struct ahc_softc *ahc; | ||
243 | u_long l; | ||
244 | |||
245 | /* | ||
246 | * We should be able to just perform | ||
247 | * the free directly, but check our | ||
248 | * list for extra sanity. | ||
249 | */ | ||
250 | ahc_list_lock(&l); | ||
251 | ahc = ahc_find_softc((struct ahc_softc *)dev->driver_data); | ||
252 | if (ahc != NULL) { | ||
253 | u_long s; | ||
254 | |||
255 | ahc_lock(ahc, &s); | ||
256 | ahc_intr_enable(ahc, FALSE); | ||
257 | ahc_unlock(ahc, &s); | ||
258 | ahc_free(ahc); | ||
259 | } | ||
260 | ahc_list_unlock(&l); | ||
261 | |||
262 | return (0); | ||
263 | } | ||
264 | #endif | ||