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