1 /* $NetBSD: mlx_eisa.c,v 1.18 2006/11/16 01:32:50 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * EISA front-end for mlx(4) driver.
41 */
42
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: mlx_eisa.c,v 1.18 2006/11/16 01:32:50 christos Exp $");
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/device.h>
49
50 #include <machine/bus.h>
51 #include <machine/intr.h>
52
53 #include <dev/eisa/eisavar.h>
54 #include <dev/eisa/eisadevs.h>
55
56 #include <dev/ic/mlxreg.h>
57 #include <dev/ic/mlxio.h>
58 #include <dev/ic/mlxvar.h>
59
60 #define MLX_EISA_SLOT_OFFSET 0x0c80
61 #define MLX_EISA_IOSIZE (0x0ce0 - MLX_EISA_SLOT_OFFSET)
62 #define MLX_EISA_CFG01 (0x0cc0 - MLX_EISA_SLOT_OFFSET)
63 #define MLX_EISA_CFG02 (0x0cc1 - MLX_EISA_SLOT_OFFSET)
64 #define MLX_EISA_CFG03 (0x0cc3 - MLX_EISA_SLOT_OFFSET)
65 #define MLX_EISA_CFG04 (0x0c8d - MLX_EISA_SLOT_OFFSET)
66 #define MLX_EISA_CFG05 (0x0c90 - MLX_EISA_SLOT_OFFSET)
67 #define MLX_EISA_CFG06 (0x0c91 - MLX_EISA_SLOT_OFFSET)
68 #define MLX_EISA_CFG07 (0x0c92 - MLX_EISA_SLOT_OFFSET)
69 #define MLX_EISA_CFG08 (0x0c93 - MLX_EISA_SLOT_OFFSET)
70 #define MLX_EISA_CFG09 (0x0c94 - MLX_EISA_SLOT_OFFSET)
71 #define MLX_EISA_CFG10 (0x0c95 - MLX_EISA_SLOT_OFFSET)
72
73 static void mlx_eisa_attach(struct device *, struct device *, void *);
74 static int mlx_eisa_match(struct device *, struct cfdata *, void *);
75
76 static int mlx_v1_submit(struct mlx_softc *, struct mlx_ccb *);
77 static int mlx_v1_findcomplete(struct mlx_softc *, u_int *, u_int *);
78 static void mlx_v1_intaction(struct mlx_softc *, int);
79 static int mlx_v1_fw_handshake(struct mlx_softc *, int *, int *, int *);
80 #ifdef MLX_RESET
81 static int mlx_v1_reset(struct mlx_softc *);
82 #endif
83
84 CFATTACH_DECL(mlx_eisa, sizeof(struct mlx_softc),
85 mlx_eisa_match, mlx_eisa_attach, NULL, NULL);
86
87 static struct mlx_eisa_prod {
88 const char *mp_idstr;
89 int mp_nchan;
90 } const mlx_eisa_prod[] = {
91 { "MLX0070", 1 },
92 { "MLX0071", 3 },
93 { "MLX0072", 3 },
94 { "MLX0073", 2 },
95 { "MLX0074", 1 },
96 { "MLX0075", 3 },
97 { "MLX0076", 2 },
98 { "MLX0077", 1 },
99 };
100
101 static int
102 mlx_eisa_match(struct device *parent, struct cfdata *match,
103 void *aux)
104 {
105 struct eisa_attach_args *ea;
106 int i;
107
108 ea = aux;
109
110 for (i = 0; i < sizeof(mlx_eisa_prod) / sizeof(mlx_eisa_prod[0]); i++)
111 if (strcmp(ea->ea_idstring, mlx_eisa_prod[i].mp_idstr) == 0)
112 return (1);
113
114 return (0);
115 }
116
117 static void
118 mlx_eisa_attach(struct device *parent, struct device *self, void *aux)
119 {
120 struct eisa_attach_args *ea;
121 bus_space_handle_t ioh;
122 eisa_chipset_tag_t ec;
123 eisa_intr_handle_t ih;
124 struct mlx_softc *mlx;
125 bus_space_tag_t iot;
126 const char *intrstr;
127 int irq, i, icfg;
128
129 ea = aux;
130 mlx = device_private(self);
131 iot = ea->ea_iot;
132 ec = ea->ea_ec;
133
134 if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) +
135 MLX_EISA_SLOT_OFFSET, MLX_EISA_IOSIZE, 0, &ioh)) {
136 printf("can't map i/o space\n");
137 return;
138 }
139
140 mlx->mlx_iot = iot;
141 mlx->mlx_ioh = ioh;
142 mlx->mlx_dmat = ea->ea_dmat;
143
144 /*
145 * Map and establish the interrupt.
146 */
147 icfg = bus_space_read_1(iot, ioh, MLX_EISA_CFG03);
148
149 switch (icfg & 0xf0) {
150 case 0xa0:
151 irq = 11;
152 break;
153 case 0xc0:
154 irq = 12;
155 break;
156 case 0xe0:
157 irq = 14;
158 break;
159 case 0x80:
160 irq = 15;
161 break;
162 default:
163 printf("controller on invalid IRQ\n");
164 return;
165 }
166
167 if (eisa_intr_map(ec, irq, &ih)) {
168 printf("can't map interrupt (%d)\n", irq);
169 return;
170 }
171
172 intrstr = eisa_intr_string(ec, ih);
173 mlx->mlx_ih = eisa_intr_establish(ec, ih,
174 ((icfg & 0x08) != 0 ? IST_LEVEL : IST_EDGE),
175 IPL_BIO, mlx_intr, mlx);
176 if (mlx->mlx_ih == NULL) {
177 printf("can't establish interrupt");
178 if (intrstr != NULL)
179 printf(" at %s", intrstr);
180 printf("\n");
181 return;
182 }
183
184 for (i = 0; i < sizeof(mlx_eisa_prod) / sizeof(mlx_eisa_prod[0]); i++)
185 if (strcmp(ea->ea_idstring, mlx_eisa_prod[i].mp_idstr) == 0) {
186 mlx->mlx_ci.ci_nchan = mlx_eisa_prod[i].mp_nchan;
187 break;
188 }
189 mlx->mlx_ci.ci_iftype = 1;
190
191 mlx->mlx_submit = mlx_v1_submit;
192 mlx->mlx_findcomplete = mlx_v1_findcomplete;
193 mlx->mlx_intaction = mlx_v1_intaction;
194 mlx->mlx_fw_handshake = mlx_v1_fw_handshake;
195 #ifdef MLX_RESET
196 mlx->mlx_reset = mlx_v1_reset;
197 #endif
198
199 printf(": Mylex RAID\n");
200 mlx_init(mlx, intrstr);
201 }
202
203 /*
204 * ================= V1 interface linkage =================
205 */
206
207 /*
208 * Try to give (mc) to the controller. Returns 1 if successful, 0 on
209 * failure (the controller is not ready to take a command).
210 *
211 * Must be called at splbio or in a fashion that prevents reentry.
212 */
213 static int
214 mlx_v1_submit(struct mlx_softc *mlx, struct mlx_ccb *mc)
215 {
216
217 /* Ready for our command? */
218 if ((mlx_inb(mlx, MLX_V1REG_IDB) & MLX_V1_IDB_FULL) == 0) {
219 /* Copy mailbox data to window. */
220 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh,
221 MLX_V1REG_MAILBOX, mc->mc_mbox, 13);
222 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh,
223 MLX_V1REG_MAILBOX, 13,
224 BUS_SPACE_BARRIER_WRITE);
225
226 /* Post command. */
227 mlx_outb(mlx, MLX_V1REG_IDB, MLX_V1_IDB_FULL);
228 return (1);
229 }
230
231 return (0);
232 }
233
234 /*
235 * See if a command has been completed, if so acknowledge its completion and
236 * recover the slot number and status code.
237 *
238 * Must be called at splbio or in a fashion that prevents reentry.
239 */
240 static int
241 mlx_v1_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status)
242 {
243
244 /* Status available? */
245 if ((mlx_inb(mlx, MLX_V1REG_ODB) & MLX_V1_ODB_SAVAIL) != 0) {
246 *slot = mlx_inb(mlx, MLX_V1REG_MAILBOX + 0x0d);
247 *status = mlx_inw(mlx, MLX_V1REG_MAILBOX + 0x0e);
248
249 /* Acknowledge completion. */
250 mlx_outb(mlx, MLX_V1REG_ODB, MLX_V1_ODB_SAVAIL);
251 mlx_outb(mlx, MLX_V1REG_IDB, MLX_V1_IDB_SACK);
252 return (1);
253 }
254
255 return (0);
256 }
257
258 /*
259 * Enable/disable interrupts as requested. (No acknowledge required)
260 *
261 * Must be called at splbio or in a fashion that prevents reentry.
262 */
263 static void
264 mlx_v1_intaction(struct mlx_softc *mlx, int action)
265 {
266
267 mlx_outb(mlx, MLX_V1REG_IE, action ? 1 : 0);
268 }
269
270 /*
271 * Poll for firmware error codes during controller initialisation.
272 *
273 * Returns 0 if initialisation is complete, 1 if still in progress but no
274 * error has been fetched, 2 if an error has been retrieved.
275 */
276 static int
277 mlx_v1_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2)
278 {
279 u_int8_t fwerror;
280
281 /*
282 * First time around, enable the IDB interrupt and clear any
283 * hardware completion status.
284 */
285 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) {
286 mlx_outb(mlx, MLX_V1REG_ODB_EN, 1);
287 DELAY(1000);
288 mlx_outb(mlx, MLX_V1REG_ODB, 1);
289 DELAY(1000);
290 mlx_outb(mlx, MLX_V1REG_IDB, MLX_V1_IDB_SACK);
291 DELAY(1000);
292 mlx->mlx_flags |= MLXF_FW_INITTED;
293 }
294
295 /* Init in progress? */
296 if ((mlx_inb(mlx, MLX_V1REG_IDB) & MLX_V1_IDB_INIT_BUSY) == 0)
297 return (0);
298
299 /* Test error value. */
300 fwerror = mlx_inb(mlx, MLX_V1REG_ODB);
301
302 if ((fwerror & MLX_V1_FWERROR_PEND) == 0)
303 return (1);
304
305 /* XXX Fetch status. */
306 *error = fwerror & 0xf0;
307 *param1 = -1;
308 *param2 = -1;
309
310 /* Acknowledge. */
311 mlx_outb(mlx, MLX_V1REG_ODB, fwerror);
312
313 return (2);
314 }
315
316 #ifdef MLX_RESET
317 /*
318 * Reset the controller. Return non-zero on failure.
319 */
320 static int
321 mlx_v1_reset(struct mlx_softc *mlx)
322 {
323 int i;
324
325 mlx_outb(mlx, MLX_V1REG_IDB, MLX_V1_IDB_SACK);
326 delay(1000000);
327
328 /* Wait up to 2 minutes for the bit to clear. */
329 for (i = 120; i != 0; i--) {
330 delay(1000000);
331 if ((mlx_inb(mlx, MLX_V1REG_IDB) & MLX_V1_IDB_SACK) == 0)
332 break;
333 }
334 if (i == 0)
335 return (-1);
336
337 mlx_outb(mlx, MLX_V1REG_ODB, MLX_V1_ODB_RESET);
338 mlx_outb(mlx, MLX_V1REG_IDB, MLX_V1_IDB_RESET);
339
340 /* Wait up to 5 seconds for the bit to clear... */
341 for (i = 5; i != 0; i--) {
342 delay(1000000);
343 if ((mlx_inb(mlx, MLX_V1REG_IDB) & MLX_V1_IDB_RESET) == 0)
344 break;
345 }
346 if (i == 0)
347 return (-1);
348
349 /* Wait up to 3 seconds for the other bit to clear... */
350 for (i = 5; i != 0; i--) {
351 delay(1000000);
352 if ((mlx_inb(mlx, MLX_V1REG_ODB) & MLX_V1_ODB_RESET) == 0)
353 break;
354 }
355 if (i == 0)
356 return (-1);
357
358 return (0);
359 }
360 #endif /* MLX_RESET */
Cache object: abc72de8dbf1ce61e567a9ad24b56547
|